Перейти к содержимому
Compvision.ru
Smorodov

Простой пример для экспериментов с SVM

Recommended Posts

Простой пример для экспериментов с SVM

OpenCv213.rar

SVM - Машина опорных векторов, может использоваться для классификации , и аппроксимации.

В данном примере пользователь ставит на экране точки, относя их к 0 или 1 классу (классов может быть и больше) при помощи левой или правой кнопок мыши. Затем нужно нажать "s" , программа обучит SVM и просчитает к какому классу отнести каждую из точек экрана.

Очистка производится кнопкой "r".

post-1-0-58589400-1293455563_thumb.jpg

  • Like 2

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


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

Всем привет, вот пытаюсь разобраться с 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.

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


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

Неплохая справка есть тут: http://www.cognotics.com/opencv/docs/1.0/ref/opencvref_ml.htm

Может параметры слишком жестко заданы, вот и подвисает.

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


Ссылка на сообщение
Поделиться на других сайтах
Отсюда ? 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 тоже, тогда не совсем ясно как она хранится, ведь я понимаю благодаря ей распознавание происходит быстро уже по известной гиперплоскости

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


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

Я уверен на 99.9% (не проверял в коде) что гиперплоскость получается при обучении "train".

А кластеризация (классификация) "predict" приводится простой подстановкой в полученные уравнения.

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


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

да мне то же так кажется.

Вот ещё такой вопрос, что такой опорные вектора когда я читал про 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);

}

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

post-2515-0-59419800-1315909135_thumb.jp

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


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

Ближайшие к параллельным гиперплоскостям точки называются опорными векторами.

Гиперплоскость а не прямая, не забывайте о добавленных измерениях.

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


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

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

post-2515-0-58877700-1315915819_thumb.jp

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


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

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

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

ЗЫ: Часто быстрее сделать все универсальным подходом, и проблем меньше.

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


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

от чего зависит более точное разделение на классы?

т.е. как на картинке

image.png

и возможно ли чтобы например зеленая область находилась в 2-х не связных местах?

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


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

Вот хорошая визуализация:

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

Строгость разделения на классы определяется штрафным коэффициентом:

В коде выше есть строки, которые задают этот штраф:

//(C_SVC) penalty multiplier C for outliers
float myC=100;[/code]

Еще интересное применение SVM для получения плавной траектории движения между препятствиями:

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


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

я прикрепил картинку с опорными векторами, на компьютере из дома, странно почему так отличается количество опорных векторов и ещё такой вопрос как найти сами опорные вектора ну я читал в какой-то статье есть два множества(класса) векторов берём произвольный вектор V1 из первого класса и ищем ближайший вектор U1 из второго класса потом берём вектор U1 и ищем ближайший вектор из первого класса и так повторяем несколько раз этот процесс должен стабилизироваться и у нас будут опорные вектора так ли они ищутся или используются какие-то другие методы?

post-2515-0-38666000-1316037747_thumb.jp

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


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

В этой теме было несколько документов, поясняющих работу SVM: http://www.compvision.ru/forum/index.php?showtopic=329

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


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

я пытаюсь реализовать 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 - это три столбца первый принадлежность классу второй тоже принадлежность к классу и расстояние между этими векторами поясните пожалуйста что я не так понимаю, в конспекте написано о квадратной матрице, а я не понимаю как я вижу там только три столбца можно даже пример какой-нить что бы разобраться что за матрица

  • Like 1

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


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

Q=(yiyjK(xi, xj)) - это не столбцы, это вероятно следует толковать так: qij=yi*yj*K(xi, xj)

То есть каждый элемент матрицы Q находящийся в ячейке ij равен qij, аналогично с y.

PS: Ссылка очень хорошая.

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


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

А ну вообще да вроде бы так логично пасибо вот ещё, что не понятно в задаче есть ограничения

0<=λ<=C, так вот что такое C написано что это параметр алгоритма, ну т.е. его как задавать вообще произвольно или какие-то ограничения на него накладываются. И ещё такой вопрос в самом алгоритме под пунктом 4 стоит решение оптимизационной задачи относительно λs как решать эту задачу я что-то не понимаю и почему там надо вычислять обратную матрицу поясните пожалуйста

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


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

Написано вот что:

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

Решение оптимизационной задачи это ,в данном случае, решение системы линейных уравнений. Для этого и находим обратную матрицу: см. 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.

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


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

Так я же тоже по результату классификации его подбирал :) , только не автоматически, а вручную.

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


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

у меня возник ещё вопрос по выводу формул для 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-ой системе целевая функция с обратным знаком взята и знаки самих слагаемых у функции различны, а у меня всё время получаются слагаемые с одинаковыми знаками прикрепляю картинку с тем как я выводил. В чём ошибка что-то разобраться не могу пока..

post-2515-0-86764600-1319020740_thumb.jp

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×