📗 第5章 自编码器
📄 一句话概括

这一节要回答一个很实际的问题:先用无标签数据预训练,能省下多少标注成本? 做法是把标签数量当变量,从 10 张扫到 320 张。 结果有点扫兴:训练步数给足(2500 步)时,预训练几乎没有优势,六行里只有两行是正的。 把训练预算收窄到 150 步,差距立刻出来:随机初始化 0.268,预训练 0.386,高 11.8 个百分点。 但到 600 步就追平了——预训练给的是起跑线,不是终点线。

📝 本节和前面几节的关系

上一节证明了「能叠起来」,这一节要证明「叠起来值得」。 教材的说法是预训练能大幅提升效果,这一节把它放在可测的场景里验一遍。 结论比教材更细:预训练的收益取决于「训练是否充分」「标签是否够用」。 这也是这套笔记一直强调的:任何方法的收益都有前提,前提比结论重要。

一、场景:标签贵,数据便宜

真实项目里,无标签数据往往一大堆,带标签的只有几十张。 标注要花钱花时间,收集原始数据几乎不要钱。 所以「能不能用无标签数据」直接决定了项目的成本。 两条路线,同一个网络结构(64 到 32 到 16 到 10,参数量完全相同):

路线 做法
甲:随机初始化 只用那 N 张带标签的图训练整个网络
乙:预训练加微调 先用 400 张无标签图逐层预训练,再用 N 张标签微调全部权重
注意两条路线的差别只有一处:权重从哪来。
结构、参数量、优化器、学习率全都一样——这是控制变量。
如果两条路线结果不同,那一定是「起点」造成的。

二、第一次扫描:标签数

先把训练步数给足(2500 步全批量),只改标签数量。 每组跑 5 个随机种子取平均。

标签数 路线甲 随机 路线乙 预训练 差距
10 0.2240 0.2200 -0.0040
20 0.2120 0.2160 +0.0040
40 0.4560 0.4160 -0.0400
80 0.7680 0.7560 -0.0120
160 0.9200 0.9000 -0.0200
320 1.0000 1.0000 +0.0000
这张表的结果对预训练不利:六行里只有两行是正的,其余都持平或更差。
如果就此收尾,结论会是「预训练没用」——但那是错的。
问题出在实验设计:训练步数给得太足了。
2500 步全批量,两条路线都跑到了各自的天花板,起跑线的差别被彻底抹平。
要看出预训练的价值,得把「训练预算」也当变量。

三、第二次扫描:训练预算

固定 40 张标签,只改训练步数。 这次每组跑 10 个随机种子,把标准差也报出来——不然分不清差距和运气。

训练步数 路线甲 随机 路线乙 预训练 差距
150 0.268 ± 0.056 0.386 ± 0.058 +0.118
300 0.438 ± 0.044 0.484 ± 0.066 +0.046
600 0.486 ± 0.050 0.482 ± 0.072 -0.004
1200 0.492 ± 0.059 0.488 ± 0.071 -0.004
150 步时差距最大:0.268 对 0.386,高 11.8 个百分点。
两边标准差都是 0.05 到 0.07,所以这 11.8 个百分点不是运气,是真差距。
到 600 步两者就追平了,再往后一路贴着走,差距落在噪声里。
所以预训练真正给的是「起跑线」,不是「终点线」。
它省下的不是「最终精度」,而是「达到某个精度要花的时间或标签」。
这个说法比「预训练能提升准确率」更准确,也更有用。
因为现实中你的训练预算总是有限的——要么算力有限,要么时间有限。
预算越紧,预训练的收益越大。

四、为什么起点能这么值钱

随机初始化下,网络要先学会「怎么从像素里看出笔画」,再学会「哪几个笔画组成几」。 第一件事需要大量样本,第二件事只需要少量标签。 预训练做的事,就是提前用无标签数据把第一件事学会,把标签全留给第二件事。 于是有限的标签不会被浪费在「学看」上, 可以直接「学认」——这就是 150 步那一栏能高 11.8 个百分点的原因。 这条结论有三条边界,缺一条就不成立:

边界 说明
同分布 无标签数据要和任务同分布;拿手写数字预训练去认路牌,帮不上忙
预算紧 训练预算越紧、标签越少,收益越大;预算一放宽,收益迅速消失
成本可控 预训练要额外一次前向反向、多一套超参数,不是免费的
三条同时成立才划算。
很多工程判断就卡在这里:方法本身没错,但在你的场景里前提不成立。

五、动手 Demo:两次扫描:标签数量与训练预算,看预训练到底省了什么

网络是 64 到 32 到 16 到 10,两层 tanh,输出 softmax。 「微调」在这个 Demo 里是真的用分类损失反传到最底层,不是只训最后那一层。 代码里 fit_classifier 的 net 参数就是起点:传随机权重是路线甲,传预训练权重是路线乙。

def fit_classifier(X, y, net, steps=2500, lr=0.1, seed=0):
    u"""两层 tanh 加 softmax,整体用分类损失反传(这才是「微调」)。"""
    Wc = rg.normal(0.0, 0.01, (16, 10))
    bc = np.zeros(10)
    W1, W2, b1, b2 = net
    for _ in range(steps):
        A1, A2 = forward(X, (W1, W2, b1, b2))
        p = softmax(A2 @ Wc + bc)
        g = (p - Y) / n
        d2 = (g @ Wc.T) * (1.0 - A2 * A2)
        d1 = (d2 @ W2.T) * (1.0 - A1 * A1)
        Wc -= lr * (A2.T @ g)
        W2 -= lr * (A1.T @ d2)
        W1 -= lr * (X.T @ d1)
    return (W1, W2, b1, b2, Wc, bc)


# 路线甲:随机初始化,只用 N 张标签
net0 = (rg.normal(0, 0.1, (64, 32)), rg.normal(0, 0.1, (32, 16)),
        np.zeros(32), np.zeros(16))
m = fit_classifier(Xs, ys, net0, steps=2500)

# 路线乙:先用无标签数据预训练,再用同样的 N 张标签微调
p1 = train_ae(Xtr, Xtr, 32, seed=31)
p2 = train_ae(np.tanh(Xtr @ p1[0] + p1[1]), None, 16, seed=32)
pre = (p1[0], p2[0], p1[1], p2[1])
m = fit_classifier(Xs, ys, pre, steps=2500)

实跑输出:

--------------------------------------------------------------------
在预训练中的应用:预训练给的是起跑线
--------------------------------------------------------------------
[1] 真实场景:无标签的图一大堆,带标签的只有几十张
  标注要花钱花时间,收集原始数据几乎不要钱——所以「能不能用无标签数据」很值钱
  这一节要回答的问题:先用无标签数据预训练,能不能省下标注费用?
  做法是把标签数量当成变量,从 10 张扫到 320 张,看两条路线各自的表现

[2] 两条路线,同一个网络结构
  网络都是 64 到 32 再到 16 再到 10,参数量完全相同
  路线甲:随机初始化,只用那 N 张带标签的图训练
  路线乙:先用 400 张无标签图逐层预训练两层自编码器,再用那 N 张标签微调全部权重
  每组跑 5 个随机种子取平均,免得把运气当成结论

  先做预训练(只做一次,与标签量无关)
  预训练完成:第一层 64 到 32,第二层 32 到 16,全程没看标签

[3] 第一步先看「训练给足」时的情况
  标签数    路线甲 随机   路线乙 预训练   差距
  10        0.2240        0.2200          -0.0040
  20        0.2120        0.2160          +0.0040
  40        0.4560        0.4160          -0.0400
  80        0.7680        0.7560          -0.0120
  160       0.9200        0.9000          -0.0200
  320       1.0000        1.0000          +0.0000

  这张表的结果对预训练不利:六行里只有两行是正的,其余都持平或更差。
  别急着下「预训练没用」的结论——这个实验设计有问题:训练步数给得太足了。
  2500 步全批量,两条路线都跑到了各自的天花板,起跑线的差别被彻底抹平。
  要看出预训练的价值,得把「训练预算」也当变量。

[4] 把训练预算收窄,起点优势立刻显出来
  固定 40 张标签,只改训练步数;这次每组跑 10 个随机种子,把波动也报出来
  训练步数    路线甲 随机     路线乙 预训练   差距
  150         0.268±0.056     0.386±0.058     +0.118
  300         0.438±0.044     0.484±0.066     +0.046
  600         0.486±0.050     0.482±0.072     -0.004
  1200        0.492±0.059     0.488±0.071     -0.004

  150 步时差距最大:随机初始化 0.268,预训练 0.386,高 11.8 个百分点。
  两边标准差都是 0.05 到 0.07,所以这 11.8 个百分点不是运气,是真差距。
  到 600 步两者就追平了,再往后一路贴着走,差距落在噪声里。
  所以预训练真正给的是「起跑线」,不是「终点线」。
  它省下的不是「最终精度」,而是「达到某个精度要花的时间或标签」。

[5] 为什么起点能这么值钱
  随机初始化下,网络要先学会「怎么从像素里看出笔画」,再学会「哪几个笔画组成几」
  第一件事需要大量样本,第二件事只需要少量标签
  预训练做的事,就是提前用无标签数据把第一件事学会,把标签全留给第二件事
  于是有限的标签不会被浪费在「学看」上,可以直接「学认」——
  这就是 150 步那一栏能高 11.8 个百分点的原因。

  这条结论的边界有三条:
  一、无标签数据要和任务同分布。拿手写数字预训练、去认路牌,帮不上忙。
  二、训练预算越紧、标签越少,收益越大;预算一放宽,收益迅速消失。
  三、预训练不是免费的:多一次前向反向、多一套超参数要调。
  判断标准很实际:标注成本高、无标签数据多、算力或时间紧——三条同时成立才划算。

[6] 今天它变成了什么
  这套「先无标签预训练、再有标签微调」的范式,今天叫「预训练加微调」,
  只是积木从自编码器换成了 Transformer,数据量从几百张换成了几十亿 token
  当年是为了让深层网络训得动,今天是为了让模型先学会语言再学任务
  动机变了,形状没变;而且当年那条纪律也没变——预训练省的是时间,不是上限

第一次扫描的结果对预训练不利,这里没有藏起来。 10 张标签(每类 1 张)时两条路线都只有 0.22 左右,接近十选一瞎猜。 这说明 10 张标签确实太少了,预训练也救不回来——它只能改善起点,不能凭空造信息。 第二次扫描才是这一节的落点。 150 步的差距是 11.8 个百分点,而标准差只有 0.056 到 0.058,这个差距是实数,不是抽样波动。 到 600 步时差距变成负的,说明随机初始化的版本后来居上——它需要的只是时间。 还有一个细节值得说:为什么第一次扫描里 320 张标签两个都是 1.0000? 因为这套数据太容易了,320 张已经覆盖全部变化,谁起步都一样。 这又一次说明:任务难度决定了你能不能测出差异。 最后一段是这一节的诚实收尾:预训练省的是时间,不是上限。 这句话在今天的预训练语言模型上依然成立。 它们真正省下的是「从零学语言」的那部分算力,不是模型能力的上限。

30 秒实验

  1. 把第一次扫描的步数从 2500 改成 300,看差距怎么变。 预训练那一列会明显占优——这就是把训练预算这个变量调紧的效果。
  2. 把无标签数据从 400 张减到 100 张再做预训练。 预训练的特征会变差,起点优势缩小——无标签数据也不是白给的,量要够。
  3. 把 lr 从 0.1 改成 0.5 再跑第二次扫描。 两条路线都会更快达到天花板,差距出现的步数会往前移。

常见误区

  1. 「预训练一定提升最终准确率。」 实测训练给足时六行里只有两行是正的。 预训练改善的是起点和收敛速度,不是能力的上限。 说「提升准确率」时一定要带上条件:标签少、预算紧。
  2. 「无标签数据越多越好。」 要看分布是否一致,还要看量是否足够。 分布不一致时,预训练学到的是另一个世界的规律,反而有害。 这也是迁移学习里最常踩的坑。
  3. 「小样本时预训练能救场。」 10 张标签时两条路线都只有 0.22,预训练救不回来。 信息量不够就是不够,起点好也补不上。 这时候该做的是加数据、减模型容量,而不是指望预训练。
自测三问(点开对答案) 1. **为什么训练给足时,预训练的优势会消失?** —— **因为两条路线最终都能爬到各自的天花板,起点的差别被时间抹平了。** **预训练改变的是「多快爬到」,不是「能爬多高」。** **所以评估预训练价值时,必须把训练预算当变量,否则测不出来。** 2. **「预训练给的是起跑线,不是终点线」怎么理解?** —— **它让你在同样步数下走得更远(150 步时高 11.8 个百分点),但走足够久之后,** **两条路线到达的地方差不多(600 步后追平)。** **所以它省的是时间和标注,不是精度的上限。** 3. **预训练在什么条件下才值得做?** —— **三条同时成立:无标签数据与任务同分布、标签少或训练预算紧、愿意承担额外的训练开销。** **缺一条就要重新算账——特别是第一条,分布不一致时预训练可能拖后腿。**

第 5 章到这里讲完了:普通自编码器、降噪、稀疏、栈式,四种改法。 下一节把它们摆在同一个台面上,同时和第 4 章的 RBM、 DBN 逐项对照——看清楚这两章到底在解决同一个问题的哪两个侧面。

相关笔记