Skip to content

Commit 9ce0077

Browse files
authored
Turing 0.41. (#661)
* Bump Turing to 0.41 * Update initial_params stuff for 0.41 * Update more initial_params stuff * istrans -> is_transformed * Minor text fixes * Remove SamplingContext * Fix loss of concreteness in MCMCChains * Fix flaky test in linear regression doc * Try StableRNG * Make GMM tutorial a bit less demanding * Fix typo
1 parent fa9823d commit 9ce0077

File tree

12 files changed

+171
-239
lines changed

12 files changed

+171
-239
lines changed

Manifest.toml

Lines changed: 81 additions & 147 deletions
Large diffs are not rendered by default.

Project.toml

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,17 @@ ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
33
AbstractGPs = "99985d1d-32ba-4be9-9821-2ec096f28918"
44
AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001"
55
AbstractPPL = "7a57a42e-76ec-4ea3-a279-07e840d6d9cf"
6-
AdvancedHMC = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d"
76
AdvancedMH = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170"
87
AdvancedVI = "b5ca4192-6429-45e5-a2d9-87aec30a685c"
98
Bijectors = "76274a88-744f-5084-9051-94815aaf08c4"
109
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
11-
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
1210
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
13-
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
14-
DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb"
1511
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
1612
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1713
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
18-
DistributionsAD = "ced4e74d-a319-5a8a-b0ac-84af2272839c"
1914
DynamicHMC = "bbc10e6e-7c05-544b-b16e-64fede858acb"
2015
DynamicPPL = "366bfd00-2699-11ea-058f-f148b4cae6d8"
2116
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
22-
Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c"
2317
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
2418
Functors = "d9f16b24-f501-4c13-a1f2-28368ffc5196"
2519
GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
@@ -35,25 +29,24 @@ MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d"
3529
MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54"
3630
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
3731
Measures = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
38-
Memoization = "6fafb56a-5788-4b4e-91ca-c0cea6611c73"
3932
Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6"
4033
NNlib = "872c559c-99b0-510c-b3b7-b6c96a88d5cd"
4134
Optimisers = "3bd65402-5787-11e9-1adc-39752487f4e2"
42-
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
4335
OptimizationNLopt = "4e6fcdb7-1186-4e1f-a706-475e75c168bb"
4436
OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e"
4537
PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150"
38+
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
4639
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
4740
RDatasets = "ce6b1742-4840-55fa-b093-852dadbb1d8b"
4841
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
4942
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
5043
SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1"
44+
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
5145
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
5246
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
5347
StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
5448
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
5549
Turing = "fce5fe82-541a-59a6-adf8-730c64b5f9a0"
56-
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
5750

5851
[compat]
59-
Turing = "0.40"
52+
Turing = "0.41"

_quarto.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ website:
4343
href: https://turinglang.org/team/
4444
right:
4545
# Current version
46-
- text: "v0.40"
46+
- text: "v0.41"
4747
menu:
4848
- text: Changelog
4949
href: https://turinglang.org/docs/changelog.html

developers/compiler/design-overview/index.qmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The following are the main jobs of the `@model` macro:
3636

3737
## The model
3838

39+
<!-- Very outdated
3940
A `model::Model` is a callable struct that one can sample from by calling
4041
4142
```{julia}
@@ -49,6 +50,7 @@ and `context` is a sampling context that can, e.g., modify how the log probabili
4950
5051
Sampling resets the log joint probability of `varinfo` and increases the evaluation counter of `sampler`. If `context` is a `LikelihoodContext`,
5152
only the log likelihood of `D` will be accumulated, whereas with `PriorContext` only the log prior probability of `P` is. With the `DefaultContext` the log joint probability of both `P` and `D` is accumulated.
53+
-->
5254

5355
The `Model` struct contains the four internal fields `f`, `args`, `defaults`, and `context`.
5456
When `model::Model` is called, then the internal function `model.f` is called as `model.f(rng, varinfo, sampler, context, model.args...)`

developers/contexts/submodel-condition/index.qmd

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,14 @@ We begin by mentioning some high-level desiderata for their joint behaviour.
102102
Take these models, for example:
103103

104104
```{julia}
105-
# We define a helper function to unwrap a layer of SamplingContext, to
106-
# avoid cluttering the print statements.
107-
unwrap_sampling_context(ctx::DynamicPPL.SamplingContext) = ctx.context
108-
unwrap_sampling_context(ctx::DynamicPPL.AbstractContext) = ctx
109-
110105
@model function inner()
111-
println("inner context: $(unwrap_sampling_context(__model__.context))")
106+
println("inner context: $(__model__.context)")
112107
x ~ Normal()
113108
return y ~ Normal()
114109
end
115110
116111
@model function outer()
117-
println("outer context: $(unwrap_sampling_context(__model__.context))")
112+
println("outer context: $(__model__.context)")
118113
return a ~ to_submodel(inner())
119114
end
120115
@@ -124,7 +119,7 @@ with_outer_cond = outer() | (@varname(a.x) => 1.0)
124119
# 'Inner conditioning'
125120
inner_cond = inner() | (@varname(x) => 1.0)
126121
@model function outer2()
127-
println("outer context: $(unwrap_sampling_context(__model__.context))")
122+
println("outer context: $(__model__.context)")
128123
return a ~ to_submodel(inner_cond)
129124
end
130125
with_inner_cond = outer2()

developers/transforms/dynamicppl/index.qmd

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Note that this acts on _all_ variables in the model, including unconstrained one
6767
vi_linked = DynamicPPL.link(vi, model)
6868
println("Transformed value: $(DynamicPPL.getindex_internal(vi_linked, vn_x))")
6969
println("Transformed logp: $(DynamicPPL.getlogp(vi_linked))")
70-
println("Transformed flag: $(DynamicPPL.istrans(vi_linked, vn_x))")
70+
println("Transformed flag: $(DynamicPPL.is_transformed(vi_linked, vn_x))")
7171
```
7272

7373
Indeed, we can see that the new logp value matches with
@@ -82,7 +82,7 @@ The reverse transformation, `invlink`, reverts all of the above steps:
8282
vi = DynamicPPL.invlink(vi_linked, model) # Same as the previous vi
8383
println("Un-transformed value: $(DynamicPPL.getindex_internal(vi, vn_x))")
8484
println("Un-transformed logp: $(DynamicPPL.getlogp(vi))")
85-
println("Un-transformed flag: $(DynamicPPL.istrans(vi, vn_x))")
85+
println("Un-transformed flag: $(DynamicPPL.is_transformed(vi, vn_x))")
8686
```
8787

8888
### Model and internal representations
@@ -104,7 +104,7 @@ Note that `vi_linked[vn_x]` can also be used as shorthand for `getindex(vi_linke
104104
We can see (for this linked varinfo) that there are _two_ differences between these outputs:
105105

106106
1. _The internal representation has been transformed using the bijector (in this case, the log function)._
107-
This means that the `istrans()` flag which we used above doesn't modify the model representation: it only tells us whether the internal representation has been transformed or not.
107+
This means that the `is_transformed()` flag which we used above doesn't modify the model representation: it only tells us whether the internal representation has been transformed or not.
108108

109109
2. _The internal representation is a vector, whereas the model representation is a scalar._
110110
This is because in DynamicPPL, _all_ internal values are vectorised (i.e. converted into some vector), regardless of distribution. On the other hand, since the model specifies a univariate distribution, the model representation is a scalar.
@@ -131,7 +131,7 @@ Before that, though, we'll take a quick high-level look at how the HMC sampler i
131131
While DynamicPPL provides the _functionality_ for transforming variables, the transformation itself happens at an even higher level, i.e. in the sampler itself.
132132
The HMC sampler in Turing.jl is in [this file](https://github.com/TuringLang/Turing.jl/blob/5b24cebe773922e0f3d5c4cb7f53162eb758b04d/src/mcmc/hmc.jl).
133133
In the first step of sampling, it calls `link` on the sampler.
134-
This transformation is preserved throughout the sampling process, meaning that `istrans()` always returns true.
134+
This transformation is preserved throughout the sampling process, meaning that `is_transformed()` always returns true.
135135

136136
We can observe this by inserting print statements into the model.
137137
Here, `__varinfo__` is the internal symbol for the `VarInfo` object used in model evaluation:
@@ -145,7 +145,7 @@ setprogress!(false)
145145
println("-----------")
146146
println("model repn: $(DynamicPPL.getindex(__varinfo__, @varname(x)))")
147147
println("internal repn: $(DynamicPPL.getindex_internal(__varinfo__, @varname(x)))")
148-
println("istrans: $(istrans(__varinfo__, @varname(x)))")
148+
println("is_transformed: $(is_transformed(__varinfo__, @varname(x)))")
149149
end
150150
end
151151
@@ -154,10 +154,10 @@ sample(demo2(), HMC(0.1, 3), 3);
154154

155155

156156
(Here, the check on `if x isa AbstractFloat` prevents the printing from occurring during computation of the derivative.)
157-
You can see that during the three sampling steps, `istrans` is always kept as `true`.
157+
You can see that during the three sampling steps, `is_transformed` is always kept as `true`.
158158

159159
::: {.callout-note}
160-
The first two model evaluations where `istrans` is `false` occur prior to the actual sampling.
160+
The first two model evaluations where `is_transformed` is `false` occur prior to the actual sampling.
161161
One occurs when the model is checked for correctness (using [`DynamicPPL.check_model_and_trace`](https://github.com/TuringLang/DynamicPPL.jl/blob/ba490bf362653e1aaefe298364fe3379b60660d3/src/debug_utils.jl#L582-L612)).
162162
The second occurs because the model is evaluated once to generate a set of initial parameters inside [DynamicPPL's implementation of `AbstractMCMC.step`](https://github.com/TuringLang/DynamicPPL.jl/blob/ba490bf362653e1aaefe298364fe3379b60660d3/src/sampler.jl#L98-L117).
163163
Both of these steps occur with all samplers in Turing.jl, so are not specific to the HMC example shown here.
@@ -169,7 +169,7 @@ The biggest prerequisite for this to work correctly is that the potential energy
169169
This is exactly the same as how we had to make sure to define `logq(y)` correctly in the toy HMC example above.
170170

171171
Within Turing.jl, this is correctly handled because a statement like `x ~ LogNormal()` in the model definition above is translated into `assume(LogNormal(), @varname(x), __varinfo__)`, defined [here](https://github.com/TuringLang/DynamicPPL.jl/blob/ba490bf362653e1aaefe298364fe3379b60660d3/src/context_implementations.jl#L225-L229).
172-
If you follow the trail of function calls, you can verify that the `assume` function does indeed check for the presence of the `istrans` flag and adds the Jacobian term accordingly.
172+
If you follow the trail of function calls, you can verify that the `assume` function does indeed check for the presence of the `is_transformed` flag and adds the Jacobian term accordingly.
173173

174174
## A deeper dive into DynamicPPL's internal machinery
175175

@@ -234,7 +234,7 @@ DynamicPPL.getindex_internal(vi_linked, vn_x)
234234
```
235235

236236
The purpose of having all of these machinery is to allow other parts of DynamicPPL, such as the tilde pipeline, to handle transformed variables correctly.
237-
The following diagram shows how `assume` first checks whether the variable is transformed (using `istrans`), and then applies the appropriate transformation function.
237+
The following diagram shows how `assume` first checks whether the variable is transformed (using `is_transformed`), and then applies the appropriate transformation function.
238238

239239
<!-- 'wrappingWidth' setting required because of https://github.com/mermaid-js/mermaid-cli/issues/112#issuecomment-2352670995 -->
240240
```{mermaid}
@@ -246,7 +246,7 @@ graph TD
246246
A["x ~ LogNormal()"]:::boxStyle
247247
B["vn = <span style='color:#3B6EA8 !important;'>@varname</span>(x)<br>dist = LogNormal()<br>x, vi = ..."]:::boxStyle
248248
C["assume(vn, dist, vi)"]:::boxStyle
249-
D(["<span style='color:#3B6EA8 !important;'>if</span> istrans(vi, vn)"]):::boxStyle
249+
D(["<span style='color:#3B6EA8 !important;'>if</span> is_transformed(vi, vn)"]):::boxStyle
250250
E["f = from_internal_transform(vi, vn, dist)"]:::boxStyle
251251
F["f = from_linked_internal_transform(vi, vn, dist)"]:::boxStyle
252252
G["x, logjac = with_logabsdet_jacobian(f, getindex_internal(vi, vn, dist))"]:::boxStyle
@@ -267,7 +267,7 @@ graph TD
267267

268268
Here, `with_logabsdet_jacobian` is defined [in the ChangesOfVariables.jl package](https://juliamath.github.io/ChangesOfVariables.jl/stable/api/#ChangesOfVariables.with_logabsdet_jacobian), and returns both the effect of the transformation `f` as well as the log Jacobian term.
269269

270-
Because we chose `f` appropriately, we find here that `x` is always the model representation; furthermore, if the variable was _not_ linked (i.e. `istrans` was false), the log Jacobian term will be zero.
270+
Because we chose `f` appropriately, we find here that `x` is always the model representation; furthermore, if the variable was _not_ linked (i.e. `is_transformed` was false), the log Jacobian term will be zero.
271271
However, if it was linked, then the Jacobian term would be appropriately included, making sure that sampling proceeds correctly.
272272

273273
## Why do we need to do this at runtime?

tutorials/bayesian-linear-regression/index.qmd

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ using StatsBase
4141
# Functionality for working with scaled identity matrices.
4242
using LinearAlgebra
4343
44-
# Set a seed for reproducibility.
45-
using Random
46-
Random.seed!(0);
44+
# For ensuring reproducibility.
45+
using StableRNGs: StableRNG
4746
```
4847

4948
```{julia}
@@ -76,7 +75,7 @@ The next step is to get our data ready for testing. We'll split the `mtcars` dat
7675
select!(data, Not(:Model))
7776
7877
# Split our dataset 70%/30% into training/test sets.
79-
trainset, testset = map(DataFrame, splitobs(data; at=0.7, shuffle=true))
78+
trainset, testset = map(DataFrame, splitobs(StableRNG(468), data; at=0.7, shuffle=true))
8079
8180
# Turing requires data in matrix form.
8281
target = :MPG
@@ -143,7 +142,7 @@ With our model specified, we can call the sampler. We will use the No U-Turn Sam
143142

144143
```{julia}
145144
model = linear_regression(train, train_target)
146-
chain = sample(model, NUTS(), 5_000)
145+
chain = sample(StableRNG(468), model, NUTS(), 20_000)
147146
```
148147

149148
We can also check the densities and traces of the parameters visually using the `plot` functionality.
@@ -158,7 +157,7 @@ It looks like all parameters have converged.
158157
#| echo: false
159158
let
160159
ess_df = ess(chain)
161-
@assert minimum(ess_df[:, :ess]) > 500 "Minimum ESS: $(minimum(ess_df[:, :ess])) - not > 700"
160+
@assert minimum(ess_df[:, :ess]) > 500 "Minimum ESS: $(minimum(ess_df[:, :ess])) - not > 500"
162161
@assert mean(ess_df[:, :ess]) > 2_000 "Mean ESS: $(mean(ess_df[:, :ess])) - not > 2000"
163162
@assert maximum(ess_df[:, :ess]) > 3_500 "Maximum ESS: $(maximum(ess_df[:, :ess])) - not > 3500"
164163
end
@@ -243,9 +242,11 @@ let
243242
ols_test_loss = msd(test_prediction_ols, testset[!, target])
244243
@assert bayes_train_loss < bayes_test_loss "Bayesian training loss ($bayes_train_loss) >= Bayesian test loss ($bayes_test_loss)"
245244
@assert ols_train_loss < ols_test_loss "OLS training loss ($ols_train_loss) >= OLS test loss ($ols_test_loss)"
246-
@assert isapprox(bayes_train_loss, ols_train_loss; rtol=0.01) "Difference between Bayesian training loss ($bayes_train_loss) and OLS training loss ($ols_train_loss) unexpectedly large!"
247-
@assert isapprox(bayes_test_loss, ols_test_loss; rtol=0.05) "Difference between Bayesian test loss ($bayes_test_loss) and OLS test loss ($ols_test_loss) unexpectedly large!"
245+
@assert bayes_train_loss > ols_train_loss "Bayesian training loss ($bayes_train_loss) <= OLS training loss ($bayes_train_loss)"
246+
@assert bayes_test_loss < ols_test_loss "Bayesian test loss ($bayes_test_loss) >= OLS test loss ($ols_test_loss)"
248247
end
249248
```
250249

251-
As we can see above, OLS and our Bayesian model fit our training and test data set about the same.
250+
We can see from this that both linear regression techniques perform fairly similarly.
251+
The Bayesian linear regression approach performs worse on the training set, but better on the test set.
252+
This indicates that the Bayesian approach is more able to generalise to unseen data, i.e., it is not overfitting the training data as much.

tutorials/bayesian-poisson-regression/index.qmd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,10 @@ We use the Gelman, Rubin, and Brooks Diagnostic to check whether our chains have
182182
We expect the chains to have converged. This is because we have taken sufficient number of iterations (1500) for the NUTS sampler. However, in case the test fails, then we will have to take a larger number of iterations, resulting in longer computation time.
183183

184184
```{julia}
185-
gelmandiag(chain)
185+
# Because some of the sampler statistics are `missing`, we need to extract only
186+
# the parameters and then concretize the array so that `gelmandiag` can be computed.
187+
parameter_chain = MCMCChains.concretize(MCMCChains.get_sections(chain, :parameters))
188+
gelmandiag(parameter_chain)
186189
```
187190

188191
From the above diagnostic, we can conclude that the chains have converged because the PSRF values of the coefficients are close to 1.

tutorials/gaussian-mixture-models/index.qmd

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ Random.seed!(3)
3838
3939
# Define Gaussian mixture model.
4040
w = [0.5, 0.5]
41-
μ = [-3.5, 0.5]
42-
mixturemodel = MixtureModel([MvNormal(Fill(μₖ, 2), I) for μₖ in μ], w)
41+
μ = [-2.0, 2.0]
42+
mixturemodel = MixtureModel([MvNormal(Fill(μₖ, 2), 0.2 * I) for μₖ in μ], w)
4343
4444
# We draw the data points.
45-
N = 60
45+
N = 30
4646
x = rand(mixturemodel, N);
4747
```
4848

@@ -145,7 +145,7 @@ let
145145
# μ[1] and μ[2] can switch places, so we sort the values first.
146146
chain = Array(chains[:, ["μ[1]", "μ[2]"], i])
147147
μ_mean = vec(mean(chain; dims=1))
148-
@assert isapprox(sort(μ_mean), μ; rtol=0.1) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
148+
@assert isapprox(sort(μ_mean), μ; atol=0.5) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
149149
end
150150
end
151151
```
@@ -212,7 +212,7 @@ let
212212
# μ[1] and μ[2] can no longer switch places. Check that they've found the mean
213213
chain = Array(chains[:, ["μ[1]", "μ[2]"], i])
214214
μ_mean = vec(mean(chain; dims=1))
215-
@assert isapprox(sort(μ_mean), μ; rtol=0.4) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
215+
@assert isapprox(sort(μ_mean), μ; atol=0.5) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
216216
end
217217
end
218218
```
@@ -350,7 +350,7 @@ let
350350
# μ[1] and μ[2] can no longer switch places. Check that they've found the mean
351351
chain = Array(chains[:, ["μ[1]", "μ[2]"], i])
352352
μ_mean = vec(mean(chain; dims=1))
353-
@assert isapprox(sort(μ_mean), μ; rtol=0.4) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
353+
@assert isapprox(sort(μ_mean), μ; atol=0.5) "Difference between estimated mean of μ ($(sort(μ_mean))) and data-generating μ ($μ) unexpectedly large!"
354354
end
355355
end
356356
```

usage/mode-estimation/index.qmd

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ data = [1.5, 2.0]
3737
model = gdemo(data)
3838
```
3939

40-
Finding the maximum aposteriori or maximum likelihood parameters is as simple as
40+
Finding the maximum a posteriori or maximum likelihood parameters is as simple as
4141

4242
```{julia}
4343
# Generate a MLE estimate.
@@ -80,6 +80,14 @@ maximum_likelihood(
8080

8181
When providing values to arguments like `initial_params` the parameters are typically specified in the order in which they appear in the code of the model, so in this case first `` then `m`. More precisely it's the order returned by `Turing.Inference.getparams(model, DynamicPPL.VarInfo(model))`.
8282

83+
::: {.callout-note}
84+
## Initialisation strategies and consistency with MCMC sampling
85+
86+
Since Turing v0.41, for MCMC sampling, the `initial_params` argument must be a `DynamicPPL.AbstractInitStrategy` as described in [the sampling options page]({{< meta usage-sampling-options >}}#specifying-initial-parameters)).
87+
The optimisation interface has not yet been updated to use this; thus, initial parameters are still specified as Vectors.
88+
We expect that this will be changed in the near future.
89+
:::
90+
8391
We can also do constrained optimisation, by providing either intervals within which the parameters must stay, or costraint functions that they need to respect. For instance, here's how one can find the MLE with the constraint that the variance must be less than 0.01 and the mean must be between -1 and 1.:
8492

8593
```{julia}

0 commit comments

Comments
 (0)