不显式增加维度,SVM 怎样画出弯曲边界?从核技巧到 RBF
从线性 SVM 无法分开同心圆出发,推导对偶表示与核技巧,手算 RBF 相似度,解释 C、gamma、支持向量和可扩展近似。
上一篇的线性支持向量机(Support Vector Machine,SVM)用最大间隔选择稳定超平面,并用软间隔容忍噪声。但同心圆、弯月形和异或(XOR)数据在原始空间中根本不存在一条直线能分开。
一种办法是手工增加 、 等非线性特征,再训练线性 SVM。问题是高阶组合的维数会快速爆炸,而且我们最后真正需要的,往往不是每个新坐标本身,而只是样本在新空间中的点积。
核技巧(Kernel Trick)利用这个缺口:不显式构造高维特征,只计算两点映射后的内积。 本文沿“对偶表示 → 核函数 → RBF 相似度 → 工程选择”讲透这条数据流。
01 一条直线为什么分不开同心圆?#
设二维样本的类别只取决于半径:圆心附近是负类,外环是正类。
x₂
▲ + + +
│ + +
│ + ○ ○ +
│ + ○ ○ ○ +
│ + ○ +
│ + +
└────────────────────► x₁
原始空间:任何直线都会同时切到内圈和外圈text若增加一个特征:
内圈的 小,外圈的 大,只需在 轴设阈值就能线性分开。也就是说,原空间中的弯曲边界,可能是另一个特征空间中的超平面。
更一般地,用映射 把输入送入新的特征空间:
然后学习:
困难在于 可能有成千上万维,甚至无限维;显式计算和存储 会很昂贵。
02 为什么 SVM 最终只需要样本之间的点积?#
上一篇写过软间隔原始问题(Primal Problem):
满足:
通过拉格朗日乘子把约束并入目标,可以得到对偶问题(Dual Problem):
\max_{\alpha}\quad \sum_{i=1}^{N}\alpha_i-rac12 \sum_{i=1}^{N}\sum_{j=1}^{N} \alpha_i\alpha_jy_iy_j\langle x_i,x_j\rangle满足:
- :第 个训练约束的乘子;
- :每个乘子的上界,同时控制软间隔违规代价;
- :两个训练样本的点积;
- 只有 的训练点会进入最终决策函数,它们就是支持向量。
最优权重可写成训练样本的线性组合:
因此新样本的分数是:
许多 为 0,实际只需支持向量集合 :
关键线索出现了:训练和预测都只通过点积比较样本。
03 核技巧到底替换了什么?#
若先映射 ,对偶中出现的是:
核函数(Kernel Function)直接返回这个内积:
于是决策函数变成:
数据流从“显式造特征”变成“计算相似度矩阵”:
训练:X_train [N,D]
│ 两两核函数 K(x_i,x_j)
▼
Gram matrix K_train [N,N]
│ 对偶优化
▼
support vectors [S,D] + dual coefficients [S]
推理:X_query [Q,D] × support vectors [S,D]
│ 核函数
▼
K_query [Q,S]
│ 加权求和 + b
▼
decision score [Q]text这里的格拉姆矩阵(Gram Matrix)第 项是 。并非任意“相似度”都能安全作为核;合法核必须对应某个内积空间,常用充分条件是对任意有限样本得到的 Gram 矩阵为半正定。
一个显式可验证的二次核#
对二维输入,令:
则:
因此 隐式包含所有二次交互。我们只算原空间的点积再平方,不必为每个样本显式保存三维 。高维、高阶时节省更明显。
04 RBF 核怎样把“近”变成影响力?#
径向基函数核(Radial Basis Function Kernel,RBF),也常称高斯核,定义为:
- :两个已按训练统计量缩放的样本;
- :平方欧氏距离;
- :单个样本影响范围的倒数尺度;
- :两点相同为 1,距离增大时趋近 0。
| 距离 | |||
|---|---|---|---|
| 0 | 1.000 | 1.000 | 1.000 |
| 1 | 0.779 | 0.368 | 0.018 |
| 2 | 0.368 | 0.018 |
小 让一个支持向量影响很远,边界更平滑;大 让影响集中在很小邻域,模型能绕着单个样本急转弯,也更容易追逐噪声。
K(x,z)
▲ gamma 大
│ /\
│ / \ gamma 小
│ ____/ \____ __/¯¯¯¯\__
└────────────────────────────────► distance
窄影响 宽影响text05 用两个支持向量手算一次预测#
考虑一维的两个支持向量:
x₁ = -1, y₁ = -1, alpha₁ = 1
x₂ = +1, y₂ = +1, alpha₂ = 1
b = 0, gamma = 1text决策函数为:
查询 时,两边距离相同:
所以 ,正好在边界上。
查询 时:
因此预测正类。这个分数不是“最近邻投票”,而是所有支持向量的带符号、带系数相似度之和。
交互手算:查询点移到 x=3
,,所以分数仍略为正,但非常接近 0。RBF SVM 不擅长在训练范围外产生线性外推;远离所有支持向量时,各项都会衰减。
06 C 与 gamma 为什么必须联合选择?#
C 和 gamma 控制不同维度,却会共同决定边界:
| 设置 | 单点影响范围 | 违反训练间隔的价格 | 常见边界 |
|---|---|---|---|
| 小 、小 | 宽 | 低 | 很平滑,可能欠拟合 |
| 小 、大 | 宽 | 高 | 努力用平滑边界分对 |
| 大 、小 | 窄 | 低 | 局部影响强但允许错误 |
| 大 、大 | 窄 | 高 | 绕样本急转,容易过拟合 |
只调一个参数会误判另一个参数的作用。例如大 提供了极强局部容量,但若 很小,优化器仍可能宁可容忍训练错误;反过来,大 也无法让过小 表达细小结构。
scikit-learn 1.9 中 gamma='scale' 使用:
它是合理起点,不是经过验证的最优值。由于方差和距离都受单位影响,标准化仍必须放进 Pipeline。
07 不调用 SVC:先验证核矩阵和数据流#
下面用 NumPy 显式计算 RBF Gram 矩阵,并用前面的两个支持向量完成预测:
import numpy as np
def rbf_kernel(X, Z, gamma):
# X [N,D], Z [M,D] -> squared_distance [N,M]
x_norm = np.sum(X**2, axis=1, keepdims=True) # [N,1]
z_norm = np.sum(Z**2, axis=1, keepdims=True).T # [1,M]
squared_distance = x_norm + z_norm - 2.0 * X @ Z.T
squared_distance = np.maximum(squared_distance, 0.0)
return np.exp(-gamma * squared_distance) # [N,M]
support = np.array([[-1.0], [1.0]]) # [S=2,D=1]
dual_coef = np.array([-1.0, 1.0]) # alpha_i * y_i, [S]
query = np.array([[0.0], [0.5], [3.0]]) # [Q=3,D=1]
K_query = rbf_kernel(query, support, gamma=1.0) # [Q,S]
score = K_query @ dual_coef + 0.0 # [Q]
prediction = np.where(score >= 0.0, 1, -1) # [Q]
K_train = rbf_kernel(support, support, gamma=1.0) # [S,S]
eigenvalues = np.linalg.eigvalsh(K_train)
assert np.allclose(K_train, K_train.T)
assert eigenvalues.min() >= -1e-10python距离公式用矩阵乘法避免创建 [N,M,D] 的巨大差值张量;由于浮点舍入,理论上非负的平方距离可能出现极小负数,所以在指数前截到 0。
真实 SVC 的 dual_coef_ 已经包含类别符号;多分类时其布局更复杂,不要把二分类示例直接推广为手写多分类推理。
08 用 scikit-learn 1.9 训练 RBF SVM#
官方当前接口中 SVC 默认核就是 RBF,但正式代码应显式写出关键选择,并在对数尺度联合搜索 与 :
import numpy as np
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
pipeline = make_pipeline(
StandardScaler(),
SVC(
kernel='rbf',
cache_size=512,
class_weight=None,
),
)
search = GridSearchCV(
estimator=pipeline,
param_grid={
'svc__C': np.logspace(-2, 3, 6),
'svc__gamma': np.logspace(-4, 1, 6),
},
scoring='balanced_accuracy',
cv=StratifiedKFold(n_splits=5, shuffle=True, random_state=42),
n_jobs=-1,
refit=True,
)
search.fit(X_train, y_train) # [N,D], [N]
score = search.decision_function(X_val) # binary: [num_val]
prediction = search.predict(X_val) # [num_val]
svc = search.best_estimator_.named_steps['svc']
print('best parameters:', search.best_params_)
print('support vectors:', svc.support_vectors_.shape) # [S,D]
print('per-class support:', svc.n_support_) # [num_classes]
print('dual coefficients:', svc.dual_coef_.shape)python重要接口语义:
support_是训练行索引[S];support_vectors_是经过 Pipeline 标准化后的支持向量[S,D];- 二分类
decision_function返回[Q],正负方向对应classes_的顺序;它不是概率; cache_size单位是 MB,增大核缓存可能提速,但会增加每个并发训练进程的内存;class_weight='balanced'会按类别频率缩放各类有效 ,不能替代合适指标和阈值设计;SVC内部多分类使用一对一(One-vs-One),默认只把决策输出整理成一对其余风格。
例如在超参数冻结后重新以交叉验证校准:
from sklearn.calibration import CalibratedClassifierCV
calibrated = CalibratedClassifierCV(
estimator=search.best_estimator_,
method='sigmoid',
cv=5,
ensemble=False,
)
calibrated.fit(X_train, y_train)
probability = calibrated.predict_proba(X_val) # [num_val, num_classes]python校准本身也是模型选择的一部分。测试集不能用于拟合校准器或选择 sigmoid/isotonic。
09 训练为何会突然变得很慢?#
核 SVM 的代价来自样本两两关系。完整 Gram 矩阵有 个元素;SVC 的训练时间至少随样本数二次增长,在数万样本以上常变得不实用。预测成本又约随支持向量数 增长:
单批推理核计算量 ≈ Q × S × D
模型状态至少包含 S 个支持向量text如果类别高度重叠,很多训练点会成为支持向量,模型体积和延迟都会上升。工程检查应同时记录:
- 样本数 与支持向量数 ;
S/N支持向量比例;- 交叉验证每折训练时间和峰值内存;
- 批量吞吐、P50/P99 推理延迟;
- 标准化器、支持向量和库版本。
数据较大时有三条常见替代路线:
- 边界近似线性:用
LinearSVC或SGDClassifier(loss='hinge'); - 仍需要 RBF 形状:用 Nyström 或随机傅里叶特征近似核,再接线性模型;
- 表格任务允许别的归纳偏置:比较直方图梯度提升等强基线。
Nyström 近似把隐式无限维核压成显式的 维特征:
from sklearn.kernel_approximation import Nystroem
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
approximate_rbf = make_pipeline(
StandardScaler(),
Nystroem(
kernel='rbf',
gamma=0.1,
n_components=1000,
random_state=42,
),
LinearSVC(C=1.0, dual='auto', max_iter=10_000),
)
approximate_rbf.fit(X_train, y_train)pythonn_components 越大通常越接近原核,也增加变换、内存与线性模型成本;它与 gamma、C 一样要在开发数据上验证。
10 常见错误与最短调试路径#
- 忘记标准化。 RBF 直接使用平方距离,一个大尺度特征会吞没其余维度;缩放必须只在训练折拟合。
- 只调 C,不调 gamma。 二者共同控制容量,应在对数网格联合搜索。
- 把 gamma 当影响半径。 gamma 越大,实际影响越窄;可先手算距离 1 时的 。
- 把 decision score 当概率。 分数可为任意实数;用校准器并验证 Brier 分数、对数损失和校准曲线。
- 对全数据先算 Gram 矩阵再交叉验证。 若核前还包含可学习预处理,会发生泄漏;优先使用 Pipeline。
- 自定义预计算核形状错误。 训练应为
[N_train,N_train],验证/推理应为[N_query,N_train],第二维始终对应训练样本。 - 无限扩大 cache_size 或 n_jobs。 每个并发折都可能占用自己的核缓存,外层并行会放大内存。
- 支持向量比例接近 100% 仍忽略延迟。 先检查重叠、噪声、C/gamma 和线性/近似替代方案。
- 在训练范围外相信分数大小。 RBF 相似度远离所有支持向量会共同衰减,外推行为并不等同于置信度。
最小诊断代码:
assert X_train.ndim == 2 and y_train.ndim == 1
assert X_train.shape[0] == y_train.shape[0]
assert np.isfinite(X_train).all()
assert np.isfinite(score).all()
assert svc.support_vectors_.shape[1] == X_train.shape[1]
assert svc.dual_coef_.shape[1] == len(svc.support_)
print('classes:', svc.classes_)
print('support ratio:', len(svc.support_) / len(X_train))python若训练和验证都差,优先检查缩放、gamma 是否过小和特征是否有信号;若训练接近完美而验证差,优先减小 gamma、减小 C、排查泄漏和标签噪声。
11 与相近方法的边界#
| 方法 | 非线性从哪里来 | 训练/推理主要状态 | 主要限制 |
|---|---|---|---|
| RBF SVM | 支持向量与 RBF 核 | 支持向量和对偶系数 | 样本规模大时昂贵 |
| KNN | 原始空间局部距离 | 几乎全部训练样本 | 高维距离退化、推理慢 |
| 核逻辑回归 | 核特征 + 对数损失 | 通常更稠密的系数 | 优化和存储可能更重 |
| 决策树/提升树 | 轴对齐分裂组合 | 规则节点 | 不做平滑外推 |
| 神经网络 | 多层可学习表示 | 网络参数 | 训练设计与数据需求更复杂 |
RBF SVM 适合中小规模、经过良好缩放、边界非线性且局部平滑的数据。它不是所有非线性问题的默认答案:图像、文本、序列和图结构通常需要更合适的表示;高维稀疏文本常先比较线性 SVM;需要概率时要把校准成本纳入方案。
12 今天真正需要记住什么?#
- SVM 的对偶目标和预测只依赖样本点积,因此可以用核函数替换高维映射后的点积。
- 决策函数是支持向量核相似度的带符号加权和:。
- RBF 核按平方距离衰减;
gamma越大,单个样本影响越窄,边界容量通常越高。 C控制违规价格,gamma控制局部影响范围,二者必须在无泄漏 Pipeline 中联合验证。- 精确核 SVM 的训练至少二次扩展,支持向量过多还会拖慢推理;大数据要比较线性或核近似方案。
13 思考题与小练习#
练习 1:手算 RBF 核
令 、、。平方距离为 2,因此 。若先把第二维放大 100 倍,核几乎变为 0,这说明尺度为何会决定相似度。
练习 2:写出查询核矩阵形状
训练集有 800 个样本,测试批有 32 个样本。若 kernel='precomputed',训练 Gram 矩阵是 [800,800],测试核矩阵是 [32,800];测试矩阵不是 [32,32]。
练习 3:做 C-gamma 二维消融
固定划分和缩放,对 C,gamma in {0.01,1,100} 的 9 个组合记录训练分数、验证分数、支持向量比例、训练时间和 P99 延迟。解释哪一角欠拟合,哪一角最可能追逐噪声。
相关工作#
- Boser, Guyon & Vapnik: A Training Algorithm for Optimal Margin Classifiers ↗:核化最大间隔分类器的经典工作。
- Schölkopf, Smola & Müller: Nonlinear Component Analysis as a Kernel Eigenvalue Problem ↗:核技巧用于非线性特征分析的代表性工作。
- Rahimi & Recht: Random Features for Large-Scale Kernel Machines ↗:用随机显式特征扩展平移不变核。
- Williams & Seeger: Using the Nyström Method to Speed Up Kernel Machines ↗:Nyström 核矩阵低秩近似的代表性工作。
- scikit-learn: SVC ↗:当前 RBF 参数、复杂度、支持向量属性与概率接口变化。
14 下一篇预告#
SVM 从几何间隔出发,通过支持向量决定边界。下一篇将换到概率生成视角:朴素贝叶斯怎样用类别先验与条件似然组合证据,并用对数空间避免许多小概率相乘后下溢。