8

我正在使用libsvm并且做了一个非常简单的实验,训练 10k 个向量并仅使用 22 个进行测试。我正在使用带参数 cost 的线性内核C=1。我的问题是多类。所以 Libsvm 将使用一对一的方法对我的数据进行分类。Libsvm 使用SMO来寻找分离的超平面。

我的一个朋友做了同样的实验,但使用的 SVM 分类器来自Statistics Toolbox。他还使用了R 的e1071包。同样,使用的内核是线性内核,参数成本C等于 1,并且在 MATLAB 中使用一对一的方法对数据进行分类(一对一方法是由我的朋友编写的)和 e1071 R 包。默认情况下,R 中的 MATLAB Statistics Toolbox 和 e1071 都使用 SMO 方法来查找分离超平面。

我还尝试了最新的LIBLINEAR库。同样,使用了相同的配置。


以下是使用的代码:

libsvm 3.18(命令行)

./svm-scale -s train.range train.libsvm > train.scale 
./svm-scale -r train.range test.libsvm > test.scale
./svm-train -t 0 -c 1 train.scale train.model
./svm-predict test.scale train.model test.predict

liblinear 1.94(命令行)

./svm-scale -s train.range train.libsvm > train.scale 
./svm-scale -r train.range test.libsvm > test.scale
./train train.scale train.model
./predict test.scale train.model test.predict

R

rm(list = ls())
cat("\014")
library(e1071)

cat("Training model\n")
Traindata = read.csv("train.csv", header=FALSE)
SVM_model = svm(Traindata[,2:ncol(Traindata)], Traindata[,1], kernel="linear",     tolerance=0.1, type="C-classification")
print(SVM_model)

cat("Testing model\n")
Testdata = read.csv("test.csv", header=FALSE)
Preddata = predict(SVM_model, Testdata[,2:ncol(Testdata)])

ConfMat = table(pred=Preddata, true=Testdata[,1])
print(ConfMat)

accuracy = 0
for (i in 1 : nrow(ConfMat)) {
   for (j in 1 : ncol(ConfMat)) {
       if (i == j) {
          accuracy = accuracy + ConfMat[i, i]
       }
   }
 }
 accuracy = (accuracy / sum(ConfMat)) * 100
 cat("Test vectors:", dim(Testdata), ", Accuracy =", accuracy, "%\n")

有一些精度差异:

  • Libsvm 正确分类了 22 个测试特征向量中的 11 个
  • Liblinear 正确分类了 22 个测试特征向量中的 18 个
  • R 正确分类了 22 个测试特征向量中的 17 个
  • 我朋友的一对一 MATLAB 实现正确分类了 22 个特征向量中的 19 个。

那么为什么预测不同呢?我的意思是,如果所有 SVM 都使用线性内核,具有相同的成本参数并使用相同的多类分类方法,那么结果不应该相同吗?

4

1 回答 1

7

首先让我谈谈R解决方案;据我了解,e1071包只是 libsvm 库的包装器。因此,假设您在两者中使用相同的设置和步骤,您应该得到相同的结果。

我自己不是普通的 R 用户,但我可以告诉你没有在 R 代码中执行数据规范化(为了将特征扩展到[-1,1]范围内)。我们知道 SVM 不是尺度不变的,所以这个遗漏应该解释与其他结果的差异。


MATLAB 在svmtrainfitcsvm中有自己的实现。它仅支持二进制分类,因此您必须手动处理多类问题(参见此处的示例)。

文档解释说它使用标准 SMO 算法(实际上是为解决二次规划优化问题而提供的三种可能算法之一)。该文档在底部列出了几本书和论文作为参考。原则上,您应该得到与 libsvm 类似的预测(假设您复制使用的参数并对数据应用相同类型的预处理)。


现在至于libsvmliblinear,您应该知道实现在目标函数的制定方面略有不同:

  • libsvm 解决了以下双重问题: libsvm 对偶问题

  • 另一方面,带有 L2 正则化 L1-loss SVC 求解器的 liblinear 的对偶形式是: 线性对偶问题

...更不用说算法的编码考虑了不同的目标:libsvm 的编写方式允许在不同的内核函数之间切换,而 liblinear 被优化为始终是线性的并且根本没有内核的概念。这就是为什么 libsvm 不容易适用于大规模问题(即使使用线性内核)的原因,并且通常建议在您有大量实例时使用 liblinear。

此外,关于类的多类问题k,libsvm 默认通过构建二元分类器实现一对一的方法k*(k-1)/2,而 liblinear 通过构建二元分类器实现一对一的策略k(它也有一个由 Crammer 提供的替代方法和 Singer 用于处理多类问题)。我之前已经展示了如何使用 libsvm 执行 one-vs-rest 分类(请参阅此处此处)。

您还必须确保匹配传递给每个参数的参数(尽可能接近):

  • libsvm 应通过调用设置为具有线性内核的 C-SVM 分类器svm-train.exe -s 0 -t 0
  • liblinear 求解器类型应该L2R_L1LOSS_DUAL通过调用来设置train.exe -s 3(L2 正则化 L1 损失支持向量分类器的双重形式)
  • 成本参数显然应该与-c 1两个训练函数匹配
  • 终止标准的容差应该匹配(-e参数的默认值在两个库之间不同,e=0.001对于 libsvm 和e=0.1对于 liblinear)
  • 应该明确指示 liblinear 添加一个偏置项,因为它默认是禁用的(通过添加train.exe -B 1)。

即使那样,我也不确定你会在两者中得到完全相同的结果,但预测应该足够接近......

其他考虑因素包括库如何处理分类特征。例如,我知道 libsvm 将具有m可能值的分类特征转换为m编码为二进制指示符属性的数字 0-1 特征(即,其中只有一个为 1,其余为 0)。我不确定 liblinear 对离散特征做了什么。

另一个问题是特定实现是否具有确定性,并且在使用相同设置对相同数据重复时总是返回相同的结果。我在某处读到 liblinear 在其工作期间内部生成随机数,但请不要在没有实际检查源代码的情况下相信我的话:)

于 2014-05-07T01:55:13.853 回答