Skip to content

Instantly share code, notes, and snippets.

@krishvishal
Forked from torfjelde/turing-ad-benchmark.jl
Created August 30, 2021 15:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krishvishal/cabf5133003626e0a01ad513789eb515 to your computer and use it in GitHub Desktop.
Save krishvishal/cabf5133003626e0a01ad513789eb515 to your computer and use it in GitHub Desktop.
Convenient code for benchmarking different AD-backends on a particular Turing.jl model.
# Use packages to ensure that we trigger Requires.jl.
using Zygote: Zygote
using ReverseDiff: ReverseDiff
using ForwardDiff: ForwardDiff
using Tracker: Tracker
using Memoization: Memoization # used for ReverseDiff.jl cache.
using Turing.Core: ForwardDiffAD, ReverseDiffAD, TrackerAD, ZygoteAD, CHUNKSIZE
const DEFAULT_ADBACKENDS = [
ForwardDiffAD{40}(), # chunksize=40
ForwardDiffAD{100}(), # chunksize=100
TrackerAD(),
ZygoteAD(),
ReverseDiffAD{false}(), # rdcache=false
ReverseDiffAD{true}() # rdcache=false
]
"""
make_turing_suite(model; kwargs...)
Create default benchmark suite for `model`.
# Keyword arguments
- `adbackends`: a collection of adbackends to use. Defaults to `$(DEFAULT_ADBACKENDS)`.
- `run_once=true`: if `true`, the body of each benchmark will be run once to avoid
compilation to be included in the timings (this may occur if compilation runs
longer than the allowed time limit).
- `save_grads=false`: if `true` and `run_once` is `true`, the gradients from the initial
execution will be saved and returned as the second return-value. This is useful if you
want to check correctness of the gradients for different backends.
# Notes
- A separate "parameter" instance (`DynamicPPL.VarInfo`) will be created for _each test_.
Hence if you have a particularly large model, you might want to only pass one `adbackend`
at the time.
"""
function make_turing_suite(model; adbackends=DEFAULT_ADBACKENDS, run_once=true, save_grads=false)
suite = BenchmarkGroup()
suite["not_linked"] = BenchmarkGroup()
suite["linked"] = BenchmarkGroup()
grads = Dict(:not_linked => Dict(), :linked => Dict())
vi_orig = DynamicPPL.VarInfo(model)
spl = DynamicPPL.SampleFromPrior()
for adbackend in adbackends
vi = DynamicPPL.VarInfo(model)
vi[spl] = deepcopy(vi_orig[spl])
if run_once
ℓ, ∇ℓ = Turing.Core.gradient_logp(
adbackend,
vi[spl],
vi,
model,
spl
)
if save_grads
grads[:not_linked][adbackend] = (ℓ, ∇ℓ)
end
end
suite["not_linked"]["$(adbackend)"] = @benchmarkable $(Turing.Core.gradient_logp)(
$adbackend,
$(vi[spl]),
$vi,
$model,
$spl
)
# Need a separate `VarInfo` for the linked version since otherwise we risk the
# `vi` from above being mutated.
vi_linked = deepcopy(vi)
DynamicPPL.link!(vi_linked, spl)
if run_once
ℓ, ∇ℓ = Turing.Core.gradient_logp(
adbackend,
vi_linked[spl],
vi_linked,
model,
spl
)
if save_grads
grads[:linked][adbackend] = (ℓ, ∇ℓ)
end
end
suite["linked"]["$(adbackend)"] = @benchmarkable $(Turing.Core.gradient_logp)(
$adbackend,
$(vi_linked[spl]),
$vi_linked,
$model,
$spl
)
end
return save_grads ? (suite, grads) : suite
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment