
速通机器人学习
作者三周内从零重实现 ACT 与 Diffusion Policy,靠超参数调优在 PushT 上以 65.6% 超越所有公开 vanilla-ACT 结果,并
三周前,我对机器人学习还一无所知。从那以后,我从零开始重新实现了两个策略,在 PushT 上击败了所有公开的 vanilla-ACT 结果,并训练了一条模拟机械臂,让它以 99.95% 的成功率把酒杯放到架子上。下面就是这段经历,以及一路上让我意外的地方。
如果你以训练模型为生,这里的大部分内容都会显得很熟悉:同样的工具箱,只不过循环闭合在了一台真实机器上。最后这一点正是它如此有趣的原因,因为取代表格里一个数字的,是你能亲眼看着一条机械臂把酒杯放上架子(或者把它打翻)。
让我意外的事(但其实本不该意外)
- 一点点超参数调优就非常关键。使用 LeRobot 的 ACT 实现及其默认配置,我在 PushT 上得到 0% 的成功率;对那份配置做了一些合理的改动后,0% 就变成了 66%。这和我从零重新实现 GPT-2 时的教训一样:PyTorch 默认的 embedding 初始化结果竟然宽了 50 倍。
- 一次只应该改变一件事。如果你坚持这一点,指标上的每一次变化都有清晰的归因。如果不这样做,理清因果关系就会变成一场噩梦,正如我在下面那个酒杯场景中所见。虽然在那里我没有什么借口,但机器人技术的物理现实会让这条规则很难遵守(例如在现实世界中,你不可能在不添加物理相机支架的情况下增加一个相机视角)。
- 莫拉维克悖论是真的!对人类来说轻而易举的事情(捏住杯柄拿起酒杯),对机器人来说却是难事,对编写机器人代码的 Claude 来说也是如此。这也正是为什么遥操作可能比脚本化专家轨迹快得多。
我做了什么
学习并讲解了机器人控制、ACT 与 Diffusion Policy
我的大部分时间都花在了理解而非编码上,而对于每个主题,我确保自己真正理解的方式就是为别人写一篇讲解文章。按顺序来说:SO-100 机械臂是如何被控制的(舵机、PID、关节空间与任务空间、正运动学与逆运动学,以及逆运动学为什么令人头疼)。然后是 ACT,尤其是它为什么被构建为一个条件 VAE。接着是扩散、流匹配与 Diffusion Policy,从两个角度切入:一门 MIT 课程将这一切框定为向量场、ODE 与 SDE,以及另一个将扩散视为分层 VAE 的视角。在我看来,写这些文章是我这三周里做过的最有用的事,所以接下来八天我会在这里陆续分享。
重新实现了 ACT,并将其调优到在 PushT 上超越所有公开的 vanilla-ACT 结果
我用 PyTorch 重新实现了 ACT(并发现了论文与参考实现之间的一处不一致),为它搭建了训练与推理循环,然后在标准的 PushT 数据集(206 条人类演示)上从零开始训练,在 160k 步时达到了 64% 的成功率。
这些超参数是在 LeRobot 的 ACT 实现上调优的。用其默认超参数(推理时 n_action_steps 为 100)训练该参考实现,在 PushT 上给我的成功率是 0%。仅仅更频繁地重新规划(n_action_steps 为 16)就将其提升到了 20%,再在此基础上调优训练超参数,在 200k 步时提升到了 65.6% ± 1.3%(95% 置信区间)。这个 65.6% 比我在 PushT 上见过的其他人用 vanilla-ACT(仅图像 + 本体感觉,如论文中所述)取得的结果高出约 14 个百分点(我找到的最佳结果是 52%,出自 AR-VLA (Hu et al., 2026)),并与 LeRobot 官方 Diffusion Policy 检查点在 PushT 上的表现(65.4%)持平。以下是我的超参数(与 LeRobot 的默认值对比):
| default | winning | |
|---|---|---|
| batch size | 8 | 64 |
| lr, AdamW (backbone too) | 1e-5 | 2e-5 |
| decoder layers | 1 | 7 |
| n_action_steps at inference | 100 | 16 |
| chunk size | 100 | 100 |
| KL weight / VAE | 10 / on | same |
| d_model, encoder layers, ffn, dropout, wd, grad clip | 512, 4, 3200, 0.1, 1e-4, 10 | same |
| steps, LR schedule, EMA, augmentation | 100k, none, none, none | 200k (100k gave 56–61%), none, none, none |
default三周前我对机器人学习一无所知。从那时起,我从零开始重新实现了两种策略,在 PushT 上击败了所有公开的基于图像的 ACT 结果,并训练了一个模拟机械臂,使其以 99.95% 的成功率将酒杯放到架子上。以下就是这一路走来的经过,以及途中让我感到意外的地方。he way.e way. way.way.ay.y.

PushT:用蓝色圆圈将灰色 T 推到绿色目标上。一旦 T 覆盖目标的 95%,该回合即算成功。上图:我从零实现的 ACT 在一个回合中的表现,完整 rollout 见下方。

重新实现 Diffusion Policy,并将 Flow Matching 引入其中
我用 PyTorch 重新实现了 Diffusion Policy 的 CNN 版本(同时发现了论文与参考实现之间的一处不一致),并在 PushT 上进行了训练。我的第一次训练尝试达到了 32% 的成功率,通过应用 LeRobot 实现中的技巧,我将其提升到了 66.1% ± 1.6%(95% 置信区间):训练时对 96x96 输入图像进行 84x84 随机裁剪(推理时进行中心裁剪)+ 从训练集中丢弃从回合最后 7 帧开始的 chunk + EMA 权重。对于 Diffusion Policy 的采样,我同时实现了 DDPM 和 DDIM,出于好奇,我还尝试将其扩散方法替换为 flow matching。开箱即用,这种替换是有效的,并且在早期训练更快,但在 10 步去噪时它比 DDIM 低了约 5 个百分点(61% 对 66%)。不过,我在这里没有尝试调整任何超参数。
构建并在 MuJoCo 场景上训练
为了熟悉 MuJoCo 和模仿学习技术栈,我构建了一个涉及 SO-100 机械臂和红色盒子的 MuJoCo 场景、一个将夹爪到达盒子视为成功的 gymnasium Env,以及一个专家轨迹生成器,然后在生成的数据集上训练了一个 ACT 策略。指标不太好(在 1000 个训练演示、500 个评估回合下成功率为 43.6% ± 4.3%,用 100 个演示时明显更差,不过那里我只运行了少量回合),这是可以理解的,因为任务构造得有点不合理:从单个摄像头的视角很难判断盒子有多远。然而,这对我来说是了解更多技术栈的好方法。

左:脚本化的专家轨迹。右:我从相同起点出发的 ACT 策略,在 1000 条此类轨迹上训练。

它的一次失败,旁边是同一初始状态下的专家演示。策略已经接近盒子,但始终没能真正落到上面。
搭建了一个很酷的场景,并训练到 99.95% 的成功率
在学会了所有这些单独的模块之后,我觉得是时候把它们组装成一个能拿得出手的东西了。为此,我决定创建一个很酷的 MuJoCo 场景/任务,以及一个在该场景上的专家轨迹数据集,然后用我的训练流程训练我的 ACT 实现,并用我的推理流程来运行它。我最终选定的场景是让 SO-100 机械臂拿起一个倒置的酒杯,把它正过来放到架子上。
由于手动编写这个场景和专家轨迹生成器会是一场噩梦,我让 Claude 把两者都生成了出来。它很快就写好了 MuJoCo 场景,但花了好几个小时来回折腾,才得到能很好完成任务的专家轨迹。这让我对莫拉维克悖论有了完全不同的体会(Claude 理解扩散模型比理解"你不能穿过杯脚去抓酒杯的杯柄"要容易得多),也让我明白了为什么要做遥操作(不过我非常好奇,如果录几条遥操作轨迹,看看 Claude 能不能从中构建出一个专家轨迹生成器)。

v1 专家轨迹,回放其中一条存储的演示:抓住倒置酒杯的杯柄,把它搬过去,然后正过来放到架子上。
在这些专家轨迹上的早期训练表现不尽如人意。观察 v1 策略的一些失败案例时,我看到夹爪误判了酒杯杯柄的精确位置,结果戳到了它而不是抓住它。这让我推测腕部摄像头可能会有帮助,因为这种情况发生时,酒杯被机械臂部分遮挡了。

v1 的一次失败:夹爪在合拢之前就把玻璃杯推倒了,抓起来几厘米后又脱手,始终没能把它送到架子上。
由于我希望场景更真实,我给机械臂加上了带碰撞几何体的相机机身,以及对应的相机视角。但这也意味着之前的专家轨迹不再可用,因为腕部相机在进入过程中会撞到地面,这迫使我修改专家轨迹(在进入时把腕部旋转 180°,并在夹持玻璃杯时反转滚转方向),而这又引出了其他问题,如此反复。等到腕部相机加好时,任务已经变化得足够多,以至于之前的失败模式消失了,而额外的相机视角也变得多余了。

左:v2 专家轨迹,现在带有腕部相机、额外的腕部滚转以及其他一些改动。右:我从同一起点出发的 ACT 策略,基于 1000 条此类轨迹训练。

同一个成功回合在环境渲染的 96x96 分辨率下,左侧为前视相机,右侧为腕部相机。该策略仅基于前视相机训练,因此这里的腕部视角仅作示意。
我的消融实验表明,抓取酒杯前额外的腕部滚转正是让抓取在早期就可学习的原因(在 5k 训练步时成功率为 78% 对 1%),不过普通的 v1 在 30k 步时追了上来(87–92% 对 86%)。实验还表明我最初的假设是正确的:在原始轨迹上,仅添加腕部相机视角而不做其他所有改动就有很大帮助(不过该消融使用的是没有物理机身的裸相机视角,因为在该姿态下真实安装的相机会与地面碰撞)。

未加腕部预旋转(左)与加入腕部预旋转(右)的 v1 专家轨迹。相同的抓取、相同的架子;唯一的区别在于抓取前腕部旋转 180°,并在握住玻璃杯时转回。

相机消融实验,两侧起始状态相同。左:仅使用前置摄像头的 v1 策略能抓起玻璃杯并将其转正,但在放下时将其从架子远端边缘碰倒。右:加入腕部相机视角训练的同一策略成功完成。
最终结果:借助预旋转,我的 ACT 实现在 100 条专家轨迹上训练不到一个 H100 小时,便得到了成功率为 99.1%(95% CI:[98.6, 99.4])的策略(在 2000 个留出回合上评估)。使用 1000 条专家轨迹时,该成功率提升至 99.95%(95% CI:[99.7, 100])。
下一步计划
- 走出仿真。是时候动手搞硬件部署、Sim2Real 差距,并掌握遥操作了。目前的障碍是我没有任何硬件,所以如果你在旧金山且有多余的机械臂或类似设备,请告诉我!
- 强化学习。我已经读完了 Sutton & Barto 的经典 RL 教材,并重新实现了其中大部分算法,但只将其应用于玩具问题(CartPole 和 FrozenLake)。我想把我的 RL 工具箱应用到机器人学习中,因为我相信这会带来那些更简单环境所没有的一系列挑战。我尤其对 RL 与 Sim2Real 的结合感到好奇。
- VLA 以及在其之上构建的东西。我已经读过 OpenVLA 和 π0 的论文,所以接下来是重新实现 SmolVLA,并在 LIBERO 上微调它。这里有两个问题:鉴于我在 PushT 上看到的情况,每张 LIBERO 表格都照抄的那个 VLA 与从零训练的 Diffusion Policy 基线之间的差距(72%)有多少只是调参带来的。以及在 450M 参数、仅微调算力的条件下,π0.5 的那些技巧(比如知识隔离)是否还能带来任何收益。
接下来
在接下来的八天里,我会分享我一路写下的那些讲解文章,那些我三周前真希望自己当时就能拥有的文章。在这里关注我,就能看到它们。
如果你在机器人学习领域,跟我打个招呼。我还会在旧金山待两周,所以现在是喝杯咖啡的好时机。