第十部分 · 把它们拼成学习器
支持向量机:几何与凸优化的合体
上一课我们让机器在没有标签的数据里自己找结构。现在回到有标签的分类,但这次换一个野心更大的问题:分开两类点的直线有无穷多条,哪一条最稳?回答这个问题,需要把前面几条河——间隔的几何、凸优化的对偶、把维度升高的核技巧——一次性汇到一处。
留下的问题:可一旦数据带上了标签——这是 A 类、那是 B 类——分开它们的直线就有无穷多条。逻辑回归(第 35 课)会找到一条,但它没回答一个更要紧的问题:哪一条最稳?哪一条离两边的点都尽量远、最经得起新数据的考验?
本课新增:支持向量机(SVM)。它把"最稳"翻译成一个干净的几何目标——最大间隔,再把这个目标交给凸优化去求解,最后用核技巧把直线变成任意复杂的曲面。这是整条数学链里,几何、代数、优化三股拧成一股的最漂亮的一个例子。
无穷多条线,凭什么挑一条
设想平面上两类点,圆圈一类、叉叉一类,恰好能用一条直线分开。麻烦立刻来了:能把它们分开的直线不止一条,而是无穷多条。有的紧贴着圆圈,有的擦着叉叉,还有的从中间穿过。它们在已有的训练点上表现一模一样——错误都是零。可它们对将来的新点会给出不同答案。我们凭什么挑?
支持向量机的回答简单到近乎倔强:挑那条离两边的点都尽量远的。想象把这条分界线加宽成一条"马路",马路两侧的边缘各自顶到最近的几个点为止。不同的分界线对应不同宽窄的马路。SVM 要的,就是那条能撑出最宽马路的线。马路越宽,分界离数据越"留有余地",一个新点稍微偏一点也不容易被分错——这就是"最稳"的精确含义。这条马路的宽度,叫间隔(margin)。
把"间隔"写成几何
要让机器去最大化间隔,先得把"间隔"写成能算的式子。一条分界线(高维里叫超平面)可以写成所有满足下式的点 x:
w · x + b = 0 (读作"权重向量 w 与点 x 的内积,加上偏置 b,等于 0")
这里 w · x 是第 20 课的内积(点积),w 是一个垂直于这条线的向量(它的方向决定了线的朝向),b 决定线离原点多远。第 11 课说过 w · x 衡量 x 在 w 方向上的投影长度;所以 w · x + b 的正负,正好告诉我们 x 落在线的哪一侧。我们就用它的符号来分类:
w · x + b > 0 → 判为 +1 类; w · x + b < 0 → 判为 −1 类
那间隔有多宽?这正是第 20 课"点到直线的距离"的直接应用。一个点 x 到这条超平面的距离是:
距离 = |w · x + b| / ‖w‖ (读作"分子取绝对值,除以 w 的范数,即 w 的长度")
这里 ‖w‖(读作"w 的范数")是向量 w 的长度。注意一个关键的"自由度":把 w 和 b 同时乘以 2,分界线纹丝不动(w · x + b = 0 还是同一条线),但式子里的数字全变了。SVM 用一个聪明的归一化钉死这个自由度:要求离线最近的那些点恰好满足 |w · x + b| = 1。于是每一侧马路的半宽就是 1 / ‖w‖,整条马路的宽度——也就是间隔——是:
间隔 = 2 / ‖w‖
最大间隔 = 一个凸问题
现在目标清清楚楚:让间隔 2 / ‖w‖ 最大。分子是常数,所以"让 2 / ‖w‖ 最大"等价于"让 ‖w‖ 最小",再换成更好算的形式——让 ‖w‖²(即 w 各分量平方和)的一半最小。但不能无脑地把 w 缩到零,否则就没有分界线了;约束是每个训练点都要落在马路正确的一侧、且不能踩进马路里。把这两件事合起来,就是 SVM 的标准形式:
最小化 ½‖w‖² 使得对每个样本 (xᵢ, yᵢ) 都有 yᵢ(w · xᵢ + b) ≥ 1
逐字读:yᵢ 是第 i 个点的标签(+1 或 −1);yᵢ(w · xᵢ + b) ≥ 1 这一条同时表达了"分对了"且"离线至少有一个单位的余量"——因为正类点要 w · xᵢ + b ≥ 1,负类点(yᵢ = −1)要 w · xᵢ + b ≤ −1,乘上 yᵢ 后两种情况统一成 ≥ 1。
这个形式为什么值得欢呼?因为它恰好是第 28 课说的那种凸问题:要最小化的 ½‖w‖² 是一个标准的凸碗(一个向上的抛物面),约束都是线性不等式(它们围出的可行区域是凸的)。第 28 课的承诺在这里兑现:凸问题没有"假的"局部最优,找到的最低点一定是全局最优。逻辑回归的目标也是凸的,但 SVM 把"想要什么"写得更几何、更干脆——它直接求的就是那条最宽马路,而且解唯一。
对偶:翻个面,支持向量浮出水面
这个带约束的凸问题,可以用第 28 课的拉格朗日乘子来处理。思路是给每条约束 yᵢ(w · xᵢ + b) ≥ 1 配一个乘子 αᵢ ≥ 0(读作"阿尔法下标 i"),把"约束下最小化"翻译成一个新的、只关于这些 α 的问题——这叫对偶问题。翻面之后,两件极漂亮的事情冒了出来。
第一件:最优的 w 只由少数几个点决定。解出来后,绝大多数点的乘子 αᵢ = 0,对答案毫无贡献;只有那些恰好顶在马路边缘的点,乘子非零。最优权重是这些点的加权和:
w = ∑ αᵢ yᵢ xᵢ (只有边缘上的点 αᵢ ≠ 0,其余项为 0)
这些非零的点,就是支持向量(support vectors)——名字由此而来。它们像几根撑住马路边的桩子:移动一个内部的点,分界线纹丝不动;但只要动一根桩子,整条马路就会重排。整个模型,其实只记住了这几个最关键的边界样本。
第二件:对偶问题里,数据只以"两两内积"的形式出现。翻面后的目标函数和预测公式,从头到尾只用到点与点之间的内积 xᵢ · xⱼ,再也不需要单独看每个点的坐标。这个看似不起眼的事实,马上就要打开一扇大门。
核技巧:把直线变成任意曲面
到这儿还有个硬伤:很多数据根本不能用一条直线分开。比如内圈是一类、外圈是另一类,平面上没有任何直线能切开这两圈。怎么办?
办法是第 24 课埋下的直觉的逆用:把点升到更高的维度。在低维纠缠不清的两类,升到高维后常常变得能用一个平面切开。比如给平面上的点 (x, y) 加一个新坐标 x² + y²(到原点的距离平方),内圈的点就被抬低、外圈的点被抬高,在三维里一刀就能水平切开。
但直接升维有个代价:维度可能高到爆炸(甚至无穷维),坐标根本算不动——这正是第 24 课"维度灾难"的阴影。核技巧(kernel trick)就在这里施展魔法。还记得吗,对偶问题里数据只以内积形式出现。那我们根本不必真的把点搬到高维去;只要有一个函数能直接算出"两点在高维里的内积"是多少就够了。这个函数就叫核函数:
K(xᵢ, xⱼ) = φ(xᵢ) · φ(xⱼ) (φ 是"升维映射";K 直接给出高维内积,不必真的升维)
读作"核函数 K 作用在两点上,等于把它们各自升维后取内积"。妙处在于:很多核函数算起来极便宜,却对应着维度极高乃至无穷高的映射。最常用的高斯核(RBF 核)K(x, x′) = exp(−‖x − x′‖² / 2σ²) 对应的就是无穷维空间——而我们一次也没真的踏进那个空间。把对偶里所有 xᵢ · xⱼ 换成 K(xᵢ, xⱼ),那条直线就在原空间里弯成了任意复杂的曲面,而背后的优化仍然是凸的、仍然全局最优。这就是核技巧:用一个便宜的内积,买到高维空间的全部表达力。
软间隔:让几个点越界,换来更稳
真实数据总有噪声和重叠,强求"每个点都在马路外"经常无解,或逼出一条窄得可笑、被一个离群点绑架的马路。SVM 的修补很务实:允许少数点踩进马路、甚至越到对面,但每越一点就罚一点。引入"松弛量" ξᵢ ≥ 0(读作"克西下标 i",衡量第 i 点越界多少),目标变成:
最小化 ½‖w‖² + C · ∑ ξᵢ (C 越大越不许越界,C 越小越宽容)
这就是软间隔。参数 C 在"马路要宽"和"别让点越界"之间调一个平衡——它和第 31 课的正则化是一回事:宽马路本身就是一种"别太相信每一个数据点"的克制。而且这个改动没有破坏凸性:加进去的还是凸的项与线性的约束,第 28 课的全局最优保证依然成立。
常见误解
- "SVM 找的就是逻辑回归找的那条线。"——不是。两者都给一条分界线,但目标不同:逻辑回归最大化标签的似然,分界线会受所有点影响;SVM 只最大化间隔,分界线只由支持向量决定,内部的点完全不参与。两条线往往不一样。
- "核技巧真的把数据搬到了高维空间。"——恰恰相反,核技巧的全部聪明就在于没有搬。它只算"高维里的内积"这一个数,绕过了在高维里真正建坐标的灾难(第 24 课)。
- "间隔越大越好,所以 C 应该取很大。"——C 大是惩罚越界、逼马路变窄去迁就每个点;C 小才换来宽马路。一个被离群点绑架的窄马路,泛化往往更差。这是个需要调的平衡。
- "支持向量越多越好,说明模型用上了更多数据。"——通常相反。支持向量太多,常意味着间隔很窄、或核太复杂、数据高度重叠,是过拟合或难分的信号,而非优点。