VariationalPosterior#
Note
The main output of a PyVBMC run is a VariationalPosterior object vp.
The variational posterior can be queried and manipulated via several methods, such as:
moments: compute mean and covariance matrix of the variational posterior;pdf: evaluate the variational posterior density at a point;plot: plot the variational posterior as a corner plot (1D and 2D marginals);sample: draw random samples from the variational posterior.to_torch(): export an independent torch distribution;to_arviz(): export independent draws in the current ArviZ DataTree format.
There are also methods to compare variational posteriors:
kl_div: compute the Kullback-Leibler divergence between two posteriors;mtv: compute the marginal total variation distance between two posteriors.
See below for the full VariationalPosterior class methods and interface.
Density gradients from pdf and log_pdf are available in transformed
coordinates (orig_flag=False). Requests for gradients in the original
parameter space raise NotImplementedError.
Performance settings#
A fitted posterior retains the fixed CalibrationProfile used by its
VBMC run. Standalone posteriors use historical defaults; pass
calibration=profile or calibration="cached" to opt in. A cache lookup
never initiates a campaign. See calibrate for measuring
settings and the reproducibility contract.
- class pyvbmc.variational_posterior.VariationalPosterior(D: int, K: int = 2, x0=None, parameter_transformer=None, rng=None, calibration=None)[source]#
The variational posterior class used in PyVBMC.
The variational posterior represents the approximate posterior as returned by the Variational Bayesian Monte Carlo (VBMC) algorithm.
In VBMC, the variational posterior is a weighted mixture of multivariate normal distributions (see Notes below for details).
- Parameters:
- Dint
The number of dimensions (i.e., parameters) of the posterior.
- Kint, optional
The number of mixture components, default 2.
- x0np.ndarray, optional
The starting points for the mixture component means, one per row. A single point of D elements, given as a flat array, a row or a column, starts every component; a 1-by-1 array starts every coordinate of every component; an n0-by-D matrix starts the components at its rows, repeated in order where n0 is below K and cut after the K-th row where it is above. By default
np.zeros.- parameter_transformerParameterTransformer, optional
The
ParameterTransformerobject specifying the transformation of the input space that leads to the current representation used by the variational posterior, by default uses an identity transform.- rngNone, int, SeedSequence or np.random.Generator, optional
The random generator, or a seed for one, used by every method that draws random numbers (e.g.
sample,kl_div,mtv). AGeneratoris used as is, so it can be shared with aVBMCinstance. By default a generator is derived from NumPy’s global random state, so thatnp.random.seedstill gives reproducible results.- calibrationCalibrationProfile, {“cached”, “off”}, or None, optional
Fixed numerical chunk settings.
Noneand"off"use the historical defaults."cached"defers a machine-local cache lookup until the first density or Monte Carlo entropy evaluation.
- Attributes:
- wnp.ndarray
The weights of the VP mixture components, shape
(1, K).- etanp.ndarray
The unbounded (softmax) parametrization of the VP mixture components, shape
(1, K).- munp.ndarray
The means of the VP mixture components, shape
(D, K).- sigmanp.ndarray
The per-component scale of the VP mixture components. Shape
(1, K).- lambdnp.ndarray
The per-dimension scale of the VP mixture components. Shape
(D, 1).- optimize_weightsbool
Whether to optimize the weights.
- optimize_mubool
Whether to optimize the means.
- optimize_sigmabool
Whether to optimize
sigma.- optimize_lambdbool
Whether to optimize
lambd.- parameter_transformerParameterTransformer
The parameter transformer implementing transformations to/from unbounded space.
- boundsdict
A dictionary containing the soft bounds for each variable to be optimized, as
get_boundslast computed them, orNonebefore the first call.- statsdict
A dictionary of statistics and other relevant info computed during optimization.
calibration_profileCalibrationProfile or NoneThe fixed profile, or
Nonebefore a cached request resolves.
Notes
In VBMC, the variational posterior is defined as a mixture of multivariate normal distributions as follows:
\[q({\theta}) = \sum_{k = 1}^K w_k N(\theta, \mu_k, \sigma^2_k \Lambda)\]where \(w_k\) are the mixture weights, \(\mu_k\) the component means, \(\sigma_k\) scaling factors, and \(\Lambda\) is a diagonal matrix common to all components with elements \(\lambda^2_d\) on the diagonal, for \(1 \le d \le D\).
Note that \(q({\theta})\) is defined in an unconstrained space. Constrained variables in the posterior are mapped to a transformed, unconstrained space via a nonlinear mapping (represented by a
ParameterTransformerobject). The transformation is handled automatically.In practice, you would almost never create a new
VariationalPosteriorobject, simply use the variational posteriors returned byVBMC.- property calibration_profile: CalibrationProfile | None#
The fixed profile, or
Nonebefore a cached request resolves.
- get_bounds(X: ndarray, options, K: int = None)[source]#
Compute soft bounds for variational posterior parameters.
These bounds are used during the variational optimization in
VBMC. They are a function of the training inputs given here: the component means are bounded by the bounding box of those inputs, and their log scale (the product ofsigmaandlambd) by the log of the width of that box, down to a fractiontol_lengthof it. The bounds on the weight parameters span the weights above half the weight tolerance. The box is also stored on the posterior asbounds, replacing any box of an earlier call.- Parameters:
- Xndarray, shape (N, D)
Training inputs.
- optionsOptions
Program options.
- Kint, optional
The number of mixture components. By default we use the number provided at class instantiation.
- Returns:
- theta_bnddict
- A dictionary of soft bounds with the following elements:
- lbnp.ndarray
Lower bounds.
- ubnp.ndarray
Upper bounds.
- tol_confloat
Fractional tolerance for constraint violation of variational parameters.
- weight_thresholdfloat, optional
Threshold below which weights are penalized.
- weight_penaltyfloat, optional
The penalty for weight below the threshold.
- get_parameters(raw_flag=True)[source]#
Get variational posterior parameters as single array.
Return all the active
VariationalPosteriorparameters flattened as a 1D (numpy) array, possibly transformed.The parameters are first normalized in place:
lambdis divided by its root mean square andsigmamultiplied by it, and the weights are divided by their sum when they are being optimized. The two scales enter the density through their product alone, so rescaling does not change the distribution. Normalizing the weights changes it only if they did not already sum to one. A mode cached by a previous call tomode()is discarded because the parameters may have changed.- Parameters:
- raw_flagbool, optional
Specifies whether the scales
sigmaandlambdand the weightsware returned as raw (unconstrained) parameters, their logarithms, or as they are, by defaultTrue.
- Returns:
- thetanp.ndarray
The variational posterior parameters flattened as a 1D array.
- kl_div(vp2: VariationalPosterior = None, samples: ndarray = None, N: int = 100000, gauss_flag: bool = False)[source]#
Kullback-Leibler divergence between two variational posteriors.
Compute the forward and reverse Kullback-Leibler (KL) divergence between two posteriors. The other variational posterior can be specified as vp2 (an instance of the class
VariationalPosterior) or with samples. One of the two must be specified.- Parameters:
- vp2VariationalPosterior, optional
The other
VariationalPosterior, by default None.- samplesnp.ndarray, optional
An N-by-D matrix of samples from the other variational posterior, by default
None.- Nint, optional
The number of random samples to estimate the KL divergence, by default
int(1e5).- gauss_flagbool, optional
If
True, returns a “Gaussianized” KL-divergence, that is the KL divergence between two multivariate normal distributions with the same moments as the variational posteriors given as inputs. By defaultFalse.
- Returns:
- kl_div: np.ndarray
A two-element vector containing the forward and reverse Kullback-Leibler divergence between the two posteriors.
- Raises:
- ValueError
Raised if neither vp2 nor samples are specified.
- ValueError
Raised if vp2 is not provided but gauss_flag =
False.- ValueError
Raised if gauss_flag is
Trueand N is 0: the moments are estimated from N samples in the original space.
Notes
Since the KL divergence is not symmetric, the method returns both the forward and the reverse KL divergence, that is KL(vp1 || vp2) and KL(vp2 || vp1).
- classmethod load(file, *, calibration=None)[source]#
Load a VP from a file.
- Parameters:
- filepath-like
The file name or path to read from. Default file extension .pkl will be added if no extension is specified.
- calibrationCalibrationProfile, {“cached”, “off”}, or None, optional
For a posterior saved while its calibration request (
"cached") was still pending, the settings that replace the request;Noneleaves it pending. For a posterior with resolved settings,None, a profile with the same settings, and"off"where the saved settings are the historical defaults keep the saved profile and its provenance; any other value raises.
- Returns:
- vpVariationalPosterior
The loaded VP instance.
- Raises:
- OSError
If the file cannot be found, or cannot be opened for other reasons.
- ValueError
If calibration asks for other settings than the resolved ones the file holds (
"cached","off"where the saved settings are not the historical defaults, or a profile with other settings), or is not one of the accepted values.
- log_pdf(*args, **kwargs)[source]#
log-probability density function of the variational posterior.
Compute the log density of the variational posterior at one or multiple input points. The parameters are the same as for
vp.pdf()withlog_flag=True. These parameters are described again here for reference.- Parameters:
- xnp.ndarray
x is a matrix of inputs to evaluate the pdf at. The rows of the N-by-D matrix x correspond to observations or points, and columns correspond to variables or coordinates. x is assumed to be in the original space by default. A one-dimensional array is one point, so for
D = 1several points go in a column.- orig_flagbool, optional
Controls if the value of the posterior density should be evaluated in the original parameter space for orig_flag is
True, or in the transformed space if orig_flag isFalse, by defaultTrue. Accordingly, x should be in the original space if orig_flag isTrueand be in the transformed space if orig_flag is False.- grad_flagbool, optional
If
Truethe gradient of the log-pdf is returned as a second output, by defaultFalse. Gradients are available only in transformed space (orig_flag=False).- dffloat, optional
Compute the log-pdf of a heavy-tailed version of the variational posterior, in which the multivariate normal components have been replaced by multivariate t-distributions with df degrees of freedom. The default is df =
np.inf, limit in which the t-distribution becomes a multivariate normal. A negative df replaces them instead by products of D univariate t-distributions withabs(df)degrees of freedom;df = 0also gives the normal components.
- Returns:
- log_pdf: np.ndarray
The log probability density of the variational posterior evaluated at each row of x.
- gradient: np.ndarray
If grad_flag is
True, the function returns the gradient as well.
- Raises:
- ValueError
Raised if the rows of x are not D wide.
- NotImplementedError
Raised if df is non-zero and finite and grad_flag =
True(Gradient of heavy-tailed pdf not supported yet).- NotImplementedError
Raised if orig_flag =
Trueand grad_flag =True(gradient computation in original space is not supported).
- mode(orig_flag=True, n_opts: int | None = None)[source]#
Find the mode of the variational posterior.
- Parameters:
- orig_flagbool, optional
If
Truefind the mode of the variational posterior in the original parameter space, otherwise in the transformed parameter space. By defaultTrue.- n_optsint, optional
Maximum number of optimization runs from different starting points to find the mode. By default n_opts is the square root of the number of mixture components K, that is \(n\_opts = \lceil \sqrt{K} \rceil\). A call in the original space that leaves n_opts out returns the mode that an earlier such call found, if the posterior still carries one, and otherwise stores the mode it finds. A call in the transformed space, or one that gives n_opts, runs the search and neither reads nor replaces that stored mode.
- Returns:
- modenp.ndarray
The mode of the variational posterior.
Notes
Mode estimation (e.g., for the purpose of maximum-a-posteriori estimation) is not recommended with VBMC, since due to the underlying representation (mixture of Gaussians) the mode of the variational posterior is a brittle and potentially unreliable estimator of the mode of the target posterior, especially if it lies close to the boundaries of the space.
The mode is not invariant to nonlinear reparameterizations of the input space, so the mode in the original space and the mode in the transformed (unconstrained) space will generally be in different locations (even after applying the appropriate transformations).
The starting points of the optimization runs are drawn from a copy of
self.rng, so a call leaves the posterior’s random stream where it found it, and two calls with nothing drawn from that stream in between give the same answer.
- moments(N: int = 1000000, orig_flag=True, cov_flag=False)[source]#
Compute mean and covariance matrix of variational posterior.
In the original space, the moments are estimated via Monte Carlo sampling. If requested in the transformed (unconstrained) space used internally by VBMC, the moments can be computed analytically.
- Parameters:
- Nint, optional
Number of samples used to estimate the moments in the original space, as any scalar that holds a whole number (see sample). By default
int(1e6).- orig_flagbool, optional
If
True, compute moments in the original parameter space, otherwise in the transformed VBMC space. By defaultTrue.- cov_flagbool, optional
If
True, return the covariance matrix as a second return value, by defaultFalse.
- Returns:
- mean: np.ndarray
The mean of the variational posterior, of shape
(1, D).- cov: np.ndarray
If cov_flag is
True, returns the covariance matrix as well, of shape(D, D).
- Raises:
- ValueError
Raised in the original space if N is not a scalar holding a whole number of samples.
- mtv(vp2: VariationalPosterior = None, samples: ndarray = None, N: int = 100000)[source]#
Marginal total variation distances between two variational posteriors.
Compute the total variation distance between the variational posterior and a second posterior, separately for each dimension (hence “marginal” total variation distance, MTV). The second posterior can be specified either as a
VariationalPosterioror as a set of samples.- Parameters:
- vp2VariationalPosterior, optional
The other
VariationalPosterior, by defaultNone.- samplesnp.ndarray, optional
An N-by-D matrix of samples from the other variational posterior, by default
None.- Nint, optional
The number of random draws to estimate the MTV, by default
int(1e5).
- Returns:
- mtvnp.ndarray
An array of shape
(1, D)holding, for each coordinate, the total variation distance between the marginal distributions of this posterior and of vp2 or samples.
- Raises:
- ValueError
Raised if neither vp2 nor samples are specified.
Notes
The total variation distance between two densities \(p_1\) and \(p_2\) is:
\[TV(p_1, p_2) = \frac{1}{2} \int | p_1(x) - p_2(x) | dx.\]
- pdf(x: ndarray, orig_flag: bool = True, log_flag: bool = False, grad_flag: bool = False, df: float = inf)[source]#
Probability density function of the variational posterior.
Compute the probability density function (pdf) of the variational posterior at one or multiple input points.
- Parameters:
- xnp.ndarray
x is a matrix of inputs to evaluate the pdf at. The rows of the N-by-D matrix x correspond to observations or points, and columns correspond to variables or coordinates. x is assumed to be in the original space by default. A one-dimensional array is one point, so for
D = 1several points go in a column.- orig_flagbool, optional
Controls if the value of the posterior density should be evaluated in the original parameter space for orig_flag is
True, or in the transformed space if orig_flag isFalse, by defaultTrue. Accordingly, x should be in the original space if orig_flag isTrueand be in the transformed space if orig_flag is False.- log_flagbool, optional
If log_flag is
Truereturn the logarithm of the pdf, by defaultFalse. Where the density of the mixture of normal components is below the smallest normal double, its logarithm and the gradient of the logarithm are computed by log-sum-exp over the components, so that they stay finite in the far tails.- grad_flagbool, optional
If
Truethe gradient of the pdf is returned as a second output, by defaultFalse. Gradients are available only in transformed space (orig_flag=False).- dffloat, optional
Compute the pdf of a heavy-tailed version of the variational posterior, in which the multivariate normal components have been replaced by multivariate t-distributions with df degrees of freedom. The default is df =
np.inf, limit in which the t-distribution becomes a multivariate normal. A negative df replaces them instead by products of D univariate t-distributions withabs(df)degrees of freedom;df = 0also gives the normal components.
- Returns:
- pdf: np.ndarray
The probability density of the variational posterior evaluated at each row of x.
- gradient: np.ndarray
If grad_flag is
True, the function returns the gradient as well.
- Raises:
- ValueError
Raised if the rows of x are not D wide.
- NotImplementedError
Raised if df is non-zero and finite and grad_flag =
True(Gradient of heavy-tailed pdf not supported yet).- NotImplementedError
Raised if orig_flag =
Trueand grad_flag =True(gradient computation in the original space is not supported).
- plot(n_samples: int = 100000, title: str = None, plot_data: bool = False, highlight_data: np.ndarray = None, plot_vp_centres: bool = False, plot_style: dict = None, gp: GaussianProcess = None)[source]#
Plot the variational posterior.
plot displays the variational posterior as a cornerplot showing the 1D and 2D marginals, estimated from samples. It uses the corner package.
plot also optionally displays the centres of the variational mixture components and the datapoints of the underlying Gaussian process (GP) used by
VBMC. The plot can be enhanced by custom styles and specific datapoints of the GP can be highlighted.- Parameters:
- n_samplesint, optional
The number of posterior samples used to create the plot, by default
int(1e5).- titlestr, optional
The title of the plot, by default
None.- plot_databool, optional
Whether to plot the datapoints of the GP, by default
False.- highlight_datanp.ndarray, optional
Indices of the GP datapoints that should be plotted in a different way than the other datapoints, by default
None.- plot_vp_centresbool, optional
Whether to plot the centres of the vp components, by default
False.- plot_styledict, optional
- A dictionary of plot styling options. The possible options are:
- cornerdict, optional
Styling options directly passed to the corner function. By default:
{"fig": plt.figure(figsize=(6, 6)), "labels": labels}. See the documentation of corner.- datadict, optional
Styling options used to plot the GP data. By default:
{"s":15, "color":'blue', "facecolors": "none"}.- highlight_datadict, optional
Styling options used to plot the highlighted GP data. By default:
{"s":15, "color":"orange"}.- vp_centredict, optional
Styling options used to plot the vp centres. By default:
{"marker":"x", "color":"red"}.
- gpgpyreg.GaussianProcess, optional
The GP to use for plotting actively sampled points.
- Returns:
- figmatplotlib.figure.Figure
The resulting
matplotlibfigure of the plot.
- property rng: Generator#
The random generator used by every method of this object that draws random numbers (
sample,kl_div,mtv,plot, …). Copies made withcopy.deepcopyshare the same generator, so that all copies of a variational posterior draw from a single random stream.
- sample(N: int, orig_flag: bool = True, balance_flag: bool = False, df: float = inf)[source]#
Draw random samples from the variational posterior.
- Parameters:
- Nint
Number of samples to draw, as any scalar that holds a whole number: a float such as
1e5, a NumPy scalar or a 0-D array is taken as that number of samples.- orig_flagbool, optional
If orig_flag is
True, the random vectors are returned in the original parameter space. IfFalse, they are returned in the transformed, unconstrained space used internally by VBMC. By defaultTrue.- balance_flagbool, optional
If balance_flag is
True, the generating process is balanced such that the random samples come from each mixture component exactly proportionally (or as close as possible) to the variational mixture weights. IfFalse, the generating mixture component for each sample is determined randomly, according to the mixture weights. By defaultFalse.- dffloat, optional
Generate the samples from a heavy-tailed version of the variational posterior, in which the multivariate normal components have been replaced by multivariate t-distributions with df degrees of freedom. The default is
np.inf, limit in which the t-distribution becomes a multivariate normal. A finite negative df is refused:pdfreads it as the product of D univariate t densities, a family this method cannot draw from.
- Returns:
- Xnp.ndarray
X is an N-by-D matrix of random vectors drawn from the variational posterior.
- Inp.ndarray
I is an N-element array of integers such that the i-th element of I indicates the index of the variational mixture component from which the i-th row of X has been generated.
- Raises:
- ValueError
Raised if N is not a scalar holding a whole number of samples.
- ValueError
Raised if df is finite and negative (the product of univariate t densities has no sampler here).
Notes
Random draws use
self.rng.
- save(file, overwrite=False)[source]#
Save the VP to a file.
The file holds no Python bytecode, so it can be loaded, used and saved again under another minor version of Python than the one that wrote it.
- Parameters:
- filepath-like
The file name or path to write to. Default file extension .pkl will be added if no extension is specified.
- overwritebool
Whether to allow overwriting existing files. Default False.
- Raises:
- FileExistsError
If the file already exists and
overwriteis False.- OSError
If the file cannot be opened for other reasons (e.g., the directory is not found, the disk is full, etc.).
- set_parameters(theta: ndarray, raw_flag=True)[source]#
Set variational posterior parameters from a single array.
Takes as input a
numpyarray and assigns it to the variational posterior parameters.eta, the unbounded (softmax) parametrization of the mixture weights, is set alongsidew, so thatsoftmax(eta)is the resultingw.When both
sigmaandlambdare optimized,lambdis then divided by its root mean square andsigmamultiplied by it. The two scales enter the density through their product alone, so that rescaling leaves the distribution as it was. A scale that is not optimized keeps its value and the other takes the value intheta, so that the parameters set are a function ofthetaalone. The weights are divided by their sum when they are being optimized.- Parameters:
- thetanp.ndarray
The array with the parameters that should be assigned.
- raw_flagbool, optional
Specifies whether the scales
sigmaandlambdand the weights are passed as raw (unconstrained) parameters or as they are, by defaultTrue. The raw scales are their logarithms, and the raw weights are the parameters of a softmax: the weights are their exponentials, normalized to sum to one.
- Raises:
- ValueError
Raised if raw_flag is
Falseand a scale or a weight in theta is negative.
Export methods#
The export methods have dedicated API pages: