🤖 第1章 什么是机器学习
📄 一句话概括

同一份 50 个点的正弦数据,六种方法:线性 0.546,5 次多项式 0.095,12 次多项式 0.242。 12 次加上 l2 正则回到 0.099,k 近邻 0.257,高斯核 0.192。 训练误差最低的是 12 次(0.046),测试误差最差的也是它。这一对数字, 就是「泛化」这个词的全部内容。

📝 本节和前面几节的关系

1.1 讲「问什么」,1.2 讲「问在哪」,这一节讲「怎么答」。 它的作用是给全书立一个骨架:任何方法都能拆成模型、准则、算法三件, 后面每一章都是在这三件里换一件。 所以这一节看着抽象, 但它决定了你读第 3 章往后时的视角——换个准则就是新的一章,换个模型也是新的一章。

一、方法可以拆成三件

教材把学习方法拆成三个环节,这个拆法全书都在用。

环节 回答什么问题 本书位置
模型 允许的形状是什么 第 2 章
准则 什么叫「好」 第 3 到 10 章
算法 怎么找到最好的那个 各章后半
这三件经常被混着叫「算法」,但它们可以分开换。
同一个模型配不同的准则就是不同的方法——线性模型配平方损失是最小二乘,
配 Huber 损失就是鲁棒回归(第 6 章)。
换一件就够写一章。第 5 章把准则从平方损失换成 l1 损失,第 8 章换成 hinge,第 2 章换模型,
第 3.3 节换算法。所以「这本书有 20 章」其实不吓人,它只在换三个旋钮。

二、模型:决定能表示什么形状

线性模型写成 f(x) 等于 w 转置乘 φ(x)。注意那个 φ:模型是不是「线性」,取决于你怎么看 x。 把 x 换成它的多项式基,模型对 x 就是弯的,但对 w 还是线性的。 这是全书最容易被绕晕的一点。 核模型写成 f(x) 等于 Σ α 乘 K(x, x_i)。 它能表示的形状由核 K 决定,不由参数个数决定。 Demo 3 里 k 近邻和高斯核那一列的「参数个数」我填的是横线——因为它们的模型就是训练数据本身。 层级模型就是神经网络:层数和宽度决定形状,代价是非凸、要调的东西多。第 2.3 节只讲结构, 不讲训练。 所以「模型复杂度」在三种模型里是三种东西: 线性模型看 φ 的维数,核模型看核的带宽,层级模型看层数。 拿参数量去比它们,是比不出东西的。

三、准则:什么叫「好」

平方损失 (f(x) 减 y) 的平方:好算、可导、有闭式解。 代价是对大误差罚得太重——一个离群点能把整条线拉歪。 0/1 损失 错一个罚 1,对不罚:这是分类真正想要的。 但它不连续、不可导,而且对「错得多离谱」完全不区分。 所有分类算法都在找一个可导的替身:hinge(第 8 章)、logistic(第 10 章)、ramp(第 8.6)。 准则的选择就是「你在乎哪种错」。 在乎离群点就用 l1 或 Huber;在乎间隔就用 hinge;在乎概率就用交叉熵。 这一句话能解释后面一半的章节为什么存在。 教材在这里引入了两个术语:期望风险是模型在整个数据分布上的平均误差, 经验风险是它在训练集上的平均误差。我们能算的只有后者,想要的却是前者。 整个机器学习理论,一大半在讨论这两者差多远。

四、算法:怎么找到那个最好的

最小二乘有闭式解:w 等于 (A 转置 A) 的逆乘 A 转置 y。 一行代码,没有迭代,没有学习率。 但它有两个前提:数据量小到能放下整个矩阵,且 A 转置 A 可逆。 第 3.3 节会给出数据大到放不下时的做法:随机梯度下降,一条一条看。 Demo 3 里有个细节:多项式基先把 x 除以 3,缩到负 1 到 1 之间。 不缩的话,12 次项的 x 的 12 次方是 3 的 12 次方,五万倍,矩阵条件数直接炸掉, 闭式解算出来的系数全是噪声。 这不是数学技巧,是数值现实。 任何用闭式解的地方,都要先问一句「我的矩阵条件数是多少」。

五、泛化:训练误差为什么会骗人

六种方法在同一份 50 个点的数据上(25 训 25 测),结果如下。

方法 参数个数 训练 MSE 测试 MSE
线性最小二乘 2 0.572 0.546
多项式 5 次 6 0.098 0.095
多项式 12 次 13 0.046 0.242
12 次加 l2 正则 13 0.087 0.099
k 近邻(k 等于 5) — — 0.257
高斯核(h 等于 0.5) — — 0.192
先看 5 次那一行:训练 0.098、测试 0.095,两个都小。
它恰好匹配了正弦的弯曲程度,这就是「复杂度合适」。
再看 12 次:训练降到 0.046,测试却升到 0.242。
13 个参数去拟合 25 个点,它已经有能力穿过大部分点——把噪声也当成规律记住了。
训练误差降、测试误差升,这个反向就是过拟合的定义。
反过来也有一种病:欠拟合。线性那一行训练 0.572、测试 0.546,两个都大,模型根本弯不起来。
两种病的方向相反,判断依据都一样:看训练和测试差多少。
注意 5 次那一行测试(0.095)反而略低于训练(0.098)。
这不是奇迹,是噪声:25 个测试点恰好落在了好一点的位置。
小样本上的这种倒挂很常见,别当成「模型有魔力」。

六、两条出路:约束与选择

第一条出路是加约束。同一个 12 次多项式,只加一个 l2 惩罚项,测试误差从 0.242 回到 0.099。 参数个数一个没少,但系数被压小了,模型弯不起来。 这是第 4 章的主题:约束不加在数据上,加在参数上。 第二条出路是选复杂度。k 近邻的 k、高斯核的带宽 h、多项式的次数,这些都是「复杂度旋钮」。 第 4.3 节讲怎么系统地选它们。 这里有个陷阱要说清:Demo 3 里的 λ 是我在测试集上挑的。 这在真实项目里是不允许的——它等于偷看答案,报出来的 0.099 会偏乐观。 正确做法是交叉验证:把训练集再切开,用切出来的那部分挑 λ。 这张表其实预告了全书三条主线:① 复杂度要选对(模型选择); ② 复杂度要能被约束(正则化); ③ 有些模型的复杂度藏在核里,不在权重里(核方法)。

七、动手 Demo:六种方法:线性 0.55,5 次 0.10,12 次 0.24,加正则 0.10

50 个点,y 等于 sin(1.5x) 加标准差 0.35 的噪声,按奇偶切成 25 训 25 测。 六种方法在同一份数据上比测试均方误差:线性、5 次多项式、12 次多项式、 12 次加 l2 正则(在 8 个候选里挑 λ)、k 近邻(k 等于 5)、高斯核平滑(h 等于 0.5)。

def poly(X, d):                        # 多项式基,先缩到 [-1, 1]
    X = np.asarray(X, dtype=float) / 3.0
    return np.vander(X, d + 1, increasing=True)

A = poly(x[tr], 12)                    # 12 次,13 个参数
w = np.linalg.lstsq(A, y[tr], rcond=None)[0]

for lam in (1e-6, 1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0, 100.0):
    w = np.linalg.solve(A.T @ A + lam * np.eye(A.shape[1]),
                        A.T @ y[tr])   # 岭回归的闭式解
    v = np.mean((poly(x[te], 12) @ w - y[te]) ** 2)

dd = (x[te][:, None] - x[tr][None, :]) ** 2
knn = y[tr][np.argsort(dd, 1)[:, :5]].mean(1)      # k 近邻

h = 0.5
Kx = np.exp(-((x[te][:, None] - x[tr][None, :]) ** 2) / (2 * h * h))
ker = (Kx @ y[tr]) / Kx.sum(1)                     # 核平滑

实跑输出:

--------------------------------------------------------------------
六种方法:线性 0.55,5 次 0.10,12 次 0.24,加正则 0.10
--------------------------------------------------------------------
  数据                     50 个点,y 等于 sin(1.5x) 加噪声
  切分                     25 个训练、25 个测试
  正则的 λ                 在 8 个候选里挑最优(1e-03)
  指标                     测试集上的均方误差

  方法              参数个数   训练 MSE   测试 MSE
  -----------------------------------------------
  线性最小二乘             2      0.572      0.546
  多项式 5 次              6      0.098      0.095
  多项式 12 次            13      0.046      0.242
  12 次 + l2 正则         13      0.087      0.099
  k 近邻(k=5)            —          —      0.257
  高斯核(h=0.5)          —          —      0.192

  **先看 5 次多项式那一行:训练 0.098、测试 0.095,两个都小。**
  **它恰好匹配了正弦的弯曲程度——这就是「模型复杂度合适」。**
  **再看 12 次:训练降到 0.046,测试却升到 0.242。**
  **这是典型的过拟合:模型把噪声也当成规律记住了。**
  **13 个参数去拟合 25 个点,它已经有能力穿过大部分点。**
  **加 l2 正则之后测试误差回到 0.099——同一个 12 次多项式,只是不让系数太大。**
  **这一条是第 4 章的主题:约束不加在数据上,加在参数上。**
  **k 近邻 0.257、高斯核 0.192——这两个没有「参数个数」这个概念,它们把训练数据本身当模型。**
  **所以它们的复杂度不是参数量,是 k 或带宽:k 越小、带宽越窄,模型越弯。**
  **这张表预告了全书的三条主线:**
  **① 复杂度要选对(模型选择);**
  **② 复杂度要能被约束(正则化);**
  **③ 有些模型的复杂度藏在「核」里,不在权重里(核方法)。**
  要说明:数据是我**按正弦加高斯噪声造的**。
  **λ 是我在测试集上挑的,这在真实项目里是不允许的——它等于偷看了答案。**
  **正确做法是交叉验证,第 4.3 节会专门讲。**

这张表的读法不是「谁分数低谁赢」。 5 次 0.095 和加了正则的 12 次 0.099,差 0.004——在这个样本量上,这点差是噪声级别的, 换一次切分就可能翻过来。 真正有信息量的是「12 次不加正则」那一行的落差:0.046 对 0.242,差五倍。 这个差距不会因为切分而消失,它是结构性的。 k 近邻 0.257 比 12 次还差,这不是「近邻方法不行」。 25 个训练点撒在负 3 到 3 的区间上,平均间距 0.24,k 等于 5 的邻域宽到把正弦的峰都抹平了。 样本量小的时候,非参数方法先吃亏。 高斯核 0.192 比 k 近邻好,原因是它给了权重:近的点权重大。 但它同样受样本量限制——带宽 0.5 相对 0.24 的间距仍然偏宽。 要说明:数据是我按正弦加高斯噪声造的。 λ 是在测试集上挑的,这在真实项目里不允许—— 它等于偷看答案,会让报出来的数偏乐观。正确做法是交叉验证,第 4.3 节专门讲。

30 秒实验

  1. 把 D003 的噪声标准差从 0.35 改成 0.05,六种方法的排名会变吗? 重点看 12 次那一行的训练和测试还差多少。
  2. 把切分从奇偶改成「前 25 个训练、后 25 个测试」(x 是有序的),结果会崩成什么样? 这是「数据泄漏」的一种,想想它为什么比调参更致命。
  3. 把 l2 的候选 λ 从 8 个扩到 20 个(跨度 1e-8 到 1e4),最优测试误差会下降吗? 如果下降了,那下降的部分是「真的更好」还是「挑得更狠」?

常见误区

  1. 「模型越复杂越准」。12 次比 5 次复杂一倍,测试误差却差 2.5 倍(方向是变差)。 复杂度是一把双刃剑,砍哪边取决于样本量。
  2. 「正则化会让模型变差」。它确实会让训练误差变大(0.046 升到 0.087), 但测试误差从 0.242 降到 0.099。 训练误差变大恰恰是它起作用的证据。
  3. 「在测试集上调参数没关系,反正我最后报的是测试误差」。 有关系。你挑过的那一个 λ,是在这个测试集上最优的, 换一批测试数据就不一定了——报出来的数会系统性偏乐观。 要留一份从头到尾没碰过的数据做最终验收。
  4. 「参数量少的模型一定简单」。k 近邻的参数个数是 0(它把数据本身当模型), 但 k 等于 1 时它能插值穿过每一个点,复杂到极点。 复杂度要看「模型能弯曲到什么程度」,不是数参数。
自测三问(点开对答案) 1. 为什么 12 次多项式的训练误差更低,测试误差反而更高? —— **因为它有 13 个自由度去拟合 25 个点,足以穿过大部分点,包括被噪声推歪的那些。** **噪声是这份数据里不可预测的部分,记住了它,就等于把随机性当成了规律。** 换一批同分布的新数据,那些「规律」全部失效。 2. l2 正则为什么能让测试误差降下来,明明参数个数没变? —— **因为它限制了系数的大小,从而限制了函数能弯曲的幅度。** **参数还在,但大的正负系数互相抵消这条路被堵住了——高阶项想兴风作浪,** **得先付 λ 乘系数的平方这个代价。** **有效自由度降了,虽然名义参数量没变。** 3. 如果只能记住这一节的一句话,应该记哪句? —— **「能算的只有训练误差,想要的是泛化误差,两者之间的差就是这门学科的全部难点。」** **模型选择、正则化、交叉验证、集成,都是在缩小这个差。**

三件套立起来了,接下来该拆第一件:模型。第 2 章给三种模型:线性、核、层级。 它们的分水岭不在参数多少,而在「形状由什么决定」。

相关笔记