支持向量机(SVM)
断断续续看了好多天,赶紧补上坑。
感谢july的 http://blog.csdn.net/v_july_v/article/details/7624837/
以及CSDN上淘的比较正规的SMO C++ 模板代码。~LINK~
1995年提出的支持向量机(SVM)模型,是浅层学习中较新代表,当然Adaboost更新一点。
按照Andrew NG的说法: "SVM的效果大概相当于调整最好的神经网络。"于是,SVM被各种神化,被誉为"未来人类的希望,世界人民的终极武器"。
甚至是IEEE选举的数据挖掘十大算法中唯一一个神经网络,对,没错,SVM就是个MLP。
SVM忽悠大法第一条“我有核函数!":
傻子都知道RBF径向基核函数在SVM发明的7年前就已经被用于RBF神经网络,RBF网络本质就是个把激活函数从Sigmoid替换成RBF的MLP。
SVM处理线性不可分的能力大致来自于两个部分,非线性映射(重点)、高维空间(核函数)。
SVM的非线性映射藏的比较隐秘,来自其伪·隐层结构:支持向量神经元层。至于核函数?就是个激活函数罢了。
实际上Logistic-Sigmoid函数也是核函数之一,Logistic回归不能处理线性不可分问题,并不是因为没有核函数,其实它有。
缺乏非线性映射变换的隐层结构,才是只能画线,不能画圆的关键,在这点上,不从神经网络角度理解SVM,是很容易产生误解的。
RBF较之于Sigmoid,确实有更快的收敛、更精确的逼近,但是,径向范围$\sigma$的选取并非易事,过大过小都会影响映射,至于SVM中默认
取定值的做法?其实并不完美。
SVM忽悠大法第二条“我分类效果好":
SVM的最优间隔理论,从数学上来讲,very good,其效果也比直接用Gradient Descent拟合好。
当然,这得益于SVM的分类环境假设:一刀切二类分类。但是,更多情况下是K类分类。
SVM确实有多类改进方法,比如基于投票机制的KNN-SVM,但是效果并不好。
相比于传统神经网络天然的多分类输出层,比如Softmax,逊色不少。
尤其在深度学习里,当样本和训练时间不作为第一要素、精度由深度网络保证,SVM的作用就弱化不少。
比如用户物体识别的ImageNet网络里,共有1000类需要分类,训练多个SVM,来达到多分类的目的,效果不会很好。
原因正如Bengio吐槽决策树那样,样本的输入空间被切分后,全样本之间的稀疏特征被分离,不利于整体的协同表达。
当然这在浅层学习中,尤其是在数据挖掘这类的统计数据上,问题并不是很大。
SVM的优势:
SVM本质就是个MLP,但是这个MLP真的很赞,它智能地解决了MLP中隐层神经元个数问题。
自MLP结构发明以来,隐层数、隐层神经元个数一直是最头疼的地方。
比如,世界上的许多骗钱模拟大脑计划,大喊着要模拟人脑840亿个神经元,疯狂在隐层上做文章。纯粹在浪费时间。
SVM直接出来打脸:隐层神经元无须很多,只要覆盖支持向量即可。
其次,径向基函数的径向基中心选取,在二次规划的求解当中也被解决,而无须依靠训练。
SVM的劣势:
来自深度学习大师Yoshua Bengio的吐槽:
学习好的表示(representations)是深度学习的核心目的,而非像 SVM 一样就是在特征的固定集合做一个线性预测。(吐槽 SVM 用 kernel 转移重点)。
SVM终究是MLP,精确的MLP,但并不是拯救世界的神器,它只不过是浅层学习这个”数值游戏“的大赢家。
尺有所短,寸有所长。对于SVM和传统神经网络,我们的态度应该是不吹不黑。知其然,知其所以然。
①最大化几何间隔。
如果数据能一道线切开的话,我们希望离这道线最近的点的距离越长越好,否则容易分类错误,这就是SVM的核心。
定义函数间隔di=y(wxi+b),其中y=1 or -1,问题在于2*di和di是等效的分隔平面,所以弃之。
所以又定义几何距离D=d/||w||。||w||=根号(w1^2+w2^2+...wn^2)
目标函数max D,约束条件di=y(wxi+b)>=d, 这里的d是取最小的函数间隔,保证离分割平面最近,且最大化距离。
化简处理:令w’=w/d, b’=b/d, 这样约束条件等式相当于两边被除了d,变成di=y(w’xi+b)>=1,
D也相当于变成1/||w||,为了方便,以后w’全部用w代替。
di=y(wxi+b)>=1, 这是个有趣的式子,由于y=±1,单独取出(wxi+b),那么±1的就是传说中里分隔平面最近的点了,称之为支持向量。
②探究规划问题
目标函数=max D=max 1/||w||,分式好讨厌,等效成min (数学原理不知道是啥=。=)
然后引入拉格朗日乘子α,把目标函数、约束条件捆在一起成一个式子。
这样有新的目标函数:
这个式子很容易被误解,它的max针对的是
min针对的是,注意看min/max底部,不要很矛盾地理解成对整个式子。
max部分是重点,引入变量α,成为拉格朗日乘子。max这部分的意义在于等效约束条件,
由于y(wxi+b)>=1,如果出现小于1的情况,那么减去的这部分就是一个负数,负负得正,会使前面的min黯然失色。至于大于1的情况,可以令α=0 踢掉它。
最理想的情况下,=min
然而这个式子还是比较麻烦的,min规划是先决条件,然后还要考虑不定的乘子部分。
利用拉格朗日对偶性大法,逆转下两个条件,变成对偶规划问题。,要满足KKT条件,就有d*<=p*。
KKT条件说白了就是0<α<C. (define C 100),0 or C称之为边界。
这样就可以先定住max求min,最后再求max了。
③大道至简
上面这个目标函数的min(主元是w、b) 部分化简很神奇,先分别对主元w和b求偏导,令偏导数为0。
第一个偏导结果巧妙地用alpha、y、x替代了恶心的w
第二个偏导结果则是带来了一个新的约束条件,好处是化简目标函数时消掉了b,坏处是给计算alpha乘子带来麻烦。(由此SMO算法诞生了)
将w的代替式拖到里,经过复杂的化简(详见July大神博客),b也被新的约束条件(为0)给消去了。
最后=,很简单,很优美。
加上max和两个约束条件之后
max部分将由SMO算法完成,SMO每次抽取确定两个乘子,然后更新w、b
更新w:。
,(这是单乘子的更新方式,SMO中不能这么干)
更新b:
这个b比较好玩,w确定之后,实际上分隔平面的方向被确定了。
想想一次函数y=wx+b,如果b没确定,则这个一次函数就可能是两个边界间任意一条直线。
那么b应该是什么值呢,应该取两条边界的中间那条比较好。(SMO中b也不能这么干)
④分类函数
训练数据时,需要一个预测分类函数,以便算出误差E。(这个E在SMO中至关重要)
分类函数自然就是带入式子y=wx+b,但是这可不是二元一次方程,w是多维的。
在上面中我们有,那么分类函数就变成。
<xi,x>是内积。这里先不管这个内积怎么算。
⑤SVM的超级武器——核函数
特征空间的映射的引入使得SVM秒掉了各种回归模型。它的原理就是将低维度数据,映射到高维度数据。
比如原来数据是2维,如果是非线性数据,很难划分隔面。但是给它加到5维,就很容易一刀切出划分面了。
巧妙的映射了维度,这对分类函数中的内积计算产生了影响,为了计算在高维空间的内积,出现了核函数。
新的分类函数为,核函数取代了原本的内积计算。
目前使用的核函数通常是 "高斯核“函数,又名径向基核函数。
⑥松弛变量的优化
outlier(异常值)是SVM需要解决的一个问题。
如果就存在一个异常值,离分隔平面超级超级超级近,设这么一个垃圾值为支持向量显然不是明智选择。(间隔越小,平面越难被划分,分类效果就越差)
所以引入松弛变量,使得原目标函数变为
切入约束条件后,拉格朗日函数变成:
然后按照⑤中方法化简,多了一个新主元,并求导令倒数为0。
你不必关系ri是什么,只要知道ri>=0即可,移个项,αi=C+ri。实际意义就是αi多了一个上界C。
同⑤中那样化简拉格朗日函数,最后惊奇发现,松弛变量被消了,和⑤最后的式子一样。
其实松弛变量引入的唯一变化,就是多了个KKT条件多了个上界C。(C的取值很难说,模板代码里取的是100)
)新的KKT条件如下:
α=0,表示非支持向量点。
0<α<C,表示支持向量点。
α=C,表示的是两条支持向量间的outlier(这些点通常被无视掉)
⑥SMO算法
1998年4月,位于总部的微软研究院副主任John Platt发明了这个奇怪的SMO算法,从此SVM超神了。
John Platt那篇论文省去了公式推导,所以大部分情况都是,直接给你个XX情况的公式是XX,以及给出的很残破的C伪代码
对初学者很不友好,链接 ~Link~,想要完全解释清楚还是比较难的。
感谢CSDN某网友提供的完整的SMO的C++代码,里面的变量名几乎与John Platt论文中的C伪代码一致。
Part I SMO的公式推导
①新的分类函数与新的目标函数
SMO定义了新的分类函数u,其实也不算新,就是把b的符号变了。
这个式子就是把y=wx-b,w替换了而已,上面已经出现了类似物了。
也定义的新的目标函数
减号两边换一下,从max变成了min,意义不明。
②两个乘子问题
还记得这玩意不,偏导出来的坑爹约束条件。
假设我们每次抽取一个乘子,设为α1,那么改了α1之后,能保证上面那个约束条件成立么?很可惜,不好办。
所以John Platt提出了SMO(最小序列算法),他认为至少(最小)要同时改变两个乘子。
分为主动乘子(α2)和被动乘子(α1)。每次主动算α2,然后根据约束条件,推出α1的值,这样α1光荣地做了嫁衣。
一个有趣的想法,比如这次搞定了α2,到了下一次,上次的α2又变成了α1,被动算出来之后,会不会导致上次的α2过程白算了?然后恶性循环?
其实想多了,实际测试,每次抽两个乘子,只会使结果变好,而不会卡死在循环里。
于是算α2成为头等大事。
先确定α2的范围,已有约束条件:0<=α1<=C, 0<=α2<=C (称为矩形条件)
y1α1+y2α2=γ,γ=Σ(yi*αi),i=3,4....,m(那个头疼的约束条件,提取出两项)
由于yi=±1, 这里分两种情况。(γ不知道正负)
情况1: y1=y2
y1α1+y2α2=γ => α1+α2=±γ(两条直线)
情况2:y1≠y2,即异号。
y1α1+y2α2=γ => α1-α2=±γ(两条直线)
画个图
这样当y1=y2,α2有下界L=max(0,γ-C),上界H=min(γ,C)
y1≠y2,α2有下界L=max(0,-γ),上界H=min(C-γ,C)
注意这里的α2称之为α2(new),原来的α2称为α2(old),同时下面所有打(*)号的变量都是old变量。
α2的具体值怎么确定呢?有如下推导。
首先,抽取两个乘子后,目标函数被剖分成这样
就是把i、j∈[1,2]的部分提出来了,但是至今不理解vi部分是怎么出来的。
对于条件,令两个式子各乘y1,有
其中,化简目标函数:
对α2求导并令导数为0:
化简:
化简:
令ui-yi=Ei,继续化简,有:
,
裁剪α2(new):
算出α1(new)
特别的,当η<0时,违反了Mercer条件,目标函数为可能∞,这时候α2不能使用上述方式计算,论文中这么写
看不懂,填坑,先按模板代码来。
③启发式抽取乘子。
尽管α1是被动乘子,我们还是得先抽取α1,然后启发式抽取α2。
启发式(经验式)主要是根据已有经验来安排三种抽取乘子的顺序。
最坏情况其实就是O(m)扫一遍全部数据找到一个α2,当然启发式原则保证我们的RP不会那么差。
一、非边界(0 or C)最大化|E1-E2|规则:选择绝对值最大的先计算。
二、非边界随机规则:非边界alpha里随机选择α2
三、含边界随机规则:实在没有办法了,算上边界再随机吧。
④收敛条件
由于每次计算α2时,都是由导数决定的,也就是说,每次新的α2产生,都标志着目标函数的优化。
一旦全部α2收敛(即全部乘子收敛,α1若不收敛,下次可能作为α2被调整),则标志着目标函数优化完毕。
SMO主循环遍历全部数据点选择α1(mainProcess函数)
次循环随机/最大化|E1-E2|规则选择起点开始遍历选择α2 (exampleExamine函数)
相当于两层for循环验证全部乘子对,保证最后的目标函数是收敛的。
⑤双乘子下的几个参数求法
一、α1
α1先通过公式,即 a1 = alph1 - s * (a2 - alph2)
若违反KKT条件,则设为边界,并按照约束条件对α2进行增/减。
二、b
John Platt不知道从哪搞来的公式。目前不知道推导过程。
双乘子情况下求b,论文中这么解释:
①α1非边界:则b=
②α2非边界,则b=
③α1、α2均在边界,则取b1、b2均值
④α1、α2均非边界,则b1=b2,所以①、②任取一个就行了。
三、w
Part Ⅱ SMO的C++代码研究 (坑ing)
一、SMO主过程。
void SMO::smo_main_process()
{
read_in_data(); //initialize
if(!is_test_only)
{
alph.resize(end_support_i,);
b=;
error_cache.resize(N);
}
self_dot_product.resize(N);
precomputed_self_dot_product();
if (!is_test_only)
{
numChanged = ;
examineAll = ;
while (numChanged > || examineAll)
{
numChanged = ;
if (examineAll)
{
for (int k = ; k < N; k++)
numChanged += examineExample (k);
}
else
{
for (int k = ; k < N; k++)
if (alph[k] != && alph[k] != C)
numChanged += examineExample (k);
}
if (examineAll == )
examineAll = ;
else if (numChanged == )
examineAll = ;
}
}
}
SMO主过程
这个过程由两个Bool值控制,numChanged 、 examineAll.
首先第一遍检查全部乘子,之后检查非边界乘子(边界乘子的值通常不会改变了),查不到了再重新检查全部,如果全部还查不到,则结束,计算完毕。
检查并修改乘子是一个智能的过程,综合使用三种手段。
int SMO::examineExample(int i1)
{
float y1, alph1, E1, r1;
y1 = (float)target[i1];
alph1 = alph[i1];
if (alph1 > && alph1 < C)
E1 = error_cache[i1];
else
E1 = learned_func_nonlinear(i1) - y1; r1 = y1 * E1;
if ((r1 < -tolerance && alph1 < C)||(r1 > tolerance && alph1 > ))
{
/////////////使用三种方法选择第二个乘子
//1:在non-bound乘子中寻找maximum fabs(E1-E2)的样本
//2:如果上面没取得进展,那么从随机位置查找non-boundary 样本
//3:如果上面也失败,则从随机位置查找整个样本,改为bound样本
if (examineFirstChoice(i1,E1)) return ; //
if (examineNonBound(i1)) return ; //
if (examineBound(i1)) return ; //
}
///没有进展
return ;
}
利用三种手段修改两个乘子
alpha1直接获取,由于每个乘子对应一条训练数据,所以该条数据误差E1=预测值-真实值,预测值就是把该条数据带入学习方程(分类函数里)去
//径向基核函数
float SMO::kernel_func(int i,int k)
{
float sum=dot_product_func(i,k);
sum*=-;
sum+=self_dot_product[i]+self_dot_product[k];
return exp(-sum/two_sigma_squared);
} float SMO::learned_func_nonlinear(int k)
{
float sum=;
for(int i=; i<end_support_i; i++)
{
if(alph[i]>)
sum+=alph[i]*target[i]*kernel_func(i,k);
}
sum-=b;
return sum;
}
核函数与分类函数
支持向量机(SVM)的更多相关文章
- 【IUML】支持向量机SVM
从1995年Vapnik等人提出一种机器学习的新方法支持向量机(SVM)之后,支持向量机成为继人工神经网络之后又一研究热点,国内外研究都很多.支持向量机方法是建立在统计学习理论的VC维理论和结构风险最 ...
- 机器学习:Python中如何使用支持向量机(SVM)算法
(简单介绍一下支持向量机,详细介绍尤其是算法过程可以查阅其他资) 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别.分类(异 ...
- 以图像分割为例浅谈支持向量机(SVM)
1. 什么是支持向量机? 在机器学习中,分类问题是一种非常常见也非常重要的问题.常见的分类方法有决策树.聚类方法.贝叶斯分类等等.举一个常见的分类的例子.如下图1所示,在平面直角坐标系中,有一些点 ...
- 机器学习算法 - 支持向量机SVM
在上两节中,我们讲解了机器学习的决策树和k-近邻算法,本节我们讲解另外一种分类算法:支持向量机SVM. SVM是迄今为止最好使用的分类器之一,它可以不加修改即可直接使用,从而得到低错误率的结果. [案 ...
- 机器学习之支持向量机—SVM原理代码实现
支持向量机—SVM原理代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9596898.html 1. 解决 ...
- 支持向量机SVM——专治线性不可分
SVM原理 线性可分与线性不可分 线性可分 线性不可分-------[无论用哪条直线都无法将女生情绪正确分类] SVM的核函数可以帮助我们: 假设‘开心’是轻飘飘的,“不开心”是沉重的 将三维视图还原 ...
- 一步步教你轻松学支持向量机SVM算法之案例篇2
一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- 一步步教你轻松学支持向量机SVM算法之理论篇1
一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- OpenCV 学习笔记 07 支持向量机SVM(flag)
1 SVM 基本概念 本章节主要从文字层面来概括性理解 SVM. 支持向量机(support vector machine,简SVM)是二类分类模型. 在机器学习中,它在分类与回归分析中分析数据的监督 ...
- OpenCV支持向量机(SVM)介绍
支持向量机(SVM)介绍 目标 本文档尝试解答如下问题: 如何使用OpenCV函数 CvSVM::train 训练一个SVM分类器, 以及用 CvSVM::predict 测试训练结果. 什么是支持向 ...
随机推荐
- Lattice Diamond 的学习之新建工程
1).打开软件 在软件打开后的初始布局会有一个Start page 可以创建.打开.导入一个ISPLEVER 工程. 2).建立工程:1,Start page 中Project --> NEW ...
- Android -- android.os.Parcelable[] cannot be cast to ...
我本想直接把Bunde.getParcelableArray(...)得到的Parcelable[]强制转换为自定义类数组,但是失败了,网上找了两种解决办法: Parcelable[] data =b ...
- Delphi运算符总结
分类 运算符 操作 操作数 结果类型 范例 算术运算符(加法.减法和乘法运算符的结果为参加运算的两个数据中的精度高的类型) + 加 整数,实数 整数,实数 X + Y - 减 整数,实数 整数,实数 ...
- [LeetCode] Same Tree
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- 解决oracle11g 空表不能exp导出的问题
在使用exp备份数据库,然后使用imp导入的时候出现了好多表或者视图不存在的错误信息. 究其原因,是11G中增加了一个新的特性:数据条数是0时不分配segment,所以就不能被导出. 解决思路:就是向 ...
- hdu 4389 数位dp
求区间内满足x%fx==0的数的个数,fx为该数各个位数上的数字之和Sample Input21 1011 20 Sample OutputCase 1: 10Case 2: 3 大小不是你想开,想开 ...
- 函数fseek() 用法(转)
在阅读代码时,遇到了很早之前用过的fseek(),很久没有用了,有点陌生,写出来以便下次查阅. 函数功能是把文件指针指向文件的开头,需要包含头文件stdio.h fseek 函数名: fseek ...
- barabasilab-networkScience学习笔记2-图理论
第一次接触复杂性科学是在一本叫think complexity的书上,Allen博士很好的讲述了数据结构与复杂性科学,barabasi是一个知名的复杂性网络科学家,barabasilab则是他所主导的 ...
- Java学习笔记(五)——数组
一.数组使用方法 1. 声明数组 语法: 数据类型[ ] 数组名: 或者 数据类型 数组名[ ]: 其中,数组名可以是任意合法的变量名 2. 分配空间 简单地说,就是指定数组中最多可存储多少个元素 ...
- 【T_SQL】 基础 事务
1.使用 T-SQL 语句来管理事务 开始事务:BEGIN TRANSACTION 提交事务:COMMIT TRANSACTION 回滚(撤销)事务:ROLLBAC ...