一 Maximum Margin Classifier
SVM 一直被认为是效果最好的现成可用的分类算法之一(其实有很多人都相信,“之一”是可以去掉的)。这里“现成可用”其实是很重要的,因为一直以来学术界和工业界甚至只是学术界里做理论的和做应用的之间,都有一种“鸿沟”,有些很 fancy 或者很复杂的算法,在抽象出来的模型里很完美,然而在实际问题上却显得很脆弱,效果很差甚至完全 fail 。而 SVM 则正好是一个特例——在两边都混得开。
好了,由于 SVM 的故事本身就很长,所以废话就先只说这么多了,直接入题吧。当然,说是入贴,但是也不能一上来就是 SVM ,而是必须要从线性分类器开始讲。这里我们考虑的是一个两类的分类问题,数据点用
x
来表示,这是一个
n
维向量,而类别用
y
来表示,可以取 1 或者 -1 ,分别代表两个不同的类(有些地方会选 0 和 1 ,当然其实分类问题选什么都无所谓,只要是两个不同的数字即可,不过这里选择 +1 和 -1 是为了方便 SVM 的推导,后面就会明了了)。一个线性分类器就是要在
n
维的数据空间中找到一个超平面,其方程可以表示为
一个超平面,在二维空间中的例子就是一条直线。我们希望的是,通过这个超平面可以把两类数据分隔开来,比如,在超平面一边的数据点所对应的
y
全是 -1 ,而在另一边全是 1 。具体来说,我们令
f(x)=wTx+b
,显然,如果
f(x)=0
,那么
x
是位于超平面上的点。我们不妨要求对于所有满足
f(x)<0
的点,其对应的
y
等于 -1 ,而
f(x)>0
则对应
y=1
的数据点。当然,有些时候(或者说大部分时候)数据并不是线性可分的,这个时候满足这样条件的超平面就根本不存在,不过关于如何处理这样的问题我们后面会讲,这里先从最简单的情形开始推导,就假设数据都是线性可分的,亦即这样的超平面是存在的。
如图所示,两种颜色的点分别代表两个类别,红颜色的线表示一个可行的超平面。在进行分类的时候,我们将数据点
x
代入
f(x)
中,如果得到的结果小于 0 ,则赋予其类别 -1 ,如果大于 0 则赋予类别 1 。如果
f(x)=0
,则很难办了,分到哪一类都不是。事实上,对于
f(x)
的绝对值很小的情况,我们都很难处理,因为细微的变动(比如超平面稍微转一个小角度)就有可能导致结果类别的改变。理想情况下,我们希望
f(x)
的值都是很大的正数或者很小的负数,这样我们就能更加确信它是属于其中某一类别的。
从几何直观上来说,由于超平面是用于分隔两类数据的,越接近超平面的点越“难”分隔,因为如果超平面稍微转动一下,它们就有可能跑到另一边去。反之,如果是距离超平面很远的点,例如图中的右上角或者左下角的点,则很容易分辩出其类别。
实际上这两个 Criteria 是互通的,我们定义 functional margin 为
γˆ=y(wTx+b)=yf(x)
,注意前面乘上类别
y
之后可以保证这个 margin 的非负性(因为
f(x)<0
对应于
y=−1
的那些点),而点到超平面的距离定义为 geometrical margin 。不妨来看看二者之间的关系。如图所示,对于一个点
x
,令其垂直投影到超平面上的对应的为
x0
,由于
w
是垂直于超平面的一个向量(请自行验证),我们有
又由于
x0
是超平面上的点,满足
f(x0)=0
,代入超平面的方程即可算出
不过,这里的
γ
是带符号的,我们需要的只是它的绝对值,因此类似地,也乘上对应的类别
y
即可,因此实际上我们定义 geometrical margin 为:
显然,functional margin 和 geometrical margin 相差一个
∥w∥
的缩放因子。按照我们前面的分析,对一个数据点进行分类,当它的 margin 越大的时候,分类的 confidence 越大。对于一个包含
n
个点的数据集,我们可以很自然地定义它的 margin 为所有这
n
个点的 margin 值中最小的那个。于是,为了使得分类的 confidence 高,我们希望所选择的 hyper plane 能够最大化这个 margin 值。 不过这里我们有两个 margin 可以选,不过 functional margin 明显是不太适合用来最大化的一个量,因为在 hyper plane 固定以后,我们可以等比例地缩放
w
的长度和
b
的值,这样可以使得
f(x)=wTx+b
的值任意大,亦即 functional margin
γˆ
可以在 hyper plane 保持不变的情况下被取得任意大,而 geometrical margin 则没有这个问题,因为除上了
∥w∥
这个分母,所以缩放
w
和
b
的时候
γ˜
的值是不会改变的,它只随着 hyper plane 的变动而变动,因此,这是更加合适的一个 margin 。这样一来,我们的 maximum margin classifier 的目标函数即定义为
当然,还需要满足一些条件,根据 margin 的定义,我们有
yi(wTxi+b)=γˆi≥γˆ,i=1,…,n
其中
γˆ=γ˜∥w∥
,根据我们刚才的讨论,即使在超平面固定的情况下,
γˆ
的值也可以随着
∥w∥
的变化而变化。由于我们的目标就是要确定超平面,因此可以把这个无关的变量固定下来,固定的方式有两种:一是固定
∥w∥
,当我们找到最优的
γ˜
时
γˆ
也就可以随之而固定;二是反过来固定
γˆ
,此时
∥w∥
也可以根据最优的
γ˜
得到。处于方便推导和优化的目的,我们选择第二种,令
γˆ=1
,则我们的目标函数化为:
max1∥w∥,s.t.,yi(wTxi+b)≥1,i=1,…,n
通过求解这个问题,我们就可以找到一个 margin 最大的 classifier ,如下图所示,中间的红色线条是 Optimal Hyper Plane ,另外两条线到红线的距离都是等于
γ˜
的:
到此为止,算是完成了 Maximum Margin Classifier 的介绍,通过最大化 margin ,我们使得该分类器对数据进行分类时具有了最大的 confidence (实际上,根据我们说给的一个数据集的 margin 的定义,准确的说,应该是“对最不 confidence 的数据具有了最大的 confidence”——虽然有点拗口)。
二 Support Vector
可以看到两个支撑着中间的 gap 的超平面,它们到中间的 separating hyper plane 的距离相等(想想看:为什么一定是相等的?),即我们所能得到的最大的 geometrical margin
γ˜
。而“支撑”这两个超平面的必定会有一些点,试想,如果某超平面没有碰到任意一个点的话,那么我就可以进一步地扩充中间的 gap ,于是这个就不是最大的 margin 了。由于在
n
维向量空间里一个点实际上是和以原点为起点,该点为终点的一个向量是等价的,所以这些“支撑”的点便叫做支持向量。
很显然,由于这些 supporting vector 刚好在边界上,所以它们是满足
y(wTx+b)=1
(还记得我们把 functional margin 定为 1 了吗?),而对于所有不是支持向量的点,也就是在“阵地后方”的点,则显然有
y(wTx+b)>1
。事实上,当最优的超平面确定下来之后,这些后方的点就完全成了路人甲了,它们可以在自己的边界后方随便飘来飘去都不会对超平面产生任何影响。这样的特性在实际中有一个最直接的好处就在于存储和计算上的优越性,例如,如果使用 100 万个点求出一个最优的超平面,其中是 supporting vector 的有 100 个,那么我只需要记住这 100 个点的信息即可,对于后续分类也只需要利用这 100 个点而不是全部 100 万个点来做计算。(当然,通常除了 K-Nearest Neighbor 之类的Memory-based Learning 算法,通常算法也都不会直接把所有的点记忆下来,并全部用来做后续 inference 中的计算。不过,如果算法使用了 Kernel 方法进行非线性化推广的话,就会遇到这个问题了。Kernel 方法在下一次会介绍。)
当然,除了从几何直观上之外,支持向量的概念也会从其优化过程的推导中得到。其实上一次还偷偷卖了另一个关子就是虽然给出了目标函数,却没有讲怎么来求解。现在就让我们来处理这个问题。回忆一下之前得到的目标函数:
max1∥w∥s.t.,yi(wTxi+b)≥1,i=1,…,n
这个问题等价于(为了方便求解,我在这里加上了平方,还有一个系数,显然这两个问题是等价的,因为我们关心的并不是最优情况下目标函数的具体数值):
min12∥w∥2s.t.,yi(wTxi+b)≥1,i=1,…,n
到这个形式以后,就可以很明显地看出来,它是一个凸优化问题,或者更具体地说,它是一个二次优化问题——目标函数是二次的,约束条件是线性的。这个问题可以用任何现成的QP (Quadratic Programming) 的优化包进行求解。
啊?呃,有人说我偷懒不负责任了?好吧,嗯,其实呢,虽然这个问题确实是一个标准的 QP 问题,但是它也有它的特殊结构,通过 Lagrange Duality 变换到对偶变量 (dual variable) 的优化问题之后,可以找到一种更加有效的方法来进行求解——这也是 SVM 盛行的一大原因,通常情况下这种方法比直接使用通用的 QP 优化包进行优化要高效得多。此外,在推导过程中,许多有趣的特征也会被揭露出来,包括刚才提到的 supporting vector 的问题。
关于 Lagrange duality 我没有办法在这里细讲了,可以参考 Wikipedia 。简单地来说,通过给每一个约束条件加上一个 Lagrange multiplier,我们可以将它们融和到目标函数里去
L(w,b,α)=12∥w∥2−∑i=1nαi(yi(wTxi+b)−1)
然后我们令
容易验证,当某个约束条件不满足时,例如
yi(wTxi+b)<1
,那么我们显然有
θ(w)=∞
(只要令
αi=∞
即可)。而当所有约束条件都满足时,则有
θ(w)=12∥w∥2
,亦即我们最初要最小化的量。因此,在要求约束条件得到满足的情况下最小化
12∥w∥2
实际上等价于直接最小化
θ(w)
(当然,这里也有约束条件,就是
αi≥0,i=1,…,n
),因为如果约束条件没有得到满足,
θ(w)
会等于无穷大,自然不会是我们所要求的最小值。具体写出来,我们现在的目标函数变成了:
minw,bθ(w)=minw,bmaxαi≥0L(w,b,α)=p∗
这里用
p∗
表示这个问题的最优值,这个问题和我们最初的问题是等价的。不过,现在我们来把最小和最大的位置交换一下:
当然,交换以后的问题不再等价于原问题,这个新问题的最优值用
d∗
来表示。并,我们有
d∗≤p∗
,这在直观上也不难理解,最大值中最小的一个总也比最小值中最大的一个要大吧! :) 总之,第二个问题的最优值
d∗
在这里提供了一个第一个问题的最优值
p∗
的一个下界,在满足某些条件的情况下,这两者相等,这个时候我们就可以通过求解第二个问题来间接地求解第一个问题。具体来说,就是要满足
KKT 条件,这里暂且先略过不说,直接给结论:我们这里的问题是满足 KKT 条件的,因此现在我们便转化为求解第二个问题。
首先要让
L
关于
w
和
b
最小化,我们分别令
∂L/∂w
和
∂L/∂b
等于零:
∂L∂w=0∂L∂b=0⇒w=∑i=1nαiyixi⇒∑i=1nαiyi=0
带回
L
得到:
L(w,b,α)=12∑i,j=1nαiαjyiyjxTixj−∑i,j=1nαiαjyiyjxTixj–b∑i=1nαiyi+∑i=1nαi=∑i=1nαi–12∑i,j=1nαiαjyiyjxTixj
此时我们得到关于 dual variable
α
的优化问题:
maxαs.t.,∑i=1nαi–12∑i,j=1nαiαjyiyjxTixjαi≥0,i=1,…,n∑i=1nαiyi=0
如前面所说,这个问题有更加高效的优化算法,不过具体方法在这里先不介绍,让我们先来看看推导过程中得到的一些有趣的形式。首先就是关于我们的 hyper plane ,对于一个数据点
x
进行分类,实际上是通过把
x
带入到
f(x)=wTx+b
算出结果然后根据其正负号来进行类别划分的。而前面的推导中我们得到
w=∑ni=1αiyixi
,因此
f(x)=(∑i=1nαiyixi)Tx+b=∑i=1nαiyi⟨xi,x⟩+b
这里的形式的有趣之处在于,对于新点
x
的预测,只需要计算它与训练数据点的内积即可(这里
⟨⋅,⋅⟩
表示向量内积),这一点至关重要,是之后使用 Kernel 进行非线性推广的基本前提。此外,所谓 Supporting Vector 也在这里显示出来——事实上,所有非 Supporting Vector 所对应的系数
α
都是等于零的,因此对于新点的内积计算实际上只要针对少量的“支持向量”而不是所有的训练数据即可。
为什么非支持向量对应的
α
等于零呢?直观上来理解的话,就是这些“后方”的点——正如我们之前分析过的一样,对超平面是没有影响的,由于分类完全有超平面决定,所以这些无关的点并不会参与分类问题的计算,因而也就不会产生任何影响了。这个结论也可由刚才的推导中得出,回忆一下我们刚才通过 Lagrange multiplier 得到的目标函数:
maxαi≥0L(w,b,α)=maxαi≥012∥w∥2−∑i=1nαi(yi(wTxi+b)−1)
注意到如果
xi
是支持向量的话,上式中红颜色的部分是等于 0 的(因为支持向量的 functional margin 等于 1 ),而对于非支持向量来说,functional margin 会大于 1 ,因此红颜色部分是大于零的,而
αi
又是非负的,为了满足最大化,
αi
必须等于 0 。这也就是这些非 Supporting Vector 的点的悲惨命运了。
嗯,于是呢,把所有的这些东西整合起来,得到的一个 maximum margin hyper plane classifier 就是支持向量机(Support Vector Machine),经过直观的感觉和数学上的推导,为什么叫“支持向量”,应该也就明了了吧?当然,到目前为止,我们的 SVM 还比较弱,只能处理线性的情况,不过,在得到了 dual 形式之后,通过 Kernel 推广到非线性的情况就变成了一件非常容易的事情了。
三 Kernel
线性情况下的支持向量机,它通过寻找一个线性的超平面来达到对数据进行分类的目的。不过,由于是线性方法,所以对非线性的数据就没有办法处理了。例如图中的两类数据,分别分布为两个圆圈的形状,不论是任何高级的分类器,只要它是线性的,就没法处理,SVM 也不行。因为这样的数据本身就是线性不可分的。
对于这个数据集,我可以悄悄透露一下:我生成它的时候就是用两个半径不同的圆圈加上了少量的噪音得到的,所以,一个理想的分界应该是一个“圆圈”而不是一条线(超平面)。如果用
X1
和
X2
来表示这个二维平面的两个坐标的话,我们知道一条二次曲线(圆圈是二次曲线的一种特殊情况)的方程可以写作这样的形式:
a1X1+a2X21+a3X2+a4X22+a5X1X2+a6=0
注意上面的形式,如果我们构造另外一个五维的空间,其中五个坐标的值分别为
Z1=X1
,
Z2=X21
,
Z3=X2
,
Z4=X22
,
Z5=X1X2
,那么显然,上面的方程在新的坐标系下可以写作:
关于新的坐标
Z
,这正是一个 hyper plane 的方程!也就是说,如果我们做一个映射
ϕ:R2→R5
,将
X
按照上面的规则映射为
Z
,那么在新的空间中原来的数据将变成线性可分的,从而使用之前我们推导的线性分类算法就可以进行处理了。这正是 Kernel 方法处理非线性问题的基本思想。
再进一步描述 Kernel 的细节之前,不妨再来看看这个例子映射过后的直观例子。当然,我没有办法把 5 维空间画出来,不过由于我这里生成数据的时候就是用了特殊的情形,具体来说,我这里的超平面实际的方程是这个样子(圆心在
X2
轴上的一个正圆):
因此我只需要把它映射到
Z1=X21
,
Z2=X22
,
Z3=X2
这样一个三维空间中即可,下图(这是一个 gif 动画)即是映射之后的结果,将坐标轴经过适当的旋转,就可以很明显地看出,数据是可以通过一个平面来分开的:
现在让我们再回到 SVM 的情形,假设原始的数据时非线性的,我们通过一个映射
ϕ(⋅)
将其映射到一个高维空间中,数据变得线性可分了,这个时候,我们就可以使用原来的推导来进行计算,只是所有的推导现在是在新的空间,而不是原始空间中进行。当然,推导过程也并不是可以简单地直接类比的,例如,原本我们要求超平面的法向量
w
,但是如果映射之后得到的新空间的维度是无穷维的(确实会出现这样的情况,比如后面会提到的 Gaussian Kernel ),要表示一个无穷维的向量描述起来就比较麻烦。于是我们不妨先忽略过这些细节,直接从最终的结论来分析,回忆一下,我们上一次得到的最终的分类函数是这样的:
现在则是在映射过后的空间,即:
f(x)=∑i=1nαiyi⟨ϕ(xi),ϕ(x)⟩+b
而其中的
α
也是通过求解如下 dual 问题而得到的:
maxαs.t.,∑i=1nαi–12∑i,j=1nαiαjyiyj⟨ϕ(xi),ϕ(xj)⟩αi≥0,i=1,…,n∑i=1nαiyi=0
这样一来问题就解决了吗?似乎是的:拿到非线性数据,就找一个映射
ϕ(⋅)
,然后一股脑把原来的数据映射到新空间中,再做线性 SVM 即可。不过若真是这么简单,我这篇文章的标题也就白写了——说了这么多,其实还没到正题呐!其实刚才的方法稍想一下就会发现有问题:在最初的例子里,我们对一个二维空间做映射,选择的新空间是原始空间的所有一阶和二阶的组合,得到了五个维度;如果原始空间是三维,那么我们会得到 19 维的新空间(验算一下?),这个数目是呈爆炸性增长的,这给
ϕ(⋅)
的计算带来了非常大的困难,而且如果遇到无穷维的情况,就根本无从计算了。所以就需要 Kernel 出马了。
不妨还是从最开始的简单例子出发,设两个向量
x1=(η1,η2)T
和
x2=(ξ1,ξ2)T
,而
ϕ(⋅)
即是到前面说的五维空间的映射,因此映射过后的内积为:
⟨ϕ(x1),ϕ(x2)⟩=η1ξ1+η21ξ21+η2ξ2+η22ξ22+η1η2ξ1ξ2
另外,我们又注意到:
(⟨x1,x2⟩+1)2=2η1ξ1+η21ξ21+2η2ξ2+η22ξ22+2η1η2ξ1ξ2+1
二者有很多相似的地方,实际上,我们只要把某几个维度线性缩放一下,然后再加上一个常数维度,具体来说,上面这个式子的计算结果实际上和映射
φ(X1,X2)=(2√X1,X21,2√X2,X22,2√X1X2,1)T
之后的内积
⟨φ(x1),φ(x2)⟩
的结果是相等的(自己验算一下)。区别在于什么地方呢?一个是映射到高维空间中,然后再根据内积的公式进行计算;而另一个则直接在原来的低维空间中进行计算,而不需要显式地写出映射后的结果。回忆刚才提到的映射的维度爆炸,在前一种方法已经无法计算的情况下,后一种方法却依旧能从容处理,甚至是无穷维度的情况也没有问题。
我们把这里的计算两个向量在映射过后的空间中的内积的函数叫做核函数 (Kernel Function) ,例如,在刚才的例子中,我们的核函数为:
核函数能简化映射空间中的内积运算——刚好“碰巧”的是,在我们的 SVM 里需要计算的地方数据向量总是以内积的形式出现的。对比刚才我们写出来的式子,现在我们的分类函数为:
其中
α
由如下 dual 问题计算而得:
maxαs.t.,∑i=1nαi–12∑i,j=1nαiαjyiyjκ(xi,xj)αi≥0,i=1,…,n∑i=1nαiyi=0
这样一来计算的问题就算解决了,避开了直接在高维空间中进行计算,而结果却是等价的,实在是一件非常美妙的事情!当然,因为我们这里的例子非常简单,所以我可以手工构造出对应于
φ(⋅)
的核函数出来,如果对于任意一个映射,想要构造出对应的核函数就很困难了。
最理想的情况下,我们希望知道数据的具体形状和分布,从而得到一个刚好可以将数据映射成线性可分的
ϕ(⋅)
,然后通过这个
ϕ(⋅)
得出对应的
κ(⋅,⋅)
进行内积计算。然而,第二步通常是非常困难甚至完全没法做的。不过,由于第一步也是几乎无法做到,因为对于任意的数据分析其形状找到合适的映射本身就不是什么容易的事情,所以,人们通常都是“胡乱”选择映射的,所以,根本没有必要精确地找出对应于映射的那个核函数,而只需要“胡乱”选择一个核函数即可——我们知道它对应了某个映射,虽然我们不知道这个映射具体是什么。由于我们的计算只需要核函数即可,所以我们也并不关心也没有必要求出所对应的映射的具体形式。
当然,说是“胡乱”选择,其实是夸张的说法,因为并不是任意的二元函数都可以作为核函数,所以除非某些特殊的应用中可能会构造一些特殊的核(例如用于文本分析的文本核,注意其实使用了 Kernel 进行计算之后,其实完全可以去掉原始空间是一个向量空间的假设了,只要核函数支持,原始数据可以是任意的“对象”——比如文本字符串),通常人们会从一些常用的核函数中选择(根据问题和数据的不同,选择不同的参数,实际上就是得到了不同的核函数),例如:
- 多项式核
κ(x1,x2)=(⟨x1,x2⟩+R)d
,显然刚才我们举的例子是这里多项式核的一个特例(
R=1,d=2
)。虽然比较麻烦,而且没有必要,不过这个核所对应的映射实际上是可以写出来的,该空间的维度是
(m+dd)
,其中
m
是原始空间的维度。
- 高斯核
κ(x1,x2)=exp(−∥x1−x2∥22σ2)
,这个核就是最开始提到过的会将原始空间映射为无穷维空间的那个家伙。不过,如果
σ
选得很大的话,高次特征上的权重实际上衰减得非常快,所以实际上(数值上近似一下)相当于一个低维的子空间;反过来,如果
σ
选得很小,则可以将任意的数据映射为线性可分——当然,这并不一定是好事,因为随之而来的可能是非常严重的过拟合问题。不过,总的来说,通过调控参数
σ
,高斯核实际上具有相当高的灵活性,也是使用最广泛的核函数之一。
- 线性核
κ(x1,x2)=⟨x1,x2⟩
,这实际上就是原始空间中的内积。这个核存在的主要目的是使得“映射后空间中的问题”和“映射前空间中的问题”两者在形式上统一起来了。
最后,总结一下:对于非线性的情况,SVM 的处理方法是选择一个核函数
κ(⋅,⋅)
,通过将数据映射到高维空间,来解决在原始空间中线性不可分的问题。由于核函数的优良品质,这样的非线性扩展在计算量上并没有比原来复杂多少,这一点是非常难得的。当然,这要归功于核方法——除了 SVM 之外,任何将计算表示为数据点的内积的方法,都可以使用核方法进行非线性扩展。
此外,略微提一下,也有不少工作试图自动构造专门针对特定数据的分布结构的核函数,感兴趣的同学可以参考,比如 NIPS 2003 的 Cluster Kernels for Semi-Supervised Learning 和 ICML 2005 的 Beyond the point cloud: from transductive to semi-supervised learning 等。
四 Outliers
在最开始讨论支持向量机的时候,我们就假定,数据是线性可分的,亦即我们可以找到一个可行的超平面将数据完全分开。后来为了处理非线性数据,使用 Kernel 方法对原来的线性 SVM 进行了推广,使得非线性的的情况也能处理。虽然通过映射
ϕ(⋅)
将原始数据映射到高维空间之后,能够线性分隔的概率大大增加,但是对于某些情况还是很难处理。例如可能并不是因为数据本身是非线性结构的,而只是因为数据有噪音。对于这种偏离正常位置很远的数据点,我们称之为 outlier ,在我们原来的 SVM 模型里,outlier 的存在有可能造成很大的影响,因为超平面本身就是只有少数几个 support vector 组成的,如果这些 support vector 里又存在 outlier 的话,其影响就很大了。例如下图:
用黑圈圈起来的那个蓝点是一个 outlier ,它偏离了自己原本所应该在的那个半空间,如果直接忽略掉它的话,原来的分隔超平面还是挺好的,但是由于这个 outlier 的出现,导致分隔超平面不得不被挤歪了,变成途中黑色虚线所示(这只是一个示意图,并没有严格计算精确坐标),同时 margin 也相应变小了。当然,更严重的情况是,如果这个 outlier 再往右上移动一些距离的话,我们将无法构造出能将数据分开的超平面来。
为了处理这种情况,SVM 允许数据点在一定程度上偏离一下超平面。例如上图中,黑色实线所对应的距离,就是该 outlier 偏离的距离,如果把它移动回来,就刚好落在原来的超平面上,而不会使得超平面发生变形了。具体来说,原来的约束条件
现在变成
其中
ξi≥0
称为松弛变量 (slack variable) ,对应数据点
xi
允许偏离的 functional margin 的量。当然,如果我们运行
ξi
任意大的话,那任意的超平面都是符合条件的了。所以,我们在原来的目标函数后面加上一项,使得这些
ξi
的总和也要最小:
其中
C
是一个参数,用于控制目标函数中两项(“寻找 margin 最大的超平面”和“保证数据点偏差量最小”)之间的权重。注意,其中
ξ
是需要优化的变量(之一),而
C
是一个事先确定好的常量。完整地写出来是这个样子:
mins.t.,12∥w∥2+C∑i=1nξiyi(wTxi+b)≥1−ξi,i=1,…,nξi≥0,i=1,…,n
用之前的方法将限制加入到目标函数中,得到如下问题:
L(w,b,ξ,α,r)=12∥w∥2+C∑i=1nξi–∑i=1nαi(yi(wTxi+b)−1+ξi)–∑i=1nriξi
分析方法和前面一样,转换为另一个问题之后,我们先让
L
针对
w
、
b
和
ξ
最小化:
∂L∂w=0∂L∂b=0∂L∂ξi=0⇒w=∑i=1nαiyixi⇒∑i=1nαiyi=0⇒C−αi−ri=0,i=1,…,n
将
w
带回
L
并化简,得到和原来一样的目标函数:
maxα∑i=1nαi–12∑i,j=1nαiαjyiyj⟨xi,xj⟩
不过,由于我们得到
C−αi−ri=0
,而又有
ri≥0
(作为 Lagrange multiplier 的条件),因此有
αi≤C
,所以整个 dual 问题现在写作:
maxαs.t.,∑i=1nαi–12∑i,j=1nαiαjyiyj⟨xi,xj⟩0≤αi≤C,i=1,…,n∑i=1nαiyi=0
和之前的结果对比一下,可以看到唯一的区别就是现在 dual variable
α
多了一个上限
C
。而 Kernel 化的非线性形式也是一样的,只要把
⟨xi,xj⟩
换成
κ(xi,xj)
即可。这样一来,一个完整的,可以处理线性和非线性并能容忍噪音和 outliers 的支持向量机才终于介绍完毕了。
五 Numerical Optimization
我在这里打算简单地介绍一下用于优化 dual 问题的 Sequential Minimal Optimization (SMO) 方法。确确实实只是简单介绍一下,原因主要有两个:第一这类优化算法,特别是牵涉到实现细节的时候,干巴巴地讲算法不太好玩,有时候讲出来每个人实现得结果还不一样,提一下方法,再结合实际的实现代码的话,应该会更加明了,而且也能看出理论和实践之间的差别;另外(其实这个是主要原因)我自己对这一块也确实不太懂。
先回忆一下我们之前得出的要求解的 dual 问题:
maxαs.t.,∑i=1nαi–12∑i,j=1nαiαjyiyjκ(xi,xj)0≤αi≤C,i=1,…,n∑i=1nαiyi=0
对于变量
α
来说,这是一个 quadratic 函数。通常对于优化问题,我们没有办法的时候就会想到最笨的办法——Gradient Descent ,也就是梯度下降。注意我们这里的问题是要求最大值,只要在前面加上一个负号就可以转化为求最小值,所以 Gradient Descent 和 Gradient Ascend 并没有什么本质的区别,其基本思想直观上来说就是:梯度是函数值增幅最大的方向,因此只要沿着梯度的反方向走,就能使得函数值减小得越大,从而期望迅速达到最小值。当然普通的 Gradient Descent 并不能保证达到最小值,因为很有可能陷入一个局部极小值。不过对于 quadratic 问题,极值只有一个,所以是没有局部极值的问题。
另外还有一种叫做 Coordinate Descend 的变种,它每次只选择一个维度,例如
α=(α1,…,αn)
,它每次选取
αi
为变量,而将
α1,…,αi−1,αi+1,…,αn
都看成是常量,从而原始的问题在这一步变成一个一元函数,然后针对这个一元函数求最小值,如此反复轮换不同的维度进行迭代。Coordinate Descend 的主要用处在于那些原本很复杂,但是如果只限制在一维的情况下则变得很简单甚至可以直接求极值的情况,例如我们这里的问题,暂且不管约束条件,如果只看目标函数的话,当
α
只有一个分量是变量的时候,这就是一个普通的一元二次函数的极值问题,初中生也会做,带入公式即可。
然而这里还有一个问题就是约束条件的存在,其实如果没有约束条件的话,本身就是一个多元的 quadratic 问题,也是很好求解的。但是有了约束条件,结果让 Coordinate Descend 变得很尴尬了:比如我们假设
α1
是变量,而
α2,…,αn
是固定值的话,那么其实没有什么好优化的了,直接根据第二个约束条件
∑ni=1αiyi=0
,
α1
的值立即就可以定下来——事实上,迭代每个坐标维度,最后发现优化根本进行不下去,因为迭代了一轮之后会发现根本没有任何进展,一切都停留在初始值。
所以 Sequential Minimal Optimization (SMO) 一次选取了两个坐标维度来进行优化。例如(不失一般性),我们假设现在选取
α1
和
α2
为变量,其余为常量,则根据约束条件我们有:
∑i=1nαiyi=0⇒α2=1y2(∑i=3nαiyi−α1y1)≜y2(K−α1y1)
其中那个从 3 到 n 的作和由于都是常量,我们统一记作
K
,然后由于
y∈{−1,+1}
,所以
y2
和
1/y2
是完全一样的,所以可以拿到分子上来。将这个式子带入原来的目标函数中,可以消去
α2
,从而变成一个一元二次函数,具体展开的形式我就不写了,总之现在变成了一个非常简单的问题:带区间约束的一元二次函数极值问题——这个也是初中就学过求解方法的。唯一需要注意一点的就是这里的约束条件,一个就是
α1
本身需要满足
0≤α1≤C
,然后由于
α2
也要满足同样的约束,即:
也可以得到
α1
的一个可行区间,同
[0,C]
交集即可得到最终的可行区间。这个问题可以从图中得到一个直观的感觉。原本关于
α1
和
α2
的区间限制构成途中绿色的的方块,而另一个约束条件
y1α1+y2α2=K
实际上表示一条直线,两个集合的交集即是途中红颜色的线段,投影到
α1
轴上所对应的区间即是
α1
的取值范围,在这个区间内求二次函数的最大值即可完成 SMO 的一步迭代。
同 Coordinate Descent 一样,SMO 也会选取不同的两个 coordinate 维度进行优化,可以看出由于每一个迭代步骤实际上是一个可以直接求解的一元二次函数极值问题,所以求解非常高效。此外,SMO 也并不是依次或者随机地选取两个坐标维度,而是有一些启发式的策略来选取最优的两个坐标维度,具体的选取方法(和其他的一些细节),可以参见 John C. Platt 的那篇论文 Fast Training of Support Vector Machines Using Sequential Minimal Optimization 。关于 SMO ,我就不再多说了。如果你对研究实际的代码比较感兴趣,可以去看 LibSVM 的实现,当然,它那个也许已经不是原来版本的 SMO 了,因为本来 SVM 的优化就是一个有许多研究工作的领域,在那些主要的优化方法之上,也有各种改进的办法或者全新的算法提出来。
除了 LibSVM 之外,另外一个流行的实现 SVMlight 似乎是用了另一种优化方法,具体可以参考一下它相关的论文 Making large-Scale SVM Learning Practical 。
此外,虽然我们从 dual 问题的推导中得出了许多 SVM 的优良性质,但是 SVM 的数值优化(即使是非线性的版本)其实并不一定需要转化为 dual 问题来完成的,具体做法我并不清楚,不过这方面的文章也不少,比如 2007 年 Neural Computation 的一篇 Training a support vector machine in the primal 。如果感兴趣可以参考一下。