pi05-so101-erythromycin-tea / SO101_PI05_HANDOFF.md
CodeChild's picture
Add model card, deployment handoff, licenses, and release code patch
e30919b verified
|
Raw
History Blame Contribute Delete
18.6 kB

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 和代码来源

仓库:

/home2/czj/AutoResearch/real_machine/so_arm101/openpi_so101_pi05

最终 checkpoint:

/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:

15a9616a00943ada6c20a0f158e3adb39df2ccac

可移植性提醒: SO-101 policy、数据 split 读取和训练脚本目前包含本地尚未提交的适配代码。仅上传权重并指向干净的上游 commit,不能保证能识别 pi05_so101_erythromycin 配置。上传 Hugging Face 前,应把这些修改形成一个可检出的 Git commit/tag,或随模型仓库提供完整 patch,至少覆盖:

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. 数据、划分和任务

数据包:

/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 视频。训练必须以此文件为准:

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_01setting_09setting_12setting_17setting_21setting_29。当前没有独立 test split,clean_val 仍可能参与 checkpoint 选择,因此不能把它称为最终无偏测试集。

任务 prompt 必须保持完全一致:

Pick up the red erythromycin ointment box and place it on top of the green Rizhao tea tin.

4. 输入 schema 和相机处理

policy server 的单次输入:

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 是:

delta_action_mask = (True, True, True, True, True, False)

设发起推理时当前状态为 s,数据中的第 t 个绝对目标为 a[t]。训练输入模型前执行:

d[t, 0:5] = a[t, 0:5] - s[0:5]
d[t, 5]   = a[t, 5]

这里 50 个未来目标全部减去同一个当前状态 s。它不是:

a[t] - a[t-1]

也不是每步速度。因此绝对不能沿时间轴对模型结果做 cumulative sum。

推理时 OpenPI 的输出 transform 会执行相反操作:

a_hat[t, 0:5] = d_hat[t, 0:5] + s[0:5]
a_hat[t, 5]   = d_hat[t, 5]

随后移除模型内部 padding,只返回前 6 维。所以外部收到:

result["actions"].shape == (50, 6)

result["actions"] 已经是机器人校准空间中的 absolute position targets。机器人客户端只需验证、限幅并按顺序下发;不要再次加 state,不要 cumsum

7. 30 Hz 和 50-step action chunk

训练 action chunk 按数据集的 30 Hz 采样:

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,再选择空闲设备:

nvidia-smi

从仓库根目录启动:

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 请求,并断言:

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 前,不能声称该模型已经可以可靠完成任务。

复现最终模型离线验证:

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.9b2=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 根目录至少包含:

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

只有在确实需要继续训练时才额外上传:

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 中包含:
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 的成功/失败和安全事件完整记录。