public void LearnTest12()
{
// Suppose we have a set of six sequences and we would like to
// fit a hidden Markov model with mixtures of Normal distributions
// as the emission densities.
// First, let's consider a set of univariate sequences:
double[][] sequences =
{
new double[] { -0.223, -1.05, -0.574, 0.965, -0.448, 0.265, 0.087, 0.362, 0.717, -0.032 },
new double[] { -1.05, -0.574, 0.965, -0.448, 0.265, 0.087, 0.362, 0.717, -0.032, -0.346 },
new double[] { -0.574, 0.965, -0.448, 0.265, 0.087, 0.362, 0.717, -0.032, -0.346, -0.989 },
new double[] { 0.965, -0.448, 0.265, 0.087, 0.362, 0.717, -0.032, -0.346, -0.989, -0.619 },
new double[] { -0.448, 0.265, 0.087, 0.362, 0.717, -0.032, -0.346, -0.989, -0.619, 0.02 },
new double[] { 0.265, 0.087, 0.362, 0.717, -0.032, -0.346, -0.989, -0.619, 0.02, -0.297 },
};
// Now we can begin specifying a initial Gaussian mixture distribution. It is
// better to add some different initial parameters to the mixture components:
var density = new Mixture<NormalDistribution>(
new NormalDistribution(mean: 2, stdDev: 1.0), // 1st component in the mixture
new NormalDistribution(mean: 0, stdDev: 0.6), // 2nd component in the mixture
new NormalDistribution(mean: 4, stdDev: 0.4), // 3rd component in the mixture
new NormalDistribution(mean: 6, stdDev: 1.1) // 4th component in the mixture
);
// Let's then create a continuous hidden Markov Model with two states organized in a forward
// topology with the underlying univariate Normal mixture distribution as probability density.
var model = new HiddenMarkovModel<Mixture<NormalDistribution>, double>(new Forward(2), density);
// Now we should configure the learning algorithms to train the sequence classifier. We will
// learn until the difference in the average log-likelihood changes only by as little as 0.0001
var teacher = new BaumWelchLearning<Mixture<NormalDistribution>, double>(model)
{
Tolerance = 0.0001,
Iterations = 0,
// Note, however, that since this example is extremely simple and we have only a few
// data points, a full-blown mixture wouldn't really be needed. Thus we will have a
// great chance that the mixture would become degenerated quickly. We can avoid this
// by specifying some regularization constants in the Normal distribution fitting:
FittingOptions = new MixtureOptions()
{
Iterations = 1, // limit the inner e-m to a single iteration
InnerOptions = new NormalOptions()
{
Regularization = 1e-5 // specify a regularization constant
}
}
};
// Finally, we can fit the model
teacher.Learn(sequences);
double logLikelihood = teacher.LogLikelihood;
// And now check the likelihood of some approximate sequences.
double[] newSequence = { -0.223, -1.05, -0.574, 0.965, -0.448, 0.265, 0.087, 0.362, 0.717, -0.032 };
double a1 = Math.Exp(model.Evaluate(newSequence)); // 11729312967893.566
int[] path = model.Decode(newSequence);
// We can see that the likelihood of an unrelated sequence is much smaller:
double a3 = Math.Exp(model.Evaluate(new double[] { 8, 2, 6, 4, 1 })); // 0.0
Assert.IsTrue(a1 > 1e+10);
Assert.IsTrue(a3 < 1e+10);
}