前言

自从23年大模型火爆以来,我博客的影响力每天都在极速增长

  1. 特别是24年我博客内开始解读一系列具身前沿论文,以及分享我司在具身方面的实践落地之后,使得不只是国内清北复交浙等等的博士生 在看本博客,连斯坦福的博士生们 也在看了
  2. 而这博客影响力的极速增长,也成为了我一直更新博客的重要动力之一

对于具身,自从PI公司推出π0之后,他们每个对外发布的工作都有着很高的影响力,比如对于机器人的高频控制技术,我在之前解读过实时分块(RTC)技术『详见此文《实时动作分块RTC——为解决高延迟,让π0.5也可以点燃火柴、插入网线:执行当前动作分块时生成下一个分块,且已执行的冻结 未执行的则通过“图像修复”做补全』,其通过异步预测动作块,并借助推理时图像修复对已执行动作进行调节,使VLA能够生成流畅、响应迅速的机器人运动轨迹

然而这种修复方法会引入增加推理延迟的计算开销

  1. PI因此再次提出一种简洁替代方案:在训练时模拟推理延迟,直接对动作前缀进行调节,从而消除所有推理时开销
    该方法无需修改模型架构或机器人运行时系统,仅需增加数行代码即可实现
  2. 至于实际效果上
    一方面,模拟实验表明,在较高推理延迟场景下,训练时实时分块(training-time RTC)性能优于推理时实时计算(inference-time RTC)
    二方面,通过π0.6版VLA模型在箱体构建与浓缩咖啡制作任务中的实体实验证明:训练时实时分块在保持任务性能与执行速度的同时,计算成本显著低于推理时实时计算

第一部分

1.1 引言、相关工作、预备知识

1.1.1 引言

如原论文所述,与聊天机器人或搜索引擎不同,具身智能体必须在实时环境中运作。智能体行为与环境之间的反馈循环要求其具备即时响应能力——如同人类运动员,当外部环境变化时,智能体无法简单地'停滞思考'

然而,前沿模型规模持续扩大使得这一要求愈发难以满足。这在机器人学习领域体现得尤为明显:由数十亿参数组成的VLA正日益广泛地应用于高频机器人控制,以完成精密操作任务。当模型推理延迟达到数十至数百毫秒时,生成流畅且响应灵敏的运动轨迹是一项巨大挑战

实时分块处理技术(RTC;[5])通过融合动作分块[9, 27]、流匹配[13]和推理时动作修复[18, 21],为解决该问题提供了有效途径

  1. 在实时分块(RTC)技术中,动作区块以异步方式被预测——当前区块仍在执行时,下一个区块已开始生成
    为确保区块间的连续性,每个生成过程均以先前预测动作的冻结前缀作为调节条件,填补剩余部分
  2. 然而,RTC采用的推理时图像修复方法会引入额外计算开销——进而导致延迟——这在某种程度上违背了实时执行框架的设计初衷
    实证研究表明,推理时图像修复方法本质上难以应对高推理延迟场景

对此,来自PI公司的研究者 Kevin Black、Allen Z. Ren、Michael Equi、Sergey Levine通过一种训练时模拟推理延迟的图像修复方法增强RTC系统,彻底消除推理阶段的计算开销『we augment RTC with an inpainting method that simulates inference delay at training time and eliminates any inference-time computational overhead

  1. 该方法不要在推理时修补动作,而在训练时就教会模型应对延迟
    咋做到呢?
    很简单,在训练阶段,模拟推理延迟。直接把“前缀动作”(即推理期间机器人已经执行掉的动作)作为已知条件喂给模型,让模型只负责预测剩下的“后缀动作”
    是不和跟『基于多帧历史观测输入(而非只输入当前帧观测)去预测未来动作』很像

    其可作为推理时RTC的直接替代方案:无需修改模型架构或机器人运行时环境,仅需添加数行代码即可实现
    在模拟基准测试中,训练时实时分块(training-time RTC)在高延迟场景下表现优于推理时实时分块(inference-time RTC)
  2. 真实场景验证表明,通过对未经动作前缀调节预训练的基础模型进行微调,可成功实现训练时RTC的部署
    比如通过将训练时实时分块应用于π0.6 VLA模型[24],作者在两项高复杂度任务(箱体构建与浓缩咖啡制作)中展现出优于推理时实时计算的性能提升

为方便大家一目了然、一看即懂,我还是再给大家举个通俗易懂的例子


1. 场景设定

  • 机器人就像接力赛的跑步者,必须不停地跑(实时动作),不能停下来发呆

  • AI 模型就像大脑,负责规划接下来的路线

  • 难题(延迟): 大脑思考“下一步怎么跑”是需要时间的(比如需要 0.1 秒)。而在大脑思考的这 0.1 秒里,跑步者(机器人)其实依然靠惯性往前跑了几步

2. 笨办法(旧的“推理时 RTC”方案)

  • 做法: 大脑在思考(生成动作)的全过程中,每产生一点念头(每一步去噪),都要停下来检查:“现在的开头跟机器人实际位置对得上吗?”

  • 补救:为了强行对齐,大脑必须在思考的每一步都进行反向计算(算导数),强迫(最新)生成的动作前缀必须吻合既定事实(已经跑出去的那 2 米)

  • 后果: 这种“边想边改”极其消耗算力,因为通过大量的数学计算“硬拽”着模型去思考,导致推理速度变慢

3. 聪明办法(本文的“训练时 RTC”方案)

  • 做法: 既然知道大脑思考需要 0.1 秒,那在平时训练的时候,就专门做一种特训

  • 特训内容: 教练(训练算法)直接告诉大脑:“你开始思考吧,但在你思考完的那一瞬间,机器人肯定已经跑到前方 2 米的位置了。所以,请你直接从 2 米外那个点开始规划后面的路线! ”

  • 结果:

    • 大脑在思考时,已经把“由于延迟而跑掉的那几步(前缀动作)”考虑进去了

    • 生成的路线天生就是完美的连接,不需要事后修补

    • 这就是“训练时动作条件化”:在训练时就把“既定事实(前缀)”作为条件喂给模型,让它只管预测后面的事

总之,不要等跑完步发现路线对不上再去修图(推理时修补),而是在起跑前就预判好你会跑到哪,直接规划后面的路(训练时条件化)

1.1.2 相关工作

首先,对于动作分块与VLA模型

  1. 动作分块[9,26]已成为端到端模仿学习中视觉运动控制的实际标准方法。近期研究表明,通过增强视觉语言模型(VLM)生成动作分块的能力,在机器人操作领域取得显著成功,由此催生了VLA[4,6-8,10-12,14,17,28,29]
  2. 随后涌现出大量方法,旨在解决大型VLA模型与高频控制之间的协调难题
    例如Gemini Robotics[23]与GR00T[3]采用分层式VLA架构,将模型拆分为重量级系统2(高层规划)与轻量级系统1(底层动作生成)组件
    MiniVLA [2] 和 SmolVLA [20] 提出的视觉语言动作模型架构,相比大多数设计具有更快的运行速度和更高的效率,使得边缘设备上的推理部署更具可行性

这些贡献与本文介绍的Training-Time RTC正交,各自存在权衡取舍

其次,对于VLA的实时执行

  1. 最密切相关的先前研究是实时分块技术(RTC; [5]),其提出的异步执行框架为本研究奠定了基础
  2. 同样相关的是 SmolVLA [20],其提出的异步执行算法与 RTC 技术相似;然而 SmolVLA 未能解决分块间不连续性问题,导致分块衔接处出现分布外的'抖动'现象
  3. 与本研究同期,A2C2 [19] 和 VLASH [22] 分别通过添加轻量级校正头模块和基于单个未来动作的条件处理,解决了不连续性问题
    与VLASH不同,作者在完整未来动作前缀上进行条件约束

1.1.3 背景知识

作者采用与RTC[5]相同的问题建模

  1. 起始于动作分块策略p\left(\mathbf{A}_{t} \mid \mathbf{o}_{t}\right)
    其中
    \mathbf{A}_{t}=\left[\mathbf{a}_{t}, \mathbf{a}_{t+1}, \ldots, \mathbf{a}_{t+H-1}\right]表示未来动作块
    \mathbf{o}_{t}表示观测值,t 代表控制器时间步
    且称H为预测时域,在推理阶段,每个动作块展开执行s \leq H个时间步,其中s称为执行范围
  2. 为考虑模型推理耗时,作者定义 d 作为以控制器时间步为单位的推理延迟
    若推理始于第 t 步,则生成的动作块需至第t+d步方可使用,因此前d 个动作实际无法执行
    但若满足d \leq H-s,这些前 d 个时间步将对应先前动作块的可执行动作

    作者称当前块与先前块重叠的d 个动作为动作前缀(参见图1)

    上图展示两个重叠动作分块的示意图位于时间点 t 与 t+d 之间的动作(取自前一分块)即为动作前缀(红色标注)
    由图可知,必须满足约束条件t+d \leq t-s+H \rightarrow d \leq H-s才能构成有效动作前缀需注意:
    \rightarrow  推理时实时计算使用全部 H-s 个重叠动作(黄区域)指导当前分块生成
    \rightarrow  而训练时实时分块仅使用前 d 个动作(红色区域)
  3. 作者考虑采用条件流匹配[13]训练的策略,该方法最小化以下损失函数:
    \mathbf{A}_{t}^{\tau}=\tau \mathbf{A}_{t}+(1-\tau) \boldsymbol{\epsilon} \quad \boldsymbol{\epsilon} \sim \mathcal{N}(\mathbf{0}, \mathbf{I})
    \mathcal{L}(\theta)=\mathbb{E}\left\|\mathbf{v}_{\theta}\left(\mathbf{A}_{t}^{\tau}, \mathbf{o}_{t}, \tau\right)-\left(\boldsymbol{\epsilon}-\mathbf{A}_{t}\right)\right\|^{2}
    其中\mathbf{v}_{\theta} 是神经网络,\tau 表示流匹配时间步长。在推理时,可将 \mathbf{v}_{\theta}\tau=0 积分至 1,以生成数据集分布p\left(\mathbf{A}_{t} \mid \mathbf{o}_{t}\right)的样本

1.2 训练时动作条件化

1.2.1 模拟推理延迟,在训练时以前缀动作为条件实现策略条件化

推理时实时计算[5]通过基于伪逆引导[18,21]的推理时图像修复方法,将策略条件化于动作前缀(图1红色部分)

  1. 为提升分块间连续性,推理时实时计算(RTC)额外以所有重叠动作为条件,对超出前缀的动作采用指数递减权重(图1黄色部分)
    在RTC中,该技术被称为'软掩码'。虽然伪逆引导提供了极大灵活性——可实现软掩码——但它也要求在每次去噪步骤中计算向量-雅可比乘积(通过反向传播实现)
  2. 本研究Training-Time RTC的核心洞见在于:可以通过模拟推理延迟,在训练时以前缀动作为条件实现策略条件化
    尽管这无法达到推理时图像修复的同等级灵活性,但彻底消除了计算开销
    ————
    形式化表述为:可学习p\left(\mathbf{A}_{t+d: H} \mid \mathbf{o}_{t}, \mathbf{A}_{t: t+d}\right),其中\mathbf{A}_{t: t+d}为动作前缀(图1红色部分)\mathbf{A}_{t+d: H}为动作后缀(图1黄绿色部分),两者均取自同一真实动作块

在大多数标准策略架构中实现此功能仅需进行3处最小改动

  1. 修改模型架构,允许每个动作时间步长使用不同的流匹配时间步长
    对于采用adalN-zero条件化处理流匹配时间步长的类扩散变换器架构[16],这很简单——只需允许不同token间的缩放、平移和门控参数不同。此修改不改变可学习参数数量
  2. 对前缀使用真实无噪动作,并将对应流匹配时间步长设为1。后缀部分保持不变
    这使模型基于真实动作前缀进行条件化,同时仅用其去除后缀噪声
  3. 对损失函数进行屏蔽处理,使损失计算仅针对对应于后缀的输出部分

关于此条件方案在标准类扩散变换器架构(例如π0.6动作专家)中的应用示例,请参见图2『始终输入真实无噪的前缀动作,同时学习对后缀动作进行去噪。不同token的流匹配时间步长存在差异,这向模型指示了推理延迟

1.2.2 完整实现代码(含我个人对代码的详细解释:让公式与代码逐一对应)

完整实现损失计算与动作生成的Python代码请参见算法1。 实际应用中,由于无法预先获知确切的推理延迟(且现实场景中的推理延迟可能存在波动),在训练期间对延迟量d 进行随机采样

经此修改后,动作生成器以动作前缀\mathbf{A}_{t: t+d}及延迟量d作为输入,并输出动作后缀\mathbf{A}_{t+d: H}

说白了,该方法模拟推理时的延迟。它将动作序列分为两部分:

  1. Prefix (前缀):模拟已经执行或确定的动作(作为条件,视为已知)

  2. Postfix (后缀):需要预测的未来动作(需要去噪生成)

因此,该组件遵循与推理时实时计算(RTC)的动作生成模块相同的接口规范(参见文献[5]算法1),可作为无缝替代组件直接部署

为方便大家更好的理解上述代码中的一系列操作,特别是把对应的代码与公式逐一对应起来,故我还是给大家做个详尽细致的解释说明

整个代码分为两个部分

首先是第一部分:训练损失计算(compute_loss)

这个函数用于在训练过程中计算损失。它随机采样一个延迟d ,将前d 个动作视为已知(Prefix),训练模型去预测剩余的动作(Postfix)

  1. 初始化与随机采样
    标准流匹配的时间采样\tau \sim U[0, 1] 和噪声采样\epsilon \sim \mathcal{N}(0, I)
    # [cite: 252-257]
    b, ah, ad = action_chunk.shape 
    noise_rng, time_rng, delay_rng = jax.random.split(rng, 3)
    time = jax.random.uniform(time_rng, (b,))          # 采样流匹配的时间步 t (0到1之间)
    noise = jax.random.normal(noise_rng, (b, ah, ad))  # 采样高斯噪声 epsilon
  2. 模拟推理延迟
    # [cite: 258-259]
    # 随机采样延迟 d,范围从 0 到 max_delay
    delay = jax.random.randint(delay_rng, (b,), 0, max_delay)
    上面代码模拟了现实世界中不同的推理延迟,d 代表动作的前缀长度
  3. 构建时间掩码
    这是算法最关键的一步。它打破了标准流匹配中所有 token 共享同一个时间 t 的规则
    # [cite: 260-261]
    # 创建前缀掩码:如果索引小于 delay,则为 True
    prefix_mask = jnp.arange(ah)[None, :] < delay[:, None] 
    
    # 核心逻辑:如果是前缀,时间设为 1.0;如果是后缀,保持原随机时间 t
    time = jnp.where(prefix_mask, 1.0, time[:, None])
    接下来,注意了
    ————
    通常流匹配插值公式为A_{t}^{\tau} = \tau A_{t} + (1-\tau)\epsilon
    \rightarrow  对于 Prefix (前缀):将 \tau 强制设为 1.0
    代入公式:A_{t}^{1.0} = 1.0 \cdot A_{t} + 0 \cdot \epsilon = A_{t}
    这意味着前缀部分直接输入干净的 Ground Truth (真实动作),不加噪声

    \rightarrow  对于 Postfix(后缀)\tau 保持为随机采样的数值(例如 0.4)
    这意味着后缀部分是加噪的,模型需要学习去噪
  4. 生成加噪输入(Noised Action)
    # [cite: 262]
    x_t = time[:, :, None] * action_chunk + (1 - time[:, :, None]) * noise
    上述代码对应于论文中的公式1
    A_{t}^{\tau}=\tau A_{t}+(1-\tau) \epsilon
    但注意,由于 time  已经根据前缀/后缀进行了修改,这里的 x_t  实际上是一个混合体:前半部分是真实动作,后半部分是加噪动作
  5. 模型预测与损失计算
    # [cite: 262-266]
    # 模型预测速度向量 v
    pred_v_t = model(observation, x_t, time) 
    
    # 计算预测值与目标值 (data - noise) 的差异
    loss = (pred_v_t - (action_chunk - noise)) ** 2
    上述代码对应论文中的公式2
    \mathcal{L}(\theta)=\mathbb{E}\left\|v_{\theta}\left(A_{t}^{\tau}, o_{t}, \tau\right)-\left(A_{t}-\epsilon\right)\right\|^{2}
    注意,原论文公式写为 (\epsilon - A_t),但代码通常实现为目标方向 A_t - \epsilon\epsilon - A_t,取平方后等价,代表向量场的方向
  6. 损失掩码
    # [cite: 267-270]
    postfix_mask = jnp.logical_not(prefix_mask)[:, :, None]
    
    # 只计算后缀部分的损失
    loss = jnp.sum(loss * postfix_mask) / (jnp.sum(postfix_mask) + 1e-8)
    对于上述代码而言,我们不希望模型预测前缀(因为前缀是已知的条件,且输入时没有加噪),所以只计算 Postfix (后缀) 部分的损失
    相当于教会模型:“给定观测 o_t 和前 d 个真实动作,预测剩下的动作”

其次是第二部分:动作生成与采样

  1. 初始化

    # [cite: 271-275]
    # action_prefix 包含已知的过去动作,但在延迟 d 之后的部分是无效的
    x_t = jax.random.normal(rng, (b, ah, ad))  # 从纯噪声开始
    time = 0.0                                 # 初始时间为 0
    dt = 1 / num_steps                         # 时间步长

    上述代码,流匹配生成过程通常是从纯噪声\tau=0积分到数据分布\tau=1

  2. 积分循环

    # [cite: 277-279]
    for _ in range(num_steps):
        # 强制将前缀部分,替换为真实的 action_prefix
        x_t = jnp.where(prefix_mask[:, :, None], action_prefix, x_t)

    上述代码是Training-Time RTC 在推理时的核心特性。在每一步去噪过程中,作者强制将前 d 个动作重置为已知的真实动作(Conditioning)
    这类似于图像生成中的 "Inpainting"(修补),但这里是硬性约束
    ————
    jnp.where 的逻辑是:“如果 是前缀(Mask为True),就强制使用 真实的 action_prefix;否则(Mask为False),继续使用 当前正在去噪生成的 x_t”
    言外之意是,不管模型怎么算,均强制把前 d个动作重置为真实的已知动作,确保生成的未来动作(后缀)能够完美衔接上已经发生的动作(前缀)

  3. 准备模型输入

    # [cite: 280-281]
    # 同样,前缀的时间设为 1.0,后缀的时间为当前积分时间 time
    time_masked = jnp.where(prefix_mask, 1.0, time)
    v_t = model(observation, x_t, time_masked)

    上述代码意味着,模型接收的 time 参数告诉它:前缀部分已经是最终结果 \tau=1,不需要去噪;后缀部分还处于中间状态\tau < 1,需要根据流场进行更新

  4. 更新Euler Step

    # [cite: 282-283]
    x_t = x_t + dt * v_t     # 更新状态
    time = time + dt         # 更新时间

    上述代码是标准的欧拉积分步。通过沿着预测的速度向量场 v_t 移动,逐渐将噪声转化为合理的动作序列

总之,这个算法巧妙地修改了输入数据构造和损失函数,而没有改变模型架构(Transformer 依然处理序列,只是不同 token 看到的t 不同)

  • 训练时:它教会模型看着“部分答案”(Prefix)做题
  • 推理时:它允许我们直接把已经发生的动作塞进去,模型就能无缝地补全剩下的动作,从而消除了额外的计算开销

// 待更

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐