尧图精选

线性可分SVM:从感知机到最大化间隔的直观解读

🕒 发布时间:2026/9/16 5:08:14 📁 来源:尧图网络
我之前在公司内部带过几轮机器学习入门每次讲到SVM都会发现一个现象绝大多数人在看《统计学习方法》或吴恩达课程时能看懂公式推导但合上书之后说不清楚SVM到底比感知机强在哪也不理解为什么要费劲去最大化间隔。等代码跑起来更是把支持向量当成一个模糊的概念只记得有个叫C的参数要调。这篇文章我打算换个讲法。不急着堆公式而是把自己从能看懂推导到真明白SVM在干什么这个过程中的关键顿悟点全部摊开来讲。今天这一篇只聚焦最基本的情况训练数据线性可分、不考虑噪声和异常点也就是所谓的线性可分SVM硬间隔SVM。搞清楚这个基本型后面再看软间隔、核函数思路才会顺。1. 线性可分SVM到底在解决什么问题1.1 从感知机说起能分对不等于分得好要理解SVM的动机得先回到感知机。感知机的目标是找到一个超平面把所有训练样本正确分类。这一点它确实能做到但这里埋着一个被很多人忽略的问题满足条件的超平面有无数个感知机会找到哪一个完全取决于初始化和更新顺序。我举个例子二维平面上有两类点正类在右上负类在左下。你随便画一条直线把它们分开这条直线只要斜率别太离谱就能做到零错误分类。但问题是有的直线几乎贴着某一类的点擦过去离另一边却远得很。训练集上它和完美居中的直线表现一样好都是100%正确率可一旦来个新样本哪怕只是稍微靠近两类边界结果就完全不一样了。感知机的做法本质上就是在无数个可行解里随便挑一个没有任何原则告诉你哪个更好。SVM的思路则是加了一条明确的标准在所有能正确划分训练集的超平面里选那个离两边样本都尽可能远的。远意味着对训练样本的分布变化不那么敏感在未见数据上的表现更稳。所以SVM的第一个关键点不是怎么分对而是怎么分得让边界稳健。这个视角转换很重要它从找一个解变成了找最优解。1.2 超平面、间隔和支持向量先见个面先把三个词说清楚因为它们后面会反复出现。超平面在二维空间是一条直线三维空间是一个平面更高维就是比当前空间少一个维度的子空间。SVM要寻找的超平面可以用方程 $w^T x b 0$ 来表示其中 $w$ 是法向量决定了超平面的朝向$b$ 是偏置决定了超平面离原点的距离。间隔指的是超平面与距离它最近的训练样本之间的距离。这个距离有两种算法分别叫函数间隔和几何间隔。很多初学者在这个地方摔倒但两者的区别其实一句话就能说清函数间隔是没归一化的原始值几何间隔是去掉尺度影响后真正物理意义上的距离。具体推导下一节细讲你先记住一个结论SVM最大化的是几何间隔因为只有它是尺度不变的。支持向量就是那些距离超平面最近的样本点。在二维情况下你会看到两类样本各有若干个点紧贴着中间的间隔边界这些点就是顶着间隔的样本。它们撑起了决策边界的位置——移动一个支持向量决策边界就会跟着变而移动一个离边界很远、被正确分类的样本决策边界纹丝不动。我把这三个概念之间的关系用一个生活化的类比说给你听。想象你在一段路中间画一条车道分界线要求所有车辆必须完全待在各自车道内。你画线时会怎么考虑肯定是尽量往中间画让左右两侧最近的车辆都离线远一点这样即使车辆稍微晃动也不容易压线。这里的分界线就是超平面车辆离线的距离就是间隔靠线最近的左右两辆车就是支持向量。理解了这三个词你再看SVM的优化目标找到一个超平面让距离它最近的样本点——也就是支持向量——到它的距离最大化。这就是最大化间隔的全部含义。2. 核心公式推导间隔到底怎么算2.1 函数间隔和几何间隔为什么需要两个概念从数学上描述点到超平面的距离最直接的公式是 $\frac{|w^T x b|}{|w|}$这是高中学过的点到直线距离在高维空间的推广。可SVM的公式里总出现 $y_i(w^T x_i b)$ 这个东西其中 $y_i$ 是样本标签正类取 $1$负类取 $-1$。你可能会问为什么不直接写距离公式非要乘一个 $y_i$原因在于乘上 $y_i$ 之后这个值的正负就代表了分类是否正确。$\frac{y_i(w^T x_i b)}{|w|}$ 的绝对值是点到超平面的距离而它的符号刚好告诉你这个点是不是被正确分类了。正值表示分类正确负值表示分类错误。这样一个值同时携带了分对没分对和离得多远两层信息。这时候可以定义两个量函数间隔$\hat{\gamma}_i y_i(w^T x_i b)$几何间隔$\gamma_i \frac{y_i(w^T x_i b)}{|w|}$两者的差异就是除以 $|w|$。在二维空间里$|w|$ 正好是法向量的长度除以它之后点积结果就从带尺度的投影长度还原成真实的距离。为什么要多此一举定义两个量因为函数间隔有一个毛病它不是尺度不变的。如果你把 $w$ 和 $b$ 同时放大两倍那么 $w^T x b$ 也会变成原来的两倍函数间隔跟着翻倍但超平面本身没有任何变化——还是那条线只是等式两边同时乘了个2而已。用这样的量来衡量间隔显然不可靠。而几何间隔除以 $|w|$ 之后$w$ 和 $b$ 同步缩放时分子分母同比例变化结果保持不变这才是真正物理意义上的距离。表格放在这儿方便对照记忆概念定义式是否尺度不变物理意义函数间隔$y_i(w^T x_i b)$否带尺度的未归一化间隔几何间隔$\frac{y_i(w^T x_i b)}{|w|}$是样本到超平面的真实距离2.2 从最大化间隔到数学优化问题明确要最大化几何间隔之后我们可以把SVM的优化目标写出来$$ \max_{w,b} \quad \gamma $$其中 $\gamma \min_i \gamma_i$也就是所有训练样本的几何间隔里最小的那个。最大化这个最小间隔等价于让最不安全的点尽量远离超平面。同时必须保证所有样本都被正确分类也就是对每个样本都满足$$ \gamma_i \geq \gamma $$把这个约束展开就是$$ y_i(w^T x_i b) \geq \gamma |w|, \quad i 1, 2, \ldots, m $$现在问题来了这个带 $|w|$ 的约束不好处理。因为它把 $w$ 同时夹在了右边——既要在左边找最好的 $w,b$又要在右边乘以 $|w|$整个问题变成一个非凸优化求解会非常麻烦。这里就用到了一个经典技巧对 $w$ 和 $b$ 进行缩放。前面说过$w$ 和 $b$ 等比缩放时超平面不会变几何间隔也不会变。那我们干脆让 $\gamma |w| 1$也就是说把 $w$ 和 $b$ 缩放到使得离超平面最近的样本的函数间隔恰好等于1。这样约束就变成$$ y_i(w^T x_i b) \geq 1, \quad i 1, 2, \ldots, m $$这是一个干净、漂亮的不等式约束不掺任何额外因子。而最大化 $\gamma$ 因为 $\gamma |w| 1$等价于 $\gamma \frac{1}{|w|}$所以最大化 $\gamma$ 就等价于最大化 $\frac{1}{|w|}$也就是最小化 $|w|$。2.3 为什么约束条件是 $y_i(w^T x_i b) \geq 1$而不是 $\geq 0$这个问题几乎每次讲SVM都会有人问。既然只要分对就行那约束写成 $y_i(w^T x_i b) \geq 0$ 不就行了吗为什么要让大于等于1关键在于$\geq 0$ 只表达了分类正确但没有给出任何间隔大小的要求。刚才我们通过缩放把最小函数间隔固定成了1所以 $\geq 1$ 其实是在说你不仅要分对而且要分得有底气最近的那个点也得离超平面有至少 $1$ 个函数间隔的距离。从另一个角度看$\geq 1$ 这个约束把优化间隔和正确分类合并进了一个不等式。如果你只要求 $\geq 0$那优化目标不管写成最大化间隔还是最小化 $|w|$都会出问题——模型可以把 $w$ 压缩到趋近于0来糊弄损失函数但这时候超平面本身的安全边际并没有被真正约束。用一个生活化的例子你选停车位目标不只是能停进去$\geq 0$还要停完车两边都能开门$\geq 1$。这样旁边车开走再停一辆你的车也不会被挤住。SVM也是一样它不但要求分类正确还要求分类正确得有余量这个余量就是可以承受训练样本轻微扰动的缓冲空间。2.4 目标函数为什么是 $\frac{1}{2}|w|^2$数学上有个偏好同一个优化问题原问题描述越简洁、数学性质越好求解工具越成熟。最大化 $\frac{1}{|w|}$ 是带根号的非凸问题不好做。但我们知道最大化 $\frac{1}{|w|}$ 完全等价于最小化 $|w|$而最小化 $|w|$ 又等价于最小化 $|w|^2$。至于系数 $\frac{1}{2}$纯粹是为了求导方便——$\frac{\partial}{\partial w}(\frac{1}{2}|w|^2) w$消掉了那个不痛不痒的2。更本质的原因在于$|w|^2$ 是一个凸函数加上线性的约束条件之后整个优化问题是一个凸二次规划问题。凸二次规划意味着没有局部最优的困扰——你找到的任何局部最优解都一定是全局最优解而且有非常成熟的求解库可以用。这一点在工程实践中极其重要它保证了SVM的求解稳定、可复现不会像神经网络那样跑十次有十次不同的结果。至此线性可分SVM的基本型就完整了$$ \begin{aligned} \min_{w,b} \quad \frac{1}{2} |w|^2 \ \text{s.t.} \quad y_i(w^T x_i b) \geq 1, \quad i 1, 2, \ldots, m \end{aligned} $$这就是你在各种教材上看到的标准形式也叫硬间隔SVM。所有SVM的后续扩展软间隔、核技巧都是在这个基础上打补丁。3. 基本型的求解与支持向量的秘密3.1 这是一个凸二次规划我们先看它有哪些性质基本型摆出来之后第一反应应该是这是凸二次规划。这三个字信息量很大第一它有唯一的全局最优解。凸目标函数 线性不等式约束标准的凸优化问题。这意味着你不必担心随机初始化和局部最优任何能解决凸二次规划的算法无论怎么跑最终都会收敛到同一个最有价值的超平面。第二它的约束数量等于样本数量。如果训练集有1000条数据就意味着有1000个不等式约束。在样本量很大的时候直接求解这个带众多约束的原问题并不轻松。这促使研究者走向对偶问题。第三约束的特点是绝大多数约束不活跃。绝大多数样本都离超平面远远的$y_i(w^T x_i b)$ 远大于1它们的约束约束根本不会限制最优解。真正卡住优化过程的只有极少数的点——那些函数间隔恰好等于1的样本也就是支持向量。所以这类大规模稀疏约束问题非常适合用拉格朗日对偶来求解因为对偶问题能让你一眼看到哪些变量在真正起作用。3.2 拉格朗日对偶为什么要绕道而行直接解原问题是可行的但引入拉格朗日对偶目的至少有三个第一个目的对偶问题能暴露支持向量的结构。后面你会看到KKT条件下只有支持向量对应的拉格朗日乘子 $\alpha_i$ 不为零其余样本的 $\alpha_i$ 全是0。这意味着最终决策函数只依赖于少数几个点。第二个目的对偶问题为核技巧铺路。对偶形式里样本特征以 $x_i^T x_j$ 的内积形式出现。如果将来要处理非线性数据我们可以用核函数 $K(x_i, x_j)$ 替换这个内积从而在低维空间计算高维映射后的内积。这是SVM能扩展到非线性问题的关键。第三个目的对偶问题在某些情况下更容易求解。成熟的序列最小优化SMO算法就是针对对偶问题设计的每次只优化两个 $\alpha$比直接面对高维 $w$ 高效得多。推导过程不在这里全部展开我说下关键两步。先写拉格朗日函数$$ L(w, b, \alpha) \frac{1}{2} |w|^2 \sum_{i1}^{m} \alpha_i \left( 1 - y_i(w^T x_i b) \right) $$对 $w$ 和 $b$ 分别求偏导并令其为零得到两个条件$$ w \sum_{i1}^{m} \alpha_i y_i x_i $$$$ \sum_{i1}^{m} \alpha_i y_i 0 $$把这两个式子代回拉格朗日函数就得到对偶问题$$ \max_{\alpha} \quad \sum_{i1}^{m} \alpha_i - \frac{1}{2} \sum_{i1}^{m} \sum_{j1}^{m} \alpha_i \alpha_j y_i y_j x_i^T x_j $$$$ \text{s.t.} \quad \alpha_i \geq 0, \quad \sum_{i1}^{m} \alpha_i y_i 0 $$注意这里 $w$ 被表达成了样本点的线性组合系数是 $\alpha_i y_i$。这个形式意味着最终的决策超平面是由训练样本线性叠加出来的而叠加的权重由 $\alpha_i$ 来决定。3.3 支持向量到底是什么这里一次性说透把拉格朗日乘子 $\alpha_i$ 和KKT条件结合起来会有非常关键的一个发现。KKT条件之一叫互补松弛写作$$ \alpha_i \left( y_i(w^T x_i b) - 1 \right) 0 $$这个等式意味着什么它说 $\alpha_i$ 和 $y_i(w^T x_i b) - 1$ 不能同时非零。于是有两种情况如果 $y_i(w^T x_i b) 1$也就是样本被正确分类且离超平面足够远此时强制 $\alpha_i 0$。这个样本对 $w$ 没有贡献。如果 $y_i(w^T x_i b) 1$样本恰好落在间隔边界上此时 $\alpha_i$ 可以大于零。这个样本对确定超平面有直接贡献。所以在最优解处绝大多数样本的 $\alpha_i$ 是0只有落在间隔边界上的那一小撮样本 $\alpha_i 0$。这些 $\alpha_i 0$ 的样本就是支持向量。这个结论的价值在于它解释了SVM的一个优雅特性训练完成后你可以丢掉所有非支持向量的训练数据模型参数完全不变。在实际项目中这意味着模型的泛化能力取决于一小群困难样本而不是全部数据。这也和直觉一致决策边界最应该关心那些险些被分错的点而不是那些远远地待在正确区域里的普通点。结合 $w \sum \alpha_i y_i x_i$最终的决策函数写出来就是$$ f(x) \text{sign}\left( \sum_{i \in SV} \alpha_i y_i x_i^T x b \right) $$注意求和只针对支持向量。这个形式在构造非线性SVM的时候会原封不动地搬过去。4. 实操中的正确打开方式与容易踩的坑4.1 训练SVM之前先做特征缩放很多初学者习惯拿原始特征直接丢进SVC()里跑完一看准确率还行就把模型部署上线了。但SVM和决策树不一样它非常依赖特征的尺度。原因是SVM的目标函数里有 $|w|^2$而约束 $y_i(w^T x_i b) \geq 1$ 中的 $w^T x_i$ 是特征的内积。如果你的特征A取值范围是0到1特征B取值范围是0到100000那么计算 $w^T x_i$ 时特征B对距离的贡献会被无限放大模型会误以为特征B更重要。更麻烦的是间隔边界会被拉向特征B的方向支持向量的选择也会被带偏最终得到的超平面和所有特征同等重要时的最优超平面完全不同。标准做法是标准化让每个特征的均值为0、方差为1from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC from sklearn.pipeline import make_pipeline model make_pipeline(StandardScaler(), SVC(kernellinear)) model.fit(X_train, y_train)用Pipeline的好处是对训练集做标准化时均值和方差被保存在Scaler里预测时自动用同一套参数转换测试数据不会发生数据泄露。4.2 用scikit-learn复现一个线性可分SVM用Python复现这个流程非常简单。下面以经典的鸢尾花数据集中前两个类别为例做一个线性可分SVM的可视化import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.svm import SVC iris load_iris() # 取前两个类别和前两个特征保证线性可分 X iris.data[:100, :2] y iris.target[:100] model SVC(kernellinear, C1e6) # C设得很大逼近硬间隔 model.fit(X, y) # 画决策边界 plt.figure(figsize(8, 6)) xx, yy np.meshgrid(np.linspace(X[:, 0].min() - 0.5, X[:, 0].max() 0.5, 500), np.linspace(X[:, 1].min() - 0.5, X[:, 1].max() 0.5, 500)) Z model.decision_function(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) plt.contour(xx, yy, Z, levels[-1, 0, 1], colorsk, linestyles[--, -, --]) plt.scatter(X[:, 0], X[:, 1], cy, cmapautumn) plt.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s100, facecolorsnone, edgecolorsblue, labelsupport vectors) plt.legend() plt.show()运行之后你会看到两条虚线分别经过两类样本中最危险的那些点实线在它们正中间。蓝圈标出的就是支持向量。一个特别好用的经验是训练完之后第一时间检查model.support_vectors_.shape[0]看看支持向量占比多少。如果支持向量数量非常少比如只占总样本的几个百分点说明两类之间确实分得比较开模型的置信度比较高如果支持向量数量几乎等于全部样本那你的数据大概率不是线性可分的或者C设置不合理。4.3 四个常见误区逐个拆给你看误区一把函数间隔和几何间隔搞混。网上不少资料画图标注margin但不说明标的是哪种。函数间隔在 $w$ 缩放时会变化如果你拿它来判断模型好坏就会得到同一个模型隔一会儿间隔变大了的荒诞结果。牢记一点只有几何间隔才是物理意义上的距离也就是图上实际画出来的。误区二用 $\geq 0$ 当约束条件认为分对就行。前面推导过$\geq 1$ 不是人为拍脑袋定的而是通过缩放 $w,b$ 得到的规范化结果。反过来如果你把优化目标改成最小化 $-\sum y_i(w^T x_i b)$ 之类的东西那完全不是SVM而是一个没有间隔概念的分类器。误区三以为SVM对特征尺度不敏感。恰恰相反SVM对尺度非常敏感。C参数、核函数参数、特征数值范围三者相互作用任何一环没做好模型的表现都会天差地别。特征缩放看似不起眼但对SVM来说是必做项。误区四以为支持向量就是离超平面最近的那个点。实际上支持向量通常不止一个而且它们不躺在超平面上而是躺在间隔边界上。超平面与支持向量之间的距离是 $\frac{1}{|w|}$超平面本身在两排支持向量的正中间。从KKT条件的互补松弛可以严格证明支持向量必须满足 $y_i(w^T x_i b) 1$也就是函数间隔恰好等于1不在超平面上。4.4 硬间隔SVM在真实数据上几乎不可用有个事实必须点破硬间隔SVM在真实数据里几乎找不到直接落地的场景。因为真实数据总是带噪声的偶尔就有几个点跑到对面阵营里这时候硬间隔SVM压根找不到可行解——没有超平面能在 $y_i(w^T x_i b) \geq 1$ 的条件下同时满足所有样本。这是基本型最大的软肋也是我为什么强调要先彻底搞懂它但不要指望它能直接上生产的原因。解决办法是引入松弛变量 $\xi_i$允许个别样本违反间隔约束同时在目标函数里对违反行为做惩罚这就是软间隔SVM。你在sklearn里看到的C参数控制的就是这个惩罚力度。那些想在真实数据上直接套硬间隔SVM的人大概率会遇到两个结果直接报错failed to converge或者为了硬凑可行解把C调得巨大结果过拟合到训练集上测试集表现惨不忍睹。所以我的建议是在动手调参之前先用一条简单的经验法则判断数据是否线性可分——你可以在二维情况下画散点图三维用plotly交互式看一眼更高维就用线性SVM在训练集上跑一次看有没有报错。如果线性模型连训练集都无法完美划分那就不要碰硬间隔SVM了直接去看软间隔和核函数那才是解决实际问题的工具。我个人调试SVM时的习惯是先StandardScaler标准化所有特征然后看训练集上线性核能不能收敛再根据支持向量占比判断数据复杂度。如果支持向量占比超过50%说明数据线性可分性很差用RBF核做一次非线性映射通常效果会好很多。这个流程走下来大部分分类任务都能在几分钟内定位到合适的模型配置。关于线性可分SVM的基本型我觉得最值得记住的一句话是它不是在找一条能分对的线而是在找一条离两边都足够远的线。理解了这句话再回头看那些公式你会觉得它们都顺理成章。下一篇我再展开软间隔和核技巧到时候你会发现基本型的对偶形式、支持向量概念全都会原封不动地延续下去。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →