经过第 1~19 课,我们已经从最简单的神经网络训练,逐步走到了第一个完整的机器人操作学习模型:
ACT(Action Chunking with Transformers)。
对应论文为 Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware,作者包括 Tony Z. Zhao、Vikash Kumar、Sergey Levine 和 Chelsea Finn,发表于 2023 年。
官方代码:tonyzhaozh/act。
这部分总结要回答三个问题:
ACT 想解决什么?它怎样训练?它又怎样真正驱动机器人?
一、ACT 的核心:不是一次预测一个动作,而是学习一段连续行为
我们最早的 Behavior Cloning(BC)是:
\ \\hat a_t=\\pi_\\theta(o_t) \\
假设机器人要完成一次抓取,需要连续经历:
动作 1
靠近物体
动作 2
下降夹爪
动作 3
闭合夹爪
动作 4
抬起物体
这是便于理解的动作阶段示意;真实机器人一段动作通常包含远多于四个控制时间步。
普通单步 BC 每次只预测当前动作。ACT 则直接输出一段未来动作:
\ \\boxed{ \\hat A_t = \\pi_\\theta(o_t,z) = \[\\hat a_t,\\hat a_{t+1},\\ldots,\\hat a_{t+K-1} } \]
其中:
-
\(o_t\):当前 Observation;
-
\(z\):CVAE 潜变量;
-
\(K\):Action Chunk 长度;
-
\(D_a\):单个 Action 的维度。
如果:
\ B=8,\\quad K=100,\\quad D_a=14 \\
那么一次 Forward 输出:
\ \\boxed{\\hat A:\[8,100,14} \]
即 8 个训练样本,每个样本预测未来 100 个 14 维动作。
这是与原始 ACT 双臂系统的动作表示及 README 示例配置对应的一个例子,不能把 100 和 14 当成所有机器人版本的固定值。
Action Chunking 的意义,是把一段具有时间联系的动作作为整体学习,而不是把每个控制时刻完全孤立地对待。
但 Chunking 也有一个代价:如果只预测一次、再连续执行很长一段动作,机器人中途就缺少新观察带来的修正。因此 ACT 还引入了 Temporal Ensembling,我们稍后会把它接上。
二、ACT 的完整网络:谁负责看、谁负责理解、谁负责产生动作?
用工厂做类比,可以把它理解为:
-
视觉 Backbone 是观察员,将相机画面整理为视觉特征;
-
Transformer Encoder 是信息整理员,让输入 Token 彼此交流;
-
Transformer Decoder 是动作生成员,利用 Action Queries 从 Encoder Memory 中读取信息;
-
Action Head 是输出接口,将内部特征转换为具体 Action 数值。
真正的数据流是:
\ \\boxed{ \\begin{aligned} \&\\text{RGB Images}\\rightarrow\\text{Visual Backbone}\\\\ \&\\text{Visual Features}+\\text{Joint State}+\\text{Latent }z\\\\ \&\\hspace{18mm}\\downarrow\\\\ \&\\text{Transformer Encoder}\\rightarrow\\text{Memory}\\\\ \&\\hspace{18mm}\\downarrow\\\\ \&\\text{Transformer Decoder + Action Queries}\\\\ \&\\hspace{18mm}\\downarrow\\\\ \&\\text{Action Head}\\rightarrow\\hat A \\end{aligned} } \\
这条链里,我们最应该保留下来的 Shape 认识是:
| 阶段 | 教学 Shape | 作用 |
|---|---|---|
| RGB 输入 | [B,N,3,H,W] |
\(N\) 台相机 |
| Visual Tokens | [B,S_v,D] |
图片变成视觉特征序列 |
| 加入状态和潜变量 | [B,S_v+2,D] |
增加两个条件 Token |
| Encoder Memory | [B,S_v+2,D] |
上下文化特征 |
| Decoder Queries | [B,K,D] |
\(K\) 个未来动作位置 |
| Action Head 输出 | [B,K,D_a] |
预测 Action Chunk |
这是为理解而统一成 Batch-First 的表示;作者原始 Transformer 文件中的多处计算实际采用 Sequence-First 排列 [S,B,D]。
现在你应该能自己解释:为什么 Encoder 输入 \(S_v+2\) 个 Token,Decoder 却能输出 \(K\) 个动作?
因为 Decoder 的输出位置数由 Action Queries 决定,而不是由 Encoder Memory 的长度决定。
它们通过 Cross-Attention 连接:
\ Q_{\\text{action}}K_{\\text{memory}}\^T \\
生成关系矩阵,再将 Memory 中的 Value 聚合到动作位置。
这也正是我们花几课学习 \(Q,K,V\)、矩阵转置、reshape 和 transpose 的原因。
三、ACT 为什么还要 CVAE?这不是已经有 Transformer 了吗?
因为 Transformer 负责处理信息关系,并不自动保证模型能妥善表达多个合理的动作模式。
假设同样的起始状态,人可以从障碍物左侧绕过去,也可以从右侧绕过去。普通确定性 MSE 回归可能把两种动作平均,输出一条不理想的中间轨迹。
ACT 引入 CVAE(Conditional Variational Autoencoder),训练时额外读取专家动作序列:
\ (q_t,A_t) \\xrightarrow{\\text{CVAE Encoder}} (\\mu,\\log\\sigma\^2) \\
通过重参数化:
\ \\boxed{ z=\\mu+\\sigma\\odot\\epsilon,\\qquad \\epsilon\\sim\\mathcal N(0,I) } \\
获得一个潜变量 \(z\)。
然后让 Policy 使用 Observation 和 \(z\) 预测 Action Chunk:
\ \\hat A_t=\\pi_\\theta(o_t,z) \\
CVAE 就像训练时的"示范分析员",负责学习动作示范中的潜在变化因素。这里的 \(z\) 并不是事先定义好的"向左/向右"开关,模型也不能保证每个维度都具有可直接解释的动作语义。
训练目标可以概括为:
\ \\boxed{ L_{\\text{ACT}} = L_{\\text{recon}}+\\beta L_{\\text{KL}} } \\
重建损失要求动作预测接近专家:
\ L_{\\text{recon}}=L_1(\\hat A,A) \\
KL Loss 则约束潜变量分布与标准正态先验之间的差异:
\ L_{\\text{KL}} = D_{\\mathrm{KL}}\\left( q_\\phi(z\\mid q,A) \\parallel\\mathcal N(0,I) \\right) \\
作者当前官方 policy.py 实现采用 L1 + KL。
训练中的简化 PyTorch 代码就是:
pred_actions, mu, logvar = model( images, qpos, expert_actions, is_pad)recon_loss = masked_l1(pred_actions, expert_actions, is_pad)kl_loss = gaussian_kl(mu, logvar)loss = recon_loss + beta * kl_lossoptimizer.zero_grad()loss.backward()optimizer.step()
其中 masked_l1、gaussian_kl 是为了突出逻辑使用的函数名,不是直接可运行的官方 API;它们的计算我们已在第 17 和 19 课分别展开过。
这里最重要的是看清两条梯度路径:重建损失会训练动作生成相关参数,并通过重参数化路径影响 CVAE Encoder;KL Loss 则直接约束潜变量分布参数。
四、为什么训练时需要专家动作,而推理时不需要?
这点可以说是 ACT 最容易混淆、又最应该掌握的地方。
训练阶段
专家 Action Chunk
CVAE Encoder
采样 \(z\)
Policy → Action Chunk
计算重建损失与 KL 损失
推理阶段
当前 Observation
固定 \(z=0\)
Policy → Action Chunk
不需要未来专家动作或 CVAE Encoder
训练时,专家动作已经包含在 Dataset 中,因此可以利用它们学习潜变量。
推理时,未来专家动作根本不存在。原始 ACT 采用:
\ \\boxed{z=0} \\
即使用标准正态先验的均值,生成预测 Action Chunk。
这也意味着:原始 ACT 并不是每次推理都随机抽取不同的 \(z\),再随机挑选动作风格。
五、Action Chunk 预测出来以后,机器人怎样执行?
假设模型每个时刻都预测未来四步。
| 预测时刻 | 针对未来的动作 |
|---|---|
| \(t=0\) | \(\hat a_{0\mid0},\hat a_{1\mid0},\hat a_{2\mid0},\hat a_{3\mid0}\) |
| \(t=1\) | \(\hat a_{1\mid1},\hat a_{2\mid1},\hat a_{3\mid1},\hat a_{4\mid1}\) |
| \(t=2\) | \(\hat a_{2\mid2},\hat a_{3\mid2},\hat a_{4\mid2},\hat a_{5\mid2}\) |
到了时刻 \(t=2\),我们可以找到三个对同一执行时刻的预测:
\ \\hat a_{2\\mid0},\\quad \\hat a_{2\\mid1},\\quad \\hat a_{2\\mid2} \\
Temporal Ensembling 就是把它们按权重融合:
\ \\boxed{ a_2= \\frac{\\sum_i w_i\\hat a_{2\\mid i}} {\\sum_i w_i} } \\
重要的是:融合的是对同一未来时刻的多个预测,不是把不同执行时刻的动作直接平均。
原论文使用指数权重,并明确从较旧预测开始赋予权重。
得到当前 Action 后,还必须经过训练时归一化操作的逆变换,并按照机器人执行接口的语义处理,再送入底层控制系统。
最终形成:
\ \\boxed{ Observation \\rightarrow ACT \\rightarrow Action\\ Chunk \\rightarrow Temporal\\ Ensembling \\rightarrow Execution \\rightarrow New\\ Observation } \\
这才是一条真正闭环的策略执行链。
六、ACT 的价值、边界,以及我们已经掌握什么
ACT 的主要价值不是简单地"用了 Transformer",而是将动作序列预测、生成式潜变量建模和重叠动作预测融合起来,用于高精度机器人模仿学习。
但它也存在需要正确理解的边界。原始 ACT 不是带文本指令理解能力的完整 VLA;它仍然依赖质量可靠的示范数据、清楚的 Action Representation 和与训练条件相匹配的部署接口。固定 \(z=0\) 的推理方式,也不等于充分采样所有可能的动作模式。
经过这一阶段,你应该已经能够把 ACT 拆成四个层次:
| 层次 | 现在应该理解的内容 |
|---|---|
| 数据层 | Episode、Action Chunk、Normalization、Padding Mask |
| 模型层 | Visual Backbone、Encoder、Decoder、Action Query、CVAE |
| 训练层 | Forward、L1、KL、Backward、Optimizer、Checkpoint |
| 执行层 | \(z=0\)、Chunk Prediction、Temporal Ensembling、Denormalization、Rollout |
官方代码的主线也已经建立:
utils.py → imitate_episodes.py → policy.py → detr/models/detr_vae.py → detr/models/transformer.py
我们已经具备进一步修改和调试 ACT 类模型所需的理论框架。 但这不等于已经完成真实训练复现;后者还需要数据质量验证、任务配置、实验日志、实际 Rollout 和指标复核。
接下来再学 Diffusion Policy,就能形成真正有意义的模型比较:同样预测 Action Chunk,为什么 ACT 使用 CVAE + Transformer,而 Diffusion Policy 选择从噪声中逐步生成动作?