|
18 | 18 | # Load DiffResults helpers
|
19 | 19 | include("DiffResults_helpers.jl")
|
20 | 20 |
|
21 |
| -struct ForwardDiffLogDensity{L, C} <: ADGradientWrapper |
| 21 | +struct ForwardDiffLogDensity{L, C <: ForwardDiff.Chunk, T <: Union{Nothing,ForwardDiff.Tag}, |
| 22 | + G <: Union{Nothing,ForwardDiff.GradientConfig}} <: ADGradientWrapper |
| 23 | + "supports zero-order evaluation `logdensity(ℓ, x)`" |
22 | 24 | ℓ::L
|
23 |
| - gradientconfig::C |
| 25 | + "chunk size for ForwardDiff" |
| 26 | + chunk::C |
| 27 | + "tag, or `nothing` for the default" |
| 28 | + tag::T |
| 29 | + "gradient config, or `nothing` if created for each evaluation" |
| 30 | + gradient_config::G |
24 | 31 | end
|
25 | 32 |
|
26 | 33 | function Base.show(io::IO, ℓ::ForwardDiffLogDensity)
|
27 | 34 | print(io, "ForwardDiff AD wrapper for ", ℓ.ℓ,
|
28 |
| - ", w/ chunk size ", length(ℓ.gradientconfig.seeds)) |
| 35 | + ", w/ chunk size ", ForwardDiff.chunksize(ℓ.chunk)) |
29 | 36 | end
|
30 | 37 |
|
31 | 38 | _chunk(chunk::ForwardDiff.Chunk) = chunk
|
32 | 39 | _chunk(chunk::Integer) = ForwardDiff.Chunk(chunk)
|
33 | 40 |
|
34 | 41 | _default_chunk(ℓ) = _chunk(dimension(ℓ))
|
35 | 42 |
|
36 |
| -_default_gradientconfig(ℓ, chunk, ::Nothing) = _default_gradientconfig(ℓ, chunk, zeros(dimension(ℓ))) |
37 |
| -function _default_gradientconfig(ℓ, chunk, x::AbstractVector) |
38 |
| - return ForwardDiff.GradientConfig(Base.Fix1(logdensity, ℓ), x, _chunk(chunk)) |
| 43 | +function Base.copy(fℓ::ForwardDiffLogDensity{L,C,T,<:ForwardDiff.GradientConfig}) where {L,C,T} |
| 44 | + @unpack ℓ, chunk, tag, gradient_config = fℓ |
| 45 | + ForwardDiffLogDensity(ℓ, chunk, tag, copy(gradient_config)) |
39 | 46 | end
|
40 | 47 |
|
41 | 48 | """
|
42 |
| - ADgradient(:ForwardDiff, ℓ; x, chunk, gradientconfig) |
43 |
| - ADgradient(Val(:ForwardDiff), ℓ; x, chunk, gradientconfig) |
| 49 | +$(SIGNATURES) |
| 50 | +
|
| 51 | +Make a `ForwardDiff.GradientConfig` for function `f` and input `x`. `tag = nothing` generates the default tag. |
| 52 | +""" |
| 53 | +function _make_gradient_config(f::F, x, chunk, tag) where {F} |
| 54 | + c = _chunk(chunk) |
| 55 | + gradient_config = if tag ≡ nothing |
| 56 | + ForwardDiff.GradientConfig(f, x, c) |
| 57 | + else |
| 58 | + ForwardDiff.GradientConfig(f, x, c, tag) |
| 59 | + end |
| 60 | + gradient_config |
| 61 | +end |
| 62 | + |
| 63 | +""" |
| 64 | + ADgradient(:ForwardDiff, ℓ; chunk, tag, x) |
| 65 | + ADgradient(Val(:ForwardDiff), ℓ; chunk, tag, x) |
44 | 66 |
|
45 | 67 | Wrap a log density that supports evaluation of `Value` to handle `ValueGradient`, using
|
46 | 68 | `ForwardDiff`.
|
47 | 69 |
|
48 |
| -Keywords are passed on to `ForwardDiff.GradientConfig` to customize the setup. In |
49 |
| -particular, chunk size can be set with a `chunk` keyword argument (accepting an integer or a |
50 |
| -`ForwardDiff.Chunk`), and the underlying vector used by `ForwardDiff` can be set with the |
51 |
| -`x` keyword argument (accepting an `AbstractVector`). |
| 70 | +Keyword arguments: |
| 71 | +
|
| 72 | +- `chunk` can be used to set the chunk size, an integer or a `ForwardDiff.Chunk` |
| 73 | +
|
| 74 | +- `tag` (default: `nothing`) can be used to set a tag for `ForwardDiff` |
| 75 | +
|
| 76 | +- `x` (default: `nothing`) will be used to preallocate a `ForwardDiff.GradientConfig` with |
| 77 | + the given vector. With the default, one is created for each evaluation. |
| 78 | +
|
| 79 | +Note that **pre-allocating a `ForwardDiff.GradientConfig` is not thread-safe**. You can |
| 80 | +[`copy`](@ref) the results for concurrent evaluation: |
| 81 | +```julia |
| 82 | +∇ℓ1 = ADgradient(:ForwardDiff, ℓ; x = zeros(dimension(ℓ))) |
| 83 | +∇ℓ2 = copy(∇ℓ1) # you can now use both, in different threads |
| 84 | +``` |
| 85 | +
|
| 86 | +See also the ForwardDiff documentation regarding |
| 87 | +[`ForwardDiff.GradientConfig`](https://juliadiff.org/ForwardDiff.jl/stable/user/api/#Preallocating/Configuring-Work-Buffers) |
| 88 | +and [chunks and tags](https://juliadiff.org/ForwardDiff.jl/stable/user/advanced/). |
52 | 89 | """
|
53 | 90 | function ADgradient(::Val{:ForwardDiff}, ℓ;
|
54 |
| - x::Union{Nothing,AbstractVector} = nothing, |
55 | 91 | chunk::Union{Integer,ForwardDiff.Chunk} = _default_chunk(ℓ),
|
56 |
| - gradientconfig::ForwardDiff.GradientConfig = _default_gradientconfig(ℓ, chunk, x)) |
57 |
| - ForwardDiffLogDensity(ℓ, gradientconfig) |
| 92 | + tag::Union{Nothing,ForwardDiff.Tag} = nothing, |
| 93 | + x::Union{Nothing,AbstractVector} = nothing) |
| 94 | + gradient_config = if x ≡ nothing |
| 95 | + nothing |
| 96 | + else |
| 97 | + _make_gradient_config(Base.Fix1(logdensity, ℓ), x, chunk, tag) |
| 98 | + end |
| 99 | + ForwardDiffLogDensity(ℓ, chunk, tag, gradient_config) |
58 | 100 | end
|
59 | 101 |
|
60 | 102 | function logdensity_and_gradient(fℓ::ForwardDiffLogDensity, x::AbstractVector)
|
61 |
| - @unpack ℓ, gradientconfig = fℓ |
| 103 | + @unpack ℓ, chunk, tag, gradient_config = fℓ |
62 | 104 | buffer = _diffresults_buffer(x)
|
63 |
| - result = ForwardDiff.gradient!(buffer, Base.Fix1(logdensity, ℓ), x, gradientconfig) |
| 105 | + ℓ′ = Base.Fix1(logdensity, ℓ) |
| 106 | + if gradient_config ≡ nothing |
| 107 | + gradient_config = _make_gradient_config(ℓ′, x, chunk, tag) |
| 108 | + end |
| 109 | + result = ForwardDiff.gradient!(buffer, ℓ′, x, gradient_config) |
64 | 110 | _diffresults_extract(result)
|
65 | 111 | end
|
66 | 112 |
|
|
0 commit comments