🤖 第2章 学习模型
📄 一句话概括

高斯核在七个带宽上的测试误差是 U 形:0.254、0.254、0.107、0.058、0.056、0.065、0.181。 两头都坏:带宽 0.05 时训练误差 0.0001、测试 0.254,它把每个点都穿过去了; 带宽 3.2 时核矩阵有效秩掉到 7,模型被抹成一条粗线。 而 α 的个数七行全是 20,一动没动——核模型的复杂度不在参数个数里。

📝 本节和前面几节的关系

2.1 的 sigmoid 基已经是「局部小台阶」,唯一的问题是中心得由人铺。这一节把这一步也交出去: 每个训练点放一个,宽度用一个参数统管。 所以核模型不是新数学,是线性模型的一次极端化。 它仍然是「对参数线性」,仍然一次闭式解,只是基的个数变成了样本数。

一、把中心交给数据

2.1 里 sigmoid 基的 7 个中心是我用 linspace 铺的。 这在 1 维、30 个点的玩具问题上没问题,到了 256 维就完全没法铺——维数一高, 网格的点数按指数爆炸。 核模型的做法很干脆:中心不用铺,每个训练点就是一个中心。 b 等于 n,基函数是 K(x, x_i)——只跟两个点的距离有关。 于是模型写成:f(x) 等于 Σ α_i 乘 K(x, x_i),i 从 1 到 n。 注意参数从 θ 换成了 α,个数从 b 变成 n。 这个改动看着朴素,效果很猛:不需要知道数据长什么样,只要有一个「像不像」的度量 K,就能拟合。 而「像不像」这件事在高维空间里比「在哪儿」好定义得多。

二、高斯核和它的带宽

最常用的核是高斯核:K(u, v) 等于 exp(负 (u 减 v) 的平方 除以 2h 的平方)。 h 是带宽,控制「多近才算近」。 h 很小时,只有几乎重合的两点才互相认亲,核矩阵接近单位阵。 h 很大时,所有点互相认亲,核矩阵接近「全 1」,秩接近 1。 所以带宽是核模型唯一的复杂度旋钮。 它不像多项式次数那样「加一项」,而是连续地调「多模糊」。 这是它比线性模型好用的地方:复杂度可以微调,不用重选基。 代价是:h 一旦调错,模型会以两种完全不同的方式坏掉。 太小就记噪声,太大就抹细节,而两种坏法的训练误差表现相反——这个后面看表。

三、α 的个数等于样本数

这是核模型最反直觉的一点:参数个数不随特征维数变,随样本数变。 30 个训练点是 30 个 α,100 万个训练点就是 100 万个 α。 教材特意强调了这条,因为它决定了核模型的适用边界: 样本几万以内好用,样本上百万就要换方法(第 3.3 节的随机梯度下降、或者干脆回到参数化模型)。 它的内存也是 O(n 的平方)——核矩阵是 n 乘 n。一万个点就是 1 亿个数,八字节一个,800 MB。 这就是核方法在大数据时代退居二线的直接原因,不是精度不够,是存不下。 还有个好用的性质:求 α 只需要核矩阵 K 本身,不需要知道 φ 是什么。 这叫「核技巧」——K 隐含地把 x 映射到了一个高维(甚至无穷维)空间, 而你永远不用真的算那个映射。 这是第 8.4 节支持向量机能做非线性分类的根基。

四、实测:带宽的 U 形

还是那 30 个点、20 训 10 测,高斯核,加一个极小的岭项 0.01 防病态。

带宽 h α 个数 有效秩 训练 MSE 测试 MSE
0.05 20 20 0.0001 0.254
0.10 20 20 0.0003 0.254
0.20 20 20 0.0011 0.107
0.40 20 19 0.0165 0.058
0.80 20 15 0.0206 0.056
1.60 20 10 0.0265 0.065
3.20 20 7 0.1210 0.181
先看第一行:训练 0.0001,测试 0.254。
训练误差比测试小两千倍,这是最典型的过拟合形态。
注意有效秩那一列:带宽 0.05 时是 20,满秩。
满秩听起来像「信息充足」,其实相反——
核矩阵几乎是单位阵,每个训练点只认它自己,所以它把每个点都穿过去了。
再看最后一行:带宽 3.2,有效秩掉到 7,测试反弹到 0.181。
所有点互相认亲,模型被抹平,连正弦的弯都糊掉了。
中间三行(0.4 到 1.6)的测试误差都在 0.06 左右,贴着噪声方差 0.04。
这就是 U 形的底。
而 α 的个数七行全是 20——所以「调带宽」调的不是参数量,是「这 20 个参数之间怎么分工」。

五、核模型的位置

它比线性模型灵活:不用猜基的形状,只要给一个距离度量。 它比层级模型简单:一次闭式解,没有初值、没有学习率、没有局部极小。 它的短板是规模和维度。 样本多,存不下核矩阵; 特征维数高,核的「远近」就失去意义——高维空间里所有点两两距离都差不多大,这叫距离集中。 所以核方法的主场是「样本几千到几万、特征几十到几百」的中等规模问题。 文本分类、小分子性质预测、基因数据,都是它的传统地盘。 工程上还有一招:先用核模型打基线,再上神经网络。 核模型的调参只有一个 h 加一个 λ,半天就能跑完;神经网络的调参是无底洞。 如果核模型的精度已经够用,就别上深度模型。

六、动手 Demo:高斯核:带宽 0.05 时训练 0.0001、测试 0.25;0.8 时 0.056

同一份 30 个点、20 训 10 测的数据。 七个带宽,每个都解一次(核矩阵加 0.01 的岭项防病态),算训练与测试均方误差, 并用奇异值数出核矩阵的有效秩(大于最大奇异值一亿分之一的个数)。

for h in (0.05, 0.1, 0.2, 0.4, 0.8, 1.6, 3.2):
    def K(A_, B_):
        return np.exp(-((A_[:, None] - B_[None, :]) ** 2) / (2 * h * h))

    Ktr = K(X[TR], X[TR])                       # 20 乘 20 的核矩阵
    alpha = np.linalg.solve(Ktr + 0.01 * np.eye(len(X[TR])), Y[TR])

    mtr = np.mean((K(X[TR], X[TR]) @ alpha - Y[TR]) ** 2)
    mte = np.mean((K(X[TE], X[TR]) @ alpha - Y[TE]) ** 2)

    s = np.linalg.svd(Ktr, compute_uv=False)     # 有效秩
    rank = int(np.sum(s > 1e-8 * s[0]))

实跑输出:

--------------------------------------------------------------------
高斯核:带宽 0.05 时训练 0.0001、测试 0.25;0.8 时 0.056
--------------------------------------------------------------------
  模型                     f(x) 等于 Σ α 乘 K(x, x_i),α 由核矩阵解出
  核                       高斯核 exp(-(u-v)^2 / 2h^2)
  α 的个数                 20 个,等于训练点数,与 x 的维数无关
  岭项                     λ 等于 0.01,不加这一项核矩阵病态时会发散
  最优带宽                 h 等于 0.8(测试 0.056)

  带宽 h   α 个数   有效秩   训练 MSE   测试 MSE
  ---------------------------------------------
    0.05       20       20     0.0001      0.254
    0.10       20       20     0.0003      0.254
    0.20       20       20     0.0011      0.107
    0.40       20       19     0.0165      0.058
    0.80       20       15     0.0206      0.056
    1.60       20       10     0.0265      0.065
    3.20       20        7     0.1210      0.181

  **h 等于 0.05 那一行:训练 MSE 是 0.0001,测试 0.25。**
  **有效秩 20,等于满秩——但这不是「信息多」,恰恰相反:**
  **核矩阵几乎是单位阵,每个训练点只认它自己,所以它把每个点都穿过去了。**
  **这就是核模型的过拟合:不是参数太多,是「每个点都有自己的自由度」。**
  **另一头 h 等于 3.2:有效秩掉到 7,测试反弹到 0.181。**
  **带宽太宽,所有点互相认亲,模型被抹成一条粗线。**
  **所以带宽是 U 形旋钮:太小记噪声,太大抹细节,中间才有 0.056。**
  **而 α 的个数七行全是 20,一动没动。**
  **这就是核模型和线性模型最根本的差别:线性模型靠加基变复杂,核模型靠收紧带宽变复杂,参数量始终等于样本数。**
  **推论很直接:样本越多,核模型要存的东西越多——它的内存是随数据线性涨的。**
  要说明:**带宽是拿测试集挑的,偏乐观;书里本该用交叉验证,第 4.3 节补。**

这段代码的全部内容就一件事:解一个 20 乘 20 的线性方程组。 没有迭代、没有初值、没有随机性——换个带宽重解一次,结果完全可复现。 这是核模型在工程上最讨喜的地方。 「有效秩」这个量要会读。 它数的是核矩阵里「互相独立的方向」有多少个。 带宽小时它等于 n(每个点自成一派),带宽大时它变小(点被合并成几团)。 所以它反映的是「模型实际用了几个自由度」,而不是名义参数个数。 U 形两端的原因完全不同,别混: 左端是「每个点一个自由度」,模型把噪声当信号;右端是「自由度不够」,正弦的弯曲被抹平。 一个是容量过剩,一个是容量不足,都表现为测试误差变大。 这个 U 形在机器学习里无处不在。 第 4 章会把它写成「测试误差等于偏差平方加方差加噪声」——左端是方差大,右端是偏差大。 记住这张表的形状,比记住任何公式都有用。 要说明:带宽是在测试集上挑的,偏乐观。 另外这里的岭项 0.01 只是数值稳定用,不是正经的正则化——正经的 λ 要用交叉验证选,第 4.3 节讲。

30 秒实验

  1. 把 h 从 0.8 拉到 1.2 之间细分五档,测试误差的最低点在哪? 和 0.8 比差多少?想想这点差距值不值得调。
  2. 把岭项从 0.01 改成 1.0,再看第一行(h 等于 0.05)的测试误差。 它会从 0.254 掉下来吗?为什么强岭项能救「过窄带宽」?
  3. 把样本数从 30 加到 200,带宽的最优值会往哪边走? 想清楚「点变密了,同样的带宽覆盖的点更多」这件事。

常见误区

  1. 「核模型是非线性模型」。 它对 x 是非线性的,对 α 是线性的。 求解它的方法还是最小二乘,还是闭式解。 「非线性」这个词要看修饰谁。
  2. 「核模型参数无限多」。 参数就是 n 个 α,有限且明确。 「无穷维」说的是核隐含的映射空间,不是参数个数。 这两个概念经常被混着说。
  3. 「带宽越小越精确」。 带宽小到一定程度,模型就在插值,训练误差归零而测试误差飙升。 Demo 第一行就是证据:0.0001 对 0.254。
  4. 「核方法已经过时了」。 在小样本、低维、需要可复现的场合,它仍然是性价比最高的选择。 深度模型赢在数据量大的场景,不是在所有场景。
自测三问(点开对答案) 1. 为什么核模型的参数个数等于训练点数,而不是特征维数? —— **因为基的个数被人为定成了 n——每个训练点放一个基。** **参数是这些基的系数 α,所以自然也是 n 个。** **特征维数只影响 K 怎么算,不影响有多少个 α。** 2. 带宽 0.05 时核矩阵满秩,为什么反而是坏事? —— **因为满秩的来源是「每个点只认自己」。** **核矩阵接近单位阵,意味着 20 个基互不重叠,模型有 20 个独立自由度去穿过 20 个点。** **训练集被完美拟合,连噪声一起——这就是过拟合。** **有效秩高不等于模型好,要看这些自由度用在了信号上还是噪声上。** 3. 如果有一百万条数据,你会用核模型吗? —— **不会。**核矩阵是 100 万乘 100 万,存不下也算不动。 **该换参数化模型加随机梯度下降(第 3.3 节),或者用随机傅里叶特征把核近似成有限维。** **核方法的天花板是内存,不是精度。**

核模型把「基的中心」交给了数据,但基本身还是固定的形状(高斯核)。 下一节再往前一步:连基的形状也交给训练。这就是层级模型——它自己长出基,而代价是非凸优化。

相关笔记