Tutorial 6: Mixture of GaussiansThis tutorial shows how to make a mixture of multivariate Gaussians and fit it to some data. It will introduce the switch block which allows variable-sized mixtures to be constructed. You can run the code in this tutorial either using the Examples Browser or by opening the Tutorials solution in Visual Studio and executing MixtureOfGaussians.cs. Parameters priorsBeing Bayesian, we need to define priors on each of the parameters of our model. To do this, we start by defining a range for the number of mixture components:
Using this range, we create an array for the means of our mixture components and give them priors:
The first line creates an array of Vector variables of size k. The second line assigns a multivariate Gaussian prior to each element of the array. Notice the use of ForEach(k) to duplicate the prior across the array. We define an array of PositiveDefiniteMatrix precision variables in a similar fashion but using Wishart priors instead of Gaussian:
The final parameter is the vector of mixture weights, which has a Dirichlet prior.
Notice that we pass the range k as the first parameter. This tells Infer.NET that the size of the vector weights is given by the range k. Mixing it togetherNow that we have defined variables for each of the parameters of the model, we are almost ready to construct the mixture model. But first, we must create a VariableArray for the data:
and for each data point, we need a variable to indicate which mixture component the data point came from
Now we can construct the mixture model. We use a ForEach block to loop over z and give each element of z a prior given by the weights. Then we use a Switch block to assign each data point to be drawn from the Gaussian with the mean and precision given by the element of z.
And there we have it - a fully Bayesian multivariate Gaussian mixture model. Breaking symmetryWe can now attach some data and run inference. For example data, we use a function which generates data from a known mixture of Gaussians model (see the tutorial file for the code of this function). We then use Variational Message Passing to infer posterior distributions over the weights, means and precisions.
If we run this code, the result is:
This is not a good result - the two mixture components are identical! The reason for this is that our model is symmetrical - all the mixture components are defined in exactly the same way and so they are not distinguished during inference. This problem can be resolved by introducing small random perturbations in the initial messages used in message passing, thus breaking the symmetry between mixture components. Infer.NET does not do this automatically, because it normally guarantees to give the same result each time you perform inference - introducing random initialisation would break this contract. Instead, you are required to break symmetry explicitly. In this example, we can achieve this using InitialiseTo() to randomise the initial message for z, as follows:
If we now run the inference again, we get the following result (note that results may be different on different runs due to the randomness that we have introduced):
Now we can see that the two mixture components are different and that we have a good solution. Inference using InferAll()In the above, we made separate calls to infer posterior over weights, means and precisions. This can be inefficient since Infer does not know the complete set of variables that will be requested, and therefore must generate code conservatively to infer marginals for variables that may never be requested. To avoid this (usually small) overhead, we can make use of the method InferAll to specify a specific set of variables to perform inference for. InferAll takes an array of type
|


