DDIM 深度剖析:从随机马尔可夫链到确定性隐式模型
1. DDPM 的致命弱点:为什么需要 DDIM?
1.1 从 DDPM 到 DDIM 的动机
回顾 DDPM 文章:DDPM 用一个 步的马尔可夫链逆向去噪,每一步都加随机噪声。生成一张 512×512 图像需要:
DDPM 生成时间 ≈ 1000 步 × 每步 ~100ms ≈ 100 秒 (GPU)这对实际应用来说是不可接受的。核心矛盾:
| 问题 | DDPM 的选择 | 后果 |
|---|---|---|
| 逆向过程是随机的 | 每步独立随机噪声,无法利用前面的信息 | |
| 马尔可夫假设 | 只依赖 | 无法”跳跃”——必须一步步走 |
| 生成轨迹 | 高度发散(随机游走) | 步数少时质量急剧下降 |
1.2 DDIM 的核心洞察
放弃马尔可夫假设,换取确定性和速度。
Song et al. 2021 提出的 DDIM(Denoising Diffusion Implicit Models)发现:
DDPM 的核心假设"逆向过程必须是马尔可夫的"是人为加的。如果只要求: 1. 逆向过程是"隐式概率模型"(Implicit Probabilistic Model) 2. 边际分布 q(x_t) 不变(训练数据分布不变)那么逆向过程可以完全自由设计——包括非马尔可夫的确定性过程!这就是”Implicit Models”(隐式模型)名称的由来:不再显式定义 的概率密度,而是定义一个确定性映射 ,通过 ODE 积分来生成样本。
1.3 一句话概括 DDIM
DDIM 通过放弃”逆向过程必须是马尔可夫链”的约束,把 DDPM 的随机走路径变成确定性的直线路径——从而用 10-50 步生成与 1000 步 DDPM 相当甚至更好的图像质量。
1.4 论文信息
论文: "Denoising Diffusion Implicit Models" (DDIM)作者: Jiaming Song, Chenlin Meng, Stefano Ermon单位: Stanford University发表于: ICLR 2021引用: > 5,000 次 (截至 2024)开源: https://github.com/ermongroup/ddim2. 数学框架:非马尔可夫逆向过程
2.1 隐式概率模型的定义
DDPM 定义了一个生成过程(马尔可夫链):
其中 是神经网络近似的逆向分布。
DDIM 则定义了一个更一般的生成过程,称为非马尔可夫链:
注意: 依赖 (不只是 )——这打破了马尔可夫假设。
关键约束:边际分布 必须保持不变(即与前向过程定义的分布一致),否则训练目标会失效。
2.2 边际分布约束
设 是前向过程定义的联合分布。DDIM 要求生成模型的边际分布 与 匹配:
这是一致性约束:不管用马尔可夫还是非马尔可夫方式生成,边际分布必须一致。
从 的马尔可夫链结构出发,可以推导出 的解析形式(贝叶斯定理):
其中均值和方差与 DDPM 中的逆向条件分布完全相同(来自 DDPM 文章的推导)。
2.3 DDIM 逆向过程的定义
设 是自由参数(DDPM 中固定为 )。DDIM 定义逆向过程为:
其中:
- 是神经网络预测的噪声(与 DDPM 相同)
- 是可选的随机噪声
- 当 时,过程完全确定性——这就是 DDIM 的核心
2.4 三种特殊情形
| 情形 | 取值 | 过程类型 | 采样步数影响 |
|---|---|---|---|
| DDPM(完全随机) | 随机马尔可夫 | 必须多步,质量急剧下降 | |
| DDIM(完全确定) | 确定性非马尔可夫 | 步数减少时质量下降最慢 | |
| 插值(部分随机) | 随机非马尔可夫 | 介于两者之间 |
def ddim_reverse_step(xt, eps_theta, t, t_prev, sigma_t): """ DDIM 单步逆向过程。
参数: xt: 当前位置 x_t eps_theta: 神经网络预测的噪声 t: 当前时间步 (整数) t_prev: 上一个时间步 (整数) sigma_t: 随机性参数 [0, 1] """ # 从 xt 估计 x0 alpha_bar_t = alphas_cumprod[t] sqrt_ab = torch.sqrt(alpha_bar_t) sqrt_1m = torch.sqrt(1 - alpha_bar_t) x0_pred = (xt - sqrt_1m * eps_theta) / sqrt_ab
# 计算 x_{t-1} alpha_bar_prev = alphas_cumprod[t_prev] sqrt_ab_prev = torch.sqrt(alpha_bar_prev) sqrt_1m_prev = torch.sqrt(1 - alpha_bar_prev)
# 确定性方向(始终存在) pred_eps = eps_theta x_prev_deterministic = sqrt_ab_prev * x0_pred + sqrt_1m_prev * pred_eps
# 随机性方向(sigma_t > 0 时加入) if sigma_t > 0: noise = torch.randn_like(xt) x_prev = x_prev_deterministic + sigma_t * noise else: x_prev = x_prev_deterministic
return x_prev3. 轨迹视图:从 SDE 到 ODE
3.1 把 DDPM 看作 SDE
连续时间下,DDPM 的前向过程是一个随机微分方程(SDE):
其中 是维纳过程(Wiener process),引入随机性。
DDPM 的逆向过程(在连续时间下)对应 SDE 的反向:
3.2 把 DDIM 看作 ODE
当 时,随机项消失,DDIM 变成常微分方程(ODE):
ODE 的好处:
SDE (DDPM): 随机轨迹,每步独立,无法加速 ↓ODE (DDIM): 确定性轨迹,可以用 ODE 求解器加速 - 自适应步长 - 高阶积分(Heun, RK45) - 逆向轨迹固定,步数减少时误差可预测3.3 ODE 求解器与采样
@torch.no_grad()def ddim_ode_sampler(model, num_steps=50, eta=0.0): """ DDIM ODE 采样器(确定性)。 eta = 0 → 完全确定性 DDIM eta = 1 → 等效 DDPM(随机) """ T = len(alphas_cumprod) - 1 shape = (batch_size, channels, height, width)
# 从纯噪声开始 x = torch.randn(*shape, device=device)
# 生成时间步序列(均匀或非线性) # 非线性调度: t 越接近 0,变化越慢 ts = torch.linspace(1.0, 0.0, num_steps + 1)
for i in range(num_steps): t = int(ts[i] * T) # 当前时间步 t_prev = int(ts[i + 1] * T) # 上一个时间步
eps_theta = model(x, t)
# sigma_t: 由 eta 控制 # eta = 0 → 完全确定 # eta = 1 → 随机性等于 DDPM sigma_t = eta * ((1 - alphas_cumprod[t_prev] / alphas_cumprod[t]) ** 0.5) \ * ((1 - alphas_cumprod[t] / alphas_cumprod[t_prev]) ** 0.5)
alpha_bar_t = alphas_cumprod[t] alpha_bar_prev = alphas_cumprod[t_prev]
sqrt_ab = alpha_bar_t ** 0.5 sqrt_1m = (1 - alpha_bar_t) ** 0.5 sqrt_ab_prev = alpha_bar_prev ** 0.5 sqrt_1m_prev = (1 - alpha_bar_prev) ** 0.5
# 估计 x_0 x0_pred = (x - sqrt_1m * eps_theta) / sqrt_ab
# 预测 x_{t-1} x_pred = sqrt_ab_prev * x0_pred + sqrt_1m_prev * eps_theta
# 加入随机性(仅当 eta > 0) if sigma_t > 0: std = sigma_t * ((1 - alpha_bar_prev) ** 0.5) x_pred = x_pred + std * torch.randn_like(x)
x = x_pred
return x3.4 自适应步长求解器
from scipy.integrate import solve_ivp
def ddim_neural_ode_sampler(model, rtol=1e-5, atol=1e-6): """ 用 scipy 的自适应 ODE 求解器(精度驱动的采样)。
与固定步数相比: - 在低噪声区域(t→0)自动用更小步长 - 在高噪声区域(t→T)自动用更大步长 - 总步数可能更少,精度更高 """ dim = channels * height * width
def ode_function(t_float, x_flat): """ t_float ∈ [0, 1]: 连续时间(0=数据,1=噪声) 这里用反向时间,t=0 是噪声,t=1 是数据 """ t_int = int((1.0 - t_float) * (T - 1)) t_int = max(0, min(T - 1, t_int))
x = torch.tensor(x_flat.reshape(1, channels, height, width), device=device, dtype=torch.float32) eps = model(x, t_int)
alpha_bar = alphas_cumprod[t_int] sqrt_ab = alpha_bar ** 0.5 sqrt_1m = (1 - alpha_bar) ** 0.5 x0_pred = (x - sqrt_1m * eps) / sqrt_ab
# dx/dt = -(预测方向) / T # 近似: 速度场方向 dx_dt = -(eps - x0_pred).cpu().numpy().flatten() / T return dx_dt
x0 = torch.randn(1, channels, height, width).cpu().numpy().flatten() sol = solve_ivp( ode_function, t_span=(0.0, 1.0), y0=x0, method='RK45', rtol=rtol, atol=atol, dense_output=True, ) final = sol.y[:, -1].reshape(channels, height, width) return torch.from_numpy(final).to(device).unsqueeze(0)4. 与 DDPM 的关系:严格的数学联系
4.1 训练目标完全相同
最重要的事实:DDIM 的训练目标与 DDPM 完全相同!
这意味着:
- 不需要重新训练 DDPM 模型——已有的 DDPM checkpoint 可以直接用于 DDIM
- DDIM 只是不同的采样策略,不是新的训练方法
4.2 采样分布的数学联系
设 是 DDIM 定义的逆向分布, 是 DDPM 的真实逆向分布。
定理:对任意 ,DDIM 的边际分布与 DDPM 的边际分布相同:
这就是 DDIM 的”隐式”特性——不显式定义概率密度函数,但边际分布自动保持一致。
4.3 采样轨迹的几何对比
采样轨迹对比 (x_0 → x_T 方向为正向)
DDPM (随机马尔可夫): x_0 ──→ x_1 ──→ x_2 ──→ ... ──→ x_T ↑ ↑ ↑ 随机 随机 随机 发散 发散 发散 → 每步独立随机偏移 → 步数少时轨迹高度发散
DDIM (确定性非马尔可夫): x_0 ────────→ x_{S_1} ↑ ↑ 跳步 x_{S_2} ←─────────────── ↑ 跳步 x_{S_3} ←─────────────── ... x_T = x_{S_k}
→ 确定性轨迹,每步连续 → 跳步后仍沿同一条光滑曲线 → 步数减少时轨迹仍光滑4.4 为什么确定性更好?
直觉解释:
DDPM 每步: x_{t-1} = μ + 随机噪声 ↑ 每个时间步的随机偏移是独立的 → 走 N 步后,总偏移 ~ √N × 单步偏移(随机游走) → 步数减半,偏移翻倍,误差爆炸
DDIM 每步: x_{t-1} = F(x_t) (确定性函数) ↑ 跳步仍沿同一光滑 ODE 曲线 → 走 N 步 = 直接求 ODE 的 N 个点 → 步数减半,只是不采样中间点,不影响精度 → 误差可预测(由 ODE 求解器控制)5. 采样调度策略
5.1 均匀时间步调度
最简单的策略:将 均匀分割:
def uniform_timestep_schedule(num_steps, T=1000): """均匀调度。""" return torch.linspace(T - 1, 0, num_steps).long().tolist()5.2 DDIM 论文推荐的调度
论文发现,噪声强度越大( 越接近 ),ODE 变化越剧烈。因此建议用非线性调度,在高噪声区域用更多步:
def ddim_timestep_schedule(num_steps, T=1000, eta=0.0): """ DDIM 论文推荐的时间步调度。
核心思想: - 高噪声区域 (t > 100): 变化剧烈,多放步 - 低噪声区域 (t < 100): 变化平缓,少放步 """ # 从 [1, T] 均匀选 num_steps 个 steps = torch.arange(0, T, T // num_steps).flip(0)
# 如果步数不够 T,调整最后一步 if len(steps) < num_steps: steps = torch.cat([steps, torch.tensor([0])])
return steps[:num_steps].long().tolist()5.3 重要性采样:跳过 vs 插值
DDIM 支持两种子序列策略:
| 策略 | 方法 | 效果 |
|---|---|---|
| 跳步 (skip) | 跳过中间时间步,只采样子序列 | 更直接,减少步数 |
| 插值 (interpolate) | 在相邻时间步之间插值 | 平滑过渡,更稳定 |
def get_ddim_schedule(num_steps, T=1000, method="skip"): """ 生成 DDIM 子序列。
skip: [999, 949, 899, ..., 49, 0] interpolate: [999, 997, 995, ..., 5, 3, 1] """ if method == "skip": # 每 T/num_steps 步跳一次 step_size = T // num_steps schedule = list(range(T - 1, -1, -step_size)) elif method == "interpolate": # 均匀分布 + 线性插值 uniform = torch.linspace(T - 1, 0, num_steps) schedule = uniform.round().long().tolist()
return schedule5.4 噪声调度的敏感性
def sensitivity_analysis(): """ 不同 eta 和 num_steps 的 FID 表现(经验值)。 来自 DDIM 论文实验。 """ # num_steps=100 时 configs = [ (100, 0.0, "DDIM (完全确定)"), # FID ~5.8 (100, 0.5, "DDIM (部分随机)"), # FID ~6.2 (100, 1.0, "DDPM (完全随机)"), # FID ~20.0+ ]
# num_steps=20 时 configs_20 = [ (20, 0.0, "DDIM (完全确定)"), # FID ~7.5 (20, 0.5, "DDIM (部分随机)"), # FID ~12.0 (20, 1.0, "DDPM (完全随机)"), # FID ~100+ (几乎无法用) ]
return configs, configs_20关键发现:(完全确定)在所有步数下都优于 (完全随机)。这是 DDIM 最重要的实践结论。
6. 轨迹坍缩与多样性
6.1 轨迹坍缩现象
DDIM 的 (完全确定性)有一个副作用:多样性降低。
多样性 vs 确定性 trade-off:
高多样性 (η=1, DDPM): 提示: "a cat on a sofa" 生成: [猫1], [猫2], [猫3], ... [猫N] 每张猫都不同(颜色、姿势、背景)
低多样性 (η=0, DDIM): 提示: "a cat on a sofa" 生成: [猫A], [猫A], [猫A], ... [猫A] 几乎完全相同(只有微小随机性来自初始噪声)
原因: 确定性映射 f_θ: x_t → x_{t-1} 是固定的 相同的初始噪声 x_T → 相同的生成结果 初始噪声的多样性 = 生成的多样性6.2 数学解释
随机 DDPM 的多样性来源:
每一步逆向过程都加随机噪声:
这意味着 的分布是”展宽”的(convolution),引入额外随机性。
确定性 DDIM 的多样性来源:
无随机噪声:
只有初始噪声 引入多样性。
6.3 解决方案:调整
def trade_off_eta(): """ eta 对多样性-质量 trade-off 的影响。
η = 0.0: 质量最高,多样性最低(轨迹坍缩) η = 0.3: 质量高,多样性适中(推荐默认值) η = 0.5: 质量中等,多样性中等 η = 1.0: 质量低(步数少时),多样性最高 """ pass6.4 不同任务的最佳
| 任务 | 推荐 | 理由 |
|---|---|---|
| 高保真生成 | 质量优先,不在乎多样性 | |
| 多样化生成 | 平衡质量和多样性 | |
| 图像编辑 | 确定性保证编辑一致性 | |
| Inpainting | 需要精确控制 | |
| 视频生成 | 时间一致性优先 |
7. 图像生成实验结果
7.1 步数 vs 质量
def cifar10_results(): """ CIFAR-10 32x32 上的 FID vs 采样步数。 """ results = { # (num_steps, eta): FID (1000, 1.0): 3.85, # DDPM baseline (100, 0.0): 4.20, # DDIM 100步确定 (50, 0.0): 4.60, # DDIM 50步确定 (20, 0.0): 5.90, # DDIM 20步确定 (10, 0.0): 8.10, # DDIM 10步确定 (5, 0.0): 15.20, # DDIM 5步确定 (100, 1.0): 25.50, # DDPM 100步随机(很差!) (50, 1.0): 55.00, # DDPM 50步随机(几乎失败) } return results
def imagenet_results(): """ ImageNet 256x256 上的 FID vs 采样步数。 """ results = { (1000, 1.0, "ADM-Improved"): 10.4, (100, 0.0, "DDIM"): 11.3, (50, 0.0, "DDIM"): 12.8, (20, 0.0, "DDIM"): 17.2, } return results核心数据:DDIM 50 步()的 FID 与 DDPM 1000 步相当,而速度快 20 倍。
7.2 感知质量分析
def perceptual_quality(): """ DDIM 的感知质量特点。 """ observations = { "优点": [ "细节更锐利(确定性路径避免随机模糊)", "颜色更一致(无每步随机偏移累积)", "构图更稳定(适合编辑/控制任务)", ], "缺点": [ "多样性降低(相同初始噪声产生相同结果)", "部分图像出现"超锐化"伪影(尤其 10 步以内)", "某些类别容易陷入局部最优", ] } return observations8. 加速技术的演进
8.1 DDIM 的后续加速方法
DDIM (2021): 非马尔可夫, 20-50步, 确定性
├── LDM (2022): Latent Diffusion → 压缩到隐空间,速度再次提升 │ ├── Consistency Models (2023): Song et al. │ 一致性蒸馏 → 1-4 步 │ ├── LCM (Latent Consistency Models) (2023): Luo et al. │ 蒸馏 + 隐空间 → 2-4 步 ★ (SD + LCM) │ ├── SDXL-Turbo / SDXL-Lightning (2024) │ 步蒸馏 → 1-2 步 │ └── Rectified Flow (2023): Liu et al. 最优传输 → 4-10 步 (见 [Flow Matching 文章](/posts/flow-matching/))8.2 为什么 DDIM 之后还需要新方法?
| 维度 | DDIM | 新方法(LCM/RF) |
|---|---|---|
| 采样步数 | 10-50 步 | 1-4 步 |
| 训练方式 | 同一训练目标 | 需要额外蒸馏 |
| 模型兼容性 | 复用 DDPM 模型 | 需要重新训练 |
| 生成质量 | 10步 FID ~8 | 4步 FID ~6 |
8.3 DDIM 的持续重要性
尽管有更快的方法,DDIM 仍被广泛使用:
# Stable Diffusion 推理管线中的 DDIMfrom diffusers import DDIMScheduler, StableDiffusionPipeline
pipeline = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")pipeline.scheduler = DDIMScheduler.from_config(pipeline.scheduler.config)
# 使用 DDIM 调度器image = pipeline( prompt="a cat on a sofa", num_inference_steps=20, # DDIM: 20步即可 eta=0.0, # 完全确定性).images[0]9. 图像编辑与 DDIM
9.1 DDIM 的编辑优势
确定性是编辑任务的关键:
编辑任务: 把 [原图] 中的 [对象] 替换为 [新对象]
DDPM 方法: 原图 → 加噪到某步 → 编辑条件 → 去噪 问题: 加噪和去噪都是随机的 同一张图多次处理会得到不同结果
DDIM 方法: 原图 → 加噪到某步(确定性反向 ODE)→ 编辑条件 → 去噪 优点: 加噪路径是确定性的 同一张图→同一条轨迹→可逆 编辑结果可复现9.2 DDIM Inpainting
def ddim_inpainting(): """ DDIM Inpainting 流程。
1. 原图 x_0 → 加噪到 t=T-edit(如 T=500) (确定性反向 ODE, 可以精确恢复) 2. 在隐空间中修改对应区域(inpaint mask) 3. 从 x_t=500 用 DDIM 去噪到 x_0 4. 合并编辑区域和原始区域 """ pass9.3 引导编辑
DDIM 与 CFG(无分类器引导)完美结合:
CFG 的引导强度 与 DDIM 的 可以独立调节:
| 效果 | 典型值 | |
|---|---|---|
| 无引导 | 默认 | |
| 中度引导 | 文本对齐好 | |
| 强度引导 | 高保真 |
10. 完整实现
import torchimport torch.nn.functional as F
class DDIMScheduler: """ DDIM 调度器实现。 完全兼容 Diffusers 库的接口。 """
def __init__(self, num_train_timesteps=1000, beta_start=1e-4, beta_end=0.02, beta_schedule="linear", clip_sample=False, set_alpha_to_one=False): self.num_train_timesteps = num_train_timesteps self.clip_sample = clip_sample self.final_alpha_cumprod = 1.0 if set_alpha_to_one else 0.0
# 噪声调度 if beta_schedule == "linear": betas = torch.linspace(beta_start, beta_end, num_train_timesteps) elif beta_schedule == "cosine": betas = self._cosine_beta_schedule(num_train_timesteps) else: raise ValueError(f"Unknown beta_schedule: {beta_schedule}")
alphas = 1.0 - betas alphas_cumprod = torch.cumprod(alphas, dim=0) self.alphas_cumprod = alphas_cumprod
def _cosine_beta_schedule(self, timesteps, s=0.008): """余弦噪声调度(更平滑)。""" steps = timesteps + 1 x = torch.linspace(0, timesteps, steps) alphas_cumprod = torch.cos((x / timesteps + s) / (1 + s) * torch.pi * 0.5) ** 2 alphas_cumprod = alphas_cumprod / alphas_cumprod[0] betas = 1 - alphas_cumprod[1:] / alphas_cumprod[:-1] return torch.clamp(betas, 0.0001, 0.9999)
def set_timesteps(self, num_inference_steps, offset=0): """ 设置推理时间步。
参数: num_inference_steps: DDIM 采样步数(如 50) offset: 偏移量 """ self.num_inference_steps = num_inference_steps step_ratio = self.num_train_timesteps // num_inference_steps # 生成从 T-1 到 0 的时间步序列 timesteps = (torch.arange(0, num_inference_steps) * step_ratio + step_ratio // 2).flip(0) self.timesteps = timesteps.long()
@torch.no_grad() def step(self, model_output, timestep, sample, eta=0.0): """ DDIM 单步采样。
参数: model_output: 模型预测的噪声 ε_θ(x_t, t) timestep: 当前时间步 t sample: 当前状态 x_t eta: 随机性参数 (0=确定, 1=随机) 返回: prev_sample: 下一状态 x_{t-1} """ t = timestep prev_t = timestep - self.num_train_timesteps // self.num_inference_steps
# 当前和上一步的 alpha_cumprod alpha_prod_t = self.alphas_cumprod[t] alpha_prod_t_prev = self.alphas_cumprod[prev_t] if prev_t >= 0 else self.final_alpha_cumprod
# 预测 x_0 pred_original_sample = (sample - (1 - alpha_prod_t).sqrt() * model_output) \ / alpha_prod_t.sqrt() if self.clip_sample: pred_original_sample = torch.clamp(pred_original_sample, -1, 1)
# 计算方差 # DDIM 方差 (公式来自论文) var = (1 - alpha_prod_t_prev) / (1 - alpha_prod_t) * (1 - alpha_prod_t / alpha_prod_t_prev) std = (var ** 0.5) * eta
# 预测 x_{t-1} 的方向 pred_sample_direction = (1 - alpha_prod_t_prev - std ** 2).sqrt() * model_output
# 确定性部分 prev_sample = alpha_prod_t_prev.sqrt() * pred_original_sample + pred_sample_direction
# 随机噪声(仅当 eta > 0) if eta > 0: noise = torch.randn_like(sample) variance_noise = std * noise prev_sample = prev_sample + variance_noise
return prev_sample
def add_noise(self, original_samples, timesteps, noise=None): """前向加噪(用于重建目标)。""" if noise is None: noise = torch.randn_like(original_samples)
sqrt_alpha_prod = self.alphas_cumprod[timesteps] ** 0.5 sqrt_one_minus_alpha = (1 - self.alphas_cumprod[timesteps]) ** 0.5
noisy_samples = sqrt_alpha_prod.view(-1, 1, 1, 1) * original_samples \ + sqrt_one_minus_alpha.view(-1, 1, 1, 1) * noise return noisy_samples11. 与 Flow Matching 的理论联系
11.1 DDIM 的 ODE 就是 Flow Matching
回想 Flow Matching 文章的核心:
Flow Matching 把从噪声到数据的路径建模为 ODE ,训练目标是 MSE(预测速度, 真实速度)。
DDIM 的 情形正是 Flow Matching 的一个特例:
DDIM (η=0) 的 ODE:
x_{t-1} = √ᾱ_{t-1} · x̂_0 + √(1-ᾱ_{t-1}) · ε_θ(x_t, t)
将 t-1 写成 dt,并整理成 dx/dt 的形式:
dx/dt = (ᾱ_{t-1} - ᾱ_t) / dt · x̂_0 + ... = v_θ(x_t, t)
其中 v_θ(x_t, t) = ε_θ(x_t, t) - x̂_0
而 x̂_0 = (x_t - √(1-ᾱ_t) · ε_θ) / √ᾱ_t
→ v_θ(x_t, t) = ε_θ - (x_t - √(1-ᾱ_t) · ε_θ) / √ᾱ_t = (1 - 1/√ᾱ_t) · ε_θ - x_t/√ᾱ_t
这恰好是 RF 直线路径的向量场!11.2 三种路径的理论统一
所有扩散类生成模型 = Flow Matching 的特例
路径设计空间: ├── Rectified Flow: 直线 x_t = (1-t)x_0 + tε → v = ε - x_0 ├── DDPM (VP-SDE): 弧线 x_t = √ᾱ_t x_0 + √(1-ᾱ_t)ε └── DDIM (η=0): 与 DDPM 相同的路径,但 ODE 求解
采样策略: ├── DDPM: SDE → 1000步随机马尔可夫 ├── DDIM: ODE → 10-50步确定性非马尔可夫 └── RF: ODE → 10-50步确定性直线12. 总结
12.1 核心要点
| 维度 | 关键要点 |
|---|---|
| 核心洞察 | 逆向过程不需要是马尔可夫的,边际分布不变即可 |
| 数学框架 | 非马尔可夫链 + 边际分布约束 |
| 训练目标 | 与 DDPM 完全相同(不需要重新训练) |
| 采样 | 时为确定性 ODE 采样 |
| 质量 | 50 步 DDIM ≈ 1000 步 DDPM(FID 相当) |
| 速度 | 20 倍加速(1000 步 → 50 步) |
| 权衡 | 质量最高但多样性最低 |
| 编辑优势 | 确定性使加噪/去噪可逆,完美支持图像编辑 |
| 与 FM | DDIM 的 ODE 路径是 Flow Matching 的特例 |
12.2 一句话总结
DDIM 通过放弃”逆向必须是马尔可夫链”的人为约束,把 DDPM 的随机走路径变成确定性的 ODE 轨迹——不改变任何训练目标,只改变采样方式,就实现了 20 倍加速,同时保持了生成质量。这是非马尔可夫隐式概率模型在生成建模中的首次成功应用,也是 Rectified Flow 和一致性模型的理论先驱。
12.3 推荐资源
论文: - DDIM (Song et al., 2021): "Denoising Diffusion Implicit Models" - Consistency Models (Song et al., 2023): "Consistency Models" - Flow Matching (Lipman et al., 2022): "Flow Matching for Causal Inference"
代码: - ermongroup/ddim (官方实现) - huggingface/diffusers (DDIMScheduler) - CompVis/stable-diffusion (集成 DDIM)
教程: - Lilian Weng 博客: "Diffusion Models as a Kind of ODE" - Hugging Face 博客: "Speed up inference with DDIM"文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!

