Skip to content

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-20
  • Train/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

  1. IKAbsActionRecorder:每步从 ee_frame sensor 当前 EE pose + finger joint 状态二值化拼成 8d IK-abs action,覆写默认的 actions
  2. 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.pyRewardsCfg

Reward TermWeight说明
reaching_object1.0EE 接近 cube 的距离奖励
lifting_object15.0cube 高度奖励(z 轴越高越好)
object_goal_tracking16.0cube 接近目标位置的距离奖励
object_goal_tracking_fine_grained5.0精细化目标跟踪
action_rate_l2-1e-4action 变化率惩罚(平滑控制)
joint_vel_l2-1e-4关节速度 L2 惩罚

训练过程

  • 早期:policy 随机动作 → 偶尔 EE 靠近 cube → 获得 reaching reward → 学会"靠近 cube"
  • 中期:学会靠近 → 偶尔抓住 cube → 获得 lifting reward → 学会"抓住并举起"
  • 后期:学会举起 → 偶尔放到目标 → 获得 tracking reward → 学会"放到目标位置"

代码结构

文件作用
src/sim2lerobot/sources/rl/train.pyRSL-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 训练时有差异

强烈建议

  1. 使用 NVIDIA 预训练权重直接 rollout(虽然成功率 ~3-5%,但至少可用)
  2. 或从预训练权重 fine-tune(--resume pretrained)而不是从头训练
  3. 如果必须从头训练,需要投入大量时间调试超参数

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,不会修改或覆盖权重文件

参考