public void ComputeTest() { HiddenMarkovClassifier hmm = DiscreteHiddenMarkovClassifierPotentialFunctionTest.CreateModel1(); // Declare some testing data int[][] inputs = new int[][] { new int[] { 0, 1, 1, 0 }, // Class 0 new int[] { 0, 0, 1, 0 }, // Class 0 new int[] { 0, 1, 1, 1, 0 }, // Class 0 new int[] { 0, 1, 0 }, // Class 0 new int[] { 1, 0, 0, 1 }, // Class 1 new int[] { 1, 1, 0, 1 }, // Class 1 new int[] { 1, 0, 0, 0, 1 }, // Class 1 new int[] { 1, 0, 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 }; var function = new MarkovDiscreteFunction(hmm); var target = new HiddenConditionalRandomField <int>(function); for (int i = 0; i < inputs.Length; i++) { int expected = hmm.Compute(inputs[i]); int actual = target.Compute(inputs[i]); double h0 = hmm.LogLikelihood(inputs[i], 0); double h1 = hmm.LogLikelihood(inputs[i], 1); double c0 = target.LogLikelihood(inputs[i], 0); double c1 = target.LogLikelihood(inputs[i], 1); Assert.AreEqual(expected, actual); Assert.AreEqual(h0, c0, 1e-10); Assert.AreEqual(h1, c1, 1e-10); Assert.IsFalse(double.IsNaN(c0)); Assert.IsFalse(double.IsNaN(c1)); } }
/// <summary> /// Tests the ensemble /// </summary> private void btnTest_Click(object sender, EventArgs e) { int rows = dgvTesting.Rows.Count - 1; int[] expected = new int[rows]; int[] actual = new int[rows]; // Gets the input sequences int[][] sequences = new int[rows][]; // For each row in the testing data for (int i = 0; i < rows; i++) { // Get the row at the current index DataGridViewRow row = dgvTesting.Rows[i]; // Get the training sequence to feed the model int[] sequence = decode(row.Cells["colTestSequence"].Value as string); // Get the label associated with this sequence string label = row.Cells["colTestTrueClass"].Value as string; expected[i] = hmmc.Models.Find(x => x.Tag as string == label)[0]; // Compute the model output for this sequence and its likelihood. double likelihood = hmmc.LogLikelihood(sequence, out actual[i]); row.Cells["colTestAssignedClass"].Value = hmmc.Models[actual[i]].Tag as string; row.Cells["colTestLikelihood"].Value = likelihood; row.Cells["colTestMatch"].Value = actual[i] == expected[i]; } // Use confusion matrix to compute some performance metrics dgvPerformance.DataSource = new[] { new GeneralConfusionMatrix(hmmc.NumberOfClasses, actual, expected) }; }
private static void check4(double[][][] words, HiddenMarkovClassifier <Independent> model, MarkovMultivariateFunction target, HiddenConditionalRandomField <double[]> hcrf) { double actual; double expected; foreach (var x in words) { for (int c = 0; c < model.Classes; c++) { for (int i = 0; i < model[c].States; i++) { // Check initial state transitions double xa = model.Priors[c]; double xb = Math.Exp(model[c].Probabilities[i]); double xc = model[c].Emissions[i].ProbabilityDensityFunction(x[0]); expected = xa * xb * xc; actual = Math.Exp(target.Factors[c].Compute(-1, i, x, 0, c)); Assert.IsTrue(expected.IsRelativelyEqual(actual, 1e-10)); Assert.IsFalse(double.IsNaN(actual)); } for (int t = 1; t < x.Length; t++) { // Check normal state transitions for (int i = 0; i < model[c].States; i++) { for (int j = 0; j < model[c].States; j++) { double xb = Math.Exp(model[c].Transitions[i, j]); double xc = model[c].Emissions[j].ProbabilityDensityFunction(x[t]); expected = xb * xc; actual = Math.Exp(target.Factors[c].Compute(i, j, x, t, c)); Assert.IsTrue(expected.IsRelativelyEqual(actual, 1e-10)); Assert.IsFalse(double.IsNaN(actual)); } } } actual = Math.Exp(model.LogLikelihood(x, c)); expected = Math.Exp(hcrf.LogLikelihood(x, c)); Assert.AreEqual(expected, actual, 1e-10); Assert.IsFalse(double.IsNaN(actual)); actual = model.Compute(x); expected = hcrf.Compute(x); Assert.AreEqual(expected, actual); Assert.IsFalse(double.IsNaN(actual)); } } }
public void learn_test() { double[][][] sequences; int[] labels; HiddenMarkovClassifier <Independent, double[]> model = CreateModel2_learn(out sequences, out labels); var target = new MarkovMultivariateFunction(model); var hcrf = new HiddenConditionalRandomField <double[]>(target); double actual; double expected; double[][] x = { new double[] { 0, 1.7 }, new double[] { 2, 2.1 } }; for (int c = 0; c < model.Classes; c++) { for (int i = 0; i < model[c].States; i++) { // Check initial state transitions expected = model.Priors[c] * Math.Exp(model[c].LogInitial[i]) * model[c].Emissions[i].ProbabilityDensityFunction(x[0]); actual = Math.Exp(target.Factors[c].Compute(-1, i, x, 0, c)); Assert.AreEqual(expected, actual, 1e-6); Assert.IsFalse(double.IsNaN(actual)); } for (int t = 1; t < x.Length; t++) { // Check normal state transitions for (int i = 0; i < model[c].States; i++) { for (int j = 0; j < model[c].States; j++) { double xb = Math.Exp(model[c].LogTransitions[i][j]); double xc = model[c].Emissions[j].ProbabilityDensityFunction(x[t]); expected = xb * xc; actual = Math.Exp(target.Factors[c].Compute(i, j, x, t, c)); Assert.AreEqual(expected, actual, 1e-6); Assert.IsFalse(double.IsNaN(actual)); } } } actual = model.LogLikelihood(x, c); expected = hcrf.LogLikelihood(x, c); Assert.AreEqual(expected, actual); Assert.IsFalse(double.IsNaN(actual)); } }
public void SimpleGestureRecognitionTest() { // Let's say we would like to do a very simple mechanism for // gesture recognition. In this example, we will be trying to // create a classifier that can distinguish between the words // "hello", "car", and "wardrobe". // Let's say we decided to acquire some data, and we asked some // people to perform those words in front of a Kinect camera, and, // using Microsoft's SDK, we were able to captured the x and y // coordinates of each hand while the word was being performed. // Let's say we decided to represent our frames as: // // double[] frame = { leftHandX, leftHandY, rightHandX, rightHandY }; // // Since we captured words, this means we captured sequences of // frames as we described above. Let's write some of those as // rough examples to explain how gesture recognition can be done: double[][] hello = { new double[] { 1.0, 0.1, 0.0, 0.0 }, // let's say the word new double[] { 0.0, 1.0, 0.1, 0.1 }, // hello took 6 frames new double[] { 0.0, 1.0, 0.1, 0.1 }, // to be recorded. new double[] { 0.0, 0.0, 1.0, 0.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 }, new double[] { 0.0, 0.0, 0.1, 1.1 }, }; double[][] car = { new double[] { 0.0, 0.0, 0.0, 1.0 }, // the car word new double[] { 0.1, 0.0, 1.0, 0.1 }, // took only 4. new double[] { 0.0, 0.0, 0.1, 0.0 }, new double[] { 1.0, 0.0, 0.0, 0.0 }, }; double[][] wardrobe = { new double[] { 0.0, 0.0, 1.0, 0.0 }, // same for the new double[] { 0.1, 0.0, 1.0, 0.1 }, // wardrobe word. new double[] { 0.0, 0.1, 1.0, 0.0 }, new double[] { 0.1, 0.0, 1.0, 0.1 }, }; // Here, please note that a real-world example would involve *lots* // of samples for each word. Here, we are considering just one from // each class which is clearly sub-optimal and should _never_ be done // on practice. For example purposes, however, please disregard this. // Those are the words we have in our vocabulary: // double[][][] words = { hello, car, wardrobe }; // Now, let's associate integer labels with them. This is needed // for the case where there are multiple samples for each word. // int[] labels = { 0, 1, 2 }; // We will create our classifiers assuming an independent // Gaussian distribution for each component in our feature // vectors (like assuming a Naive Bayes assumption). var initial = new Independent <NormalDistribution> ( new NormalDistribution(0, 1), new NormalDistribution(0, 1), new NormalDistribution(0, 1), new NormalDistribution(0, 1) ); // Now, we can proceed and create our classifier. // int numberOfWords = 3; // we are trying to distinguish between 3 words int numberOfStates = 5; // this value can be found by trial-and-error var hmm = new HiddenMarkovClassifier <Independent <NormalDistribution> > ( classes: numberOfWords, topology: new Forward(numberOfStates), // word classifiers should use a forward topology initial: initial ); // Create a new learning algorithm to train the sequence classifier var teacher = new HiddenMarkovClassifierLearning <Independent <NormalDistribution> >(hmm, // Train each model until the log-likelihood changes less than 0.001 modelIndex => new BaumWelchLearning <Independent <NormalDistribution> >(hmm.Models[modelIndex]) { Tolerance = 0.001, Iterations = 100, // This is necessary so the code doesn't blow up when it realize // there is only one sample per word class. But this could also be // needed in normal situations as well. // FittingOptions = new IndependentOptions() { InnerOption = new NormalOptions() { Regularization = 1e-5 } } } ); // Finally, we can run the learning algorithm! double logLikelihood = teacher.Run(words, labels); // At this point, the classifier should be successfully // able to distinguish between our three word classes: // int tc1 = hmm.Compute(hello); int tc2 = hmm.Compute(car); int tc3 = hmm.Compute(wardrobe); Assert.AreEqual(0, tc1); Assert.AreEqual(1, tc2); Assert.AreEqual(2, tc3); // Now, we can use the Markov classifier to initialize a HCRF var function = new MarkovMultivariateFunction(hmm); var hcrf = new HiddenConditionalRandomField <double[]>(function); // We can check that both are equivalent, although they have // formulations that can be learned with different methods // for (int i = 0; i < words.Length; i++) { // Should be the same int expected = hmm.Compute(words[i]); int actual = hcrf.Compute(words[i]); // Should be the same double h0 = hmm.LogLikelihood(words[i], 0); double c0 = hcrf.LogLikelihood(words[i], 0); double h1 = hmm.LogLikelihood(words[i], 1); double c1 = hcrf.LogLikelihood(words[i], 1); double h2 = hmm.LogLikelihood(words[i], 2); double c2 = hcrf.LogLikelihood(words[i], 2); Assert.AreEqual(expected, actual); Assert.AreEqual(h0, c0, 1e-10); Assert.IsTrue(h1.IsRelativelyEqual(c1, 1e-10)); Assert.IsTrue(h2.IsRelativelyEqual(c2, 1e-10)); Assert.IsFalse(double.IsNaN(c0)); Assert.IsFalse(double.IsNaN(c1)); Assert.IsFalse(double.IsNaN(c2)); } // Now we can learn the HCRF using one of the best learning // algorithms available, Resilient Backpropagation learning: // Create a learning algorithm var rprop = new HiddenResilientGradientLearning <double[]>(hcrf) { Iterations = 50, Tolerance = 1e-5 }; // Run the algorithm and learn the models double error = rprop.Run(words, labels); // At this point, the HCRF should be successfully // able to distinguish between our three word classes: // int hc1 = hcrf.Compute(hello); int hc2 = hcrf.Compute(car); int hc3 = hcrf.Compute(wardrobe); Assert.AreEqual(0, hc1); Assert.AreEqual(1, hc2); Assert.AreEqual(2, hc3); }
public void LearnTest() { #region doc_learn // Declare some testing data int[][] inputs = new int[][] { new int[] { 0, 1, 2, 0 }, // Class 0 new int[] { 0, 0, 2, 0 }, // Class 0 new int[] { 0, 1, 2, 1, 0 }, // Class 0 new int[] { 0, 1, 2, 0 }, // Class 0 new int[] { 1, 0, 2, 1 }, // Class 1 new int[] { 1, 1, 2, 1 }, // Class 1 new int[] { 1, 0, 2, 0, 1 }, // Class 1 new int[] { 1, 0, 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 }; // Create a new learning algorithm to train the sequence classifier var teacher = new HiddenMarkovClassifierLearning() { // Train each model until the log-likelihood changes less than 0.001 Learner = (i) => new BaumWelchLearning() { Tolerance = 0.001, Iterations = 0, NumberOfStates = 2, } }; // Train the sequence classifier HiddenMarkovClassifier classifier = teacher.Learn(inputs, outputs); // Obtain classification labels for the output int[] predicted = classifier.Decide(inputs); // Obtain prediction scores for the outputs double[] lls = classifier.LogLikelihood(inputs); #endregion Assert.AreEqual(0, classifier.NumberOfInputs); Assert.AreEqual(2, classifier.NumberOfOutputs); Assert.AreEqual(2, classifier.NumberOfClasses); Assert.AreEqual(3, classifier.NumberOfSymbols); for (int i = 0; i < classifier.NumberOfClasses; i++) { Assert.AreEqual(2, classifier[i].NumberOfStates); Assert.AreEqual(3, classifier[i].NumberOfSymbols); Assert.AreEqual(1, classifier[i].NumberOfInputs); Assert.AreEqual(2, classifier[i].NumberOfOutputs); } Assert.AreEqual(0.5, classifier.Priors[0]); Assert.AreEqual(0.5, classifier.Priors[1]); for (int i = 0; i < inputs.Length; i++) { int expected = outputs[i]; int actual = predicted[i]; Assert.AreEqual(expected, actual); } }
public void LearnTest2_old() { #region doc_rejection_old // 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 teacher.Learn(inputs, outputs); // Obtain prediction classes for the outputs int[] prediction = classifier.Decide(inputs); // Obtain prediction scores for the outputs double[] lls = classifier.LogLikelihood(inputs); #endregion double likelihood = teacher.LogLikelihood; Assert.AreEqual(-24.857860924867815, likelihood, 1e-8); likelihood = testThresholdModel(inputs, outputs, classifier, likelihood); }
public void LearnTest_old() { // Declare some testing data int[][] inputs = new int[][] { new int[] { 0, 1, 1, 0 }, // Class 0 new int[] { 0, 0, 1, 0 }, // Class 0 new int[] { 0, 1, 1, 1, 0 }, // Class 0 new int[] { 0, 1, 0 }, // Class 0 new int[] { 1, 0, 0, 1 }, // Class 1 new int[] { 1, 1, 0, 1 }, // Class 1 new int[] { 1, 0, 0, 0, 1 }, // Class 1 new int[] { 1, 0, 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 two symbols (0 or 1) int symbols = 2; // Nested models will have two states each int[] states = new int[] { 2, 2 }; // 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 } ); // Train the sequence classifier teacher.Learn(inputs, outputs); // Obtain classification labels for the output int[] predicted = classifier.Decide(inputs); // Obtain prediction scores for the outputs double[] lls = classifier.LogLikelihood(inputs); // Will assert the models have learned the sequences correctly. for (int i = 0; i < inputs.Length; i++) { int expected = outputs[i]; int actual = predicted[i]; Assert.AreEqual(expected, actual); } }
private static void check4(double[][][] words, HiddenMarkovClassifier<Independent> model, MarkovMultivariateFunction target, HiddenConditionalRandomField<double[]> hcrf) { double actual; double expected; foreach (var x in words) { for (int c = 0; c < model.Classes; c++) { for (int i = 0; i < model[c].States; i++) { // Check initial state transitions double xa = model.Priors[c]; double xb = Math.Exp(model[c].Probabilities[i]); double xc = model[c].Emissions[i].ProbabilityDensityFunction(x[0]); expected = xa * xb * xc; actual = Math.Exp(target.Factors[c].Compute(-1, i, x, 0, c)); Assert.IsTrue(expected.IsRelativelyEqual(actual, 1e-10)); Assert.IsFalse(double.IsNaN(actual)); } for (int t = 1; t < x.Length; t++) { // Check normal state transitions for (int i = 0; i < model[c].States; i++) { for (int j = 0; j < model[c].States; j++) { double xb = Math.Exp(model[c].Transitions[i, j]); double xc = model[c].Emissions[j].ProbabilityDensityFunction(x[t]); expected = xb * xc; actual = Math.Exp(target.Factors[c].Compute(i, j, x, t, c)); Assert.IsTrue(expected.IsRelativelyEqual(actual, 1e-10)); Assert.IsFalse(double.IsNaN(actual)); } } } actual = Math.Exp(model.LogLikelihood(x, c)); expected = Math.Exp(hcrf.LogLikelihood(x, c)); Assert.AreEqual(expected, actual, 1e-10); Assert.IsFalse(double.IsNaN(actual)); actual = model.Compute(x); expected = hcrf.Compute(x); Assert.AreEqual(expected, actual); Assert.IsFalse(double.IsNaN(actual)); } } }
private void btnTrain_Click(object sender, EventArgs e) { if (dataGridView1.Rows.Count == 0) { MessageBox.Show("Please load or insert some data first."); return; } int states = (int)numStates.Value; int iterations = (int)numIterations.Value; double tolerance = (double)numConvergence.Value; if (rbStopIterations.Checked) { tolerance = 0.0; } if (rbStopConvergence.Checked) { iterations = 0; } // Retrieve the training data from the data grid view int rows = dataGridView1.Rows.Count; int[] outputs = new int[rows]; var sequences = new int[rows][]; for (int i = 0; i < rows; i++) { outputs[i] = (int)dataGridView1.Rows[i].Cells["colLabel"].Value - 1; sequences[i] = GetFeatures((double[][])dataGridView1.Rows[i].Tag); } int classes = outputs.Distinct().Count(); string[] labels = new string[classes]; for (int i = 0; i < labels.Length; i++) { labels[i] = (i + 1).ToString(); } // Create a sequence classifier for 3 classes classifier = new HiddenMarkovClassifier(labels.Length, new Forward(states), symbols: 20, names: labels); // Create the learning algorithm for the ensemble classifier var teacher = new HiddenMarkovClassifierLearning(classifier, // Train each model using the selected convergence criteria i => new BaumWelchLearning(classifier.Models[i]) { Tolerance = tolerance, Iterations = iterations, } ); // Create and use a rejection threshold model teacher.Rejection = cbRejection.Checked; teacher.Empirical = true; teacher.Smoothing = (double)numSmoothing.Value; // Run the learning algorithm teacher.Run(sequences, outputs); double error = classifier.LogLikelihood(sequences, outputs); int hits = 0; toolStripProgressBar1.Visible = true; toolStripProgressBar1.Value = 0; toolStripProgressBar1.Step = 1; toolStripProgressBar1.Maximum = dataGridView1.Rows.Count; for (int i = 0; i < rows; i++) { double likelihood; int index = classifier.Compute(sequences[i], out likelihood); DataGridViewRow row = dataGridView1.Rows[i]; if (index == -1) { row.Cells["colClassification"].Value = String.Empty; } else { row.Cells["colClassification"].Value = classifier.Models[index].Tag; } int expected = (int)row.Cells["colLabel"].Value; if (expected == index + 1) { row.Cells[0].Style.BackColor = Color.LightGreen; row.Cells[1].Style.BackColor = Color.LightGreen; row.Cells[2].Style.BackColor = Color.LightGreen; hits++; } else { row.Cells[0].Style.BackColor = Color.White; row.Cells[1].Style.BackColor = Color.White; row.Cells[2].Style.BackColor = Color.White; } toolStripProgressBar1.PerformStep(); } dgvModels.DataSource = classifier.Models; toolStripProgressBar1.Visible = false; toolStripStatusLabel1.Text = String.Format("Training complete. Hits: {0}/{1} ({2:0%})", hits, dataGridView1.Rows.Count, (double)hits / dataGridView1.Rows.Count); }
private void btnTrain_Click(object sender, EventArgs e) { if (dataGridView1.Rows.Count == 0) { MessageBox.Show("Please load or insert some data first."); return; } int states = (int)numStates.Value; int iterations = (int)numIterations.Value; double tolerance = (double)numConvergence.Value; if (rbStopIterations.Checked) tolerance = 0.0; if (rbStopConvergence.Checked) iterations = 0; // Retrieve the training data from the data grid view int rows = dataGridView1.Rows.Count; int[] outputs = new int[rows]; var sequences = new int[rows][]; for (int i = 0; i < rows; i++) { outputs[i] = (int)dataGridView1.Rows[i].Cells["colLabel"].Value - 1; sequences[i] = GetFeatures((double[][])dataGridView1.Rows[i].Tag); } int classes = outputs.Distinct().Count(); string[] labels = new string[classes]; for (int i = 0; i < labels.Length; i++) labels[i] = (i+1).ToString(); // Create a sequence classifier for 3 classes classifier = new HiddenMarkovClassifier(labels.Length, new Forward(states), symbols: 20, names: labels); // Create the learning algorithm for the ensemble classifier var teacher = new HiddenMarkovClassifierLearning(classifier, // Train each model using the selected convergence criteria i => new BaumWelchLearning(classifier.Models[i]) { Tolerance = tolerance, Iterations = iterations, } ); // Create and use a rejection threshold model teacher.Rejection = cbRejection.Checked; teacher.Empirical = true; teacher.Smoothing = (double)numSmoothing.Value; // Run the learning algorithm teacher.Run(sequences, outputs); double error = classifier.LogLikelihood(sequences, outputs); int hits = 0; toolStripProgressBar1.Visible = true; toolStripProgressBar1.Value = 0; toolStripProgressBar1.Step = 1; toolStripProgressBar1.Maximum = dataGridView1.Rows.Count; for (int i = 0; i < rows; i++) { double likelihood; int index = classifier.Compute(sequences[i], out likelihood); DataGridViewRow row = dataGridView1.Rows[i]; if (index == -1) { row.Cells["colClassification"].Value = String.Empty; } else { row.Cells["colClassification"].Value = classifier.Models[index].Tag; } int expected = (int)row.Cells["colLabel"].Value; if (expected == index + 1) { row.Cells[0].Style.BackColor = Color.LightGreen; row.Cells[1].Style.BackColor = Color.LightGreen; row.Cells[2].Style.BackColor = Color.LightGreen; hits++; } else { row.Cells[0].Style.BackColor = Color.White; row.Cells[1].Style.BackColor = Color.White; row.Cells[2].Style.BackColor = Color.White; } toolStripProgressBar1.PerformStep(); } dgvModels.DataSource = classifier.Models; toolStripProgressBar1.Visible = false; toolStripStatusLabel1.Text = String.Format("Training complete. Hits: {0}/{1} ({2:0%})", hits, dataGridView1.Rows.Count, (double)hits / dataGridView1.Rows.Count); }
public void SimpleGestureRecognitionTest() { // Let's say we would like to do a very simple mechanism for // gesture recognition. In this example, we will be trying to // create a classifier that can distinguish between the words // "hello", "car", and "wardrobe". // Let's say we decided to acquire some data, and we asked some // people to perform those words in front of a Kinect camera, and, // using Microsoft's SDK, we were able to captured the x and y // coordinates of each hand while the word was being performed. // Let's say we decided to represent our frames as: // // double[] frame = { leftHandX, leftHandY, rightHandX, rightHandY }; // // Since we captured words, this means we captured sequences of // frames as we described above. Let's write some of those as // rough examples to explain how gesture recognition can be done: double[][] hello = { new double[] { 1.0, 0.1, 0.0, 0.0 }, // let's say the word new double[] { 0.0, 1.0, 0.1, 0.1 }, // hello took 6 frames new double[] { 0.0, 1.0, 0.1, 0.1 }, // to be recorded. new double[] { 0.0, 0.0, 1.0, 0.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 }, new double[] { 0.0, 0.0, 0.1, 1.1 }, }; double[][] car = { new double[] { 0.0, 0.0, 0.0, 1.0 }, // the car word new double[] { 0.1, 0.0, 1.0, 0.1 }, // took only 4. new double[] { 0.0, 0.0, 0.1, 0.0 }, new double[] { 1.0, 0.0, 0.0, 0.0 }, }; double[][] wardrobe = { new double[] { 0.0, 0.0, 1.0, 0.0 }, // same for the new double[] { 0.1, 0.0, 1.0, 0.1 }, // wardrobe word. new double[] { 0.0, 0.1, 1.0, 0.0 }, new double[] { 0.1, 0.0, 1.0, 0.1 }, }; // Here, please note that a real-world example would involve *lots* // of samples for each word. Here, we are considering just one from // each class which is clearly sub-optimal and should _never_ be done // on practice. For example purposes, however, please disregard this. // Those are the words we have in our vocabulary: // double[][][] words = { hello, car, wardrobe }; // Now, let's associate integer labels with them. This is needed // for the case where there are multiple samples for each word. // int[] labels = { 0, 1, 2 }; // We will create our classifiers assuming an independent // Gaussian distribution for each component in our feature // vectors (like assuming a Naive Bayes assumption). var initial = new Independent<NormalDistribution> ( new NormalDistribution(0, 1), new NormalDistribution(0, 1), new NormalDistribution(0, 1), new NormalDistribution(0, 1) ); // Now, we can proceed and create our classifier. // int numberOfWords = 3; // we are trying to distinguish between 3 words int numberOfStates = 5; // this value can be found by trial-and-error var hmm = new HiddenMarkovClassifier<Independent<NormalDistribution>> ( classes: numberOfWords, topology: new Forward(numberOfStates), // word classifiers should use a forward topology initial: initial ); // Create a new learning algorithm to train the sequence classifier var teacher = new HiddenMarkovClassifierLearning<Independent<NormalDistribution>>(hmm, // Train each model until the log-likelihood changes less than 0.001 modelIndex => new BaumWelchLearning<Independent<NormalDistribution>>(hmm.Models[modelIndex]) { Tolerance = 0.001, Iterations = 100, // This is necessary so the code doesn't blow up when it realize // there is only one sample per word class. But this could also be // needed in normal situations as well. // FittingOptions = new IndependentOptions() { InnerOption = new NormalOptions() { Regularization = 1e-5 } } } ); // Finally, we can run the learning algorithm! double logLikelihood = teacher.Run(words, labels); // At this point, the classifier should be successfully // able to distinguish between our three word classes: // int tc1 = hmm.Compute(hello); int tc2 = hmm.Compute(car); int tc3 = hmm.Compute(wardrobe); Assert.AreEqual(0, tc1); Assert.AreEqual(1, tc2); Assert.AreEqual(2, tc3); // Now, we can use the Markov classifier to initialize a HCRF var function = new MarkovMultivariateFunction(hmm); var hcrf = new HiddenConditionalRandomField<double[]>(function); // We can check that both are equivalent, although they have // formulations that can be learned with different methods // for (int i = 0; i < words.Length; i++) { // Should be the same int expected = hmm.Compute(words[i]); int actual = hcrf.Compute(words[i]); // Should be the same double h0 = hmm.LogLikelihood(words[i], 0); double c0 = hcrf.LogLikelihood(words[i], 0); double h1 = hmm.LogLikelihood(words[i], 1); double c1 = hcrf.LogLikelihood(words[i], 1); double h2 = hmm.LogLikelihood(words[i], 2); double c2 = hcrf.LogLikelihood(words[i], 2); Assert.AreEqual(expected, actual); Assert.AreEqual(h0, c0, 1e-10); Assert.IsTrue(h1.IsRelativelyEqual(c1, 1e-10)); Assert.IsTrue(h2.IsRelativelyEqual(c2, 1e-10)); Assert.IsFalse(double.IsNaN(c0)); Assert.IsFalse(double.IsNaN(c1)); Assert.IsFalse(double.IsNaN(c2)); } // Now we can learn the HCRF using one of the best learning // algorithms available, Resilient Backpropagation learning: // Create a learning algorithm var rprop = new HiddenResilientGradientLearning<double[]>(hcrf) { Iterations = 50, Tolerance = 1e-5 }; // Run the algorithm and learn the models double error = rprop.Run(words, labels); // At this point, the HCRF should be successfully // able to distinguish between our three word classes: // int hc1 = hcrf.Compute(hello); int hc2 = hcrf.Compute(car); int hc3 = hcrf.Compute(wardrobe); Assert.AreEqual(0, hc1); Assert.AreEqual(1, hc2); Assert.AreEqual(2, hc3); }