为什么这个清理后的数据会提供奇怪的SVM分类结果?

我的问题和疑问在下文中加粗显示。

我通过遵循Accord.NET文档页面上的示例,如这个,成功使用了Accord.NET的支持向量机。然而,当使用KernelSupportVectorMachineOneclassSupportVectorLearning进行训练时,训练过程产生了较大的误差值和错误的分类结果

下面的最小示例展示了我的意思。它生成一个密集的训练点集,然后训练一个SVM来将点分类为集群的内点或外点。训练集群只是一个以原点为中心的0.6 x 0.6的正方形,训练点以0.1的间隔排列:

static void Main(string[] args){    // 模型和训练参数    double kernelSigma = 0.1;    double teacherNu = 0.5;    double teacherTolerance = 0.01;    // 生成输入点云,一个以0,0为中心的0.6 x 0.6的正方形。    double[][] trainingInputs = new double[49][];    int inputIdx = 0;    for (double x = -0.3; x <= 0.31; x += 0.1) {        for (double y = -0.3; y <= 0.31; y += 0.1) {            trainingInputs[inputIdx] = new double[] { x, y };            inputIdx++;        }    }    // 生成内点和外点测试点。    double[][] outliers =    {        new double[] { 1E6, 1E6 },  // 非常远的外点        new double[] { 0, 1E6 },    // 非常远的外点        new double[] { 100, -100 }, // 远的外点        new double[] { 0, -100 },   // 远的外点        new double[] { -10, -10 },  // 仍然是远的外点        new double[] { 0, -10 },    // 仍然是远的外点    };    double[][] inliers =    {        new double[] { 0, 0 },      // 集群中间        new double[] { .15, .15 },  // 集群角落的一半处        new double[] { -0.1, 0 },   // 舒适地在集群内部        new double[] { 0.25, 0 }    // 接近集群内部边缘    };    // 构建内核、模型和训练器,然后进行训练。    Console.WriteLine($"训练模型的参数如下:");    Console.WriteLine($"  kernelSigma = {kernelSigma.ToString("#.##")}");    Console.WriteLine($"  teacherNu={teacherNu.ToString("#.##")}");    Console.WriteLine($"  teacherTolerance={teacherTolerance}");    Console.WriteLine();    var kernel = new Gaussian(kernelSigma);    var svm = new KernelSupportVectorMachine(kernel, inputs: 1);    var teacher = new OneclassSupportVectorLearning(svm, trainingInputs)    {        Nu = teacherNu,        Tolerance = teacherTolerance    };    double error = teacher.Run();    Console.WriteLine($"训练完成 - 误差为 {error.ToString("#.##")}");    Console.WriteLine();    // 测试训练后的分类器。    Console.WriteLine("测试外点:");    foreach (double[] outlier in outliers) {        WriteResultDetail(svm, outlier);    }    Console.WriteLine();    Console.WriteLine("测试内点:");    foreach (double[] inlier in inliers) {        WriteResultDetail(svm, inlier);    }}private static void WriteResultDetail(KernelSupportVectorMachine svm, double[] coordinate){    string prettyCoord = $"{{ {string.Join(", ", coordinate)} }}".PadRight(20);    Console.Write($"分类: {prettyCoord} 结果: ");    // 分类坐标,打印结果。    double result = svm.Compute(coordinate);    if (Math.Sign(result) == 1) {        Console.Write("内点");    }    else {        Console.Write("外点");    }    Console.Write($" ({result.ToString("#.##")})\n");}

以下是合理参数集的输出结果:

训练模型的参数如下:  kernelSigma = .1  teacherNu=.5  teacherTolerance=0.01训练完成 - 误差为 222.4测试外点:分类: { 1000000, 1000000 } 结果: 内点 (2.28)分类: { 0, 1000000 }       结果: 内点 (2.28)分类: { 100, -100 }        结果: 内点 (2.28)分类: { 0, -100 }          结果: 内点 (2.28)分类: { -10, -10 }         结果: 内点 (2.28)分类: { 0, -10 }           结果: 内点 (2.28)测试内点:分类: { 0, 0 }             结果: 内点 (4.58)分类: { 0.15, 0.15 }       结果: 内点 (4.51)分类: { -0.1, 0 }          结果: 内点 (4.55)分类: { 0.25, 0 }          结果: 内点 (4.64)

括号中的数字是SVM为该坐标给出的分数。使用Accord.NET的SVM(以及一般情况下),负分数表示一个类别,正分数表示另一个类别。在这里,所有结果都是正分数。内点被正确分类,但外点(即使是非常远的外点)也被分类为内点。

请注意,以前我使用Accord.NET训练模型时,训练误差总是非常接近于零,但在这里误差超过了200。

这是另一组参数的输出结果:

训练模型的参数如下:  kernelSigma = .3  teacherNu=.8  teacherTolerance=0.01训练完成 - 误差为 1945.67测试外点:分类: { 1000000, 1000000 } 结果: 内点 (20.96)分类: { 0, 1000000 }       结果: 内点 (20.96)分类: { 100, -100 }        结果: 内点 (20.96)分类: { 0, -100 }          结果: 内点 (20.96)分类: { -10, -10 }         结果: 内点 (20.96)分类: { 0, -10 }           结果: 内点 (20.96)测试内点:分类: { 0, 0 }             结果: 内点 (44.52)分类: { 0.15, 0.15 }       结果: 内点 (41.62)分类: { -0.1, 0 }          结果: 内点 (43.85)分类: { 0.25, 0 }          结果: 内点 (40.53)

同样,训练误差非常高,所有分数都是正的。

模型确实从训练中得到了一些东西——内点和外点的分数是不同的。但为什么这个简单的场景没有像应该的那样给出正负符号不同的结果呢?


附注:这里有一个类似的程序,它测试了许多训练和模型参数的组合,这里是它的输出。同样,所有结果都是正的分类分数,高误差值,以及错误分类的外点。


回答:

问题中提出的问题已在Accord.NET的3.7.0版本中得到解决。还添加了一个与您的示例相似的单元测试,在提交be81aab中完成。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注