API reference
Public
DifferentiableExpectations.DifferentiableExpectations
— ModuleDifferentiableExpectations
A Julia package for differentiating through expectations with Monte-Carlo estimates.
Exports
DifferentiableExpectations.DifferentiableExpectation
— TypeDifferentiableExpectation{t}
Abstract supertype for differentiable parametric expectations E : θ -> 𝔼[f(X)]
where X ∼ p(θ)
, whose value and derivative are approximated with Monte-Carlo averages.
Subtypes
Calling behavior
(E::DifferentiableExpectation)(θ...; kwargs...)
Return a Monte-Carlo average (1/S) ∑f(xᵢ)
where the xᵢ ∼ p(θ)
are iid samples.
Type parameters
threaded::Bool
: specifies whether the sampling should be performed in parallel
Required fields
f
: The function applied inside the expectation.dist_constructor
: The constructor of the probability distribution.rng::AbstractRNG
: The random number generator.nb_samples::Integer
: The number of Monte-Carlo samples.seed
::Union{Nothing,Integer}: The seed for the random number generator, reset before each call. Set tonothing
for no seeding.
The field dist_constructor
must be a callable such that dist_constructor(θ...)
generates an object dist
that corresponds to p(θ)
. The resulting object dist
needs to satisfy:
- the Random API for sampling with
rand(rng, dist)
- the DensityInterface.jl API for loglikelihoods with
logdensityof(dist, x)
DifferentiableExpectations.FixedAtomsProbabilityDistribution
— TypeFixedAtomsProbabilityDistribution{threaded}
A probability distribution with finite support and fixed atoms.
Whenever its expectation is differentiated, only the weights are considered active, whereas the atoms are considered constant.
Example
julia> using DifferentiableExpectations, Statistics, Zygote
julia> using DifferentiableExpectations: atoms, weights
julia> dist = FixedAtomsProbabilityDistribution([2, 3], [0.4, 0.6]);
julia> atoms(map(abs2, dist))
2-element Vector{Int64}:
4
9
julia> weights(map(abs2, dist))
2-element Vector{Float64}:
0.4
0.6
julia> mean(abs2, dist)
7.0
julia> gradient(mean, abs2, dist)[2]
(atoms = nothing, weights = [4.0, 9.0])
Constructor
FixedAtomsProbabilityDistribution(
atoms::AbstractVector,
weights::AbstractVector=uniform_weights(atoms);
threaded=false
)
Fields
atoms::AbstractVector
weights::AbstractVector{<:Real}
DifferentiableExpectations.Reinforce
— TypeReinforce{threaded} <: DifferentiableExpectation{threaded}
Differentiable parametric expectation F : θ -> 𝔼[f(X)]
where X ∼ p(θ)
using the REINFORCE (or score function) gradient estimator:
∂F(θ) = 𝔼[f(X) ∇₂logp(X,θ)ᵀ]
Example
using DifferentiableExpectations, Distributions, Zygote
E = Reinforce(exp, Normal; nb_samples=10^5)
E_true(μ, σ) = mean(LogNormal(μ, σ))
μ, σ = 0.5, 1,0
∇E, ∇E_true = gradient(E, μ, σ), gradient(E_true, μ, σ)
isapprox(collect(∇E), collect(∇E_true); rtol=1e-1)
# output
true
Constructor
Reinforce(
f,
dist_constructor,
dist_logdensity_grad=nothing;
rng=Random.default_rng(),
nb_samples=1,
threaded=false,
seed=nothing
)
Fields
f::Any
: function applied inside the expectationdist_constructor::Any
: constructor of the probability distribution(θ...) -> p(θ)
dist_logdensity_grad::Any
: eithernothing
or a parameter gradient callable(x, θ...) -> ∇₂logp(x, θ)
rng::Random.AbstractRNG
: random number generatornb_samples::Int64
: number of Monte-Carlo samplesseed::Union{Nothing, Int64}
: seed for the random number generator, reset before each call. Set tonothing
for no seeding.
See also
DifferentiableExpectations.Reparametrization
— TypeReparametrization{threaded} <: DifferentiableExpectation{threaded}
Differentiable parametric expectation F : θ -> 𝔼[f(X)]
where X ∼ p(θ)
using the reparametrization (or pathwise) gradient estimator: if X = g(Z,θ)
where Z ∼ q
then
∂F(θ) = 𝔼_q[∂f(g(Z,θ)) ∂₂g(Z,θ)ᵀ]
Example
using DifferentiableExpectations, Distributions, Zygote
E = Reparametrization(exp, Normal; nb_samples=10^4)
E_true(μ, σ) = mean(LogNormal(μ, σ))
μ, σ = 0.5, 1,0
∇E, ∇E_true = gradient(E, μ, σ), gradient(E_true, μ, σ)
isapprox(collect(∇E), collect(∇E_true); rtol=1e-1)
# output
true
Constructor
Reparametrization(
f,
dist_constructor,
rng=Random.default_rng(),
nb_samples=1,
threaded=false,
seed=nothing
)
Fields
f::Any
: function applied inside the expectationdist_constructor::Any
: constructor of the probability distribution(θ...) -> p(θ)
rng::Random.AbstractRNG
: random number generatornb_samples::Int64
: number of Monte-Carlo samplesseed::Union{Nothing, Int64}
: seed for the random number generator, reset before each call. Set tonothing
for no seeding.
See also
DifferentiableExpectations.empirical_distribution
— Methodempirical_distribution(E::DifferentiableExpectation, θ...; kwargs...)
Return a uniform FixedAtomsProbabilityDistribution
over {f(x₁), ..., f(xₛ)}
, where the xᵢ ∼ p(θ)
are iid samples.
Private
DifferentiableExpectations.FixKwargs
— TypeFixKwargs(f, kwargs)
Callable struct that fixes the keyword arguments of f
to kwargs...
, and only accepts positional arguments.
DifferentiableExpectations.TransformedDistribution
— TypeTransformedDistribution
Represent the probability distribution p
of a random variable X ∼ p
with a transformation X = T(Z)
where Z ∼ q
.
Fields
base_dist::Any
: the distributionq
that gets transformed intop
transformation::Any
: the transformation functionT
Base.map
— Methodmap(f, dist::FixedAtomsProbabilityDistribution)
Apply f
to the atoms of dist
, leave the weights unchanged.
Base.rand
— Methodrand(rng, dist::TransformedDistribution)
Sample from dist
by applying dist.transformation
to dist.base_dist
.
Base.rand
— Methodrand(rng, dist::FixedAtomsProbabilityDistribution)
Sample from the atoms of dist
with probability proportional to their weights.
DifferentiableExpectations.atoms
— Methodatoms(dist::FixedAtomsProbabilityDistribution)
Get the vector of atoms of a distribution.
DifferentiableExpectations.empirical_predistribution
— Methodempirical_predistribution(E::DifferentiableExpectation, θ...)
Return a uniform FixedAtomsProbabilityDistribution
over {x₁, ..., xₛ}
, where the xᵢ ∼ p(θ)
are iid samples.
DifferentiableExpectations.maybe_eachcol
— Methodmaybe_eachcol(x::AbstractMatrix)
Return eachcol(x)
.
DifferentiableExpectations.maybe_eachcol
— Methodmaybe_eachcol(x::AbstractVector)
Return x
.
DifferentiableExpectations.mymap
— Methodmymap(::Val{threaded}, args...)
Apply either tmap(args...)
or map(args...)
depending on the value of threaded
.
DifferentiableExpectations.mymapreduce
— Methodmymapreduce(::Val{threaded}, args...)
Apply either tmapreduce(args...)
or mapreduce(args...)
depending on the value of threaded
.
DifferentiableExpectations.reparametrize
— Functionreparametrize(dist)
Turn a probability distribution p
into a TransformedDistribution
(q, T)
such that the new distribution q
does not depend on the parameters of p
. These parameters are encoded (closed over) in the transformation function T
.
DifferentiableExpectations.weights
— Methodweights(dist::FixedAtomsProbabilityDistribution)
Get the vector of weights of a distribution.
Statistics.mean
— Methodmean(f, dist::FixedAtomsProbabilityDistribution)
Shortcut for mean(map(f, dist))
.
Statistics.mean
— Methodmean(dist::FixedAtomsProbabilityDistribution)
Compute the expectation of dist
, i.e. the sum of all atoms multiplied by their respective weights.