Перейти к содержимому
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);

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В смысле целые числа, так-то функция возвращает 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;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
31 минуту назад, Smorodov сказал:

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну например значения векторов у меня такие: 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 автор в разделе Уверенность классификации говорит о некоем значении классифицирующей функции, по которому можно судить о достоверности классификации. Где ее, эту функцию взять?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Регрессия вроде именно регрессия, но применять её к задаче классификации не адекватно, т.к. у вас 'расстояние' между 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Цитата

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

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

 

Можно CNN

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

На python полегче:

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

histogram.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×