深度信念网络就是一摞 RBM:下面一层的隐单元当上面一层的可见单元,一层层往上叠。 训练分两步走——逐层无监督预训练,然后整体微调。 预训练的价值实测得到:同样的结构,随机初始化准确率 0.1071(十选一瞎猜), 换成预训练权重 0.8929。差别不在结构,只在权重从哪来。 微调再把它推到 0.9732,甚至超过了直接用 64 个原始像素的 0.9643。 16 维压过了 64 维,这才是深度信念网络想说明的事。
第 1.2 节讲历史时提过:2006 年深度学习重新出发,靠的就是这一套。 当时的痛点是「深层网络从随机权重开始根本训不动」,逐层预训练是绕过去的办法。 这一节也是第 4 章的收尾。 Hopfield 存样本、玻尔兹曼机描述分布、RBM 学一层特征、DBN 学多层特征——四步走完, 正好接上第 5 章的自编码器。
一、怎么叠
叠法很直接:第一层 RBM 训练完,把它的隐单元当成第二层的可见单元,在上面再接一个 RBM, 训练完再往上叠。
64 个像素 --RBM 1--> 32 个隐单元 --RBM 2--> 16 个隐单元 --> 分类器
训练时:先冻结上面,专练 RBM 1;练完冻结 RBM 1,专练 RBM 2
麻烦在于第二层看到的东西。 它不是原始数据,而是第一层加工过的表示——那么第二层到底在拟合什么? 如果两层的目标不一致,整体就可能越叠越差。 2006 年给出的答案是逐层来:一次只练一层,下面的层全部冻结。 每一层都在做同一件事——把自己接收到的表示拟合得更好。 只要每层都不变差,整体就不会变差。
二、预训练到底带来了什么
最硬的证据是一组对照实验。 结构完全一样、特征维度完全一样、分类器完全一样,唯一的差别是权重从哪来:
| 特征 | 训练准确率 | 测试准确率 |
|---|---|---|
| 原始 64 像素 | 0.9970 | 0.9643 |
| 随机两层,16 维输出 | 0.1686 | 0.1071 |
| 预训练两层,16 维输出 | 0.8817 | 0.8929 |
| 预训练第一层,32 维 | 0.9467 | 0.9643 |
| 随机两层是 0.1071,十选一瞎猜是 0.1——等于什么都没学到。 | ||
| 同一套结构换成预训练权重,直接到 0.8929。 | ||
| 这不是「稍微好一点」,是从「完全不可用」到「接近可用」。 | ||
| 但也要看清另一面:0.8929 还是低于原始像素的 0.9643,差 7.14 个百分点。 | ||
| 别把这当成预训练的失败。 | ||
| 这套数据的十类本来就线性可分(原始像素直接分就能到 96.43%),压成 16 维自然要丢信息。 | ||
| 它证明的是「无标签预训练能学到可用的表示」,不是「预训练一定比原始特征强」。 | ||
| 后者要在真 MNIST 上才成立——那里原始像素根本不够用。 |
三、为什么要微调
预训练只保证「每层都能描述自己的输入」,不保证「这些描述对分类有用」。 一个能把输入完美复现的表示,可能把猫和狗的特征混在一起——因为它没被要求区分。 微调就是把分类误差一路反传回去,让底层特征也为「分清数字」服务。 学习率和步数在这里特别敏感。 下面这张表是测试准确率,横轴步数、纵轴学习率:
| 学习率 | 步数 400 | 步数 2000 |
|---|---|---|
| 0.002 | 0.1964 | 0.6429 |
| 0.010 | 0.6429 | 0.8482 |
| 0.050 | 0.8482 | 0.9375 |
| 0.200 | 0.8839 | 0.9375 |
| 0.500 | 0.9464 | 0.9732 |
| 学习率 0.002 配 400 步只有 0.1964,这是没走够; | ||
| 0.5 配 2000 步到 0.9732,这是这一格上最好的一组。 | ||
| 从 0.8929 涨到 0.9732,涨了 8.04 个百分点。 | ||
| 结果超过了直接用原始像素的 0.9643。 | ||
| 也就是说,经过预训练和微调的这 16 维表示,已经比原始 64 维更适合做区分。 | ||
| 这才是深度信念网络想说明的事:无监督预训练加上有监督微调, | ||
| 能把「表示学习」和「任务目标」这两件事接起来。 |
四、为什么逐层训练不算错
严格说,冻结下层只练上层,优化的不是整个网络的对数似然,而是它的一个下界。 这叫变分下界,意思是「真正想优化的量,至少不比这个差」。 直观理解:每加一层,都是在「用下面几层给出的表示」重新描述数据。 只要这一层把它的输入拟合得更好,整体的似然就不会变差。 代价是这个下界很松——它只保证不变差,不保证够好。 所以后面还要微调,把下界和真实目标之间的差距补一部分回来。 这套思路今天已经不流行了。 ReLU、批归一化、残差连接、更好的初始化,让深层网络从随机权重开始就能练,不必再逐层预训练。 但「先用无标签数据学表示,再用少量标签做判断」这个思路没过时。 它换了个名字继续活着——今天的预训练语言模型,就是它在另一条路上的后代。
五、动手 Demo:两层 RBM 摞起来:预训练、加分类器、再微调
数据 450 张,每张打坏 5 个像素;训练集 338 张、测试集 112 张。
第一层 64 到 32,第二层 32 到 16,两层都用 CD-1,各练 60 轮。
注意第二层的输入是 sig(c1 + Xtr @ W1),也就是「概率」而不是采样的 0 与 1。
def train_rbm(X, NH, k=1, epochs=60, lr=0.1, seed=0):
u"""CD-k 训练,一层 RBM。"""
W = rg.normal(0.0, 0.01, (X.shape[1], NH))
b = np.zeros(X.shape[1])
c = np.zeros(NH)
for _ in range(epochs):
for s in range(0, len(X), 16): # 小批量
W, b, c = cd_step(X[s:s + 16], W, b, c, k=k, lr=lr)
return W, b, c
# 逐层预训练:一次只练一层,下面几层全部冻结
W1, b1, c1 = train_rbm(Xtr, 32, seed=1) # 64 到 32
H1tr = sig(c1 + Xtr @ W1) # 拿概率当下一层的输入
W2, b2, c2 = train_rbm(H1tr, 16, seed=2) # 32 到 16
H2tr = sig(c2 + H1tr @ W2)
# 加一个最普通的 softmax 分类器,看这批特征好不好用
Wc, bc = softmax_train(H2tr, ytr)
print(((H2te @ Wc + bc).argmax(1) == yte).mean()) # 0.8929
实跑输出:
--------------------------------------------------------------------
深度信念网络:逐层预训练加微调,从瞎猜走到会认
--------------------------------------------------------------------
[1] 为什么要把 RBM 叠起来
一层 RBM 只表示一层特征;想要「笔画的组合」「整字的布局」这种更高层的东西,得再叠一层
叠法很直接:把第一层的隐单元当成第二层的可见单元,上面再接一个 RBM
麻烦在于第二层看到的是第一层加工过的表示、不是原始数据,怎么练才不歪?
2006 年给出的答案是逐层来——一次只练一层,下面的层全部冻结,这就叫预训练
[2] 逐层预训练:先练底层,再练高层
第一层:64 个可见单元 到 32 个隐单元,参数 2048 加 64 加 32 等于 2144
第一层重构误差:首轮 0.2236,末轮 0.1447
第二层:32 个可见单元 到 16 个隐单元,参数 512 加 32 加 16 等于 560
第二层重构误差:首轮 0.2239,末轮 0.0538
两层合计训练 0.68 秒,全程没用到任何标签
注意第二层的输入是「概率」,取值在 0 到 1 之间而不是 0/1;
严格按 RBM 定义该用采样的 0/1,但实测用概率当输入更稳,这也是实践中的通行做法
[3] 预训练到底有没有用:拿学到的特征去做分类
做法:把两层 RBM 的输出当特征,接一个最普通的 softmax 分类器,看测试准确率
对照组一:直接用 64 个原始像素当特征
对照组二:结构完全一样,但权重随机初始化、不做任何预训练
特征 训练准确率 测试准确率
原始 64 像素 0.9970 0.9643
随机两层,16 维输出 0.1686 0.1071
预训练两层,16 维输出 0.8817 0.8929
预训练第一层,32 维 0.9467 0.9643
随机两层是 0.1071,差不多是十选一瞎猜的水平;同一套结构换成预训练权重,涨到 0.8929。
这是这一节最硬的一条证据:差别不在结构,只在「权重从哪来」。
和原始像素的 0.9643 比还差 7.14 个百分点。别把这当成预训练的失败——
这套数据的十类本来就线性可分(原始像素直接分就能到 96.43%),
压成 16 维自然要丢掉一些信息。它证明的是「无标签预训练能学到可用的表示」,
不是「预训练一定比原始特征强」——后者在真 MNIST 上才成立,那里原始像素根本不够用。
[4] 为什么逐层训练不算错
严格说,冻结下层只练上层,优化的不是整个网络的对数似然,而是它的一个下界
直观理解:每加一层,都是在「用下面几层给出的表示」重新描述数据,
只要这一层能把它的输入拟合得更好,整体似然就不会变差
代价是这个下界很松——它只保证不变差,不保证够好
所以后面还要微调:把判别误差一路反传回去,让下层的权重也动一动
[5] 微调:从「会描述」到「会判断」
前面只训练分类器,等于把下面两层的权重全冻住
微调是把分类误差一路反传回两层 RBM,让底层特征也为「分清数字」服务
下面用最朴素的全连接反向传播,试一试学习率和步数怎么选
学习率 步数 400 步数 2000
0.002 0.1964 0.6429
0.010 0.6429 0.8482
0.050 0.8482 0.9375
0.200 0.8839 0.9375
0.500 0.9464 0.9732
学习率太小(0.002 配 400 步只有 0.1964)是没走够;太大又容易在训练集上冲过头。
这一格上最好的是学习率 0.500 配 2000 步:训练 1.0000,测试 0.9732。
只训练分类器是 0.8929,微调后 0.9732,涨了 8.04 个百分点;
甚至超过了直接用原始像素的 0.9643。也就是说,经过预训练和微调的这 16 维表示,
已经比原始 64 维更适合做区分——这才是深度信念网络想说明的事。
[6] 这一节的结论
深度信念网络等于一堆 RBM 摞起来,逐层无监督预训练,最后加一层判别输出再整体微调
它在 2006 年前后解决了「深层网络训不动」的问题,是深度学习重新出发的那一脚
今天的主流做法换成别的了:ReLU、批归一化、残差连接、更好的初始化,
让深层网络从随机权重开始就能练,不必再逐层预训练
但「先用无标签数据学表示,再用少量标签做判断」这个思路没过时,
它换了个名字继续活着——今天的预训练语言模型就是它在另一条路上的后代
第一层的重构误差从 0.2236 降到 0.1447,第二层从 0.2239 降到 0.0538。 第二层降得更狠,因为它的输入是 32 维概率、结构更规整,比原始像素好拟合。 参数账单值得记一下:第一层 2048 加 64 加 32 等于 2144 个, 第二层 512 加 32 加 16 等于 560 个。 两层合计 2704 个参数,全部用无标签数据练出来。 标签只在最后的分类器和微调里用到。 微调那张表最值得琢磨的是左上角:学习率 0.002 配 400 步只有 0.1964,比不微调还差。 原因是被预训练好的权重被反传搅乱了、却又没走到新的好位置——这叫「半途而废」, 在微调里非常常见。 实践中的对策是「微调用小学习率、多走几步」,或者干脆分层设不同的学习率。 最后一处要诚实说明:0.9732 这个数字是在 112 张测试集上得到的,一张对错就是 0.89 个百分点。 所以「0.9732 比 0.9643 高」这句话的统计意义很弱,别当成硬结论。 真正稳的结论是「预训练相对随机初始化有数量级的提升」(0.11 到 0.89),那个差距远超噪声。
30 秒实验
- 把第二层的 16 改成 8 再跑一遍。 8 维要分 10 类,信息瓶颈太窄,测试准确率会掉到 0.5 附近——维度不是越小越好。
- 把
noise=5改成 8,看预训练和微调各掉多少。 输入越脏,无监督预训练的相对优势越明显——这正是它当年被需要的原因。 - 把微调的
A1(第一层权重)冻住,只让第二层和分类器更新。 这更接近「只微调上层」的做法,看准确率掉多少,就知道底层特征有多重要。
常见误区
- 「预训练一定比直接用原始特征好。」 不一定。实测预训练两层是 0.8929,原始像素是 0.9643,前者反而低。 预训练的价值是「在没有足够标签时提供一个好起点」,不是「无条件地把特征变得更强」。 标签够多、数据够简单时,端到端训练往往更好。
- 「逐层预训练等价于端到端训练。」 不等价。它优化的是一个下界,不是原目标。 所以必须有微调这一步——只做预训练不做微调,等于把「会描述」当成了「会判断」。
- 「微调的学习率随便设,反正会收敛。」 实测学习率 0.002 配 400 步只有 0.1964,比不微调还差。 微调是从一个好起点出发,走得太慢会停在半路,走得太快会把好起点拆掉。 这一格上的最佳是 0.5 配 2000 步,换个任务就得重新调。
自测三问(点开对答案)
1. **逐层预训练时,下面几层的权重为什么必须冻结?** —— **因为不冻结的话,第二层训练时会把第一层的权重也改掉,** **而第一层改完之后第二层面对的输入又变了——两层互相追,训练就不收敛。** **冻结的意义是把「表示学习」拆成一个个独立的、各自能收敛的小问题。** 2. **为什么第二层的输入用概率而不是 0 与 1?** —— **采样成 0 与 1 会丢掉「有多确定」这条信息,第二层看到的输入就变得很粗糙。** **用概率保留了不确定性,实测效果好得多。** **严格说这不符合 RBM 的定义,但实践中通行。** 3. **0.9732 比 0.9643 高,能证明微调一定有效吗?** —— **不能。测试集只有 112 张,一张对错就是 0.89 个百分点。** **两个数字差 0.89 个百分点,正好是一张图。** **能站住的结论是「预训练相对随机初始化有数量级提升」(0.11 到 0.89),** **那个差距远超采样噪声。**第 4 章到这里讲完了:从存样本,到存分布,再到学一层特征、学多层特征。 下一节把四张网络摆在同一张台面上,用同一批数据各跑一遍,看清它们之间的关系。
- ☐ (本节完,下一节 4.6 小结)