直观感受一下 DDPM 和 DDIM 的区别:
准备好了吗?我们开始!
第一步:前置小知识(重参数化技巧)
在扩散模型中,我们最常用到一个技巧:如果你有一个符合正态分布的变量 X∼N(μ,σ2)(均值为 μ,方差为 σ2),我们可以把它拆成:
X=μ+σ⋅ϵ这里的 ϵ 是一个标准正态分布的纯噪声 ϵ∼N(0,1)。
直白点说: 任意状态 = 确定的基础值 + (随机噪声 × 噪声强度)。记住这个公式,它是贯穿整个推导的灵魂。
第二步:DDPM 的基础设定(从头到尾加噪)
在原来的 DDPM(去噪扩散概率模型)中,我们有一个清晰的正向加噪过程。
假设我们有一张清晰的图像(或者机器人的一个完美动作),叫做 x0。我们在它上面不断加噪声,加到第 t 步时,它变成了 xt。
DDPM 证明了一个极其重要的结论:我们不需要一步步加噪声,我们可以直接从 x0 一步跳到 xt。
公式是这样的:
xt=αˉtx0+1−αˉtϵ
- x0: 初始干净数据。
- xt: 第 t 步的含噪数据。
- αˉt: 一个介于 0 到 1 之间的系数。你可以把它理解为**“信号保留率”**。随着步数 t 变大,αˉt 会越来越小(趋近于 0)。
- 1−αˉt: “噪声强度”。
- ϵ: 标准正态分布的纯噪声。
总结一句话: 第 t 步的数据 xt,就是**“衰减后的干净数据”加上“逐渐增强的噪声”**。
第三步:逆向思考 —— 如何从 xt 猜出 x0?
现在,我们进入大模型真正工作的阶段:反向去噪。
大模型(比如一个 U-Net 神经网络)在推理时,看到的是一团带有噪声的 xt。它的任务是:预测出这团数据里包含的噪声 ϵ 是什么。
假设我们训练好了一个神仙大模型,记作 ϵθ(xt,t)。它可以精准地猜出当前 xt 里面的噪声。
既然噪声被猜出来了,我们是不是可以利用第二步的公式,反推(猜测)出干净的 x0?
我们将第二步的公式 xt=αˉtx0+1−αˉtϵ 移项变形,求 x0:
预测的 x0=αˉtxt−1−αˉt⋅ϵθ(xt,t)(这一步只是简单的初中代数移项哦!)
这就是大模型在任意第 t 步时,脑海中“想象”出的最终清晰结果。
第四步:DDIM 的核心魔法 —— 重新拼装 xt−1
在传统的 DDPM 中,必须依赖马尔可夫链一步一步倒退(xt→xt−1→xt−2)。
DDIM 的天才之处在于:它打破了必须一步一步退的规则。 它提出,只要我保证最后生成的边缘分布一样,中间怎么走随便我!于是 DDIM 强行构造了一个生成 xt−1 的新公式。
DDIM 认为,第 t−1 步的数据 xt−1,可以由三部分拼装而成:
xt−1=部分1+部分2+部分3让我们把这三部分详细写出来(不要怕长,我们拆开看):
xt−1=部分1:指向预测的 x0αˉt−1⋅(αˉtxt−1−αˉt⋅ϵθ(xt,t))+部分2:指向 xt 的方向1−αˉt−1−σt2⋅ϵθ(xt,t)+部分3:随机噪声σt⋅ϵt我们来逐一翻译这三部分:
- 部分1(指向 x0): 你看括号里的那一坨,是不是就是我们在第三步预测的 x0?前面乘上 αˉt−1,意思是我们要保留多少 x0 的信号。
- 部分2(指向 xt 的方向): 为了平滑过渡,我们还需要加一点点我们刚预测出的噪声 ϵθ(xt,t) 回去。系数 1−αˉt−1−σt2 是为了保证总的方差对齐。
- 部分3(随机噪声): σt 是我们自己可以控制的方差参数,ϵt 是新的随机噪声。
第五步:见证奇迹的时刻 —— 为什么能加速?
上面的公式就是泛化的扩散模型采样公式。接下来就是 DDIM 发挥威力的地方了:
操作 1:让 σt=0(消除随机性)
DDIM 的论文作者指出,如果我们直接把随机性砍掉,也就是让方差参数 σt=0。
此时,公式中的部分3直接消失!
xt−1=αˉt−1⋅(预测的 x0)+1−αˉt−1⋅ϵθ(xt,t)这意味着什么?意味着从 xt 到 xt−1 的过程变成了**完全确定(Deterministic)**的!只要你的输入噪声固定,无论生成多少次,结果都一模一样。这对具身智能机器人的稳定性至关重要!
操作 2:跳步(Accelerated Sampling)
仔细看最后这个化简后的公式,你会发现:计算 xt−1 的时候,我们只用到了 xt、大模型的预测 ϵθ、以及 αˉt−1。
这里的 t−1 只是一个符号,它不需要真的是上一个整数!
也就是说,我们可以把时间步设定为一个子序列,比如从 t=1000 直接跳到 t=900,把 900 作为公式里的 “t−1” 代入计算。
这就实现了巨大的跳跃,原来需要迭代 1000 次,现在我们每 50 步跳一次,只需 20 次就能生成最终结果!这就是 DDIM 加速的根本原理。
总结归纳
- 我们通过大模型预测出当前的噪声 ϵθ。
- 我们用这个噪声反推出干净的数据 x0。
- DDIM 构造了一个新公式,用预测的 x0 和预测的噪声按特定比例组合,直接算出一个确定性的前置状态。
- 因为公式不再依赖马尔可夫链的严密连贯性,我们可以大步幅地“跳着算”,实现几倍甚至几十倍的加速。
第一重解密:如何证明可以直接从 x0 跳到 xt?
要想证明这个公式,我们需要先准备一个非常基础的统计学**“外挂定理”**(正态分布的可加性):
定理: 如果你有两个相互独立的正态分布变量,分别带有方差 A 和方差 B。把它们加在一起,新的变量依然是正态分布,且方差相加,等于 A+B。
在扩散模型中,我们定义单步的加噪过程是这样的(每次只加一点点噪声):
x1=α1x0+1−α1ϵ0x2=α2x1+1−α2ϵ1这里的 ϵ0,ϵ1 都是标准正态分布的纯噪声(均值为0,方差为1)。系数 α 也就是我们说的“信号保留率”。
现在,我们要挑战把 x2 直接用 x0 表示出来:
把 x1 的公式,直接代入到 x2 的公式里去:
x2=α2(α1x0+1−α1ϵ0)+1−α2ϵ1我们把括号拆开:
x2=α1α2x0+这里是两坨噪声相加α2(1−α1)ϵ0+1−α2ϵ1见证奇迹的时刻到了!我们用上面提到的“外挂定理”来合并这两坨噪声:
第一坨噪声的方差是:α2(1−α1)=α2−α1α2
第二坨噪声的方差是:1−α2
根据定理,两个噪声相加,方差相加:
(α2−α1α2)+(1−α2)=1−α1α2也就是说,这两坨噪声合并后,变成了一个全新的、方差为 1−α1α2 的标准噪声(我们叫它 ϵˉ):
x2=α1α2x0+1−α1α2ϵˉ你看!中间的 x1 完美消失了!
如果我们为了书写方便,定义 αˉt=α1×α2×...×αt(即前 t 步信号保留率的连乘)。
以此类推,一直套娃代入到第 t 步,就会得到那个核心结论:
xt=αˉtx0+1−αˉtϵ结论: 因为正态分布的噪声加法具有奇妙的抵消和合并特性,我们不需要经过中间的 x1,x2...,就能直接算出第 t 步的含噪结果。
第二重解密:DDIM 的生成公式为什么会分裂成三部分?
这其实不是凭空捏造的,而是作者为了**“凑出”**一个符合规定的分布,反向推导(Reverse-engineer)出来的。
1. DDIM 作者的终极目标是什么?
DDIM 的核心理念是:我不管反向去噪的过程怎么走,但我必须保证任意第 t−1 步的图像 xt−1,必须符合我们刚刚在第一步推导出的那个前向公式的规律。
也就是说,xt−1 必须满足:
xt−1=αˉt−1x0+1−αˉt−1⋅(总噪声)2. “拆解”总噪声(核心原理)
现在,我们手里有三个已知情报:
- 预测出的干净图像(x0)
- 当前的带噪图像(xt)
- 我们预测出的,包含在 xt 里的那坨噪声(ϵθ)
在上面的终极目标公式中,“总噪声”的方差(或者说它的总强度)必须是 1−αˉt−1。
作者想:如果我把这团“总噪声”全部变成随机噪声,那就是普通的 DDPM,每次结果都不一样。我能不能把这团总噪声“切”成两块?
- 一块是确定的(Deterministic): 用我们大模型已经预测出来的噪声 ϵθ 来代替,这样它就有确定的方向(指向 xt)。
- 一块是随机的(Stochastic): 引入一点点全新的纯随机噪声 ϵt,它的方差我们自己设定为 σt2。
就像分蛋糕一样,总方差预算是 1−αˉt−1:
既然我分给了“随机噪声” σt2 的份额,那么留给“确定性噪声”的份额就只剩下:
(1−αˉt−1)−σt23. 拼装成型
根据上面的“分蛋糕”逻辑,我们把原本的 xt−1 公式重新写一遍:
xt−1=干净信号部分+确定性噪声部分+随机噪声部分把对应的方差系数套进去:
xt−1=干净信号部分αˉt−1⋅x0+确定性噪声部分1−αˉt−1−σt2⋅ϵθ+随机噪声部分σt⋅ϵt最后,因为真实的 x0 我们是不知道的,我们只能用大模型预测出来的 x0(也就是你提到的初中代数移项出来的那个式子)来替换掉公式里的 x0。
这就是那“三部分”的由来!
它没有任何魔法,它的原理就是:在保持总方差(噪声强度)绝对不变的前提下,巧妙地把噪声分成了“可预测部分”和“纯随机部分”。 当我们把纯随机部分(方差 σt)设为 0 时,整个过程就变成了完全确定的加速跳步过程。
核心定理:方差的平方缩放性质
在概率论中,如果你有一个随机变量 X,它的方差是 Var(X)。如果你给它乘上一个常数 c,那么新变量的方差,等于原来方差乘以常数 c 的平方。
写成公式就是:
Var(c⋅X)=c2⋅Var(X)
把定理套用到我们的推导里
在扩散模型中,我们所有的基础噪声 ϵ(无论是 ϵ0,ϵ1 还是 ϵt),都被定义为标准正态分布。
标准正态分布有一个最重要的特性:它的均值是 0,方差是 1。
也就是说:Var(ϵ)=1。
现在,我们来看你抓出的第一坨噪声:
常数系数 cα2(1−α1)⋅随机变量 Xϵ0我们来算一下这一整坨的方差:
- 这里的常数 c=α2(1−α1)
- 根据上面的定理,这坨东西的方差 = c2⋅Var(ϵ0)
- 我们把 c 平方,根号就直接消掉了,变成了:α2(1−α1)
- 又因为基础噪声的方差 Var(ϵ0)=1
- 所以,最终的方差 = α2(1−α1)⋅1=α2(1−α1)
同理,我们看第二坨噪声:
常数系数 c1−α2⋅随机变量 Xϵ1它的方差就是把系数平方再乘以 1,即:(1−α2)2⋅1=1−α2。
最后一步:加起来重新打包
因为 ϵ0 和 ϵ1 是两次完全独立的随机抽卡(独立同分布),它们加在一起的总方差,就是各自的方差直接相加(这就是我们前面说的“外挂定理”):
总方差=α2(1−α1)+(1−α2)=1−α1α2现在,我们得到了这两坨噪声合并后的总方差是 1−α1α2。
但我们要把它重新写回公式里呀!公式里需要的是系数乘以一个标准噪声。
根据逆向推导:既然方差是 1−α1α2,那么根据 Var(c⋅X)=c2⋅Var(X),我们要找的新系数 c,必然就是总方差的平方根。
所以,合并后的噪声项就顺理成章地写成了:
1−α1α2⋅ϵˉ(这里的 ϵˉ 就是代表合并后的全新标准正态分布噪声)。
在具身智能(比如控制一个机械臂去抓杯子)的 Diffusion Policy 中,大模型输出的不再是一张图片,而是机器人的动作序列(比如未来 16 步的关节角度)。
下面这段极简风格的 Python 伪代码,展示了我们刚刚推导的 DDIM 公式是如何在机器人大脑中高速运转的:
Python
def ddim_fast_sample(robot_camera_image, unet_model, total_train_steps=1000, jump_steps=10):
"""
使用 DDIM 加速生成机器人动作轨迹
原本需要 1000 步,现在我们只跳跃计算 10 步 (极大提升速度,满足实时控制)
"""
action_t = generate_random_noise(shape=(16, joint_dim))
timesteps = get_jump_sequence(total_train_steps, jump_steps)
for i in range(len(timesteps)):
t = timesteps[i]
t_prev = timesteps[i+1] if i < len(timesteps)-1 else 0
predicted_noise = unet_model(action_t, t, condition=robot_camera_image)
predicted_x0 = calculate_clean_x0(action_t, predicted_noise, t)
action_t = ddim_assemble_formula(predicted_x0, predicted_noise, t_prev)
return action_t
while robot_is_turned_on:
current_image = get_camera_frame()
action_trajectory = ddim_fast_sample(current_image, my_diffusion_model)
execute_on_physical_robot(action_trajectory[0:8])
伪代码里的三个核心看点:
condition=robot_camera_image(条件控制):这就是具身智能的灵魂。传统的扩散模型是根据文字生成图片,而在具身智能里,模型是根据当前的视觉画面来指导噪声的预测,从而生成符合当前环境的动作。
- 只循环 10 次(极速推理):因为有了 DDIM 的跳步公式
ddim_assemble_formula,原本 for 循环要跑 1000 次,现在只要 10 次或者 20 次。这让计算延迟从几秒钟缩短到了几十毫秒,机器人才能不卡顿地丝滑运动。
- 滚动执行(Receding Horizon):你看最后的主循环,机器人每次预测一长串动作,但只执行一小部分。这就像人开车一样,眼睛看着远方(预测 16 步),但手只打眼前的方向盘(执行 8 步),然后不断循环这个过程,安全且鲁棒。