public static void Main(string[] args) { var data = new Sequences("nbt.1882-S6.txt"); // Now we create a hidden Markov model with arbitrary probabilities var hmm = new HiddenMarkovModel(states: data.StateNum, symbols: data.SymbolNum); // Create a Baum-Welch learning algorithm to teach it var teacher = new BaumWelchLearning(hmm); // and call its Run method to start learning var trainSamples = data.PartOfSequences(0, 2); double error = teacher.Run(trainSamples); var testSamples = data.PartOfSequences(1, 2); // Let's now check the probability of some sequences: double prob1 = Math.Exp(hmm.Evaluate(trainSamples [0])); double prob2 = Math.Exp(hmm.Evaluate(trainSamples [1])); double prob3 = Math.Exp(hmm.Evaluate(trainSamples [2])); // Now those obviously violate the form of the training set: double prob4 = Math.Exp(hmm.Evaluate(testSamples [0])); double prob5 = Math.Exp(hmm.Evaluate(testSamples [1])); }
static void runArbitraryDensityHiddenMarkovModelLearningExample() { // Create continuous sequences. // In the sequences below, there seems to be two states, one for values between 0 and 1 and another for values between 5 and 7. // The states seems to be switched on every observation. double[][] observationSequences = new double[][] { new double[] { 0.1, 5.2, 0.3, 6.7, 0.1, 6.0 }, new double[] { 0.2, 6.2, 0.3, 6.3, 0.1, 5.0 }, new double[] { 0.1, 7.0, 0.1, 7.0, 0.2, 5.6 }, }; // Creates a continuous hidden Markov Model with two states organized in a ergoric topology // and an underlying univariate Normal distribution as probability density. var hmm = new HiddenMarkovModel <NormalDistribution>(topology: new Ergodic(states: 2), emissions: new NormalDistribution()); // Configure the learning algorithms to train the sequence classifier // until the difference in the average log-likelihood changes only by as little as 0.0001. var trainer = new BaumWelchLearning <NormalDistribution>(hmm) { Tolerance = 0.0001, Iterations = 0, }; // Fit the model. double averageLogLikelihood = trainer.Run(observationSequences); Console.WriteLine("average log-likelihood for the observations = {0}", averageLogLikelihood); // The log-probability of the sequences learned. double logLik1 = hmm.Evaluate(new[] { 0.1, 5.2, 0.3, 6.7, 0.1, 6.0 }); // -0.12799388666109757. double logLik2 = hmm.Evaluate(new[] { 0.2, 6.2, 0.3, 6.3, 0.1, 5.0 }); // 0.01171157434400194. // The log-probability of an unrelated sequence. double logLik3 = hmm.Evaluate(new[] { 1.1, 2.2, 1.3, 3.2, 4.2, 1.0 }); // -298.7465244473417. // Transform the log-probabilities to actual probabilities. Console.WriteLine("probability = {0}", Math.Exp(logLik1)); // 0.879. Console.WriteLine("probability = {0}", Math.Exp(logLik2)); // 1.011. Console.WriteLine("probability = {0}", Math.Exp(logLik3)); // 0.000. // Ask the model to decode one of the sequences. // The state variable will contain: { 0, 1, 0, 1, 0, 1 }. double logLikelihood = 0.0; int[] path = hmm.Decode(new[] { 0.1, 5.2, 0.3, 6.7, 0.1, 6.0 }, out logLikelihood); Console.Write("log-likelihood = {0}, Viterbi path = [", logLikelihood); foreach (int state in path) { Console.Write("{0},", state); } Console.WriteLine("]"); }
public static void Evaluate() { double[,] transition = { { 0.7, 0.3 }, { 0.4, 0.6 } }; double[,] emission = { { 0.1, 0.4, 0.5 }, { 0.6, 0.3, 0.1 } }; double[] initial = { 0.6, 0.4 }; HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); int[] sequence = new int[] { 0, 1, 2 }; double logLikeliHood = hmm.Evaluate(sequence); // At this point, the log-likelihood of the sequence // occurring within the model is -3.3928721329161653. Console.WriteLine("logLikeliHood: {0}", logLikeliHood); }
public static double BaumWelchLearning(double[][] data) { // Specify a initial normal distribution for the samples. NormalDistribution density = new NormalDistribution(); // Creates a continuous hidden Markov Model with two states organized in a forward // topology and an underlying univariate Normal distribution as probability density. var model = new HiddenMarkovModel <NormalDistribution>(new Ergodic(2), density); // Configure the learning algorithms to train the sequence classifier until the // difference in the average log-likelihood changes only by as little as 0.0001 var teacher = new BaumWelchLearning <NormalDistribution>(model) { Tolerance = 0.001, Iterations = 0, }; // Fit the model double likelihood = teacher.Run(data); // See the log-probability of the sequences learned double a1 = model.Evaluate(new[] { 0.999999999999928, 0, 0.999999999999988, 0, 0.999999999999988 }); // -0.12799388666109757 return(a1); }
public void LikelihoodTest() { var hmm = DiscreteHiddenMarkovModelFunctionTest.CreateModel2(); int states = hmm.States; int symbols = hmm.Symbols; var hcrf = new ConditionalRandomField <int>(states, new MarkovDiscreteFunction(hmm)); var hmm0 = new HiddenMarkovModel(states, symbols); var hcrf0 = new ConditionalRandomField <int>(states, new MarkovDiscreteFunction(hmm0)); int[] observations = new int[] { 0, 0, 1, 1, 1, 2 }; double la = hcrf.LogLikelihood(observations, observations); double lb = hcrf0.LogLikelihood(observations, observations); Assert.IsTrue(la > lb); double lc = hmm.Evaluate(observations, observations); double ld = hmm0.Evaluate(observations, observations); Assert.IsTrue(lc > ld); double za = hcrf.LogPartition(observations); double zb = hcrf0.LogPartition(observations); la += za; lb += zb; Assert.AreEqual(la, lc, 1e-6); Assert.AreEqual(lb, ld, 1e-6); }
public void GenerateTest() { // Example taken from http://en.wikipedia.org/wiki/Viterbi_algorithm double[,] transition = { { 0.7, 0.3 }, { 0.4, 0.6 } }; double[,] emission = { { 0.1, 0.4, 0.5 }, { 0.6, 0.3, 0.1 } }; double[] initial = { 0.6, 0.4 }; HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); double logLikelihood; int[] path; int[] samples = hmm.Generate(10, out path, out logLikelihood); double expected = hmm.Evaluate(samples, path); Assert.AreEqual(expected, logLikelihood); }
public double Run(int[][] observations_db) { int K = observations_db.Length; double currLogLikelihood = Double.NegativeInfinity; for (int k = 0; k < K; ++k) { currLogLikelihood = LogHelper.LogSum(currLogLikelihood, mModel.Evaluate(observations_db[k])); } double oldLogLikelihood = -1; double deltaLogLikelihood = -1; int iteration = 0; do { oldLogLikelihood = currLogLikelihood; int[][] paths_db = new int[K][]; for (int k = 0; k < K; ++k) { paths_db[k] = mModel.Decode(observations_db[k]); } mMaximumLikelihoodLearner.Run(observations_db, paths_db); currLogLikelihood = double.NegativeInfinity; for (int k = 0; k < K; ++k) { currLogLikelihood = LogHelper.LogSum(currLogLikelihood, mModel.Evaluate(observations_db[k])); } deltaLogLikelihood = System.Math.Abs(currLogLikelihood - oldLogLikelihood); iteration++; }while(!ShouldTerminate(deltaLogLikelihood, iteration)); return(currLogLikelihood); }
public void DecodeTest() { // Example taken from http://en.wikipedia.org/wiki/Viterbi_algorithm // Create the transition matrix A double[,] transition = { { 0.7, 0.3 }, { 0.4, 0.6 } }; // Create the emission matrix B double[,] emission = { { 0.1, 0.4, 0.5 }, { 0.6, 0.3, 0.1 } }; // Create the initial probabilities pi double[] initial = { 0.6, 0.4 }; // Create a new hidden Markov model HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); // After that, one could, for example, query the probability // of a sequence occurring. We will consider the sequence int[] sequence = new int[] { 0, 1, 2 }; // And now we will evaluate its likelihood double logLikelihood = hmm.Evaluate(sequence); // At this point, the log-likelihood of the sequence // occurring within the model is -3.3928721329161653. // We can also get the Viterbi path of the sequence int[] path = hmm.Decode(sequence, out logLikelihood); // At this point, the state path will be 1-0-0 and the // log-likelihood will be -4.3095199438871337 Assert.AreEqual(logLikelihood, Math.Log(0.01344), 1e-10); Assert.AreEqual(path[0], 1); Assert.AreEqual(path[1], 0); Assert.AreEqual(path[2], 0); }
/// <summary> /// Returns a dictionary of Markov probabilities for all supplied sequences /// </summary> /// <param name="sequences"></param> /// <returns></returns> public Dictionary <string, double> GetMarkovProbabilities(List <string> sequences) { Dictionary <string, double> probabilities = new Dictionary <string, double>(); //determine probability for each sequence foreach (string sequence in sequences) { //each sequence is in the form "#-#-#...-#". We need to conver this into an array of //integers for use in the markov model int[] sequenceNumbers = sequence.Split('_').Select(m => Convert.ToInt32(m)).ToArray(); //store probability in dictionary for use elsewhere probabilities[sequence] = Math.Exp(_model.Evaluate(sequenceNumbers)); } return(probabilities); }
static void runDiscreteDensityHiddenMarkovModelExample() { // Create the transition matrix A. double[,] transition = { { 0.7, 0.3 }, { 0.4, 0.6 } }; // Create the emission matrix B. double[,] emission = { { 0.1, 0.4, 0.5 }, { 0.6, 0.3, 0.1 } }; // Create the initial probabilities pi. double[] initial = { 0.6, 0.4 }; // Create a new hidden Markov model. HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); // Query the probability of a sequence occurring. int[] sequence = new int[] { 0, 1, 2 }; // Evaluate its likelihood. double logLikelihood = hmm.Evaluate(sequence); // The log-likelihood of the sequence occurring within the model is -3.3928721329161653. Console.WriteLine("log-likelihood = {0}", logLikelihood); // Get the Viterbi path of the sequence. int[] path = hmm.Decode(sequence, out logLikelihood); // The state path will be 1-0-0 and the log-likelihood will be -4.3095199438871337. Console.Write("log-likelihood = {0}, Viterbi path = [", logLikelihood); foreach (int state in path) { Console.Write("{0},", state); } Console.WriteLine("]"); }
static void runArbitraryDensityHiddenMarkovModelExample() { // Create the transition matrix A. double[,] transitions = { { 0.7, 0.3 }, { 0.4, 0.6 } }; // Create the vector of emission densities B. GeneralDiscreteDistribution[] emissions = { new GeneralDiscreteDistribution(0.1, 0.4, 0.5), new GeneralDiscreteDistribution(0.6, 0.3, 0.1) }; // Create the initial probabilities pi. double[] initial = { 0.6, 0.4 }; // Create a new hidden Markov model with discrete probabilities. var hmm = new HiddenMarkovModel <GeneralDiscreteDistribution>(transitions, emissions, initial); // Query the probability of a sequence occurring. We will consider the sequence. double[] sequence = new double[] { 0, 1, 2 }; // Evaluate its likelihood. double logLikelihood = hmm.Evaluate(sequence); // The log-likelihood of the sequence occurring within the model is -3.3928721329161653. Console.WriteLine("log-likelihood = {0}", logLikelihood); // Get the Viterbi path of the sequence. int[] path = hmm.Decode(sequence, out logLikelihood); // The state path will be 1-0-0 and the log-likelihood will be -4.3095199438871337. Console.Write("log-likelihood = {0}, Viterbi path = [", logLikelihood); foreach (int state in path) { Console.Write("{0},", state); } Console.WriteLine("]"); }
public static void ViterbiLearning() { int[][] sequences = new int[][] { new int[] { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }; // Creates a new Hidden Markov Model with 3 states for // an output alphabet of two characters (zero and one) HiddenMarkovModel hmm = new HiddenMarkovModel(state_count: 3, symbol_count: 2); // Try to fit the model to the data until the difference in // the average log-likelihood changes only by as little as 0.0001 var teacher = new ViterbiLearning(hmm) { Tolerance = 0.0001, Iterations = 0 }; double ll = teacher.Run(sequences); // Calculate the probability that the given // sequences originated from the model double l1 = hmm.Evaluate(new int[] { 0, 1 }); // 0.999 double l2 = hmm.Evaluate(new int[] { 0, 1, 1, 1 }); // 0.916 Console.WriteLine("l1: {0}", System.Math.Exp(l1)); Console.WriteLine("l2: {0}", System.Math.Exp(l2)); // Sequences which do not start with zero have much lesser probability. double l3 = hmm.Evaluate(new int[] { 1, 1 }); // 0.000 double l4 = hmm.Evaluate(new int[] { 1, 0, 0, 0 }); // 0.000 Console.WriteLine("l3: {0}", System.Math.Exp(l3)); Console.WriteLine("l4: {0}", System.Math.Exp(l4)); // Sequences which contains few errors have higher probability // than the ones which do not start with zero. This shows some // of the temporal elasticity and error tolerance of the HMMs. double l5 = hmm.Evaluate(new int[] { 0, 1, 0, 1, 1, 1, 1, 1, 1 }); // 0.034 double l6 = hmm.Evaluate(new int[] { 0, 1, 1, 1, 1, 1, 1, 0, 1 }); // 0.034 Console.WriteLine("l5: {0}", System.Math.Exp(l5)); Console.WriteLine("l6: {0}", System.Math.Exp(l6)); }
public static void BaumWelchLearning() { // We will try to create a Hidden Markov Model which // can detect if a given sequence starts with a zero // and has any number of ones after that. int[][] sequences = new int[][] { new int[] { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }; // Creates a new Hidden Markov Model with 3 states for // an output alphabet of two characters (zero and one) HiddenMarkovModel hmm = new HiddenMarkovModel(3, 2); // Try to fit the model to the data until the difference in // the average log-likelihood changes only by as little as 0.0001 var teacher = new BaumWelchLearning(hmm) { Tolerance = 0.0001, Iterations = 0 }; double ll = teacher.Run(sequences); double l0 = Math.Exp(hmm.Evaluate(new int[] { 1, 0 })); // Calculate the probability that the given // sequences originated from the model double l1 = Math.Exp(hmm.Evaluate(new int[] { 0, 1 })); // 0.999 double l2 = Math.Exp(hmm.Evaluate(new int[] { 0, 1, 1, 1 })); // 0.916 // Sequences which do not start with zero have much lesser probability. double l3 = Math.Exp(hmm.Evaluate(new int[] { 1, 1 })); // 0.000 double l4 = Math.Exp(hmm.Evaluate(new int[] { 1, 0, 0, 0 })); // 0.000 // Sequences which contains few errors have higher probability // than the ones which do not start with zero. This shows some // of the temporal elasticity and error tolerance of the HMMs. double l5 = Math.Exp(hmm.Evaluate(new int[] { 0, 1, 0, 1, 1, 1, 1, 1, 1 })); // 0.034 double l6 = Math.Exp(hmm.Evaluate(new int[] { 0, 1, 1, 1, 1, 1, 1, 0, 1 })); // 0.034 }
public static void Viterbi() { // Create the transition matrix A double[,] transition = { { 0.7, 0.3 }, { 0.4, 0.6 } }; // Create the emission matrix B double[,] emission = { { 0.1, 0.4, 0.5 }, { 0.6, 0.3, 0.1 } }; // Create the initial probabilities pi double[] initial = { 0.6, 0.4 }; // Create a new hidden Markov model HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); // After that, one could, for example, query the probability // of a sequence occurring. We will consider the sequence int[] sequence = new int[] { 0, 1, 2 }; // And now we will evaluate its likelihood double logLikelihood = hmm.Evaluate(sequence); // At this point, the log-likelihood of the sequence // occurring within the model is -3.3928721329161653. // We can also get the Viterbi path of the sequence int[] path = hmm.Decode(sequence, out logLikelihood); // At this point, the state path will be 1-0-0 and the // log-likelihood will be -4.3095199438871337 }
public static void Viterbi() { // Create the transition matrix A double[,] transition = { { 1.0 / 3, 1.0 / 3, 1.0 / 3 }, { 1.0 / 3, 1.0 / 3, 1.0 / 3 }, { 1.0 / 3, 1.0 / 3, 1.0 / 3 } }; // Create the emission matrix B double[,] emission = { { 1.0 / 4, 1.0 / 4, 1.0 / 4, 1.0 / 4, 0, 0, 0, 0 }, { 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6, 0, 0 }, { 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8 }, }; // Create the initial probabilities pi double[] initial = { 0.3, 0.3, 0.4 }; //var pS = new double[] { 1.0 / 3, 1.0 / 3, 1.0 / 3 }; //var p4N = new double[] { 1.0 / 4, 1.0 / 4, 1.0 / 4, 1.0 / 4 }; //var p6N = new double[] { 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6, 1.0 / 6 }; //var p8N = new double[] { 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8, 1.0 / 8 }; //var pN = new double[][] { p4N, p6N, p8N }; HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); int[] sequence = new int[] { 1, 6, 3 }; double logLikelihood = hmm.Evaluate(sequence); int[] path = hmm.Decode(sequence, out logLikelihood); }
public void LearnTest2() { // Declare some testing data int[][] inputs = new int[][] { new int[] { 0,0,1,2 }, // Class 0 new int[] { 0,1,1,2 }, // Class 0 new int[] { 0,0,0,1,2 }, // Class 0 new int[] { 0,1,2,2,2 }, // Class 0 new int[] { 2,2,1,0 }, // Class 1 new int[] { 2,2,2,1,0 }, // Class 1 new int[] { 2,2,2,1,0 }, // Class 1 new int[] { 2,2,2,2,1 }, // Class 1 }; int[] outputs = new int[] { 0,0,0,0, // First four sequences are of class 0 1,1,1,1, // Last four sequences are of class 1 }; // We are trying to predict two different classes int classes = 2; // Each sequence may have up to 3 symbols (0,1,2) int symbols = 3; // Nested models will have 3 states each int[] states = new int[] { 3, 3 }; // Creates a new Hidden Markov Model Classifier with the given parameters HiddenMarkovClassifier classifier = new HiddenMarkovClassifier(classes, states, symbols); // Create a new learning algorithm to train the sequence classifier var teacher = new HiddenMarkovClassifierLearning(classifier, // Train each model until the log-likelihood changes less than 0.001 modelIndex => new BaumWelchLearning(classifier.Models[modelIndex]) { Tolerance = 0.001, Iterations = 0 } ); // Enable support for sequence rejection teacher.Rejection = true; // Train the sequence classifier using the algorithm double likelihood = teacher.Run(inputs, outputs); HiddenMarkovModel threshold = classifier.Threshold; Assert.AreEqual(6, threshold.States); Assert.AreEqual(classifier.Models[0].Transitions[0, 0], threshold.Transitions[0, 0], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[1, 1], threshold.Transitions[1, 1], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[2, 2], threshold.Transitions[2, 2], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[0, 0], threshold.Transitions[3, 3], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[1, 1], threshold.Transitions[4, 4], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[2, 2], threshold.Transitions[5, 5], 1e-10); for (int i = 0; i < 3; i++) for (int j = 3; j < 6; j++) Assert.AreEqual(Double.NegativeInfinity, threshold.Transitions[i, j]); for (int i = 3; i < 6; i++) for (int j = 0; j < 3; j++) Assert.AreEqual(Double.NegativeInfinity, threshold.Transitions[i, j]); Assert.IsFalse(Matrix.HasNaN(threshold.Transitions)); classifier.Sensitivity = 0.5; // Will assert the models have learned the sequences correctly. for (int i = 0; i < inputs.Length; i++) { int expected = outputs[i]; int actual = classifier.Compute(inputs[i], out likelihood); Assert.AreEqual(expected, actual); } int[] r0 = new int[] { 1, 1, 0, 0, 2 }; double logRejection; int c = classifier.Compute(r0, out logRejection); Assert.AreEqual(-1, c); Assert.AreEqual(0.99906957195279988, logRejection); Assert.IsFalse(double.IsNaN(logRejection)); logRejection = threshold.Evaluate(r0); Assert.AreEqual(-4.5653702970734793, logRejection, 1e-10); Assert.IsFalse(double.IsNaN(logRejection)); threshold.Decode(r0, out logRejection); Assert.AreEqual(-8.21169955167614, logRejection, 1e-10); Assert.IsFalse(double.IsNaN(logRejection)); foreach (var model in classifier.Models) { double[,] A = model.Transitions; for (int i = 0; i < A.GetLength(0); i++) { double[] row = A.Exp().GetRow(i); double sum = row.Sum(); Assert.AreEqual(1, sum, 1e-10); } } { double[,] A = classifier.Threshold.Transitions; for (int i = 0; i < A.GetLength(0); i++) { double[] row = A.GetRow(i); double sum = row.Exp().Sum(); Assert.AreEqual(1, sum, 1e-6); } } }
public void LearnTest6() { Accord.Math.Tools.SetupGenerator(0); // We will try to create a Hidden Markov Model which // can detect if a given sequence starts with a zero // and has any number of ones after that. // int[][] sequences = new int[][] { new int[] { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }; // Creates a new Hidden Markov Model with 3 states for // an output alphabet of two characters (zero and one) // HiddenMarkovModel hmm = new HiddenMarkovModel(new Forward(3), 2); // Try to fit the model to the data until the difference in // the average log-likelihood changes only by as little as 0.0001 // var teacher = new ViterbiLearning(hmm) { Tolerance = 0.0001, Iterations = 0 }; double ll = teacher.Run(sequences); // Calculate the probability that the given // sequences originated from the model double l1 = hmm.Evaluate(new int[] { 0, 1 }); // 0.613 double l2 = hmm.Evaluate(new int[] { 0, 1, 1, 1 }); // 0.500 // Sequences which do not start with zero have much lesser probability. double l3 = hmm.Evaluate(new int[] { 1, 1 }); // 0.186 double l4 = hmm.Evaluate(new int[] { 1, 0, 0, 0 }); // 0.003 // Sequences which contains few errors have higher probability // than the ones which do not start with zero. This shows some // of the temporal elasticity and error tolerance of the HMMs. // double l5 = hmm.Evaluate(new int[] { 0, 1, 0, 1, 1, 1, 1, 1, 1 }); // 0.033 double l6 = hmm.Evaluate(new int[] { 0, 1, 1, 1, 1, 1, 1, 0, 1 }); // 0.026 double pl = System.Math.Exp(ll); double p1 = System.Math.Exp(l1); double p2 = System.Math.Exp(l2); double p3 = System.Math.Exp(l3); double p4 = System.Math.Exp(l4); double p5 = System.Math.Exp(l5); double p6 = System.Math.Exp(l6); Assert.AreEqual(1.754393540912413, pl, 1e-6); Assert.AreEqual(0.61368718756104801, p1, 1e-6); Assert.AreEqual(0.50049466955818356, p2, 1e-6); Assert.AreEqual(0.18643340385264684, p3, 1e-6); Assert.AreEqual(0.00300262431355424, p4, 1e-6); Assert.AreEqual(0.03338686211012481, p5, 1e-6); Assert.AreEqual(0.02659161933179825, p6, 1e-6); Assert.IsTrue(l1 > l3 && l1 > l4); Assert.IsTrue(l2 > l3 && l2 > l4); }
/// <summary> /// Runs the Maximum Likelihood learning algorithm for hidden Markov models. /// </summary> /// /// <param name="observations">An array of observation sequences to be used to train the model.</param> /// <param name="paths">An array of state labels associated to each observation sequence.</param> /// /// <returns> /// The average log-likelihood for the observations after the model has been trained. /// </returns> /// /// <remarks> /// Supervised learning problem. Given some training observation sequences O = {o1, o2, ..., oK}, /// known training state paths H = {h1, h2, ..., hK} and general structure of HMM (numbers of /// hidden and visible states), determine HMM parameters M = (A, B, pi) that best fit training data. /// </remarks> /// public double Run(Array[] observations, int[][] paths) { // Convert the generic representation to a vector of multivariate sequences double[][][] obs = observations as double[][][]; if (obs == null) { obs = new double[observations.Length][][]; for (int i = 0; i < observations.Length; i++) { obs[i] = convert(observations[i], model.Dimension); } } // Grab model information int N = observations.Length; int states = model.States; int[] initial = new int[states]; int[,] transitions = new int[states, states]; // 1. Count first state occurrences for (int i = 0; i < paths.Length; i++) { initial[paths[i][0]]++; } // 2. Count all state transitions foreach (int[] path in paths) { for (int j = 1; j < path.Length; j++) { transitions[path[j - 1], path[j]]++; } } if (useWeights) { int totalObservations = 0; for (int i = 0; i < obs.Length; i++) { totalObservations += obs[i].Length; } double[][] weights = new double[states][]; for (int i = 0; i < weights.Length; i++) { weights[i] = new double[totalObservations]; } double[][] all = new double[totalObservations][]; for (int i = 0, c = 0; i < paths.Length; i++) { for (int t = 0; t < paths[i].Length; t++, c++) { int state = paths[i][t]; all[c] = obs[i][t]; weights[state][c] = 1; } } for (int i = 0; i < model.States; i++) { model.Emissions[i].Fit(all, weights[i], fittingOptions); } } else { // 3. Count emissions for each state List <double[]>[] clusters = new List <double[]> [model.States]; for (int i = 0; i < clusters.Length; i++) { clusters[i] = new List <double[]>(); } // Count symbol frequencies per state for (int i = 0; i < paths.Length; i++) { for (int t = 0; t < paths[i].Length; t++) { int state = paths[i][t]; double[] symbol = obs[i][t]; clusters[state].Add(symbol); } } // Estimate probability distributions for (int i = 0; i < model.States; i++) { if (clusters[i].Count > 0) { model.Emissions[i].Fit(clusters[i].ToArray(), null, fittingOptions); } } } // 4. Form log-probabilities, using the Laplace // correction to avoid zero probabilities if (useLaplaceRule) { // Use Laplace's rule of succession correction // http://en.wikipedia.org/wiki/Rule_of_succession for (int i = 0; i < initial.Length; i++) { initial[i]++; for (int j = 0; j < states; j++) { transitions[i, j]++; } } } // Form probabilities int initialCount = initial.Sum(); int[] transitionCount = transitions.Sum(1); for (int i = 0; i < initial.Length; i++) { model.Probabilities[i] = Math.Log(initial[i] / (double)initialCount); } for (int i = 0; i < transitionCount.Length; i++) { for (int j = 0; j < states; j++) { model.Transitions[i, j] = Math.Log(transitions[i, j] / (double)transitionCount[i]); } } System.Diagnostics.Debug.Assert(!model.Probabilities.HasNaN()); System.Diagnostics.Debug.Assert(!model.Transitions.HasNaN()); // 5. Compute log-likelihood double logLikelihood = Double.NegativeInfinity; for (int i = 0; i < observations.Length; i++) { logLikelihood = Special.LogSum(logLikelihood, model.Evaluate(observations[i])); } return(logLikelihood); }
/// <summary> /// Runs the Maximum Likelihood learning algorithm for hidden Markov models. /// </summary> /// /// <param name="observations">An array of observation sequences to be used to train the model.</param> /// <param name="paths">An array of state labels associated to each observation sequence.</param> /// /// <returns> /// The average log-likelihood for the observations after the model has been trained. /// </returns> /// /// <remarks> /// Supervised learning problem. Given some training observation sequences O = {o1, o2, ..., oK}, /// known training state paths H = {h1, h2, ..., hK} and general structure of HMM (numbers of /// hidden and visible states), determine HMM parameters M = (A, B, pi) that best fit training data. /// </remarks> /// public double Run(int[][] observations, int[][] paths) { // Grab model information int N = observations.Length; int states = model.States; int symbols = model.Symbols; Array.Clear(initial, 0, initial.Length); Array.Clear(transitions, 0, transitions.Length); Array.Clear(emissions, 0, emissions.Length); // 1. Count first state occurrences for (int i = 0; i < paths.Length; i++) { initial[paths[i][0]]++; } // 2. Count all state transitions foreach (int[] path in paths) { for (int j = 1; j < path.Length; j++) { transitions[path[j - 1], path[j]]++; } } // 3. Count emissions for each state for (int i = 0; i < observations.Length; i++) { for (int j = 0; j < observations[i].Length; j++) { emissions[paths[i][j], observations[i][j]]++; } } // 4. Form log-probabilities, using the Laplace // correction to avoid zero probabilities if (useLaplaceRule) { // Use Laplace's rule of succession correction // http://en.wikipedia.org/wiki/Rule_of_succession for (int i = 0; i < initial.Length; i++) { initial[i]++; for (int j = 0; j < states; j++) { transitions[i, j]++; } for (int k = 0; k < symbols; k++) { emissions[i, k]++; } } } // Form probabilities int initialCount = initial.Sum(); int[] transitionCount = transitions.Sum(1); int[] emissionCount = emissions.Sum(1); if (initialCount == 0) { initialCount = 1; } for (int i = 0; i < transitionCount.Length; i++) { if (transitionCount[i] == 0) { transitionCount[i] = 1; } } for (int i = 0; i < emissionCount.Length; i++) { if (emissionCount[i] == 0) { emissionCount[i] = 1; } } for (int i = 0; i < initial.Length; i++) { model.Probabilities[i] = Math.Log(initial[i] / (double)initialCount); } for (int i = 0; i < transitionCount.Length; i++) { for (int j = 0; j < states; j++) { model.Transitions[i, j] = Math.Log(transitions[i, j] / (double)transitionCount[i]); } } for (int i = 0; i < emissionCount.Length; i++) { for (int j = 0; j < symbols; j++) { model.Emissions[i, j] = Math.Log(emissions[i, j] / (double)emissionCount[i]); } } System.Diagnostics.Debug.Assert(!model.Probabilities.HasNaN()); System.Diagnostics.Debug.Assert(!model.Transitions.HasNaN()); System.Diagnostics.Debug.Assert(!model.Emissions.HasNaN()); // 5. Compute log-likelihood double logLikelihood = Double.NegativeInfinity; for (int i = 0; i < observations.Length; i++) { logLikelihood = Special.LogSum(logLikelihood, model.Evaluate(observations[i])); } return(logLikelihood); }
static void Main(string[] args) { //// Create a model with given probabilities //HiddenMarkovModel hmm = new HiddenMarkovModel( //transitions: new[,] // matrix A //{ // { 0.25, 0.25, 0.00 }, // { 0.33, 0.33, 0.33 }, // { 0.90, 0.10, 0.00 }, //}, //emissions: new[,] // matrix B //{ // { 0.1, 0.1, 0.8 }, // { 0.6, 0.2, 0.2 }, // { 0.9, 0.1, 0.0 }, //}, //initial: new[] // vector pi //{ // 0.25, 0.25, 0.0 //}); //// Create an observation sequence of up to 2 symbols (0 or 1) //int[] observationSequence = new[] { 0, 1, 1, 0}; //// Decode the sequence: the path will be 1-1-1-1-2-0-1-1 //int[] stateSequence = hmm.Decode(observationSequence); //foreach (int a in stateSequence) //{ // System.Console.Write(a + " "); //} ////////////////////////////////////////////////////////////////////////////// // Create the transation matrix A double[,] transition = { { 0.3, 0.2, 0.2 }, { 0.4, 0.3, 0.1 }, { 0.4, 0.3, 0.1 } }; // emission probability by kmean algo. double[,] emission = { { 0.55, 0.075, 0.275, 0, 0.1 }, //Dance 1 { 0.52, 0.22, 0.16, 0, 0.1 }, //Dance 2 { 0.357, 0.357, 0.186, 0, 0.1 } //Dance 3 }; // Create the initial probabilities pi double[] initial = { 0.4, 0.2, 0.4 }; // Create a new hidden Markov model HiddenMarkovModel hmm = new HiddenMarkovModel(transition, emission, initial); // After that, one could, for example, query the probability // of a sequence ocurring. We will consider the sequence int[] sequence = new int[] { 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }; // And now we will evaluate its likelihood double logLikelihood = hmm.Evaluate(sequence); // At this point, the log-likelihood of the sequence // ocurring within the model is -3.3928721329161653. // We can also get the Viterbi path of the sequence int[] path = hmm.Decode(sequence, out logLikelihood); // At this point, the state path will be 1-0-0 and the // log-likelihood will be -4.3095199438871337 foreach (int a in path) { System.Console.Write(a + " "); } System.Console.ReadKey(); }
public void LearnTest7() { // Create continuous sequences. In the sequences below, there // seems to be two states, one for values between 0 and 1 and // another for values between 5 and 7. The states seems to be // switched on every observation. double[][] sequences = new double[][] { new double[] { 0.1, 5.2, 0.3, 6.7, 0.1, 6.0 }, new double[] { 0.2, 6.2, 0.3, 6.3, 0.1, 5.0 }, new double[] { 0.1, 7.0, 0.1, 7.0, 0.2, 5.6 }, }; // Specify a initial normal distribution for the samples. var density = new NormalDistribution(); // Creates a continuous hidden Markov Model with two states organized in a forward // topology and an underlying univariate Normal distribution as probability density. var model = new HiddenMarkovModel <NormalDistribution>(new Forward(2), density); // Configure the learning algorithms to train the sequence classifier until the // difference in the average log-likelihood changes only by as little as 0.0001 var teacher = new ViterbiLearning <NormalDistribution>(model) { Tolerance = 0.0001, Iterations = 0, }; // Fit the model double logLikelihood = teacher.Run(sequences); // See the probability of the sequences learned double a1 = model.Evaluate(new[] { 0.1, 5.2, 0.3, 6.7, 0.1, 6.0 }); // 0.40 double a2 = model.Evaluate(new[] { 0.2, 6.2, 0.3, 6.3, 0.1, 5.0 }); // 0.46 // See the probability of an unrelated sequence double a3 = model.Evaluate(new[] { 1.1, 2.2, 1.3, 3.2, 4.2, 1.0 }); // 1.42 double likelihood = Math.Exp(logLikelihood); a1 = Math.Exp(a1); a2 = Math.Exp(a2); a3 = Math.Exp(a3); Assert.AreEqual(1.5418305348314281, likelihood, 1e-10); Assert.AreEqual(0.4048936808991913, a1, 1e-10); Assert.AreEqual(0.4656014344844673, a2, 1e-10); Assert.AreEqual(1.4232710878429383E-48, a3, 1e-10); Assert.IsFalse(double.IsNaN(logLikelihood)); Assert.IsFalse(double.IsNaN(a1)); Assert.IsFalse(double.IsNaN(a2)); Assert.IsFalse(double.IsNaN(a3)); Assert.AreEqual(2, model.Emissions.Length); var state1 = (model.Emissions[0] as NormalDistribution); var state2 = (model.Emissions[1] as NormalDistribution); Assert.AreEqual(0.16666666666666, state1.Mean, 1e-10); Assert.AreEqual(6.11111111111111, state2.Mean, 1e-10); Assert.IsFalse(Double.IsNaN(state1.Mean)); Assert.IsFalse(Double.IsNaN(state2.Mean)); Assert.AreEqual(0.007499999999999, state1.Variance, 1e-10); Assert.AreEqual(0.538611111111111, state2.Variance, 1e-10); Assert.IsFalse(Double.IsNaN(state1.Variance)); Assert.IsFalse(Double.IsNaN(state2.Variance)); Assert.AreEqual(2, model.Transitions.GetLength(0)); Assert.AreEqual(2, model.Transitions.GetLength(1)); var A = Matrix.Exp(model.Transitions); Assert.AreEqual(0.090, A[0, 0], 1e-3); Assert.AreEqual(0.909, A[0, 1], 1e-3); Assert.AreEqual(0.875, A[1, 0], 1e-3); Assert.AreEqual(0.125, A[1, 1], 1e-3); Assert.IsFalse(A.HasNaN()); }
public void PredictTest() { int[][] sequences = new int[][] { new int[] { 0, 3, 1, 2 }, }; HiddenMarkovModel hmm = new HiddenMarkovModel(new Forward(4), 4); var teacher = new BaumWelchLearning(hmm) { Tolerance = 1e-10, Iterations = 0 }; double ll = teacher.Run(sequences); double l11, l12, l13, l14; int p1 = hmm.Predict(new int[] { 0 }, 1, out l11)[0]; int p2 = hmm.Predict(new int[] { 0, 3 }, 1, out l12)[0]; int p3 = hmm.Predict(new int[] { 0, 3, 1 }, 1, out l13)[0]; int p4 = hmm.Predict(new int[] { 0, 3, 1, 2 }, 1, out l14)[0]; Assert.AreEqual(3, p1); Assert.AreEqual(1, p2); Assert.AreEqual(2, p3); Assert.AreEqual(2, p4); double l21 = hmm.Evaluate(new int[] { 0, 3 }); double l22 = hmm.Evaluate(new int[] { 0, 3, 1 }); double l23 = hmm.Evaluate(new int[] { 0, 3, 1, 2 }); double l24 = hmm.Evaluate(new int[] { 0, 3, 1, 2, 2 }); Assert.AreEqual(l11, l21, 1e-10); Assert.AreEqual(l12, l22, 1e-10); Assert.AreEqual(l13, l23, 1e-10); Assert.AreEqual(l14, l24, 1e-10); Assert.IsFalse(double.IsNaN(l11)); Assert.IsFalse(double.IsNaN(l12)); Assert.IsFalse(double.IsNaN(l13)); Assert.IsFalse(double.IsNaN(l14)); Assert.IsFalse(double.IsNaN(l21)); Assert.IsFalse(double.IsNaN(l22)); Assert.IsFalse(double.IsNaN(l23)); Assert.IsFalse(double.IsNaN(l24)); double ln1; int[] pn = hmm.Predict(new int[] { 0 }, 4, out ln1); Assert.AreEqual(4, pn.Length); Assert.AreEqual(3, pn[0]); Assert.AreEqual(1, pn[1]); Assert.AreEqual(2, pn[2]); Assert.AreEqual(2, pn[3]); double ln2 = hmm.Evaluate(new int[] { 0, 3, 1, 2, 2 }); Assert.AreEqual(ln1, ln2, 1e-10); }
/* * this method passes all the possible directions * that can create a horizontal line to the HMM library * as observations. A and B are the state and * observation probabilities for the model * pi is the intial state of the model * the function returns true if the input matches any * of the observations used to train the model */ bool horizontalEvalution(int [] input) { if(input.Length != 1){ return false; } int[][] sequences = new int[][] { new int[]{ EAST }, new int[] { WEST } }; double [,] A = new double[8,8] { {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0} }; double [,] B = new double[8,8] { {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1} }; double [] pi = new double [] {0, 0, 0.5, 0.5, 0, 0, 0, 0}; HiddenMarkovModel model = new HiddenMarkovModel(A, B, pi); model.Learn(sequences, 0.0001); if(model.Evaluate(input) >= 0.5){ return true; }else{ return false; } }
static void runDiscreteDensityHiddenMarkovModelLearningExample() { int[][] observationSequences = { new[] { 0, 1, 2, 3 }, new[] { 0, 0, 0,1, 1, 2, 2, 3, 3 }, new[] { 0, 0, 1,2, 2, 2, 3, 3 }, new[] { 0, 1, 2,3, 3, 3, 3 }, }; { // Create a hidden Markov model with arbitrary probabilities. HiddenMarkovModel hmm = new HiddenMarkovModel(states: 4, symbols: 4); // Create a Baum-Welch learning algorithm to teach it. BaumWelchLearning trainer = new BaumWelchLearning(hmm); // Call its Run method to start learning. double averageLogLikelihood = trainer.Run(observationSequences); Console.WriteLine("average log-likelihood for the observations = {0}", averageLogLikelihood); // Check the probability of some sequences. double logLik1 = hmm.Evaluate(new[] { 0, 1, 2, 3 }); // 0.013294354967987107. Console.WriteLine("probability = {0}", Math.Exp(logLik1)); double logLik2 = hmm.Evaluate(new[] { 0, 0, 1, 2, 2, 3 }); // 0.002261813011419950. Console.WriteLine("probability = {0}", Math.Exp(logLik2)); double logLik3 = hmm.Evaluate(new[] { 0, 0, 1, 2, 3, 3 }); // 0.002908045300397080. Console.WriteLine("probability = {0}", Math.Exp(logLik3)); // Violate the form of the training set. double logLik4 = hmm.Evaluate(new[] { 3, 2, 1, 0 }); // 0.000000000000000000. Console.WriteLine("probability = {0}", Math.Exp(logLik4)); double logLik5 = hmm.Evaluate(new[] { 0, 0, 1, 3, 1, 1 }); // 0.000000000113151816. Console.WriteLine("probability = {0}", Math.Exp(logLik5)); } { // Create a hidden Markov model with arbitrary probabilities. var hmm = new HiddenMarkovModel <GeneralDiscreteDistribution>(states: 4, emissions: new GeneralDiscreteDistribution(symbols: 4)); // Create a Baum-Welch learning algorithm to teach it // until the difference in the average log-likelihood changes only by as little as 0.0001 // and the number of iterations is less than 1000. var trainer = new BaumWelchLearning <GeneralDiscreteDistribution>(hmm) { Tolerance = 0.0001, Iterations = 1000, }; // Call its Run method to start learning. double averageLogLikelihood = trainer.Run(observationSequences); Console.WriteLine("average log-likelihood for the observations = {0}", averageLogLikelihood); // Check the probability of some sequences. double logLik1 = hmm.Evaluate(new[] { 0, 1, 2, 3 }); // 0.013294354967987107. Console.WriteLine("probability = {0}", Math.Exp(logLik1)); double logLik2 = hmm.Evaluate(new[] { 0, 0, 1, 2, 2, 3 }); // 0.002261813011419950. Console.WriteLine("probability = {0}", Math.Exp(logLik2)); double logLik3 = hmm.Evaluate(new[] { 0, 0, 1, 2, 3, 3 }); // 0.002908045300397080. Console.WriteLine("probability = {0}", Math.Exp(logLik3)); // Violate the form of the training set. double logLik4 = hmm.Evaluate(new[] { 3, 2, 1, 0 }); // 0.000000000000000000. Console.WriteLine("probability = {0}", Math.Exp(logLik4)); double logLik5 = hmm.Evaluate(new[] { 0, 0, 1, 3, 1, 1 }); // 0.000000000113151816. Console.WriteLine("probability = {0}", Math.Exp(logLik5)); } }
/// <summary> /// Gets the probability mass function (pmf) for /// this distribution evaluated at point <c>x</c>. /// </summary> /// /// <param name="x">A single point in the distribution range.</param> /// /// <returns> /// The probability of <c>x</c> occurring /// in the current distribution. /// </returns> /// /// <remarks> /// The Probability Mass Function (PMF) describes the /// probability that a given value <c>x</c> will occur. /// </remarks> /// public override double ProbabilityMassFunction(int[] x) { return(Math.Exp(model.Evaluate(x))); }
private static double testThresholdModel(int[][] inputs, int[] outputs, HiddenMarkovClassifier classifier, double likelihood) { HiddenMarkovModel threshold = classifier.Threshold; Assert.AreEqual(6, threshold.States); Assert.AreEqual(classifier.Models[0].Transitions[0, 0], threshold.Transitions[0, 0], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[1, 1], threshold.Transitions[1, 1], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[2, 2], threshold.Transitions[2, 2], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[0, 0], threshold.Transitions[3, 3], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[1, 1], threshold.Transitions[4, 4], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[2, 2], threshold.Transitions[5, 5], 1e-10); for (int i = 0; i < 3; i++) { for (int j = 3; j < 6; j++) { Assert.AreEqual(Double.NegativeInfinity, threshold.Transitions[i, j]); } } for (int i = 3; i < 6; i++) { for (int j = 0; j < 3; j++) { Assert.AreEqual(Double.NegativeInfinity, threshold.Transitions[i, j]); } } Assert.IsFalse(Matrix.HasNaN(threshold.LogTransitions)); classifier.Sensitivity = 0.5; // Will assert the models have learned the sequences correctly. for (int i = 0; i < inputs.Length; i++) { int expected = outputs[i]; int actual = classifier.Compute(inputs[i], out likelihood); Assert.AreEqual(expected, actual); } int[] r0 = new int[] { 1, 1, 0, 0, 2 }; double logRejection; int c = classifier.Compute(r0, out logRejection); Assert.AreEqual(-1, c); Assert.AreEqual(0.99996241769427985, logRejection, 1e-10); logRejection = threshold.Evaluate(r0); Assert.AreEqual(-5.5993214137039073, logRejection, 1e-10); threshold.Decode(r0, out logRejection); Assert.AreEqual(-9.31035541707617, logRejection, 1e-10); foreach (var model in classifier.Models) { double[,] A = model.Transitions; for (int i = 0; i < A.GetLength(0); i++) { double[] row = A.Exp().GetRow(i); double sum = row.Sum(); Assert.AreEqual(1, sum, 1e-10); } } { double[,] A = classifier.Threshold.Transitions; for (int i = 0; i < A.GetLength(0); i++) { double[] row = A.GetRow(i); double sum = row.Exp().Sum(); Assert.AreEqual(1, sum, 1e-6); } } return(likelihood); }
public void LearnTest8() { // Create continuous sequences. In the sequence below, there // seems to be two states, one for values equal to 1 and another // for values equal to 2. double[][] sequences = new double[][] { new double[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 } }; // Specify a initial normal distribution for the samples. var density = new NormalDistribution(); // Creates a continuous hidden Markov Model with two states organized in a forward // topology and an underlying univariate Normal distribution as probability density. var model = new HiddenMarkovModel <NormalDistribution>(new Forward(2), density); // Configure the learning algorithms to train the sequence classifier until the // difference in the average log-likelihood changes only by as little as 0.0001 var teacher = new ViterbiLearning <NormalDistribution>(model) { Tolerance = 0.0001, Iterations = 0, // However, we will need to specify a regularization constant as the // variance of each state will likely be zero (all values are equal) FittingOptions = new NormalOptions() { Regularization = double.Epsilon } }; // Fit the model double likelihood = teacher.Run(sequences); // See the probability of the sequences learned double a1 = model.Evaluate(new double[] { 1, 2, 1, 2, 1, 2, 1, 2, 1 }); // exp(a1) = infinity double a2 = model.Evaluate(new double[] { 1, 2, 1, 2, 1 }); // exp(a2) = infinity // See the probability of an unrelated sequence double a3 = model.Evaluate(new double[] { 1, 2, 3, 2, 1, 2, 1 }); // exp(a3) = 0 double a4 = model.Evaluate(new double[] { 1.1, 2.2, 1.3, 3.2, 4.2, 1.0 }); // exp(a4) = 0 Assert.AreEqual(double.PositiveInfinity, System.Math.Exp(likelihood)); Assert.AreEqual(3340.6878090199571, a1); Assert.AreEqual(1855.791720669667, a2); Assert.AreEqual(0.0, Math.Exp(a3)); Assert.AreEqual(0.0, Math.Exp(a4)); Assert.AreEqual(2, model.Emissions.Length); var state1 = (model.Emissions[0] as NormalDistribution); var state2 = (model.Emissions[1] as NormalDistribution); Assert.AreEqual(1.0, state1.Mean, 1e-10); Assert.AreEqual(2.0, state2.Mean, 1e-10); Assert.IsFalse(Double.IsNaN(state1.Mean)); Assert.IsFalse(Double.IsNaN(state2.Mean)); Assert.IsTrue(state1.Variance < 1e-30); Assert.IsTrue(state2.Variance < 1e-30); var A = Matrix.Exp(model.Transitions); Assert.AreEqual(2, A.GetLength(0)); Assert.AreEqual(2, A.GetLength(1)); Assert.AreEqual(0.0714285714285714, A[0, 0], 1e-6); Assert.AreEqual(0.9285714285714286, A[0, 1], 1e-6); Assert.AreEqual(0.9230769230769231, A[1, 0], 1e-6); Assert.AreEqual(0.0769230769230769, A[1, 1], 1e-6); }
public void LearnTest2() { // Declare some testing data int[][] inputs = new int[][] { new int[] { 0, 0, 1, 2 }, // Class 0 new int[] { 0, 1, 1, 2 }, // Class 0 new int[] { 0, 0, 0, 1, 2 }, // Class 0 new int[] { 0, 1, 2, 2, 2 }, // Class 0 new int[] { 2, 2, 1, 0 }, // Class 1 new int[] { 2, 2, 2, 1, 0 }, // Class 1 new int[] { 2, 2, 2, 1, 0 }, // Class 1 new int[] { 2, 2, 2, 2, 1 }, // Class 1 }; int[] outputs = new int[] { 0, 0, 0, 0, // First four sequences are of class 0 1, 1, 1, 1, // Last four sequences are of class 1 }; // We are trying to predict two different classes int classes = 2; // Each sequence may have up to 3 symbols (0,1,2) int symbols = 3; // Nested models will have 3 states each int[] states = new int[] { 3, 3 }; // Creates a new Hidden Markov Model Classifier with the given parameters HiddenMarkovClassifier classifier = new HiddenMarkovClassifier(classes, states, symbols); // Create a new learning algorithm to train the sequence classifier var teacher = new HiddenMarkovClassifierLearning(classifier, // Train each model until the log-likelihood changes less than 0.001 modelIndex => new BaumWelchLearning(classifier.Models[modelIndex]) { Tolerance = 0.001, Iterations = 0 } ); // Enable support for sequence rejection teacher.Rejection = true; // Train the sequence classifier using the algorithm double likelihood = teacher.Run(inputs, outputs); // Will assert the models have learned the sequences correctly. for (int i = 0; i < inputs.Length; i++) { int expected = outputs[i]; int actual = classifier.Compute(inputs[i], out likelihood); Assert.AreEqual(expected, actual); } HiddenMarkovModel threshold = classifier.Threshold; Assert.AreEqual(6, threshold.States); Assert.AreEqual(classifier.Models[0].Transitions[0, 0], threshold.Transitions[0, 0], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[1, 1], threshold.Transitions[1, 1], 1e-10); Assert.AreEqual(classifier.Models[0].Transitions[2, 2], threshold.Transitions[2, 2], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[0, 0], threshold.Transitions[3, 3], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[1, 1], threshold.Transitions[4, 4], 1e-10); Assert.AreEqual(classifier.Models[1].Transitions[2, 2], threshold.Transitions[5, 5], 1e-10); Assert.IsFalse(Matrix.HasNaN(threshold.Transitions)); int[] r0 = new int[] { 1, 1, 0, 0, 2 }; double logRejection; int c = classifier.Compute(r0, out logRejection); Assert.AreEqual(-1, c); Assert.AreEqual(0.99569011079012049, logRejection); Assert.IsFalse(double.IsNaN(logRejection)); logRejection = threshold.Evaluate(r0); Assert.AreEqual(-6.7949285513628528, logRejection, 1e-10); Assert.IsFalse(double.IsNaN(logRejection)); threshold.Decode(r0, out logRejection); Assert.AreEqual(-8.902077561009957, logRejection, 1e-10); Assert.IsFalse(double.IsNaN(logRejection)); }
public void LearnTest6() { // We will try to create a Hidden Markov Model which // can detect if a given sequence starts with a zero // and has any number of ones after that. int[][] sequences = new int[][] { new int[] { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, }; // Creates a new Hidden Markov Model with 3 states for // an output alphabet of two characters (zero and one) HiddenMarkovModel hmm = new HiddenMarkovModel(3, 2); // Try to fit the model to the data until the difference in // the average log-likelihood changes only by as little as 0.0001 var teacher = new BaumWelchLearning(hmm) { Tolerance = 0.0001, Iterations = 0 }; double ll = teacher.Run(sequences); // Calculate the probability that the given // sequences originated from the model double l1 = hmm.Evaluate(new int[] { 0, 1 }); // 0.999 double l2 = hmm.Evaluate(new int[] { 0, 1, 1, 1 }); // 0.916 // Sequences which do not start with zero have much lesser probability. double l3 = hmm.Evaluate(new int[] { 1, 1 }); // 0.000 double l4 = hmm.Evaluate(new int[] { 1, 0, 0, 0 }); // 0.000 // Sequences which contains few errors have higher probability // than the ones which do not start with zero. This shows some // of the temporal elasticity and error tolerance of the HMMs. double l5 = hmm.Evaluate(new int[] { 0, 1, 0, 1, 1, 1, 1, 1, 1 }); // 0.034 double l6 = hmm.Evaluate(new int[] { 0, 1, 1, 1, 1, 1, 1, 0, 1 }); // 0.034 double pl = System.Math.Exp(ll); double p1 = System.Math.Exp(l1); double p2 = System.Math.Exp(l2); double p3 = System.Math.Exp(l3); double p4 = System.Math.Exp(l4); double p5 = System.Math.Exp(l5); double p6 = System.Math.Exp(l6); Assert.AreEqual(0.95151126952069587, pl, 1e-6); Assert.AreEqual(0.99996863060890995, p1, 1e-6); Assert.AreEqual(0.91667240076011669, p2, 1e-6); Assert.AreEqual(0.00002335133758386, p3, 1e-6); Assert.AreEqual(0.00000000000000012, p4, 1e-6); Assert.AreEqual(0.034237231443226858, p5, 1e-6); Assert.AreEqual(0.034237195920532461, p6, 1e-6); Assert.IsTrue(l1 > l3 && l1 > l4); Assert.IsTrue(l2 > l3 && l2 > l4); }
/* * this method passes all the possible directions * that can create a square to the HMM library * as observations. A and B are the state and * observation probabilities for the model * pi is the intial state of the model * the function returns true if the input matches any * of the observations used to train the model */ bool squareEvalution(int [] input) { if(input.Length != 4){ return false; } int[][] sequences = new int[][] { new int[]{ NORTH, EAST, SOUTH, WEST}, new int[] { EAST, SOUTH, WEST, NORTH}, new int[] { SOUTH, WEST, NORTH, EAST}, new int[] { WEST, NORTH, EAST, SOUTH} }; double [,] A = new double[8,8] { {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0} }; double [,] B = new double[8,8] { {1, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 1, 0}, {0, 0, 0, 0, 0, 0, 0, 1} }; double [] pi = new double [] {0.25,0.25,0.25,0.25, 0, 0, 0, 0}; HiddenMarkovModel model = new HiddenMarkovModel(A, B, pi); model.Learn(sequences, 0.0001); if(model.Evaluate(input) >= 0.25){ return true; }else{ return false; } }
public void PosteriorTest1() { // Example from http://ai.stanford.edu/~serafim/CS262_2007/notes/lecture5.pdf double[,] A = { { 0.95, 0.05 }, // fair dice state { 0.05, 0.95 }, // loaded dice state }; double[,] B = { { 1 / 6.0, 1 / 6.0, 1 / 6.0, 1 / 6.0, 1 / 6.0, 1 / 6.0 }, // fair dice probabilities { 1 / 10.0, 1 / 10.0, 1 / 10.0, 1 / 10.0, 1 / 10.0, 1 / 2.0 }, // loaded probabilities }; double[] pi = { 0.5, 0.5 }; HiddenMarkovModel hmm = new HiddenMarkovModel(A, B, pi); int[] x = new int[] { 1, 2, 1, 5, 6, 2, 1, 5, 2, 4 }.Subtract(1); int[] y = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; double py = Math.Exp(hmm.Evaluate(x, y)); Assert.AreEqual(0.00000000521158647211, py, 1e-16); x = new int[] { 1, 2, 1, 5, 6, 2, 1, 5, 2, 4 }.Subtract(1); y = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; py = Math.Exp(hmm.Evaluate(x, y)); Assert.AreEqual(0.00000000015756235243, py, 1e-16); Accord.Math.Tools.SetupGenerator(0); var u = new UniformDiscreteDistribution(0, 6); int[] sequence = u.Generate(1000); int start = 120; int end = 150; for (int i = start; i < end; i += 2) { sequence[i] = 5; } // Predict the next observation in sequence int[] path; double[][] p = hmm.Posterior(sequence, out path); for (int i = 0; i < path.Length; i++) { Assert.AreEqual(1, p[i][0] + p[i][1], 1e-10); } int loaded = 0; for (int i = 0; i < start; i++) { if (p[i][1] > 0.95) { loaded++; } } Assert.AreEqual(0, loaded); loaded = 0; for (int i = start; i < end; i++) { if (p[i][1] > 0.95) { loaded++; } } Assert.IsTrue(loaded > 15); loaded = 0; for (int i = end; i < p.Length; i++) { if (p[i][1] > 0.95) { loaded++; } } Assert.AreEqual(0, loaded); }
public double Run(int[][] observations_db, int[][] path_db) { int K = observations_db.Length; DiagnosticsHelper.Assert(path_db.Length == K); int N = mModel.StateCount; int M = mModel.SymbolCount; int[] initial = new int[N]; int[,] transition_matrix = new int[N, N]; int[,] emission_matrix = new int[N, M]; for (int k = 0; k < K; ++k) { initial[path_db[k][0]]++; } int T = 0; for (int k = 0; k < K; ++k) { int[] path = path_db[k]; int[] observations = observations_db[k]; T = path.Length; for (int t = 0; t < T - 1; ++t) { transition_matrix[path[t], path[t + 1]]++; } for (int t = 0; t < T; ++t) { emission_matrix[path[t], observations[t]]++; } } if (mUseLaplaceRule) { for (int i = 0; i < N; ++i) { initial[i]++; for (int j = 0; j < N; ++j) { transition_matrix[i, j]++; } for (int j = 0; j < M; ++j) { emission_matrix[i, j]++; } } } int initial_sum = initial.Sum(); int[] transition_sum_vec = Sum(transition_matrix, 1); int[] emission_sum_vec = Sum(emission_matrix, 1); for (int i = 0; i < N; ++i) { mModel.LogProbabilityVector[i] = System.Math.Log(initial[i] / (double)initial_sum); } for (int i = 0; i < N; ++i) { double transition_sum = (double)transition_sum_vec[i]; for (int j = 0; j < N; ++j) { mModel.LogTransitionMatrix[i, j] = System.Math.Log(transition_matrix[i, j] / transition_sum); } } for (int i = 0; i < N; ++i) { double emission_sum = (double)emission_sum_vec[i]; for (int m = 0; m < M; ++m) { mModel.LogEmissionMatrix[i, m] = System.Math.Log(emission_matrix[i, m] / emission_sum); } } double logLikelihood = double.NegativeInfinity; for (int i = 0; i < observations_db.Length; i++) { logLikelihood = LogHelper.LogSum(logLikelihood, mModel.Evaluate(observations_db[i])); } return(logLikelihood); }