我正在开发一个项目,需要进行手势识别。在寻找实现方法的过程中,我发现了动态时间扭曲。为了尝试这个想法,并且由于我的项目是用C#开发的,我决定尝试使用Accord.NET。在将其应用到我的项目之前,我创建了一个新的项目,并修改了Accord.NET文档中的示例,该示例可以在这里找到:
http://accord-framework.net/docs/html/T_Accord_Statistics_Kernels_DynamicTimeWarping.htm
目前,我正在尝试用一组学习数据(包括向右滑动、向左滑动和双击手势)来训练我的算法,然后使用学习数据中的相同示例来查看算法是否能正确识别手势。这些值只是示例,并非真实数据。
文档对于如何做到这一点的说明并不清晰,因为示例中使用的Decide方法只返回一个布尔值。我在文档中搜索了如何识别正确类的其他方法,但没有找到答案。
我找到的唯一线索是以下这行代码,但它返回的是0或1的整数值,而不是布尔值:
var res1 = ((IClassifier)svm.ToMulticlass()).Decide(sequences[0]);
有没有人能指导我如何正确识别手势?这是我第一次尝试机器学习和Accord.NET,所以这一切对我来说都是全新的。示例代码如下所示:
namespace DynamicTimeWarpingExample{ public class Program { public static void Main(string[] args) { double[][][] sequences = { new double[][] // 向左滑动 { new double[] { 1, 1, 1 }, new double[] { 1, 2, 1 }, new double[] { 1, 2, 2 }, new double[] { 2, 2, 2 }, }, new double[][] // 向右滑动 { new double[] { 1, 10, 6 }, new double[] { 1, 5, 6 }, new double[] { 6, 7, 1 }, }, new double[][] // 双击 { new double[] { 8, 2, 5 }, new double[] { 1, 50, 4 }, } }; int[] outputs = { 0, // 向左滑动 1, // 向右滑动 2 // 双击 }; var smo = new SequentialMinimalOptimization<DynamicTimeWarping, double[][]>() { Complexity = 1.5, Kernel = new DynamicTimeWarping(alpha: 1, degree: 1) }; var svm = smo.Learn(sequences, outputs); bool[] predicted = svm.Decide(sequences); double error = new ZeroOneLoss(outputs).Loss(predicted); // 错误将为0.0 var res1 = ((IClassifier<double[][], int>)svm.ToMulticlass()).Decide(sequences[0]); // 返回0 var res2 = ((IClassifier<double[][], int>)svm.ToMulticlass()).Decide(sequences[1]); // 返回1 var res3 = ((IClassifier<double[][], int>)svm.ToMulticlass()).Decide(sequences[2]); // 返回1 } }}
***************** 新版本 *****************
public static void Main(string[] args){ double[][][] sequences = { new double[][] // 向左滑动 { new double[] { 1, 1, 1 }, new double[] { 1, 2, 1 }, new double[] { 1, 2, 2 }, new double[] { 2, 2, 2 }, }, new double[][] // 向右滑动 { new double[] { 1, 10, 6 }, new double[] { 1, 5, 6 }, new double[] { 6, 7, 1 }, }, new double[][] // 双击 { new double[] { 8, 2, 5 }, new double[] { 1, 50, 4 }, } }; int[] outputs = { 0, // 向左滑动 1, // 向右滑动 2 // 双击 }; var teacher = new MulticlassSupportVectorLearning<DynamicTimeWarping, double[][]>() { // 配置学习算法使用SMO来训练每个二元类子问题的底层SVM。 Learner = (param) => new SequentialMinimalOptimization<DynamicTimeWarping, double[][]> { Complexity = 1.5, Kernel = new DynamicTimeWarping(alpha: 1, degree: 1), //UseKernelEstimation = true } }; // 学习机器 var machine = teacher.Learn(sequences, outputs); // 为机器创建多类学习算法 var calibration = new MulticlassSupportVectorLearning<DynamicTimeWarping, double[][]>() { Model = machine, // 我们将从现有机器开始 // 配置学习算法使用Platt的校准 Learner = (param) => new ProbabilisticOutputCalibration<DynamicTimeWarping, double[][]>() { Model = param.Model // 从现有机器开始 } }; // 配置并行执行选项 calibration.ParallelOptions.MaxDegreeOfParallelism = 1; // 学习机器 calibration.Learn(sequences, outputs); double decision1, decision2, decision3, decision4, decision5, decision6; var res1 = machine.Probability(sequences[0], out decision1); // 决策0 - 概率0.78698604216159851 - 分数1 var res2 = machine.Probability(sequences[1], out decision2); // 决策1 - 概率0.67246889837875257 - 分数1 var res3 = machine.Probability(sequences[2], out decision3); // 决策2 - 概率0.78698604216159851 - 分数1 var newGesture1 = new double[][] { new double[] { 1, 1, 1 }, new double[] { 1, 2, 1 }, new double[] { 1, 2, 2 }, new double[] { 2, 2, 2 }, }; var newGesture2 = new double[][] { new double[] { 1, 10, 6 }, new double[] { 1, 5, 6 }, new double[] { 6, 7, 1 }, }; var newGesture3 = new double[][] { new double[] { 8, 2, 5 }, new double[] { 1, 50, 4 }, }; var res5 = machine.Score(newGesture1, out decision5); // 决策0 - 概率0.35577588944247057 - 分数0.051251948605637254 var res6 = machine.Score(newGesture2, out decision6); // 决策1 - 概率0.40733908994050544 - 分数0.19912250476931792 var res4 = machine.Score(newGesture3, out decision4); // 决策2 - 概率0.71853321355842836 - 分数0.816934034911964}
回答:
问题在于您正在为一个涉及多个类的问题创建一个二元分类器。
在您的情况下,不是这样做:
var smo = new SequentialMinimalOptimization<DynamicTimeWarping, double[][]>() { Complexity = 1.5, Kernel = new DynamicTimeWarping(alpha: 1, degree: 1)};var svm = smo.Learn(sequences, outputs);
您应该将这个二元学习问题包装成多类学习,如下所示:
// 为机器创建多类学习算法var teacher = new MulticlassSupportVectorLearning<DynamicTimeWarping, double[][]>(){ // 配置学习算法使用SMO来训练每个二元类子问题的底层SVM。 Learner = (param) => new SequentialMinimalOptimization<DynamicTimeWarping, double[][]> { Complexity = 1.5, Kernel = new DynamicTimeWarping(alpha: 1, degree: 1) };}// 学习机器var svm = teacher.Learn(inputs, outputs);