@@ -2,105 +2,22 @@ module TuringOptimExt
2
2
3
3
if isdefined (Base, :get_extension )
4
4
import Turing
5
- import Turing: Distributions, DynamicPPL, ForwardDiff, NamedArrays, Printf, Accessors, Statistics, StatsAPI, StatsBase
5
+ import Turing:
6
+ DynamicPPL,
7
+ NamedArrays,
8
+ Accessors,
9
+ Optimisation
6
10
import Optim
7
11
else
8
12
import .. Turing
9
- import .. Turing: Distributions, DynamicPPL, ForwardDiff, NamedArrays, Printf, Accessors, Statistics, StatsAPI, StatsBase
13
+ import .. Turing:
14
+ DynamicPPL,
15
+ NamedArrays,
16
+ Accessors,
17
+ Optimisation
10
18
import .. Optim
11
19
end
12
20
13
- """
14
- ModeResult{
15
- V<:NamedArrays.NamedArray,
16
- M<:NamedArrays.NamedArray,
17
- O<:Optim.MultivariateOptimizationResults,
18
- S<:NamedArrays.NamedArray
19
- }
20
-
21
- A wrapper struct to store various results from a MAP or MLE estimation.
22
- """
23
- struct ModeResult{
24
- V<: NamedArrays.NamedArray ,
25
- O<: Optim.MultivariateOptimizationResults ,
26
- M<: Turing.OptimLogDensity
27
- } <: StatsBase.StatisticalModel
28
- " A vector with the resulting point estimates."
29
- values:: V
30
- " The stored Optim.jl results."
31
- optim_result:: O
32
- " The final log likelihood or log joint, depending on whether `MAP` or `MLE` was run."
33
- lp:: Float64
34
- " The evaluation function used to calculate the output."
35
- f:: M
36
- end
37
- # ############################
38
- # Various StatsBase methods #
39
- # ############################
40
-
41
-
42
-
43
- function Base. show (io:: IO , :: MIME"text/plain" , m:: ModeResult )
44
- print (io, " ModeResult with maximized lp of " )
45
- Printf. @printf (io, " %.2f" , m. lp)
46
- println (io)
47
- show (io, m. values)
48
- end
49
-
50
- function Base. show (io:: IO , m:: ModeResult )
51
- show (io, m. values. array)
52
- end
53
-
54
- function StatsBase. coeftable (m:: ModeResult ; level:: Real = 0.95 )
55
- # Get columns for coeftable.
56
- terms = string .(StatsBase. coefnames (m))
57
- estimates = m. values. array[:, 1 ]
58
- stderrors = StatsBase. stderror (m)
59
- zscore = estimates ./ stderrors
60
- p = map (z -> StatsAPI. pvalue (Distributions. Normal (), z; tail= :both ), zscore)
61
-
62
- # Confidence interval (CI)
63
- q = Statistics. quantile (Distributions. Normal (), (1 + level) / 2 )
64
- ci_low = estimates .- q .* stderrors
65
- ci_high = estimates .+ q .* stderrors
66
-
67
- level_ = 100 * level
68
- level_percentage = isinteger (level_) ? Int (level_) : level_
69
-
70
- StatsBase. CoefTable (
71
- [estimates, stderrors, zscore, p, ci_low, ci_high],
72
- [" Coef." , " Std. Error" , " z" , " Pr(>|z|)" , " Lower $(level_percentage) %" , " Upper $(level_percentage) %" ],
73
- terms)
74
- end
75
-
76
- function StatsBase. informationmatrix (m:: ModeResult ; hessian_function= ForwardDiff. hessian, kwargs... )
77
- # Calculate Hessian and information matrix.
78
-
79
- # Convert the values to their unconstrained states to make sure the
80
- # Hessian is computed with respect to the untransformed parameters.
81
- linked = DynamicPPL. istrans (m. f. varinfo)
82
- if linked
83
- m = Accessors. @set m. f. varinfo = DynamicPPL. invlink!! (m. f. varinfo, m. f. model)
84
- end
85
-
86
- # Calculate the Hessian, which is the information matrix because the negative of the log likelihood was optimized
87
- varnames = StatsBase. coefnames (m)
88
- info = hessian_function (m. f, m. values. array[:, 1 ])
89
-
90
- # Link it back if we invlinked it.
91
- if linked
92
- m = Accessors. @set m. f. varinfo = DynamicPPL. link!! (m. f. varinfo, m. f. model)
93
- end
94
-
95
- return NamedArrays. NamedArray (info, (varnames, varnames))
96
- end
97
-
98
- StatsBase. coef (m:: ModeResult ) = m. values
99
- StatsBase. coefnames (m:: ModeResult ) = names (m. values)[1 ]
100
- StatsBase. params (m:: ModeResult ) = StatsBase. coefnames (m)
101
- StatsBase. vcov (m:: ModeResult ) = inv (StatsBase. informationmatrix (m))
102
- StatsBase. loglikelihood (m:: ModeResult ) = m. lp
103
-
104
21
# ###################
105
22
# Optim.jl methods #
106
23
# ###################
@@ -125,26 +42,41 @@ mle = optimize(model, MLE())
125
42
mle = optimize(model, MLE(), NelderMead())
126
43
```
127
44
"""
128
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MLE , options:: Optim.Options = Optim. Options (); kwargs... )
129
- ctx = Turing. OptimizationContext (DynamicPPL. LikelihoodContext ())
130
- f = Turing. OptimLogDensity (model, ctx)
45
+ function Optim. optimize (
46
+ model:: DynamicPPL.Model , :: Optimisation.MLE , options:: Optim.Options = Optim. Options ();
47
+ kwargs...
48
+ )
49
+ ctx = Optimisation. OptimizationContext (DynamicPPL. LikelihoodContext ())
50
+ f = Optimisation. OptimLogDensity (model, ctx)
131
51
init_vals = DynamicPPL. getparams (f)
132
52
optimizer = Optim. LBFGS ()
133
53
return _mle_optimize (model, init_vals, optimizer, options; kwargs... )
134
54
end
135
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MLE , init_vals:: AbstractArray , options:: Optim.Options = Optim. Options (); kwargs... )
55
+ function Optim. optimize (
56
+ model:: DynamicPPL.Model ,
57
+ :: Optimisation.MLE ,
58
+ init_vals:: AbstractArray ,
59
+ options:: Optim.Options = Optim. Options ();
60
+ kwargs...
61
+ )
136
62
optimizer = Optim. LBFGS ()
137
63
return _mle_optimize (model, init_vals, optimizer, options; kwargs... )
138
64
end
139
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MLE , optimizer:: Optim.AbstractOptimizer , options:: Optim.Options = Optim. Options (); kwargs... )
140
- ctx = Turing. OptimizationContext (DynamicPPL. LikelihoodContext ())
141
- f = Turing. OptimLogDensity (model, ctx)
65
+ function Optim. optimize (
66
+ model:: DynamicPPL.Model ,
67
+ :: Optimisation.MLE ,
68
+ optimizer:: Optim.AbstractOptimizer ,
69
+ options:: Optim.Options = Optim. Options ();
70
+ kwargs...
71
+ )
72
+ ctx = Optimisation. OptimizationContext (DynamicPPL. LikelihoodContext ())
73
+ f = Optimisation. OptimLogDensity (model, ctx)
142
74
init_vals = DynamicPPL. getparams (f)
143
75
return _mle_optimize (model, init_vals, optimizer, options; kwargs... )
144
76
end
145
77
function Optim. optimize (
146
78
model:: DynamicPPL.Model ,
147
- :: Turing .MLE ,
79
+ :: Optimisation .MLE ,
148
80
init_vals:: AbstractArray ,
149
81
optimizer:: Optim.AbstractOptimizer ,
150
82
options:: Optim.Options = Optim. Options ();
@@ -154,8 +86,8 @@ function Optim.optimize(
154
86
end
155
87
156
88
function _mle_optimize (model:: DynamicPPL.Model , args... ; kwargs... )
157
- ctx = Turing . OptimizationContext (DynamicPPL. LikelihoodContext ())
158
- return _optimize (model, Turing . OptimLogDensity (model, ctx), args... ; kwargs... )
89
+ ctx = Optimisation . OptimizationContext (DynamicPPL. LikelihoodContext ())
90
+ return _optimize (model, Optimisation . OptimLogDensity (model, ctx), args... ; kwargs... )
159
91
end
160
92
161
93
"""
@@ -178,26 +110,41 @@ map_est = optimize(model, MAP())
178
110
map_est = optimize(model, MAP(), NelderMead())
179
111
```
180
112
"""
181
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MAP , options:: Optim.Options = Optim. Options (); kwargs... )
182
- ctx = Turing. OptimizationContext (DynamicPPL. DefaultContext ())
183
- f = Turing. OptimLogDensity (model, ctx)
113
+ function Optim. optimize (
114
+ model:: DynamicPPL.Model , :: Optimisation.MAP , options:: Optim.Options = Optim. Options ();
115
+ kwargs...
116
+ )
117
+ ctx = Optimisation. OptimizationContext (DynamicPPL. DefaultContext ())
118
+ f = Optimisation. OptimLogDensity (model, ctx)
184
119
init_vals = DynamicPPL. getparams (f)
185
120
optimizer = Optim. LBFGS ()
186
121
return _map_optimize (model, init_vals, optimizer, options; kwargs... )
187
122
end
188
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MAP , init_vals:: AbstractArray , options:: Optim.Options = Optim. Options (); kwargs... )
123
+ function Optim. optimize (
124
+ model:: DynamicPPL.Model ,
125
+ :: Optimisation.MAP ,
126
+ init_vals:: AbstractArray ,
127
+ options:: Optim.Options = Optim. Options ();
128
+ kwargs...
129
+ )
189
130
optimizer = Optim. LBFGS ()
190
131
return _map_optimize (model, init_vals, optimizer, options; kwargs... )
191
132
end
192
- function Optim. optimize (model:: DynamicPPL.Model , :: Turing.MAP , optimizer:: Optim.AbstractOptimizer , options:: Optim.Options = Optim. Options (); kwargs... )
193
- ctx = Turing. OptimizationContext (DynamicPPL. DefaultContext ())
194
- f = Turing. OptimLogDensity (model, ctx)
133
+ function Optim. optimize (
134
+ model:: DynamicPPL.Model ,
135
+ :: Optimisation.MAP ,
136
+ optimizer:: Optim.AbstractOptimizer ,
137
+ options:: Optim.Options = Optim. Options ();
138
+ kwargs...
139
+ )
140
+ ctx = Optimisation. OptimizationContext (DynamicPPL. DefaultContext ())
141
+ f = Optimisation. OptimLogDensity (model, ctx)
195
142
init_vals = DynamicPPL. getparams (f)
196
143
return _map_optimize (model, init_vals, optimizer, options; kwargs... )
197
144
end
198
145
function Optim. optimize (
199
146
model:: DynamicPPL.Model ,
200
- :: Turing .MAP ,
147
+ :: Optimisation .MAP ,
201
148
init_vals:: AbstractArray ,
202
149
optimizer:: Optim.AbstractOptimizer ,
203
150
options:: Optim.Options = Optim. Options ();
@@ -207,8 +154,8 @@ function Optim.optimize(
207
154
end
208
155
209
156
function _map_optimize (model:: DynamicPPL.Model , args... ; kwargs... )
210
- ctx = Turing . OptimizationContext (DynamicPPL. DefaultContext ())
211
- return _optimize (model, Turing . OptimLogDensity (model, ctx), args... ; kwargs... )
157
+ ctx = Optimisation . OptimizationContext (DynamicPPL. DefaultContext ())
158
+ return _optimize (model, Optimisation . OptimLogDensity (model, ctx), args... ; kwargs... )
212
159
end
213
160
214
161
"""
@@ -218,7 +165,7 @@ Estimate a mode, i.e., compute a MLE or MAP estimate.
218
165
"""
219
166
function _optimize (
220
167
model:: DynamicPPL.Model ,
221
- f:: Turing .OptimLogDensity ,
168
+ f:: Optimisation .OptimLogDensity ,
222
169
init_vals:: AbstractArray = DynamicPPL. getparams (f),
223
170
optimizer:: Optim.AbstractOptimizer = Optim. LBFGS (),
224
171
options:: Optim.Options = Optim. Options (),
@@ -236,25 +183,19 @@ function _optimize(
236
183
237
184
# Warn the user if the optimization did not converge.
238
185
if ! Optim. converged (M)
239
- @warn " Optimization did not converge! You may need to correct your model or adjust the Optim parameters."
186
+ @warn """
187
+ Optimization did not converge! You may need to correct your model or adjust the
188
+ Optim parameters.
189
+ """
240
190
end
241
191
242
- # Get the VarInfo at the MLE/MAP point, and run the model to ensure
243
- # correct dimensionality.
192
+ # Get the optimum in unconstrained space. `getparams` does the invlinking.
244
193
f = Accessors. @set f. varinfo = DynamicPPL. unflatten (f. varinfo, M. minimizer)
245
- f = Accessors. @set f. varinfo = DynamicPPL. invlink (f. varinfo, model)
246
- vals = DynamicPPL. getparams (f)
247
- f = Accessors. @set f. varinfo = DynamicPPL. link (f. varinfo, model)
248
-
249
- # Make one transition to get the parameter names.
250
194
vns_vals_iter = Turing. Inference. getparams (model, f. varinfo)
251
195
varnames = map (Symbol ∘ first, vns_vals_iter)
252
196
vals = map (last, vns_vals_iter)
253
-
254
- # Store the parameters and their names in an array.
255
197
vmat = NamedArrays. NamedArray (vals, varnames)
256
-
257
- return ModeResult (vmat, M, - M. minimum, f)
198
+ return Optimisation. ModeResult (vmat, M, - M. minimum, f)
258
199
end
259
200
260
201
end # module
0 commit comments