30u30 中文导读 / 30 天目录 / 第 23 天

第 23 天 · 限制解码器的视野,逼隐变量去学全局结构

第 5 单元Variational Lossy AutoencoderXi Chen, Diederik P. Kingma, Tim Salimans et al.ICLR 2017(arXiv 2016) · 2016
这是导读,不是翻译。先用 10 分钟拿到这篇论文的思想地图,再去读 原论文 →,去原仓库的 23_variational_lossy_autoencoder/ 目录 → 动手写代码。
给孩子讲:这一天有 10 岁孩子能听懂的讲义,带猜字游戏和动手活动,可打印。打开儿童讲义 → · PDF 简体 · PDF 繁體

一句话

论文用 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。

方法:有意设计"缺什么"。

作者还改进了先验:用自回归流(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 年的潜扩散模型都采用类似的两阶段结构。

学前准备

在原仓库怎么学

  1. 运行 setup.py:它对掩码卷积(A 型和 B 型)、MADE 自回归性质和 VLAE 前向传播做单元测试。
  2. 阅读 data/README.md:了解二值化 MNIST 的准备方式。
  3. 阅读 implementation.py:找出编码器、局部 PixelCNN 解码器和流先验三部分。
  4. 按顺序做 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 组装完整模型。
  5. 对照 exercises/solutions/ 检查实现。
  6. 运行 train_minimal.py:它记录重建损失、KL 和 bits/dim。加 --use-flow 启用流先验。把 --decoder-layers 调到 8 让解码器视野变大,观察 KL 是否塌到 0。
  7. 运行 visualization.py:生成 KL 与重建损失曲线、重建对比、逐像素采样、KL 热力图和隐变量遍历图。
  8. 最后用 notebook.ipynb 串起全流程。

今天再看

"隐变量管全局、解码器管细节"这个分工今天随处可见。Stable Diffusion 等潜扩散模型先用自编码器把图像压到低分辨率潜空间,让扩散模型只处理语义结构,纹理细节交给解码器还原。图像和音频的分词器(tokenizer)也遵循同一原则。

和大语言模型的联系有两点。第一,GPT 类模型是纯自回归模型,没有显式隐变量。VLAE 的分析解释了一个现象:给强自回归语言模型加隐变量,往往会被模型忽略。第二,"学习就是压缩"是 Ilya 反复讲的观点。语言模型的交叉熵损失本身就是平均编码长度,与 VLAE 的 Bits-Back 视角一致。

被取代的部分:用 VAE 做高质量图像生成的路线,已经让位于扩散模型和自回归 Transformer。

容易卡住的地方

延伸阅读