很多人在学支持向量机(SVM)的时候,最先被劝退的不是分类间隔,而是“拉格朗日乘子法”这几个字:明明前面还在讲怎么找一条最大间隔的直线,怎么后脚就冒出来一堆 α、对偶问题、KKT 条件,仿佛换了本书。我当年也是这样,翻了好几版讲义才把这条线串明白。其实线性可分 SVM 的推导,本质上就是解一个带不等式约束的凸优化问题,拉格朗日乘子法正是处理这类约束的标准工具,一点都不玄乎。
这篇文章我打算顺着“几何直观 → 优化建模 → 拉格朗日变换 → 对偶求解 → 手算例题”这条路径,把公式从头到尾完整推一遍,最后用一组非常干净的三点数据,带你手动算出 α、w、b。整个过程可以拿纸笔跟着走,不需要依赖任何机器学习库。学完之后你再看 SMO、核函数、软间隔,都会顺很多。适合正在学 SVM 的算法初学者、准备面试刷推导的人,以及想补数学基础的开发者。
1. 从“找最大间隔直线”说起:线性可分SVM到底在解什么问题
1.1 先有分类任务,再有超平面
假设我们有 n 个样本,每个样本有特征向量 x_i,类别标签是 y_i,并且为了后面的数学推导方便,约定二分类的标签为 +1 和 -1,而不是 0 和 1。如果存在一个超平面 w·x + b = 0 能把正负样本完全分开,我们就说这个数据集是线性可分的。这里 w 是超平面的法向量,b 是偏置项,向量点乘 w·x 是“投影”的意思。
在这个条件下,所有满足 w·x_i + b > 0 的样本可以被判定为正类,满足 w·x_i + b < 0 的样本判定为负类。但问题是:能把两类数据分开的超平面通常有无数个。例如一条向右侧偏一点的直线、向左侧偏一点的直线,都可能把训练样本完全分开。那么问题来了,这无数条线里,哪一条才是“最好”的?
SVM 给出的答案非常直观:选那条“站在正负样本正中间”的线。也就是说,这条线要离最近的正样本和最近的负样本都尽可能远。这样做的好处是,模型对噪声和轻微扰动的容忍度更高,泛化能力通常也更好。一个离样本太近的决策边界,往往换个新样本就分错了。
1.2 用数学描述“间隔”
要衡量“离得远不远”,先要定义距离。一个点 x_i 到超平面 w·x + b = 0 的距离公式是:
|w·x_i + b| / ||w||
这是中学就学过的点到直线距离公式在高维空间的推广。对于样本 x_i,我们不仅关心它到超平面的绝对值距离,还关心它是否被正确分类。如果把标签 y_i 乘进去,就得到 y_i (w·x_i + b),这个值如果正,说明分类正确,如果负,说明分类错误。它的几何含义是带方向的“函数间隔”。
训练集里所有样本的函数间隔最小值,就决定了这个超平面离数据“最近”的距离。SVM 想要的超平面,是让这个最小函数间隔尽量大。但我们马上会遇到一个问题:w 和 b 同时放大或缩小任意倍数,超平面本身不变,函数间隔 y_i(w·x_i+b) 却会跟着放大缩小,所以“函数间隔”不是一个规范的量。解决办法是除以 ||w||,也就是用几何间隔来度量:
y_i (w·x_i + b) / ||w||
这个式子表示样本 x_i 到超平面的带符号距离,缩放 w、b 不会改变它的值。SVM 的目标,就是最大化所有训练样本中最小几何间隔。
1.3 把最大化间隔写成优化问题
因为训练集线性可分,我们可以通过尺度调整,让距离超平面最近的样本满足:
y_i (w·x_i + b) = 1
这个“1”不是凭空规定的。任何超平面都可以通过等比例缩放 w 和 b,使最近样本的函数间隔恰好为 1。做完这个归一化之后,所有样本的约束就统一成:
y_i (w·x_i + b) ≥ 1
此时几何间隔就变成了 1 / ||w||。最大化最小几何间隔,等价于最大化 1/||w||,再等价于最小化 ||w||。为了后面求导方便,通常写成:
min 1/2 ||w||²
subject to y_i (w·x_i + b) ≥ 1,对所有 i。
这就是线性可分 SVM 的原始优化问题。这里最小化 ||w||² 而不是 ||w||,是因为平方后函数光滑、便于求导,并且最优解不变。为什么要 1/2?纯粹是求导后消掉系数,让公式干净。
2. 拉格朗日乘子法速成:从等式约束到不等式约束
2.1 等式约束下的拉格朗日乘子法复习
先说最经典的等式约束问题。比如:
min x + y subject to x² + y² = 1
这是一个在单位圆上找 x+y 最小值的几何问题。没有约束时,x+y 没有下界;加了约束后,x 和 y 被限制在一个圆上。怎么解?拉格朗日乘子法的思路是:把这个带约束问题转成一个无约束问题。定义拉格朗日函数:
L(x, y, λ) = x + y + λ(x² + y² - 1)
然后对所有变量分别求偏导并令其为 0。为什么可以这样做?因为在极值点上,目标函数的梯度方向必须与约束曲面的法向量方向平行,拉格朗日乘子 λ 就用来表示这两个梯度之间的大小关系。用一句直观的话说:如果不平行,只要沿约束曲面稍微走一步,目标函数还能继续下降,所以不可能达到极值。
这种手法本身不复杂,但 SVM 稍微复杂了一点,因为它的约束是不等式,不是等式。
2.2 不等式约束与KKT条件
处理不等式约束,需要引入 KKT 条件。所谓 KKT 条件,简单理解就是拉格朗日乘子法在不等式约束下的扩展版。考虑一个形式化的问题:
min f(w) subject to g_i(w) ≤ 0,i = 1, ..., m
为了方便,先把不等式整理成小于等于 0 的形式。定义拉格朗日函数:
L(w, α) = f(w) + Σ_i α_i g_i(w)
其中 α_i ≥ 0。极值点除了需要满足梯度为 0、原始约束 g_i(w) ≤ 0 以外,还必须满足一个核心条件:
α_i · g_i(w) = 0
这个条件叫互补松弛条件。它的意思是:如果第 i 个约束没有被激活,也就是 g_i(w) < 0,那么 α_i 必须等于 0;如果 α_i > 0,那么对应的约束必须取到等号 g_i(w) = 0。
可以用一个生活化类比来理解:不等式约束就像一面围栏,物体在没有抵到围栏时,围栏对物体没有作用力;只有当物体刚好压到围栏上时,才会产生一个支撑力。这里的“支撑力”就是 α_i,“围栏”就是约束边界。SVM 中那些真正落在最大间隔边界上的样本点,就是“压到围栏”的点,它们对应的 α_i 会大于 0;其他离边界远的点,对应 α_i 等于 0。这个性质是整个支持向量机名字的来源。
需要说明的是,KKT 条件在普通非凸问题里只是必要条件,但在 SVM 的线性可分场景下,目标函数是凸二次函数,约束是线性不等式,满足强对偶条件,所以 KKT 条件既是必要条件也是充分条件。这给了我们后续通过对偶问题求解的底气。
2.3 把SVM原始问题改写成拉格朗日函数
现在把 SVM 原始问题套进这个框架。我们的约束是:
y_i (w·x_i + b) ≥ 1
为了变成小于等于 0 的标准形式,写成:
1 - y_i (w·x_i + b) ≤ 0
对应每个样本引入一个拉格朗日乘子 α_i ≥ 0,构造拉格朗日函数:
L(w, b, α) = 1/2 ||w||² + Σ_i α_i [1 - y_i (w·x_i + b)]
也有的教材写成减号形式,本质上一种写法。我个人习惯用这个加号形式,因为约束条件的符号和 α 的正负号不会混淆。接下来就要用这个 L 函数做文章。
注意,在拉格朗日函数里,我们并不是直接求 L 的极小值就结束了,而是要构造“原始问题”和“对偶问题”的博弈关系。原始问题是先对 α 求最大、再对 w 和 b 求最小;对偶问题则是反过来,先对 w 和 b 求最小、再对 α 求最大。在凸问题里,这两个问题的解相等,这就是强对偶性。实际计算中,对偶问题往往更好解,所以我们走对偶路线。
3. 线性可分SVM推导:三步拿到对偶问题
3.1 对 w 和 b 求偏导,得到关键等式
求解对偶问题的第一步,是固定 α,先让 L 关于 w 和 b 取得最小值。因为 L 是关于 w 和 b 的凸函数,直接求偏导并令其为 0,就能得到最优条件。
先对 w 求偏导:
∂L / ∂w = w - Σ_i α_i y_i x_i = 0
所以:
w = Σ_i α_i y_i x_i
这个式子非常重要。它说明最优超平面的法向量 w,可以表示成所有样本点的线性组合,组合系数是 α_i y_i。也就是说,最终的超平面完全由样本点决定,而不是凭空冒出来的。
再对 b 求偏导:
∂L / ∂b = -Σ_i α_i y_i = 0
于是得到:
Σ_i α_i y_i = 0
注意,这里没有直接解出 b 的表达式,而是得到了一个关于 α 的线性约束。b 的求解要留到后面通过 KKT 条件处理。
3.2 消去 w 和 b,得到对偶函数
得到了 w 关于 α 的表达式之后,把它代回拉格朗日函数,就能消掉原始变量 w 和 b。
我们把 L(w, b, α) 一项一项展开。先看二次项:
1/2 ||w||² = 1/2 (Σ_i α_i y_i x_i) · (Σ_j α_j y_j x_j) = 1/2 Σ_i Σ_j α_i α_j y_i y_j (x_i · x_j)
再看约束项里的第一部分:
Σ_i α_i y_i (w·x_i) = Σ_i Σ_j α_i α_j y_i y_j (x_i · x_j)
约束项里还有一部分是 Σ_i α_i y_i b,但这一项等于 b · Σ_i α_i y_i = b · 0 = 0,所以在代回时直接消失。
把这几项合在一起:
L = 1/2 ΣΣ α_i α_j y_i y_j (x_i·x_j) - ΣΣ α_i α_j y_i y_j (x_i·x_j) + Σ_i α_i = Σ_i α_i - 1/2 Σ_i Σ_j α_i α_j y_i y_j (x_i·x_j)
于是对偶问题变成:
max_α W(α) = Σ_i α_i - 1/2 Σ_i Σ_j α_i α_j y_i y_j (x_i · x_j) subject to α_i ≥ 0,且 Σ_i α_i y_i = 0
注意,原来的最小值问题,现在变成了一个只关于 α 的最大值问题。这个转变就是“拉格朗日对偶”。很多人推导到这里容易懵,但只要跟着算一遍,会发现每一步都是代入消元,没有跳跃。
3.3 KKT互补松弛条件与b的求解
光靠对偶问题,我们已经能求出 α,但还要找回 b。这里必须用 KKT 互补松弛条件:
α_i [y_i (w·x_i + b) - 1] = 0
这个条件告诉我们:要么 α_i = 0,样本点落在间隔边界之外,对模型没有贡献;要么 y_i(w·x_i+b)=1,样本点刚好落在最大间隔的边界上,这种点就是支持向量。
对于任意一个支持向量 x_s,因为满足 y_s(w·x_s + b) = 1,所以可以直接解得:
b = y_s - w·x_s
注意,这里看到 y_s 直接出现在公式里,不需要再除以 y_s,因为对支持向量来说 y_s 是 ±1,两边乘一个 y_s 后等式就变成 w·x_s + b = y_s。
实际计算时,为了避免浮点数误差导致选到略微偏离边界的样本,通常把所有支持向量分别算出的 b 取平均值,这样更稳定。
3.4 决策函数与支持向量的本质
有了 w 和 b,决策函数就是:
f(x) = sign(w·x + b)
把 w = Σ α_i y_i x_i 代进去,决策函数变成:
f(x) = sign(Σ_i α_i y_i (x_i · x) + b)
这里出现了一个非常关键的现象:预测时我们只需要计算新样本 x 与训练样本 x_i 的内积,而大量 α_i = 0 的样本根本不需要参与计算。只有支持向量的 α_i 非零,换句话说,支持向量机的模型参数虽然看起来长,但真正“撑住”超平面的只有一小部分样本,这个性质叫稀疏性。这也是为什么这类模型被称为“支持向量机”:决定边界的不是所有样本,而是那些“顶”在间隔边界上的支持向量。
同时,“只需要内积”这个性质也为后来的核技巧埋下了伏笔:如果数据在当前空间线性不可分,可以把它映射到更高维空间,只要内积能算,整个推导依然成立。不过这是后话,线性可分的推导是理解一切的基础。
4. 一个可以手算的例题:三个点的线性可分SVM
4.1 数据与优化目标
为了把前面的公式落到纸面上,我选一个故意设计得很简单的数据集。正类有两个点:
A = (1, 2) B = (2, 1)
负类有一个点:
C = (0, 0)
这三个点有一个很漂亮的对称性:A 和 B 都在直线 x + y = 3 上,C 在原点。从几何上看,最佳分界线大概率是一条与 x + y 方向垂直的线,也就是法向量方向为 (1, 1)。我们不用猜,直接用对偶问题算。
先把原始优化问题写出来。我们的目标是:
min 1/2 (w1² + w2²) subject to: y_A (w·A + b) ≥ 1 y_B (w·B + b) ≥ 1 y_C (w·C + b) ≥ 1
其中 y_A = y_B = 1,y_C = -1。三个变量是 w1、w2、b。
4.2 构造对偶问题
根据第三节的推导,对偶问题是极大化 W(α),其中 α1、α2 对应正类点 A、B,α3 对应负类点 C。约束是:
α1, α2, α3 ≥ 0 α1·1 + α2·1 + α3·(-1) = 0
也就是:
α3 = α1 + α2
接着计算样本之间的内积。A、B、C 三个点的内积矩阵是:
A·A = 1²+2² = 5 B·B = 2²+1² = 5 A·B = B·A = 1×2 + 2×1 = 4 A·C = B·C = C·C = 0
因为 C 是原点,所以凡是和 C 相关的内积项全部为 0。这对手算非常友好。
把内积代入对偶目标函数:
W(α) = α1 + α2 + α3 - 1/2 [ 5α1² + 8α1α2 + 5α2² ]
为什么没有 α3 的二次项?因为 C 和自己的内积是 0,和 A、B 的内积也是 0,所以 α3 只会以一次项出现,不会出现在二次项中。后面我们会看到,这个“巧合”让手算变得极其简单。
4.3 求解α
把 α3 = α1 + α2 代入目标函数:
W = 2α1 + 2α2 - 1/2 (5α1² + 8α1α2 + 5α2²)
整理一下:
W = 2α1 + 2α2 - 2.5α1² - 4α1α2 - 2.5α2²
现在问题变成了在 α1 ≥ 0、α2 ≥ 0 条件下最大化这个二元函数。既然没有其他不等式约束,直接对 α1 和 α2 求偏导并令其等于 0:
∂W/∂α1 = 2 - 5α1 - 4α2 = 0 ∂W/∂α2 = 2 - 4α1 - 5α2 = 0
两个方程长得非常对称,相减得到 α1 = α2,再代回任意一个方程:
2 - 9α1 = 0
所以:
α1 = α2 = 2/9 α3 = α1 + α2 = 4/9
三个 α 都大于 0,说明三个点全部会成为支持向量。这个结果也符合直觉:A、B、C 确实是恰好撑住最大间隔边界的三个点。
4.4 恢复 w 和 b
利用 w = Σ α_i y_i x_i:
w = (2/9) × 1 × (1, 2) + (2/9) × 1 × (2, 1) + (4/9) × (-1) × (0, 0) = (2/9 + 4/9, 4/9 + 2/9) = (6/9, 6/9) = (2/3, 2/3)
和我们一开始的猜测一致,w 的方向确实是 (1, 1) 方向。
接着用支持向量 A 求解 b。因为 A 在间隔边界上,满足 w·A + b = 1,所以:
b = 1 - w·A = 1 - (2/3 × 1 + 2/3 × 2) = 1 - 2 = -1
再用 C 验证一下。C 是负类,满足 w·C + b = -1,代入:
0 + (-1) = -1
完全一致。
于是最终的决策超平面是:
(2/3)x1 + (2/3)x2 - 1 = 0
化简一下,就是:
x1 + x2 = 1.5
两个分类间隔边界分别是正类一侧的 x1 + x2 = 3 和负类一侧的 x1 + x2 = 0。A、B 正好都落在正类边界上,C 落在负类边界上,几何间隔大小为 3 / (2√2),最大间隔为 2/||w|| = 3/√2。
4.5 验证KKT条件,看看每个样本的贡献
我们最后验证一下互补松弛条件。对 A 来说,α1 = 2/9 > 0,并且函数间隔:
y_A(w·A + b) = 1 × (2 - 1) = 1
刚好取等号,条件成立。B 同样算出来是 1,C 算出来也是 1。三个点都牢牢压在间隔边界上,所以它们的 α 都大于 0。
反过来,如果我们往数据集里加入一个离边界更远的正类点 D = (3, 3),它的函数间隔会是 4 或者更大,远大于 1,那么根据互补松弛条件,它对偶变量 α_D 必须等于 0。也就是说,这个远点不会进入 w 的表达式,决策边界不会因为它的加入而改变。理解这一点,才算真正理解“支持向量”这四个字的含义:真正决定模型的,只有那些贴在边界上的点。
5. 推导和实现中容易踩的坑
5.1 拉格朗日函数符号写反
这是初学者最常见的问题。同样是约束 y_i(w·x_i + b) ≥ 1,可以写成 1 - y_i(w·x_i+b) ≤ 0,也可以写成 y_i(w·x_i+b) - 1 ≥ 0,不同的写法会直接影响拉格朗日乘子的符号和 KKT 条件的形式。如果在某本教材里看到 α 符号和你习惯的不一样,不要慌,只要保持同一套符号体系从头到尾自洽,结果是一样的。我个人的经验是:写成“1 - y_i(w·x_i+b) ≤ 0”这种形式,配合 α≥0,最容易记住,也最不容易出符号错误。
5.2 b 为什么不能直接求出来
有些朋友在推导到对 b 求偏导那一步时,会发现求导结果里根本没有 b 的表达式,只有 Σα_i y_i = 0,于是疑惑 b 去哪了。原因是 b 在目标函数里没有正则项,它只通过约束条件起作用,所以无法从一阶条件中直接确定。b 必须依赖 KKT 的互补松弛条件,从支持向量样本上反解。实操中还有一个细节:如果支持向量不止一个,建议用所有支持向量算出的 b 取平均,因为浮点误差会让个别点看起来没有严格满足等式,取平均能减小误差。
5.3 对偶问题不能无脑用梯度上升
对偶问题是二次规划问题,直接对 W(α) 做梯度上升会遇到两个麻烦:一是要保证 α_i ≥ 0 和 Σα_i y_i = 0 两个约束始终成立;二是样本多时内积矩阵规模很大。实际工程中很少直接手写二次规划求解,而是使用 SMO 这类专用算法。SMO 的主要思想是每次只更新两个 α_i,因为受等式约束限制,至少两个变量才能在更新时保持 Σα_i y_i = 0 不破坏。这个思路在理解了本节的对偶推导之后,会显得非常自然。
5.4 线性可分是起点,不是终点
看到这里,你可能会想:现实中哪有这么干净的线性可分数据?确实,真实数据里绝大多数情况是线性不可分的,或者虽然是线性可分但存在噪声。线性可分 SVM 的意义在于,它是整个 SVM 家族的地基。后续的软间隔 SVM,只是把硬约束 y_i(w·x_i+b)≥1 换成加了松弛变量的形式;核 SVM,只是把样本点之间的内积 x_i·x_j 换成核函数 K(x_i, x_j)。如果你把本文的推导过程亲手写过一遍,再去看软间隔和核方法,会发现只是多了一两个变量和一张“内积替换表”,思路完全一样。
就我个人经验来说,这个三点例题虽然小,但当年我花了一个下午,把拉格朗日函数展开、求偏导、代回、解二次规划,一步步算到最终结果后,整个人对 SVM 的理解是质变的。那种“原来 α 和间隔边界真的是严格对应的”的感觉,只靠看书是得不到的。所以我建议你拿起纸笔,把第 4 节的例题完整走一遍。算完之后再看 SMO、核函数、软间隔,你的思路会清晰非常多。