上一篇讲完 VAE,走到一条因果链:VAE 通过把 Encoder 的输出从确定点变成概率分布,让 latent space 服从已知 prior,于是可以从 prior 采样、交给 Decoder 生成新样本。
整个过程很精巧,但回头看,它对概率计算的依赖很重:Encoder 参数化 \(q(z|x)\),训练目标里有 KL divergence、有 reconstruction likelihood,每一步都在和 density 打交道。
继续看 6.S191 Lecture 4,下一个出场的生成模型是 GAN(Generative Adversarial Network,生成对抗网络)。我之前对 GAN 的了解基本停留在"两个网络互相对抗"这句话。看下去才发现,GAN 走了一条和 VAE 完全不同的路——它根本不计算 density。
不计算 density 怎么做生成?这是我开始看 GAN 时最大的困惑。
不知道 density,怎么比较两个分布#
先退一步。生成模型的目标是什么?
学习一个生成分布 \(p_g\),让它尽量接近真实数据分布 \(p_{\text{data}}\)。用数学的话说,希望:
$$ p_g(x) \approx p_{\text{data}}(x) $$但实际操作中,两边都有麻烦。
\(p_{\text{data}}(x)\) 没有解析形式。我们手上只有从真实分布中采样得到的一堆 samples。
\(p_g(x)\) 通常也没有显式的 density。Generator 的做法是从一个简单分布采样 \(z\),然后通过一个 neural network \(G\) 把它映射成 \(x = G(z)\)。我们能从 \(p_g\) 中采样,但不知道 \(p_g(x)\) 在任意一个 \(x\) 处等于多少。
高维空间里,直接比较两个分布的差异本来就很困难。而我们连两个分布的 density 都不知道。
GAN 的做法是:既然不知道怎么直接比较两个分布,那就训练一个 classifier 来区分它们的 samples。 classifier 做的事情很朴素——给一个样本,判断它是 real 还是 fake。但这个过程间接地给出了两个分布之间差异的信号。Generator 根据这个信号调整自己的输出,让两个分布靠得更近。
后面所有的数学,包括 minimax objective、最优判别器、JS divergence,都是围绕这个想法展开的。
Generator 和 Discriminator 各自在做什么#
GAN 由两个 neural network 组成。
Generator G#
Generator 接收一个简单的随机变量作为输入:
$$ z \sim p_z(z) $$通常是标准高斯分布 \(\mathcal{N}(0, I)\)。然后输出一个生成样本:
$$ x_{\text{fake}} = G(z) $$\(G\) 把采出来的 \(z\) 映射成一个生成样本。这个 \(z\) 从哪来、为什么叫 noise,当时把我卡住了一下。
为什么 Generator 从 noise 开始?#
6.S191 的 slide 上画着:Gaussian noise \(z \sim \mathcal{N}(0,1)\),经过 Generator 做 distribution transformation(分布变换),变成复杂的数据分布。
我当时最直接的疑问是:Gaussian noise 是什么东西?和高斯分布有关吗?跟着又冒出一串——为什么输入是一堆随机数?这是在给图片加噪声吗?为什么偏偏用 Gaussian?Generator 到底只是在把随机向量变成图片,还是在做更本质的事情?
Gaussian noise 没有比字面意思更神秘的东西。它就是从 Gaussian distribution(高斯分布)里随机采样得到的数值。一维最简单:
$$ z \sim \mathcal{N}(0, 1) $$意思是 \(z\) 从均值为 0、方差为 1 的标准高斯里抽出来。可能抽到 0.31,也可能抽到 -1.17、0.02、2.13。实际 GAN 里 \(z\) 通常不是标量,而是高维向量,比如 \(z \in \mathbb{R}^{128}\):
$$ z = [0.31,\; -1.17,\; 0.02,\; 0.73,\; \ldots] $$每个维度按标准高斯采样、彼此通常独立,更常见的写法是 \(z \sim \mathcal{N}(0, I)\)。\(I\) 在这里只是在说:各维各自是标准高斯,通常彼此独立。
“noise” 这个词太容易让人联想到:已有一张图,叠上随机噪点,得到 noisy image。经典 GAN 甚至根本不需要先有一张图。流程是随机采样 \(z\),输入 Generator,输出一张图。noise 本身就是 Generator 的输入。这个词主要在表达:它来自随机采样,输入没有人为规定的语义——并没有预先定义"第 3 维表示头发颜色"“第 10 维表示脸型”。Generator 自己通过训练学习怎么利用这些随机自由度。\(z\) 有点像一个连续、高维的随机 seed,但这只是辅助直觉,不应该把 latent vector 严格等同于普通程序里的 random seed。
GAN 也并不必须用高斯。更一般的形式是 \(z \sim p_z(z)\),\(p_z\) 是一个简单、容易采样的 noise distribution / prior distribution(噪声分布 / 先验分布)。标准高斯 \(z \sim \mathcal{N}(0, I)\) 和均匀分布 \(z_i \sim U(-1, 1)\) 都常见。我后来才意识到,问题不在于 Gaussian 有某种特殊魔法,而在于需要一个简单、已知、容易采样的概率分布当起点。标准高斯只是一个非常自然、常见的选择。
VAE 也经常从类似的 \(z \sim \mathcal{N}(0, I)\) 出发,但两边用它的方式不一样:VAE 靠 Encoder、Decoder 和 KL divergence 这些 probabilistic objective 组织 latent space;GAN 这边 \(z\) 只是采样起点,让 \(p_g\) 靠近 \(p_{\text{data}}\) 的信号来自 Discriminator 的 adversarial training。
我一开始也只看到 random vector → Generator → image,等于只从单个 sample 理解 Generator。一次采样 \(z \sim p_z\),再算 \(x = G_\theta(z)\),回答的是一张 generated image 怎么来的——比如一个 128 维随机向量,经过 Generator,变成一张 256×256 的图片。
但如果不断从 \(p_z\) 里采样 \(z_1, z_2, z_3, \ldots\),分别送进 Generator,这些生成样本整体会形成一个新的概率分布 \(p_g(x)\)。从分布的视角看:
$$ p_z \xrightarrow{G_\theta} p_g $$我后来才看清楚:Generator 不只是一个"把随机数变成图片"的函数。它在学习一个 distribution transformation,把简单的 \(p_z\) 映射成数据空间里的复杂分布 \(p_g\)。
左边是 sample 视角:\(z \to G(z)\)。右边是 distribution 视角:\(p_z \to p_g\),再经过 adversarial training 希望 \(p_g \to p_{\text{data}}\)。
Generator 并没有直接写出 \(p_g(x) = \ldots\) 这样的公式,通常也不会去算某张图片 \(x\) 的概率密度。它只是提供了一种采样方法:从 \(p_z\) 采 \(z\),算 \(x = G(z)\),不断重复。这些 \(x\) 的总体统计分布就是 \(p_g\)。Discriminator 出场之后,整件事才接到怎么让这个隐式定义出来的 \(p_g\) 靠近 \(p_{\text{data}}\):
$$ p_z \xrightarrow{G_\theta} p_g \xrightarrow{\text{adversarial training}} p_{\text{data}} $$Discriminator D#
Discriminator 接收一个样本 \(x\),输出一个 0 到 1 之间的值:
$$ D(x) \in (0, 1) $$可以理解为 Discriminator 估计的"这个样本是真实的"的概率:
$$ D(x) \approx P(\text{real} \mid x) $$Discriminator 的目标很直接:
- 对真实样本,\(D(x_{\text{real}}) \to 1\)
- 对生成样本,\(D(G(z)) \to 0\)
而 Generator 的目标和 D 在生成样本上相反——希望 \(D(G(z)) \to 1\),让 Discriminator 误判 fake 为 real。
注意图中从 \(G(z)\) 到 Discriminator 的那条边上标注的 \(D(G(z))\)。这个量同时被 Generator 和 Discriminator 影响,是后面整个讨论的核心。
“对抗"到底发生在哪里#
“两个网络互相对抗"这句话我听了很多次,但一直没想清楚到底什么叫"对抗”。
一开始我以为:因为有两个 network,所以叫 adversarial。但仔细一想,这说不通。普通的两层网络 \(A \to B \to \text{Loss}\),Loss 也同时依赖 A 和 B 的参数,但 A 和 B 是合作关系——它们一起把 Loss 降低。
后来发现,关键不在于"存在两个网络”,而在于这两组参数围绕同一个量有相反的目标。
设:
$$ q = D(G(z)) $$这个 \(q\) 同时被 \(\theta_D\)(Discriminator 的参数)和 \(\theta_G\)(Generator 的参数)影响。
Discriminator 希望 \(q \to 0\)(正确识别 fake)。Generator 希望 \(q \to 1\)(让 Discriminator 误判为 real)。
左边是普通网络:两组参数对同一个 Loss 的优化方向一致,是合作关系。右边是 GAN:两组参数围绕 \(D(G(z))\) 的优化方向完全相反——一个拉向 0,一个拉向 1。
对抗不是因为存在两个网络,而是因为两组参数围绕同一个量 \(D(G(z))\) 有相冲突的优化方向。
从 BCE 推到 minimax#
理解了对抗结构之后,目标函数就不用死记了——它从标准的二分类 loss 自然推出来。
把 Discriminator 看作一个普通的 binary classifier。真实样本标记为 \(y = 1\),生成样本标记为 \(y = 0\)。标准的 Bernoulli log-likelihood(也就是 BCE,Binary Cross Entropy)是:
$$ y \log D(x) + (1 - y) \log(1 - D(x)) $$代入两类样本:
- 真实样本 \(x \sim p_{\text{data}}\),\(y = 1\),贡献 \(\log D(x)\)
- 生成样本 \(x = G(z)\),\(y = 0\),贡献 \(\log(1 - D(G(z)))\)
Discriminator 要最大化分类准确率,所以 D 的目标是最大化期望:
$$ \max_D \; \mathbb{E}_{x \sim p_{\text{data}}}[\log D(x)] + \mathbb{E}_{z \sim p_z}[\log(1 - D(G(z)))] $$Generator 的目标和 D 相反——G 希望 D 尽可能分不清 real 和 fake,也就是说 G 希望最小化上面这个量。于是自然得到 GAN 论文里的 minimax objective:
$$ \min_G \max_D \; \mathbb{E}_{x \sim p_{\text{data}}}[\log D(x)] + \mathbb{E}_{z \sim p_z}[\log(1 - D(G(z)))] $$看这个公式需要注意几个点:
\(\max_D\) 的意思是:给定当前的 G,D 试图把 real 和 fake 分开。分得越好,这个值越大。
\(\min_G\) 的意思是:给定当前的 D,G 试图让 D 的分类失败。
第一项 \(\mathbb{E}[\log D(x)]\) 和 G 没有关系——因为 real samples 不经过 G。
G 真正能控制的只有第二项里的 \(D(G(z))\)。G 通过改变自己的参数来改变 \(G(z)\) 的输出,进而影响 \(D(G(z))\) 的值。
目标完全相反,那还怎么训练#
到这里我被卡住了。
D 要最大化,G 要最小化,同一个 objective。如果在一个 backward pass 里同时做两件事,梯度方向不就互相抵消了吗?
答案是:GAN 不在一步里同时优化两个目标。实际训练是交替优化(Alternating Optimization):
- 固定 G,训练 D 若干步——此时就是标准的二分类器训练。
- 固定 D,训练 G 若干步——此时 D 提供的梯度是一个固定的 landscape,G 在这个 landscape 上做梯度下降。
然后重复。
单独看每一步,都是普通的 optimization。GAN 的特殊之处在于:每个玩家的每一次更新,都在改变对方下一轮面对的 landscape。
这种"固定一组变量,优化另一组"的模式不是 GAN 发明的。K-means 就是经典的例子——固定 cluster assignments 更新 centroids,固定 centroids 更新 assignments。类似的还有矩阵分解里的 ALS(Alternating Least Squares),以及 EM 算法。当多组变量耦合、联合优化困难时,交替优化是一个通用的策略。
freeze parameter 和 gradient flow#
顺便补充一个工程细节,因为后面看代码时很容易卡在这里。
训练 D 时,G 的参数不需要更新。实际操作通常是对 G 的输出调用 .detach():
1fake = G(z).detach()这样 backward 时梯度不会流过 G,只更新 D。
训练 G 时,情况有点微妙。D 的参数不更新,但梯度必须流过 D。因为 G 的 loss 来自 D 的输出,链式法则是:
$$ \frac{\partial L}{\partial \theta_G} = \frac{\partial L}{\partial D} \cdot \frac{\partial D}{\partial G(z)} \cdot \frac{\partial G(z)}{\partial \theta_G} $$中间那个 \(\frac{\partial D}{\partial G(z)}\) 必须能计算——虽然 D 的参数不更新,梯度计算仍然要经过 D 的整个计算图。
freeze parameters 不等于 stop gradient through that module。这不是 GAN 的特有机制,而是 autograd 的通用行为。
突然冒出来的 D*#
继续往下看理论分析,碰到了 \(D^*(x)\) 这个概念。
D 不是训练出来的吗?怎么突然就有一个"最优判别器"的解析公式了?
理解之后才发现,\(D^*(x)\) 描述的不是实际训练中某一步的 D。它是一个理想化的极限——在当前 Generator 固定的前提下,如果 D 的模型能力无限、数据无限、优化完美收敛,那 D 最终会实现什么函数。
$$ D^*(x) = \frac{p_{\text{data}}(x)}{p_{\text{data}}(x) + p_g(x)} $$这个公式有两种理解方式。
Bayes 直觉#
假设训练时 real 和 fake 各占一半——先验概率 \(P(\text{real}) = P(\text{fake}) = 0.5\)。
看到一个样本 \(x\) 之后,用 Bayes 公式算后验:
$$ P(\text{real} \mid x) = \frac{p(x \mid \text{real}) \cdot P(\text{real})}{p(x \mid \text{real}) \cdot P(\text{real}) + p(x \mid \text{fake}) \cdot P(\text{fake})} $$其中 \(p(x \mid \text{real}) = p_{\text{data}}(x)\),\(p(x \mid \text{fake}) = p_g(x)\),先验对半。代入化简:
$$ D^*(x) = \frac{p_{\text{data}}(x)}{p_{\text{data}}(x) + p_g(x)} $$直接求导#
固定一个 \(x\),令 \(a = p_{\text{data}}(x)\),\(b = p_g(x)\)。D 在这个 \(x\) 处要最大化:
$$ f(D) = a \log D + b \log(1 - D) $$对 \(D\) 求导令其为零:
$$ f'(D) = \frac{a}{D} - \frac{b}{1 - D} = 0 \implies D^* = \frac{a}{a + b} $$和 Bayes 方式得到的结果一样。
一个离散例子#
假设世界上只有三种东西:猫、狗、鸟。真实分布和 Generator 的输出分布如下:
| \(p_{\text{data}}\) | \(p_g\) | \(D^*(x)\) | 直觉 | |
|---|---|---|---|---|
| 猫 | 0.5 | 0.1 | 0.5 / 0.6 ≈ 0.833 | 真实分布里更常见 → 更像 real |
| 狗 | 0.4 | 0.4 | 0.4 / 0.8 = 0.500 | 两边一样常见 → 无法判断 |
| 鸟 | 0.1 | 0.5 | 0.1 / 0.6 ≈ 0.167 | Generator 里更多 → 更像 fake |
猫在真实数据中出现概率远高于 Generator 输出,所以 D 倾向于判为 real。鸟的情况相反。而狗在两边同样常见,D 找不到区分依据。
但这个公式不能直接拿来算#
既然 \(D^*\) 的公式已经有了,为什么还需要用 neural network 来训练 D?
因为公式里需要 \(p_{\text{data}}(x)\) 和 \(p_g(x)\) 的值。而我们恰恰不知道这两个 density:
- \(p_{\text{data}}(x)\) 没有解析形式,只有 samples。
- \(p_g(x)\) 是隐式分布——可以通过 \(z \to G(z)\) 采样,但没办法计算任意一个 \(x\) 对应的 density 值。
所以 \(D^*\) 是一个理论分析工具,不是训练时直接计算的函数。实际训练中,我们用 real samples 配上 label 1、fake samples 配上 label 0 来训练一个 neural network D,让它去逼近这个理论最优。
从二分类到 distribution matching#
到这里,GAN 看起来只是一个特殊的二分类问题。但接下来的推导彻底改变了我对这件事的理解。
二分类器隐含了 density ratio#
从 \(D^*\) 出发,做一步简单的变形。先算 \(1 - D^*(x)\):
$$ 1 - D^*(x) = \frac{p_g(x)}{p_{\text{data}}(x) + p_g(x)} $$然后两者相除:
$$ \frac{D^*(x)}{1 - D^*(x)} = \frac{p_{\text{data}}(x)}{p_g(x)} $$一个 binary classifier,表面上只是在预测 real 或 fake,但它实际上隐含地学习了两个分布的 density ratio。
我们不需要知道 \(p_{\text{data}}(x)\) 或 \(p_g(x)\) 的解析形式。只需要能够从两个分布中采样,就可以通过训练一个 classifier 来间接学习它们之间的差异。
为什么 GAN 在做 distribution matching#
Generator 真正的目标不是"生成某一张能骗过 D 的图片",而是让 \(p_g\) 在整体上接近 \(p_{\text{data}}\)。
如果 \(p_g \neq p_{\text{data}}\),那么在某些区域,两个分布的 density 必然不同。D 可以利用这些统计差异进行分类。G 根据 D 提供的梯度调整自己的输出。然后 D 重新学习新的差异。不断循环。
训练早期,\(p_g\) 和 \(p_{\text{data}}\) 差异明显,D 能找到可区分的统计特征,并把梯度信号传给 G。随着训练推进,\(p_g\) 不断向 \(p_{\text{data}}\) 靠拢。理论上的理想终点是 \(p_g = p_{\text{data}}\)。此时:
$$ D^*(x) = \frac{p_{\text{data}}(x)}{p_{\text{data}}(x) + p_{\text{data}}(x)} = 0.5 $$为什么是 0.5#
这个 0.5 容易被误读成"D 训练失败了,什么都分不出来"。但方向反了。
D 输出 0.5 不是因为 D 太差,而是因为这个分类问题本身已经无法通过观察 \(x\) 来解决。
当 \(p_g(x) = p_{\text{data}}(x)\) 时,不管看到什么样的 \(x\),它来自 real 或 fake 的条件概率都完全相同。\(x\) 本身不包含任何关于"来源"的信息。在 prior 为 50/50 的情况下,posterior 退化为 prior:\(P(\text{real} \mid x) = 0.5\)。
需要注意,0.5 依赖于 prior 的假设。如果我们规定每个 batch 里 70% 是 real、30% 是 fake,而两个条件分布仍然完全相同,那最优输出是 0.7 而不是 0.5。标准 GAN 之所以是 0.5,只是因为通常假设 real 和 fake 的 prior 各占一半。
JS divergence 和逻辑闭环#
最后一步:把 \(D^*\) 代回 GAN 的 minimax objective。经过整理可以得到:
$$ V(D^*, G) = -\log 4 + 2 \cdot JS(p_{\text{data}} \| p_g) $$其中 \(JS\) 是 Jensen-Shannon Divergence,用来衡量两个分布之间的差异。
所以 GAN 的理论目标最终等价于:让 \(p_g\) 和 \(p_{\text{data}}\) 之间的 JS divergence 尽可能小。
到这里整条逻辑链闭合了:Binary Classification → Optimal Discriminator → Density Ratio → Distribution Difference → Generator Optimization → Distribution Matching。
GAN 表面在做 binary classification,实际是在做 distribution matching。
实际训练用的 non-saturating loss#
原始 minimax objective 对 G 来说是:
$$ \min_G \; \mathbb{E}_{z \sim p_z}[\log(1 - D(G(z)))] $$但实际训练中更常见的写法是:
$$ \min_G \; -\mathbb{E}_{z \sim p_z}[\log D(G(z))] $$这叫 non-saturating loss(非饱和损失)。两者的理想目标一致——都希望 \(D(G(z)) \to 1\)。区别是训练早期的梯度行为:当 G 还很差、\(D(G(z))\) 接近 0 时,\(\log(1 - D(G(z)))\) 的梯度很小(\(\log\) 曲线在接近 1 时趋平),而 \(-\log D(G(z))\) 在接近 0 时梯度大得多。
理论 objective 和实际训练 loss 不完全一样。看 GAN 的代码时如果发现 loss 和论文公式对不上,大概率是在用 non-saturating 版本。
为什么难训练#
GAN 的理论很漂亮,但实际训练出了名地不稳定。三个最常见的问题:
Moving objective#
训练 G 时,G 面对的 loss landscape 取决于当前的 D。但 D 下一轮又会变——因为 G 变了。反之亦然。
每个玩家面对的 objective 本身也在不断变化。和普通 optimization 中固定一个 loss function 反复迭代不同,这里的 loss function 本身每一步都在漂移。
Discriminator 太强#
如果 D 很快就能完美区分 real 和 fake,那 \(D(G(z)) \approx 0\),此时原始 loss \(\log(1 - D(G(z)))\) 的梯度接近于零。G 几乎收不到有用的梯度信号。这也是 non-saturating loss 被提出的背景之一。
Mode collapse#
GAN 训练中最典型的失败模式。Generator 可能只学会生成一小部分非常成功的样本模式,而完全忽略其他模式。
比如真实数据包含猫、狗、鸟、汽车,但 Generator 只学会生成猫——而且猫生成得非常逼真。
这意味着单个样本的质量可能很高,但分布覆盖度很差——\(p_g\) 的 support 远小于 \(p_{\text{data}}\) 的 support。
和 VAE 的区别#
回到 VAE 和 GAN 的对比。两者都是生成模型,但走了非常不同的路。
VAE 是显式概率建模的路线。它引入 latent variable \(z\),显式定义 prior \(p(z)\),通过 ELBO 训练。整个过程需要计算 KL divergence 和 reconstruction likelihood,和 density 打交道。
GAN 走的是隐式生成建模(implicit generative modeling)的路线。Generator 只需要能采样——给一个 \(z\),输出一个 \(G(z)\)——不需要计算 \(p_g(x)\) 的 density。分布之间的比较不靠 likelihood,而靠一个 classifier。
两者各有各的问题。VAE 的 ELBO 是 log-likelihood 的下界,优化目标和"生成质量"之间存在 gap。GAN 没有 ELBO 的约束,但训练不稳定、容易 mode collapse、也缺少像 ELBO 这样直接可用的 likelihood 度量。
2026 年的生成模型#
今天的生成模型领域早已不是"VAE 还是 GAN"的二选一。
当前图像和视频生成的主流范式是 Diffusion Models 和 Flow Matching。FLUX、Stable Diffusion 3、VEO-3 等大规模生成系统的核心都是 flow matching 或 diffusion 框架。MIT 2026 年的课程 An Introduction to Flow Matching and Diffusion Models 直接把 flow matching 定位为当前最先进的生成建模方法。CVPR 2026 上的 FreqFlow 在 ImageNet-256 上达到 FID 1.38,是目前 flow matching 方向的最好成绩之一。
但 GAN 所代表的 adversarial objective 并没有消失。在 diffusion model 的加速蒸馏(distillation)领域,adversarial loss 被广泛用作辅助训练目标。Adversarial Diffusion Distillation(ADD,ECCV 2024)把 adversarial loss 和 score distillation 结合,把多步 diffusion model 压缩到 1-4 步。DMD2 使用 GAN-based regularizer 来对抗 mode collapse。ICCV 2025 的 Adversarial Distribution Matching(ADM)更是直接把 GAN 训练机制嵌入 score distillation 框架来做 distribution matching。
VAE 和 Autoencoder 也没有离场。Latent Diffusion 系统中的 VAE encoder/decoder 仍然是核心组件——负责把高分辨率图像压缩到 latent space,让 diffusion 或 flow matching 在更低维的空间中工作。
现代生成系统通常是多种思想和组件的组合。GAN 作为 standalone 的通用生成范式已经让位,但 adversarial objective 作为一种训练工具,在特定场景中仍然发挥作用。
写在最后#
GAN 最打动我的地方,不是它生成的图片有多像真的,而是它回答了一个看起来无解的问题:两个分布都不知道 density,怎么比较它们?
答案是不比较。训练一个 classifier。classifier 在区分两个分布的 samples 时,隐式地学习了它们的 density ratio。Generator 根据 classifier 的梯度不断调整自己,直到 classifier 再也找不到可区分的统计特征——此时两个分布一致。
这个思路把一个 intractable 的 density estimation 问题,转化成了一个我们非常熟悉的 supervised learning 问题。
参考资料#
- MIT 6.S191: Introduction to Deep Learning — Lecture 4: Generative Modeling
- Goodfellow et al., Generative Adversarial Nets, NeurIPS 2014
- An Introduction to Flow Matching and Diffusion Models — MIT CSAIL 2026
- Ren et al., Frequency-Aware Flow Matching for High-Quality Image Generation, CVPR 2026
- Sauer et al., Adversarial Diffusion Distillation, ECCV 2024
- Lu et al., Adversarial Distribution Matching for Diffusion Distillation, ICCV 2025
- VAE 为什么要让 Latent Variable 变成一个概率分布