Smorodov 579 Жалоба Опубликовано December 27, 2010 Простой пример для экспериментов с SVM OpenCv213.rar SVM - Машина опорных векторов, может использоваться для классификации , и аппроксимации. В данном примере пользователь ставит на экране точки, относя их к 0 или 1 классу (классов может быть и больше) при помощи левой или правой кнопок мыши. Затем нужно нажать "s" , программа обучит SVM и просчитает к какому классу отнести каждую из точек экрана. Очистка производится кнопкой "r". 2 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 9, 2011 Всем привет, вот пытаюсь разобраться с SVM реализовал его вроде всё работает для двух классов всё считается хорошо, красные точки это 0 класс, зелёные это 1-ый и я ещё добавил ещё один 2-ой класс синие точки они заданы константно в программе // testApp.cpp: определяет точку входа для консольного приложения. // #include "stdafx.h" #include <cv.hpp> #include <opencv2\opencv.hpp> #include <opencv2\highgui\highgui.hpp> #include <opencv2\ml\ml.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <string> #include <iostream> using namespace std; using namespace cv; Mat img = Mat::zeros(Size(640,480),CV_8UC3); SVM svm; const int num_features = 2; struct TFeature { Point pt;//int pt[num_features]; int value; }; typedef vector<TFeature> TFeatureList; TFeatureList points; void Update(void) { for(int i=0; i<points.size(); i++) { if(points[i].value == 1) { circle(img,points[i].pt,3,CV_RGB(0,255,0),-1); } if(points[i].value == 0) { circle(img,points[i].pt,3,CV_RGB(255,0,0),-1); } if(points[i].value == 2) { circle(img,points[i].pt,3,CV_RGB(0,0,255),-1); } } } void on_mouse(int event, int x, int y, int flags, void* ) { if(img.empty()) return; TFeature pts; if(event == CV_EVENT_LBUTTONDOWN) { pts.pt = Point(x,y); pts.value = 0; points.push_back(pts); img = Mat::zeros(Size(640,480),CV_8UC3);; Update(); } if( event == CV_EVENT_RBUTTONDOWN) { pts.pt = Point(x,y); pts.value = 1; points.push_back(pts); img = Mat::zeros(Size(640,480),CV_8UC3);; Update(); } } void TrainSVM(void) { int num_sampl = points.size(); float myC = 100; float myGamma = 0.00001; Mat data(num_sampl,num_features,CV_32F); Mat responses(num_sampl,1,CV_32F); for(int i=0; i<num_sampl; i++) { data.at<float>(i,0) = points[i].pt.x; data.at<float>(i,1) = points[i].pt.y; responses.at<float>(i) = points[i].value; } SVMParams params(CvSVM::C_SVC, CvSVM::RBF, 0, myGamma, 0, myC, 0, 0, 0, TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 1000, 1e-6)); svm.clear(); svm.train(&(CvMat)data,&(CvMat)responses,0,0,params); } int _tmain(int argc, _TCHAR* argv[]) { img = Mat::zeros(Size(640,480),CV_8UC3); Mat test(1,num_features,CV_32F); namedWindow("SVMDemo",1); setMouseCallback("SVMDemo",on_mouse,0); int c=0; for(; { /*TFeature pts; pts.pt = Point(587,20); pts.value = 2; points.push_back(pts); pts.pt = Point(603,47); pts.value = 2; points.push_back(pts); pts.pt = Point(627,30); pts.value = 2; points.push_back(pts); pts.pt = Point(578,37); pts.value = 2; points.push_back(pts); pts.pt = Point(555,25); pts.value = 2; points.push_back(pts);*/ imshow("SVMDemo",img); c = waitKey(10); if((char)c ==27) break; switch((char)c) { case 's': { if(points.size()>0) { TrainSVM(); for(int x=0;x<640; x++) { for(int y=0; y<480;y++) { test.at<float>(0,0)=x; test.at<float>(0,1)=y; if(svm.predict(test) == 0) { circle(img,Point(x,y),1,CV_RGB(100,0,0),-1); } if(svm.predict(test) == 1) { circle(img,Point(x,y),1,CV_RGB(0,100,0),-1); } /*if(svm.predict(test) == 2) { circle(img,Point(x,y),1,CV_RGB(0,0,100),-1); }*/ Update(); } } } break; }; case 'r': { if(points.size()>0) { img = Mat::zeros(Size(640,480),CV_8UC3); svm.clear(); points.clear(); } break; }; default:; } } svm.clear(); points.clear(); return 0; } [/code] для появления точек третьего класса надо раскоментировать в двух местах [code] /*TFeature pts; pts.pt = Point(587,20); pts.value = 2; points.push_back(pts); pts.pt = Point(603,47); pts.value = 2; points.push_back(pts); pts.pt = Point(627,30); pts.value = 2; points.push_back(pts); pts.pt = Point(578,37); pts.value = 2; points.push_back(pts); pts.pt = Point(555,25); pts.value = 2; points.push_back(pts);*/ /*if(svm.predict(test) == 2) { circle(img,Point(x,y),1,CV_RGB(0,0,100),-1); }*/ с двумя классами программа работает, при добавлении третьего всё подвисает и программа вообще ничего не выдаёт, подскажите что не так вроде бы должен классифицировать больше 2-х классов как написано в документации Введение в SVM Type of SVM. We choose here the type CvSVM::C_SVC that can be used for n-class classification (n>2). This parameter is defined in the attribute CvSVMParams.svm_type. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 9, 2011 Неплохая справка есть тут: http://www.cognotics.com/opencv/docs/1.0/ref/opencvref_ml.htm Может параметры слишком жестко заданы, вот и подвисает. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 12, 2011 Отсюда ? http://www.compvisio...p?showtopic=404 , хотя похоже только по кнопкам ) да вся основа была взята оттуда только переделана под С++ интерфейс вот, оказалось что программа работает правда очень долго минут 45 для 3-х классов в каждом из которых всего 5-ть точек. Но в моей задаче классов не 3-и а около 100-ни я классифицирую изображения.. и такой вопрос как я понимаю void TrainSVM(void) { int num_sampl = points.size(); float myC = 100; float myGamma = 0.00001; Mat data(num_sampl,num_features,CV_32F); Mat responses(num_sampl,1,CV_32F); for(int i=0; i<num_sampl; i++) { data.at<float>(i,0) = points[i].pt.x; data.at<float>(i,1) = points[i].pt.y; responses.at<float>(i) = points[i].value; } SVMParams params(CvSVM::C_SVC, CvSVM::RBF, 0, myGamma, 0, myC, 0, 0, 0, TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 1000, 1e-6)); svm.clear(); svm.train(&(CvMat)data,&(CvMat)responses,0,0,params); } в этом коде svm только обучается ну получает опорные вектора, а сама разделяющая гиперплоскость получается из вызова svm.predict(test) или гиперплоскость получается из вызова метода train тоже, тогда не совсем ясно как она хранится, ведь я понимаю благодаря ей распознавание происходит быстро уже по известной гиперплоскости Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 12, 2011 Я уверен на 99.9% (не проверял в коде) что гиперплоскость получается при обучении "train". А кластеризация (классификация) "predict" приводится простой подстановкой в полученные уравнения. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 13, 2011 да мне то же так кажется. Вот ещё такой вопрос, что такой опорные вектора когда я читал про SVM я понял, что это вектора с наименьшим расстоянием между двумя классами векторов и они уже в дальнейшем и используются для получения гиперплоскости, я дописал код для вывода опорных векторов после обучения ну по нажатию 's' int bс = svm.get_support_vector_count(); cout<<bс<<"\n"; for(int i=0; i<bс; i++) { const float* v = svm.get_support_vector(i); int x = v[0]; int y = v[1]; circle(img,Point(x,y),5,CV_RGB(255,255,255),1); } но вид(их расположение) и количество опорных векторов уж больно странное, больно много их как мне кажется скрин экрана я прикрепил, причём это скрин с рабочего компьютера дома у меня на домашнем компьютере их меньше значительно, но всё равно видно на глаз, что там есть вектора не с минимальным расстоянием до другого класса Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 13, 2011 Ближайшие к параллельным гиперплоскостям точки называются опорными векторами. Гиперплоскость а не прямая, не забывайте о добавленных измерениях. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 13, 2011 точно, я что - то забыл, что гиперплоскость может быть не плоскостью, а какой-то более сложной функцией, но вот ещё один принт скрин там как мне кажется уж их совсем много можно было бы намного меньше на мой взгляд или я ошибаюсь Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 13, 2011 Можно было-бы но комп. все делает формально - т.е. сказано работать в пространстве с тремя измерениями - он будет работать в 3-х измерениях, даже если очевидно что задачу можно существенно упростить. Анализ частных случаев, нужно отдельно встраивать, например если получилась граница, близкая к прямой, то использовать более простое ядро или другой метод. ЗЫ: Часто быстрее сделать все универсальным подходом, и проблем меньше. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано September 14, 2011 от чего зависит более точное разделение на классы? т.е. как на картинке и возможно ли чтобы например зеленая область находилась в 2-х не связных местах? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 14, 2011 Вот хорошая визуализация: Если взять более сложную поверхность (ядро), то мы получим несколько разделенных на плоскости областей. Строгость разделения на классы определяется штрафным коэффициентом: В коде выше есть строки, которые задают этот штраф: //(C_SVC) penalty multiplier C for outliers float myC=100;[/code] Еще интересное применение SVM для получения плавной траектории движения между препятствиями: Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 14, 2011 я прикрепил картинку с опорными векторами, на компьютере из дома, странно почему так отличается количество опорных векторов и ещё такой вопрос как найти сами опорные вектора ну я читал в какой-то статье есть два множества(класса) векторов берём произвольный вектор V1 из первого класса и ищем ближайший вектор U1 из второго класса потом берём вектор U1 и ищем ближайший вектор из первого класса и так повторяем несколько раз этот процесс должен стабилизироваться и у нас будут опорные вектора так ли они ищутся или используются какие-то другие методы? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 15, 2011 В этой теме было несколько документов, поясняющих работу SVM: http://www.compvision.ru/forum/index.php?showtopic=329 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 19, 2011 я пытаюсь реализовать INSAC это алгоритм классифицирующий вектора на два не пересекающихся класса. Он описан в википедии http://www.machinelearning.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_INCAS и там же дана ссылка на конспект лекций Воронцова К.В., в котором тоже этот алгоритм рассмотрен. У меня есть несколько вопросов по этому методу 1.начальное приближение Is = две ближайшие точки из разных классов Io = все остальные точки Ic = 0 Начальное приближение мне ясно там написано как можно его найти к примеру можно так Выбирается произвольная точка выборки, и находится ближайшая к ней точка другого класса. Для неё, в свою очередь, находится ближайшая точка в первом классе, и т. д. Этот итерационный процесс, как правило, сходится очень быстро к некоторой паре пограничных точек. Это и есть начальное приближение в этом алгоритме. Вопрос в том влияет ли число опорных точек(векторов) на качество решения. Далее по алгоритму решается задача оптимизации с матрицей Q, но из чего она состоит...в конспекте лекций приведено следующее Q=(yiyjK(xi, xj)), i,j=1..L Q размера LxL и вот как я понимаю y - это метка какому классу вектор принадлежит {-1,1}, K(xi, xj) это ядро к примеру евклидово расстояние между i-ым и j-ым вектором т.е. матрица Q - это три столбца первый принадлежность классу второй тоже принадлежность к классу и расстояние между этими векторами поясните пожалуйста что я не так понимаю, в конспекте написано о квадратной матрице, а я не понимаю как я вижу там только три столбца можно даже пример какой-нить что бы разобраться что за матрица 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 19, 2011 Q=(yiyjK(xi, xj)) - это не столбцы, это вероятно следует толковать так: qij=yi*yj*K(xi, xj) То есть каждый элемент матрицы Q находящийся в ячейке ij равен qij, аналогично с y. PS: Ссылка очень хорошая. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 20, 2011 А ну вообще да вроде бы так логично пасибо вот ещё, что не понятно в задаче есть ограничения 0<=λ<=C, так вот что такое C написано что это параметр алгоритма, ну т.е. его как задавать вообще произвольно или какие-то ограничения на него накладываются. И ещё такой вопрос в самом алгоритме под пунктом 4 стоит решение оптимизационной задачи относительно λs как решать эту задачу я что-то не понимаю и почему там надо вычислять обратную матрицу поясните пожалуйста Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 20, 2011 Написано вот что: С подбирается по скользящему контролю, что является трудоёмкой процедурой. Решение оптимизационной задачи это ,в данном случае, решение системы линейных уравнений. Для этого и находим обратную матрицу: см. http://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%82%D1%80%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4 в конце страницы. См. еще решение при помощи SVD. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано September 22, 2011 а в реализованной программе параметр С задаётся как float myC = 100; Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 22, 2011 Так я же тоже по результату классификации его подбирал , только не автоматически, а вручную. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ProgRoman 9 Жалоба Опубликовано October 19, 2011 у меня возник ещё вопрос по выводу формул для SVM в двойственной задачи у целевой функции у меня получается два плюса вот ссылка http://www.machinelearning.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_INCAS там в 1-ой системе целевая функция с обратным знаком взята и знаки самих слагаемых у функции различны, а у меня всё время получаются слагаемые с одинаковыми знаками прикрепляю картинку с тем как я выводил. В чём ошибка что-то разобраться не могу пока.. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах