Jump to content
Compvision.ru
Андрей_Андрей

svm.predict возвращает int, вместо float.

Recommended Posts

Коллеги, svm.predict возвращает мне int, вместо float. Я никак не могу оценить с какой достоверностью он мне распознает. Что я делаю не так? 
код примерно такой (С++):

vector <float>predicted_vector(img_vector.size());{
        for (int i = 0; i < img_vector.size(); i++){
            img_vector = symbRecognitor.deskew(img_vector); //наклон перед распознаванием
            hists = symbRecognitor.preprocess_hog(img_vector); // hog
            predicted_vector = svm.predict(hists, true);
            ....
}

вот параметры: 

 SVMParams param;
    param.kernel_type = SVM::POLY;
    param.svm_type = SVM::C_SVC;
    param.C = 1;
    svm.load(datFilePath);

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

дистанция до гиперплоскости меня абсолютно устроит. и в документации говорят, что, мол если returnDFVal = true, то predict ее и вернет . а у меня все равно int на выходе...
как мне ее (дистанцию) получить? 

Share this post


Link to post
Share on other sites

В смысле целые числа, так-то функция возвращает float. 

Попробуйте запустить OpenCV-шный пример points_classifier, для SVM ну допилить чуть, чтобы выдавал расстояние, до границы, сможете визуально проверить то он выдает или нет.

Глянул еще раз документацию, похоже оптимизация идет на сетке

Generates a grid for SVM parameters.

C++: CvParamGrid CvSVM::get_default_grid(int param_id)
Parameters:
  • param_id 

    SVM parameters IDs that must be one of the following:

    • CvSVM::C
    • CvSVM::GAMMA
    • CvSVM::P
    • CvSVM::NU
    • CvSVM::COEF
    • CvSVM::DEGREE

    The grid is generated for the parameter with this ID.

The function generates a grid for the specified parameter of the SVM algorithm. The grid may be passed to the function CvSVM::train_auto().

Сетка строится по параметрам, которые вы задаете, возможно она в вашем случае целочисленная. 

 

Но вообще там double

CvParamGrid::CvParamGrid

The constructors.

C++: CvParamGrid::CvParamGrid()
 
C++: CvParamGrid::CvParamGrid(double min_val, double max_val, double log_step)
 

The full constructor initializes corresponding members. The default constructor creates a dummy grid:

CvParamGrid::CvParamGrid()
{
    min_val = max_val = step = 0;
}

 

Share this post


Link to post
Share on other sites
31 минуту назад, Smorodov сказал:

Сетка строится по параметрам, которые вы задаете, возможно она в вашем (?) случае целочисленная. 

Спасибо. запускаю points_classifier, разбираюсь.

svm.predict возвращает float, но десятичная часть всегда ==0 . 
я не очень Вас понял - какой именно параметр из Вашего списка у меня может быть целочисленный?
я распознаю символы на картинке методом hog + svm
пробую выводить svm.get_support_vector(i) - для совершенно разных символов он мне выводит абсолютно одинаковые числа. 

 

Share this post


Link to post
Share on other sites

По поводу svm.get_support_vector, в SVM по определению расстояния до опорных векторов  вроде как всегда равно единице (ну или величине зазора, если они не нормированы, но одинаковые), в SVM c "мягкой" (soft margin svm) границей возможны варианты. Параметр С, насколько я помню, как раз и задает "жесткость" границы.

Не параметр целочисленный, а, возможно, сетка целочисленная используется при решении, поэтому и расстояния целые.

Я расстояния до границы не использовал в SVM, так что могу только предполагать.

Share this post


Link to post
Share on other sites

оох. Андрей Владимирович, расстояние не меняется ни в примере points_classifier, ни у меня в программе, и не зависит от параметра С. я ставил С =1000, и цифры суппорт вектора абсолютно такие-же вне зависимости даже от того, корректно распознался символ, или нет. Подскажите что еще можно подумать?

Share this post


Link to post
Share on other sites

А одно и тоже значение какое выдаёт? может какой то 'краевой' случай?

 

Есть такой пример, правда он на питоне, но хотя бы можно параметры SVM оттуда взять

http://docs.opencv.org/trunk/dd/d3b/tutorial_py_svm_opencv.html

Share this post


Link to post
Share on other sites

ну например значения векторов у меня такие: 0.055761, 0.0971997, 0.188256, 0.149404, 0.176307, 0.16017, 0.167007, 0.0969387 
количество векторов - всегда 5650, сумма значений длин векторов для разных символов тоже одинаковая. Например для первого она вседа 536.1, для второго 634.7 и т.д. но эти цифры повторяются, для разных символов, в том числе для неправильно распознанных. 
Я как-раз все и делаю на основе этого примера. 

Вот тут: http://www.recognition.mccme.ru/pub/RecognitionLab.html/methods.html#nonLinearSVM автор в разделе Уверенность классификации говорит о некоем значении классифицирующей функции, по которому можно судить о достоверности классификации. Где ее, эту функцию взять?

Share this post


Link to post
Share on other sites

Проверить не могу, у меня версия 3.x там такого параметра нет, только что попробовал.

Share this post


Link to post
Share on other sites

может у вас это getDecisionFunction()?

в opencv2 svm.predict(Mat img, true) должен мне возвращать это значение  отражающее дистанцию от плоскости. но почему-то он мне возвращает label... Кто знает почему?

Share this post


Link to post
Share on other sites

Есть один выход, открыть исходники и посмотреть, что делается при установленном флаге returnDFVal = true.

Share this post


Link to post
Share on other sites

Похоже проблема в том, что я использую классификацию, CvSVM::C_SVC C-Support Vector Classification; а должен исп регрессию CvSVM::EPS_SVR \epsilon-Support Vector Regression. тогда predict вернет значение функции. 
переучиваю каскад. 

UPD. predict стал возвращать float. но количество ошибок с 0.11% выросло до 74%... а новый *.dat файл
стал размером в 1 кБ вместо 6кБ у старого..

что-то не так.. 

Share this post


Link to post
Share on other sites

Что то мне подсказывает, что SVR служит для интерполяции функций по точкам. 

Share this post


Link to post
Share on other sites

Регрессия вроде именно регрессия, но применять её к задаче классификации не адекватно, т.к. у вас 'расстояние' между 1 и 2 будет меньше чем между 1 и 10, а в задаче классификации 'расстояние' должно быть одинаковым.

По вероятности есть такой вот раздел в LibSVM:

http://www.csie.ntu.edu.tw/~cjlin/papers/libsvm.pdf

8 Probability Estimates (page 30)

SVM predicts only class label (target value for regression) without probability information.

 

Можно вот такой хак (прочитайте коменты):

https://stackoverflow.com/a/27739386/1179925

P.s. простым языком объяснить можно почему confidence score!=probability?

 

От себя добавлю:

Я пробовал решать https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition#evaluation

там предполагается что вы предсказываете вероятность собаки для картинки в интервале [0,1]

Я использовал Linear SVM поверх CNN фич и результат был не очень(т.е. хуже чем просто ответы CNN затрейненой с Softmax ), видимо потому, что пробабилити из SVM было не 'затюнено'?

http://scikit-learn.org/stable/auto_examples/calibration/plot_calibration_curve.html#sphx-glr-auto-examples-calibration-plot-calibration-curve-py

 

Вот еще некоторые ссылки по теме:

https://stackoverflow.com/questions/26478000/converting-linearsvcs-decision-function-to-probabilities-scikit-learn-python

https://stackoverflow.com/questions/15111408/how-does-sklearn-svm-svcs-function-predict-proba-work-internally

 

 

 

UPDATE:

If true and the problem is 2-class classification then the method returns the decision function value that is signed distance to the margin, else the function returns a class label (classification) or estimated function value (regression).

Прочитал еще раз и понял что distance to hyperplane возвращается только в случае бинарной классификации, т.е. когда например 10 цифр то возращается по тихому лейбл.

Вот и код

https://github.com/opencv/opencv/blob/f70cc29edb8a606fb859eaa67a4c9609f7f904fa/modules/ml/src/svm.cpp#L1913

Share this post


Link to post
Share on other sites

Коллеги, огромное спасибо за Ваши комментарии.

Насколько я понимаю, получить значение функции для классификации у меня нет вариантов, бо я распознаю 22 символа (буквы и цифры)  и это никак не бинарная классификация. У меня нет проблемы, что получить из алгоритма - надежность (confidence) или вероятность (probability) - мне хоть-бы что-нибудь заиметь, уже было-бы неплохо, т.к. сейчас нет вообще ничего. Из описания упомянутого mrgloom'ом в предыдущем посте хака, я вынес только то, что все сказанное справедливо только для бинарной классификации, что не есть мой случай.

Разбираюсь в упомянутом RVM.  

Беда моя в том, что без достоверности (вероятности),в любом виде, ничего у меня не выйдет, т.к. у меня нет четких областей в которых я распознаю символ. а есть набор предположительно областей, каждую из которых я отправляю на распознавание и вот по достоверности( вероятности) хотел определять, что-же за символ на самом деле передо мной. 

Что еще можно придумать, прежде чем отказаться от SVM в пользу другого алгоритма?

Share this post


Link to post
Share on other sites

Не ну есть конечно метод, но он "через назад".

Можно обучить по бинарному SVM классификатору на каждый символ. Дальше думаю понятно. 

Share this post


Link to post
Share on other sites
Цитата

Беда моя в том, что без достоверности (вероятности),в любом виде, ничего у меня не выйдет, т.к. у меня нет четких областей в которых я распознаю символ. а есть набор предположительно областей, каждую из которых я отправляю на распознавание и вот по достоверности( вероятности) хотел определять, что-же за символ на самом деле передо мной. 

Может решить бинарную задачу символ-не символ? если я правильно понял у вас что то типа скользящего окна по изображению на котором есть символы и фон и вы хотите по порогу определить где фон.

 

Можно CNN

На С++: Caffe+DIGITS можно легко обучить, деплой чуть сложнее.

На python полегче:

Если хотите sliding window можете присмотреться к этому примеру, который будет быстрее чем naive sliding window.

https://github.com/mrgloom/Fully-Convolutional-Example/blob/master/fully_convolutional_example.ipynb

 

Share this post


Link to post
Share on other sites

нет, это не скользящее окно. это символы автомобильного номера, разделенные  по градиенту яркости вдоль широкой стороны номера.

в целом все хорошо, но есть символы,  которые этим алгоритмом режутся пополам ( м, н, 8, 6  )  - у всех них есть ложный максимум гистограммы  яркости посередине, довольно большой, простым сравнением с соседними  надежно отфильтровать его не удается. А для буквы М он даже выше чем соседние максимумы. И вот дилемма - то-ли это 2 цифры "1"? то-ли одна буква "м"... вот как-то так.

вроде питонская библиотека sklearn.svm обучает классификатор с возможностью определять вероятность, но эта либа не для С++.
Ищу аналог. вот народ вроде про аналоги пишет: https://stackoverflow.com/questions/11378819/scikit-learn-equivalent-for-c

не знаю во что у меня все эти приседания выльются в плане быстродействия...
 

histogram.jpg

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×