2014-10-20 4 views
3

Я уже давно застрял в этом. Реализация SVM OpenCV, похоже, не работает для линейного ядра. Я уверен, что в коде нет ошибки: когда я изменяю kernel_type на RBF или POLY, сохраняя все остальное как есть, он работает.OpenCV Linear SVM не тренируется

Причина, по которой я говорю, что она не работает, я сохраняю сгенерированную модель и проверяю ее. Он показывает количество векторов поддержки как 1. Что не имеет места в RBF или полиномиальных ядрах.

В коде нет ничего особенного, я использовал ранее реализацию SVM OpenCV, но никогда не линейное ядро. Я попытался установить degree на 1 в ядре POLY, и это приводит к той же модели. Это заставляет меня думать, что здесь что-то не так.

Код структуры, если это необходимо:

Mat trainingdata; //acquire from files. done and correct. 
Mat testingdata;  //acquire from files. done and correct again. 
Mat labels;   //corresponding labels. checked and correct. 

SVM my_svm; 
SVMParams my_params; 
my_params.svm_type = SVM::C_SVC; 
my_params.kernel_type = SVM::LINEAR; //or poly, with my_params.degree = 1. 
my_param.C = 0.02; //doesn't matter if I set it to 20000, makes no difference. 

my_svm.train(trainingdata, labels, Mat(), Mat(), my_params); 
//train_auto(..) function with 10-fold cross-validation takes the same time as above (~2sec)! 
Mat responses; 
my_svm.predict(testingdata, responses); 
//responses matrix is all wrong. 

У меня есть 500 образцов из одного класса и 600 из другого класса, чтобы проверить, и правильные классификации я получаю: 1/500 и 597/600.

Самая сухая часть: Я сделал тот же эксперимент с теми же данными об обертке libSVM MATLAB, и он работает. Просто пытался сделать версию OpenCV.

+0

Вы уверены, что данные линейно разделены? Тот факт, что он работает с ядрами fancier, настоятельно предлагает нелинейно разделяемые данные ... Вы тренируете libSVM с использованием линейных ядер? –

+0

Вы знаете формулировку SVM? При установке C на 0,02 или 20000 должна быть разница. Убедитесь, что вы правильно установили его. Он не может быть одинаковым для всех параметров. Также вы должны установить параметр epsilon равным 0,001, по умолчанию это еще что-то AFAIK. Последнее, что происходит, когда вы запускаете 'train_auto()' вместо 'train()'? – guneykayim

+1

Попробуйте адаптировать примеры стандартных примеров/cpp/points_classifier.cpp, также существует svm-классификатор. Я проверил его, и это сработало. –

ответ

2

Это не ошибка, когда вы всегда получаете только один вектор поддержки с linear CvSVM.

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

Параметр C Не имеет значения, являются ли ваши данные для обучения линейно разделяемыми. Возможно, это ваше дело.

+0

Я не понимаю, как разделительная гиперплоскость _ всего лишь один вектор поддержки. И кроме того, я использовал линейные SVM ранее и получил ряд поддерживающих векторов (что хорошо работает с идеями обложения и обобщения). –

+0

И 'C' будет полезен в случаях, когда шум влияет на классификацию; присутствие шума не является большим предположением (по крайней мере в этом случае). –

+0

Когда svm тренируется, он использует некоторое количество опорных векторов, которые лежат на краю или внутри него (если мы используем «мягкий» запас). Но когда opencv хранит подготовленный классификатор - единственной требуемой ему информацией является только один вектор (нормальный к гиперплоскости), который определяет дискриминационную гиперплоскость. http://www.songho.ca/math/plane/plane.html – Temak