最近完成的一个项目用到了SVM,之前也一直有听说支持向量机,知道它是机器学习中一种非常厉害的算法。利用将近一个星期的时间学习了一下支持向量机,把原理推了一遍,感觉支持向量机确实挺厉害的,尤其是核函数变换可以把一个低维不可分问题转化为高维可分的问题。
需要解决的问题
支持向量机是一种监督学习的方法,主要用来进行分类和回归分析,当我们对一些数据进行分类的时候,可能会考虑以下问题:
- 怎么选择决策边界?什么样的决策边界最好?
- 目标函数如何求解?
- 对于线性不可分的问题该用何种方法来解决。
解决问题流程
- 选取决策边界(选取出最好的决策边界)
- 列目标函数
- 优化目标函数
- 求解优化目标(利用拉格朗日乘子法)
- 软间隔问题的解决(解决离群点)
- 核函数变换
决策边界的选择
Step1
当我们拿到一些简单的线性可分的数据的时候,如下图,将两类数据分类的决策边界有n条直线(图中显示了三条),那么哪一个决策边界才是最好的呢。

直觉告诉我:中间的那一条边界是最好的,而实际也的确如此:
举个简单的栗子:

两侧的数据就好比是两边是河,我们肯定希望可以走的地方越宽越好,这样掉入河里的几率就降低了。
所以我们选择的决策边界是:选出来离河岸最远的(河岸就是边界上的点,要Large Margin),第二个肯定比第一个效果好。
好了,知道要选择什么样的边界之后,接下来就是要求解边界了。
我们希望找到离决策边界最近的点,这样就找到了决策边界。
所以,假设决策边界是一个阴影平面,求点到平面的距离转换成点到点的距离,然后再垂直方向上的投影。大概的模型如下图:

x为一个点,面的方程可以用线性方程来描述:

其中w为法向量,决定了超平面的方向,b为位移量,决定了超平面与原点的距离。(学过高数几何那一部分的应该都看的懂)
接下来就是算一下x到平面的距离。假设平面上有两点x’,x’’,那么则有:
W^Tx'+b=0WTx′+b=0
W^Tx''+b=0WTx′′+b=0
即W^T(x''-x')+b=0WT(x′′−x′)+b=0
直接求垂线的距离比较难,但是我们可以通过求xx’两点的长度,再求其在垂直方向的投影来得到垂线的距离。
通过计算可以得到以下式子:

Step 2
接下来我们引入数据来将上面的式子完整化具体化
假设现在有数据集(x1,y1),(x2,y2)……(xn,yn)(x为数据,y为标签)。
在这里我们认为当X为正例时Y=1,负例是Y=-1。
这里的±1仅仅是一个标号,代表正负样本,并不是具体的数值,主要是因为这里是二分类,而且方便下面的简化。和Logistics Regression(Logistics Regression中用0和1来区分正负例)一样,而且这是可以由Logistics Regression推出来的(具体过程不在这里写了)
假设现在的决策边界为:

如果感觉ϕ(x)这种表述方式不太习惯,可以考虑所有的ϕ(x)=x,式主要是为了强调,在实际问题中,输入空间x一般不会作为模型的输入,而是要将输入空间通过一定的特征转换算法ϕ(x),转换到特征空间,最后在特征空间中做算法学习。而且,在实际问题中,各种算法基本上都是死的,但是,特征变换的这个过程ϕ(x)却是活的,很多时候,决定一个实际问题能不能很好的解决,ϕ(x)起着决定性的作用。举个简单的例子,比如Logistics Regression,数据最好要做归一化,如果数据不归一化,那么那些方差特别大的特征就会成为主特征,影响模型的计算,ϕ(x)就可以做这个事情。
给上面这个函数做一个定义:当预测的结果大于0的时候Y=1(对应着正例),小于0的时候为负例。即:
y(x)大于0时,y_iyi=1,y(x)小于0时,y_iyi=-1,那么下面我们可以将这个式子合着写成y_iyiy(x)>0。
Step 3
对于第一步推出来的点到距离的公式,我们注意到有绝对值的存在,在计算机中这是不容易表示的,于是我们可以引入第二步的yi,因为y_iyiy(x)>0。所以我们可以将距离公式表达成:

这样一来就去掉了绝对值。
优化目标
优化目标:找到一条线,使得距离线最近的点能够最远(找到一条线,使得距离河岸最近的线能够最远)
即:

首先min中求了所有点中离线最近的点,max是使得该点与边界最远。
这个目标看起来是不是特别繁琐~那接下来我们再来简化一下。
通过一个放缩变换:决策方程中的(w,b)可以通过放缩使其结果值|Y|≥1(之前认为是大于0,现在严格了一些)。
这个放缩的过程就是通过等比例扩大或缩小y,w,b的系数,总能得到|Y|≥1。而且表达式中重要的不是w 和 b 的取值,重要的是 w 和 b 的比值, w 和 b 的比值决定了一个决策面的点集,也就决定了一个决策面。
|Y|≥1,即:

所以上面优化目标中

所以我们现在只剩下:

只需要将1/||W||最大化就OK了。所以这就是我们的目标函数。
目标函数求解
由上面的推导我们可以知道,目标函数为:

求解这个式子就是求解一个极大值,机器中一般都是将求极大值的问题转化为求极小值的问题。求1/W的极大值不就是求W的极小值嘛。所以我们可以转化成:

这个式子也不好求啊~那么该如何求解呢?
这里就要用到拉格朗日乘子法:
我们需要解决的问题是带约束的拉格朗日乘子法问题:

是不是有点复杂……总之吧,我们要求得式子可以转化为:

还有约束:

咦,这个α是什么东东,现在我们先理解为每个xi前面加了个系数,下面会继续说,我们可以把求w转为求α。
SVM求解推导
Step 1
接下来的推导我感觉挺复杂的……推完想吐。
引入数学KKT公式(这里不详细证明)

大概意思就是先求里面的最大值在求外面的最小值和先求里面的最小值在求外面的最大值是一样的。
求极小值肯定先想到的就是求偏导,分别对w和b求偏导,让偏导等于0:

再将得到的结果带到我们所要求解的原式中:

通过上面的推导我们就把求w转化为了求α,即需要对α求极大值:

条件:


按照常规套路:将求极大值问题转化为求极小值问题:求一个数的最大值也即求该数相反数的最小值,即:

条件不变。
Step 2
α怎么解呢,举个简单的例子:

因为x1,x2是正例,所以对应的Y=1,x3是负例,所以对应的Y=-1

分别对α1和α2求偏导,偏导等于0可得α1=1.5,α2=-1。
但是α2<0,和我们的条件αi≥0不相符,所以解应该在边界点上。
所以分别令α1和α2等于0来计算。
α1=0,α2=-2/13,带入原式得到-0.153,α2依然小于0,不满足约束
α1=0.25,α2=0,带入原式得到-0.25,符合约束。根据α1和α2计算得到α3,α3=α1+α2=0.25。所以最小值在(0.25,0,0.25)处取得。

终于解完了……有点想吐的感觉。
————————————————————————————————————
通过上面的这个例子是不是有一点别的发现呢?
通过上面的例子可以知道只有边界点对应的不为0,即非边界点对应的均为0,也就是说最终影响w值的只是边界点(距离决策边界最近的那些点)这也与我们的求解目标是一致的。此时,我们可以说决策变量是由边界上的点支持决定的,我们可以叫这些边界点为支持向量,只有这些支持向量会对结果有影响。据说这也是支持向量机名字的由来。
软间隔问题
先来观察一下这个图:

在图中我们发现一个离群点造成了超平面的移动,间隔缩小了,可以看到模型对噪声非常敏感。如果这个离群点在另外一个类中时,那我们的模型就线性不可分了。
之前的方法要求把两类点完全分得开,这个要求有点过于严格了,来放松一下!这时候我们给原来的模型加一些条件,即允许这些个别离群点违背限制条件,引入松弛因子:

那么新的目标函数为:

限制条件为:


该模型称为软间隔,引入的非负参数ξi(松弛变量),引入了这个参数后,可以发现允许一些样本点的函数间隔小于1,即在最大间隔区间内,或者函数间隔为负,即样本点在另一个类的区域内。 平白无故的放宽了条件,总是要讨回一点债的。因此我们将目标函数进行了调整,用来对离群点进行惩罚,目标函数后面加上的C∑ξi,表示离群点越多,目标函数值越大,而我们要求的是尽可能小的目标函数值,也就是说我在选择超平面时,要选择最合适的超平面使离群点的数目最小,这样目标函数的值就会相对离群点多的时候更小。C是离群点的权重,C越大表明离群点对目标函数影响越大,所以我们不希望超平面分离出更多的离群点。
这里的C是我们需要制定的一个参数。
解法和上面的流程大致相同(这里不多说了):

核变换
接下来主要是谈论一下ϕ(x)。看了上面的介绍,是不是有一种这样的感觉:并没有觉得SVM厉害在哪里,只是进行了一个线性二分。要是真这样感觉那就大错特错了,不信接着往下看,SVM最厉害的地方出现了。
左边的图这些数据分布比较复杂,明显是线性不可分的。那么有没有一种方法来分开呢。当然有,那就是把低微不可分问题转为高维可分的(如右图)。

再如下图:


那么接下来给出核函数的定义:
核函数(kernel function)就是指K(x, y) = <f(x), f(y)>,其中x和y是n维的输入值,f(·) 是从n维到m维的映射(通常,m>>n)。<x, y>是x和y的内积。
再来举个小小的栗子。
假如现在又两个数据: x = (x1, x2, x3); y = (y1, y2, y3);
按照SVM和函数理论来说,在3D空间内已经不能进行线性可分了,我们得通过一个函数把它映射到更高维的空间。
令 f(x) = (x1x1, x1x2, x1x3, x2x1, x2x2, x2x3, x3x1, x3x2, x3x3); f(y)亦然;(实际上就是把特征组合,相当于升维)。由于需要计算内积,所以需要计算在9维下的数据,一想就知道很复杂……
具体到数字:令x=(1,2,3);y=(4,5,6)。那么f(x)=(1,2,3,2,4,6,3,6,9),f(y)=(16,20,24,20,25,36,24,30,36)。此时<f(x),f(y)>=16+40+72…+324=1024。
这些数字比较小,看起来还能应付,但是如果数再大点呢,是不是就很复杂了,甚至没办法计算了。
但是发现:K(x, y)=(<x,y>)^2(<x,y>)2
K(x, y)=(4+10+18)^2=1024(4+10+18)2=1024
这种计算方法要比刚才的计算方法简单很多吧
这也是一个非常重要的特性。在支持向量机中,虽然说是映射到高维空间中去求内积,但是实际中计算的时候并没有在高维度下计算。只是假设映射到了高维空间,但实际上要的是计算的结果,这个结果在低维空间中计算就可以,然后把这个值映射到高维空间。所以核函数把高维空间的计算转换为低维空间中计算,实际并没有映射到高维空间中去。
从低维到高维需要的这个映射就是核函数,那么核函数怎么来指定呢?
常用的核函数是高斯核函数(也称径向基 (RBF) 函数,是常用的一种核函数。它可以将有限维数据映射到高维空间)。
在机器中的效果如下:
线性核函数:

高斯核函数:
