Model Fitting
Now that we’ve learnt to describe and build a model in describing your model, we want to put it to use! Keanu enables you to calculate the most probable values of components of your model given certain conditions or ‘observations’. More formally, these are known as posterior estimates, and we are going to look at how we can obtain these through an optimization method called Maximum A Posteriori (MAP).
Another technique for obtaining posterior estimates is through sampling. Read more about that on posterior-sampling. Sampling should be used when optimization techniques are not appropriate, e.g: you have discrete variables in your model.
Maximum A Posteriori
We are going to learn how to calculate posterior estimates of your model. Or, using Keanu terminology, enabling you to calculate the most likely value of latent vertices inside your Bayesian network.
We are going to calculate posterior estimates using an Optimizer. Keanu has two types of Optimizer:
- Gradient Optimizer
- Non-Gradient Optimizer
From the names it’s pretty obvious what the difference is. The Gradient Optimizer utilises gradients that are calculated on your bayesian network using Automatic-Differentiation (AD), whereas the Non-Gradient Optimizer does not use gradients. Automatic Differentiation may sound technical and scary, but don’t worry, Keanu handles all the calculations for you! All you have to focus on is describing your model.
“Which one do I use then?” I hear you ask. “How do I know if my model can make use of gradients?”
Well it depends on whether your latent variables (the ones we’re going to find the most probable value of) are continuous or discrete. Keanu does not support gradient optimisation on discrete latents. Still not sure? Don’t worry, Keanu can analyse your model and determine whether or not to use gradients for you. The next section will teach you how to use this.
Optimizer
Let’s say you’ve described the thermometer model and want to run MAP but you’re not sure whether to use the Gradient or Non-Gradient Optimizer. You can use the following code to let Keanu decide which one to use.
BayesianNetwork bayesNet = new BayesianNetwork(temperature.getConnectedGraph());
Optimizer optimizer = KeanuOptimizer.of(bayesNet);
optimizer.maxAPosteriori();
double calculatedTemperature = temperature.getValue().scalar();
The Optimizer mutates the values of the graph while finding the most probable values and leaves the graph in its
most optimal state. Therefore, to find the most probable value of a vertex once, simply get the value
of the vertex.
Gradient Optimizer
This section will focus on the parameters available to you on the Gradient Optimizer. A builder is available for the Gradient Optimizer that lets you change any combination of the default parameters. The snippet below demonstrates how to use the builder to change all of the available parameters.
Java
GradientOptimizer optimizer = KeanuOptimizer.Gradient.builderFor(temperature.getConnectedGraph())
.maxEvaluations(5000)
.relativeThreshold(1e-8)
.absoluteThreshold(1e-8)
.build();
optimizer.maxAPosteriori();
double calculatedTemperature = temperature.getValue().scalar();
bayesianNetwork
(required) - The Bayesian Network (model) to run the Optimizer onmaxEvaluations
(default: max int) - The max number of iterations the Optimizer goes through before terminatingrelativeThreshold
(default: 1e-8) - If the delta in the log prob is less than the log prob times relativeThreshold, the Optimizer has convergedabsoluteThreshold
(default: 1e-8) - If the delta in the log prob is less than absoluteThreshold, the Optimizer has converged
Python
optimizer = GradientOptimizer(bayes_net, max_evaluations=5000,
relative_threshold=1e-8, absolute_threshold=1e-8)
optimizer.max_a_posteriori()
calculated_temperature = model.temperature.get_value()
Non-Gradient Optimizer
The Non-Gradient Optimizer implements the BOBYQA algorithm, which stands for Bound Optimization BY Quadratic Approximation. It attempts to find the minimum of a black box objective function by forming a quadratic approximation in a trust region and finding the solution of the approximation.
This section will focus on the parameters available to you on the Non-Gradient Optimizer. A builder is available for the Non-Gradient Optimizer that lets you change any combination of the default parameters. The snippet below demonstrates how to use the builder to change all of the available parameters.
Java
OptimizerBounds temperatureBounds = new OptimizerBounds().addBound(temperature.getId(), -250., 250.0);
NonGradientOptimizer optimizer = KeanuOptimizer.NonGradient.builderFor(temperature.getConnectedGraph())
.maxEvaluations(5000)
.boundsRange(100000)
.optimizerBounds(temperatureBounds)
.initialTrustRegionRadius(5.)
.stoppingTrustRegionRadius(2e-8)
.build();
optimizer.maxAPosteriori();
double calculatedTemperature = temperature.getValue().scalar();
bayesianNetwork
(required) - The Bayesian Network (model) to run the Optimizer onmaxEvaluations
(default: max int) - The max number of iterations the Optimizer goes through before terminatingboundsRange
(default: positive infinity) - a bounding box of ‘allowed values’ that the Optimizer can try around the starting pointoptimizerBounds
(default: no bounds) - a bounding box of ‘allowed values’ for a specific vertexinitialTrustRegionRadius
(default: 10) - initial trust region radius (refer to BOBYQA paper for detail)stoppingTrustRegionRadius
(default: 1e-8) - stopping trust region radius (refer to BOBYQA paper for detail)
Python
optimizer = NonGradientOptimizer(bayes_net, max_evaluations=5000, bounds_range=100000.,
initial_trust_region_radius=5., stopping_trust_region_radius=2e-8)
optimizer.max_a_posteriori()
calculated_temperature = model.temperature.get_value()