跳到主要内容

数据截至 (上游 commit c187ef3271d5)

自编码器与 VAE — 让网络抄自己,然后让它造出没见过的东西

这一章讲三件事。第一件,是一个听起来毫无意义的点子:让网络把输入原样吐回来。 它之所以有意义,全在于中间那一道卡口 —— 网络被迫先把输入压得很小,再从那么小的东西里还原。

第二件:压出来的那十几个数是什么。 它们不是乱码,是一套坐标 —— 长得像的输入落在相近的位置。

第三件,也是这一章真正的落点:同样一套结构,改一步就能拿来造新东西。 而这一步引出的麻烦(随机这一步没法求梯度),又逼出了一个非常漂亮的解法。

在全书链条里的位置: 三个零件里,这一章换的是目标 —— 前面几章的答案都来自外面(标签、框、评分),这一章的答案就是输入自己。 训练循环仍然一个字没改。

顺带解决一个上一章留下的问题: 第 06 章那些「训出来的一串数」到底能不能拿来做事? 这一章会让你亲眼看见 —— 从那串数解回一张图。

1. 顶层全景:一张手写数字,压到 2%,再还原

这一章的走查只用一张图:一个手写的数字,28 × 28 的灰度图,一共 784 个像素1

一张手写数字(784 个像素)

├─① 编码器:一路压 ──────→ 只剩 16 个数(784 的 2%)

├─② 解码器:从这 16 个数还原 ──→ 又是一张 28×28 的图

├─③ 拿还原出来的图和原图比 ──→ 差多少,就是损失

└─④ 训 12 轮 ────────────→ 第 1 轮糊得认不出,第 12 轮认得出是几

换成 VAE 之后:

├─⑤ 编码器不再吐 16 个数,而是吐 16 个中心 + 16 个宽度

├─⑥ 按这些中心和宽度随机取一组数 ──→ 解码 ──→ 重建

└─⑦ 训完之后干脆不给输入,直接随机取 16 组数 ──→ 造出 16 个从没存在过的数字

图说:①②③④ 是前半章,⑤⑥⑦ 是后半章。两半的差别只有一步 —— 第 ⑤ 步。

2. 让网络抄自己:一个听起来毫无意义的任务

先看现象。 前面五章的训练都是「给输入,给答案,让它学两者之间的关系」。 这一章的答案换成了输入自己:喂进去一张图,要它吐出同一张图。

这看起来毫无意义 —— 一个把输入原样复制到输出的程序,一行代码就写完了。

意义全在中间那道卡口。 网络被强行掰成两段,中间夹着一层特别窄的层2:

输入 ──→ [编码器:越压越小] ──→ 瓶颈 ──→ [解码器:越放越大] ──→ 重建出来的输入

只有十几个数

图说:这个结构和第 05 章那个分割网络的形状一样,但目的完全不同 —— 那边的输出是逐像素的类别,这边的输出是输入自己

中间那道卡口叫瓶颈:它规定了「你只能带这么多东西过去」。 网络要想把图还原出来,就必须在压缩的时候把最本质的东西挑出来带走, 把噪声(数据里那些没有规律、纯属偶然的成分)和冗余扔掉3

这套结构的名字叫自编码器 —— 「自」指的就是它拿自己当答案。 书说它主要有三个用处:把数据压小、发现异常、以及(改造之后)生成新数据4

训练怎么开始的? 一开始网络里的数都是随机的,所以输出是一团噪点; 随着训练推进,解码器越还原越像,输出越来越接近原始输入5

3. 瓶颈:这里的压缩是有损的,而「损了多少」就是训练信号

先把一个可能的误解掐掉:这里的压缩和你熟悉的压缩文件不是一回事。 压缩文件能原封不动地还原,一个数都不差;这里的压缩必然丢东西 —— 784 个数被塞进 16 个数,信息量摆在那里,不可能无损。

而这一章最漂亮的一点就在这儿:那个「丢掉的部分」不需要另外去量, 它自己就是训练信号。

做法朴素得出奇:把还原出来的图和原图逐个像素比一遍,差值平方再平均 —— 这就是第 01 章那个均方误差,一个字没改6

损失 = 平均((还原出来的每个像素 − 原图对应的像素)²)

图说:损失越小,说明瓶颈里那 16 个数带走的信息越管用。 注意这里完全不需要人工标注 —— 答案本来就在输入里。

为什么这么做有效: 瓶颈越窄,网络越没法偷懒。如果中间那层和输入一样宽, 它可以直接把数原样传过去,什么也学不到;掐窄之后,它被迫做取舍。 (这一句是我们补的推理,书只描述了结构。)

4. 潜空间:那十几个数是一套坐标

中间那十几个数,不是乱码,是坐标。

书给了它一个正式名字和一条计数规矩:瓶颈那一层所在的空间叫潜空间, 它有几维,由这一层放几个神经元决定 —— 128 个神经元就叫 128 维的潜空间7。 这一章用的是 16 维。

为什么说它是坐标,而不是随便一堆数? 因为解码器必须能从这 16 个数还原出原图。 要做到这一点,长得像的两张图,它们的这 16 个数就必须接近 —— 否则解码器没法用同一套规则同时还原它们(这一步推理是我们补的)。

这就把第 06 章那件事接上了: 那一章的嵌入是「给一个编号配一串训出来的数」, 这一章的潜空间是「给一整张图配一串训出来的数」。两者都是把一个东西压成一串坐标, 而且都靠训练让相似的东西靠得近。区别只在这一章能把那串数解回原来的东西。

它有什么用? 书列了三条8:

用处怎么用
压缩 / 降维存 16 个数,而不是 784 个
去噪噪声是随机的、没有规律,过不了瓶颈那道卡口
异常检测拿正常数据训一遍;之后还原不好的那些,多半就是异常

第三条值得多说一句:它把「异常」这件事变成了一个可以算的数 —— 不需要事先知道异常长什么样,只要重建误差明显偏大就报警。

5. 为什么这样的网络不能拿来造新图

先看现象: 潜空间既然是一套坐标,那随便挑一个坐标解码一下, 不就造出一张新图了吗?

不行,而且原因很具体。

书说经典自编码器有一个性质叫确定性 —— 同一个输入进去, 每次算出来的结果一模一样,没有任何随机成分。

于是一个输入进去,它被钉在潜空间里一个固定的点上; 所有训练数据在潜空间里留下的,就是一堆孤立的、离散的点9

孤立的点之间是什么?书没有明说,这一步由我们补上:是空的。

潜空间(简化成两维来看)

· · · ← 每个点是一张训练图落的位置
· ·
· × · · ← × 是你随手挑的一个坐标
· · ·

图说:训练时解码器只被要求在那些「·」上还原得好,× 那种没有任何训练图落过的地方, 它从来没被约束过 —— 解出来是什么样,谁也不知道,通常是垃圾。

这就是下一节那个改动存在的全部理由。10

6. VAE:一个输入不再对应一个点,而是对应一团分布

改动只有一步,但它改掉的是整个性质。

VAE 的做法: 编码器不再输出「潜空间里的一个点」,而是输出一团概率分布 (不是一个确定的值,而是「哪些值更可能出现」的一张说明)的两个参数 —— 中心在哪(均值 μ),摊得多开(标准差 σ)11。下面为了顺口,分布就是它的简称。

这里用的那一种叫高斯分布(也叫正态分布):中间最高、往两边越来越低, 书形容它像一个从中心向四面下坡的小山包12

经典自编码器: 一张图 ──→ 潜空间里的一个点

VAE: 一张图 ──→ 一个中心 + 一个宽度(一团小山包)

从这团里随机取一个点,再解码

图说:因为每次取的点都不同,同一张图在潜空间里占的不再是一个点,而是一小片区域。

为什么这一步就能拿来生成 —— 这才是关键。 损失函数里除了原来那个重建差,还多了一项:逼所有这些小山包都向「标准正态」靠拢 (标准正态就是中心在 0、宽度为 1 的那个高斯分布)。这一项叫 KL 散度, 它量的是「学出来的分布」和「标准正态」差多远;差得越远,罚得越狠13

两项一拉扯,结果就是:所有输入的小山包被挤到同一片区域里、彼此重叠, 潜空间被填满了 —— 没有第 5 节那种空隙。 于是随手取一个点, 它落在某个(或某几个)小山包的覆盖范围内,解码器解得出东西来14

训完之后怎么造新图? 不给任何输入,直接从标准正态里随机抓一组数,送进解码器 —— 出来的就是一张从没存在过的图15

这类「能造出新样本」的模型,有个统称就叫生成模型。

7. 重参数化:随机这一步挡住了梯度,怎么办

先看现象 —— 这是一个真正的死结。

第 01 章说过:训练靠的是从损失往回算梯度。可现在中间多了一步「随机取一个点」, 而随机取数这个动作是没法求导的:它不是一个把输入算成输出的函数, 你没法问「输入挪一点,输出会怎么变」16

梯度在这一步断掉,就意味着编码器那两条输出中心和宽度的分支永远收不到更新 —— 整个 VAE 训不起来。

解法漂亮得像个魔术,而且只有一行:把随机性挪到外面去。

原来:z = 从「中心 μ、宽度 σ」这团分布里随机取一个 ← 不可导

改成:ε = 从「中心 0、宽度 1」的标准正态里随机取一个 ← 随机,但它和网络无关
z = μ + σ × ε ← 这一步是纯算术,可导

图说:随机性还在,但它被拆成了一个外部的噪声 ε。 对网络来说,z 只是 μ 和 σ 的一个普通算式:μ 挪一点、z 就跟着挪一点; σ 挪一点、z 就跟着变宽一点。梯度顺着这个算式流回去,编码器就训得动了17

这一招的名字叫重参数化。书自己的措辞是:它「让训练一个 VAE 成为可能」18

为什么这么做是对的(不只是「能求导」这么简单): 从「中心 μ、宽度 σ」里取一个数,和「先从标准正态取一个数、再乘 σ 加 μ」, 得到的是同一种分布 —— 所以这不是近似,是等价改写。 (这一句是我们补的;书只给了做法,没说为什么两者等价。)

8. 主走查:一张手写数字,从 784 压到 16,再从随机数造出 16 个新数字

下面每个数都来自书。

8.1 前半段:压缩与还原

第 ① 步,准备数据。 MNIST 手写数字,6 万张 28×28 的灰度图,内容是 0 到 919。 每张图缩放到 −1 到 +1 之间 —— 这个范围是特意选的,后面会看到原因20。 按 9:1 切开:训练 54000 张 / 验证 6000 张21

第 ② 步,编码器把图压小。 三层22:

输入 [批, 1, 28, 28]
→ 卷积(1 个通道进、6 个通道出,3×3) → [批, 6, 26, 26] 28 被 3×3 滑完剩 26
→ ReLU
→ 拉直 → [批, 4056] 6 × 26 × 26 = 4056
→ 线性层 → [批, 16] ← 瓶颈

第 ③ 步,数一下压了多少。 784 个像素 → 16 个数。 16 ÷ 784 ≈ 2% —— 书自己算的就是这个数23

第 ④ 步,解码器原路放大。 编码器每一步都有一个反过来的对应操作24:

[批, 16]
→ 线性层 → [批, 4056]
→ ReLU
→ 还原形状 → [批, 6, 26, 26]
→ 转置卷积(6 个通道进、1 个通道出,3×3) → [批, 1, 28, 28] 26 被放回 28
→ tanh → 把每个数压进 −1 到 +1

这里能看出第 ① 步那个 −1 到 +1 的来历: 输出层用的是第 01 章那个 tanh, 它的取值范围正好是 −1 到 +1。输入的范围和输出的范围必须对得上, 否则损失永远降不下去 —— 书在第 01 章说 tanh 已经边缘化了,而这里是全书唯一一次正经用它25

第 ⑤ 步,训练。 损失是均方误差,优化器 Adam、学习率 0.001、每批 32 张、训 12 轮26。 书打印的路标27:

训练损失验证损失
第 1 轮0.11270.0692
第 2 轮0.06140.0562
第 12 轮0.03840.0395

第 ⑥ 步,看还原效果。 书每一轮都把同样几张图的原图和还原图并排存下来。 第 1 轮已经像样但还有点糊,第 12 轮就能清楚地认出是哪个数字了28。 两条损失曲线都是先陡降、然后逼近一个值走平 —— 训练是健康的29

8.2 后半段:换成 VAE,造出没存在过的数字

第 ⑦ 步,编码器多长两条分支。 结构基本不变,只在末尾分岔: 拉直之后先过一个 128 维的中间层,再分成两条线性层 —— 一条输出 16 个中心,另一条输出 16 个宽度30:

[批, 4056] → 线性层 → [批, 128] → ReLU ─┬─→ 线性层 → [批, 16] ← 16 个中心 μ
└─→ 线性层 → [批, 16] ← 16 个宽度(记的是对数方差)

第 ⑧ 步,重参数化。 按第 7 节那三行走。第二条分支吐出来的不是标准差本身, 而是它的对数:一种把很大或很小的数压进合适量级的记法(这里存的是方差取对数之后的值)。 所以先换算回标准差,再从标准正态抓一组和它同样大小的随机数 ε,最后 z = μ + σ × ε31。 这 16 个 z 才是送进解码器的东西。

第 ⑨ 步,损失变成两项相加32:

损失 = 重建差(还原图 vs 原图,均方误差) + KL 散度(把每团分布往标准正态推)

第 ⑩ 步,造新数字。 训完之后调用一个专门的方法: 不给任何输入,直接从标准正态里抓 16 组各 16 个数,一组一组送进解码器33。 书给的结果很诚实:大部分能一眼认出是哪个数字,但也有几个说明还得再多训一会儿34

这最后一步才是这一章的落点: 前半段的自编码器,你必须先给它一张图它才有东西可还原; 后半段的 VAE 什么都不要,凭 16 个随机数就画出一个数字。

9. 书里的立场与证据

书里给了证据的:

  • 压到 2% 还能还原 —— 有逐轮的图像对照和损失数字,可复核;
  • 重参数化让训练成为可能 —— 是数学事实(把不可导的采样改写成可导的算式), 书的解释准确;
  • VAE 能生成新样本 —— 有 16 张生成图为证,而且作者照实说了有几张不够好。

作者的经验判断(书里没给证据):

  • 16 维这个数 —— 没解释为什么是 16;
  • 12 轮、批 32、学习率 0.001 —— 同样没解释;
  • 「KL 这一项保证潜空间连续且有序」 —— 是对结果的描述,书没给出为什么它能保证。

书里的一处坦白值得记: 讲生成结果时作者直接写「有些数字说明可能需要更长时间的训练」—— 没有挑好看的图。 这一点比结论更值钱。

10. 边界与局限

这本书对的地方先说清: 这一章的结构安排很好 —— 先讲清经典自编码器是确定性的(一个输入一个固定点), 再由此引出 VAE 的改动;重参数化那个信息框写得尤其准确, 把「为什么需要它」和「怎么做到」都说清楚了。

但有三处它没讲透:

  1. 它没有说清「为什么固定点就不能生成」。 书只说经典自编码器映到固定点、 VAE 映到分布,中间那一步「点与点之间是空的、解码器在那里没被训练过」没写。 我们在第 5 节补上了,并配了书架依据;
  2. KL 散度只给了名字和一行代码,没有解释它在算什么。 我们在第 6 节按定义写了一句(「量两个分布差多远」);
  3. 重建损失和 KL 之间的配比没有讨论。 代码里两项直接相加、系数都是 1, 而这个配比在实践中很敏感 —— 偏向 KL 会让重建变糊,偏向重建会让潜空间重新出现空隙。 补充(不在书里,依据我们的 ai-book-reference 书架):这个配比通常用一个系数来调35

这一章没覆盖的:

  • 异常检测只提了名字,没有代码,也没说重建误差的门槛怎么定;
  • 潜空间没有被可视化过。 16 维压不成图,而这一章又没做降维展示 —— 读者始终没能亲眼看见「相似的数字聚在一起」;
  • 今天做图像生成的主力已经不是 VAE。 书里对此一字未提; 补充(不在书里,依据我们的 ai-book-reference 书架):生成图像的主力已经换成了扩散模型36;
  • 公式是图片。 均方误差、KL 散度、以及 z = μ + σ × ε 在原文正文里都是图片, 提取出来是空行 —— 上面那三处算式,一处按定义写、两处从代码反推。

还有一个转码事故要提醒: 这一章代码里有两行括号没配对 (算每轮平均损失那两行),照抄会直接报错、程序根本跑不起来37。这属于排版事故,不影响理解。

11. 可带走的

主走查一行写完: 一张 28×28 手写数字(784 个像素,缩放到 −1~+1) → 卷积到 6×26×26 → 拉直 4056 → 线性层压到 16 个数(2%) → 解码器原路放回 28×28、tanh 收尾 → 均方误差训 12 轮,损失 0.1127 → 0.0384 → 换 VAE:编码器改吐 16 个中心 + 16 个宽度 → z = μ + σ × ε → 损失多一项 KL → 最后从标准正态抓 16 组数,造出 16 个从没存在过的数字。

  1. 自编码器 = 拿输入自己当答案,不需要任何人工标注;
  2. 中间那道卡口叫瓶颈,它逼网络做取舍 —— 没有它,网络会原样传值、什么都学不到;
  3. 这里的压缩是有损的,而「损了多少」正好就是训练信号(均方误差);
  4. 瓶颈那一层所在的空间叫潜空间,几个神经元就是几维;
  5. 潜空间里的坐标不是乱码 —— 长得像的输入必然落得近,否则解码器还原不出来;
  6. 三个用处:压缩降维、去噪(噪声过不了瓶颈)、异常检测(还原不好的就是异常);
  7. 经典自编码器不能生成:每个输入被钉在一个孤立的点上,点与点之间解码器没训过;
  8. VAE 的改动只有一步:输出一团分布的中心和宽度,而不是一个点;
  9. 再加一项 KL,把所有分布往标准正态推 —— 潜空间被填满,随手取一点也解得出东西;
  10. 随机取数不可导,所以要重参数化:z = μ + σ × ε,把随机性挪成一个外部噪声;
  11. 输出层的取值范围必须和输入的取值范围对得上(这里是 tanh 配 −1~+1);
  12. 训完之后不给输入、直接从标准正态抓数,就能造出新样本 —— 这就是「生成」。

12. 原文地图

主题原书章原文位置
自编码器的定义与三个用处Chapter 6text/08-ch06-chapter-6.txt:12(搜「consists of an encoder and a decoder」) · text/08-ch06-chapter-6.txt:18(搜「reduce dimensionality」)
三个组成部分与瓶颈Chapter 6text/08-ch06-chapter-6.txt:27(搜「three main components」) · text/08-ch06-chapter-6.txt:43(搜「low」)
潜空间的维度怎么数Chapter 6text/08-ch06-chapter-6.txt:44(搜「128-dimensional latent space」)
训练从噪声开始Chapter 6text/08-ch06-chapter-6.txt:46(搜「randomly initialized」)
重建损失用 MSEChapter 6text/08-ch06-chapter-6.txt:50(搜「deviation of the reconstructed」)
MNIST 与超参数Chapter 6text/08-ch06-chapter-6.txt:58(搜「consists of 60,000」) · text/08-ch06-chapter-6.txt:97(搜「BATCH_SIZE = 32」)
归一化到 −1~+1、切分Chapter 6text/08-ch06-chapter-6.txt:117(搜「Normalize to [-1, 1]」) · text/08-ch06-chapter-6.txt:162(搜「Training data count: 54000」)
编码器与解码器结构Chapter 6text/08-ch06-chapter-6.txt:174(搜「makes sense to use a Conv2d layer」) · text/08-ch06-chapter-6.txt:207(搜「reverses the process」) · text/08-ch06-chapter-6.txt:210(搜「hyperbolic tangent」)
训练损失路标与压缩比Chapter 6text/08-ch06-chapter-6.txt:350(搜「train_loss=0.1127」) · text/08-ch06-chapter-6.txt:391(搜「2% of the original data」)
重建效果与损失曲线Chapter 6text/08-ch06-chapter-6.txt:387(搜「After one epoch」) · text/08-ch06-chapter-6.txt:374(搜「asymptotically approach」)
经典自编码器是确定性的Chapter 6text/08-ch06-chapter-6.txt:421(搜「deterministic」)
VAE 映到分布、高斯、山包Chapter 6text/08-ch06-chapter-6.txt:426(搜「models a probability distribution」) · text/08-ch06-chapter-6.txt:429(搜「hilltop」)
VAE 编码器的两条分支Chapter 6text/08-ch06-chapter-6.txt:456(搜「two vectors for the dense layers」) · text/08-ch06-chapter-6.txt:493(搜「two parallel branches」)
重参数化信息框Chapter 6text/08-ch06-chapter-6.txt:526(搜「Reparameterization Trick」) · text/08-ch06-chapter-6.txt:530(搜「random sampling is not dif」) · text/08-ch06-chapter-6.txt:540(搜「deterministic and differentiable」)
两项损失Chapter 6text/08-ch06-chapter-6.txt:623(搜「Reconstruction loss」) · text/08-ch06-chapter-6.txt:628(搜「KL divergence loss」)
生成 16 个新数字Chapter 6text/08-ch06-chapter-6.txt:738(搜「generating sixteen digits」) · text/08-ch06-chapter-6.txt:761(搜「easily recognizable」)
转码事故 两处括号没配对Chapter 6text/08-ch06-chapter-6.txt:330(搜「train_epoch_loss = running_loss」)

Footnotes

  1. 出处:「Chapter 6 Autoencoders」第 56-59 段(text/08-ch06-chapter-6.txt:58,搜「consists of 60,000」)。原文:数据集叫 MNIST,包含大量手写数字;这个经典数据集由 6 万张图组成,每张是 28 × 28 像素的灰度图,内容是 0 到 9 的数字。

  2. 出处:「Chapter 6」第 27-34 段(text/08-ch06-chapter-6.txt:27,搜「three main components」)。原文三个部分:编码器、瓶颈(也叫潜空间)、解码器;输入数据应当被自编码器用更少的数据表示,从而给出一份能用少得多的参数描述的重建结果。

  3. 出处:「Chapter 6」第 11-16 段(text/08-ch06-chapter-6.txt:12,搜「consists of an encoder and a decoder」)。原文:自编码器的目标是提取数据最重要的特征、把它们压成一个极小的「刮干净」的形式(编码器),之后再从这个压缩形式尽可能准确地还原原始数据(解码器);这个网络学会的是去掉数据里的噪声和冗余。

  4. 出处:「Chapter 6」第 17-18 段(text/08-ch06-chapter-6.txt:18,搜「reduce dimensionality」)。原文:这一章看自编码器怎么完成这个任务,以及怎么用这个强大的工具来降维、检测异常、生成新数据。

  5. 出处:「Chapter 6」第 46-49 段(text/08-ch06-chapter-6.txt:46,搜「randomly initialized」)。原文:训练开始时模型结果是随机初始化的,所以对应一张充满噪声的图;随着时间推移,解码器越来越擅长重建数据,模型结果越来越接近原始输入。

  6. 出处:「Chapter 6」第 50-53 段(text/08-ch06-chapter-6.txt:50,搜「deviation of the reconstructed」)。原文:训练时损失函数必须度量重建图与原图的偏差;一个简单的做法是逐一比较像素值并对偏差取平方 —— 我们在前面几章已经学过这个均方误差。原书的公式是图片,提取出来是空行。

  7. 出处:「Chapter 6」第 42-45 段(text/08-ch06-chapter-6.txt:44,搜「128-dimensional latent space」)。原文:相对于输入数据,潜空间是一个低维空间,反映数据的本质特征;它的维度由这一层的神经元数量描述 —— 如果潜空间有 128 个神经元,就称它为 128 维的潜空间。

  8. 出处:「Chapter 6」第 17-18 段(text/08-ch06-chapter-6.txt:18,搜「reduce dimensionality」)与第 765-777 段的小结(text/08-ch06-chapter-6.txt:768,搜「dimensionality reduction, anomaly detection」)。原文小结:自编码器与 VAE 的主要应用领域包括降维、异常检测和数据清洗,而 VAE 还被大量用于生成式建模。「还原不好的就是异常」这一句机制上的说明书里没有明说,是我们按它的定义补的。

  9. 出处:「Chapter 6」第 419-424 段(text/08-ch06-chapter-6.txt:421,搜「deterministic」)。原文:经典自编码器学到的是数据的一个压缩表示,也就是潜空间;在这个空间里,每个观测到的数据点被映射到唯一一个点;不存在概率分布,因为自编码器是确定性的 —— 它把输入映射到潜空间里一个固定的、预测出来的点,所以潜在数据的分布由一个个孤立的离散点组成,常被表示成一条无限高、积分为 1 的竖线。

  10. 补充(不在书里,依据我们的 ai-book-reference 书架):书只说经典自编码器映到固定点、VAE 映到分布,没有说明「为什么固定点就不能拿来生成」。依据: book=deep-learning-crash-course §06-encoder-decoder 事实=该章明确写出这条边界 —— 标准自编码器不能生成,原因是潜空间有空白带,必须靠 VAE、WAE 这类「填空白」的改造。

  11. 出处:「Chapter 6」第 425-428 段(text/08-ch06-chapter-6.txt:426,搜「models a probability distribution」)。原文:VAE 不为每个观测数据点建模一个单独的点,而是在潜空间里建模一个概率分布;这个分布通常假定为高斯曲线(正态分布),意思是 VAE 为潜变量的每一个维度估计一个均值 μ 和一个标准差 σ,得到的是一段可能取值的范围而不是单一的点。

  12. 出处:「Chapter 6」第 429-433 段(text/08-ch06-chapter-6.txt:429,搜「hilltop」)。原文:潜在数据的分布因此看起来像一个向四面下坡的山顶,中心处密度最高、越往外越低 —— 这意味着 VAE「知道」潜空间里哪些点最有可能代表原始数据,而这个性质让它能够通过从这个分布中采样来生成新的、貌似合理的数据点。

  13. 出处:「Chapter 6」第 628-634 段(text/08-ch06-chapter-6.txt:628,搜「KL divergence loss」)。原文:这一项度量编码器学到的概率分布(体现在 mu 和 logvar 两个变量里)与标准正态分布之间的差异;如果学到的分布离一个简单、良序的正态分布太远,VAE 就会施加惩罚;这个限制是必要的,它保证潜空间连续而有序,并让 VAE 之后能生成新的、逼真的数据点。

  14. 这一段的因果链条(「两项一拉扯 → 小山包互相重叠 → 空隙消失 → 随手取点也能解码」)是我们把书里分散的两处说法接起来的:书在第 429-433 段说 VAE「知道哪些点最可能代表原始数据」,在第 628-634 段说 KL 项保证潜空间连续有序,但没有把它们连成一条因果链。

  15. 出处:「Chapter 6」第 562-564 段(text/08-ch06-chapter-6.txt:562,搜「def generate」)。原文的这个方法就是:抓一批标准正态随机数,直接送进解码器。

  16. 出处:「Chapter 6」第 526-532 段(text/08-ch06-chapter-6.txt:530,搜「random sampling is not dif」)。原文:VAE 必须从潜空间里一个学到的概率分布中抽取随机样本,但训练神经网络需要反向传播来计算梯度、进而调整权重 —— 问题在于随机采样这个过程是不可微的。

  17. 出处:「Chapter 6」第 533-542 段(text/08-ch06-chapter-6.txt:540,搜「deterministic and differentiable」)。原文三步:编码器继续学习并输出一个分布的均值和标准差;不直接从这个分布抽样,而是从固定的标准正态分布(均值 0、标准差 1)里取一个简单的随机数;用 z = μ + σ × ϵ 把这个随机数变成新变量 z。这个变换是确定性且可微的,反向传播因此可以顺利穿过它,调整编码器输出的均值与标准差参数,VAE 才训得动。

  18. 出处:「Chapter 6」第 522-524 段(text/08-ch06-chapter-6.txt:524,搜「makes the training of a VAE possible」)。原文:VAE 类里有一个 reparameterize 方法,它用的重参数化技巧才使得训练一个 VAE 成为可能。

  19. 出处:「Chapter 6」第 56-59 段(text/08-ch06-chapter-6.txt:58,搜「consists of 60,000」)。

  20. 出处:「Chapter 6」第 113-133 段(text/08-ch06-chapter-6.txt:117,搜「Normalize to [-1, 1]」)。原文代码里的注释直接写明了理由:归一化到 [-1, 1],好让 tanh 的解码器输出与输入的取值范围一致;随后打印出来的取值范围确实是 −1.0 到 1.0。

  21. 出处:「Chapter 6」第 153-163 段(text/08-ch06-chapter-6.txt:162,搜「Training data count: 54000」)。原文:初始数据集有 6 万个元素,验证集占 10%,所以应该是 54000 训练、6000 验证 —— 结果确实如此。原文还提了一句:这里用两份切分,你也可以自己切成三份。

  22. 出处:「Chapter 6」第 173-204 段(text/08-ch06-chapter-6.txt:174,搜「makes sense to use a Conv2d layer」)。原文:因为处理的是图像,用卷积层是合理的;输入通道数为 1(灰度图),输出 6 个通道,卷积核用标准的 3;经过卷积层维度从 28 降到 26,所以线性层的输入是 6 × 26 × 26 个神经元;这一步把四维张量变成二维张量。

  23. 出处:「Chapter 6」第 389-393 段(text/08-ch06-chapter-6.txt:391,搜「2% of the original data」)。原文:原图由 28 × 28 也就是 784 个像素描述,重建图是从只有 16 维的压缩潜空间还原出来的,因此我们把数据压到了原来的 2%。

  24. 出处:「Chapter 6」第 207-230 段(text/08-ch06-chapter-6.txt:207,搜「reverses the process」)。原文:解码器类反转整个过程,通常是编码器的镜像,用的是 ConvTranspose2d(反转 Conv2d)和 unflatten(反转 flatten)。

  25. 出处:「Chapter 6」第 210-213 段(text/08-ch06-chapter-6.txt:210,搜「hyperbolic tangent」)。原文:输出层用双曲正切 tanh 激活,因为它把输出归一化到 −1 到 +1,正好对应输入数据的取值范围 —— 作者还半开玩笑地补了一句:我们总算在这一处正经用上了这个特殊的激活函数。

  26. 出处:「Chapter 6」第 289-297 段(text/08-ch06-chapter-6.txt:295,搜「nn.MSELoss()」)与第 93-105 段(text/08-ch06-chapter-6.txt:97,搜「BATCH_SIZE = 32」)。超参数:批 32、12 轮、学习率 0.001、潜空间 16 维、验证占 10%。

  27. 出处:「Chapter 6」第 350-353 段(text/08-ch06-chapter-6.txt:350,搜「train_loss=0.1127」)。

  28. 出处:「Chapter 6」第 387-388 段(text/08-ch06-chapter-6.txt:387,搜「After one epoch」)。原文:一轮之后结果已经相当不错,但仍然有些不清晰;十二轮之后就能清楚地把重建图对应到具体的数字上。

  29. 出处:「Chapter 6」第 373-374 段(text/08-ch06-chapter-6.txt:374,搜「asymptotically approach」)。原文:损失看起来非常好 —— 训练和验证损失都先急剧下降,然后渐近地逼近一个值。

  30. 出处:「Chapter 6」第 455-494 段(text/08-ch06-chapter-6.txt:456,搜「two vectors for the dense layers」)与第 492-494 段(text/08-ch06-chapter-6.txt:493,搜「two parallel branches」)。原文:与经典自编码器的网络相比,稠密层这里有两个向量,一个给均值、一个给方差;拉直层的输出被送进两条并行的分支。代码里中间那一层是 nn.Linear(6*26*26, 128)

  31. 出处:「Chapter 6」第 552-555 段(text/08-ch06-chapter-6.txt:553,搜「std = torch.exp」)。原文的三行:由对数方差算出标准差、抓一组与它同形状的标准正态随机数、返回 mu + eps * std

  32. 出处:「Chapter 6」第 620-643 段(text/08-ch06-chapter-6.txt:623,搜「Reconstruction loss」)。原文:损失由两部分组成 —— 重建损失度量 VAE 还原原始输入的好坏,用的是均方误差;KL 散度损失度量编码器学到的分布与标准正态分布的差异。代码里两项直接相加。

  33. 出处:「Chapter 6」第 738-747 段(text/08-ch06-chapter-6.txt:738,搜「generating sixteen digits」)。原文:最后我们通过生成十六个数字来测试模型的能力;用的是模型的 generate 方法,它从潜空间随机选取十六个点,并在此基础上生成数据集里没有出现过的数字。

  34. 出处:「Chapter 6」第 761-763 段(text/08-ch06-chapter-6.txt:761,搜「easily recognizable」)。原文:大多数生成结果都能轻易辨认成熟悉的数字,但有些数字表明可能需要更长时间的训练。

  35. 补充(不在书里,依据我们的 ai-book-reference 书架):书把重建损失与 KL 散度直接相加、没有讨论配比,而这个配比在实践中会直接影响结果。依据: book=deep-learning-crash-course §06-encoder-decoder 事实=该章写明 KL 与重建之间的拉扯常以「输出偏软、重建偏糊」为代价,并说明原书用一个 β 系数来调这个平衡。

  36. 补充(不在书里,依据我们的 ai-book-reference 书架):这本书出版于 2026 年,但对图像生成的现状一字未提。依据: book=deep-learning-with-python-2e §12-generative 事实=该章的边界一节写明图像生成的主力已经从 VAE 和 GAN 换成了扩散模型。

  37. 出处:「Chapter 6」第 330 段(text/08-ch06-chapter-6.txt:330,搜「train_epoch_loss = running_loss」)。这两行的右括号缺失,是转码或排版事故,照抄会直接报语法错误。