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

同一个求解器、同一份 30 个点的数据,只换基函数,测试误差从 0.664 掉到 0.054。线性 0.664, 多项式 5 次 0.077,三角 3 对 0.060,sigmoid 7 个 0.054。 这四种都算「线性模型」——它们对参数 w 是线性的,一次最小二乘就解完。但对 x 一点都不线性。 线性模型的表达能力,全在人选的基上;模型自己不长形状。

📝 本节和前面几节的关系

第 1 章讲了「问什么」和「怎么答」,这一章开始拆第一件:模型。 模型回答的是「允许的形状是什么」。 2.1 是三种模型里最基础的一种。 它的形式定下来之后,第 3 章立刻接上「怎么求参数」——最小二乘。 所以这一节真正的产出是一个可代进去的公式,不是概念。

一、一般形式:基函数的线性组合

教材给的式子是一行: f(x) 等于 Σ θ_j 乘 φ_j(x),j 从 1 到 b。写成向量就是 f(x) 等于 θ 转置乘 φ(x)。 这里的 φ 叫基函数,θ 叫参数。b 是基的个数,也就是模型的自由度。 θ 有多少个,模型就有多能弯——但前提是那些 φ 本身是弯的。 记号要认清:φ(x) 是把 x 变成 b 维向量的那个映射,θ 是 b 维的参数。 x 可以是 1 维、10 维、256 维,b 和它没关系。 这个式子之所以重要,是因为它对 θ 是线性的:把它写成矩阵形式 A θ,A 的第 i 行是 φ(x_i) 转置。 于是「求最优 θ」就变成解一个线性方程组——这是全书最省事的一次。

二、「线性」指的是对参数线性

这是最容易绕晕的一句,值得单独说清。 f(x) 等于 θ 转置乘 φ(x),对 θ 是线性的,对 x 完全可以是弯的。 把 φ 取成 (x, x 的平方, x 的 3 次方),画出 f 就是一条抛物线——但求解它的方法还是最小二乘, 还是一次算完。 反过来,对 x 线性的模型反而更弱:f 等于 a 乘 x 加 b,只能画直线。 所以「线性模型」这个名字容易误导,它是「关于参数线性」的模型。 这条性质的好处很实在:不管 φ 多复杂,求解永远是一次闭式解,没有迭代、没有学习率、没有初值。 第 3 章会把这个性质用到极致。

三、三种常用的基

多项式基。 φ 取 1、x、x 的平方、一直到 x 的 b 减 1 次方。 它的问题是「一头翘一头沉」:区间中间挺准,两端容易飞。 而且次数一高,矩阵条件数就爆——Demo 里我先把 x 除以 3 缩到负 1 到 1,就是为了压住它。 三角基。 φ 取 sin(πkz) 与 cos(πkz),k 从 1 到 m。 它天然带周期性,画出来像一条条等距的波浪。 对周期信号好用,对单调趋势就不好用。 sigmoid 基。 φ 取 1 除以 (1 加 exp(负 (x 减 c) 除 s)),c 是中心。 它是一个「台阶」——每个基只在自己中心附近从 0 爬到 1。 把若干个台阶按不同高度叠加起来,就能拼出任意曲线,这就是它的威力。 三种基的差别,本质上是对「形状」的三种先验: 多项式假设「平坦、光滑」,三角假设「周期」,sigmoid 假设「局部、分段」。 你选哪一种,等于在告诉模型「我认为答案长这样」。

四、实测:只换基,误差差一个数量级

30 个点,y 等于 sin(1.5x) 加标准差 0.2 的噪声,随机抽 20 个训练、10 个测试。

基函数 个数 训练 MSE 测试 MSE
线性(只有 x) 2 0.504 0.664
多项式 5 次 6 0.029 0.077
三角函数 3 对 7 0.070 0.060
sigmoid 7 个 8 0.024 0.054
第一行是关键对照:只有 x 和常数两项时,测试 MSE 0.664,和「全部预测平均值」差不多。
它连正弦的一个弯都画不出来。
后三行的测试误差都在 0.05 到 0.08,逼近噪声方差 0.04。
基一换,同一个求解器从「废物」变「够用」。
三角基(0.060)占了个便宜:它的频率是 1.05、2.09、3.14,而 sin(1.5x) 正好夹在头两个之间。
换成真实数据,这个便宜就没了。
sigmoid 基(0.054)最好,而它藏着一个关键伏笔:每个基只管自己附近一段,
把中心铺开就等于「局部平滑」。
下一节的核模型干的正是这件事——只不过中心不再由人铺,而是直接放到每个训练点上。

五、模型的边界在哪里

线性模型的极限由 b 决定,也由 φ 决定。 b 太小,弯不起来(欠拟合);b 太大、φ 又选得不好,两端乱飞(过拟合)。 这两个毛病第 4 章都会用正则化来处理。 但更要紧的限制是:它不会自己发现形状。 你给多项式基,它就只会画多项式;你给三角基,它只会画波浪。 数据的形状如果不在你选的基张成的空间里,参数再多也学不到。 所以线性模型的实际工作流是「先看图,再选基」,这一步没有理论指导。 2.2 和 2.3 两种模型都在绕开这个人工步骤: 一个把中心交给数据,一个把基交给训练。

六、动手 Demo:换基函数:线性 0.66,多项式 0.077,三角 0.060,sigmoid 0.054

30 个点,x 在负 3 到 3 之间均匀取,y 等于 sin(1.5x) 加标准差 0.2 的噪声,随机抽 20 个训练、 10 个测试。四种基都用同一个求解器:把基矩阵 A 和 y 丢进最小二乘,一次算完。

def phi_lin(z):                       # 2 个基:常数与 x
    z = np.asarray(z, dtype=float)
    return np.column_stack([np.ones_like(z), z])

def phi_poly(z):                      # 6 个基,先缩到 [-1, 1]
    z = np.asarray(z, dtype=float) / 3.0
    return np.vander(z, 6, increasing=True)

def phi_tri(z):                       # 7 个基:1 加 3 对正余弦
    z = np.asarray(z, dtype=float) / 3.0
    cols = [np.ones_like(z)]
    for k in (1, 2, 3):
        cols.append(np.sin(np.pi * k * z))
        cols.append(np.cos(np.pi * k * z))
    return np.column_stack(cols)

def phi_sig(z):                       # 8 个基:7 个台阶加常数
    z = np.asarray(z, dtype=float)
    cs = np.linspace(-3.0, 3.0, 7)
    return np.column_stack([np.ones_like(z)] +
        [1.0 / (1.0 + np.exp(-(z - c) / 0.9)) for c in cs])

A = phi_sig(X[TR])                    # 一次最小二乘,没有迭代
w = np.linalg.lstsq(A, Y[TR], rcond=None)[0]

实跑输出:

--------------------------------------------------------------------
换基函数:线性 0.66,多项式 0.077,三角 0.060,sigmoid 0.054
--------------------------------------------------------------------
  数据                     30 个点,y 等于 sin(1.5x) 加噪声 0.2
  切分                     随机抽 20 个训练、10 个测试
  求解方式                 四种全是一次 lstsq,没有任何迭代
  基函数来自               人手工指定的,不算学出来的

  基函数           个数   训练 MSE   测试 MSE
  ------------------------------------------
  线性(只有 x)      2      0.504      0.664
  多项式 5 次         6      0.029      0.077
  三角函数 3 对       7      0.070      0.060
  sigmoid 7 个        8      0.024      0.054

  **四行里的后三行,教材都算「线性模型」——它们对 w 是线性的。**
  **对 w 线性,才意味着能写成 A 乘 w,才能一次 lstsq 解出来。**
  **但它们对 x 一点都不线性:多项式、三角、sigmoid 画出来都是弯的。**
  **这就是教材那句「线性模型并不只能表示直线」的全部含义。**
  **四行的落差就是本节最硬的事实:同样的 x,同样的 w 求解器,只换基,测试 MSE 从 0.66 掉到 0.054。**
  **三角基(0.060)占了便宜:它的频率是 1.05、2.09、3.14,而 sin(1.5x) 正好夹在头两个之间。**
  **换成真实数据,这个便宜就没了——所以第 2 章后面两种模型都在想办法「别靠人猜基」。**
  **sigmoid 基最好(0.054),它是局部基:每个基只管自己附近一段。**
  **注意它已经非常接近下一节的核模型——核模型干的事,就是把「中心」也交给数据决定,不再由人铺。**
  要说明:**基函数是我手选的,参数 w 是算的。**
  **这也暴露了线性模型的老底:表达能力全靠人给的基,模型自己不长形状。**

四行代码的区别只有 phi 那一个函数,后面三行完全一样。 这就是「线性模型」这个框架的价值:换基不用改求解器。 第一行 0.664 这个数别跳过。 它约等于 y 的标准差平方——也就是说,只给一个 x 和常数项,模型等于什么都没学。 这条基线以后会反复用到:任何回归先算「全填平均值」的误差。 多项式那行训练 0.029、测试 0.077,差 2.6 倍。 这个差不算大,但已经能看出「五次多项式在两端开始晃」。 如果测试点恰好在端点附近,这个数会难看很多——我第一次跑就是这样, 等间隔切分让测试集吃到了全部端点,误差飙到 2.0。 sigmoid 基这一行的 0.054,其实是全书一个重要转折点。 它说明「局部小台阶」这种基非常能打。 核模型不需要发明新东西,它只是把这个想法推到极端:每个训练点都放一个台阶, 宽度由带宽统一控制。 要说明:基函数是我手选的,参数是算的。 这是线性模型真实的工作方式:人负责「形状的大方向」,机器负责「每个基的系数」。

30 秒实验

  1. 把多项式次数从 5 改到 9,测试 MSE 会怎么动? 先猜,再跑。想清楚「训练降、测试升」出现在第几次。
  2. 把 sigmoid 基的中心从 7 个减到 3 个,再把宽度 s 从 0.9 改到 0.3,四种组合里哪一种最差? 这个结果说明了「个数」和「宽度」哪个更要紧?
  3. 把 phi_lin 换成 [1, x, x 的平方] 三个基,只加一项,测试误差能好多少? 为什么加一项就够好很多,而加到 8 项就好不动了?

常见误区

  1. 「线性模型只能拟合直线」。 它拟合的是参数的线性组合,不是 x 的直线。 把 φ 换成多项式,它画的就是曲线。 「线性」这个词修饰的是参数,不是图像。
  2. 「基函数越多越好」。基多了,矩阵 A 变高变瘦,最小值还在, 但系数会变得很大、彼此抵消,边界处开始剧烈摆动。 b 大于样本数时甚至有无穷多组解,全都完美拟合训练集。
  3. 「选基是算法的事」。 在本书的线性模型里,选基完全是人干的。 机器只做「给定基,求最优系数」这一件事。 所以基选错了,调参调到天亮也没用。
  4. 「对 x 做非线性变换就等于非线性模型」。 不对。变换完之后如果还是对参数线性,那就是线性模型,只是换了个坐标系。 真正意义上的非线性模型,参数进入的方式是非线性的(比如 2.3 的层级模型)。
自测三问(点开对答案) 1. 为什么说「线性模型」这个名字容易误解? —— **因为它修饰的是参数,不是输入。** **f 等于 θ 转置 φ(x),对 θ 线性,对 x 可以任意弯。** **判断标准只有一条:参数是不是以一次方的形式出现。** 2. 多项式基为什么要先把 x 缩到负 1 到 1? —— **为了压住基矩阵的条件数。**x 到 3 时,9 次项是 3 的 9 次方,接近两万; **基的各列量级差五六个数量级,A 转置 A 就接近奇异,解出来的系数全是数值噪声。** **缩放不改变模型能表示的函数,只改变求解的数值稳定性。** 3. 四种基里 sigmoid 最好,能据此说「sigmoid 基最优」吗? —— **不能。**这份数据是一个光滑的正弦, **sigmoid 铺开本质上是分段平滑,正好对上;三角基差一点是因为频率没踩准。** **换一个带尖锐跳变的目标,多项式就会明显更差、sigmoid 更好;** **换一个长周期信号,三角基又会赢。** **基的选择没有普适最优,只有「和目标形状是否匹配」。**

线性模型的短板很明确: 基是人选的。下一节换一个思路—— 不预设中心,直接把每个训练点都当成一个基的中心,宽度统一交给一个带宽参数。这就是核模型。

相关笔记