标准化流
这一章的主角是标准化流(Normalizing Flows)——一种既会"采样"又会"打分"的生成模型:能像 GAN 一样生成新样本,也能精确算出任意样本的概率。学完这章,你会懂"变形如何改变密度"、可逆网络怎么揉分布,以及它和 GAN、VAE 的取舍。
生成模型的两副担子:采样与打分
生成模型要干两件事:采样(sampling)——从学到的分布里抽出新样本;算概率(likelihood)——给样本打分,分数越高越像真货。
上一章的 GAN 只会第一件:它能用噪声生成以假乱真的图片,但模型没有定义概率分布,没法回答"这张图多像真的"。标准化流两件都会,而且概率是精确算出来的——这是它的招牌。
核心思想:把简单分布"揉"成复杂分布
标准化流的思路一句话说清:从简单分布出发,通过一连串可逆变换,把它慢慢"揉"成复杂的数据分布。
我们选一个简单的基础分布 $\Pr(z)$——通常是标准正态,即以 0 为中心的钟形曲线——再套一个带参数 $\phi$ 的函数 $x = f[z, \phi]$。$\phi$ 是旋钮,拧到合适位置,$x$ 的分布恰好长成数据的样子。
于是采样出奇简单:从基础分布抽一个 $z^*$,算一遍 $x^* = f[z^*, \phi]$,新样本就诞生了。
把标准正态想象成一块厚薄均匀的面团。每一层变换就是一次揉面:拉长、压扁,一层层揉成数据的复杂形状——揉薄处密度变稀,压厚处变浓。如果每步都能"倒放",面团就能复原成最初均匀的样子:这就是"流(flow)"的来历,"标准化"则指反着走时,任何分布都被归一化回标准正态。
变形要付出代价:变量变换公式
采样容易,反过来问:给定 $x$,它的概率是多少?要小心——变形会改变密度:拉伸输入的地方,概率被"摊薄";压缩的地方,密度被"挤浓"。但总面积必须恒为 1,所以换算密度要乘一个修正因子——一维下就是导数绝对值的倒数:
$$\Pr(x|\phi) = \left|\frac{\partial f(z,\phi)}{\partial z}\right|^{-1} \Pr(z), \quad \text{其中 } z = f^{-1}[x, \phi]$$这叫变量变换公式(change of variables):逆变换找到产生 $x$ 的 $z$,查它在基础分布里的概率,再除以 $|f'(z)|$。导数大于 1(拉伸)概率变小,小于 1(压缩)概率变大。隐藏要求:$f$ 必须可逆——这是对架构最根本的约束。
到了高维,$z$、$x$ 成向量,导数升级为 $D \times D$ 的雅可比矩阵,修正因子也升级为行列式绝对值的倒数:
$$\Pr(x|\phi) = \left|\det \frac{\partial f(z,\phi)}{\partial z}\right|^{-1} \Pr(z)$$一维"面积守恒",高维"体积守恒":行列式告诉我们小块邻域被放大几倍,放得越大密度越稀。一般网络算它要 $O(D^3)$,太贵——所有精巧设计都为了让行列式好算。训练时拧 $\phi$ 让样本总概率最大,即最小化负对数似然 $\sum_i -\log \Pr(x_i|\phi)$。
光说不练假把式。用 NumPy 验证:用"负半轴压缩 5 倍"的可逆变换揉标准正态,再用公式算密度,与采样直方图对比:
import numpy as np
import matplotlib.pyplot as plt
# 可逆变换 x = f(z):z 为负时被压缩 5 倍,非负时原样保留
def f(z):
return np.where(z >= 0, z, 0.2 * z)
def dfdz(z): # 一维"雅可比":|f'(z)|
return np.where(z >= 0, 1.0, 0.2)
# 1) 采样:从基础分布抽 z,正向映射得到"数据"
rng = np.random.default_rng(0)
z = rng.normal(size=200_000)
x = f(z)
# 2) 变量变换公式:Pr(x) = Pr(z) / |f'(z)|,其中 z = f^{-1}(x)
grid = np.linspace(-5, 5, 400)
zx = np.where(grid >= 0, grid, grid / 0.2) # 逆映射
pr_x = np.exp(-0.5 * zx**2) / np.sqrt(2 * np.pi) / dfdz(grid)
# 3) 对比:公式曲线应当与样本直方图重合
plt.hist(x, bins=100, density=True, alpha=0.5, label="样本")
plt.plot(grid, pr_x, label="公式 Pr(x)")
plt.legend()
plt.show()
跑起来会看到,公式曲线与直方图严丝合缝地重合——压缩一侧密度明显变高,正是修正因子在起作用。
可逆网络与耦合层
单层 $f$ 表达能力太弱。真正的做法是把很多层串起来:$x = f_K[f_{K-1}[\cdots f_1[z]\cdots]]$。好消息是,复合函数的雅可比行列式等于各层行列式的乘积:
$$\left|\det \frac{\partial f}{\partial z}\right| = \prod_{k=1}^{K} \left|\det \frac{\partial f_k}{\partial f_{k-1}}\right|$$意思是总变形因子等于各层变形因子相乘——把 10 次"放大 2 倍"串起来,总共放大 $2^{10}$ 倍。但每层必须满足四个条件:可逆、逆好算、雅可比好算、有表达力;训练要反复给样本打分,慢一点都不行。
最常用的破解办法是耦合层:把输入 $h$ 切成两半,$h_1$ 原样输出,$h_2$ 用可逆小函数 $g$ 变换,$g$ 的参数由 $h_1$ 决定:
$$h_1' = h_1, \qquad h_2' = g[h_2, \phi[h_1]]$$妙处在于雅可比是块三角的,行列式等于对角块乘积,几乎免费;逆变换也简单:取回 $h_1$ → 算参数 → 对 $h_2'$ 做 $g^{-1}$($g$ 通常是缩放加平移这类简单可逆函数)。代价是每层只动一半变量,所以层间穿插固定随机置换,让每个维度都被照顾到。图像模型 GLOW 就靠它把真实图片一步步"倒放"成噪声。
精确似然 vs 训练难度:三种生成模型的取舍
标准化流这么全能,是不是无敌了?并非如此,它和 GAN、VAE 各有取舍:
- GAN:采样质量高、速度快,但模型里没有概率分布,算不了似然,对抗训练也难调。
- VAE:能算概率,但只是下界(ELBO),不是精确值,样本通常偏模糊。
- 标准化流:采样、精确似然两不误,还能客串密度估计器做异常检测;代价是被"可逆 + 雅可比好算"锁住,图像质量通常逊于 GAN 和扩散模型。
一句话:精确似然是流模型的王牌,可逆架构是它的紧箍咒。