ConditionalDists.jl

Conditional probability distributions powered by DistributionsAD.jl
Author aicenter
Popularity
21 Stars
Updated Last
8 Months Ago
Started In
November 2019

Run tests codecov

ConditionalDists.jl

Conditional probability distributions powered by Flux.jl and DistributionsAD.jl.

The conditional PDFs that are defined in this package can be used in conjunction with Flux models to provide trainable mappings. As an example, assume you want to learn the mapping from a conditional to an MvNormal. The mapping m takes a vector x and maps it to a mean μ and a variance σ, which can be achieved by using a ConditionalDists.SplitLayer as the last layer in the network.

julia> m = Chain(Dense(2,2,σ), SplitLayer(2, [3,4]))
julia> m(rand(2))
(Float32[0.07946974, 0.13797458, 0.03939067], Float32[0.7006321, 0.37641272, 0.3586885, 0.82230335])

With the mapping m we can create a conditional distribution with trainable mapping parameters:

julia> using ConditionalDists, Distributions
julia> using ConditionalDists: SplitLayer

julia> xlength = 3
julia> zlength = 2
julia> batchsize = 10
julia> m = SplitLayer(zlength, [xlength,xlength])
julia> p = ConditionalMvNormal(m)

julia> res = condition(p, rand(zlength))  # this also works for batches!
julia> μ = mean(res)
julia> σ2 = var(res)
julia> @assert res isa DistributionsAD.TuringDiagMvNormal

julia> x = rand(xlength, batchsize)
julia> z = rand(zlength, batchsize)
julia> logpdf(p,x,z)
julia> rand(p, randn(zlength, 10))

The trainable parameters (of the SplitLayer) are accessible as usual through Flux.params. For different variance configurations (i.e. fixed/unit variance, etc) check the doc strings with julia>? ConditionalMvNormal/julia>? SplitLayer.

The next few lines show how to optimize p to match a given Gaussian by using the kl_divergence defined in IPMeasures.jl.

julia> using IPMeasures

julia> d = MvNormal(zeros(xlength), ones(xlength))
julia> loss(x) = sum(kl_divergence(p, d, x))
julia> opt = ADAM(0.1)
julia> data = [(randn(zlength),) for i in 1:2000]
julia> Flux.train!(loss, Flux.params(p), data, opt)

The learnt mean and variance are close to a standard normal:

julia> @assert condition(p, randn(zlength)) isa DistributionsAD.TuringDiagMvNormal
julia> mean(p,randn(zlength))
3-element Array{Float32,1}:
  0.003194877
  1.7912015f-32
 -1.6101733f-6

julia> var(p,randn(zlength))
3-element Array{Float32,1}:
 1.000585
 1.0021493
 1.0000007