主题
RL 数据采集
L2 数据生成层中等难度的一支:用 RSL-RL PPO 在 IsaacLab 自带的 Isaac-Lift-Cube-Franka-v0 (joint_pos task) 上学一个 policy,然后让它在 sim 里 rollout,把 (obs, action) 录到 HDF5。
数据金字塔角色:量级中等(10³–10⁴ 条),主要价值是自然产生 recovery / 长尾轨迹——RL 探索期 + 收敛后的失败案例都是 scripted 永远生成不出来的数据分布。
核心原理
阶段 1:训练(学习"什么动作能获得高 reward")
obs → PPO policy → 9d joint_pos action → env.step()
↓ 累积 reward
更新 policy(让高 reward 的 action 更可能被选中)
↓ 重复 600 次
收敛的 policy(学会了 pick-and-lift)
阶段 2:Rollout(用学到的 policy 生成轨迹)
obs → policy → 9d joint_pos action → env.step()
↓ 同时
自定义 RecorderTerm 重写为 8d IK-abs action
↓
RecorderManager 写 (obs, 8d action) 到 HDF5关键特点:
- 自然产生 recovery:cube 掉了 → 重新抓;抓歪了 → 调整姿态
- 长尾分布:scripted 永远不会产生的"意外情况"
- 训练 joint_pos,写盘 IK-abs:训练路径不变,只在写盘时做等价转换
使用方法
1. 训练 PPO
选项 A:使用 NVIDIA 预训练权重(推荐)
NVIDIA 提供了 Isaac-Lift-Cube-Franka-v0 的预训练权重,可以直接用于 rollout 或作为起点继续训练:
bash
# 直接用预训练权重 rollout(跳到步骤 2)
# 或从预训练权重继续训练(fine-tune)
uv run sim2lerobot rl train \
--resume pretrained \
--max_iterations 1500优点:
- 节省训练时间(预训练模型已经收敛)
- 适合快速验证流程或生成高质量数据
- 可以作为 fine-tune 的起点
选项 B:从头训练
bash
# 默认 1024 envs × 600 iters,A100 上 ~10-20 分钟到 sanity 收敛
uv run sim2lerobot rl train --max_iterations 1500
# 从本地 checkpoint 继续训练
uv run sim2lerobot rl train \
--resume data/lift_cube/rl/latest.pt \
--max_iterations 2000
# 输出:
# data/lift_cube/rl/{run_id}/model_<iter>.pt (run_id 默认时间戳)
# data/lift_cube/rl/latest.pt -> 上面那个最终 checkpoint监控训练进度:
bash
tensorboard --logdir data/lift_cube/rl/
# 浏览器打开 http://localhost:6006关键指标:
Metrics/success_rate:上升到 ~0.8-1.0(可以 rollout)Train/mean_reward:上升,收敛到 ~15-20Train/mean_episode_length:下降(学会快速完成任务)
收敛判断:success_rate 达到 0.8+ 即可 rollout(100% 不是必需的,失败轨迹也有价值)。
注意:
- 训练 100 次迭代通常不够,success_rate 会保持在 0%
- 建议至少训练 1500 次迭代以达到合理的成功率
- 预训练权重会自动下载到
data/.pretrained_checkpoints/目录(已 gitignore)
2. Rollout 录制
bash
# 使用 NVIDIA 预训练权重 rollout(推荐)
uv run sim2lerobot rl rollout \
--checkpoint data/.pretrained_checkpoints/rsl_rl/Isaac-Lift-Cube-Franka-v0/Assets/Isaac/6.0/Isaac/IsaacLab/PretrainedCheckpoints/rsl_rl/Isaac-Lift-Cube-Franka-v0/checkpoint.pt \
--num_demos 100 \
--num_envs 32
# 或使用本地训练的 checkpoint
uv run sim2lerobot rl rollout \
--checkpoint data/lift_cube/rl/latest.pt \
--num_demos 100 \
--num_envs 32
# 录制视频(每 10 个 episode 录一个)
uv run sim2lerobot rl rollout \
--checkpoint data/lift_cube/rl/latest.pt \
--num_demos 100 \
--num_envs 32 \
--video --video_interval 10
# 检查 schema
uv run h5_inspect data/lift_cube/rl/{run_id}/episodes.hdf5注意:
- 预训练权重路径较长,首次使用时会自动下载
- 可以先运行一次训练脚本的
--resume pretrained来触发下载 rollout_and_record.py只读取 checkpoint,不会修改或覆盖权重文件- 默认只导出成功的 episode(
success=True),使用--keep_failed保留失败轨迹
关键设计:训练 joint_pos / 录制时换 IK-abs
为什么这么做
- IsaacLab 只对
Isaac-Lift-Cube-Franka-v0(joint_pos) 注册了 PPO cfg;Isaac-Lift-Cube-Franka-IK-Abs-v0没有 RL agent cfg - PPO 直接学 7d EE pose(含 4d unit quat)的 box action space 不收敛
- 工程最干净的方案:复用 IsaacLab 验证过的 joint_pos PPO 配方,把 action 空间对齐挪到 rollout 阶段当数据后处理做
怎么实现的
src/sim2lerobot/sources/rl/recorders.py 里两个自定义 RecorderTerm:
- IKAbsActionRecorder:每步从
ee_framesensor 当前 EE pose + finger joint 状态二值化拼成 8d IK-abs action,覆写默认的actions列 - PolicySplitObsRecorder:rollout 时
concatenate_terms=True(PPO 网络硬要求 1-D 输入),本 term 按ObservationManager.group_obs_term_dim["policy"]把 1-D obs 切回 dict,同时用上面的 8d action 替换 actions term(原 9d joint_pos last_action)
详细推理见 Obs/Action 对齐 末尾"src/sim2lerobot/sources/rl 实现细节"。
Reward 组成
PPO 训练的 reward 来自 IsaacLab/.../lift/lift_env_cfg.py 的 RewardsCfg:
| Reward Term | Weight | 说明 |
|---|---|---|
reaching_object | 1.0 | EE 接近 cube 的距离奖励 |
lifting_object | 15.0 | cube 高度奖励(z 轴越高越好) |
object_goal_tracking | 16.0 | cube 接近目标位置的距离奖励 |
object_goal_tracking_fine_grained | 5.0 | 精细化目标跟踪 |
action_rate_l2 | -1e-4 | action 变化率惩罚(平滑控制) |
joint_vel_l2 | -1e-4 | 关节速度 L2 惩罚 |
训练过程:
- 早期:policy 随机动作 → 偶尔 EE 靠近 cube → 获得 reaching reward → 学会"靠近 cube"
- 中期:学会靠近 → 偶尔抓住 cube → 获得 lifting reward → 学会"抓住并举起"
- 后期:学会举起 → 偶尔放到目标 → 获得 tracking reward → 学会"放到目标位置"
代码结构
| 文件 | 作用 |
|---|---|
src/sim2lerobot/sources/rl/train.py | RSL-RL PPO 训练入口(精简版,不走 IsaacLab hydra 流程) |
src/sim2lerobot/sources/rl/rollout_and_record.py | 加载 checkpoint + 挂 RecorderManager + rollout 录数据 |
src/sim2lerobot/sources/rl/env_cfg.py | 训练 / rollout 两个 env_cfg 工厂(共享同一 task,差异在 obs concat 与 recorders) |
src/sim2lerobot/sources/rl/recorders.py | 自定义 IKAbsActionRecorder / PolicySplitObsRecorder |
关键函数:
train.py:build_agent_cfg()— 构造 PPO agent 配置(obs_groups / actor / critic)rollout_and_record.py:main()— Rollout 主循环:加载 checkpoint,循环 policy(obs)recorders.py:_compute_ik_abs_equivalent_action()— 核心逻辑:EE pose + finger joint → 8d IK-abs
常见问题
Q: 为什么训练用 joint_pos 但写盘用 IK-abs?
A:
- IsaacLab 只对 joint_pos task 注册了 PPO cfg(IK-Abs 没有)
- PPO 直接学 7d EE pose(含 4d unit quat)不收敛
- 录制层重写 action 是工程上最干净的方案:训练路径不变,只在写盘时做等价转换
Q: 为什么 rollout 时 concatenate_terms=True?
A: PPO 网络(MLPModel)硬要求 1-D obs 输入。训练和 rollout 必须用同一份网络结构,所以 rollout 也要 concat。自定义 PolicySplitObsRecorder 在写盘时把 1-D obs 切回 dict。
Q: IKAbsActionRecorder 写的 action 跟 PPO 输出的 action 有什么关系?
A:
- PPO 输出:9d joint_pos(7 panda joints + 2 fingers)
- IKAbsActionRecorder 写盘:8d IK-abs(当前 EE pose + gripper 二值化)
- 两者是"等价"的:PPO 的 9d joint_pos 执行后,EE 会到达某个 pose,IKAbsActionRecorder 记录的就是这个 pose
Q: 从头训练为什么不收敛?
A: 实验发现从头训练即使 1500 次迭代也无法收敛(成功率始终为 0)。可能的原因:
- 超参数配置需要调整(学习率、batch size、reward 权重等)
- 需要更多训练时间(>3000 次迭代?)
- 随机种子或初始化问题
- 环境配置与 NVIDIA 训练时有差异
强烈建议:
- 使用 NVIDIA 预训练权重直接 rollout(虽然成功率 ~3-5%,但至少可用)
- 或从预训练权重 fine-tune(
--resume pretrained)而不是从头训练 - 如果必须从头训练,需要投入大量时间调试超参数
Q: NVIDIA 预训练权重的成功率为什么这么低(~3-5%)?
A: 这是正常现象:
- RL policy 本身就不是 100% 成功率(探索-利用权衡)
- 失败轨迹也有价值(recovery 数据)
- 可以通过增加
--num_envs和运行时间来收集更多成功 episode - 如果需要更高成功率,可以从预训练权重继续训练(fine-tune)
数据价值:Recovery 轨迹
/\
/ \ Teleop (10²–10³ 条)
/ \ 高质量,但慢
/------\
/ RL \ (10³–10⁴ 条)
/ recovery\ 自然产生 recovery / 长尾
/------------\
/ Scripted \ (10⁵+ 条)
/________________\ 量大,覆盖底座技能RL 的价值:
- Recovery 轨迹:cube 掉了 → 重新抓;抓歪了 → 调整姿态
- 长尾分布:scripted 永远不会产生的"意外情况"
- 探索期数据:训练早期的"乱试"轨迹,覆盖更广的状态空间
为什么 recovery 重要?
- BC 模型在部署时会遇到 distribution shift(实际状态 ≠ 训练数据)
- 有 recovery 数据 → 模型学会"出错后怎么纠正"
- 没 recovery 数据 → 模型一旦偏离就崩溃
注意事项
训练相关
- 从头训练不推荐:实验表明即使 1500 次迭代也无法收敛(成功率 0%)
- 优先使用预训练权重:NVIDIA 提供的预训练权重虽然成功率低(~3-5%)但至少可用
- 训练耗 GPU 时(默认 1024 envs,A100 上 1500 iters ~15-20 分钟)
- 如果必须从头训练,建议:
- 增加迭代数到 3000+
- 调整超参数(学习率、reward 权重等)
- 监控
Metrics/success_rate指标,确保在训练过程中上升
Rollout 相关
rollout_and_record.py的--num_envs 32是经验值——更高吞吐但显存敏感- 预训练权重成功率低(~3-5%)是正常的,可以通过增加
--num_envs和运行时间收集更多成功 episode - 默认只导出成功 episode(
success=True),使用--keep_failed保留失败轨迹用于 recovery 数据 - 推荐先跑通
src/sim2lerobot/sources/scripted再来这步——scripted 提供 sanity check 的 baseline
Checkpoint 管理
- 训练产生的 checkpoint 在
data/lift_cube/rl/{run_id}/model_*.pt(run_id 默认时间戳,每次训练落独立 run 目录,不再覆盖) data/lift_cube/rl/latest.pt是指向最近一次 train run 最终 checkpoint 的 symlink- 预训练权重下载到
data/.pretrained_checkpoints/(已 gitignore) rollout_and_record.py只读取 checkpoint,不会修改或覆盖权重文件
参考
- L2 三种轨迹来源 §2
- Obs/Action 对齐 "src/sim2lerobot/sources/rl 实现细节"
- 快速开始