向量机基本原理#
以下推导部分参考自该视频
支持向量的本质#
我们首先来思考这么一个问题,如上图所示,如果要求你画一条直线,使其能够将图中的两类点分开,并且在加入新的点后也尽可能实现这个目的(具有预测能力),你会如何画这个条直线呢?直觉上来讲,这条直线靠近任何一类点都不太可行。因此我们认为,这条直线到任何一个点都足够远时,直线的分类效果最好。

为了实现我们上述的初步猜想,我们要先引入一个概念: 间隔(Margin)。间隔的作用是将两类数据所处的空间分隔开来,并且间隔越大,两类数据的差异也就越大。因此,要想区分两类数据,我们就得找到两类数据的最大间隔,然后我们再以间隔的正中间作为决策边界,就可以实现我们的猜想。

我们将已经找到的超平面上下移动 C 个单位,使其恰好经过某些数据点,我们称这两条直线为间隔上下边界。由于间隔上下边界必然会经过几个数据点,而这几个数据点也是起到了限制间隔上下边界的作用,因此我们称这几个点为 支持向量(Support Vector)。这便是 支持向量机(Support Vector Machine,简称 SVM)名称的由来。

归一化技巧#
对于直线方程来说,如果我们对其两边同时除以一个数,我们就可以得到一个新的方程。因此空间上的 一条直线 拥有 无数 个直线方程,这对我们的计算会产生影响。因此我们规定:决策上下边界的右值必须为 ±1 。

这样我们就得到了三个平面:正超平面(Positive Hyperplane)、负超平面(Negative Hyperplane)和决策超平面(Decision Hyperplane)。
软间隔技巧#
我们再进一步思考这样一个问题:如果两类数据的间隔中出现了一个异常点,那么我们计算所得的的间隔就会缩小,但我们是否要为了这个异常点而牺牲我们的间隔呢?

答案是否定的。但我们要如何判断什么样的点是异常点呢?或者说,我们可以让算法自己判断是否要忽略某个数据点吗?对此,我们引入了 损失因子 这个概念。你可以将原本的间隔视为经营的 收入 ,而将损失看作经营的 成本 ,那么我们最初的问题则可以转化为最大化 利润 。此时的间隔我们称之为 软间隔(Soft Margin)。
向量机数学建模#
基本思想已经讲解清楚了,接下来我们就将我们的猜想转换为数学模型,也就是建模(由于篇幅的限制,我们将重点介绍硬间隔支持向量机,软间隔向量机将放到代码实现中的内容拓展中讲解)。
以下推导部分参考自该视频
首先我们分别在正负超平面上任意选取一个支持向量点 xm 和 xn 。由于它们分别在正负超平面上,所以它们一定满足下列等式:
w1x1m+w2x2m+b=1w1x1n+w2x2n+b=−1我们将上述的两个等式相减后又可以得到下面这个式子:
w1(x1m−x1n)+w2(x2m−x2n)=2上面这个式子又相当于下面这个式子:
w⋅(xm−xn)=2
我们再从决策超平面上随机选取两个点 xo 和 xp ,同理我们可以得到下面这个式子:
w⋅(xo−xp)=0由此我们可以得知:w 与决策超平面垂直。

回到上面的推导过程,我们将上面的点积式子用模长表示:
∥xm−xn∥∗cosθ∗∥w∥=2由于 w 与决策超平面垂直,从几何含义可以得到:
∥xm−xn∥∗cosθ=L其中 L 为间隔宽度。
结合上面的两个式子,我们便可以得到间隔宽度 L 的表达式:
L=∥w∥2
我们再来看看约束条件。所有的绿点都属于正类,对应的分类值 yi=1 ,又因为它们处于正超平面的 上方,因此满足 w⋅xi+b≥1 ;同理,对于所有的黄点来说,它们对应的分类值 yi=−1 ,满足 w⋅xi+b≤−1 。
综上可知,这些数据点均满足下面这个不等式:
yi∗(w⋅xi+b)≥1
从上面的式子我们可以知道,最大化间隔其实就是最小化 w 的模长,形式地来讲:
min∥w∥2s.t.yi∗(w⋅xi+b)≥1∀i=1,2,…,N到此,我们成功地将我们的猜想转换成一个带约束的最优化问题。
向量机深层理解#
看到上面的最优化问题后,许多人的第一反应应该是使用 拉格朗日乘数法 来解决,这在一般情况下的确如此。但对于支持向量机来说,为了后续求解的效率,我们往往会将上述最优化问题转化为它的 拉格朗日对偶问题 来求解。但我们暂且按下不表,让我们顺着拉格朗日乘数法的思路往下推导,顺便深度了解一下支持向量的含义。
为了后续推导的方便,我们可以将上述的最优化问题做个小变形:
minf(w)=2∥w∥22s.t.gi(w,b)=yi∗(w⋅xi+b)−1≥0∀i=1,2,…,N显然转换之后不影响最小值的求解。
对于约束条件是不等式的情况,我们需要引入一个非负变量来将不等式转化为等式(我们这里之所以要将不等式转化为等式进行处理是为了从零开始推导不等式约束的拉格朗日系数必须非负这个条件,后续使用拉格朗日乘数法时不再使用,可以直接将不等式写入拉格朗日函数):
s.t.gi(w,b)=yi∗(w⋅xi+b)−1=pi2∀i=1,2,…,N由此我们可以得到下面这个拉格朗日方程式:
L(w,b,λi,pi)=2∥w∥2−i=1∑Nλi[yi(w⋅xi+b)−1−pi2]将拉格朗日函数对 w 、b 、λi 和 pi 分别求导可得:
∂w∂L=w−i=1∑Nλiyixi=0∂b∂L=−i=1∑Nλiyi=0∂pi∂L=2λipi=0∂λi∂L=−(yi(w⋅xi+b)−1−pi2)=0联立下面两个等式可以得到:
λi(yi(w⋅xi+b)−1)=0根据条件 yi∗(w⋅xi+b)−1≥0 ,所以我们可以知道:
⎩⎨⎧yi(w⋅xi+b)−1>0,yi(w⋅xi+b)−1=0,λi=0λi=0如果我们将 λi 看成惩罚因子,那么上面的两种情况可以解释成:当数据点不在正负超平面上时,该数据点不对整体产生贡献;当数据点在正负超平面时,该数据点会对整体产生贡献。这便是支持向量的深层含义:只有 落在正负超平面上 的数据点才会对拉格朗日函数 造成约束 。这也符合我们在几何空间上的直观理解。
并且我们还能得出拉格朗日的约束系数必须满足 λi≥0 ,因为当数据点不满足约束条件时必然有:
yi∗(w⋅xi+b)−1<0如果再加上 λi<0 则必然会有拉格朗日约束项小于零,这相当于变相鼓励支持向量机去违反约束条件,显然这种情况是不被允许的。

拉格朗日对偶问题#
接下来的内容将是本篇博客的重点内容,也是支持向量机的核心难点内容。让我们一起来看一下什么是拉格朗日对偶问题。
以下推导部分参考下面两个视频
拉格朗日乘数法#
要想理解什么是拉格朗日对偶问题,那就不得不先了解什么是拉格朗日乘数法。不知道读者在第一次接触拉格朗日乘数法的时候是否会感到好奇,为什么这样一顿操作之后就能求解出带约束下函数的极值呢?不如用优美的几何图像与严谨的数学语言来理解一遍吧。
让我们来看一下这样一个简单的带约束优化问题:
求 f(x,y) 的最小值, 并且 y≤g(x)L(x,y)=f(x,y)+λ(y−g(x))⇓∇L(x,y)=0⇓⎩⎨⎧∂x∂f(x,y)+λ∂x∂(y−g(x))=0∂y∂f(x,y)+λ∂y∂(y−g(x))=0如图所示(图中的数学符号不太契合我们现在探讨的问题,因此只需要关注图像即可),圆环套圆环表示类似于旋转抛物面的 f(x,y) 的函数图像,直线则表示 z=y−g(x)≤0 的边界线(可以想象是一个柱面投影在 xOy 平面的图像)。
观察图像易得,当圆环与直线相切时,这个切点便是带约束下函数的极值点。并且此时两个函数的梯度 恰好共线 ,如果再调节 λ 的值则有可能使其 正负相互抵消 ,因此将拉格朗日函数写成上面的形式(将原函数与约束线性组合)后再求导便可以得到带约束条件下函数的极值点。

我们再来看看在多个约束下的几何图像是什么样的。如图所示,我们再添加一个约束,此时两个约束的相交点为最优解,两个约束的梯度向量的线性组合可能会与函数的梯度向量共线且相等,对拉格朗日函数求导仍然可以得到带约束条件下函数的极值点。

如果我们再加入一个约束,如图所示,这个新加入的约束并不会改变先前所有约束条件的交集的形状,因此它的加入并不会对答案造成影响。

这其实是 KKT 条件(关于什么是 KKT 条件我会在下文介绍)中 互补松弛条件(Complementary Slackness Condition) 的几何解释。如果一个条件对答案有影响,那么它对应的 λi 必然大于零,我们则称其为 紧致条件;如果一个条件对答案没有影响,那么它对应的 λi 必然等于零,我们则称其为 松弛条件(因为 λ<0 会导致约束条件的梯度向量与函数的梯度向量同向而无法相互抵消,因此不可能出现)。由此我们又可以从 互补松弛的角度 再次了解什么是支持向量:支持向量是 支持向量机最优化问题中的紧致条件 。
凸问题与凸优化#
拉格朗日乘数法非常强大,但它的缺点也非常明显:只能求解极值点/鞍点。拉格朗日乘数法并不能保证求解出的结果一定是最值点(但一定包含最值点),但如果我们要求解的问题是一个 凸问题(Convex Problem),那么这个问题中的极值点就是最值点(凸问题的性质)。
而我们的拉格朗日对偶问题有个非常美妙的结论:原问题的拉格朗日对偶问题 一定是凸问题 。
接下来我们就仔细地讲解一下拉格朗日对偶问题的推导过程,首先需要将拉格朗日问题稍微改写一下:
mins.t.f0(x),x∈Rnfi(x)≤0,i=1,2,…,mhi(x)=0,i=1,2,…,q⇓L(x,λ,ν)=f0(x)+i=1∑mλifi(x)+i=1∑qνihi(x)原问题:xminλ,νmaxL(x,λ,ν)s.t.λ≥0当 x 不在可行域内时有: fi(x)>0 和 hi(x)=0 。若想最大化 L(x,λ,ν) ,我们可以让 λi 取到正无穷,让 νihi(x) 取到正无穷:
λ,νmaxL(x,λ,ν)=f0(x)+∞+∞=∞当 x 在可行域内时有: fi(x)≤0 和 hi(x)=0 。若想最大化 L(x,λ,ν) ,我们可以让 λi 取到 0(因为 hi(x)=0 ,所以 νi 取任意值均可):
λ,νmaxL(x,λ,ν)=f0(x)+0+0=f0(x)然后在此基础上再取 min 可以得到:
xminλ,νmaxL(x,λ,ν)=xmin{f0(x),∞}=xminf0(x)因此拉格朗日问题的两种形式是等价的。
接下来我们看看拉格朗日对偶问题的数学形式:
对偶函数:对偶问题:g(λ,ν)=xminL(x,λ,ν)λ,νmaxg(λ,ν)=λ,νmaxxminL(x,λ,ν)s.t. λ≥0很明显,原问题就是先求 max 再求 min 的过程,对偶问题就是先求 min 再求 max 的过程。
我们来看看凸问题的定义:当一个问题的 约束条件是凸集 且 问题函数为凸函数 时,该问题被称为凸问题。观察对偶函数 L(x,λ,ν) ,如果先对参数 x 做最小值优化,则在做最大值优化的时候, f0(x∗) 、 fi(x∗) 和 hi(x∗) 都是常数,也就是说:此时的对偶函数 g(λ,ν) 是一个 线性函数 ,而线性函数是一个 凸函数 。再加上对偶问题的约束条件是 λ≥0 ,这是一个 半空间 ,而半空间是一个 凸集 。综上所述,对偶问题是一个 凸问题 。
g(λ,ν)=f0(x∗)+i=1∑mλifi(x∗)+i=1∑qνihi(x∗)弱对偶与强对偶#
到此为止,我们已经知道了什么是拉格朗日对偶问题,也弄懂为什么拉格朗日对偶问题一定是一个凸问题。但我们要想用拉格朗日对偶问题来解决原问题,就必须证明两个问题得到的解之间是相关的,否则对偶问题有再多优美的性质,也无法帮我们去解决原问题。所以接下来,就让我们来看一下拉格朗日问题与其对偶问题之间的关系吧。
首先我们可以轻松地证明出:拉格朗日问题的解大于等于其对偶问题的解。下面是证明过程:
λ,νmaxL(x,λ,ν)≥L(x,λ,ν)≥xminL(x,λ,ν)A(x)=λ,νmaxL(x,λ,ν)≥L(x,λ,ν)≥xminL(x,λ,ν)=I(λ,ν)A(x)≥I(λ,ν)(∀x,λ,ν)A(x)≥xminA(x)≥λ,νmaxI(λ,ν)≥I(λ,ν)P∗=xminA(x)≥λ,νmaxI(λ,ν)=D∗而上述这个性质我们称之为 弱对偶性(Weak Duality Theorem)。也就是说:拉格朗日对偶问题与原问题 一定满足弱对偶性 。那么拉格朗日对偶问题在什么条件下与原问题之间满足 强对偶性(Strong Duality Theorem) 呢?当原问题是 凸问题 且满足一定的 正则条件(Slater 条件就是其中之一) 时,原问题与其对偶问题满足强对偶性。
具体证明省略,需要的读者可以观看下面这个 PDF
对偶理论(Duality)
但另一个问题也随之而来:既然原问题已经是凸问题,为什么仍要引出对偶问题这个概念呢?原因就是原问题虽然也是凸问题,但原问题本身往往非常复杂,求解起来十分困难,而对偶问题将繁杂的约束条件融入到拉格朗日函数中,求解起来十分简单,因此我们会更倾向于将原问题转化成它的对偶问题来进行求解(即便原问题不是凸问题我们也会尝试将其转化成对偶问题来求解)。
KKT 强队偶条件#
原理部分讲到这里其实已经足够了,但在先前讲解拉格朗日乘数法时所提到的 KKT 条件并不完整,因此在这里给出详细的 KKT 条件:
⎩⎨⎧∇f(x∗)+∑i=1mλi∇gi(x∗)+∑j=1pνj∇hj(x∗)=0gi(x∗)≤0,i=1,…,mhj(x∗)=0,j=1,…,pλi≥0,i=1,…m,λigi(x∗)=0,i=1,…,m(Stationarity)(Primal feasibility)(Equality constraints)(Dual feasibility)(Complementary slackness)KKT 条件的作用就是能让我们快速判断一个问题是否是强对偶问题:在绝大多数条件下(少数情况几乎都是人为构造,实际应用相当罕见),只要满足 KKT 条件的问题就是强队偶问题。
向量机代码实现#
根据拉格朗日对偶问题的原理,我们来推导一下支持向量机问题的对偶问题。
# 假设 X: (n_samples, n_features), y: (n_samples,) 且值为 +1/-1
def linear_svm_train(X, y, lr=0.001, epochs=1000):
n_samples, n_features = X.shape
alpha = np.zeros(n_samples)
for i in range(n_samples):
grad = 1 - np.sum(alpha * y * y[i] * np.dot(X, X[i]))
alpha[i] = max(alpha[i], 0) # 保证 α_i >= 0
w = np.sum((alpha * y)[:, None] * X, axis=0)
sv_idx = np.where(alpha > 1e-5)[0][0]
b = y[sv_idx] - np.dot(w, X[sv_idx])
def linear_svm_predict(X, w, b):
return np.sign(np.dot(X, w) + b)
引入拉格朗日乘子 αi 并写出拉格朗日函数:
L(w,b,α)=2∥w∥2−i=1∑Nαi[yi(w⋅xi+b)−1]将其对 w 和 b 求偏导:
∂w∂L=w−i=1∑sαiyixi∂b∂L=−i=1∑sαiyi令偏导为零并带入拉格朗日函数可得到支持向量机问题的对偶问题:
αmaxs.t.i=1∑nαi−21i=1∑nj=1∑nαiαjyiyjxi⋅xjαi≥0,i=1∑nαiyi=0接下来我们只需要用梯度上升(这里是求 max)的方式求解出参数 α 即可。
内容拓展#
支持向量机其实还有很多可以优化的点。
-
首先就是上面的梯度上升算法:对于支持向量机来说,直接使用梯度上升算法是不太行的,由于对偶问题有 等式约束 ,直接梯度很难保持约束。不仅如此,计算梯度还会遇到开销大、收敛慢等问题。因此我们往往会使用 SMO 算法 来替代梯度上升算法(SMO 算法的具体内容可以看下面的博客)。
详细推导序列最小优化SMO算法
-
然后就是对于线性不可分的数据:我们在前面这么长的推导过程其实都有一个前提假设 ———— 数据是线性可分的。但是在大多数情况下,数据往往是线性不可分的,那我们就得要引出我们的 核技巧(Kernel Trick) 了。核技巧的原理非常简单,就是想办法将数据升维后,再进行支持向量机的构建,因为 维度越高数据越有可能线性可分 (具体讲解可以看下面这个视频,限于篇幅原因不过多讲解)。
-
最后就是软间隔问题:在上文我们讲到过什么是软间隔,但我们没有过多解释软间隔的数学原理,如果读者感兴趣可以观看下面的视频。