研究了下SVM,神经网络的训练方法是梯度下降法,SVM的训练方法貌似说的最多的就是SMO算法
#include "opencv2/core/core_c.h"
#include "opencv2/core/core.hpp"
#include "opencv2/flann/miniflann.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"
#include "opencv2/video/video.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include <cctype>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <map>
#include <cmath>
using namespace std;
using namespace cv;
static float calc_inner_product(float *x, int dims, int i, int j)
{
float sum = 0;
for (int k=0; k<dims; k++)
{
sum += x[i*dims+k] * x[j*dims+k];
}
return sum;
}
static float calc_ui(float *x, float *y, float *a, float b, int dims, int nums, int C, int i)
{
float ui = b;
for (int j=0; j<nums; j++)
{
if (a[j] == C)
continue;
ui += y[j]*a[j]*calc_inner_product(x, dims, i, j);
}
return ui;
}
#define ABS(x) ((x) >= 0 ? (x) : (-(x)))
#define MAX(x,y) ((x)>(y) ? (x):(y))
#define MIN(x,y) ((x)<(y) ? (x):(y))
#define MIN_MAX(min, x, max) (MAX((min), MIN((max), (x))))
/* 输入特征数据,训练得到分类器 */
int train(float *x, float *y, float *w, float *b, float *a, int dims, int nums, int C)
{
int i, j, k;
//int C = 1; /* 松弛因子 */
int iter = 0; /* 迭代次数 */
float tol = 0.0001;
float ui, uj, ei, ej, max_ej, old_ai, old_aj, L, H, eta, bi, bj;
/* 初始化 */
for (i=0; i<nums; i++)
{
a[i] = 0;
}
*b = 0;
while (iter < 100000)
{
int adjust_nums = 0;
for (i=0; i<nums; i++)
{
/* 找出不符合KKT条件的a[i] */
ui = calc_ui((float *)x, (float *)y, a, *b, dims, nums, C, i);
if (((y[i]*ui < 1) && (a[i] < C)) ||
((y[i]*ui > 1) && (a[i] > 0)) ||
((y[i]*ui == 1) && ((a[i] == 0) || (a[i] == C))))
{
ei = ui - y[i];
/* 寻找误差最大的a[j],在支持变量上找 */
max_ej = ei;
for (j=0; j<nums; j++)
{
if (i == j)
continue;
if ((a[j] == 0) || (a[j] == C))
continue;
uj = calc_ui((float *)x, (float *)y, a, *b, dims, nums, C, j);
ej = uj - y[j];
if (ABS(ej - ei) > ABS(max_ej - ei))
{
k = j;
max_ej = ej;
}
}
/* 如果支持变量上没找到,在其他里面找误差最大的a[j] */
if (max_ej == ei)
{
for (j=0; j<nums; j++)
{
if (i == j)
continue;
if ((a[j] > 0) && (a[j] < C))
continue;
uj = calc_ui((float *)x, (float *)y, a, *b, dims, nums, C, j);
ej = uj - y[j];
if (ABS(ej - ei) > ABS(max_ej - ei))
{
k = j;
max_ej = ej;
}
}
}
j = k;
ej = max_ej;
/* 保存原来的ai和aj */
old_ai = a[i];
old_aj = a[j];
/* 计算上界和下界 */
if (y[i] != y[j])
{
L = MAX(0, old_aj - old_ai);
H = MIN(C, C + old_aj - old_ai);
}
else
{
L = MAX(0, old_aj + old_ai - C);
H = MIN(C, old_aj + old_ai);
}
/* 计算新的aj */
eta = calc_inner_product((float *)x, dims, i, i) +
calc_inner_product((float *)x, dims, j, j) -
2 * calc_inner_product((float *)x, dims, i, j);
a[j] = old_aj + y[j]*(ei - ej)/eta;
a[j] = MIN_MAX(L, a[j], H);
/* 计算新的ai, 重新保持Σai yi = 0 */
a[i] = old_ai + y[i]*y[j]*(old_aj - a[j]);
/* 重新计算b */
bi = *b - ei - y[i]*(a[i]-old_ai)*calc_inner_product((float *)x, dims, i, i)
- y[j]*(a[j]-old_aj)*calc_inner_product((float *)x, dims, i, j);
bj = *b - ej - y[i]*(a[i]-old_ai)*calc_inner_product((float *)x, dims, i, j)
- y[j]*(a[j]-old_aj)*calc_inner_product((float *)x, dims, j, j);
if (0 < a[i] && a[i] < C)
*b = bi;
else if (0 < a[j] && a[j] < C)
*b = bj;
else
*b = (bi + bj) / 2;
adjust_nums++;
}
}
if (adjust_nums < nums * 0.01)
break;
iter++;
}
cout << "iter:" << iter << endl;
cout << "w: ";
for (i=0; i<dims; i++)
{
w[i] = 0;
for (j=0; j<nums; j++)
{
if (a[j] == C)
continue;
w[i] += y[j] * a[j] * x[j*dims + i];
}
cout << w[i] << ",";
}
cout << endl << "b: " << *b << endl;
cout << "alpha vector:";
for (j=0; j<nums; j++)
{
cout << a[j] << ",";
}
cout << endl;
return 0;
}
#define IMG_SIZE 400
void random_features(int* w, int b, int* x,
int dims, int nums, int noise)
{
int i, j;
for (i=0; i<nums; i++)
{
int rand_noise = randu<int>() % noise;
int sum = rand_noise + b;
for (j=0; j<dims-1; j++)
{
x[i*dims+j] = randu<unsigned int>() % IMG_SIZE;
sum += w[j] * x[i*dims+j];
}
x[i*dims+j] = -sum / w[j];
}
}
#define DIMS 2
#define NUMS 100
int main( int argc, const char** argv )
{
Mat img = Mat::zeros(Size(IMG_SIZE, IMG_SIZE), CV_8UC3);
int features[NUMS*2][DIMS];
float x[NUMS*2][DIMS];
float y[NUMS*2], a[NUMS*2];
int pre_w[DIMS] = {1, -1}, pre_b0 = 60, pre_b1 = -60, pre_noise = 30;
float w[DIMS], b = 0;
int C = 1; //松弛因子
/* 生成 x-y+60=0 的随机特征数据 */
random_features(pre_w, pre_b0, &features[0][0], DIMS, NUMS, pre_noise);
for (int i=0; i<NUMS; i++)
{
y[i] = 1;
if (i > NUMS*9/10) //生成错误标签
{
y[i] = -1;
}
}
/* 生成 x-y-60=0 的随机特征数据 */
random_features(pre_w, pre_b1, &features[NUMS][0], DIMS, NUMS, pre_noise);
for (int i=0; i<NUMS; i++)
{
y[i+NUMS] = -1;
if (i > NUMS*9/10) //生成错误标签
{
y[i+NUMS] = 1;
}
}
for (int i=0; i<NUMS*2; i++)
{
for (int j=0; j<DIMS; j++)
{
//x[i][j] = (float)features[i][j] / IMG_SIZE;
x[i][j] = features[i][j];
}
}
train(&x[0][0], y, w, &b, a, DIMS, NUMS*2, C);
cvNamedWindow("test", 1);
/* 画图 */
int support_vector_num = 0;
for (int i=0; i<NUMS; i++)
{
/* 距离远的向量 */
if (a[i] == 0)
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(0,128,0));
}
/* 松弛向量 */
else if (a[i] == C)
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(128,128,0));
}
/* 支持向量 */
else
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(0,255,0));
support_vector_num++;
}
}
for (int i=NUMS; i<NUMS*2; i++)
{
/* 距离远的向量 */
if (a[i] == 0)
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(0,0,128));
}
/* 松弛向量 */
else if (a[i] == C)
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(128,0,128));
}
/* 支持向量 */
else
{
cv::circle(img, Point(features[i][0], features[i][1]),
3, Scalar(0,0,255));
support_vector_num++;
}
}
//cout << "support vector num:" << support_vector_num << endl;
float pt_st_x = 10, pt_st_y, pt_ed_x = 390, pt_ed_y;
//pt_st_y = ((pt_st_x / IMG_SIZE * w[0] + b) / (-w[1])) * IMG_SIZE;
//pt_ed_y = ((pt_ed_x / IMG_SIZE * w[0] + b) / (-w[1])) * IMG_SIZE;
pt_st_y = ((pt_st_x * w[0] + b) / (-w[1]));
pt_ed_y = ((pt_ed_x * w[0] + b) / (-w[1]));
//cout << pt_st_x << "," << pt_st_y << "," << pt_ed_x << "," << pt_ed_y << endl;
cv::line(img, Point(pt_st_x, pt_st_y), Point(pt_ed_x, pt_ed_y), Scalar(255,255,255));
cv::imshow("test", img);
while (1)
{
char c = (char)waitKey();
if( c == 27 )
break;
}
cvDestroyWindow("test");
return 0;
}
return 0;
}
参考文章:
http://blog.csdn.net/shuimanting520/article/details/45459803