Различная точность в разных библиотеках SVM с одинаковыми параметрами для одних и тех же данных

Я использую libsvm, и я провел очень простой эксперимент, обучая 10К векторов и тестируя только 22. Я использую линейное ядро ​​с параметром cost C=1, Моя проблема мультиклассовая. Поэтому Libsvm будет использовать подход "один против одного" для классификации моих данных. Libsvm использует SMO для поиска разделяющей гиперплоскости.

Мой друг провел тот же эксперимент, но использовался классификатор SVM из набора инструментов статистики. Он также использовал пакет e1071 от R. Опять же, используемое ядро ​​было линейным ядром, параметр стоил C равен единице, и подход "один против одного" используется для классификации данных в MATLAB (подход "один против одного" был написан моим другом) и пакете e1071 R. И MATLAB Statistics Toolbox, и e1071 от R используют подход 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

р

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 правильно классифицировал 11 из 22 векторов признаков теста
  • Либлинерически правильно классифицировано 18 из 22 векторов признаков
  • R правильно классифицировано 17 из 22 векторов признаков
  • Реализация MATLAB "один против одного" моего друга правильно классифицировала 19 из 22 векторов признаков.

Так почему же прогнозы разные? Я имею в виду, если все SVM используют линейные ядра с одинаковым параметром стоимости и одинаковым подходом для мультиклассовой классификации, разве результат не должен быть одинаковым?

1 ответ

Решение

Сначала позвольте мне обратиться к решению R; Насколько я понимаю, пакет e1071 - это просто оболочка для библиотеки libsvm. Поэтому, предполагая, что вы используете одинаковые настройки и шаги в обоих случаях, вы должны получать одинаковые результаты.

Я сам не обычный пользователь R, но я могу сказать, что вы не выполняете нормализацию данных в коде R (для того, чтобы масштабировать функции в [-1,1] спектр). Как мы знаем, SVM не являются масштабно-инвариантными, поэтому это упущение должно объяснить отличие от других результатов.


MATLAB имеет свои собственные реализации в svmtrain и fitcsvm. Он поддерживает только двоичную классификацию, поэтому вам придется вручную обрабатывать многоклассовые проблемы (см. Пример здесь).

В документации объясняется, что он использует стандартный алгоритм SMO (фактически один из трех возможных алгоритмов, предлагаемых для решения задачи оптимизации квадратичного программирования). Документы перечисляют пару книг и бумаг внизу как ссылки. В принципе, вы должны получить такие же прогнозы, как libsvm (при условии, что вы копируете используемые параметры и применяете тот же вид предварительной обработки к данным).


Теперь, что касается libsvm против liblinear, вы должны знать, что реализации немного отличаются в формулировке целевой функции:

  • libsvm решает следующую двойственную проблему: двойная проблема

  • С другой стороны, двойственная форма либлинна с L2-регуляризованным решателем SVC с L1-потерями: либлинейная двойственная задача

... не говоря уже о том, что алгоритмы написаны с разными целями: libsvm написан таким образом, что позволяет переключаться между различными функциями ядра, а liblinear оптимизирован, чтобы всегда быть линейным и вообще не иметь представления о ядрах. Вот почему libsvm нелегко применить к задачам большого масштаба (даже с линейным ядром), и часто предлагается использовать liblinear, когда у вас есть большое количество экземпляров.

Кроме того, относительно многоклассовых проблем с k классы, libsvm по умолчанию реализует подход " один против одного", создавая k*(k-1)/2 двоичные классификаторы, в то время как liblinear реализует стратегию " один против остальных", создавая k двоичные классификаторы (у Crammer и Singer есть альтернативный метод для решения многоклассовых задач). Ранее я показал, как выполнить классификацию "один против остальных" с помощью libsvm (см. Здесь и здесь).

Вы также должны убедиться, что параметры соответствуют каждому (как можно ближе):

  • libsvm должен быть установлен в C-SVM классификатор с линейным ядром, вызывая svm-train.exe -s 0 -t 0
  • Тип liblinear solver должен быть установлен в L2R_L1LOSS_DUAL позвонив train.exe -s 3 (двойная форма L2-регуляризованного классификатора опорных векторов L1-потерь)
  • параметр стоимости, очевидно, должен совпадать -c 1 для обеих тренировочных функций
  • допуск для критерия завершения должен совпадать (значение по умолчанию -e параметр отличается между двумя библиотеками, с e=0.001 для libsvm и e=0.1 для либлинейных)
  • liblinear должно быть явно указано, чтобы добавить термин смещения, так как он отключен по умолчанию (путем добавления train.exe -B 1).

Даже тогда, я не уверен, что вы получите одинаковые результаты в обоих случаях, но прогнозы должны быть достаточно близки...

Другие соображения включают в себя то, как библиотеки обрабатывают категориальные функции. Например, я знаю, что libsvm преобразует категорическую особенность с m возможные значения в m числовые 0-1 объекты, закодированные как атрибуты двоичного индикатора (т. е. только один из них - один, остальные - нули). Я не уверен, что liblinear делает с дискретными функциями.

Другая проблема заключается в том, является ли конкретная реализация детерминированной и всегда возвращает одинаковые результаты при повторении для одних и тех же данных с использованием одинаковых настроек. Я где-то читал, что liblinear внутренне генерирует случайные числа во время своей работы, но, пожалуйста, не поверьте мне на слово, не проверив исходный код:)

Другие вопросы по тегам