Instructions to use CodeChild/pi05-so101-erythromycin-tea with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use CodeChild/pi05-so101-erythromycin-tea with LeRobot:
- Notebooks
- Google Colab
- Kaggle
| # SO-101 pi0.5 训练与真机部署交接 | |
| 更新时间:2026-08-04 | |
| 状态:8000-step 微调和离线评估已完成;**尚未进行真机闭环验证**。 | |
| 本文是当前 checkpoint 的权威交接说明。文中将训练时已经确定的事实和首次上真机的建议明确分开。任何真机客户端都必须先读完“动作语义”和“首次上机流程”,尤其不能把服务端返回值再次当作 delta 累加。 | |
| ## 1. 一页摘要 | |
| | 项目 | 当前结果 | | |
| | --- | --- | | |
| | 任务 | `Pick up the red erythromycin ointment box and place it on top of the green Rizhao tea tin.` | | |
| | 模型 | OpenPI pi0.5 base,全参数微调 | | |
| | 最终 checkpoint | `checkpoints/pi05_so101_erythromycin/pi05_so101_stage1_wandb/7999` | | |
| | 训练量 | 8000 次 optimizer update,batch size 8 | | |
| | 推理参数 | EMA 参数,`ema_decay=0.99` | | |
| | 训练数据 | `clean_train`:67 episodes / 15070 frames | | |
| | 验证数据 | `clean_val`:18 episodes / 3972 frames | | |
| | 未使用数据 | `recovery`:5 episodes / 1515 frames | | |
| | 相机 | 固定相机 `fixed` + 腕部相机 `wrist`,RGB 640x480 @ 30 FPS | | |
| | 状态/动作 | 6 维 SO-101 校准后位置空间 | | |
| | 动作表示 | 前 5 维在模型内部为相对当前 state 的 delta;第 6 维夹爪为 absolute | | |
| | 服务端输出 | `(50, 6)`,已经还原为 SO-101 **绝对目标** | | |
| | 数据/控制频率 | 30 Hz,约 33.33 ms/step | | |
| | 预测 horizon | 50 steps;50 个控制 tick 约 1.667 s | | |
| | 首次真机建议 | 30 Hz 执行,每次只执行前 5 steps 后重规划;这是建议,不是已验证参数 | | |
| | W&B | <https://wandb.ai/99087192-zhejiang-university/openpi/runs/xgk0h74f> | | |
| 最重要的三点: | |
| 1. policy server 返回的动作已经是 absolute,机器人端不要 `cumsum`,也不要再次加当前 state。 | |
| 2. 训练数据是 30 Hz。不能把 50 个目标按 10 Hz 执行,否则同一段轨迹会被拉长约 3 倍。 | |
| 3. 50 是预测长度,不代表首次测试应开环执行完整 50 steps。先执行 5 steps 后重新观测和规划。 | |
| ## 2. Artifact 和代码来源 | |
| 仓库: | |
| ```text | |
| /home2/czj/AutoResearch/real_machine/so_arm101/openpi_so101_pi05 | |
| ``` | |
| 最终 checkpoint: | |
| ```text | |
| /home2/czj/AutoResearch/real_machine/so_arm101/openpi_so101_pi05/checkpoints/ | |
| pi05_so101_erythromycin/pi05_so101_stage1_wandb/7999 | |
| ``` | |
| 目录内容和磁盘占用: | |
| | 目录 | 用途 | 大小 | | |
| | --- | --- | ---: | | |
| | `params/` | 推理必需;保存的是 EMA 参数 | 约 12 GiB | | |
| | `assets/` | 推理必需;包含仅由 `clean_train` 计算的 norm stats | 约 16 KiB | | |
| | `train_state/` | 仅继续训练需要;包含 optimizer state 等 | 约 31 GiB | | |
| | 全部 | 可推理并可续训 | 约 42 GiB | | |
| `7999` 是从 0 开始计数的最终保存 step,对应已经完成 8000 次更新。checkpoint 保存逻辑在存在 EMA 时会将 EMA 参数放进 `params/`,所以 policy server 加载的就是 EMA 推理权重。 | |
| 当前 OpenPI 上游基准 commit: | |
| ```text | |
| 15a9616a00943ada6c20a0f158e3adb39df2ccac | |
| ``` | |
| **可移植性提醒:** SO-101 policy、数据 split 读取和训练脚本目前包含本地尚未提交的适配代码。仅上传权重并指向干净的上游 commit,不能保证能识别 `pi05_so101_erythromycin` 配置。上传 Hugging Face 前,应把这些修改形成一个可检出的 Git commit/tag,或随模型仓库提供完整 patch,至少覆盖: | |
| ```text | |
| src/openpi/policies/so101_policy.py | |
| src/openpi/training/config.py | |
| src/openpi/training/data_loader.py | |
| scripts/compute_so101_norm_stats.py | |
| scripts/eval_so101_checkpoint.py | |
| scripts/run_so101_training.sh | |
| scripts/so101_preflight.py | |
| ``` | |
| ## 3. 数据、划分和任务 | |
| 数据包: | |
| ```text | |
| /home2/czj/AutoResearch/real_machine/so_arm101/ | |
| so101_erythromycin_on_tea_grid90_v2_portable | |
| ``` | |
| 总数据为 90 episodes / 20557 frames / 685.233 s,SO-101 follower,单一语言任务,两路原始 AV1 视频。训练必须以此文件为准: | |
| ```text | |
| splits/split_manifest.json | |
| ``` | |
| 实际划分: | |
| | split | episodes | frames | 是否用于本次训练 | | |
| | --- | ---: | ---: | --- | | |
| | `clean_train` | 67 | 15070 | 是;也只用它计算 norm stats | | |
| | `clean_val` | 18 | 3972 | 只用于离线验证 | | |
| | `recovery` | 5 | 1515 | 否;保留给后续 recovery 实验 | | |
| **绝不能直接使用 `dataset/meta/info.json` 中的 `train: 0:90`。** 那是原始录制范围,不是实验划分;使用它会把 validation 和 recovery 都混入训练。 | |
| `clean_val` 是六个完整 held-out layout settings:`setting_01`、`setting_09`、`setting_12`、`setting_17`、`setting_21`、`setting_29`。当前没有独立 test split,`clean_val` 仍可能参与 checkpoint 选择,因此不能把它称为最终无偏测试集。 | |
| 任务 prompt 必须保持完全一致: | |
| ```text | |
| Pick up the red erythromycin ointment box and place it on top of the green Rizhao tea tin. | |
| ``` | |
| ## 4. 输入 schema 和相机处理 | |
| policy server 的单次输入: | |
| ```python | |
| observation = { | |
| "observation/state": state_float32_6, | |
| "observation/fixed_image": fixed_rgb_uint8_hwc, | |
| "observation/wrist_image": wrist_rgb_uint8_hwc, | |
| "prompt": "Pick up the red erythromycin ointment box and place it on top of the green Rizhao tea tin.", | |
| } | |
| ``` | |
| 约束: | |
| - `state_float32_6.shape == (6,)`。 | |
| - 图像使用 RGB,而不是 OpenCV 默认的 BGR。 | |
| - 最稳妥的图像格式是 `uint8`、HWC、范围 `[0, 255]`;分辨率按采集配置为 640x480。 | |
| - `fixed` 必须对应训练时的固定相机视角,`wrist` 必须对应腕部视角,不得互换、镜像或旋转。 | |
| - OpenPI 内部使用等比例 `resize_with_pad` 变成 224x224,不应在客户端做会改变宽高比的强制拉伸。 | |
| - pi0.5 需要三个图像槽;SO-101 适配会把第三个 `right_wrist_0_rgb` 塞零并设置 `mask=false`。客户端不需要发送第三路图像。 | |
| ### 训练中实际使用的图像增强 | |
| 本次没有添加 SO-101 专用的自定义增强,但 OpenPI 的标准 JAX 训练预处理在 `train=True` 时确实启用: | |
| - 固定相机:95% 随机裁剪后 resize、随机旋转 `[-5 deg, +5 deg]`、颜色扰动; | |
| - 腕部相机:颜色扰动,不做上述随机裁剪和旋转; | |
| - 颜色扰动参数:brightness `0.3`、contrast `0.4`、saturation `0.5`; | |
| - 离线评估和 policy inference 使用 `train=False`,不做随机增强。 | |
| 因此复现实验时不能将本次训练描述成“完全无图像增强”。 | |
| ## 5. 状态、动作顺序和校准 | |
| state 和 action 的六维顺序完全相同: | |
| | index | LeRobot 名称 | 含义 | | |
| | ---: | --- | --- | | |
| | 0 | `shoulder_pan.pos` | shoulder pan | | |
| | 1 | `shoulder_lift.pos` | shoulder lift | | |
| | 2 | `elbow_flex.pos` | elbow flex | | |
| | 3 | `wrist_flex.pos` | wrist flex | | |
| | 4 | `wrist_roll.pos` | wrist roll | | |
| | 5 | `gripper.pos` | gripper | | |
| 这些值不是电机原始 encoder tick,而是 LeRobot SO-101 校准后的 position space:前五维按关节角度使用,夹爪使用线性校准空间,通常映射到约 `[0, 100]`。部署机器必须使用与采集机器一致的关节顺序、方向、零点、角度定义和夹爪标定。 | |
| 不要只因为数值“看起来在范围内”就假设两台机器人标定一致。首次连接时应逐关节读取 state,与已知安全姿态和采集数据样本对照;发现符号、offset 或夹爪开合方向不一致时禁止下发模型动作。 | |
| ## 6. Delta 的精确定义 | |
| 训练配置中的 mask 是: | |
| ```python | |
| delta_action_mask = (True, True, True, True, True, False) | |
| ``` | |
| 设发起推理时当前状态为 `s`,数据中的第 `t` 个绝对目标为 `a[t]`。训练输入模型前执行: | |
| ```text | |
| d[t, 0:5] = a[t, 0:5] - s[0:5] | |
| d[t, 5] = a[t, 5] | |
| ``` | |
| 这里 50 个未来目标全部减去同一个当前状态 `s`。它不是: | |
| ```text | |
| a[t] - a[t-1] | |
| ``` | |
| 也不是每步速度。因此绝对不能沿时间轴对模型结果做 cumulative sum。 | |
| 推理时 OpenPI 的输出 transform 会执行相反操作: | |
| ```text | |
| a_hat[t, 0:5] = d_hat[t, 0:5] + s[0:5] | |
| a_hat[t, 5] = d_hat[t, 5] | |
| ``` | |
| 随后移除模型内部 padding,只返回前 6 维。所以外部收到: | |
| ```python | |
| result["actions"].shape == (50, 6) | |
| ``` | |
| `result["actions"]` 已经是机器人校准空间中的 absolute position targets。机器人客户端只需验证、限幅并按顺序下发;不要再次加 state,不要 `cumsum`。 | |
| ## 7. 30 Hz 和 50-step action chunk | |
| 训练 action chunk 按数据集的 30 Hz 采样: | |
| ```text | |
| control period = 1 / 30 s = 33.33 ms | |
| action horizon = 50 steps | |
| 50 control ticks = 1.667 s | |
| last sampled target offset = 49 / 30 s = 1.633 s | |
| ``` | |
| ### 已确定的事实 | |
| - 模型每次预测 50 个顺序目标。 | |
| - 每个相邻目标的训练时间间隔是 33.33 ms。 | |
| - policy 不会自动决定机器人端执行其中多少个动作。 | |
| - 50-step prediction horizon 不等于必须 50-step open-loop execution。 | |
| ### 首次真机建议,尚未验证 | |
| - 机器人目标下发循环保持 30 Hz。 | |
| - 初始设置执行前缀 `K=5`,即每次预测后执行约 167 ms,再用新图像和新 state 重规划。 | |
| - shadow 和低速测试稳定后,可根据实测推理延迟尝试 `K=5..10`;不要一开始开环执行完整 50 steps。 | |
| - 若采用异步推理,记录 observation timestamp、response timestamp、p50/p95 round-trip latency 和实际控制 jitter。执行前缀至少应覆盖正常的 p95 推理时间;可用 `ceil(p95_latency_seconds * 30)` 估算最低 K,再留少量调度余量。 | |
| - 如果覆盖 p95 延迟所需的 K 已经大于 10,首次上机不应简单增大开环窗口来掩盖问题;应先降低推理/网络延迟,或采用可安全 hold 的同步流程。 | |
| - 丢弃明显过期、乱序或基于旧 observation 的 response。切换到新 chunk 时记录其 observation 序号,避免旧结果覆盖新结果。 | |
| - 不要按 10 Hz 直接执行这 50 个动作;那会把约 1.67 s 的训练轨迹拉成约 5 s。 | |
| `K=5` 是保守起点,不是已经通过真机成功率验证的超参数。最终 K 应由推理延迟、安全性和真实 rollout 数据共同决定。 | |
| ## 8. Policy server 启动 | |
| 在 145 上先检查 GPU,再选择空闲设备: | |
| ```bash | |
| nvidia-smi | |
| ``` | |
| 从仓库根目录启动: | |
| ```bash | |
| CUDA_VISIBLE_DEVICES=<GPU_ID> .venv/bin/python scripts/serve_policy.py \ | |
| policy:checkpoint \ | |
| --policy.config pi05_so101_erythromycin \ | |
| --policy.dir checkpoints/pi05_so101_erythromycin/pi05_so101_stage1_wandb/7999 | |
| ``` | |
| 部署前至少做一次 motors-off 请求,并断言: | |
| ```python | |
| actions = np.asarray(result["actions"]) | |
| assert actions.shape == (50, 6) | |
| assert np.isfinite(actions).all() | |
| ``` | |
| 若从 Hugging Face 下载的是 inference-only snapshot,snapshot 根目录应直接包含 `params/` 和 `assets/`,此时 `--policy.dir` 指向 snapshot 根目录即可。 | |
| ## 9. 真机安全门和首次 rollout 流程 | |
| 以下保护应在机器人客户端实现,不能依赖模型自己学会: | |
| 1. **形状和数值检查:** 必须是 `(50, 6)` 且全部 finite;出现 NaN、Inf、缺帧或超时立即 hold/stop。 | |
| 2. **硬件绝对限位:** 按该台 SO-101 的校准和物理限制 clamp 五个关节;夹爪限制在有效线性标定区间。训练集 q01/q99 不是硬件安全限位。 | |
| 3. **单步变化限制:** 对每个相邻 absolute target 应用 `max_relative_target` 或等价检查,拒绝突跳;同时限制速度和必要的加速度。 | |
| 4. **工作空间约束:** 禁止桌面穿透、自碰撞、相机线缆拉扯和进入人员区域。 | |
| 5. **时序保护:** 30 Hz monotonic scheduler;监测 missed deadline、queue underrun、过期 chunk 和相机/state 时间差。 | |
| 6. **失联行为:** policy server、相机或网络超时后进入定义好的 safe hold/stop,而不是继续无限执行旧 chunk。 | |
| 7. **现场保护:** 低速/低力矩起步、急停可触达、单人专职观察、首次 rollout 不无人值守。 | |
| 推荐按以下顺序放行: | |
| ### 阶段 A:离线接口检查 | |
| - 用一条已录制 observation 请求模型;保存输入图像、state 和 `(50, 6)` 输出。 | |
| - 检查 RGB/BGR、相机顺序、图像方向和 prompt。 | |
| - 画出六维 action chunk,并比较 `actions[0, :5] - state[:5]`;确认没有明显跳变。 | |
| ### 阶段 B:shadow inference,电机不执行 | |
| - 真机按 30 Hz 采集相机和 state,但仅打印/记录模型动作。 | |
| - 统计各维 min/max、最大单步变化、相对当前 state 的最大偏差和推理 p95 latency。 | |
| - 人工确认夹爪开合方向、所有关节符号和目标姿态合理。 | |
| ### 阶段 C:低速闭环 | |
| - 从安全 home pose 开始,桌面清空危险障碍物。 | |
| - `K=5`,30 Hz,开启全部限位和急停,人工全程监护。 | |
| - 先做短时运动并主动停止,再做完整任务。 | |
| ### 阶段 D:正式评估 | |
| - 固定初始姿态、物体布局、光照和相机位置,并记录每次实验配置。 | |
| - 每个 layout 做多次独立 rollout;建议至少 10 次,报告成功数和总次数,而不只展示最好视频。 | |
| - 同时记录抓取成功、最终放置稳定、掉落、碰撞、人工干预、超时和完成时间。 | |
| ## 10. 离线评估结果 | |
| 评估脚本使用 batch size 4、固定随机 seed、无随机图像增强。结果如下: | |
| | 模型 | split | 实际样本数 | flow-matching loss | | |
| | --- | --- | ---: | ---: | | |
| | 原始 pi0.5 base | `clean_val` | 3972 | 0.04753249 | | |
| | 最终微调模型 | `clean_train` | 15068 | 0.00407172 | | |
| | 最终微调模型 | `clean_val` | 3972 | 0.01467515 | | |
| 说明: | |
| - `clean_train` 原有 15070 frames;评估按完整 batch 统计,因此使用 15068 个样本。 | |
| - 相对原始 pi0.5 base,微调模型的 validation loss 降低约 69.126%。 | |
| - 微调模型的 val/train loss 比约为 3.604,存在明显泛化差距。 | |
| - validation 是完整 held-out settings,不与 train 重叠;但没有独立 test split。 | |
| - flow-matching loss 衡量训练目标,不等于抓取成功率、放置成功率或安全性。 | |
| - 在完成受控真机 rollout 前,不能声称该模型已经可以可靠完成任务。 | |
| 复现最终模型离线验证: | |
| ```bash | |
| CUDA_VISIBLE_DEVICES=<GPU_ID> .venv/bin/python scripts/eval_so101_checkpoint.py \ | |
| --checkpoint-dir checkpoints/pi05_so101_erythromycin/pi05_so101_stage1_wandb/7999 \ | |
| --split-name clean_val | |
| ``` | |
| ## 11. 训练配置记录 | |
| W&B run 中记录的实际运行参数优先于源码中的默认值: | |
| | 参数 | 值 | | |
| | --- | --- | | |
| | base weights | `gs://openpi-assets/checkpoints/pi05_base/params` | | |
| | fine-tuning | full parameters,`freeze_filter=Nothing()` | | |
| | updates | 8000 | | |
| | batch size | 8 | | |
| | seed | 42 | | |
| | precision | bfloat16 | | |
| | optimizer | Adam,`b1=0.9`,`b2=0.95`,gradient clip 1.0 | | |
| | LR | warmup 1000,peak `2.5e-5`,配置的 decay horizon 30000 | | |
| | EMA | 0.99 | | |
| | checkpoint interval | 1000;manager 只保留最新 regular checkpoint | | |
| | W&B run ID | `xgk0h74f` | | |
| 训练只运行到 8000 updates,因此 30000-step LR decay schedule 没有完整走完。源码默认训练步数后来仍可显示 30000,不要据此误称本 checkpoint 已训练 30000 steps。 | |
| ## 12. Hugging Face 发布建议 | |
| ### 推荐默认:inference-only,约 12 GiB | |
| 模型 repo 根目录至少包含: | |
| ```text | |
| params/ | |
| assets/ | |
| _CHECKPOINT_METADATA # 建议保留原始 checkpoint 元数据 | |
| README.md # Hugging Face model card | |
| SO101_PI05_HANDOFF.md | |
| LICENSE_GEMMA.txt | |
| NOTICE | |
| LICENSE_OPENPI.txt # 或等价保留 OpenPI Apache-2.0 文本 | |
| ``` | |
| 还应提供一个可复现的 OpenPI code commit/tag 或 patch。该 checkpoint 是 Orbax/OpenPI 格式,不是可直接用 `transformers.AutoModel.from_pretrained()` 加载的标准 Transformers 权重;model card 必须明确要求通过 OpenPI policy loader 使用。 | |
| ### 可选:resumable,约 42 GiB | |
| 只有在确实需要继续训练时才额外上传: | |
| ```text | |
| train_state/ | |
| ``` | |
| 上传 `train_state` 会增加约 31 GiB,并且仍需完全匹配的代码、配置和 optimizer 定义。默认不建议为了推理上传它。 | |
| ### 许可证和数据权限 | |
| - OpenPI 代码为 Apache-2.0。 | |
| - 权重由包含 Gemma 的 pi0.5 派生,发布时不能把整个模型简单标成纯 Apache-2.0。 | |
| - HF model card 建议使用 `license: other`,正文同时说明 OpenPI Apache-2.0 和 Gemma Terms。 | |
| - 分发时保留完整 `LICENSE_GEMMA.txt`,并在 `NOTICE` 中包含: | |
| ```text | |
| Gemma is provided under and subject to the Gemma Terms of Use found at ai.google.dev/gemma/terms | |
| ``` | |
| - 数据包当前明确写着“未分配数据许可证”。除非数据拥有方确认可再分发,否则不要顺手把原始双相机视频或整个数据集上传到公开 HF repo。 | |
| - 发布前由发布者确认 Gemma 条款和数据授权;本文不构成法律意见。 | |
| ### 上传前需要确认的信息 | |
| 1. HF namespace:使用个人账号 `CodeChild`,还是某个 organization。 | |
| 2. model repo 名,例如 `pi05-so101-erythromycin-tea`。 | |
| 3. repo 是 `public` 还是 `private`。 | |
| 4. 上传 inference-only(约 12 GiB,推荐)还是 resumable(约 42 GiB)。 | |
| 5. model card 上的作者、机构、联系方式和希望展示的模型名称。 | |
| 6. 是否有允许公开链接的数据集 repo;若没有,model card 只描述数据,不上传原始数据。 | |
| 7. 是否确认按 Gemma Terms 分发派生权重并保留要求的 notice。 | |
| 8. SO-101 适配代码是发布为 Git commit/tag,还是随模型提供 patch。 | |
| 本机已检测到可用的 Hugging Face 登录,当前身份为 `CodeChild`。不要在聊天中粘贴 access token;如果要换账号,应在本机运行 `hf auth login`,并使用具有目标 namespace write 权限的 token。 | |
| ## 13. 发布和上机前最终 checklist | |
| - [ ] HF repo 中同时有 `params/` 和 `assets/`,norm stats 没有遗漏。 | |
| - [ ] code commit/tag 或 patch 可以构造 `pi05_so101_erythromycin` policy。 | |
| - [ ] model card 明确 Orbax/OpenPI 加载方法、delta 语义、30 Hz 和 50-step horizon。 | |
| - [ ] model card 不把 flow-matching loss 写成真机成功率。 | |
| - [ ] Gemma license 和 `NOTICE` 完整,数据发布权限已确认。 | |
| - [ ] 真机校准、关节顺序、方向和 gripper range 与采集端一致。 | |
| - [ ] fixed/wrist 图像为 RGB、方向正确、时间同步。 | |
| - [ ] 客户端确认输出是 absolute,没有二次加 state 或 `cumsum`。 | |
| - [ ] 30 Hz 调度、`K=5` 初始前缀、超时 hold、限位和急停均已实现。 | |
| - [ ] 完成 motors-off shadow inference 后才进入低速真机测试。 | |
| - [ ] 真机结果按多次 rollout 的成功/失败和安全事件完整记录。 | |