SVM训练方法之SMO算法

研究了下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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值