第 23 天 · 限制解码器的视野,逼隐变量去学全局结构
一句话
论文用 Bits-Back 编码解释了强解码器 VAE 为什么会忽略隐变量,并据此提出对策:只给自回归解码器一个局部视野。这样全局结构必须经过隐变量,隐变量成为丢弃纹理细节的有损表示。
论文讲了什么
结论先行:VAE 的隐变量里存什么,可以通过设计解码器来控制。解码器能自己建模的信息,隐变量就不会存。作者限制解码器只看局部像素,于是隐变量只存全局结构。
问题:后验坍塌。变分自编码器(VAE)有一个编码器把图像 x 压成隐变量 z,一个解码器从 z 重建 x。如果解码器是 PixelCNN 这种自回归模型,它本身就能逐像素生成很好的图像。训练后人们常常发现:KL 项降到接近 0,z 几乎不携带信息,解码器完全不看 z。这个现象叫后验坍塌(posterior collapse)。2015 年 Bowman 等人在文本 VAE 上就遇到过同样的问题。
解释:用编码长度看 ELBO。作者把 VAE 的训练目标(ELBO)解读为 Bits-Back 编码方案的平均编码长度。用 z 传递信息有一项额外成本:近似后验 q(z|x) 和真实后验之间的差距。如果解码器不用 z 也能把 x 编码得很好,那么使用 z 只会增加编码长度。优化器因此选择不用 z。结论是:凡是解码器能在局部建模的信息,都不会进入 z。
方法:有意设计"缺什么"。
- 解码器仍是自回归的 PixelCNN,但只看当前像素周围很小的窗口。它能画出局部纹理和笔画细节,却看不到整张图的形状。
- 全局信息(数字是几、物体轮廓、整体布局)解码器自己建模不了,只能通过 z 传递。
- 结果是 z 成为一种有损表示:它保留全局结构,丢掉局部纹理。从同一个 z 多次采样,得到的图像整体形状相同,细节各不相同。
作者还改进了先验:用自回归流(autoregressive flow)参数化 p(z),代替标准高斯。更灵活的先验让 z 的编码成本更低,似然进一步提高。
关键结果。在 MNIST、OMNIGLOT 和 Caltech-101 Silhouettes 的密度估计任务上,VLAE 取得了当时最好的对数似然。在 CIFAR-10 上达到 2.95 bits/dim,与当时最强的纯自回归模型接近。可视化实验显示:重建图与原图整体形状一致,局部像素不同,这正是"有损"的含义。
关键概念
- 后验坍塌(posterior collapse)
- VAE 训练后 KL 项趋近 0,编码器输出的分布和先验几乎相同,解码器完全忽略隐变量。解码器越强,越容易发生。
- 自回归解码器(autoregressive decoder)
- 按固定顺序逐个生成像素或 token,每一步以已生成部分为条件的模型,例如 PixelCNN。它单独就能建模复杂分布。
- Bits-Back 编码(Bits-Back coding)
- 一种把带隐变量模型解释为压缩方案的视角。ELBO 的负值等于平均编码长度,因此可以用比特数分析 z 是否值得使用。
- 有损表示(lossy representation)
- 只保留部分信息的编码。VLAE 中 z 保留全局结构、丢弃局部纹理,丢掉的部分由解码器负责生成。
- 感受野(receptive field)
- 一个输出位置能看到的输入范围。VLAE 刻意把解码器的感受野限制在小窗口内,以此决定哪些信息必须进入 z。
- 自回归流先验(autoregressive flow prior)
- 用可逆的自回归变换把简单高斯变成复杂分布,作为 z 的先验。它让 z 的编码成本更低,提高整体似然。
历史位置:为什么值得读
这篇论文把两条生成模型路线接在了一起。2013 年的 VAE 擅长学隐变量,但生成的图像模糊。2016 年的 PixelRNN 和 PixelCNN 生成清晰,但没有可解释的隐变量。直接把两者拼起来会发生后验坍塌。VLAE 给出了原因和可控的解决办法。
作者名单很强:Diederik Kingma 是 VAE 和 Adam 的作者,Tim Salimans 是 PixelCNN++ 的作者,Ilya Sutskever 和 Pieter Abbeel 也在其中。这是 Ilya 本人参与、又被他放进推荐清单的论文。
它和清单里的信息论主线直接相连。第 4 天 Hinton 讨论用描述长度约束网络,Bits-Back 的思想正源自那里。第 5 天的最小描述长度原则和第 26 天的柯尔莫哥洛夫复杂度也是同一条线:学习等于压缩。VLAE 用这个视角回答了一个具体工程问题。
后续影响:2017 年的 VQ-VAE 用离散隐变量加 PixelCNN 先验,延续了"隐变量管全局、自回归模型管细节"的分工。DALL·E 第一版和 2021 年的潜扩散模型都采用类似的两阶段结构。
学前准备
- 理解 VAE 的 ELBO:重建项减去 KL 项
- 知道 PixelCNN 如何用掩码卷积保证自回归顺序
- 会在 nats 和 bits 之间换算,理解 bits/dim
- 建议先看第 4、5 天,理解编码长度与学习的关系
在原仓库怎么学
- 运行 setup.py:它对掩码卷积(A 型和 B 型)、MADE 自回归性质和 VLAE 前向传播做单元测试。
- 阅读 data/README.md:了解二值化 MNIST 的准备方式。
- 阅读 implementation.py:找出编码器、局部 PixelCNN 解码器和流先验三部分。
- 按顺序做 exercises/ 里的 5 个练习:
exercise_01_masked_conv.py实现掩码卷积,exercise_02_pixelcnn_prior.py实现 PixelCNN,exercise_03_posterior_collapse.py复现后验坍塌,exercise_04_flow_prior.py实现流先验,exercise_05_vlae_complete.py组装完整模型。 - 对照 exercises/solutions/ 检查实现。
- 运行 train_minimal.py:它记录重建损失、KL 和 bits/dim。加
--use-flow启用流先验。把--decoder-layers调到 8 让解码器视野变大,观察 KL 是否塌到 0。 - 运行 visualization.py:生成 KL 与重建损失曲线、重建对比、逐像素采样、KL 热力图和隐变量遍历图。
- 最后用 notebook.ipynb 串起全流程。
今天再看
"隐变量管全局、解码器管细节"这个分工今天随处可见。Stable Diffusion 等潜扩散模型先用自编码器把图像压到低分辨率潜空间,让扩散模型只处理语义结构,纹理细节交给解码器还原。图像和音频的分词器(tokenizer)也遵循同一原则。
和大语言模型的联系有两点。第一,GPT 类模型是纯自回归模型,没有显式隐变量。VLAE 的分析解释了一个现象:给强自回归语言模型加隐变量,往往会被模型忽略。第二,"学习就是压缩"是 Ilya 反复讲的观点。语言模型的交叉熵损失本身就是平均编码长度,与 VLAE 的 Bits-Back 视角一致。
被取代的部分:用 VAE 做高质量图像生成的路线,已经让位于扩散模型和自回归 Transformer。
容易卡住的地方
- 以为后验坍塌只能靠 KL 退火解决:KL 退火和 free bits 只是训练技巧。VLAE 的思路是改结构,让解码器在局部之外无能为力,z 自然会被使用。
- 掩码卷积的 A 型和 B 型用反:第一层用 A 型,不能看到当前像素;后续层用 B 型,可以看到当前位置的上一层特征。用 setup.py 的单元测试验证。
- bits/dim 算错:把负对数似然(nats)除以像素总数 D,再除以 ln 2。漏掉任一步,数字就无法与论文比较。
- 增加解码器层数时,不知道感受野随层数增长:每加一层卷积,视野扩大一圈。仓库用 decoder-layers 控制这一点,层数多就更容易坍塌。
延伸阅读
- 原论文:Variational Lossy Autoencoder
- 原仓库第 23 天目录:23_variational_lossy_autoencoder/ —— 代码、笔记本、练习与答案(英文)
- Generating Sentences from a Continuous Space —— 文本 VAE 中后验坍塌的早期报告
- Improved Variational Inference with Inverse Autoregressive Flow —— 同一作者的流模型工作,与本文先验相关
- Neural Discrete Representation Learning —— VQ-VAE,离散隐变量加自回归先验
- High-Resolution Image Synthesis with Latent Diffusion Models —— 潜扩散模型,两阶段分工的现代版