三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

RoboTTT 方法详解 - S-X

RoboTTT 方法详解 - S-X

RoboTTT 方法详解


0. 先用 30 秒看懂

0.1 一句话

RoboTTT = 机器人基础模型 + 会在推理时做梯度更新的“小型记忆网络”。

它不把几分钟的历史帧全部保存在 KV Cache 中,而是把历史不断压进一组固定大小的 快权重(fast weights);下一步决策时,再用当前输入去查询这组快权重。

flowchart LRA["连续视觉、语言、关节状态、动作"] --> B["TTT:把经历写入快权重"]B --> C["固定大小的参数化记忆 W_t"]C --> D["当前输入查询记忆"]D --> E["生成下一段动作"]E --> A

0.2 它解决的不是“看不清”,而是“记不住、不会用、用不起”

flowchart TDQ["怎样让机器人利用几分钟的细粒度视觉—动作历史?"]Q --> C1["容量:历史太长,短窗口装不下"]Q --> C2["利用:存下历史,不代表模型会提取有用信息"]Q --> C3["速度:全历史注意力的延迟随历史增长"]C1 --> S["RoboTTT:用快权重充当循环状态"]C2 --> SC3 --> SS --> R1["8K 时间步上下文"]S --> R2["单个人类视频的一次模仿"]S --> R3["执行中失败恢复"]S --> R4["长流程阶段跟踪与扰动恢复"]

0.3 全方法只有四块

flowchart TBA["① 架构:在 GR00T 的 16 个 DiT 层中加入 TTT MLP"]B["② 记忆:每步先用 K→V 自监督损失更新快权重,再用 Q 读取"]C["③ 长序列训练:Sequence Action Forcing + TBPTT"]D["④ 上下文学习:屏蔽部分动作损失,只让它们负责写记忆"]A --> B --> C --> DD --> E1["人类视频作为纯上下文"]D --> E2["失败动作作为上下文,人类纠正作为监督"]

最重要的直觉:慢权重像老师傅多年形成的固定手艺;快权重像当前工位上的可擦写作业本。机器人不会每一步重看全部监控录像,而是边做边改这本作业本。


1. 为什么普通机器人策略需要长上下文

1.1 一个单帧无法回答的问题

假设机器人此刻看到“钻头贴近螺丝”。只看当前画面,它无法确定:

  • 这是第一次对准,还是前两次已经钻偏?
  • 屋顶是否已经装好,还是被人刚刚拿走?
  • 该继续拧,还是退回、抬臂、重新对齐?
  • 在十阶段任务中,目前究竟做到第几阶段?
flowchart LRO["当前画面:钻头靠近螺丝"] --> A{"缺少历史时存在状态混叠"}A --> X1["可能:尚未开始拧"]A --> X2["可能:刚刚拧偏"]A --> X3["可能:已经拧完"]A --> X4["可能:零件刚被外力移除"]H["过去的观察和动作"] --> B["消除歧义"]B --> Y["选择正确动作:继续、重试或退回阶段"]

论文把机器人轨迹写成:

\[\xi = \{(o_t,q_t,A_t)\}_{t=1}^{T} \]

其中:

符号 含义
\(o_t\) \(t\) 个时刻的图像观察
\(q_t\) 本体状态,例如双臂关节与夹爪状态
\(A_t=[a_t,\ldots,a_{t+H-1}]\) 从当前时刻开始的 \(H\) 步动作块
\(\xi_{<t}\) 当前时刻之前的全部视觉—动作历史
\(l\) 整条轨迹共享的语言指令;论文在简化定义时暂时省略,训练公式中重新加入

目标策略是:

\[\pi(A_t\mid \xi_{<t},o_t,q_t) \]

也就是:当前动作不仅由当前画面决定,还要由此前发生过什么决定。

1.2 8K 到底有多长

论文部署频率为 30 Hz,因此可以近似换算:

flowchart LRA["128 步"] --> A1["约 4.3 秒"]B["1K 步"] --> B1["约 33 秒"]C["8K 步"] --> C1["约 273 秒 ≈ 4.55 分钟"]

这与论文的表述一致:1K 约半分钟,8K 超过四分钟、约五分钟。

这里换算的是原始控制时间覆盖范围。架构图又以 \(t=1,1+H,\ldots\) 表示动作块决策,并把末态画成 \(W_{T/H}\),暗示一次快权重更新可能对应一个 \(H\) 步动作块,而非每个 30 Hz 低层控制点都更新一次。正文没有完全统一这两个粒度,因此不能把“8K 控制时间步”武断等同为“8K 次快权重梯度更新”。

1.3 为什么不用其他记忆方案

方案 像什么 历史表示 每步成本是否随历史增长 主要问题
单步 / 短窗口 VLA 只看眼前 当前帧或少量帧 很快忘记阶段、失败和演示
全历史 Transformer 每步重看录像 全部历史 token / KV 历史越长,注意力读取越慢、显存越大
普通 RNN / LSTM 一张小便签 一个向量状态 固定向量容量有限,长序列扩展性较弱
外部语义记忆 一份任务清单 关键帧、语言、事件摘要 取决于实现 容易丢失细粒度视觉—动作信息
RoboTTT 可擦写的“肌肉记忆” 小网络的参数 \(W_t\) 相对历史长度恒定 是有损、不可解释的学习式压缩;更新本身仍有计算成本
flowchart TBH["越来越长的历史"]H --> T["全历史注意力:保存并反复读取全部历史"]H --> R["RNN:压成向量 h_t"]H --> M["RoboTTT:压进小网络参数 W_t"]T --> TC["信息丰富,但每步读取范围增长"]R --> RC["固定成本,但状态容量较小"]M --> MC["固定大小、较高容量、由梯度下降更新"]

准确理解“恒定延迟”:它指单步推理成本不随已经看过的历史长度增长,并不表示加入 TTT 后没有额外计算,也不表示完整 rollout 的总耗时是常数。


2. 核心:快权重如何把历史写进参数

2.1 慢权重与快权重

flowchart LRsubgraph Slow["慢权重:通用能力"]S1["VLM、DiT、Q/K/V 投影、W_0、门控等"]S2["训练时更新"]S3["部署时冻结"]endsubgraph Fast["快权重:当前 rollout 的临时记忆"]F1["每个 TTT 层中的小型 MLP 参数 W_t"]F2["训练时也会沿序列更新"]F3["部署时每次动作块决策继续更新"]F4["新 rollout 从学到的 W_0 重新开始"]endSlow -->|"决定怎样写、怎样读"| Fast

这里的“测试时训练”不是把整个 GR00T 模型在线微调:

  • 冻结的是庞大的慢权重;
  • 在线变化的是专门设计的小型快模型;
  • 快权重充当循环状态,而非永久知识;
  • 更新所需的目标来自当前 token 自身,不需要测试时动作标签或人工奖励。

实际模型有 16 个 TTT 层,所以文中为简洁写成的 \(W_t\),应理解为“各层快权重状态的集合”,不是全模型共用一个矩阵。

2.2 一次 TTT 操作:先写,再读

输入 token \(X_t\) 经过三组可学习投影,得到:

\[Q_t=X_t\theta_Q,\qquad K_t=X_t\theta_K,\qquad V_t=X_t\theta_V \]

快模型记为 \(f_W:\mathbb{R}^d\rightarrow\mathbb{R}^d\)。论文实际使用两层 GeLU MLP。

第一步:写入

让快模型学会把 \(K_t\) 映射到 \(V_t\)

\[\mathcal L_{\mathrm{FW}} =\left\|f_{W_{t-1}}(K_t)-V_t\right\|^2 \]

然后做一步梯度下降:

\[\boxed{ W_t=W_{t-1}-\eta\nabla_W \mathcal L_{\mathrm{FW}} \left(f_{W_{t-1}}(K_t),V_t\right) } \]

第二步:读取

更新后的快权重处理查询 \(Q_t\)

\[\boxed{O_t=f_{W_t}(Q_t)} \]

sequenceDiagramparticipant X as 当前 token X_tparticipant P as 可学习 Q/K/V 投影participant W as 快模型 f_Wparticipant O as TTT 输出X->>P: 生成 Q_t、K_t、V_tP->>W: K_t 与 V_tW->>W: 计算 K→V 自监督误差W->>W: 梯度下降,W_{t-1} → W_tP->>W: 用 Q_t 查询W->>O: O_t = f_{W_t}(Q_t)

一句话概括:

K_t 决定“用什么地址写”
V_t 决定“写入什么内容”
Q_t 决定“此刻想取回什么”
W_t 是已经被整段历史塑形过的参数化记忆

2.3 为什么这不需要测试时标签

flowchart LRX["当前内部 token"] --> K["投影得到 K_t"]X --> V["投影得到 V_t"]K --> L["自监督目标:f_W(K_t) 接近 V_t"]V --> LL --> U["更新快权重"]Y["真实机器人动作标签"] -. "测试时不需要" .-> UR["环境奖励"] -. "测试时不需要" .-> U

关键不在这个 MSE 本身多聪明,而在于 \(\theta_Q,\theta_K,\theta_V\)、学习率和初始快权重 \(W_0\) 都由外层机器人动作任务反向塑造。外层训练会逐渐学到:

  • 什么信息值得写入;
  • 用什么键组织信息;
  • 之后该如何查询;
  • 更新多大一步;
  • 哪些重复内容应被覆盖或忽略。

2.4 一个极简数值例子

为了看清“梯度就是记忆状态转移”,先把真实的两层 MLP 简化成标量模型 \(f_W(x)=Wx\)

设:

\[W_0=0,\quad K=2,\quad V=4,\quad \eta=0.1 \]

则:

\[\mathcal L=(WK-V)^2 \]

\[\frac{\partial\mathcal L}{\partial W} =2(WK-V)K =2(0-4)\times 2=-16 \]

\[W_1=0-0.1\times(-16)=1.6 \]

若当前查询 \(Q=1.5\),则:

\[O=f_{W_1}(Q)=1.6\times1.5=2.4 \]

flowchart LRA["初始 W_0 = 0"] --> B["看到关联 K=2 → V=4"]B --> C["梯度 = -16"]C --> D["更新后 W_1 = 1.6"]D --> E["查询 Q=1.5"]E --> F["输出 O=2.4"]

这个玩具例子只演示机制。真实 RoboTTT 中:

  • \(W\) 是两层 MLP 的整组参数;
  • 每个 DiT 层都有自己的 TTT 层;
  • 一条轨迹会连续进行成千上万次更新;
  • 外层动作损失会元学习整个写入—读取过程。

2.5 RoboTTT 也可以看成一种 RNN

普通 RNN:

\[h_t=g_\theta(h_{t-1},x_t) \]

RoboTTT:

\[W_t=W_{t-1}-\eta\nabla_W\mathcal L_{\mathrm{FW}}(x_t;W_{t-1}) \]

flowchart LRsubgraph RNN["普通 RNN"]H0["向量 h_{t-1}"] --> G["固定状态转移网络"] --> H1["向量 h_t"]endsubgraph TTT["RoboTTT"]W0["参数 W_{t-1}"] --> GD["当前 token 定义的梯度更新"] --> W1["参数 W_t"]end

差别是:RoboTTT 的循环状态不是一个激活向量,而是一个小网络的参数,因此容量和非线性表达能力更强。


3. RoboTTT 架构:帧内用 Attention,跨时间用 TTT

3.1 骨干

论文只在一个具体骨干上完成实证:GR00T N1.7

  • VLM 骨干:Eagle;
  • 动作头:Diffusion Transformer(DiT),使用 flow matching 生成连续动作;
  • DiT 共 16 层;
  • 每个 DiT 层都加入一个 TTT 层;
  • 每个 TTT 快模型是两层 GeLU MLP;
  • 原 DiT 报告为 538M 参数,加入 TTT 后报告约 690M;
  • 每个 TTT 层约增加 10M 参数。

论文称该插入方式原则上适用于其他 VLA 骨干,但实验只验证了 GR00T N1.7。

3.2 每个时刻有哪些 token

\(t\) 个时刻进入 DiT 的信息为:

\[[R_t,\Phi_t,q_t,\widetilde A_t] \]

token 来源 作用
\(\Phi_t\) VLM 对语言与图像的编码 提供视觉—语言语义
\(q_t\) 本体状态编码器 提供关节、夹爪等机器人状态
\(\widetilde A_t=A_t^{\tau}\) 加噪后的动作块 flow matching 的动作生成输入
\(R_t\) 每个时刻加入的 16 个可学习 register token 汇聚当前视觉—语言信息,并作为跨时间的紧凑载体
flowchart LRI["语言指令 + 多相机图像 o_t"] --> VLM["VLM / Eagle"]VLM --> PHI["视觉—语言 token Φ_t"]Q["本体状态 q_t"] --> SE["状态编码器"]SE --> QT["状态 token"]A["真实动作 A_t + 噪声 ε + 流时间 τ_t"] --> AE["动作编码器"]AE --> AT["加噪动作 token Ã_t"]R["16 个可学习 register token R_t"] --> ATT["单时刻 Self + Cross Attention"]QT --> ATTAT --> ATTPHI -->|"Cross Attention"| ATT

容易混淆:论文中“16 个 register token”和“16 个 DiT 层”恰好都是 16,但它们是两个独立概念。

3.3 两条轴:当前时刻 vs. 时间历史

Attention 只在一个时刻内部工作:

  • \(R_t,q_t,\widetilde A_t\) 做 self-attention;
  • 它们 cross-attend 到同一时刻的 \(\Phi_t\)

随后将各时刻的较小 token 集按时间拼接:

\[X=[R_1,q_1,\widetilde A_1,\ldots,R_T,q_T,\widetilde A_T] \]

再交给 TTT 层跨时间更新快权重。

flowchart TBsubgraph T1["时刻 1"]A1["R_1, q_1, Ã_1"] --> B1["帧内 Attention"]P1["Φ_1"] --> B1endsubgraph T2["时刻 2"]A2["R_2, q_2, Ã_2"] --> B2["帧内 Attention"]P2["Φ_2"] --> B2endsubgraph TT["……直到时刻 T"]AT["R_T, q_T, Ã_T"] --> BT["帧内 Attention"]PT["Φ_T"] --> BTendB1 --> C["沿时间拼接较小 token 集"]B2 --> CBT --> CC --> D["TTT:跨时刻写入与读取快权重"]

3.4 为什么不把全部视觉 token 直接送进 TTT

视觉—语言 token \(\Phi_t\) 数量大,若全部跨几千时刻做 TTT,会很贵。RoboTTT 使用 register token 做桥梁:

flowchart LRP["大量视觉—语言 token Φ_t"] -->|"同一时刻 cross-attention"| R["16 个 register token R_t"]R -->|"较小的跨时间载体"| T["TTT 层"]T --> W["快权重记忆"]

因此 register token 不是独立的外部记忆;它们先在当前帧中吸收视觉—语言信息,再把紧凑表示交给跨时间 TTT。

3.5 门控:先保护预训练能力

直接加入随机初始化的 TTT 分支,可能冲击原有 GR00T 能力。论文在每个 DiT 层学习一个向量门控 \(\alpha\in\mathbb R^d\),初始值接近 0,具体为 0.001:

\[\boxed{ O=O_{\mathrm{attn}}+\tanh(\alpha)\odot O_{\mathrm{TTT}} } \]

flowchart LRA["Attention 输出 O_attn"] --> ADD["逐元素相加"]A --> T["TTT 分支"]T --> OT["O_TTT"]ALPHA["可学习 α,初始 0.001"] --> TANH["tanh"]OT --> MUL["逐元素相乘"]TANH --> MULMUL --> ADDADD --> O["融合输出 O"]

训练刚开始时 \(\tanh(0.001)\approx0.001\),模型几乎沿用预训练 Attention;随后再按需要逐维放大或抑制 TTT 分支。

这不是两个分支之间的凸插值:Attention 分支系数始终为 1,而且 \(\tanh(\alpha)\) 可以变成负值。门控只缩放 TTT 输出贡献,不等于停止快权重更新。

3.6 一层中的完整数据流

flowchart LRX["当前时刻 token"] --> ATT["Self + Cross Attention"]ATT --> OA["O_attn"]OA --> TTT["TTT:K→V 更新 W,再用 Q 读取"]TTT --> G["tanh 门控"]OA --> ADD["残差相加"]G --> ADDADD --> NEXT["下一 DiT 层 / 动作预测"]

4. 训练全景:内层写记忆,外层教它怎样写

4.1 两层学习

RoboTTT 同时存在两种优化:

flowchart TBsubgraph Inner["内层:沿一条轨迹快速更新"]I1["当前 token 产生 K、V"] --> I2["最小化 L_FW"]I2 --> I3["W_{t-1} → W_t"]endsubgraph Outer["外层:跨训练数据慢速优化"]O1["动作 flow-matching 损失"] --> O2["更新 VLM/DiT 或新增层、Q/K/V 投影、门控、W_0、内层学习率"]O2 --> O3["学会更有用的记忆更新动力学"]endInner -->|"动作预测质量"| OuterOuter -->|"元学习怎样写与读"| Inner

内层的梯度更新本身被放在外层计算图里,所以外层会出现“梯度的梯度”。这使初始快权重 \(W_0\) 和写入规则能够针对机器人动作任务被元学习。

4.2 训练样本

数据集:

\[\mathcal D=\{\xi^{(i)}\}_{i=1}^{N} \]

每条轨迹:

\[\xi=\{(l,o_t,q_t,A_t)\}_{t=1}^{T} \]

一个训练序列可以是:

  • 一条完整轨迹;或
  • 一条连续子轨迹;
  • 长度不超过当前设定的最大上下文。

每条新序列从学到的 \(W_0\) 开始,快权重沿序列持续传播。

4.3 外层动作目标:flow matching

对真实动作块 \(A_t\) 和高斯噪声 \(\epsilon\sim\mathcal N(0,I)\),构造:

\[A_t^{\tau_t}=\tau_t A_t+(1-\tau_t)\epsilon \]

含义:

flowchart LRN["τ=0:纯噪声 ε"] --> M["0<τ<1:噪声与动作的线性混合"] --> A["τ=1:真实动作 A"]

沿这条直线路径的速度是:

\[A_t-\epsilon \]

因此 DiT 速度场 \(v_\theta\) 的每步损失为:

\[\ell_t= \mathbb E_{\tau_t,\epsilon} \left[ \left\| v_\theta(\Phi_t,A_t^{\tau_t},q_t;W_{t-1}) -(A_t-\epsilon) \right\|^2 \right] \]

整段序列取平均:

\[\boxed{ \mathcal L_{\mathrm{fm}}(\xi;W_0) =\frac1T\sum_{t=1}^{T}\ell_t } \]

公式把 \(W_{t-1}\) 写成进入第 \(t\) 步 TTT 层的状态;该步内部仍然执行“更新成 \(W_t\),再读取”的操作,并不与前面的 update-then-apply 冲突。

4.4 Sequence Action Forcing:一条序列里混合难度

普通做法可能为整条序列共享一个 \(\tau\)

flowchart LRS1["整条序列共享 τ=0.08"] --> H1["所有动作块几乎都是噪声:整段都很难"]S2["整条序列共享 τ=0.93"] --> H2["所有动作块几乎都是真实动作:整段都很容易"]H1 --> U["批次难度剧烈波动,长序列训练不稳定"]H2 --> U

RoboTTT 对每个动作块独立采样 \(\tau_t\)

\[\tau_t=s(1-u_t),\qquad u_t\sim\mathrm{Beta}(1.5,1),\qquad s=0.999 \]

flowchart LRA1["A_1:τ_1=0.12,难"] --> M["同一训练序列"]A2["A_2:τ_2=0.81,易"] --> MA3["A_3:τ_3=0.47,中"] --> MA4["A_4:τ_4=0.95,很易"] --> MM --> B["每段序列同时包含多种去噪难度"]B --> C["训练更稳定"]

这就是论文所说的 Sequence Action Forcing

防误解:这里的名字很像 teacher forcing,但论文给出的核心定义是“每个动作块独立采样 flow-matching 噪声等级”,不是把模型输出强行替换为真实动作历史。

消融显示:去掉它后,动作不准确到几乎无法推进任务,是整个方法中不可缺少的训练设计。

4.5 TBPTT:状态过河,梯度不过河

完整 BPTT 必须保存全部 \(T\) 步激活,显存随序列长度增长。RoboTTT 把长序列切成短段:

flowchart LRW0["W_0"] --> S1["段 1:正常反向传播"]S1 --> W1["段末快权重"]W1 --> D1["stop_gradient"]D1 --> S2["段 2:正常反向传播"]S2 --> W2["段末快权重"]W2 --> D2["stop_gradient"]D2 --> S3["段 3:正常反向传播"]S3 --> WT["最终快权重"]

两件事同时成立:

  1. 快权重数值继续传递:段 2 仍然继承段 1 写下的内容,因此 TTT 的上下文没有被重置;
  2. 跨段梯度被截断:段 2 不再反向追溯段 1 的全部计算图,因此显存由段长决定,而非总序列长决定。
flowchart TBA["完整序列长度 T"] --> C1["计算量:仍随 T 增长"]A --> C2["状态覆盖范围:仍可贯穿 T"]B["TBPTT 段长 S"] --> M["训练激活显存:主要由 S 决定"]

特殊点:\(W_0\) 只通过第一段收到梯度,因为进入后续段的快权重已经 detach;其他慢参数仍可从各段内部的局部损失学习。

论文据此说固定显存下可以训练任意长的上下文。更精确地讲:内存不必随总长度增长,但总计算量和数据处理时间仍会随总长度增长;论文实证上限是 8K。

4.6 长序列训练伪代码

下面是忠于论文机制的概念伪代码;具体工程中的并行 mini-batch 和优化器调度可能不同。

算法:RoboTTT 长序列训练输入:轨迹 ξ={(l,o_t,q_t,A_t)}_{t=1..T}
参数:慢权重 θ、可学习快权重初值 W_0、TBPTT 段长 S1. W ← W_0
2. 清空慢权重梯度3. 将轨迹按连续时间切成若干段,每段最多 S 步
4. 对每个段 segment 依次执行:segment_loss ← 0对 segment 中每个时刻 t:# Sequence Action Forcing:每个动作块独立采样难度采样 u_t ~ Beta(1.5, 1)τ_t ← 0.999 × (1-u_t)采样 ε_t ~ Normal(0, I)A_t^τ ← τ_t A_t + (1-τ_t) ε_t# 编码当前语言、图像、本体状态和加噪动作构造当前时刻 token X_t对每个 TTT 层 j:Q_t^j, K_t^j, V_t^j ← 可学习投影(X_t^j)# 内层自监督写入;不需要动作标签L_FW^j ← ||f_{W^j}(K_t^j)-V_t^j||²W^j ← W^j - η_j ∇_{W^j} L_FW^j# 用更新后的快权重读取O_TTT^j ← f_{W^j}(Q_t^j)X_t^j ← O_attn^j + tanh(α_j) ⊙ O_TTT^j# 外层动作监督预测速度 ← v_θ(Φ_t, A_t^τ, q_t; W)ℓ_t ← ||预测速度 - (A_t-ε_t)||²segment_loss ← segment_loss + mask_t × ℓ_t对该段的平均 segment_loss 反向传播并累计慢权重梯度# TBPTT:保留记忆数值,但切断跨段计算图W ← stop_gradient(W)5. 用累计的外层梯度更新慢权重 θ 与可学习初值 W_0

mask_t 在普通轨迹上为 1;在人类视频或 DAgger Distillation 中会选择性变为 0,后文详解。

论文没有说明屏蔽后的动作损失究竟按总时间步数、有效纠正步数还是 mini-batch 方式重新归一化;伪代码只表达“哪些位置产生监督”,不补造归一化规则。



5. 推理:机器人每一步究竟做什么

5.1 rollout 级生命周期

stateDiagram-v2[*] --> Reset: 新 rollout 开始Reset --> Observe: 所有 TTT 层载入学到的 W_0Observe --> Update: 每次策略调用时编码观察并更新快权重Update --> Act: 用更新后的快权重生成动作块Act --> Observe: 执行动作,获得下一观察Act --> End: 任务结束或达到终止条件End --> [*]

快权重不会永久写回慢权重。下一条独立 rollout 重新从 \(W_0\) 开始。

5.2 单步时序

sequenceDiagramparticipant Env as 真实环境participant Enc as VLM / 状态编码器participant Attn as DiT 帧内 Attentionparticipant TTT as TTT 快模型participant Head as Flow-matching 动作头Env->>Enc: 图像 o_t、本体状态 q_t、语言 lEnc->>Attn: Φ_t、q_t、register token、动作生成 tokenAttn->>TTT: 当前时刻紧凑表示TTT->>TTT: K→V 损失,W_{t-1} 更新为 W_tTTT->>Head: 用 Q 查询 W_t 后的表示Head->>Head: k 步去噪 / ODE 积分Head->>Env: 执行动作块 A_tNote over TTT: W_t 保留到下一次动作块决策

5.3 推理伪代码

算法:RoboTTT 在线推理输入:语言指令 l、环境、学到的慢权重 θ、快权重初值 W_01. 对每个 TTT 层 j:W^j ← W_0^j2. 当 rollout 未结束时:读取当前多相机图像 o_t 与本体状态 q_tΦ_t ← VLM(l, o_t)# 由 flow matching 从噪声逐步得到动作块初始化动作变量为高斯噪声# 概念上,每次策略调用 / 动作块决策吸收当前上下文构造当前 token,并对每个 TTT 层:Q_t^j, K_t^j, V_t^j ← 投影(当前层 token)L_FW^j ← ||f_{W^j}(K_t^j)-V_t^j||²W^j ← W^j - η_j ∇_{W^j}L_FW^j读取 O_TTT^j ← f_{W^j}(Q_t^j)使用更新后的快权重完成 k 步 flow-matching 去噪得到 H 步动作块 A_t=[a_t,...,a_{t+H-1}]执行动作块,并把当前 W 传到下一时刻3. rollout 结束;丢弃当前 W

论文明确说明“更新快权重、生成 \(H\) 步动作块,并用 \(k\) 步去噪”;架构图按 \(t,t+H\) 推进,并标注一次 inference 使用一个 mini-batch,但没有公开 \(H\)\(k\),也没有把 \(k\) 次网络调用与快权重 commit 的精确工程调度写清。上面是机制级伪代码,不应被当作逐行复现代码。

5.4 复杂度直觉

令已经经历的历史长度为 \(t\),快权重参数量为 \(P_{\mathrm{fast}}\)

机制 \(t\) 步需要保留的历史状态 \(t\) 步历史读取范围
全历史 Attention + KV Cache \(t\) 增长 \(t\) 增长
普通 RNN 固定大小 固定大小
RoboTTT 固定大小的 \(W_t\) 固定大小,但需计算快模型梯度
flowchart LRT["历史从 1K 增长到 8K"] --> A["全历史 Attention:每步要读更长 KV"]T --> R["RoboTTT:仍只携带当前 W_t"]R --> C["单步成本不依赖已经过去多少步"]

6. 关键技巧:把“上下文写入”和“动作监督”分开

6.1 两种损失不是一回事

每个时刻可能涉及:

  1. 快权重损失 \(\mathcal L_{\mathrm{FW}}\):负责把当前 token 写进记忆;
  2. 动作 flow-matching 损失 \(\ell_t\):负责教策略此刻应该输出什么动作。

RoboTTT 可以屏蔽第 2 种而保留第 1 种:

flowchart LRX["某个上下文时刻"] --> F["L_FW:开启"]X --> A["动作 loss:可关闭"]F --> W["仍然更新快权重"]A -. "mask=0" .-> N["不要求模仿该时刻动作"]

这使不同来源的数据可以承担不同角色:

数据 是否写入快权重 是否作为动作监督
普通机器人专家轨迹
人类视频演示片段
DAgger 中机器人做错的动作
DAgger 中人类纠正动作

这张表是理解 one-shot imitation 和 DAgger Distillation 的总钥匙。


7. 能力一:看一个人类视频,再完成未见配置

7.1 训练数据怎样拼

对同一个 Circuit 配置,取:

  • 一段人类手工装配视频 \(\xi^{\mathrm{video}}\)
  • 一条机器人完成该配置的轨迹 \(\xi^{\mathrm{robot}}\)

把二者前后拼成一个长序列:

flowchart LRV1["人类视频:观察配置与装配顺序"] --> V2["持续更新快权重"]V2 --> R1["机器人轨迹:同一目标配置"]R1 --> R2["继续更新快权重,并计算动作 loss"]M1["视频部分动作 loss = 0"] -.-> V1M2["机器人部分动作 loss = 1"] -.-> R1

视频部分没有机器人动作监督,但会通过 TTT 把“用了哪些零件、什么顺序、目标布局”压进快权重。机器人部分的动作损失再教模型:如何读取刚才的演示信息,并转化成机器人动作。

7.2 测试时怎样做

sequenceDiagramparticipant Human as 人类participant TTT as RoboTTT 快权重participant Scene as 工作台participant Robot as 机器人Human->>Scene: 演示一个未见 Circuit 配置Scene->>TTT: 视频帧持续写入配置与顺序Scene->>Scene: 场景重置Note over TTT: 快权重不重置,保留演示上下文TTT->>Robot: 当前观察查询演示记忆Robot->>Scene: 按演示选择零件并按顺序装配

实验刻意把所有配置的语言提示都设为同一句 “assemble circuit”,所以目标配置无法从语言偷看,只能来自视频上下文。

7.3 具体数据与结果

  • Circuit 约有 80 种配置;
  • 训练 20 种,测试剩余 60 种;
  • 每个训练配置额外收集 5–20 段人类视频,初始布局不同;
  • 拍摄人类视频时机器人保持不动,由人手完成装配;
  • 测试每次给一个未见配置的人类视频;
  • RoboTTT:任务完成分数 65%,完整成功 6/10;
  • GDN:任务完成分数 33%,完整成功 0/10。
flowchart LRR["RoboTTT"] --> RS["65% 完成分数;6/10 完整成功"]G["GDN"] --> GS["33% 完成分数;0/10 完整成功"]

7.4 它证明了什么,又没有证明什么

flowchart TBP["论文证明"] --> P1["能从一个人类视频识别未见的 Circuit 目标配置"]P --> P2["长上下文可跨演示阶段与执行阶段传递任务信息"]N["论文没有证明"] --> N1["任意开放世界新技能都能一看即会"]N --> N2["不需要相关训练配置"]N --> N3["成功率已经接近可靠部署:实际为 6/10"]

8. 能力二:DAgger Distillation,让失败成为上下文

8.1 先回顾普通 DAgger

机器人自己运行,进入它真实会遇到的状态;当它做错时,人类接管并给出纠正动作。得到一条交错轨迹:

\[\xi^{\mathrm{DAgger}} =\{(l,o_t,q_t,A_t)\}_{t=1}^{T},\qquad A_t\in\{A_t^{\mathrm R},A_t^{\mathrm H}\} \]

其中 \(A_t^{\mathrm R}\) 是机器人动作,\(A_t^{\mathrm H}\) 是人类纠正。

普通 DAgger 通常只把人类纠正当监督目标,错误动作被丢弃。

flowchart LRR1["机器人动作"] --> R2["发生偏差"]R2 --> H["人类纠正"]H --> D["普通 DAgger 数据"]D --> K["只保留纠正动作作为训练目标"]R1 -. "通常丢弃" .-> X["错误动作与错误演化过程"]

8.2 RoboTTT 的不对称用法

DAgger Distillation 认为:错误动作虽然不值得模仿,却非常适合解释“这个纠正是在纠正什么”。

flowchart LRsubgraph Context["完整交互历史:全部写入快权重"]A1["机器人正常动作"] --> A2["机器人错误动作"] --> A3["人类纠正"] --> A4["后续动作"]endA1 --> W["更新 W"]A2 --> WA3 --> WA4 --> WA1 -. "动作 loss=0" .-> L["外层监督"]A2 -. "动作 loss=0" .-> LA3 -->|"动作 loss=1"| LA4 -. "若非人类纠正则为 0" .-> L

因此训练信号是:

失败和此前动作:告诉快权重“发生了什么”
人类纠正:告诉外层策略“看到这种历史后应该怎么修”

这与 Algorithm Distillation 的思想一致:被蒸馏的不是某个孤立正确动作,而是从失败到改进的过程

8.3 DAgger Distillation 伪代码

算法:构造并训练 DAgger Distillation 序列输入:带人工接管标记的 DAgger 轨迹每步 action_source_t ∈ {ROBOT, HUMAN}1. W ← W_0
2. 对轨迹中每个时刻 t:# 无论动作来自谁,完整经历都进入 TTT 记忆用 (l,o_t,q_t,A_t) 更新快权重 W如果 action_source_t == HUMAN:mask_t ← 1# 只在人工纠正处教模型输出正确动作计算 flow-matching 动作损失 ℓ_t否则:mask_t ← 0# 机器人动作只解释失败过程,不能作为模仿目标不计算动作监督3. 最小化 Σ_t mask_t × ℓ_t
4. 部署时不再需要人工;模型用自身 rollout 历史更新 W 并尝试恢复

8.4 一个直观例子:钻头连续两次没对准

flowchart LRA["第 1 次:钻头错过螺丝"] --> B["快权重吸收错误位置与已执行动作"]B --> C["抬臂、重新对齐"]C --> D["第 2 次:更近但仍未命中"]D --> E["快权重继续吸收新偏差"]E --> F["再次调整"]F --> G["第 3 次成功"]

训练数据中的人类接管教会了“什么失败历史对应什么纠正”。部署时没有人类,也没有在线奖励;模型只是利用已经学到的更新动力学,从自己的历史中触发类似修正。

8.5 实验怎样做

  • 在 Pup Go Car 上收集 100 条 DAgger 轨迹;
  • 50 条以 RoboTTT 为基础策略收集;
  • 50 条以 GR00T N1.7 为基础策略收集;
  • 合并后供所有方法训练,确保数据相同;
  • 普通 DAgger:只监督人类纠正;
  • DAgger Distillation:全部动作写上下文,只监督人类纠正。

结果:

flowchart LRB1["RoboTTT 训练前"] -->|"DAgger Distillation:+36%"| A1["RoboTTT 改进后"]B2["GDN 训练前"] -->|"DAgger Distillation:+29%"| A2["GDN 改进后"]B3["四种方法平均"] -->|"普通 DAgger:约 +9%"| A3["只学人类纠正"]B4["两个序列模型平均"] -->|"DAgger Distillation:约 +33%"| A4["利用完整失败上下文"]
方法 DAgger 前 仅人类纠正 把完整轨迹都当动作目标 DAgger Distillation
RoboTTT 65.50% 72.50% 89.25%
GDN 44.00% 51.00% 56.75%
GR00T N1.7 52.75% 57.00% 57.00% 不适用
GR00T N1.7 Hist. 38.75% 39.50% 不适用

把机器人错误动作也当监督目标并无帮助:GR00T 用完整轨迹训练和只用纠正训练都得到 57%。错误动作的价值在于上下文,不在于模仿。

防误解:这不是机器人在部署时凭空“自我进化”。恢复能力依赖预先收集的人类纠正轨迹,以及外层训练对 failure-to-correction 映射的蒸馏。


9. 第三个上下文用法:同一 episode 内的外力扰动恢复

在 Pup Go Car 中,机器人刚装好零件后,人为把它拿走:

flowchart LRA["机器人装好黄色车顶"] --> B["人类突然移除车顶"]B --> C{"策略是否记得此前已经装过?"}C -->|"短上下文"| D["可能继续下一阶段"]C -->|"长上下文"| E["识别进度被回滚"]E --> F["返回车顶安装阶段并重装"]

论文额外收集 30 分钟扰动数据,并与任务数据共同训练,因此这不是零样本扰动恢复。

方法 车顶被移除后成功重装 轮胎被移除后成功重装
RoboTTT 15/20 18/20
GR00T N1.7 10/20 11/20
GR00T N1.7 Hist. 3/20 5/20
GDN 13/20 18/20

结论应当读成:有针对性训练时,长时序状态更容易把当前观察解释成“任务进度被外力回滚”,并返回正确阶段。


10. 从头跑一遍:Circuit 一次视频模仿示例

下面用一个虚构但与论文设置一致的配置走完全部机制:人类先演示“先插红灯,再插开关并打开”。快权重内部不可解释,下表中的“可能保留内容”只是功能性直觉,不是论文声称能直接读出的文字记忆。

flowchart TBV1["演示帧:人类拿起红灯"] --> V2["演示帧:红灯插入左侧"]V2 --> V3["演示帧:开关插入右侧并打开"]V3 --> RS["场景重置;W 不重置"]RS --> R1["机器人选择红灯"]R1 --> R2["机器人插入左侧"]R2 --> R3["机器人选择开关"]R3 --> R4["机器人插入右侧并打开"]
阶段 当前输入 TTT 快权重的作用 动作监督
看人类拿红灯 视频帧、语言“assemble circuit” 写入目标零件线索 屏蔽
看红灯位置 视频帧 写入空间位置与第一阶段 屏蔽
看开关及顺序 视频帧 写入第二零件、顺序、需开启 屏蔽
场景重置 新工作台画面 读取此前配置,而不是把 reset 当遗忘
机器人执行 当前图像、本体状态、过去动作 边读取演示,边写入自身进度 训练时开启;测试时无标签
sequenceDiagramparticipant Slow as 慢权重participant Fast as 快权重 Wparticipant Video as 人类视频participant Robot as 机器人执行Slow->>Fast: 提供学到的 W_0 与写入规则Video->>Fast: 无动作监督地连续更新 WFast->>Robot: 提供配置和顺序相关上下文Robot->>Fast: 自身观察与动作继续更新 WFast->>Robot: 跟踪当前执行进度

11. 实验设置:论文到底在哪些任务上验证

11.1 硬件与观察

  • 机器人:YAM 双臂桌面机器人;
  • 相机:4 个 RealSense D405,分别位于顶部、底部、左腕、右腕;
  • 图像:480p RGB;
  • 部署 GPU:NVIDIA RTX 5090;
  • 控制频率:30 Hz。
flowchart TBTOP["顶部相机"] --> POLICY["RoboTTT"]BOTTOM["底部相机"] --> POLICYLEFT["左腕相机"] --> POLICYRIGHT["右腕相机"] --> POLICYPROP["双臂本体状态"] --> POLICYLANG["语言指令"] --> POLICYPOLICY --> ACT["双臂动作块"]

11.2 三个任务

flowchart LRP["Pup Go Car\n平均约 2 分钟\n8 小时数据"] --> P1["装车顶、拧螺丝、交接钻头、翻车、装轮胎"]C["Circuit\n平均约 1 分钟\n6 小时数据"] --> C1["2–3 个电路元件;约 80 种配置;顺序可变"]G["Gear Bot\n平均约 5 分钟\n5 小时数据"] --> G1["十阶段;双面齿轮和轮子、头部、遥控器"]

Pup Go Car 流程

flowchart LRA["拿车顶"] --> B["放置并对准螺丝"] --> C["拿钻头并拧紧"] --> D["钻头交右手"]D --> E["翻转车身"] --> F["拿轮胎并插入"] --> G["再次拿钻头拧紧"] --> H["钻头交左手"]
Pup Go Car 完整评分细则
  • 0.05:拿起车顶;
  • 0.10:把车顶放到车身;
  • 0.25:车顶螺丝正确插入车身;
  • 0.30:拿起钻头;
  • 0.35:钻头尖接触螺丝;
  • 0.45:车顶螺丝完全拧紧;
  • 0.50:把钻头交给右手;
  • 0.55:翻转并稳定车身;
  • 0.60:拿起轮胎;
  • 0.75:轮胎插入车身;
  • 0.80:再次拿起钻头;
  • 0.85:钻头与轮胎螺丝对齐并接触;
  • 0.90:轮胎完全拧紧;
  • 1.00:把钻头交给左手。

轮胎装配最多允许两次尝试。

Gear Bot 流程

flowchart LRA["一面朝上"] --> B["装 1 个齿轮 + 2 个轮子"] --> C["翻面"]C --> D["另一面装 1 个齿轮 + 2 个轮子"] --> E["再次翻转"]E --> F["装红色机器人头"] --> G["拿遥控器并推动摇杆"]

评分:每次车身翻转、每个齿轮或轮子安装、机器人头安装、成功使用遥控器,各加 0.1。

Circuit 流程与评分

可用元件包括红 LED、绿 LED、彩色 LED、灯、马达、导线、按钮和开关。机器人按指定顺序安装 2 或 3 个元件;若有按钮或开关,还必须打开电路。

配置 评分
2 个元件,无按钮/开关 每装一个 +0.5
2 个元件,有按钮/开关 每装一个 +0.33;打开电路 +0.33
3 个元件,无按钮/开关 每装一个 +0.33
3 个元件,有按钮/开关 每装一个 +0.25;打开电路 +0.25

若安装顺序错误,不给部分分。

11.3 基线

方法 上下文 记忆机制
GR00T N1.7 单步 无长时序记忆
GR00T N1.7 Hist. 当前帧 + 1 个历史帧 直接拼接短历史
GDN 长序列 用 Gated DeltaNet 线性复杂度循环状态替代 TTT;层位置、门控和参数量匹配
RoboTTT 长序列 非线性快模型 + 测试时梯度更新

所有方法使用相同下游任务数据;序列模型以 1K 上下文后训练,非序列模型匹配训练计算预算。

11.4 评估协议

  • Pup Go Car:20 次;
  • Circuit:20 次;
  • Gear Bot:10 次,因单次任务很长;
  • Circuit one-shot:10 次;
  • 尽量复现相同初始物体摆放;
  • 指标一:完整成功次数;
  • 指标二:按任务细则计算、归一化到 \([0,1]\) 的完成分数。

12. 主结果:长上下文是否真的有用

12.1 平均完成分数

xychart-betatitle "三项任务平均完成分数"x-axis ["RoboTTT", "GR00T", "GR00T Hist.", "GDN"]y-axis "完成分数(%)" 0 --> 100bar [79, 42, 49, 56]

精确图值如下;正文把核心平均值四舍五入为 79%、42% 和 56%。

方法 Pup Go Car Circuit Gear Bot 三任务平均
RoboTTT 89.25% 78.00% 71.00% 79.42%
GR00T N1.7 57.00% 23.15% 47.00% 42.38%
GR00T N1.7 Hist. 39.50% 54.26% 54.00% 49.25%
GDN 56.75% 52.94% 59.00% 56.23%
  • RoboTTT:平均 79%;
  • 单步 GR00T:42%;
  • 最强基线 GDN:56%;
  • RoboTTT 比单步基线高 87%;
  • 比 GDN 高 41%。

12.2 完整成功次数

方法 Pup Go Car Circuit Gear Bot
RoboTTT 9/20 13/20 2/10
GR00T N1.7 3/20 3/20 0/10
GR00T N1.7 Hist. 0/20 8/20 0/10
GDN 3/20 8/20 0/10
flowchart LRG["Gear Bot:约 5 分钟、10 阶段"] --> R["RoboTTT:2 次完整成功"]G --> B1["GR00T:0"]G --> B2["GR00T Hist.:0"]G --> B3["GDN:0"]

12.3 论文观察到的三种行为优势

flowchart TBR["RoboTTT 的长历史"] --> S1["阶段跟踪:区分视觉上相似的任务阶段"]R --> S2["策略性恢复:钻偏后抬臂、重对齐、重试"]R --> S3["遮挡下精细操作:利用过去看清物体时的信息"]

短历史并不总是有益:Pup Go Car 上,GR00T Hist. 为 39.5%,反而低于无历史 GR00T 的 57%。直接拼历史可能引入伪相关,也可能让训练与部署的时间分布不一致。


13. 最关键的规模化结论:上下文越长,RoboTTT 越强

预训练上下文从 128 步逐渐扩大到 8K,之后所有模型仍在下游任务上以 1K 上下文后训练。

flowchart LRA["128\n30.82%"] --> B["256\n28.97%"] --> C["512\n39.30%"] --> D["1K\n43.90%"] --> E["2K\n54.32%"] --> F["4K\n60.33%"] --> G["8K\n71.50%"]
flowchart TBL["扩大预训练上下文"] --> R["RoboTTT:总体趋势强;从 256 到 8K 单调上升"]L --> G["GDN:上下波动,没有稳定扩展趋势"]R --> M["说明关键不只是输入更长,而是梯度更新式快权重会被更长外层序列塑造"]

明确数字:

  • RoboTTT-1K:43.9%;
  • RoboTTT-8K:71.5%;
  • 8K 比 1K 约高 63%;
  • 最佳短上下文基线:45.6%;
  • 8K 比它高 57%。

完整曲线读数:

预训练上下文 RoboTTT GDN
128 30.82% 1.50%
256 28.97% 17.95%
512 39.30% 40.20%
1K 43.90% 34.62%
2K 54.32% 42.59%
4K 60.33% 35.55%
8K 71.50% 44.32%

两个严谨口径:

  1. 论文正文称 RoboTTT 随上下文“steady”提升,但图中 128→256 实际从 30.82% 小降到 28.97%;严格单调提升是从 256 开始。
  2. 正文称 1K 以下 RoboTTT 仍优于同长度 GDN,但 512 点实际为 39.30% 对 40.20%,GDN 略高 0.90 个百分点。总体扩展趋势仍明显不同,但不应把正文措辞理解成每个点都成立。

摘要写“高 62%”,正文写“高 63%”;由 71.5 和 43.9 计算约为 62.9%,只是舍入差异。

为什么 1K 以下表现不够好?论文给出两点解释:

flowchart LRS["训练只看 ≤1K 步"] --> I["部署任务超过 1K 步"]I --> U1["快权重被更新到训练没见过的步数"]I --> U2["位置编码延伸到训练没见过的位置"]U1 --> P["长 rollout 性能受限"]U2 --> P

上下文缩放曲线采集于 Pup Go Car 的 DAgger 训练之前,不能把这条曲线归因于 DAgger Distillation。


14. 消融:哪些设计真的重要

14.1 快模型要非线性

用线性层替代两层 MLP 后,虽然仍优于单步 GR00T,但比完整 MLP 快模型低 27%。

消融变体(Pup Go Car) 完成分数
完整消融设置:加入 register token 65.50%
加入 action token、尚无 register token 55.50%
仅 state token 45.00%
TTT Linear 48.00%
无 Sequence Action Forcing 约 2%
GR00T + 相同 register token 43.75%

这里完整消融设置的 65.50% 是 DAgger Distillation 之前的 Pup Go Car 模型;主结果中的 89.25% 已包含后续 DAgger Distillation,二者不能直接当成同一训练阶段。

flowchart LRL["线性快模型"] --> C1["能做简单关联压缩"]M["两层 GeLU MLP"] --> C2["能表达更复杂的历史结构"]C1 --> R["低于完整模型 27%"]C2 --> B["完整 RoboTTT"]

14.2 TTT 应该看到过去动作

flowchart LRS["只让 TTT 处理状态 token"] -->|"加入动作 token:+23%"| A["同时知道看到了什么、做过什么"]A -->|"加入 register token:再 +18%"| R["紧凑携带视觉—语言上下文"]

动作 token 很重要,因为环境如何变化取决于机器人刚刚执行了什么;只看状态,较难建模完整动力学。

14.3 register token 不是单独起作用

给普通 GR00T 加相同数量的 register token 并没有帮助。它们的价值来自与 TTT 的配合:先汇聚帧内视觉—语言信息,再交给跨时间记忆。

14.4 Sequence Action Forcing 不可少

去掉独立噪声等级后,Pup Go Car 几乎无法取得有意义进展。它解决的是长序列 flow-matching 训练稳定性,而不是一个可有可无的数据增强。

flowchart TBF["完整 RoboTTT"] --> MLP["非线性 MLP 快模型"]F --> ACT["TTT 处理状态 + 动作 token"]F --> REG["16 个 register token 传递视觉语义"]F --> SAF["每个动作块独立采样 τ_t"]F --> TB["TBPTT 保持状态、截断梯度"]

15. 完整训练与部署配置

15.1 模型配置

项目 论文设置
基础模型 GR00T N1.7
VLM Eagle
动作头 16 层 DiT,flow matching
TTT 插入位置 每个 DiT 层的 self/cross attention 之后
TTT 快模型 两层 MLP + GeLU
register token 每个时刻 16 个
门控 \(\tanh(\alpha)\)\(\alpha\) 初始 0.001
快权重更新器 标准梯度下降
内层学习率 以常数 0.1 为基础,再学习 test-time learning rate
位置编码 RoPE,\(\theta_{\mathrm{rope}}=10000\)
DiT 参数规模 原 538M;加入 TTT 后论文报告约 690M

15.2 预训练

项目 设置
数据 桌面双臂机器人数据 + 第一视角人类视频,偏重长轨迹
更新参数 只训练新增序列层(TTT 或 GDN),冻结 GR00T 其他部分
上下文 逐渐增加到目标长度,例如 RoboTTT-8K 增至 8K
步数 30K
GPU 16 × NVIDIA GB200
每卡 batch(≤4K) 4;全局 64
每卡 batch(>4K) 1;全局 16
优化器 AdamW,weight decay \(1\times10^{-5}\)
学习率计划 Warmup-Stable-Decay
峰值学习率 \(2\times10^{-5}\)

15.3 下游后训练

项目 设置
每个任务上下文 1K
更新参数 全部参数
步数 20K
GPU 8 × NVIDIA GB200
每卡 batch 1
优化器 AdamW,weight decay \(1\times10^{-5}\)
学习率计划 cosine
峰值学习率 \(5\times10^{-5}\)
flowchart LRP["预训练\n长轨迹混合数据\n只训新增序列层\n上下文逐步增至 8K"] --> F["下游后训练\n每任务 1K 上下文\n全参数微调"]F --> D["真实机器人部署\nRTX 5090,30 Hz"]

16. 最容易误解的十件事

16.1 对 / 错速查

flowchart TBsubgraph Correct["正确理解"]C1["快权重是固定大小的参数化循环状态"]C2["测试时只更新专门的小型快模型"]C3["内层更新不需要动作标签"]C4["外层动作损失元学习怎样写与读"]C5["TBPTT 降低激活显存,不消除总计算"]endsubgraph Wrong["错误理解"]W1["保存了可逐帧检索的完整录像"]W2["部署时微调整个 GR00T"]W3["机器人靠在线奖励自行强化学习"]W4["8K 已证明可以无限外推"]W5["one-shot 等于任意新技能一次学会"]end
  1. 快权重不是文字笔记或数据库。 它是有损、分布式、不可直接解释的参数压缩。
  2. TTT 不是完整模型微调。 慢权重部署时冻结。
  3. 测试时不需要动作标签。 内层目标由 \(K_t,V_t\) 自监督构造。
  4. 当前步是先 update 再 apply。 不是先输出再把当前信息写入。
  5. Attention 和 TTT 分工不同。 前者处理单时刻 token 交互,后者处理时间轴。
  6. Sequence Action Forcing 不是传统 teacher forcing。 它是逐动作块独立采样噪声等级。
  7. TBPTT 没有切断上下文本身。 快权重值跨段传递,只切断梯度图。
  8. DAgger Distillation 不是无监督自我进化。 它依赖训练阶段的人类纠正。
  9. 一次视频模仿不是完全陌生技能。 实验是在 Circuit 的未见配置上做组合泛化。
  10. “延迟恒定”只相对历史长度成立。 快权重梯度更新仍有固定额外开销。

17. 局限、证据边界与复现缺口

17.1 作者明确承认的局限

flowchart TBL1["长上下文训练成本更高"] --> F1["未来可用 TNT 等更高效训练技术"]L2["当前 TTT 目标不是机器人专用"] --> F2["可探索 robotics-oriented 自监督目标"]L3["仍无法处理所有部署失败"] --> F3["可结合直接优化任务成功率的强化学习"]

17.2 论文实验证明到哪里

可以说 不应该扩张成
在三个 YAM 双臂装配任务上更强 已对导航、移动操作、开放世界普遍有效
实证上下文上限为 8K 已证明任意长上下文都稳定
Circuit 未见配置 one-shot 为 6/10 任意新技能都能一次视频学会
DAgger 数据后能现场恢复 无人工数据、无训练即可自我进化
原理上可接其他 VLA 已在多种骨干上验证通用性
单步成本不随历史长度增长 比所有短上下文模型绝对更快

17.3 论文没有公开、不能靠猜补齐的细节

以下参数在提供的论文正文与附录中未明确给出:

  • 动作块长度 \(H\)
  • 推理 flow-matching 去噪步数 \(k\)
  • TBPTT 的实际段长;
  • 上下文从短到长的精确 curriculum 日程;
  • TTT 两层 MLP 的精确隐藏维度与每层完整张量形状;
  • 一次策略调用中的 TTT 更新与 \(k\) 次去噪网络调用的精确调度;
  • 原始 30 Hz 控制时间步、动作块决策步与论文记号 \(T\) 之间的精确换算,以及实际快权重更新次数;
  • masked 动作损失的精确归一化分母;
  • 预训练混合数据的完整规模、来源占比和采样权重;
  • 端到端单步延迟、TTT 相对基础模型的延迟增量;
  • 多随机种子方差或置信区间。
flowchart LRP["论文已给:机制、核心公式、主要超参、硬件、结果"] --> R["足以理解方法"]M["未给:H、k、段长、精确调度、数据配比等"] --> X["不足以仅凭论文逐行复现"]

18. 术语表

术语 无痛解释
VLA 视觉—语言—动作模型:看图、读指令、输出机器人动作
VLM 视觉—语言模型,RoboTTT 中负责产生语义 token
DiT Diffusion Transformer,这里是连续动作生成头
Flow Matching 学习从噪声流向真实动作的速度场
Slow Weights 常规模型参数;训练时更新,部署时冻结
Fast Weights TTT 小网络参数;训练和部署时都沿序列快速更新
TTT Test-Time Training;用自监督目标在线更新快权重
\(W_0\) 每条 rollout 起点的、通过外层任务学到的快权重初始化
\(W_t\) 吸收了截至时刻 \(t\) 的上下文后得到的快权重
\(Q,K,V\) 查询、键、值;决定怎样读取、怎样定位、写入什么
Register Token 每时刻 16 个可学习 token,用来汇聚视觉—语言信息并交给 TTT
Sequence Action Forcing 每个动作块独立采样 flow-matching 噪声等级
BPTT 沿整个时间序列反向传播
TBPTT 分段反向传播;状态跨段、梯度截断
DAgger 在策略自己访问到的状态上收集人类纠正
DAgger Distillation 失败动作只作上下文,人类纠正才作监督,蒸馏失败→纠正过程
GDN Gated DeltaNet;论文中的匹配参数量循环记忆基线
状态混叠 当前画面相似,但因历史不同,正确动作其实不同

19. 面试 / 复习版:五个问题讲完整篇论文

Q1:RoboTTT 的核心创新是什么?

把 TTT 快权重嵌入 VLA 的 DiT 动作头,让快权重成为随 rollout 更新的循环状态,以固定大小参数空间压缩长视觉—动作历史。

Q2:快权重怎样更新?

当前 token 投影成 \(Q_t,K_t,V_t\);先最小化 \(\|f_W(K_t)-V_t\|^2\) 做一步梯度下降,再用更新后的 \(f_{W_t}(Q_t)\) 输出上下文表示。

Q3:为什么能训练到 8K?

Sequence Action Forcing 让每个动作块独立采样噪声难度,稳定长序列 flow matching;TBPTT 让快权重跨段传递,但在段边界切断梯度,使显存由段长而非总长度决定。

Q4:怎样从视频或失败中学习?

把动作损失和快权重更新解耦。视频帧、机器人错误动作仍更新快权重,但动作损失被屏蔽;机器人专家动作或 DAgger 人类纠正才提供动作监督。

Q5:最强证据是什么?

8K 预训练上下文达到 71.5%,比 1K 的 43.9% 高约 63%;三任务平均 79%,比单步 GR00T 的 42% 高 87%;在五分钟 Gear Bot 上只有 RoboTTT 出现完整成功;一次视频模仿为 6/10,而 GDN 为 0/10。

flowchart LRI["插入 TTT 层"] --> M["快权重成为长时记忆"]M --> T["SAF + TBPTT 训练到 8K"]T --> C["loss masking 让异构上下文可用"]C --> A1["视频 one-shot"]C --> A2["DAgger 现场恢复"]C --> A3["长任务阶段跟踪"]

20. 最终速查:端到端数据流

flowchart TBDATA["训练轨迹:(语言、图像、本体状态、动作块)"]DATA --> ENC["VLM / 状态 / 动作编码"]ENC --> ATT["每个时刻:Self + Cross Attention"]ATT --> REG["register token 携带视觉—语言摘要"]REG --> TTT["跨时间 TTT:K→V 更新快权重,Q 读取"]TTT --> GATE["tanh 门控,与 Attention 残差融合"]GATE --> FM["Flow-matching 动作速度预测"]FM --> LOSS["逐时刻动作损失;可按数据来源 mask"]SAF["Sequence Action Forcing:τ_t 独立"] --> FMTB["TBPTT:状态跨段、梯度截断"] --> TTTLOSS --> META["外层梯度元学习 W_0、Q/K/V、门控和更新动力学"]META --> DEPLOY["部署:慢权重冻结,W 从 W_0 开始在线更新"]

一句收尾

RoboTTT 真正的新意,不只是“记得更久”,而是把“如何在执行中改写自己的短期行为参数”也作为训练目标学出来。


← 返回列表