SVM与C++源码实现

1. 推导出函数间隔最小

2. 约束优化函数变形至如下形式

/*
min 1/2*||w||^2
s.t.  (w[i]*x[i] + b[i] - y[i]) >= 0;
*/

3. 对偶函数

/*
min(para alpha) 1/2*sum(i)sum(j)(alpha[i]*alpha[j]*y[i]*y[j]*x[i]*x[j]) - sum(alpha[i])
s.t. sum(alpha[i] * y[i]) = 0
C>= alpha[i] >= 0
*

4. 根据KKT条件优化。。

下面是C++代码


/*********************************************************
**CopyRight by Weidi Xu, S.C.U.T in Guangdong, Guangzhou**
**********************************************************/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>

using std::sort;
using std::fabs;

const int MAX_DIMENSION = 2;
const int MAX_SAMPLES = 3;
double x[MAX_SAMPLES][MAX_DIMENSION];
double y[MAX_SAMPLES];
double alpha[MAX_SAMPLES];
double w[MAX_DIMENSION];
double b;
double c;
double eps = 1e-6;
struct _E{
double val;
int index;
}E[MAX_SAMPLES];

bool cmp(const _E & a, const _E & b)
{
return a.val < b.val;
}

int num_dimension;
int num_samples;

double max(double a,double b)
{
return a>b?a:b;
}

double min(double a,double b)
{
return a>b?b:a;
}

double kernal(double x1[], double x2[], double dimension)
{
double ans = 0 ;
for(int i = 0 ; i < dimension; i++)
{
ans += x1[i]*x2[i];
}
return ans;
}

double target_function()
{
double ans = 0;
for(int i = 0 ; i < num_samples; i++)
{
for(int j = 0 ; j < num_samples; j++)
{
ans += alpha[i]*alpha[j]*y[i]*y[j]*kernal(x[i],x[j],num_dimension);
}
}

for(int i = 0 ; i < num_samples; i++)
{
ans -= alpha[i];
}

return ans;
}

double g(double _x[], int dimension)
{
double ans = b;

for(int i = 0 ; i < num_samples; i++)
{
ans += alpha[i]*y[i]*kernal(x[i],_x,dimension);
}

return ans;
}

bool satisfy_constrains(int i, int dimension)
{
if(alpha[i] == 0)
{
if(y[i]*g(x[i], dimension) >= 1)
return true;
else
return false;
}
else if( alpha[i] > 0 && alpha[i] < c)
{
if(y[i] * g(x[i], dimension) == 1)
return true;
else
return false;
}
else
{
if(y[i] * g(x[i], dimension) <= 1)
return true;
else
return false;
}
}

double calE(int i, int dimension)
{
return g(x[i], dimension) - y[i];
}

void calW()
{
for(int i = 0 ; i < num_dimension; i++)
{
w[i] = 0;
for(int j = 0 ; j < num_samples; j++)
{
w[i] += alpha[j] * y[j] * x[j][i];
}
}
return ;
}

void calB()
{
double ans = y[0];
for(int i = 0 ; i < num_samples ; i++)
{
ans -= y[i]*alpha[i]*kernal(x[i], x[0], num_dimension);
}
b = ans;
return;
}

void recalB(int alpha1index,int alpha2index, int dimension, double alpha1old, double alpha2old)
{
double alpha1new = alpha[alpha1index];
double alpha2new = alpha[alpha2index];

alpha[alpha1index] = alpha1old;
alpha[alpha2index] = alpha2old;

double e1 = calE(alpha1index, num_dimension);
double e2 = calE(alpha2index, num_dimension);

alpha[alpha1index] = alpha1new;
alpha[alpha2index] = alpha2new;

double b1new = -e1 - y[alpha1index]*kernal(x[alpha1index], x[alpha1index], dimension)*(alpha1new - alpha1old);
b1new -= y[alpha2index]*kernal(x[alpha2index], x[alpha1index], dimension)*(alpha2new - alpha2old) + b;

double b2new = -e2 - y[alpha1index]*kernal(x[alpha1index], x[alpha2index], dimension)*(alpha1new - alpha1old);
b1new -= y[alpha2index]*kernal(x[alpha2index], x[alpha2index], dimension)*(alpha2new - alpha2old) + b;

b = (b1new + b2new)/2;
}

bool optimizehelp(int alpha1index,int alpha2index)
{
double alpha1new = alpha[alpha1index];
double alpha2new = alpha[alpha2index];

double alpha1old = alpha[alpha1index];
double alpha2old = alpha[alpha2index];

double H,L;

if(fabs(y[alpha1index] - y[alpha2index]) > eps)
{
L = max(0, alpha2old - alpha1old);
H = min(c, c + alpha2old - alpha1old);
}
else
{
L = max(0, alpha2old + alpha1old - c);
H = min(c, alpha2old + alpha1old);
}

//cal new
double lena = kernal(x[alpha1index], x[alpha1index], num_dimension) + kernal(x[alpha2index], x[alpha2index], num_dimension) - 2*kernal(x[alpha1index], x[alpha2index], num_dimension);
alpha2new = alpha2old + y[alpha2index]*(calE(alpha1index, num_dimension) - calE(alpha2index, num_dimension))/lena;

if(alpha2new > H)
{
alpha2new = H;
}
else if( alpha2new < L)
{
alpha2new = L;
}

alpha1new = alpha1old + y[alpha1index]*y[alpha2index]*(alpha2old - alpha2new);

double energyold = target_function();

alpha[alpha1index] = alpha1new;
alpha[alpha2index] = alpha2new;

double gap = 0.001;

recalB(alpha1index, alpha2index, num_dimension, alpha1old, alpha2old);
return true;
}

bool optimize()
{
int alpha1index = -1;
int alpha2index = -1;
double alpha2new = 0;
double alpha1new = 0;

//cal E[]
for(int i = 0 ; i < num_samples; i++)
{
E[i].val = calE(i, num_dimension);
E[i].index = i;
}

//traverse the alpha1index with 0 < && < c
for(int i = 0 ; i < num_samples; i++)
{
alpha1new = alpha[i];

if(alpha1new > 0 && alpha1new < c)
{

if(satisfy_constrains(i, num_dimension))
continue;

sort(E, E+num_samples, cmp);

//simply find the maximum or minimun;
if(alpha1new > 0)
{
if(E[0].index == i)
{
;
}
else
{
alpha1index = i;
alpha2index = E[0].index;
if(optimizehelp(alpha1index, alpha2index))
{
return true;
}
}
}
else
{
if(E[num_samples-1].index == i)
{
;
}
else
{
alpha1index = i;
alpha2index = E[num_samples-1].index;
if(optimizehelp(alpha1index, alpha2index))
{
return true;
}
}
}

//find the alpha2 > 0 && < c
for(int j = 0 ; j < num_samples; j++)
{
alpha2new = alpha[j];

if(alpha2new > 0 && alpha2new < c)
{
alpha1index = i;
alpha2index = j;
if(optimizehelp(alpha1index , alpha2index))
{
return true;
}
}
}

//find other alpha2
for(int j = 0 ; j < num_samples; j++)
{
alpha2new = alpha[j];

if(!(alpha2new > 0 && alpha2new < c))
{
alpha1index = i;
alpha2index = j;
if(optimizehelp(alpha1index , alpha2index))
{
return true;
}
}
}
}
}

//find all alpha1
for(int i = 0 ; i < num_samples; i++)
{
alpha1new = alpha[i];

if(!(alpha1new > 0 && alpha1new < c))
{
if(satisfy_constrains(i, num_dimension))
continue;

sort(E, E+num_samples, cmp);

//simply find the maximum or minimun;
if(alpha1new > 0)
{
if(E[0].index == i)
{
;
}
else
{
alpha1index = i;
alpha2index = E[0].index;
if(optimizehelp(alpha1index, alpha2index))
{
return true;
}
}
}
else
{
if(E[num_samples-1].index == i)
{
;
}
else
{
alpha1index = i;
alpha2index = E[num_samples-1].index;
if(optimizehelp(alpha1index, alpha2index))
{
return true;
}
}
}

//find the alpha2 > 0 && < c
for(int j = 0 ; j < num_samples; j++)
{
alpha2new = alpha[j];

if(alpha2new > 0 && alpha2new < c)
{
alpha1index = i;
alpha2index = j;
if(optimizehelp(alpha1index , alpha2index))
{
return true;
}
}
}

//find other alpha2
for(int j = 0 ; j < num_samples; j++)
{
alpha2new = alpha[j];

if(!(alpha2new > 0 && alpha2new < c))
{
alpha1index = i;
alpha2index = j;
if(optimizehelp(alpha1index , alpha2index))
{
return true;
}
}
}
}
}

//for(int i = 0 ; i < num_samples; i++)
//{
// alpha1new = alpha[i];

// for(int j = 0 ; j < num_samples; j++)
// {
// if(1)
// {
// alpha1index = i;
// alpha2index = j;
// if(optimizehelp(alpha1index , alpha2index))
// {
// return true;
// }
// }
// }
//}
return false;
}

bool check()
{
double sum = 0;
for(int i = 0 ; i < num_samples; i++)
{
sum += alpha[i] * y[i];
if(!(0 <= alpha[i] && alpha[i] <= c))
{
printf("alpha[%d]: %lf wrong\n", i, alpha[i]);
return false;
}
if(!satisfy_constrains(i, num_dimension))
{
printf("alpha[%d] not satisfy constrains\n", i);
return false;
}
}

if(fabs(sum) > eps)
{
printf("Sum = %lf\n", sum);
return false;
}
return true;
}
/*
min 1/2*||w||^2
s.t. (w[i]*x[i] + b[i] - y[i]) >= 0;
*/
/*
step 1: cal alpha[]
step 2: cal w,b
*/

/*
min(para alpha) 1/2*sum(i)sum(j)(alpha[i]*alpha[j]*y[i]*y[j]*x[i]*x[j]) - sum(alpha[i])
s.t. sum(alpha[i] * y[i]) = 0
C>= alpha[i] >= 0
*/

int main()
{
scanf("%d%d", &num_samples, &num_dimension);

for(int i = 0 ; i < num_samples; i++)
{
for(int j = 0; j < num_dimension; j++)
{
scanf("%lf",&x[i][j]);
}
scanf("%lf",&y[i]);
}
c = 1;

//初值附为0;
for(int i = 0 ; i < num_samples; i++)
{
alpha[i] = 0;
}

int count = 0;
while(optimize()){
calB();
count++;
}
printf("%d ",count);

calW();
calB();

printf("y = ");

for(int i = 0 ; i < num_dimension; i++)
{
printf("%lf * x[%d] + ", w[i], i);
}
printf("%lf\n", b);

if(!check())
printf("Not satisfy KKT.\n");
else
printf("Satisfy KKT\n");
}

/*
3 2
3 3 1
4 3 1
1 1 -1
*/

实验结论:

1. SVM的收敛与迭代顺序和初值基本无关。
2.
将不满足kkt条件的alpha值进行修改不一定减少目标函数(未验证,实验的感觉是这样的)。因为加入每次目标函数减少的限制后,不收敛到最优值。

SVM与C++源码实现

时间: 2024-10-09 16:26:32

SVM与C++源码实现的相关文章

HOG+SVM(OpenCV案例源码train_HOG.cpp解读)

有所更改,参数不求完备,但求实用.源码参考D:\source\opencv-3.4.9\samples\cpp\train_HOG.cpp [解读参考]https://blog.csdn.net/xiao__run/article/details/82902267 [HOG原理]https://livezingy.com/hogdescriptor-in-opencv3-1/ https://cloud.tencent.com/developer/article/1434949 #include

hog源码分析

http://www.cnblogs.com/tornadomeet/archive/2012/08/15/2640754.html 在博客目标检测学习_1(用opencv自带hog实现行人检测) 中已经使用了opencv自带的函数detectMultiScale()实现了对行人的检测,当然了,该算法采用的是hog算法,那么hog算法是怎样实现的呢?这一节就来简单分析一下opencv中自带 hog源码. 网上也有不少网友对opencv中的hog源码进行了分析,很不错,看了很有收获.比如: htt

实验报告: 人脸识别方法回顾与实验分析 【OpenCV测试方法源码】

趁着还未工作,先把过去做的东西整理下出来~   Github源码:https://github.com/Blz-Galaxy/OpenCV-Face-Recognition (涉及个人隐私,源码不包含测试样本,请谅解~) 对实验结果更感兴趣的朋友请直接看 第5章 [摘要]这是一篇关于人脸识别方法的实验报告.报告首先回顾了人脸识别研究的发展历程及基本分类:随后对人脸识别技术方法发展过程中一些经典的流行的方法进行了详细的阐述:最后作者通过设计实验对比了三种方法的识别效果并总结了人脸识别所面临的困难与

spark.mllib源码阅读-优化算法1-Gradient

Spark中定义的损失函数及梯度,在看源码之前,先回顾一下机器学习中定义了哪些损失函数,毕竟梯度求解是为优化求解损失函数服务的. 监督学习问题是在假设空间F中选取模型f作为决策函数,对于给定的输入X,由f(X)给出相应的输出Y,这个输出的预测值f(X)与真实值Y可能一致也可能不一致,用一个损失函数(lossfunction)或代价函数(cost function)来度量预测错误的程度.损失函数是f(X)和Y的非负实值函数,记作L(Y, f(X)). 统计学习中常用的损失函数有以下几种: (1)

Mahout源码目录说明

Mahout源码目录说明 mahout项目是由多个子项目组成的,各子项目分别位于源码的不同目录下,下面对mahout的组成进行介绍: 1.mahout-core:核心程序模块,位于/core目录下: 2.mahout-math:在核心程序中使用的一些数据通用计算模块,位于/math目录下: 3.mahout-utils:在核心程序中使用的一些通用的工具性模块,位于/utils目录下: 上述三个部分是程序的主题,存储所有mahout项目的源码. 另外,mahout提供了样例程序,分别在taste-

struct2源码解读(1)之struts2启动

struct2源码解读(1)之struts启动 之前用struct2.spring.hibernate在开发一个电子商城,每天都在重复敲代码,感觉对struct2.spring.hibernate的理解都在使用层面上,虽然敲了几个月代码,但是技术水平还是得不到显著提高.于是就想着研究下struct2.spring.hibernate的源码,研究完后不仅对struct2.spring.hibernate加深了了解,同时也加强了java的学习,例如xml的解析,字符操作,线程等等,受益匪浅.想着当初

OpenCV2.4.9源码分析——Support Vector Machines

引言 本文共分为三个部分,第一个部分介绍SVM的原理,我们全面介绍了5中常用的SVM算法:C-SVC.ν-SVC.单类SVM.ε-SVR和ν-SVR,其中C-SVC和ν-SVC不仅介绍了处理两类分类问题的情况,还介绍处理多类问题的情况.在具体求解SVM过程中,我们介绍了SMO算法和广义SMO算法.第二个部分我们给出了OpenCV中SVM程序的详细注解.第三个部分我们给出了一个基于OpenCV的SVM算法的简单应用实例. 由于这篇文章太长,公式很多,把文章复制到这里,阅读体验会很差,因此,我把这篇

【转】近200篇机器学习&amp;深度学习资料分享(含各种文档,视频,源码等)

编者按:本文收集了百来篇关于机器学习和深度学习的资料,含各种文档,视频,源码等.而且原文也会不定期的更新,望看到文章的朋友能够学到更多. <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost 到随机森林.Deep Learning. <Deep Learning in Neural Networks: An Overview> 介绍:这是瑞士人工智能实验室 Ju

近200篇机器学习&amp;深度学习资料分享(含各种文档,视频,源码等)(1)

原文:http://developer.51cto.com/art/201501/464174.htm 编者按:本文收集了百来篇关于机器学习和深度学习的资料,含各种文档,视频,源码等.而且原文也会不定期的更新,望看到文章的朋友能够学到更多. <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost 到随机森林.Deep Learning. <Deep Learning i