OpenVLA 在 LIBERO 跑出 10/10 之后:重新定义机器人的“成功”
从模型加载、环境适配到严格完成判据,复盘一次 OpenVLA 闭环验证为什么从瞬时 10/10 变成稳定 8/10。
一次 OpenVLA 推理验证中,最初的结果非常漂亮:LIBERO-Spatial 十个任务、固定初始状态和随机种子,每项单次 rollout 全部触发成功。但逐帧看视频后,一个问题越来越明显:机械手还夹着碗,只要碗与盘子瞬间满足接触关系,环境就已经返回 done=True。
于是我没有停在 10/10,而是把“成功”改成完整动作语义:放稳、松手、回到起始姿态,并连续保持。相同十项任务重新评估后,结果变成 8/10。这个下降不是模型退化,而是评测变得更诚实。
先把模型与环境分别跑通
目标 checkpoint 是 openvla/openvla-7b-finetuned-libero-spatial,已经存在本机 Hugging Face cache。直接进入 220 步闭环会让依赖、渲染、模型和动作问题混在一起,因此验证拆成三层:
- 模型单帧输入能否输出合法 7 维动作;
- RoboVerse/LIBERO 环境能否 reset、step 和 EGL render;
- 两者闭环后能否完成一局并保存 JSON/MP4。
模型以 BF16 + SDPA 加载,单卡显存约 14.4 GiB。环境链路是 RoboVerse passthrough → LIBERO OffScreenRenderEnv → robosuite → MuJoCo → EGL。画面和模型推理由 GPU 加速,MuJoCo 物理和 H.264 编码主要在 CPU。
这次还遇到两个兼容点。通用 RoboVerse OpenVLA evaluator 使用的动作归一化键面向另一数据分布,不能直接套在 libero_spatial checkpoint 上;正确路径是原生 LIBERO passthrough 加该 checkpoint 自己的动作统计。PyTorch 新版本读取可信的旧初始化状态时,也需要显式处理 weights_only 行为变化。
策略实际看到了什么
OpenVLA 每一步只接收:
- 旋转 180° 后的第三人称
agentviewRGB; - 一条英文任务指令。
它不使用腕部相机,也没有读取关节角、末端位姿或 proprioception。输出是单步 7 维动作:三维位置增量、三维旋转增量与夹爪控制。
机器人状态和接触信息只进入评估器,不进入策略。这一边界必须写清楚,否则“系统使用了关节状态”很容易被误解为模型输入包含关节状态。
原始成功为什么会过于宽松
这组 spatial 任务的 BDDL 目标可以概括为 On(bowl, plate)。LIBERO 根据物体高度、物理接触与水平距离判断谓词;某一步为真时,稀疏奖励变成 1,环境即可结束。
问题是它不要求:
- 夹爪已经松开;
- 目标不再被抓住;
- 碗在盘子上稳定保持;
- 机械臂离开目标区域或回位。
于是“夹着碗压到盘子上”也可能触发瞬时成功。这对验证原始 benchmark 协议没有错,但如果产品语义是“把碗放在盘子上并完成动作”,就明显不够。
更严格的完成判据
新的评估器要求连续 5 步同时满足:
- 原始 BDDL 目标仍成立;
- 夹爪张开宽度至少 6 cm;
- 夹爪不再抓住目标碗;
- 末端位置距初始位置不超过 3 cm;
- 姿态误差不超过 0.15 rad;
- 七轴关节 RMSE 不超过 0.15 rad。
当原始目标首次达成后,控制切到确定性的“张开夹爪 → 回到起始姿态”。如果松手后目标失效,评估器不会宣布成功,而是允许 OpenVLA 在剩余步数内再次尝试。
这正是两个失败任务暴露的问题:碗在松爪后没有继续稳定留在盘子上。其余八项完成了放置、释放、回位和稳定保持。
10/10 与 8/10 都不能当统计成功率
两轮结果使用每任务一个固定初始状态、固定 seed、单次 rollout,最多 220 个策略步。它们是功能验证,不是官方多初始状态、多次采样的统计评测。
原始判据下的 10/10 回答“策略能否让官方 goal predicate 至少瞬间成立”;严格判据的 8/10 回答“能否完成我们定义的稳定放置和收尾动作”。两个数字只有连同协议一起报告才有意义。
每项保存视频和结构化 JSON也非常重要。汇总数字负责比较,视频负责发现指标没有表达的问题,JSON则记录原始 goal、严格状态、步数、恢复步数、末端/关节误差与失败原因。三者缺一,很难判断模型错了还是评测器太宽松。
具身智能评测最危险的不是低分,而是高分回答了错误的问题。先定义任务完成的物理语义,再写 success condition,往往比再调一次模型更能提高结论质量。