对应 Maps to:Stanford CS236 Deep Generative Models(Fall 2023,Stefano Ermon),Lecture 3 · 2023-10-04 · Autoregressive Models(slides:
cs236_lecture3.pdf,36 页);课程笔记 Autoregressive Models。 依据说明:本讲按原课 slides 的顺序展开:动机(二值化 MNIST)→ FVSBN → NADE → 一般离散分布与 RNADE → 自回归模型 vs 自编码器 → MADE → RNN 与字符 RNN → 注意力与生成式 Transformer → PixelRNN、PixelCNN → PixelDefend 与 WaveNet → 小结。slides 上的图(FVSBN、NADE、PixelCNN 的样本,Karpathy 的字符 RNN 例子)用文字和论文出处代替;字符 RNN 那一页的 softmax 数字取自 slide 19。全部实验是本讲义补充的:7 个自回归模型在第 1 讲的像素世界上训练,测试 bits 和真实熵直接比较;PixelCNN 的盲点用梯度精确画出;顺序、异常检测、“容易与难的条件”三个实验检验 slide 36 的总结。 配套代码 Code:code/lecture03/(PyTorch;共享模块ar_models.py+ 5 个演示脚本。第一次运行要训练 7 个模型,代码 03 约 100 秒、代码 04 约 45 秒,其余在 10–50 秒;训练好的模型缓存在checkpoints/,之后几秒钟) 预计阅读时间:3.5 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说清楚自回归模型 = 链式法则 + 用带参数的函数表示每个条件分布,以及”这是一个建模假设”是什么意思;解释”自回归”这个名字的来历。
- 写出 FVSBN 的条件分布、算出它的参数个数(),会手算 和逐个像素采样。
- 解释 NADE 的权重共享为什么让参数线性于 、让 可以递推;说明怎样把 NADE 推广到类别分布(softmax)和连续变量(RNADE,混合高斯)。
- 区分自编码器和自回归模型:为什么普通的自编码器不是生成模型;MADE 怎样用掩码把自编码器变成合法的自回归模型,会给定编号推出掩码。
- 说出 RNN 的优缺点(参数和长度无关 vs 一个向量概括全部历史、不能并行、梯度消失),注意力的四步,以及生成式 Transformer 为什么需要因果掩码。
- 解释 PixelCNN 的掩码卷积(A 型 / B 型)和它的盲点;知道 PixelRNN、WaveNet 的思路。
- 总结自回归模型的优点和局限:采样容易但慢、似然精确且可并行、必须选顺序、没有天然的特征;“顺着顺序的条件容易,逆着顺序的条件难”。
- 读懂本讲的实验:7 个模型在像素世界上离真实分布有多远,以及几个和预期相反的结果(RNN 胜过 Transformer、MADE 在随机顺序下更好)。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲只给直觉,后面几讲再展开 Previewed only |
|---|---|
| 第 2 讲:链式法则、贝叶斯网络、“用函数代替表格”、逻辑回归 | 最大似然训练的原理(第 4 讲;本讲直接用”最小化 “训练) |
| 神经网络的基本概念:全连接层、激活函数、反向传播 | 过拟合与正则化(第 4 讲;本讲只指出现象) |
| PyTorch 不会也没关系,代码里有解释 | 重要性采样与隐变量(第 5 讲;本讲代码 05 只预演一次) |
| 用 Transformer 做大规模语言建模的工程细节(见本仓库 CS336、CS324) |
0.3 本讲地图 Map
§1 思路:链式法则 + 函数参数化的条件分布;“自回归”的含义
§2 FVSBN:每个条件一个逻辑回归 ← 代码 01
§3 NADE、一般离散分布、RNADE;自回归模型 vs 自编码器;MADE ← 代码 02
§4 RNN、字符 RNN、注意力、生成式 Transformer ← 代码 03
§5 PixelRNN、PixelCNN(掩码卷积与盲点)、WaveNet ← 代码 04
§6 应用与总结:排行榜、顺序、异常检测、容易与难的条件 ← 代码 05
§7 2023 年之后
§8–12 小结、常见误区、练习、延伸阅读、下一讲预告
0.4 记号 Notation
| 符号 | 含义 |
|---|---|
| 按某个顺序排好的变量(像素);像素世界里 | |
| 模型给出的 (二值情形) | |
| FVSBN 第 个逻辑回归的系数向量 | |
| 隐藏表示(NADE 的第 个隐藏向量;RNN 的第 步状态) | |
| NADE 的参数(共享的第一层、偏置、输出层) | |
| MADE 中单元 的编号(它最多能看前 个输入) | |
| bits/图、bits/dim | 测试集上的平均 ,以及除以 后的值 |
0.5 关于数字 · About the numbers
所有实验用同一份数据:像素世界的 10,000 张训练图、2,000 张验证图、5,000 张测试图;真实分布在这 5,000 张测试图上的平均是 25.52 bit/图(0.3987 bits/dim),表里测试集上的”比真实多 bit”都是相对这个数;训练集上的”比真实多 bit”减去的是真实分布在训练集自己上的平均(25.61 bit)。数字来自作者机器(macOS,PyTorch 单线程 CPU)的实际输出,重复运行逐字节相同(计时除外);把 checkpoints/ 删掉重新训练,会得到完全相同的模型(已验证)。有好几个结果和写代码之前的预期相反,讲义按实际结果写,并在 代码 README 的”关于实验结果”里逐条记录。
1. 思路:链式法则 + 函数参数化的条件分布 · The idea
1.1 从第 2 讲接着往下走
原课第 3 页先回顾了第 2 讲的结论:用链式法则写出联合分布,
这是完全一般的,不需要任何假设(代价是指数大小,没有免费的午餐)。贝叶斯网络假设条件独立、用表表示条件分布;神经模型假设条件分布有特定的函数形式——“足够深的神经网络可以逼近任何函数”。第 2 讲代码 04 已经在一个条件分布上看到了:12 个父节点的表要 4096 格,而一个神经网络用 1538 个参数、1000 个样本就学得最好。本讲把这个想法用到每一个条件分布上。
1.2 动机:二值化 MNIST
原课第 5 页:给定一个手写数字的数据集 (二值化的 MNIST),每张图有 个像素,每个像素非黑即白。目标是学一个分布 ,使得从中采样的 看起来像一个数字。分两步:
- 参数化一个模型族 ——本讲;
- 根据训练数据搜索参数 ——下一讲。
本讲义的玩具版本是像素世界:,真实分布已知。
1.3 自回归模型
原课第 6 页:选一个所有随机变量的顺序,例如从左上角()到右下角()的光栅扫描顺序。不失一般性,用链式法则分解:
有些条件分布太复杂,没法存成表。于是假设:
更明确地:
原课特别强调:“This is a modeling assumption.” 链式法则本身是恒等式,“每个条件是一个逻辑回归”才是假设。用带参数的函数(这里是逻辑回归)根据前面所有的像素预测下一个像素,这样的模型叫自回归模型(autoregressive model)——“自”是因为预测的对象和用来预测的变量来自同一个序列,“回归”是因为每一步都是一个回归(这个词来自时间序列分析里的 AR 模型:用过去的值回归下一个值)。
为什么这个思路这么好用? 三个原因,本讲会反复验证:
- 合法性是免费的:只要每个条件分布是一个合法的分布(例如 ),乘起来就一定是合法的联合分布——链式法则保证了这一点。不需要算任何归一化常数(第 11 讲的能量模型就要为此付出巨大代价)。
- 似然精确可算:,每一项都能直接算。
- 训练就是监督学习:每个条件分布都是”给定前面,预测下一个”的分类问题——这正是语言模型的训练方式。
2. FVSBN:每个条件一个逻辑回归 · Fully Visible Sigmoid Belief Network
2.1 定义
原课第 7 页:条件变量 是伯努利分布,参数为
这叫 FVSBN(fully visible sigmoid belief network:所有变量都是可见的、用 sigmoid 连接的信念网络)。
- 怎样算 ? 把所有条件乘起来。slide 7 的例子:,其中每个 都用已知的前缀算出:,,。
- 怎样采样? 先 (
np.random.choice([1, 0], p=[x̂₁, 1 − x̂₁])),再 ,再 …… - 有多少参数? 。
代码 01 第 1、2 部分把这些算了一遍: 时 2,080 个参数, 时 307,720 个(完整的表要 )。随机取一组 的 4 像素例子:
| 像素 | 条件 | 这一项 | |
|---|---|---|---|
| (无) | 0.522 | ||
| 0.413 | |||
| 0.455 | |||
| 0.758 |
乘起来 ;对全部 16 种取值求和恰好是 1——任何 都如此。注意两个过程的不对称:求概率时,所有 都只依赖已知的 ,可以一次并行算完;采样时,必须先抽出 才能算 ,只能一个一个来。这个不对称贯穿所有自回归模型。
2.2 在像素世界上训练 FVSBN
代码 01 第 3 部分(64 个逻辑回归的系数放进一个 的严格下三角矩阵,一次矩阵乘法算完所有条件):
| 模型 | 参数个数 | 测试:比真实多 bit | 训练:比真实多 bit |
|---|---|---|---|
| FVSBN(64 个逻辑回归) | 2,080 | 4.65 | 4.35 |
| 贝叶斯网络:独立像素 | 64 | 9.98 | 10.02 |
| 贝叶斯网络:左 + 左上 + 上 + 右上 | 771 | 5.26 | 5.13 |
| 贝叶斯网络:左 2 + 上 2 + 两个对角 | 2,575 | 3.64 | 3.31 |
(贝叶斯网络是第 2 讲的 PixelBN,用同样的 1 万张训练图。)
FVSBN 胜过四邻居的表,却输给了六邻居的表。这说明了两种表示各自的代价:表能表示邻居之间的任意组合(“左边两个都黑”和”只有左边一个黑”可以给完全不同的概率),逻辑回归只能让每个像素各自线性地”投票”。FVSBN “看得远”(以前面所有像素为条件),局部的表”看得细”——下一步自然是两者兼得:看得远、又能表示组合。这就是神经网络条件分布要做的事。
2.3 FVSBN 学到了什么
条件概率 。 代码 01 第 5 部分把一张测试图上每个像素的 画成深浅图(原课 slide 11 右图对 NADE 做了同样的事):笔画的第一个像素很难预测( 很浅——在它之前,模型不知道形状会从哪里开始);笔画开始以后,后面像素的 明显升高(约 0.4–0.6),但并不果断——线性模型没法确定”这是一条横线、还要再画 2 个像素”。
系数。 第 6 部分打印了像素 (4,4) 那个逻辑回归的系数:最大的正系数在紧挨着的左边 (4,3)(+1.4)和上边 (3,4)(+1.2);隔一个的 (4,2)、(2,4) 也是正的(+0.8、+1.0);而正好隔 4 个的 (4,0)、(0,4) 是负的(−0.7、−0.8)。如果 4 个像素之前就开始了一条线,长度为 4 的线到 (4,3) / (3,4) 就已经结束了——模型用线性的方式学到了一点”线长 4 个像素”的规律。没有人告诉它”要看邻居”,它从数据里学到了局部性。
样本里能看到横线、竖线、方框的片段,但常常画不完整或画过头。原课 slide 8 展示的 FVSBN 样本(Caltech 101 剪影)也是这样:大致的形状对了,细节模糊。
3. NADE、MADE 与自编码器 · NADE, MADE and autoencoders
3.1 NADE:单隐藏层,加上权重共享
原课第 9 页:为了改进模型,用单隐藏层的神经网络代替逻辑回归:
如果每个条件都有自己的 ,参数会比 FVSBN 还多。第 10 页的关键一步是权重共享(tie weights):所有条件共用同一个矩阵 和偏置 ,第 个条件只用 的前 列:
这叫 NADE(Neural Autoregressive Density Estimation,Larochelle & Murray 2011)。如果 ,参数一共有多少?、,再加 个逻辑回归系数向量 ——线性于 。概率在 时间内算完。
为什么是 ?因为权重共享让隐藏层的输入可以递推:记 ,则
从 到 只要加一列。代码 02 用累加和(cumsum)一次算出全部 ,和”对每个 单独算 “的朴素写法比较,logit 的最大差是 (float32 的舍入误差)。参数个数():
| 像素数 | FVSBN: | NADE: |
|---|---|---|
| 64 | 2,080 | 8,320 |
| 784 | 307,720 | 101,200 |
| 3072 | 4,720,128 | 396,352 |
时 NADE 反而更多, 一大就反过来了。
一个关于速度的小插曲:代码 02 第 4 部分对 1000 张图计时,NADE 的累加和写法()并不比朴素写法(,64 次小的矩阵乘法)快,甚至更慢(两者都只要几毫秒,具体数字每次运行不同)。原因是累加和写法要建一个 的中间张量,时间花在内存读写上,而矩阵乘法在 CPU 上被高度优化。“运算量少”不等于”跑得快”——在小规模上,常数和内存访问才是主角。
3.2 一般的离散分布与连续变量
非二值的离散变量(原课第 12 页),例如取 0–255 的像素亮度:让 参数化一个类别分布,
softmax 把 sigmoid 推广到 类:,把 个任意实数变成 个非负、和为 1 的概率(numpy:np.exp(a) / np.sum(np.exp(a)))。
连续变量(第 13–14 页),例如语音信号:让 参数化一个连续分布,例如 个高斯的均匀混合,
标准差用 保证非负。这叫 RNADE(Uria et al. 2013)。注意这里又出现了第 2 讲 §6 的思想:每个条件分布形式简单(高斯混合),乘起来的联合分布却可以非常复杂。
3.3 自回归模型 vs 自编码器
原课第 15 页:表面上看,FVSBN 和 NADE 很像一个自编码器(autoencoder):
- 编码器 ,例如 ;
- 解码器 ,使得 ,例如 ;
- 损失:二值变量用 ,连续变量用 。
编码器和解码器被加了限制(例如中间层很窄),不让它学到恒等映射;我们希望 是 的一个有意义的压缩表示(特征学习)。但是:普通的自编码器不是生成模型——它没有定义一个可以从中采样的 上的分布。损失函数看起来像对数似然,可 依赖于整个 ,包括 自己;把这些”概率”乘起来并不构成任何分布。
3.4 MADE:带掩码的自编码器
原课第 16 页:能不能从自编码器得到一个生成模型?需要保证它对应一个合法的贝叶斯网络(DAG 结构),即需要一个链式法则的顺序。如果顺序是 1, 2, 3: 不能依赖任何输入(于是生成时不需要任何输入就能开始); 只能依赖 ;……额外的好处:可以用一个神经网络( 个输入、 个输出)一次前向就产生所有 ,而 NADE 需要 次——在现代硬件上效率高得多。
MADE(Masked Autoencoder for Distribution Estimation,Germain et al. 2015,第 17 页)的办法是用掩码禁止某些路径:
- 给每个输入一个编号:它在顺序里排第几(顺序 时, 的编号是 1、 是 2、 是 3)。
- 每个隐藏单元随机取一个整数 (更准确地说,在 [上一层的最小编号, ] 里取):这个单元最多只能依赖前 个输入。
- 加掩码维持这个不变量:隐藏层的单元只连接上一层中编号小于等于它的单元;输出层严格小于。
代码 02 第 2 部分打印了 slide 17 的例子(3 个输入、顺序 、两层各 4 个隐藏单元):
输入编号:x₁ → 3,x₂ → 1,x₃ → 2
第 1 隐藏层的编号:[1, 1, 2, 2] 第 2 隐藏层的编号:[1, 1, 1, 2]
第 1 层掩码(列 = x₁ x₂ x₃):h1 [0,1,0] h2 [0,1,0] h3 [0,1,1] h4 [0,1,1]
输出层掩码:x̂1(m=3)[1,1,1,1] x̂2(m=1)[0,0,0,0] x̂3(m=2)[1,1,1,0]
⇒ x̂1 依赖 x₂、x₃;x̂2 不依赖任何输入;x̂3 只依赖 x₂
正是 要求的结构。为什么这个规则保证自回归性质?沿着任何一条从输入 到输出 的路径,编号”只增不减”(每层要求 ),最后一步严格增加(要求 );所以只有编号小于 的输入能到达输出 。输出层为什么必须严格大于?如果允许等于,编号为 的隐藏单元可能看到第 个输入,而第 个输出又连接它——输出就”看到了自己”。代码对 64 像素的 MADE(2 × 256 隐藏单元)用雅可比矩阵 做了穷举检查:违反自回归性质的 对为 0。
3.5 实验:NADE、MADE 和 FVSBN
| 模型 | 参数个数 | 测试:比真实多 bit | 训练:比真实多 bit |
|---|---|---|---|
| FVSBN(逻辑回归) | 2,080 | 4.65 | 4.35 |
| NADE(,权重共享) | 8,320 | 3.89 | 3.46 |
| MADE(2 × 256,掩码) | 50,456 | 3.71 | 2.65 |
NADE 把每个条件从逻辑回归换成单隐藏层网络,测试误差从 4.65 降到 3.89 bit:隐藏层能表示像素之间的组合。MADE 参数多得多,测试误差 3.71 bit;它的训练误差(2.65)明显低于测试误差——1 万张图对 5 万个参数来说开始不够了(第 4 讲的过拟合)。三者都是同一个链式法则,区别只在”条件分布用什么函数表示”。
4. 越来越长的历史:RNN 与 Transformer · RNNs and Transformers
4.1 RNN:用一个摘要概括历史
原课第 18 页:要建模 ,难点是”历史” 越来越长。想法:保留一个摘要,递推地更新它:
- 隐藏层 是到时刻 为止看到的输入的摘要;
- 输出层 给出条件分布 的参数;
- 参数是 (初始化)和三个矩阵 ——参数个数和 无关!
4.2 字符 RNN
原课第 19 页(来自 Karpathy):设 ,用 one-hot 编码。自回归地,
看到 以后输出层 (对应 h, e, l, o),于是
(这个 RNN 最想接的是 o:——它还没学好。)代码 03 第 1 部分还把一个随机初始化的小 RNN 处理”hello”的整个过程打印了出来:每一步隐藏向量怎样更新、条件概率是多少、最后相乘得到 。
slides 第 21–24 页展示了在莎士比亚全集、维基百科、婴儿名字上训练的字符 RNN 的样本:生成是一个字符一个字符进行的,模型必须自己学会合法的单词、语法、标点,甚至维基百科的 Markdown 语法(成对出现的 [[ 和 ]])。
4.3 RNN 的优缺点
原课第 20、25 页:
优点:可以用于任意长度的序列;非常一般——对每个可计算的函数,都存在一个有限大小的 RNN 能计算它。
缺点:
- 仍然需要一个顺序;
- 似然的计算是串行的(训练很慢);
- 生成是串行的(这在自回归模型里无法避免);
- 一个隐藏向量要概括全部(不断增长的)历史——例如 要概括 “My friend opened the” 的意思;
- 串行计算,无法并行;
- 从很多步之前取信息时,梯度会爆炸或消失。
4.4 注意力与生成式 Transformer
原课第 26 页:注意力机制拿一个查询向量和一组键向量比较:
- 拿当前的隐藏状态(查询)和过去所有的隐藏状态(键)比较,例如取点积;
- 构造一个注意力分布,判断历史的哪些部分相关,例如用 softmax;
- 构造历史的摘要,例如加权求和;
- 用这个摘要和当前状态预测下一个 token / 词。
第 27 页:当前最先进的模型(GPT)用 Transformer 代替 RNN:用注意力机制自适应地只关注相关的上下文;避免递推计算,只用自注意力,从而可以并行;需要带掩码的自注意力来保持自回归结构(位置 不能看位置 )。
代码 03 的 TransformerAR 是一个 2 层、64 维、4 个头的 GPT 缩小版:输入序列是 (整体右移一位),位置 预测 ;每个位置的输入 = 取值的嵌入 + 可学的位置嵌入。
4.5 实验:RNN、GRU、Transformer
代码 03 第 2 部分(同一份 1 万张训练图;GRU 是带门控的 RNN,门控让它更容易记住几十步之前的信息、缓解梯度消失):
| 模型 | 参数个数 | 测试:比真实多 bit | 训练:比真实多 bit | 训练用时(参考) |
|---|---|---|---|---|
| FVSBN | 2,080 | 4.65 | 4.35 | 不到 1 秒 |
| NADE | 8,320 | 3.89 | 3.46 | 几秒 |
| MADE | 50,456 | 3.71 | 2.65 | 几秒 |
| RNN(tanh,128 维) | 17,025 | 0.91 | 0.82 | 16 秒 |
| GRU(96 维) | 28,897 | 0.83 | 0.72 | 31 秒 |
| Transformer(2 层,64 维) | 104,449 | 1.56 | 1.29 | 50 秒 |
这是本讲最出乎我意料的结果:普通的 tanh RNN 和 GRU 是最好的模型,比 MADE 好近 3 bit,也比 Transformer 好。
- RNN 按光栅顺序一个像素一个像素地更新隐藏状态,像一台有限状态机:可以数”这一行已经画了几个黑像素”、记住”上一行的这个位置有没有笔画”——这正是像素世界的结构。
- Transformer 在训练集上的误差本身就比 GRU 差得多(1.29 vs 0.72),说明主要问题不是过拟合,而是在这个训练预算下(2500 步、1 万张图)还没学到位:它要从 64 个可学的位置嵌入里自己发现二维网格的结构,而 RNN 的”顺序递推”天生就带着这种归纳偏置。我们没有试更长的训练,结论只针对这里的设置(练习 8)。
“Transformer 一定最好”不是定律。架构是一种先验(第 1 讲 §2.2):在大数据、大模型、长序列上,Transformer 的并行性和灵活的注意力胜出;在小而规则的序列上,RNN 的偏置可能恰好更合适。
误差花在哪里? 第 3 部分按行统计了每个像素的条件 bits(每一行 8 个像素的 之和,在测试集上平均):
| 行 | FVSBN | NADE | RNN | GRU | Transformer |
|---|---|---|---|---|---|
| 第 0 行 | 3.24 | 3.25 | 3.20 | 3.19 | 3.19 |
| 第 2 行 | 4.08 | 4.02 | 3.68 | 3.67 | 3.75 |
| 第 4 行 | 4.29 | 4.17 | 3.61 | 3.61 | 3.74 |
| 第 6 行 | 3.49 | 3.33 | 2.83 | 2.80 | 2.98 |
| 合计(8 行) | 30.17 | 29.41 | 26.43 | 26.35 | 27.08 |
第 0 行各模型几乎一样:没有历史可用时,谁也没有优势。差距主要在第 2–5 行(每行约 0.5 bit):形状的中间部分需要”记住上面画了什么”。最后两行大家都变便宜——形状通常已经画完,下面多半是空白。
注意力在看哪里? 第 4 部分把 Transformer 最后一层(4 个头平均)的注意力画了出来。我原以为预测竖笔画中间的像素时,注意力会集中在正上方;实际上两个例子里,最后一层的注意力都主要落在同一行左边的几个像素和开始符上(例如预测 (2,2) 时,(2,0) 0.27、(1,1) 0.14、(2,1) 0.14,开始符 0.21)。一种可能的解释是它在判断”这一行的笔画从哪里开始、已经画了多长”,而”上方有没有笔画”可能由第一层处理。注意力图只是一个线索,不能当作模型”怎样思考”的完整解释。
样本:GRU 的样本是到目前为止最像真实数据的——完整的方框、十字、长度为 4 的线,还带着和真实数据一样的零星噪声像素。但无论 RNN 还是 Transformer,生成都仍然是 64 步串行的:Transformer 解决的是”训练时的并行”和”远距离依赖”,不是”采样慢”。
5. 图像上的自回归模型:PixelRNN、PixelCNN、WaveNet · Autoregressive models for images and audio
5.1 PixelRNN
原课第 28–29 页(van den Oord et al. 2016):按光栅顺序逐像素建模图像;每个像素的条件分布要给出 3 个颜色,再用链式法则分解成
每个条件是一个 256 类的类别分布;条件分布用 RNN 的变体(LSTM + 类似 MADE 的掩码)建模。在下采样的 ImageNet 上效果很好,但非常慢:似然要串行计算。
5.2 PixelCNN 与掩码卷积
原课第 30–32 页:卷积天然适合图像数据,而且在现代硬件上容易并行。PixelCNN(van den Oord et al. 2016)的想法:用卷积架构,根据上下文(一个像素邻域)预测下一个像素。挑战是必须保持自回归结构:掩码卷积保持光栅顺序(彩色图还要额外的掩码处理颜色的顺序)。在 32×32 的 ImageNet 上,PixelCNN 和 PixelRNN 表现相近,但快得多。
代码 04 第 1 部分打印了两种掩码:
A 型(5×5) B 型(3×3)
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 0 0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
保留中心上方的所有行,以及中心所在行的左边——正是光栅顺序里”之前”的像素。第一层用 A 型(连中心也不看,否则就看到了要预测的像素);后面的层用 B 型(可以看中心:那个位置存的已经是”只依赖之前像素”的特征)。
5.3 盲点
堆叠的掩码卷积能看到所有之前的像素吗?代码 04 第 3 部分用梯度精确地画出了训练好的 PixelCNN(1 层 5×5 A 型 + 4 层 3×3 B 型)的感受野(██ = 看得到的之前的像素,░░ = 之前但看不到的像素,<> = 目标):
目标 (6,1):
████████████████
████████████████
██████████████░░
████████████░░░░
██████████░░░░░░
████████░░░░░░░░
██<>· · · · · ·
右上方有一块看不到的三角形区域:目标 (6,1) 之前的 49 个像素里有 10 个看不到(目标 (4,4) 只有 1 个看不到)。这就是原始 PixelCNN 著名的盲点(blind spot):B 型掩码只允许信息”向右下”传播,堆叠几层以后,感受野是一个缺了右上角的三角形。在 8×8 的小画布上,5 层卷积的感受野已经覆盖了几乎整张图,看不到的全是盲点里的像素;在大图上,感受野有限还会让远处的像素也看不到。Gated PixelCNN(van den Oord et al. 2016b)用”竖直栈 + 水平栈”两路卷积消除了盲点。
实验结果(代码 04 第 2 部分):PixelCNN 只有 21,057 个参数(卷积核在所有位置共享),测试误差 0.84 bit,训练误差 0.66——和最好的 GRU(0.83)不相上下,好于 Transformer。我原以为盲点会让它明显吃亏;实际上像素世界的形状最大只有 4×4,预测一个像素主要靠附近的像素,局部的卷积恰好是对路的先验(平移等变:同一种笔画在任何位置都用同一个卷积核识别)。训练时一次卷积就算出全部 64 个条件;采样仍然要 64 次前向计算。
5.4 WaveNet
原课第 35 页(van den Oord et al. 2016):非常有效的语音模型。语音每秒有上万个采样点,要看到足够长的历史,普通卷积的感受野增长太慢。扩张卷积(dilated convolution)让卷积核每隔 个位置才接触一次信号:第 层的扩张率是 ,感受野随层数指数增长。WaveNet 是因果的(只看过去),所以同样是一个自回归模型;它的采样同样是逐个采样点进行的——这直接导致了第 8 讲的 Parallel WaveNet(用流模型把采样并行化)。
6. 应用与总结 · Applications and summary
6.1 PixelDefend:用似然检测对抗样本
原课第 33–34 页:机器学习方法容易受到对抗样本的攻击。能不能检测它们?PixelDefend(Song et al. 2018):在干净的输入上训练一个生成模型 (PixelCNN);对一个新输入算 ;对抗样本在 下的概率显著更低。
代码 05 第 3 部分在像素世界上做了同样的事(异常输入和第 1 讲代码 04 相同):
| 异常输入 | AUC:真实模型 | AUC:GRU | AUC:FVSBN |
|---|---|---|---|
| 噪声更大(ε = 15%) | 0.971 | 0.967 | 0.947 |
| 随机噪声图 | 1.000 | 1.000 | 1.000 |
| 世界里没有的形状:对角线 | 0.896 | 0.863 | 0.728 |
| 两个形状叠在一起 | 0.891 | 0.881 | 0.776 |
| 黑白反色 | 1.000 | 1.000 | 1.000 |
| 空白画布 + 噪声 | 0.616 | 0.480 | 0.209 |
GRU 的 AUC 几乎和真实模型一样:学得越接近真实分布,异常检测就越接近”理论上能做到的程度”;FVSBN 在需要理解结构的异常上差得多。“空白画布”是三者共同的盲区,而且模型越差,越偏爱空白画布(0.616 → 0.480 → 0.209)。即使是完美的模型也抓不住它:问题不只在模型学得好不好,还在”用似然检测异常”这个方法本身(第 1 讲 §4.4、第 15 讲)。
6.2 排行榜
代码 05 第 1 部分:
| 模型 | 参数个数 | 测试:比真实多 bit/图 | 测试 bits/dim |
|---|---|---|---|
| FVSBN | 2,080 | 4.65 | 0.4714 |
| NADE | 8,320 | 3.89 | 0.4595 |
| MADE | 50,456 | 3.71 | 0.4568 |
| RNN | 17,025 | 0.91 | 0.4130 |
| GRU | 28,897 | 0.83 | 0.4116 |
| Transformer | 104,449 | 1.56 | 0.4231 |
| PixelCNN | 21,057 | 0.84 | 0.4118 |
| (真实分布) | 0 | 0.3987 |
参照:第 1 讲的伯努利混合()多 4.62 bit,第 2 讲最好的局部贝叶斯网络(同一份数据)多 3.64 bit。同一个链式法则,条件分布的表示方式决定了一切:从 FVSBN 的 4.65 bit 到 GRU / PixelCNN 的约 0.8 bit。最好的几个模型离真实分布已经不到 1 bit/图(每个像素约 0.013 bit)——自回归模型是精确似然的”优等生”。
6.3 顺序重要吗?
代码 05 第 2 部分:FVSBN 和 MADE 分别用光栅顺序、列优先顺序、随机顺序训练,每种设置训练 3 次(不同的随机排列 / 不同的 MADE 掩码):
| 模型 | 光栅顺序 | 列优先 | 随机顺序 |
|---|---|---|---|
| FVSBN | 4.65(4.65–4.66) | 4.65(4.65–4.66) | 4.65(4.64–4.65) |
| MADE | 3.74(3.71–3.79) | 3.71(3.64–3.75) | 3.30(3.30–3.31) |
理论上,如果每个条件分布都足够灵活(例如一张完整的表),任何顺序都能表示任何分布——链式法则对任何顺序都成立。条件分布被限制在某个函数族里时,顺序可能变得重要。实际结果:FVSBN 对顺序几乎不敏感;MADE 在随机顺序下反而更好(三次都是 3.30),和我预想的”随机顺序最差”相反。一个可能的解释是:光栅顺序的前几十个像素(上面几行)通常是空白,携带的信息很少;随机顺序下,前面几个像素散布在整张图上,很快就告诉模型”形状大概在哪里”,后面的条件因此更容易预测。无论如何,自回归模型必须选一个顺序,怎样选本身就是一个建模决策。
6.4 容易的条件与难的条件
自回归模型精确地给出了 ,那它能回答所有概率问题吗?代码 05 第 4 部分用 GRU(光栅顺序)回答了两个问题,“上半张”是前 32 个像素:
(a) :顺着光栅顺序继续相乘,一次前向计算。模型 12.201 bit,真实分布 11.634 bit,差 0.567 bit——和整体的误差差不多。
(b) :,要对上半张的 亿种取值求和。只能用采样近似:从模型的 抽 个上半张,取 :
| 上半张的样本数 | 估计 − 真实 :平均 | 最大 | 最小 |
|---|---|---|---|
| 1 | −3.383 | 4.705 | −17.801 |
| 10 | −0.658 | 1.711 | −3.762 |
| 100 | −0.268 | 1.158 | −1.950 |
| 1000 | −0.171 | 1.171 | −1.748 |
(20 张测试图;“真实”是像素世界精确边缘化得到的 。)
- 顺着顺序的条件对自回归模型是免费的;逆着顺序的边缘 / 条件就难了,要对所有可能的”前面”求和。
- 单张图的估计可能偏高也可能偏低,但平均偏低,这不是偶然: 本身是 的无偏估计,可 是凹函数,(Jensen 不等式)。 越大越准,但每张图要采样、计算 次。
- 时仍有约 −0.17 bit 的偏差:一部分是剩下的采样误差,一部分是模型本身的误差——估计收敛到的是模型的 ,不是真实的 。
“从隐藏的部分采样、再对条件概率取平均”来估计边缘概率——这正是第 5 讲(隐变量模型的边际似然、重要性采样、ELBO)要处理的问题。
6.5 自回归模型小结(原课 slide 36)
- 容易采样:先 ,再 ……(但要 步串行)
- 容易算概率:算出 、……乘起来(对数相加);理想情况下这些项可以并行算出,训练才快。
- 容易推广到连续变量:例如高斯条件分布 ,或者 logistic 混合。
- 没有天然的办法得到特征、聚类、做无监督学习:自回归模型没有隐变量 ,“这张图是什么形状”这种高层描述不在任何地方显式地出现(第 5 讲的隐变量模型要解决它)。
- 下一讲:学习。
7. 2023 年之后 · Since 2023
- 自回归模型统治了语言。 GPT-4、Claude、Llama、Qwen……所有主流大语言模型都是 §4.4 的生成式 Transformer:,用最大似然在海量文本上训练。本仓库的 CS336、CS324 从工程和规模的角度详细讲了它们。
- 自回归图像生成的复兴。 先用一个”图像分词器”(VQ-VAE / VQGAN,第 17 讲的离散隐变量)把图像变成离散 token,再用 Transformer 自回归地生成 token:DALL·E(2021)、Parti(2022),到 VAR(“预测下一个尺度”而不是下一个像素,NeurIPS 2024 最佳论文)。MAR(Li et al. 2024)则保留自回归的结构,但每个 token 是连续的、用一个小扩散模型建模条件分布——又是”条件分布形式灵活、联合分布由链式法则保证”的思路。2025 年起,GPT-4o 等多模态模型把文字和图像放进同一个自回归模型。
- “采样慢”的对策。 自回归采样必须串行(§2.1),大语言模型的推理成本主要来自这里。投机解码(speculative decoding)用一个小模型先猜几个 token,再用大模型一次并行地验证,在不改变输出分布的前提下加速;KV 缓存避免每一步重复计算之前的位置(本讲代码为了简单没有做,每一步都重算整个序列)。
- 顺序的问题。 §6.3 发现顺序会影响结果。“任意顺序”的自回归模型(MADE 原论文就提出了用多个随机顺序训练,类似的想法后来发展成 any-order / σ-GPT 等)可以在推理时选择顺序;第 18 讲的掩码扩散语言模型可以看成一种”一次生成多个、顺序不固定”的自回归模型,它正是为了摆脱”必须从左到右”而提出的。
8. 小结 · Summary
- 自回归模型 = 链式法则 + 带参数的条件分布。链式法则是恒等式,“条件分布的函数形式”才是假设。它的三大优点:合法性免费(不需要归一化常数)、似然精确可算、训练就是”预测下一个”的监督学习。
- FVSBN 每个条件一个逻辑回归, 个参数;求概率可以并行,采样只能串行。它”看得远”但只能线性投票,在像素世界上输给”看得细”的六邻居表(4.65 vs 3.64 bit)。
- NADE 用共享权重的单隐藏层网络,参数线性于 , 可以递推();推广到类别分布(softmax)和连续变量(RNADE)。普通的自编码器不是生成模型;MADE 用编号和掩码把自编码器变成合法的自回归模型,一次前向算出所有条件。
- RNN 用一个隐藏向量概括历史,参数和长度无关,但串行、梯度消失、“一个向量装下全部历史”;注意力按相关程度加权历史;生成式 Transformer 用带因果掩码的自注意力并行训练。在像素世界上,RNN / GRU(0.91 / 0.83 bit)反而胜过 Transformer(1.56 bit):架构是一种先验。
- PixelCNN 用 A / B 型掩码卷积保持光栅顺序,训练快、参数少,但有右上方的盲点;在像素世界上它和 GRU 不相上下(0.84 bit)。PixelRNN 好但慢;WaveNet 用扩张卷积扩大感受野。
- 优点与局限:采样容易但 步串行;似然精确且可并行;必须选顺序(MADE 在随机顺序下反而更好);顺着顺序的条件容易,逆着顺序的条件需要对指数多的项求和(采样近似有 Jensen 偏差);没有天然的隐表示。学得好的模型做异常检测接近理论上限,但”简单的输入概率高”仍是似然方法的盲区。
9. 常见误区 · Common pitfalls
- “自回归模型对分布做了很强的假设,因为它用了链式法则。” 链式法则是恒等式,不是假设;假设在于条件分布的函数形式(逻辑回归、神经网络……)。如果条件分布足够灵活,自回归模型能表示任何分布。
- “自回归模型生成快,因为训练快。” 训练(求似然)可以一次并行算完所有条件;采样必须一个一个来, 个变量就要 次串行计算。MADE、PixelCNN、Transformer 都只加速了前者。
- “自编码器的重构损失就是对数似然,所以自编码器是生成模型。” 普通自编码器的 依赖整个 (包括 自己),这些”概率”乘起来不构成任何分布,也没法从中采样。必须加上自回归结构(MADE)才行。
- “MADE 的掩码随便设就行,只要输出不连到对应的输入。” 只断开”输入 → 输出 “的直接连接不够:信息可以经过隐藏单元绕过去。必须用编号规则(隐藏层 、输出层 )保证所有路径都满足顺序。
- “掩码卷积能看到所有之前的像素。” 堆叠的 B 型掩码卷积有右上方的盲点(代码 04:目标 (6,1) 之前的 49 个像素里 10 个看不到)。
- “Transformer 一定比 RNN 好。” 在像素世界的设置里(小数据、规则的短序列、有限的训练预算),GRU 比 Transformer 好 0.7 bit。架构的优劣取决于数据和规模。
- “自回归模型能精确算 ,所以任何条件概率都好算。” 只有”顺着顺序”的条件好算; 要对 种上半张求和,只能用采样近似,而且 估计平均偏低。
- “似然越高,异常检测就一定越好。” 学得越好的模型确实越接近理论上限,但理论上限本身有盲区(空白画布):完美的模型也抓不住”简单”的异常。
10. 练习 · Exercises
练习 1(参数计数)
(a) 推导 FVSBN 的参数个数 。
(b) 一个灰度图(每个像素 256 个取值)的”类别分布版 FVSBN”:第 个条件是一个 softmax 回归,以前面 个像素的数值为输入。参数有多少?
(c) NADE(隐藏维数 )的参数个数为什么是 ?对应 ar_models.NADE 里的哪几个张量?
参考答案
(a) 第 个逻辑回归有 个系数加 1 个偏置,共 个参数;。
(b) 第 个 softmax 回归有 256 个输出,每个输出有 个系数和 1 个偏置: 个参数(严格地说 softmax 有一个冗余自由度,可以减去一组)。合计 。(如果把每个前面的像素也 one-hot 编码成 256 维,系数还要再乘 256。)
(c) (共享的第一层,)+ ()+ (每个条件的输出权重 ,)+ (每个条件的输出偏置,)。对应代码里的 self.W、self.c、self.V、self.b。
练习 2(FVSBN 一定是合法的分布) 证明:对任意参数 ,FVSBN 的 。提示:从 开始求和。这个证明用到了 的什么性质?换成任意函数 还成立吗?
参考答案
,所以对 求和后乘积里最后一个因子消失;依次对 求和,每次都同理。只用到了”每个条件分布本身是一个合法的分布”,即 。 保证了这一点;换成任意函数 时,只要输出被限制在 (或者对类别分布用 softmax)就仍然成立——这就是为什么自回归模型”合法性免费”。
练习 3(NADE 的递推) 写出 和 的关系,证明 NADE 算出全部 个条件的总运算量是 。朴素写法(每个 单独算 )的运算量是多少?代码 02 的计时为什么和这个分析不一致?
参考答案
,每次 ;再算 和 各 。总共 。朴素写法第 个条件要 ,合计 。代码 02 里 、 都很小,运算量的差别被常数和内存访问淹没了:累加和写法要建一个 的中间张量并多次读写,而 64 次小的矩阵乘法调用的是高度优化的 BLAS。复杂度分析描述的是 很大时的趋势。
练习 4(MADE 的掩码) 4 个输入、顺序 、一个隐藏层,隐藏单元的编号是 。(a) 写出输入层到隐藏层的掩码(5 × 4)和隐藏层到输出层的掩码(4 × 5)。(b) 输出 依赖哪些输入? 呢?(c) 有没有输入完全没被用到?这会带来什么后果?
参考答案
(a) 输入编号 。隐藏单元 连接输入 当且仅当 :编号 1 的单元只连 ;编号 3 的连 ;编号 2 的连 。输出 连接隐藏单元 当且仅当 : 不连任何单元; 连编号 1 的两个单元; 连编号 1、2 的四个单元; 连全部 5 个。 (b) 依赖 (通过编号 3 的单元能到 ); 依赖 。 (c) 不连任何隐藏单元——它是顺序里的最后一个,本来就不需要被任何条件使用,这是正确的。但如果编号都偏小(例如没有一个隐藏单元的编号是 3), 就看不到 ,模型会损失表达能力(虽然仍然合法)。所以 MADE 的编号要在 里取,并且常常训练时换几组编号。
练习 5(盲点) 只用两层 3×3 的 B 型掩码卷积(第一层换成 3×3 的 A 型)。对目标像素 ,第二层输出能看到哪些输入像素?画出来,指出盲点。
参考答案
A 型 3×3 让第一层在 的特征看到偏移 处的输入;B 型 3×3 让第二层在 看到第一层偏移 处的特征。目标能看到的输入偏移就是两组偏移所有可能的和:第 行的 ;第 行的 ;第 行的 。第 行的 在光栅顺序里排在目标之前、也在 5×5 的范围内,却看不到——这就是盲点的雏形。层数越多,缺失的区域越大,形成右上方的三角形(对照代码 04 的图)。
练习 6(顺序与表达能力) (a) 证明:如果每个条件分布都用完整的表表示,对任意顺序,自回归模型都能精确表示任意分布。 (b) 条件分布限制为逻辑回归(FVSBN)。两个二值变量时,顺序有没有影响?三个呢?提示:把 写成对数线性展开 。
参考答案
(a) 链式法则对任何顺序都成立:,而完整的表能表示任何条件分布。
(b) 两个变量时, 是任意的伯努利, 的两个参数恰好能表示任意的两行 CPT,所以任何顺序都能表示任何分布。三个变量时,前两个因子仍然不受限制;最后一个因子 ,它是逻辑回归的形式当且仅当 。所以 FVSBN 的分布族 = “三阶交互项为 0 的分布”。三阶交互项 对三个变量是对称的,和谁排在最后无关——三个变量时顺序也没有影响(异或 正是一个 的分布,任何顺序都表示不了)。四个变量起,中间的条件分布也受限制,而且限制的是边缘分布的交互项,不同顺序的分布族一般不同。代码 05 里 FVSBN 对顺序几乎不敏感,和这个分析的精神一致:线性条件分布的”缺陷”在很大程度上是对称的。
练习 7(Jensen 偏差) 代码 05 的 。(a) 证明 。(b) 证明 。(c) 时,“估计 − 真实”的最小值是 −17.8 bit,这意味着什么?
参考答案
(a) , 个独立样本的平均也一样。 (b) 是凹函数,由 Jensen 不等式 。 (c) 抽到的那个上半张和观察到的下半张”不配”(例如下半张是一个方框的下半部分,而抽到的上半张是空白), 极小。大多数样本的贡献都很小,真正有贡献的上半张很少被抽到——这就是第 5 讲说的”朴素蒙特卡洛几乎所有样本都贡献为零”,改进的办法是从一个更好的分布(接近 )里抽样:重要性采样。
练习 8(动手:让 Transformer 训练得更久)
把 ar_models.CONFIGS["transformer"] 的 steps 从 2500 改成 10000,删掉 checkpoints/transformer.pt,重新运行代码 03。这会运行约 3–4 分钟(超过本讲义”2 分钟”的约定,所以作者没有运行,留给你)。预测:Transformer 会不会追上 GRU?训练误差和测试误差会怎样变化?
参考答案(预测的思路)
如果 Transformer 落后的原因是”没学到位”(训练误差和测试误差很接近、都偏高),更长的训练应该会继续降低两者,可能缩小和 GRU 的差距;如果主要原因是”从位置嵌入里学二维结构需要更多数据”,那么只加训练步数、不加数据,训练误差会下降,但测试误差下降得少,两者的差距会拉大(开始过拟合)。具体结果以你的运行为准。做完记得把 steps 改回 2500(或者删掉新的缓存),否则代码 04、05 读到的是你训练的版本。
练习 9(思考:自回归模型的”特征”) slide 36 说自回归模型”没有天然的办法得到特征”。可是 GRU 的隐藏向量 不正是整张图的一个摘要吗?它和第 5–6 讲 VAE 的隐变量 有什么不同?
参考答案
确实是一个确定性的摘要,可以拿来当特征用(很多工作也这样做)。但它和隐变量 有两点本质不同:(1) 不是生成过程的一部分——没有”先抽 、再生成 “的过程,所以不能通过控制 来控制生成(不能”指定形状 = 十字”再采样);(2) 依赖于顺序,只概括了前 个像素,而且它的含义没有任何约束(不像 有先验 )。隐变量模型把”高层描述”放进了模型的定义里,于是推断 有明确的含义——代价是似然不再好算(第 5 讲)。
11. 延伸阅读 · Further reading
原课材料
- CS236 Fall 2023 Lecture 3 slides:https://deepgenerativemodels.github.io/assets/slides/cs236_lecture3.pdf
- CS236 课程笔记 Autoregressive Models:https://deepgenerativemodels.github.io/notes/autoregressive/
本讲的模型
- FVSBN:Frey, Hinton & Dayan, Does the wake-sleep algorithm produce good density estimators?, NeurIPS 1996;Gan et al., Learning Deep Sigmoid Belief Networks with Data Augmentation, AISTATS 2015(slide 8 的样本)
- NADE:Larochelle & Murray, The Neural Autoregressive Distribution Estimator, AISTATS 2011;RNADE:Uria, Murray & Larochelle, NeurIPS 2013
- MADE:Germain, Gregor, Murray & Larochelle, MADE: Masked Autoencoder for Distribution Estimation, ICML 2015
- 字符 RNN:Karpathy, The Unreasonable Effectiveness of Recurrent Neural Networks(博客,2015)
- Transformer:Vaswani et al., Attention Is All You Need, NeurIPS 2017;GPT-2:Radford et al. 2019
- PixelRNN / PixelCNN:van den Oord, Kalchbrenner & Kavukcuoglu, Pixel Recurrent Neural Networks, ICML 2016;Gated PixelCNN:van den Oord et al., Conditional Image Generation with PixelCNN Decoders, NeurIPS 2016
- WaveNet:van den Oord et al., WaveNet: A Generative Model for Raw Audio, 2016
- PixelDefend:Song, Kim, Nowozin, Ermon & Kushman, ICLR 2018
2023 年之后
- Tian et al., Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction(VAR), NeurIPS 2024
- Li, Tian, Li, Deng & He, Autoregressive Image Generation without Vector Quantization(MAR), NeurIPS 2024
- Leviathan, Kalman & Matias, Fast Inference from Transformers via Speculative Decoding, ICML 2023
12. 下一讲预告 · Next lecture
本讲解决了”怎样表示 “,训练时直接用了”最小化测试集上的 “。第 4 讲(原课 Lecture 4 Maximum Likelihood Learning)回答第二个问题:怎样学习,以及为什么是这个目标:
- “最好的”模型是什么意思?学习 = 密度估计;
- KL 散度:定义、非负性、不对称、“多用了多少比特”的压缩解释;
- 最小化 = 最大化期望对数似然——但因为熵未知,我们永远不知道离最优还差多远(像素世界是个例外);
- 蒙特卡洛估计、经验对数似然、抛硬币的 MLE;
- 自回归模型的 MLE:梯度下降与随机梯度下降;参数共享;
- 过拟合与偏差–方差权衡——本讲 MADE 的训练 / 测试差距、第 2 讲不加正则的神经网络,都会在那里得到解释。