我最近在给实验室做 robomimic 教学型复现,工程卡在 Lift-PH 这个数据集上。很多人第一次跑 State BC,以为把命令一敲、等训练完就结束了,实际上坑最多的地方不在训练,而在启动前那十分钟的配置准备与审计。Phase 3 要做的就是把官方 State BC 配置从“能打开”变成“确定能跑出可复现结果”。
这篇文章面向的是正在按阶段复现 robomimic 的同学,尤其是刚接触机器人模仿学习、对数据集和配置结构还不熟的人。我会按自己实际操作时的顺序,把准备官方 State BC 配置、审计环境与数据、试跑验证这一整套流程讲清楚。每一步为什么要做、会出现什么现象、怎么排查,我都会提到。如果你已经跑通了前面两个阶段,这篇可以直接照做。
1. 为什么把“配置准备与审计”单独做成一个阶段
1.1 教学型复现的路线图里,Phase 3 承担什么角色
教学型复现和一般的调参跑实验不太一样。正常做研究时,你可能会直接改 config 然后跑 50 epoch,失败了再改。但教学型复现的目标是让一个完全没接触过 robomimic 的人,能按阶段从零走到一个可信的结果。它需要把流程切碎,让每个阶段都承担一个明确任务:
- Phase 1:安装 robomimic 仓库、创建虚拟环境、解决依赖;
- Phase 2:下载并理解 Lift-PH 数据集,搞清楚数据形态;
- Phase 3:准备官方 State BC 配置,并对环境、数据和配置做一致性审计;
- Phase 4:启动训练、保存基线模型、可视化结果。
Phase 3 夹在数据准备和正式训练之间,看起来只是“写一个 json 配置文件”的事情,但它实际上是整个复现项目里风险最高的关卡。因为后续所有训练结果都建立在这个配置上,如果配置里某个路径写错、某个 observation key 对不上、某个 filter 条件把数据过滤成空集,后面跑出来的要么是报错,要么是一个看起来正常但完全不可信的模型。单独做一个阶段,就是要把这类问题在训练开始前全部暴露出来。
1.2 配置审计到底在审什么
审计这个词听着重,其实核心就是回答三类问题:
- 环境对不对:Python 版本、torch 版本、CUDA 是否可用、robomimic 是否能正常 import;
- 数据全不全:Lift-PH 数据集文件是否存在、HDF5 内部结构是否完整、轨迹数量和时间步是否符合预期;
- 配置匹配不匹配:官方 bc.json 里写的路径、obs modality、batch size 等参数,是否和当前数据集、当前设备条件一致。
我见过很多同学直接跑官方命令,结果报错 FileNotFoundError,或者训练完才发现模型根本没有看到图像/状态特征,只是因为 config 和数据集版本不一致导致数据被静默过滤。审计阶段的作用,就是用最少的时间把这三类问题全查一遍。
2. 先把家底盘清楚:环境、仓库与数据集资产清单
2.1 虚拟环境与依赖版本核对
进入 Phase 3 时,假设你已经按 robomimic 的官方 README 装好了环境。但“装过”不表示“现在还能用”,环境是动态的,你可能中途升级过某个包,也可能多装了一个会产生依赖冲突的库。我启动前会先跑一组快速检查:
conda activate robomimic python -c "import robomimic; print(robomimic.__version__)" python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())" python -c "import h5py; print(h5py.__version__)"这里有一个容易忽略的点:robomimic.__version__可能不存在。robomimic 有些版本没有在__init__.py里定义版本号,如果报 AttributeError,不要慌,直接看 pip 包信息或者 git commit 号即可:
pip show robomimic git -C /path/to/robomimic log --oneline -1为什么这一步值得单独拎出来?因为 robomimic 的配置文件结构在不同 commit 之间有过调整,有的新版本把experiment.name改成必填项,有的旧版本还在用train.data_dir而新版本已经要求dataset_path。确定 commit 号,后面解析配置、对齐官方示例时才有参照物。
2.2 数据集目录结构与 Lift-PH 文件确认
robomimic 官方的数据集下载脚本会把数据放到统一的目录结构里。Lift-PH 对应的低维状态数据路径通常是:
datasets/ └── lift/ └── ph/ └── low_dim.hdf5建议用绝对路径管理,不要用相对路径。因为run_training.py里如果只写了../datasets,它相对的是当前工作目录,而很多人喜欢在仓库根目录下敲命令,这时相对路径的基准目录就很容易搞混。我在实际部署时使用下面的检查方式:
ls -lh /workspace/datasets/lift/ph/low_dim.hdf5正常文件大小在几十 MB 量级。如果文件只有几 KB,基本可以怀疑是下载失败或者git-lfs没有正确拉取内容。robomimic 某些数据集走的是download_datasets.py脚本,下载中断也可能产生这种问题,建议重新下载并确认文件哈希。
同时检查一下high_dim.hdf5是否存在。Phase 3 虽然用的是低维状态数据,但后续如果你想扩展成 Image BC 或者看演示视频,高度数据还会用到。都放在那里,不影响 Phase 3,但能省去后面临时补下载的麻烦。
2.3 用一段小脚本把数据集元信息读出来
路径和大小没问题,还不够。HDF5 是个容器,真正内容在里面。我建议花 30 秒写一个小脚本,把数据集的关键元信息打印出来:
import h5py demo_path = "/workspace/datasets/lift/ph/low_dim.hdf5" with h5py.File(demo_path, "r") as f: print("root attrs:", dict(f.attrs)) print("top-level keys:", list(f.keys())) data_grp = f["data"] print("data attrs:", dict(data_grp.attrs)) demo_keys = list(data_grp.keys()) print("num demos inside data:", len(demo_keys)) first_demo = demo_keys[0] first_grp = data_grp[first_demo] print("first demo keys:", list(first_grp.keys())) print("obs group keys:", list(first_grp["obs"].keys())) print("actions shape:", first_grp["actions"].shape) print("rewards shape:", first_grp["rewards"].shape)在我的实机上,打印结果类似这样:
data.attrs["total_timesteps"]在几千到一万多之间;data.attrs["num_traj"]对应 Lift-PH 官方数据集的轨迹数;obs下能看到object、robot0_eef_pos、robot0_eef_quat、robot0_gripper_qpos、robot0_gripper_qvel等低维 key。
这段输出非常关键。因为 State BC 配置里的observation.modalities会和这里的 obs key 逐项匹配。如果数据集里根本没有某个 obs key,而配置里写了它,robomimic 可能会在运行时才报错;如果配置里漏了某个 key,训练出的模型会缺失一部分状态信息,成功率会明显下降。提前打印出来,相当于给后续配置审计做了一次“字典对齐”。
3. 官方 State BC 配置文件逐段拆解
3.1 experiment / train / algo 三段式结构
官方提供的基线配置统一放在robomimic/scripts/configs/下面,State BC 对应的就是bc.json。打开这个文件,第一感觉是字段很多,但其实核心就是三段:实验信息、训练参数、算法参数。
experiment段负责定义实验的名称、输出目录、数据集路径和运行设备。它决定了“本次实验去哪里读数据、往哪里写结果”。训练参数段train则控制训练流程:随机种子、训练轮数、batch size、日志打印频率、Checkpoint 保存策略、数据加载线程数等。算法参数段algo才是 State BC 本身的定义:策略网络结构、优化器、损失函数、是否使用 RNN 等。
理解三段式结构,对审计的意义在于:当你需要排查一个问题时,能快速定位到它是属于路径问题、训练流程问题还是网络结构问题,而不是在 json 里瞎翻。官方注释里也写得很清楚,建议花十分钟从头到尾读一遍,很多报错就是读注释读出来的。
3.2 observation.modalities:为什么是 State 方案的核心
State BC,英文是 State-Based Behavior Cloning,核心就是只使用低维状态向量,不使用图像。在配置里体现为:
"observation": { "modalities": { "obs": { "low_dim": [ "object", "robot0_eef_pos", "robot0_eef_quat", "robot0_gripper_qpos", "robot0_gripper_qvel" ], "image": [] } } }这个字段决定了模型从观测中读取哪些信息。low_dim列出来的 key 要和 HDF5 里obs组下的低维 key 一一对应;image数组为空,则表示不加载任何图像。
很多第一次接触的人会觉得 State BC 和 Image BC 的区别只是“图像字段有没有值”。实际不止如此。State BC 的输入是拼接后的低维向量,不需要经过图像编码器,所以网络结构可以是简单的 MLP;Image BC 则通常需要 CNN 编码器,训练更慢、显存需求更大、对数据增强也更敏感。对于教学型复现来说,选择 State BC 是合理的:它更容易跑通,也能更快验证数据管线、训练代码和评估流程是否正常。
3.3 训练尺度:epoch、batch、learning rate 怎么来的
官方bc.json里默认的训练尺度,是按“Lift-PH 这种规模的单任务数据集”设计的。比如训练轮数、batch size、学习率这些数值,并不是拍脑袋定的,它们参考了 robomimic 论文发布时的实验设置。
这些参数在复现阶段不建议一上来就大改。原因很简单:官方配置是经过验证的基准配置,改参后如果结果变差,你很难判断是改动本身造成的,还是数据集/环境的问题。教学型复现的第一目标是把官方基线复现出来,得到一个可信的 baseline,然后再谈调优。如果机器显卡显存不够,可以优先考虑减小 batch size,但也要同时考虑是否需要相应调整学习率;如果时间紧张,可以先把 epoch 减少到 1/5 做冒烟测试,不要直接砍一半就正式出结果。
3.4 版本差异提醒:不同分支的字段有变化
robomimic 仓库在过去一段时间内更新比较频繁,bc.json的字段在不同 commit 之间有差异。举个我遇到的例子:旧版本里train段会有data_dir和dataset_path两个字段并用,新版本可能只保留dataset_path,且新增了部分用于数据集筛选和轨迹处理的字段。
所以在按照网上教程配置时,一定要先确认你 clone 的仓库版本。最直接的方式是打开仓库根目录的README.md,里面通常标注了推荐的使用方式;然后对比robomimic/scripts/configs/bc.json的注释内容和当前仓库robomimic/core里各模块的源码字段。如果直接用不是当前版本的旧配置文件,很容易遇到字段不匹配或行为不一致的问题。我的建议是:以自己 clone 到的官方bc.json为基准,不要从网上随便复制一份。
4. 配置与数据的一致性审计:逐步操作
4.1 路径审计:五处容易写错的地方
配置准备里最容易翻车的不是算法参数,而是路径。我总结了五处容易写错的地方:
dataset_path写成了相对路径,而当前工作目录不是仓库根目录;output_dir指向了一个不存在的目录,程序启动时报 OSError;- 数据集文件名写错,把
low_dim.hdf5写成lowdim.hdf5; - 路径里用了
~而没有做 shell 展开,python 不会自动把它替换成主目录; - 在 Windows 上用了反斜杠
\拼接路径,导致转义符号问题。
审计路径时,我的做法是在启动训练前,先手工用python验证一下最重要的两个路径:
import os from robomimic.utils.file_utils import ensure_dir dataset_path = "/workspace/datasets/lift/ph/low_dim.hdf5" print("dataset exists:", os.path.exists(dataset_path)) output_dir = "/workspace/results/lift_ph_state_bc" ensure_dir(output_dir) print("output dir ready:", os.path.exists(output_dir))这样不会等到训练脚本跑到一半才炸出来。
4.2 obs key 对照审计
路径对了,下一步就进入观察空间的一致性审计。这一步是 State BC 配置准备的核心,因为模型能否学到有效的策略,取决于它拿到的状态特征是否完整且有序。
我把观测空间的审计拆成三步:
- 从 HDF5 里取出
obs组的低维 key 列表; - 从
bc.json的observation.modalities里取出配置的低维 key 列表; - 对比这两个列表,确认配置里的 key 都真实存在于数据中,并且没有遗漏关键状态。
import h5py, json demo_path = "/workspace/datasets/lift/ph/low_dim.hdf5" config_path = "/workspace/robomimic/scripts/configs/bc.json" with h5py.File(demo_path, "r") as f: demo_key = list(f["data"].keys())[0] data_obs_keys = list(f["data/{}/obs".format(demo_key)].keys()) data_lowdim_keys = sorted([ k for k in data_obs_keys if not k.lower().endswith("image") ]) with open(config_path, "r") as f: cfg = json.load(f) config_lowdim_keys = sorted(cfg["observation"]["modalities"]["obs"]["low_dim"]) print("data lowdim keys: ", data_lowdim_keys) print("config lowdim keys:", config_lowdim_keys) print("missing in config:", set(data_lowdim_keys) - set(config_lowdim_keys)) print("not found in data:", set(config_lowdim_keys) - set(data_lowdim_keys))注意这里我用了一个简单规则:凡是 key 名字里带image的都归为图像模态。实际数据集里可能还有agentview_image、robot0_eye_in_hand_image这类 key,而低维多维特征一般是object、robot0_eef_pos这些不带 image 的字段。通过这个小脚本,基本能一眼看出问题。
4.3 数据集切分与 filter_by_attribute
官方配置里还包含一个容易被忽略的字段:dataset.filter_by_attribute。它的作用是按轨迹属性过滤数据集,常见用法是只保留成功轨迹。
Lift-PH 这个数据集里的轨迹质量整体较高,因为它是熟练操作者(Proficient Human)的演示。但如果你用的数据集是混合质量,或者包含失败轨迹,就需要考虑是否设置过滤条件。robomimic 数据集在 HDF5 的轨迹组 attr 里可能保存了属性信息,例如success、edited等。如果filter_by_attribute设置为null,表示不过滤,使用全部轨迹;如果设置成某个属性名,训练时会只保留该属性为 True 的轨迹。
我在教学型复现里一般先保持null,这样能让第一次跑的人看到完全按照官方配置的结果。后续如果要演示“数据质量对模仿学习的影响”,可以再对比过滤前后的结果,这个作为扩展实验更合适。
4.4 Dry-run 试跑设计
配置和数据的静态检查都通过后,不要直接跑完整训练。先设计一个轻量的试跑,也就是“冒烟测试”。具体做法是在命令行覆盖关键超参,把训练规模缩小:
python run_training.py \ --config /workspace/robomimic/scripts/configs/bc.json \ --dataset /workspace/datasets/lift/ph/low_dim.hdf5 \ --output_dir /workspace/results/lift_ph_state_bc_smoke \ --experiment.name lift_ph_state_bc_smoke \ --train.num_epochs 1这样只会跑 1 个 epoch。如果数据集规模不大,整个试跑只要几分钟。试跑不是真的为了出结果,而是为了验证整个管线能通:数据能加载、模型能构建、优化器能更新、日志能写入、Checkpoint 能保存。这一步能筛掉九成以上的运行时问题。
跑完后检查一下输出目录,应该能看到日志文件、模型 checkpoint 和 tensorboard 文件。如果只出现了日志但没有任何 checkpoint,要检查是不是 checkpoint 保存频率设得太高,或者本地磁盘空间不足。
5. 试跑与结果合理性检查
5.1 一个 epoch 的冒烟测试要观察什么
冒烟测试跑完后,我会先打开输出目录里的训练日志,关注几个关键指标:
- 数据加载速度是否正常;
- 首个 batch 的 loss 是否在“不奇怪”的范围;
- 训练 epoch 是否在预期时间内完成;
- checkpoint 是否顺利保存。
这些指标不需要很精确,但能反映管线是否健康。比如,如果首步 loss 直接是 NaN,那就别继续了,优先去看学习率是不是设得太大,或者 obs 里是不是混入了缺失值;如果一个 epoch 跑了几个小时,那可能数据加载卡死,要去检查num_data_workers是否设置过高导致 worker 阻塞。
5.2 第一个 checkpoint 前后的 Loss 曲线长什么样
State BC 做的是监督式行为克隆,损失函数衡量的是模型预测动作和演示动作之间的差异。正常情况下,第 1 个 epoch 的 loss 会明显下降,后面下降速度放缓,进入一个缓慢下降平台。
在我的经验里,Lift-PH 这个任务在 State BC 下,loss 的绝对值不会特别小,因为动作空间有多个维度,而且夹爪动作是离散的。比绝对值更重要的是变化趋势。如果第一个 epoch 结束后 loss 纹丝不动,说明模型可能没有有效学习,常见原因是优化器参数设置错误或者输入输出张量拼接有问题。如果 loss 下降到某个点之后开始反弹,常见原因则可能是学习率偏大,或者 batch size 太小导致梯度噪声过大。
冒烟测试结束后,因为只跑了一个 epoch,看不到完整的 loss 形态,所以我会在此基础上补做一个短训实验,比如把 epoch 设到 10 左右,跑一次看看趋势,再决定是否进入正式长训。
5.3 用官方基准预期值兜底对照
robomimic 论文和官方仓库都公布过基线结果。Lift 任务在 State BC 下通常能取得很高的任务成功率,因为任务本身相对简单,且 PH 演示质量高。如果你跑完短训后,想马上评估一轮,robomimic 提供了评估脚本或run_training.py的--evaluate相关选项。
我一般在得到第一个完整 checkpoint 后,先用官方评估流程跑一次 rollout,把成功率记录下来。预期成功率会偏低,因为训练并没有充分进行。但你不应该看到成功率等于 0 且很多 rollout 卡在同一个位置,如果出现这种情况,很可能是动作空间归一化出错,或者是策略网络输出和机器人控制器不匹配。
5.4 常见失败现象排查表
试跑阶段会暴露各种问题,我整理了一个排查表,方便按图索骥:
| 现象 | 可能原因 | 检查方式 |
|---|---|---|
| FileNotFoundError: dataset_path | 路径写错或~未展开 | os.path.exists验证 |
| AttrError: no obs key | 配置里写了数据集中不存在的 key | 用 h5py 打印 obs group 的 key |
| 训练 loss 为 NaN | 学习率过高、输入含无穷值 | 检查 obs 数值范围,降低学习率 |
| CUDA out of memory | batch size 或模型过大 | 减小 batch size 或换小模型 |
| 训练速度极慢 | num_data_workers 太高或太低 | 调整 worker 数,观察 CPU 占用 |
| checkpoint 文件没生成 | 保存频率设置为 0 或输出路径无权限 | 检查 train.log_every_n_epochs |
| 评估成功率一直为 0 | 动作空间/奖励函数理解有误 | 先手工回放一条演示轨迹核对 |
这个表只是起点,真正遇到问题时要学会看完整堆栈,robomimic 的报错信息通常会把出错模块和具体字段都打出来,顺着源码追一遍,往往比搜教程更快。
6. 跑通之后的下一步:记录基线、留好审计痕迹
6.1 实验命名与输出目录规范
正式训练开始前,建议花两分钟想清楚实验命名。一个规范的名字应该让人一眼看出:用了什么算法、什么数据、什么模态、什么配置。比如:
lift_ph_state_bc_v1输出目录可以是:
results/lift_ph_state_bc_v1/然后在experiment.name里保持同一个名字。这样后续做多组对比时,不会因为目录名相似而混淆。教学型复现尤其需要这个习惯,因为学习者要靠这些痕迹理解每一个实验对应什么用途。
6.2 怎么把这一次配置固化成一个 session 报告
我在 Phase 3 结束时,会把这次审计结果整理成一个简单的 markdown 文件,内容包括:
- 仓库 commit 号和 pip 包版本;
- 数据集路径、轨迹数、总时间步;
bc.json的关键字段快照;- 冒烟测试的日志摘要;
- 试跑是否通过,以及是否遇到过问题。
这个报告不需要很长,三十分钟内可以写完。但它对后续阶段非常有用,特别是当你跑完 Phase 4 发现结果不理想,回过头来排查时,这份报告能帮你快速确认“配置审计阶段到底是怎么准备的”。
6.3 Phase 4 可以怎么做
配置审计跑通后,你已经拿到了一个干净的训练管线。下一步建议直接按照官方配置跑一份完整的 State BC 基线,把训练日志、checkpoint、成功率评估结果都保存下来。然后再考虑扩展改动:比如改成 Image BC、换用cql.json、或者在数据集上叠加filter_by_attribute。
按照我的习惯,Phase 3 到 Phase 4 之间隔一天最好。隔这一天的意义不是拖时间,而是让自己从“怎么让程序跑通”的思维切换到“怎么解释结果”的思维。训练脚本跑起来以后,你会花更多时间在结果分析上,而配置审计阶段的数据和判断正好是分析的基准。