Learning a prior distribution
Neural estimators are usually trained with parameters drawn from a known prior distribution. Sometimes, however, prior knowledge comes in the form of samples: for example, parameter estimates from many previous analyses of related data, or posterior draws from an earlier analysis (e.g., Schmidli et al., 2014; Roch and Shen, 2026).
Here, we use a PriorEstimator to fit a flexible distribution to such samples (i.e., unconditional density estimation). The trained estimator can be used to sample from the learned distribution (e.g., to simulate training data for another neural estimator), to evaluate its density (e.g., as the prior of a RatioEstimator), and to map parameters to the latent space of a normalising flow, where unusual parameter vectors can be flagged.
Package dependencies
using NeuralEstimators
using Flux
using CairoMakie
using Distributions: Chisq, quantileTo improve computational efficiency, various GPU backends are supported. Once the relevant package is loaded and a compatible GPU is available, it will be used automatically:
using CUDA, cuDNNusing AMDGPUusing Metalusing oneAPISamples from the target distribution
In practice, the samples would be, for example, existing parameter estimates, stored as a NamedMatrix), where
sampler(K) = NamedMatrix(μ = randn(K), σ = rand(K))
θ_train = sampler(100_000)
θ_val = sampler(100_000)
d = size(θ_train, 1) # dimension of the parameter vectorStandardising the parameters
A PriorEstimator does not standardise the parameters. When they are on very different scales, standardise each parameter before training (e.g., subtract its mean and divide by its standard deviation, both computed from the training samples), and apply the inverse transformation to samples from the learned distribution.
Constructing the estimator
By default, a PriorEstimator approximates the distribution with a NormalisingFlow. Other Approximate distributions can be used through the keyword argument q:
estimator = PriorEstimator(d)Training the estimator
We train the estimator with train, passing the training and validation samples. No data or simulator are needed:
estimator = train(estimator, θ_train, θ_val; batchsize = 256)Training progress is reported in the terminal:

If new samples can be drawn at will, one may instead pass the function that draws them, train(estimator, sampler; K = 100_000), in which case new samples are drawn during training.
The risk is the average of
where
The risk over the course of training can be plotted using plotrisk:
plotrisk()
Assessing the estimator
The function assess compares draws from the learned distribution with test samples from the true distribution. The resulting Assessment contains the risk, here the average negative log density of the test samples under the learned distribution, which estimates the expected risk discussed above. The draws can be visualised with plot(assessment), which compares the marginal distributions of
θ_test = sampler(100_000) # test samples from the true distribution
assessment = assess(estimator, θ_test) # compares 100,000 draws from the learned distribution with θ_test
risk(assessment) # ≈ 1.44, slightly above its lower bound H(p) ≈ 1.42
plot(assessment)
The learned distribution closely matches the true distribution. Since a normalising flow is a smooth transformation of a Gaussian distribution, it slightly smooths the sharp boundaries of the uniform distribution of
With three or more parameters, plot(assessment) gives a pairs plot, and plot(assessment; plots = :marginals) gives the marginal histograms alone. If no test samples are available, assess(estimator) can be used to visualise the learned distribution alone.
Evaluating the learned distribution
The density of the learned distribution is evaluated with logdensity, and forward and inverse map between the parameter space and the latent space of the normalising flow:
θ = sampler(5)
logdensity(estimator, θ) # log density of each parameter vector
U = forward(estimator, θ) # latent representation of each parameter vector
inverse(estimator, U) ≈ θ # the flow is invertibleFor parameter vectors drawn from the learned distribution, the latent representation is standard Gaussian, so that its squared norm approximately follows a
θ_new = NamedMatrix(μ = [0.1, -1.2, 8.0], σ = [0.5, 0.2, 0.5]) # the third vector is unusual
U = forward(estimator, θ_new)
r² = vec(sum(abs2, U; dims = 1))
r² .> quantile(Chisq(d), 0.999) # flags the third vector