logo Mr.Robota 具身智能学习手册 EN
第十二章:具身智能面试问题汇总

直观感受一下 DDPM 和 DDIM 的区别:

准备好了吗?我们开始!


第一步:前置小知识(重参数化技巧)

在扩散模型中,我们最常用到一个技巧:如果你有一个符合正态分布的变量 X∼N(μ,σ2)X \sim \mathcal{N}(\mu, \sigma^2)(均值为 μ\mu,方差为 σ2\sigma^2),我们可以把它拆成:

X=μ+σ⋅ϵX = \mu + \sigma \cdot \epsilon

这里的 ϵ\epsilon 是一个标准正态分布的纯噪声 ϵ∼N(0,1)\epsilon \sim \mathcal{N}(0, 1)。

直白点说: 任意状态 = 确定的基础值 + (随机噪声 ×\times 噪声强度)。记住这个公式,它是贯穿整个推导的灵魂。


第二步:DDPM 的基础设定(从头到尾加噪)

在原来的 DDPM(去噪扩散概率模型)中,我们有一个清晰的正向加噪过程。

假设我们有一张清晰的图像(或者机器人的一个完美动作),叫做 x0x_0。我们在它上面不断加噪声,加到第 tt 步时,它变成了 xtx_t。

DDPM 证明了一个极其重要的结论:我们不需要一步步加噪声,我们可以直接从 x0x_0 一步跳到 xtx_t。

公式是这样的:

xt=αˉtx0+1−αˉtϵx_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1 - \bar{\alpha}_t} \epsilon
  • x0x_0: 初始干净数据。
  • xtx_t: 第 tt 步的含噪数据。
  • αˉt\bar{\alpha}_t: 一个介于 0 到 1 之间的系数。你可以把它理解为**“信号保留率”**。随着步数 tt 变大,αˉt\bar{\alpha}_t 会越来越小(趋近于 0)。
  • 1−αˉt1 - \bar{\alpha}_t: “噪声强度”。
  • ϵ\epsilon: 标准正态分布的纯噪声。

总结一句话: 第 tt 步的数据 xtx_t,就是**“衰减后的干净数据”加上“逐渐增强的噪声”**。


第三步:逆向思考 —— 如何从 xtx_t 猜出 x0x_0?

现在,我们进入大模型真正工作的阶段:反向去噪。

大模型(比如一个 U-Net 神经网络)在推理时,看到的是一团带有噪声的 xtx_t。它的任务是:预测出这团数据里包含的噪声 ϵ\epsilon 是什么。

假设我们训练好了一个神仙大模型,记作 ϵθ(xt,t)\epsilon_\theta(x_t, t)。它可以精准地猜出当前 xtx_t 里面的噪声。

既然噪声被猜出来了,我们是不是可以利用第二步的公式,反推(猜测)出干净的 x0x_0?

我们将第二步的公式 xt=αˉtx0+1−αˉtϵx_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1 - \bar{\alpha}_t} \epsilon 移项变形,求 x0x_0:

预测的 x0=xt−1−αˉt⋅ϵθ(xt,t)αˉt\text{预测的 } x_0 = \frac{x_t - \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon_\theta(x_t, t)}{\sqrt{\bar{\alpha}_t}}

(这一步只是简单的初中代数移项哦!)

这就是大模型在任意第 tt 步时,脑海中“想象”出的最终清晰结果。


第四步:DDIM 的核心魔法 —— 重新拼装 xt−1x_{t-1}

在传统的 DDPM 中,必须依赖马尔可夫链一步一步倒退(xt→xt−1→xt−2x_t \rightarrow x_{t-1} \rightarrow x_{t-2})。

DDIM 的天才之处在于:它打破了必须一步一步退的规则。 它提出,只要我保证最后生成的边缘分布一样,中间怎么走随便我!于是 DDIM 强行构造了一个生成 xt−1x_{t-1} 的新公式。

DDIM 认为,第 t−1t-1 步的数据 xt−1x_{t-1},可以由三部分拼装而成:

xt−1=部分1+部分2+部分3x_{t-1} = \text{部分1} + \text{部分2} + \text{部分3}

让我们把这三部分详细写出来(不要怕长,我们拆开看):

xt−1=αˉt−1⋅(xt−1−αˉt⋅ϵθ(xt,t)αˉt)⏟部分1:指向预测的 x0+1−αˉt−1−σt2⋅ϵθ(xt,t)⏟部分2:指向 xt 的方向+σt⋅ϵt⏟部分3:随机噪声x_{t-1} = \underbrace{\sqrt{\bar{\alpha}_{t-1}} \cdot \left( \frac{x_t - \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon_\theta(x_t, t)}{\sqrt{\bar{\alpha}_t}} \right)}_{\text{部分1:指向预测的 } x_0} + \underbrace{\sqrt{1 - \bar{\alpha}_{t-1} - \sigma_t^2} \cdot \epsilon_\theta(x_t, t)}_{\text{部分2:指向 } x_t \text{ 的方向}} + \underbrace{\sigma_t \cdot \epsilon_t}_{\text{部分3:随机噪声}}

我们来逐一翻译这三部分:

  1. 部分1(指向 x0x_0): 你看括号里的那一坨,是不是就是我们在第三步预测的 x0x_0?前面乘上 αˉt−1\sqrt{\bar{\alpha}_{t-1}},意思是我们要保留多少 x0x_0 的信号。
  2. 部分2(指向 xtx_t 的方向): 为了平滑过渡,我们还需要加一点点我们刚预测出的噪声 ϵθ(xt,t)\epsilon_\theta(x_t, t) 回去。系数 1−αˉt−1−σt2\sqrt{1 - \bar{\alpha}_{t-1} - \sigma_t^2} 是为了保证总的方差对齐。
  3. 部分3(随机噪声): σt\sigma_t 是我们自己可以控制的方差参数,ϵt\epsilon_t 是新的随机噪声。

第五步:见证奇迹的时刻 —— 为什么能加速?

上面的公式就是泛化的扩散模型采样公式。接下来就是 DDIM 发挥威力的地方了:

操作 1:让 σt=0\sigma_t = 0(消除随机性)

DDIM 的论文作者指出,如果我们直接把随机性砍掉,也就是让方差参数 σt=0\sigma_t = 0。

此时,公式中的部分3直接消失!

xt−1=αˉt−1⋅(预测的 x0)+1−αˉt−1⋅ϵθ(xt,t)x_{t-1} = \sqrt{\bar{\alpha}_{t-1}} \cdot (\text{预测的 } x_0) + \sqrt{1 - \bar{\alpha}_{t-1}} \cdot \epsilon_\theta(x_t, t)

这意味着什么?意味着从 xtx_t 到 xt−1x_{t-1} 的过程变成了**完全确定(Deterministic)**的!只要你的输入噪声固定,无论生成多少次,结果都一模一样。这对具身智能机器人的稳定性至关重要!

操作 2:跳步(Accelerated Sampling)

仔细看最后这个化简后的公式,你会发现:计算 xt−1x_{t-1} 的时候,我们只用到了 xtx_t、大模型的预测 ϵθ\epsilon_\theta、以及 αˉt−1\bar{\alpha}_{t-1}。

这里的 t−1t-1 只是一个符号,它不需要真的是上一个整数!

也就是说,我们可以把时间步设定为一个子序列,比如从 t=1000t=1000 直接跳到 t=900t=900,把 900900 作为公式里的 “t−1t-1” 代入计算。

这就实现了巨大的跳跃,原来需要迭代 1000 次,现在我们每 50 步跳一次,只需 20 次就能生成最终结果!这就是 DDIM 加速的根本原理。


总结归纳

  1. 我们通过大模型预测出当前的噪声 ϵθ\epsilon_\theta。
  2. 我们用这个噪声反推出干净的数据 x0x_0。
  3. DDIM 构造了一个新公式,用预测的 x0x_0 和预测的噪声按特定比例组合,直接算出一个确定性的前置状态。
  4. 因为公式不再依赖马尔可夫链的严密连贯性,我们可以大步幅地“跳着算”,实现几倍甚至几十倍的加速。

第一重解密:如何证明可以直接从 x0x_0 跳到 xtx_t?

要想证明这个公式,我们需要先准备一个非常基础的统计学**“外挂定理”**(正态分布的可加性):

定理: 如果你有两个相互独立的正态分布变量,分别带有方差 AA 和方差 BB。把它们加在一起,新的变量依然是正态分布,且方差相加,等于 A+BA + B。

在扩散模型中,我们定义单步的加噪过程是这样的(每次只加一点点噪声):

x1=α1x0+1−α1ϵ0x_1 = \sqrt{\alpha_1} x_0 + \sqrt{1 - \alpha_1} \epsilon_0
x2=α2x1+1−α2ϵ1x_2 = \sqrt{\alpha_2} x_1 + \sqrt{1 - \alpha_2} \epsilon_1

这里的 ϵ0,ϵ1\epsilon_0, \epsilon_1 都是标准正态分布的纯噪声(均值为0,方差为1)。系数 α\alpha 也就是我们说的“信号保留率”。

现在,我们要挑战把 x2x_2 直接用 x0x_0 表示出来:

把 x1x_1 的公式,直接代入到 x2x_2 的公式里去:

x2=α2(α1x0+1−α1ϵ0)+1−α2ϵ1x_2 = \sqrt{\alpha_2} (\sqrt{\alpha_1} x_0 + \sqrt{1 - \alpha_1} \epsilon_0) + \sqrt{1 - \alpha_2} \epsilon_1

我们把括号拆开:

x2=α1α2x0+α2(1−α1)ϵ0+1−α2ϵ1⏟这里是两坨噪声相加x_2 = \sqrt{\alpha_1 \alpha_2} x_0 + \underbrace{\sqrt{\alpha_2(1 - \alpha_1)} \epsilon_0 + \sqrt{1 - \alpha_2} \epsilon_1}_{\text{这里是两坨噪声相加}}

见证奇迹的时刻到了!我们用上面提到的“外挂定理”来合并这两坨噪声:

第一坨噪声的方差是:α2(1−α1)=α2−α1α2\alpha_2(1 - \alpha_1) = \alpha_2 - \alpha_1 \alpha_2

第二坨噪声的方差是:1−α21 - \alpha_2

根据定理,两个噪声相加,方差相加:

(α2−α1α2)+(1−α2)=1−α1α2(\alpha_2 - \alpha_1 \alpha_2) + (1 - \alpha_2) = 1 - \alpha_1 \alpha_2

也就是说,这两坨噪声合并后,变成了一个全新的、方差为 1−α1α21 - \alpha_1 \alpha_2 的标准噪声(我们叫它 ϵˉ\bar{\epsilon}):

x2=α1α2x0+1−α1α2ϵˉx_2 = \sqrt{\alpha_1 \alpha_2} x_0 + \sqrt{1 - \alpha_1 \alpha_2} \bar{\epsilon}

你看!中间的 x1x_1 完美消失了!

如果我们为了书写方便,定义 αˉt=α1×α2×...×αt\bar{\alpha}_t = \alpha_1 \times \alpha_2 \times ... \times \alpha_t(即前 tt 步信号保留率的连乘)。

以此类推,一直套娃代入到第 tt 步,就会得到那个核心结论:

xt=αˉtx0+1−αˉtϵx_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1 - \bar{\alpha}_t} \epsilon

结论: 因为正态分布的噪声加法具有奇妙的抵消和合并特性,我们不需要经过中间的 x1,x2...x_1, x_2...,就能直接算出第 tt 步的含噪结果。


第二重解密:DDIM 的生成公式为什么会分裂成三部分?

这其实不是凭空捏造的,而是作者为了**“凑出”**一个符合规定的分布,反向推导(Reverse-engineer)出来的。

1. DDIM 作者的终极目标是什么?

DDIM 的核心理念是:我不管反向去噪的过程怎么走,但我必须保证任意第 t−1t-1 步的图像 xt−1x_{t-1},必须符合我们刚刚在第一步推导出的那个前向公式的规律。

也就是说,xt−1x_{t-1} 必须满足:

xt−1=αˉt−1x0+1−αˉt−1⋅(总噪声)x_{t-1} = \sqrt{\bar{\alpha}_{t-1}} x_0 + \sqrt{1 - \bar{\alpha}_{t-1}} \cdot (\text{总噪声})

2. “拆解”总噪声(核心原理)

现在,我们手里有三个已知情报:

  1. 预测出的干净图像(x0x_0)
  2. 当前的带噪图像(xtx_t)
  3. 我们预测出的,包含在 xtx_t 里的那坨噪声(ϵθ\epsilon_\theta)

在上面的终极目标公式中,“总噪声”的方差(或者说它的总强度)必须是 1−αˉt−11 - \bar{\alpha}_{t-1}。

作者想:如果我把这团“总噪声”全部变成随机噪声,那就是普通的 DDPM,每次结果都不一样。我能不能把这团总噪声“切”成两块?

  • 一块是确定的(Deterministic): 用我们大模型已经预测出来的噪声 ϵθ\epsilon_\theta 来代替,这样它就有确定的方向(指向 xtx_t)。
  • 一块是随机的(Stochastic): 引入一点点全新的纯随机噪声 ϵt\epsilon_t,它的方差我们自己设定为 σt2\sigma_t^2。

就像分蛋糕一样,总方差预算是 1−αˉt−11 - \bar{\alpha}_{t-1}:

既然我分给了“随机噪声” σt2\sigma_t^2 的份额,那么留给“确定性噪声”的份额就只剩下:

(1−αˉt−1)−σt2(1 - \bar{\alpha}_{t-1}) - \sigma_t^2

3. 拼装成型

根据上面的“分蛋糕”逻辑,我们把原本的 xt−1x_{t-1} 公式重新写一遍:

xt−1=干净信号部分+确定性噪声部分+随机噪声部分x_{t-1} = \text{干净信号部分} + \text{确定性噪声部分} + \text{随机噪声部分}

把对应的方差系数套进去:

xt−1=αˉt−1⋅x0⏟干净信号部分+1−αˉt−1−σt2⋅ϵθ⏟确定性噪声部分+σt⋅ϵt⏟随机噪声部分x_{t-1} = \underbrace{\sqrt{\bar{\alpha}_{t-1}} \cdot x_0}_{\text{干净信号部分}} + \underbrace{\sqrt{1 - \bar{\alpha}_{t-1} - \sigma_t^2} \cdot \epsilon_\theta}_{\text{确定性噪声部分}} + \underbrace{\sigma_t \cdot \epsilon_t}_{\text{随机噪声部分}}

最后,因为真实的 x0x_0 我们是不知道的,我们只能用大模型预测出来的 x0x_0(也就是你提到的初中代数移项出来的那个式子)来替换掉公式里的 x0x_0。

这就是那“三部分”的由来!

它没有任何魔法,它的原理就是:在保持总方差(噪声强度)绝对不变的前提下,巧妙地把噪声分成了“可预测部分”和“纯随机部分”。 当我们把纯随机部分(方差 σt\sigma_t)设为 0 时,整个过程就变成了完全确定的加速跳步过程。


核心定理:方差的平方缩放性质

在概率论中,如果你有一个随机变量 XX,它的方差是 Var(X)Var(X)。如果你给它乘上一个常数 cc,那么新变量的方差,等于原来方差乘以常数 cc 的平方。

写成公式就是:

Var(c⋅X)=c2⋅Var(X)Var(c \cdot X) = c^2 \cdot Var(X)

把定理套用到我们的推导里

在扩散模型中,我们所有的基础噪声 ϵ\epsilon(无论是 ϵ0,ϵ1\epsilon_0, \epsilon_1 还是 ϵt\epsilon_t),都被定义为标准正态分布。

标准正态分布有一个最重要的特性:它的均值是 0,方差是 1。

也就是说:Var(ϵ)=1Var(\epsilon) = 1。

现在,我们来看你抓出的第一坨噪声:

α2(1−α1)⏟常数系数 c⋅ϵ0⏟随机变量 X\underbrace{\sqrt{\alpha_2(1 - \alpha_1)}}_{\text{常数系数 } c} \cdot \underbrace{\epsilon_0}_{\text{随机变量 } X}

我们来算一下这一整坨的方差:

  1. 这里的常数 c=α2(1−α1)c = \sqrt{\alpha_2(1 - \alpha_1)}
  2. 根据上面的定理,这坨东西的方差 = c2⋅Var(ϵ0)c^2 \cdot Var(\epsilon_0)
  3. 我们把 cc 平方,根号就直接消掉了,变成了:α2(1−α1)\alpha_2(1 - \alpha_1)
  4. 又因为基础噪声的方差 Var(ϵ0)=1Var(\epsilon_0) = 1
  5. 所以,最终的方差 = α2(1−α1)⋅1=α2(1−α1)\alpha_2(1 - \alpha_1) \cdot 1 = \alpha_2(1 - \alpha_1)

同理,我们看第二坨噪声:

1−α2⏟常数系数 c⋅ϵ1⏟随机变量 X\underbrace{\sqrt{1 - \alpha_2}}_{\text{常数系数 } c} \cdot \underbrace{\epsilon_1}_{\text{随机变量 } X}

它的方差就是把系数平方再乘以 1,即:(1−α2)2⋅1=1−α2(\sqrt{1 - \alpha_2})^2 \cdot 1 = 1 - \alpha_2。


最后一步:加起来重新打包

因为 ϵ0\epsilon_0 和 ϵ1\epsilon_1 是两次完全独立的随机抽卡(独立同分布),它们加在一起的总方差,就是各自的方差直接相加(这就是我们前面说的“外挂定理”):

总方差=α2(1−α1)+(1−α2)=1−α1α2\text{总方差} = \alpha_2(1 - \alpha_1) + (1 - \alpha_2) = 1 - \alpha_1\alpha_2

现在,我们得到了这两坨噪声合并后的总方差是 1−α1α21 - \alpha_1\alpha_2。

但我们要把它重新写回公式里呀!公式里需要的是系数乘以一个标准噪声。

根据逆向推导:既然方差是 1−α1α21 - \alpha_1\alpha_2,那么根据 Var(c⋅X)=c2⋅Var(X)Var(c \cdot X) = c^2 \cdot Var(X),我们要找的新系数 cc,必然就是总方差的平方根。

所以,合并后的噪声项就顺理成章地写成了:

1−α1α2⋅ϵˉ\sqrt{1 - \alpha_1\alpha_2} \cdot \bar{\epsilon}

(这里的 ϵˉ\bar{\epsilon} 就是代表合并后的全新标准正态分布噪声)。


在具身智能(比如控制一个机械臂去抓杯子)的 Diffusion Policy 中,大模型输出的不再是一张图片,而是机器人的动作序列(比如未来 16 步的关节角度)。

下面这段极简风格的 Python 伪代码,展示了我们刚刚推导的 DDIM 公式是如何在机器人大脑中高速运转的:

Python# 假设我们训练好了一个扩散大模型 (U-Net),它能根据看到的画面预测动作里的噪声
# robot_camera_image: 机器人当前看到的画面 (作为生成动作的条件)

def ddim_fast_sample(robot_camera_image, unet_model, total_train_steps=1000, jump_steps=10):
    """
    使用 DDIM 加速生成机器人动作轨迹
    原本需要 1000 步,现在我们只跳跃计算 10 步 (极大提升速度,满足实时控制)
    """
    # 1. 初始化:凭空捏造一条完全随机的动作轨迹 (纯噪声)
    # 比如:随机生成未来 16 步的关节运动指令,这时的动作完全是乱抖的
    action_t = generate_random_noise(shape=(16, joint_dim)) 
    
    # 2. 规划跳步路线:比如从 1000 跳到 900, 800 ... 一直到 0
    timesteps = get_jump_sequence(total_train_steps, jump_steps)
    
    # 3. 核心逆向去噪循环 (DDIM 开始发威)
    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)
        
        # [对应数学推导的移项公式]:用当前带噪动作和预测的噪声,反推算出完全干净的完美动作 (x_0)
        predicted_x0 = calculate_clean_x0(action_t, predicted_noise, t)
        
        # [对应数学推导的三部分拼装]:DDIM 的确定性公式
        # 这里直接消除了随机方差项 (sigma_t = 0),只用 x_0 和 预测噪声 组合出 t_prev 步的动作
        action_t = ddim_assemble_formula(predicted_x0, predicted_noise, t_prev)
        
    # 循环结束,这时的 action_t 已经从一团乱码,变成了一套极其平滑、精准的抓取动作!
    return action_t


# ==========================================
# 机器人的真实物理控制循环 (例如每秒执行 10 次)
# ==========================================
while robot_is_turned_on:
    # A. 睁开眼睛,看看当前环境
    current_image = get_camera_frame()
    
    # B. 大脑飞速运转:调用上面的 DDIM 算法,仅用 10 步算出未来 16 步的动作
    action_trajectory = ddim_fast_sample(current_image, my_diffusion_model)
    
    # C. 具身智能的特殊技巧:Receding Horizon Control (滚动时域控制)
    # 虽然预测了未来 16 步,但为了应对突发情况,我们只执行前 8 步,然后重新看、重新算!
    execute_on_physical_robot(action_trajectory[0:8])

伪代码里的三个核心看点:

  1. condition=robot_camera_image(条件控制):这就是具身智能的灵魂。传统的扩散模型是根据文字生成图片,而在具身智能里,模型是根据当前的视觉画面来指导噪声的预测,从而生成符合当前环境的动作。
  2. 只循环 10 次(极速推理):因为有了 DDIM 的跳步公式 ddim_assemble_formula,原本 for 循环要跑 1000 次,现在只要 10 次或者 20 次。这让计算延迟从几秒钟缩短到了几十毫秒,机器人才能不卡顿地丝滑运动。
  3. 滚动执行(Receding Horizon):你看最后的主循环,机器人每次预测一长串动作,但只执行一小部分。这就像人开车一样,眼睛看着远方(预测 16 步),但手只打眼前的方向盘(执行 8 步),然后不断循环这个过程,安全且鲁棒。