Skip to content

Commit 2f6a992

Browse files
committed
remove Zygote, add DynamicPPL.DebugUtils in performance tips
1 parent 1de0684 commit 2f6a992

File tree

1 file changed

+28
-39
lines changed

1 file changed

+28
-39
lines changed

usage/performance-tips/index.qmd

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The following example:
2525
using Turing
2626
@model function gmodel(x)
2727
m ~ Normal()
28-
for i in 1:length(x)
28+
for i in eachindex(x)
2929
x[i] ~ Normal(m, 0.2)
3030
end
3131
end
@@ -44,34 +44,23 @@ end
4444

4545
## Choose your AD backend
4646

47-
Automatic differentiation (AD) makes it possible to use modern, efficient gradient-based samplers like NUTS and HMC, and that means a good AD system is incredibly important. Turing currently
48-
supports several AD backends, including [ForwardDiff](https://github.com/JuliaDiff/ForwardDiff.jl) (the default),
49-
[Mooncake](https://github.com/compintell/Mooncake.jl),
50-
[Zygote](https://github.com/FluxML/Zygote.jl), and
51-
[ReverseDiff](https://github.com/JuliaDiff/ReverseDiff.jl).
47+
Automatic differentiation (AD) makes it possible to use modern, efficient gradient-based samplers like NUTS and HMC.
48+
This, however, also means that using a performant AD system is incredibly important.
49+
Turing currently supports several AD backends, including [ForwardDiff](https://github.com/JuliaDiff/ForwardDiff.jl) (the default), [Mooncake](https://github.com/chalk-lab/Mooncake.jl), and [ReverseDiff](https://github.com/JuliaDiff/ReverseDiff.jl).
5250

53-
For many common types of models, the default ForwardDiff backend performs great, and there is no need to worry about changing it. However, if you need more speed, you can try
54-
different backends via the standard [ADTypes](https://github.com/SciML/ADTypes.jl) interface by passing an `AbstractADType` to the sampler with the optional `adtype` argument, e.g.
55-
`NUTS(adtype = AutoZygote())`. See [Automatic Differentiation]({{<meta usage-automatic-differentiation>}}) for details. Generally, `adtype = AutoForwardDiff()` is likely to be the fastest and most reliable for models with
56-
few parameters (say, less than 20 or so), while reverse-mode backends such as `AutoZygote()` or `AutoReverseDiff()` will perform better for models with many parameters or linear algebra
57-
operations. If in doubt, it's easy to try a few different backends to see how they compare.
51+
For many common types of models, the default ForwardDiff backend performs well, and there is no need to worry about changing it.
52+
However, if you need more speed, you can try different backends via the standard [ADTypes](https://github.com/SciML/ADTypes.jl) interface by passing an `AbstractADType` to the sampler with the optional `adtype` argument, e.g. `NUTS(; adtype = AutoMooncake())`.
5853

59-
### Special care for Zygote
60-
61-
Note that Zygote will not perform well if your model contains `for`-loops, due to the way reverse-mode AD is implemented in these packages. Zygote also cannot differentiate code
62-
that contains mutating operations. If you can't implement your model without `for`-loops or mutation, `ReverseDiff` will be a better, more performant option. In general, though,
63-
vectorized operations are still likely to perform best.
64-
65-
Avoiding loops can be done using `filldist(dist, N)` and `arraydist(dists)`. `filldist(dist, N)` creates a multivariate distribution that is composed of `N` identical and independent
66-
copies of the univariate distribution `dist` if `dist` is univariate, or it creates a matrix-variate distribution composed of `N` identical and independent copies of the multivariate
67-
distribution `dist` if `dist` is multivariate. `filldist(dist, N, M)` can also be used to create a matrix-variate distribution from a univariate distribution `dist`. `arraydist(dists)`
68-
is similar to `filldist` but it takes an array of distributions `dists` as input. Writing a [custom distribution](advanced) with a custom adjoint is another option to avoid loops.
54+
Generally, `adtype = AutoForwardDiff()` is likely to be the fastest and most reliable for models with few parameters (say, less than 20 or so), while reverse-mode backends such as `AutoMooncake()` or `AutoReverseDiff()` will perform better for models with many parameters or linear algebra operations.
55+
If in doubt, you can benchmark your model with different backends to see which one performs best.
56+
See the [Automatic Differentiation]({{<meta usage-automatic-differentiation>}}) page for details.
6957

7058
### Special care for ReverseDiff with a compiled tape
7159

72-
For large models, the fastest option is often ReverseDiff with a compiled tape, specified as `adtype=AutoReverseDiff(true)`. However, it is important to note that if your model contains any
73-
branching code, such as `if`-`else` statements, **the gradients from a compiled tape may be inaccurate, leading to erroneous results**. If you use this option for the (considerable) speedup it
74-
can provide, make sure to check your code. It's also a good idea to verify your gradients with another backend.
60+
For large models, the fastest option is often ReverseDiff with a compiled tape, specified as `adtype=AutoReverseDiff(; compile=true)`.
61+
However, it is important to note that if your model contains any branching code, such as `if`-`else` statements, **the gradients from a compiled tape may be inaccurate, leading to erroneous results**.
62+
If you use this option for the (considerable) speedup it can provide, make sure to check your code for branching and ensure that it does not affect the gradients.
63+
It is also a good idea to verify your gradients with another backend.
7564

7665
## Ensure that types in your model can be inferred
7766

@@ -117,10 +106,10 @@ Alternatively, you could use `filldist` in this example:
117106
end
118107
```
119108

120-
Note that you can use `@code_warntype` to find types in your model definition that the compiler cannot infer.
121-
They are marked in red in the Julia REPL.
109+
You can use DynamicPPL's debugging utilities to find types in your model definition that the compiler cannot infer.
110+
These will be marked in red in the Julia REPL (much like when using the `@code_warntype` macro).
122111

123-
For example, consider the following simple program:
112+
For example, consider the following model:
124113

125114
```{julia}
126115
@model function tmodel(x)
@@ -131,22 +120,22 @@ For example, consider the following simple program:
131120
end
132121
```
133122

134-
We can use
123+
Because the element type of `p` is an abstract type (`Real`), the compiler cannot infer a concrete type for `p[1]`.
124+
To detect this, we can use
135125

136126
```{julia}
137127
#| eval: false
138-
using Random
139-
140128
model = tmodel(1.0)
141129
142-
@code_warntype model.f(
143-
model,
144-
Turing.VarInfo(model),
145-
Turing.SamplingContext(
146-
Random.default_rng(), Turing.SampleFromPrior(), Turing.DefaultContext()
147-
),
148-
model.args...,
149-
)
130+
using DynamicPPL
131+
DynamicPPL.DebugUtils.model_warntype(model)
150132
```
151133

152-
to inspect type inference in the model.
134+
In this particular model, the following call to `getindex` should be highlighted in red (the exact numbers may vary):
135+
136+
```
137+
[...]
138+
│ %120 = p::AbstractVector
139+
│ %121 = Base.getindex(%120, 1)::Any
140+
[...]
141+
```

0 commit comments

Comments
 (0)