本仓库是在 3D Diffusion Policy (DP3) 基础上实现并整理的 RL-100 版本,包含:
- DP3 行为克隆训练与评测
- RL-100 的
IL -> Offline RL -> Online RL三阶段训练 - MetaWorld / Adroit / DexArt 演示数据采集脚本
- DDIM 主策略与 Consistency Model 的评测入口
论文:
核心代码位于 3D-Diffusion-Policy:
- train_rl100.py:RL-100 训练入口
- eval_rl100.py:RL-100 单 checkpoint 评测入口
- rl100.yaml:RL-100 主配置
- config/task:各任务配置
- scripts:数据采集、DP3 训练与评测脚本
环境配置 直接沿用 DP3,这里没有额外改动。
- 安装说明见 INSTALL.md
- 常见报错见 ERROR_CATCH.md
如果你已经能正常跑 DP3,就可以直接跑 RL-100。
所有演示数据默认写入 3D-Diffusion-Policy/data。
脚本: gen_demonstration_metaworld.sh
bash scripts/gen_demonstration_metaworld.sh dial-turn
bash scripts/gen_demonstration_metaworld.sh basketball sparse
bash scripts/gen_demonstration_metaworld.sh push dense说明:
- 第一个参数是 MetaWorld 任务名
- 第二个参数是奖励类型,默认
sparse - 当前脚本固定采集
100个 episode
脚本: gen_demonstration_adroit.sh
bash scripts/gen_demonstration_adroit.sh door
bash scripts/gen_demonstration_adroit.sh hammer
bash scripts/gen_demonstration_adroit.sh pen说明:
- 当前脚本固定采集
10个 episode - 依赖
third_party/VRL3/ckpts/下的 expert checkpoint
脚本: gen_demonstration_dexart.sh
bash scripts/gen_demonstration_dexart.sh laptop
bash scripts/gen_demonstration_dexart.sh faucet
bash scripts/gen_demonstration_dexart.sh bucket
bash scripts/gen_demonstration_dexart.sh toilet说明:
- 当前脚本固定采集
100个 episode - 依赖
third_party/dexart-release/assets/rl_checkpoints/
如果你的真机演示数据是:
data/action:(K, 13)data/right_state:(K, 13)data/rgbm:(K, H, W, 4)data/right_cam_img:(K, H, W, 3)meta/episode_ends:(J,)
可以直接转换成 RL-100 训练用 zarr:
python scripts/convert_real_robot_hdf5_to_zarr.py \
--input /path/to/real_robot_demo.hdf5 \
--output 3D-Diffusion-Policy/data/realrobot_dualcam13dof.zarr \
--overwrite默认会把 rgbm 和 right_cam_img resize 到 84x84,并把 RGB 归一化到 [0, 1]。
如果你想保留原分辨率,可以把 --resize-height 和 --resize-width 设成 0。
如果你的原始数据直接来自 /home/yrz/dex-data-collection 的采集输出,也就是每个 episode 一个 .pkl,包含:
episode_ur5e_pos_eef或episode_ur5e_pos_jepisode_inspire_hand_posepisode_l515_colorepisode_orbbec_femto_bolt_color
可以直接转换成 RL100/QAM 可训练的 zarr:
python scripts/convert_dex_data_collection_pkl_to_zarr.py \
--input-dir /path/to/raw_dexcollector_pkls \
--output /path/to/realrobot_pick_place_dexcollector.zarr \
--arm-source eef \
--action-source next_state \
--head-camera-key episode_orbbec_femto_bolt_color \
--wrist-camera-key episode_l515_color \
--hand-encoding normalized_minus1_1 \
--mask-mode zeros \
--resize-height 224 \
--resize-width 224 \
--overwrite这条脚本默认做了几件事:
right_state[t] = [ur5e_state(t), inspire_hand_state(t)]action[t] = right_state[t+1]- 最后一帧会重复最后一个状态
- 头相机写成
rgbm- 前
3通道是归一化后的图像 - 第
4通道是常量 mask
- 前
- 腕部相机写成
right_cam_img - hand 的后
6维默认从原始0~2000映射到[-1, 1] - zarr 直接按“只沿时间维 chunk”写出,不需要再单独 rechunk
如果你现在手里只有师兄已经处理好的 zarr,例如:
data/actiondata/right_statedata/rgbmdata/right_cam_imgmeta/episode_ends
可以先再做一层“训练友好版”预处理:
python scripts/preprocess_real_robot_zarr.py \
--input /path/to/dex-data.zarr \
--output 3D-Diffusion-Policy/data/dex-data-train84.zarr \
--resize-height 84 \
--resize-width 84 \
--process-batch-size 32 \
--overwrite如果你希望预处理阶段就把 sparse terminal reward/done 也写进去,可以加:
python scripts/preprocess_real_robot_zarr.py \
--input /path/to/dex-data.zarr \
--output 3D-Diffusion-Policy/data/dex-data-train84.zarr \
--resize-height 84 \
--resize-width 84 \
--write-terminal-labels \
--overwrite推荐先缩到 84x84 再跑,原因很直接:
- 当前
RealRobotDataset默认历史实现会把 replay 复制到内存 - 这份数据有
79799帧、双相机 - 即便只是 RGB
uint8,224x224也会非常大 - 现在仓库已经给
RealRobotDataset加了zarr直读后端,但第一版建议仍然用84x84,更稳
对应的固定数据集训练 preset:
只跑 IL:
cd 3D-Diffusion-Policy
python train_rl100.py \
--config-name rl100_qam_pick_place_processed \
training.num_offline_iterations=0 \
training.run_online_rl=false跑一版固定数据集的 QAM offline RL:
cd 3D-Diffusion-Policy
python train_rl100.py --config-name rl100_qam_pick_place_processed默认数据路径已经写在 realrobot_pick_place_processed.yaml:
dataset_zarr_path: data/dex-data-train84.zarr
use_mask: false
use_right_cam_img: true如果你想临时换数据,不需要改文件,也可以命令行覆盖:
python train_rl100.py \
--config-name rl100_qam_pick_place_processed \
task.dataset_zarr_path=/path/to/other.zarr观测输入用两个接口切换:
python train_rl100.py \
--config-name rl100_qam_pick_place_processed \
task.use_mask=false \
task.use_right_cam_img=false这两个开关的含义:
use_mask=false, use_right_cam_img=false:right_state + rgbm[..., :3],默认推荐第一版使用use_mask=true, use_right_cam_img=false:right_state + rgbm,使用第三视角 RGB+maskuse_mask=false, use_right_cam_img=true:right_state + rgbm[..., :3] + right_cam_imguse_mask=true, use_right_cam_img=true:right_state + rgbm + right_cam_img,恢复之前最重的双相机+mask输入
use_mask=false 不要求 zarr 里真的有 data/head_rgb。当前 dataset 会从现有 data/rgbm 自动取前三通道生成。
如果确实需要手动指定 obs key,也保留了高级覆盖:
python train_rl100.py \
--config-name rl100_qam_pick_place_processed \
task.obs_mode=head_rgb_right_cam这个 preset 的特点是:
training.offline_collect_new_data=falsecollection_episodes=0task.env_runner=null- offline RL 只在固定 zarr 上训练 critics + QAM actor
- 不做 rollout
- 不做 merge
- 不做 collection 后的 IL retrain
如果你只想跑原始 DP3 行为克隆流程,可以继续用原脚本。
脚本: train_policy.sh
bash scripts/train_policy.sh dp3 metaworld_dial-turn exp1 0 0
bash scripts/train_policy.sh dp3 adroit_hammer exp1 0 0
bash scripts/train_policy.sh simple_dp3 dexart_laptop exp1 0 0参数顺序:
- 算法名:
dp3或simple_dp3 - 任务名:例如
metaworld_dial-turn - 附加字符串:用于组成实验名
- 随机种子
- GPU id
脚本: eval_policy.sh
bash scripts/eval_policy.sh dp3 metaworld_dial-turn exp1 0 0RL-100 不走 shell 脚本,直接用 Hydra 入口。
先进入项目目录:
cd 3D-Diffusion-Policypython train_rl100.py task=metaworld_dial-turn仓库新增了一个真机模板任务:
它默认使用:
right_state作为低维 proprio 输入rgbm作为头相机4通道输入right_cam_img作为腕部相机3通道输入action维度13task.execution.enable_eval=false,训练过程中不做真机 evaltask.execution.enable_amq=false,offline RL 跳过 AM-Q / OPE gatetask.execution.enable_cm_policy=false,禁用 consistency-model runtime policytask.execution.stop_env_on_keyboard_interrupt=true,Ctrl+C时对 env 做 best-effort stop
如果只想先验证离线 IL,可直接关掉 rollout 阶段:
cd 3D-Diffusion-Policy
python train_rl100.py \
task=realrobot_dualcam13dof \
training.num_offline_iterations=0 \
training.run_online_rl=false如果要跑真机 offline-collection / online RL,需要在配置里给 task.env_runner.env 提供真实机器人环境:
python train_rl100.py \
task=realrobot_dualcam13dof \
task.env_runner.env._target_=your_robot_pkg.envs.YourRealRobotEnv如果你之后想显式打开真机评测或 cm,可以在命令行覆盖:
python train_rl100.py \
task=realrobot_dualcam13dof \
task.execution.enable_eval=true \
task.execution.enable_cm_policy=true这个 env 需要至少提供:
reset() -> obs_dict或(obs_dict, info)step(action) -> obs_dictstep(action) -> (obs_dict, info)step(action) -> (obs_dict, reward, done, info)step(action) -> (obs_dict, reward, terminated, truncated, info)
其中 obs_dict 的 key 需要和 task 配置一致,例如:
right_statergbmright_cam_img
如果你后面直接把项目拷到连着 UR5e 的电脑上,推荐用这套配置:
- realrobot_pick_place_dexcollector.yaml
- rl100_qam_pick_place_dexcollector.yaml
- rl100_qam_pick_place_offline_ur5e.yaml
这套配置默认假定:
- 第一版 offline RL 可以直接从已经处理好的
data/dex-data-train84.zarr启动 action/right_state都是12维- 前
6维是 UR5e joint,按[-2π, 2π] -> [-1, 1]归一化 - 后
6维是 Inspire hand,按[0, 2000] -> [-1, 1]归一化 - rollout 真机执行也用
UR5e + Inspire + Orbbec + L515 - 默认观测输入和 processed 版本保持一致:
task.use_mask=falsetask.use_right_cam_img=true- 也就是
right_state + rgbm[..., :3] + right_cam_img
真机执行时 env 会把 policy 输出的前 6 维 normalized joint 反解成 UR5e 弧度 joint,再通过 RTDE 下发;采集到的新 rollout 仍按 rgbm/right_cam_img/right_state/action/reward/done 写回 zarr,和师兄处理后的数据格式对齐。
如果要在 dexcollector 真机路径里打开 mask 或腕部相机,也用同样两个接口:
python train_rl100.py \
--config-name rl100_qam_pick_place_dexcollector \
task.use_mask=true \
task.use_right_cam_img=true注意:当前 raw .pkl 转换脚本默认只能写常量 mask。除非你同时接入师兄的 segmask 生成结果,否则不建议打开 task.use_mask=true。
关键路径都暴露成了环境变量,迁到机械臂电脑后直接改:
export REALROBOT_ZARR_PATH=/path/to/realrobot_pick_place_dexcollector.zarr
export UR5E_IP=192.168.1.109
export INSPIRE_HAND_PORT=/dev/ttyUSB0
export REALROBOT_HEAD_CAMERA=orbbec_femto_bolt
export REALROBOT_WRIST_CAMERA=l515
export REALROBOT_HEAD_MASK_MODE=zeros
export REALROBOT_ARM_ACTION_MODE=joint
export REALROBOT_ARM_STATE_MODE=joint
export REALROBOT_ARM_ENCODING=normalized_minus1_1
export REALROBOT_HAND_ENCODING=normalized_minus1_1只跑 IL:
cd 3D-Diffusion-Policy
python train_rl100.py \
--config-name rl100_qam_pick_place_dexcollector \
training.num_offline_iterations=0 \
training.run_online_rl=false跑 IL + offline RL + 真机 rollout:
cd 3D-Diffusion-Policy
python train_rl100.py \
--config-name rl100_qam_pick_place_offline_ur5e \
training.resume_path=/path/to/your_il.ckpt \
task.dataset_zarr_path=data/dex-data-train84.zarr \
training.num_offline_iterations=1 \
training.collection_episodes=1这个 preset 默认比较保守:
num_offline_iterations=1collection_episodes=1eval_episodes=1runtime.collection_policy=flowtraining.resume_load_rl_state=false,即从 IL policy 开始,critics/QAM optimizer 重新初始化
避免第一次上真机就沿用仿真里的大规模采样设置。
python train_rl100.py \
task=metaworld_dial-turn \
training.seed=0 \
training.device=cuda:0 \
logging.use_wandb=true \
task.env_runner.eval_episodes=100python train_rl100.py \
task=metaworld_dial-turn \
training.resume=true \
training.resume_path=/path/to/checkpoints/after_il.ckpttrain_rl100.py 默认执行以下流程:
IL:先用 demonstration 训练 DP3/RL100 policyOffline RL:训练 transition model、IQL critics、offline PPO,并做 OPE gateData Collection + IL Retrain:收集新轨迹并并回数据集,再做 IL retrainOnline RL:对 fresh rollout 做 on-policy PPO + GAEFinal Eval:按配置评测ddim和/或cm
如果你把:
training.offline_collect_new_data=falsetraining.collection_episodes=0
那第 2 阶段会变成“固定数据集 offline RL”:
- 仍然训练 critics
- 仍然训练 PPO 或 QAM actor
- 但跳过 rollout / merge / IL retrain
相关主配置见 rl100.yaml。
脚本入口: eval_rl100.py
python eval_rl100.py \
task=metaworld_dial-turn \
checkpoint_path=/path/to/checkpoints/final.ckpt \
runtime.eval_policy_mode=ddim \
runtime.eval_use_ema=false \
task.env_runner.eval_episodes=100python eval_rl100.py \
task=metaworld_dial-turn \
checkpoint_path=/path/to/checkpoints/final.ckpt \
runtime.eval_policy_mode=ddim \
runtime.eval_use_ema=true \
task.env_runner.eval_episodes=100python eval_rl100.py \
task=metaworld_dial-turn \
checkpoint_path=/path/to/checkpoints/final.ckpt \
runtime.eval_policy_mode=cm \
runtime.eval_use_ema=true \
task.env_runner.eval_episodes=100训练输出目录由 Hydra 管理,默认在:
3D-Diffusion-Policy/outputs/rl100_<task>_seed<seed>/<date>_<time>/其中通常包含:
checkpoints/after_il.ckptcheckpoints/offline_iter_<N>.ckptcheckpoints/online_iter_<N>.ckptcheckpoints/final.ckptplots/下的各类 loss / success 曲线
常用项基本都在 rl100.yaml:
training.num_offline_iterationstraining.offline_collect_new_datatraining.critic_epochstraining.ppo_epochstraining.ppo_inner_stepstraining.collection_episodestraining.online_rl_iterationstraining.online_collection_episodestraining.rl_policy_lrruntime.collection_policyruntime.collection_use_emaruntime.il_retrain_success_onlyruntime.final_eval_policiesruntime.final_eval_use_ematask.env_runner.eval_episodes
任务数据路径、观测维度、评测 episode 数在各自 task yaml 里定义,例如:
最终训练评测和 eval_rl100.py 都直接读取 task.env_runner.eval_episodes。
如果要改评测轮数,改 task yaml 或在命令行覆盖:
python train_rl100.py task=metaworld_dial-turn task.env_runner.eval_episodes=100当前逻辑是:
- offline RL / online RL 都使用完整采样轨迹,包括失败轨迹
success-only只作用于后续IL retrain的数据筛选
这和 RL 训练、IL 重训的语义已经拆开了。
RL-100 的 PPO ratio 计算依赖 epsilon 参数化。当前配置已固定为:
policy:
noise_scheduler:
prediction_type: epsilon不要改成 sample。
根据 RL-100 论文 2510.14830 v4 的消融结论,stochastic DDIM 的标准差上界需要按控制模式区分:
sigma_max = 0.8- Adroit
- Mujoco locomotion
- 真机单步控制任务
sigma_max = 0.1- MetaWorld
- 真机 chunk-action 控制任务
仓库当前默认:
policy:
sigma_max: 0.1这适合 MetaWorld / chunk-action。
如果你做真机单步控制,应该按论文建议改到 0.8。
当前 MetaWorld 演示脚本默认是:
bash scripts/gen_demonstration_metaworld.sh <task> sparse如果你要跑 dense,需要保证:
- 采集脚本真的生成了 dense reward
- 配置里的
critics.reward_type与数据一致
不要拿 sparse 数据去伪装 dense reward。
RL-100 论文里的真机 rollout 本身就是“人工给 sparse success signal”;仓库里的真机 runner 也按这个思路实现了。默认真机模板配置是:
task.env_runner.reward_mode=terminal_sparse_manualtask.env_runner.episode_end_mode=env_or_manual_or_max_steps
也就是:
- 每个 episode 的中间步 reward 默认全是
0 - episode 结束时,如果人工标记成功,则终止步 reward=
1 - 如果人工标记失败,则终止步 reward=
0 - episode 可以由 env 自己结束、达到
max_steps结束,或者每个 action chunk 后人工决定continue/success/failure - 当前终端输入兼容
c继续、1/s成功结束、0/f失败结束
这更接近主流真机 RL 在“没有可靠 success classifier 时”的做法。
如果你之后接入了自动 success classifier / 自动 reset 逻辑,可以切到:
task.env_runner.reward_mode=terminal_sparse_env_successtask.env_runner.episode_end_mode=env_or_max_steps
如果 checkpoint 不是用 Recon/VIB 训练出来的,不要直接在中途打开:
policy:
use_recon_vib: true这会把随机初始化的 decoder/VIB 分支引进来,破坏已有 policy。
如果要用,应该从 demonstration 开始重新训练。
- 训练时真正反向更新的是主模型
policy ema_policy是主模型参数的指数滑动平均- 最终评测是否用 EMA,取决于:
runtime.final_eval_use_emaruntime.eval_use_ema
如果不想用 WandB,直接在配置里关掉:
python train_rl100.py task=metaworld_dial-turn logging.use_wandb=false- RL-100 代码说明: RL100_README.md
- DP3 安装说明: INSTALL.md
- 安装踩坑记录: ERROR_CATCH.md
如果这个仓库对你有帮助,可以引用:
@inproceedings{Ze2024DP3,
title={3D Diffusion Policy: Generalizable Visuomotor Policy Learning via Simple 3D Representations},
author={Yanjie Ze and Gu Zhang and Kangning Zhang and Chenyuan Hu and Muhan Wang and Huazhe Xu},
booktitle={Proceedings of Robotics: Science and Systems (RSS)},
year={2024}
}
@article{lei2025rl100,
title={RL-100: Performant Robotic Manipulation with Real-World Reinforcement Learning},
author={Lei, Kun and Li, Huanyu and Yu, Dongjie and Wei, Zhenyu and Guo, Lingxiao and Jiang, Zhennan and Wang, Ziyu and Liang, Shiyu and Xu, Huazhe},
journal={arXiv preprint arXiv:2510.14830},
year={2025}
}