π₀.₅ 是来自 Physical Intelligence 的具有开放世界泛化能力的视觉-语言-action(VLA)模型。LeRobot 的实现改编自其开源 OpenPI 仓库。
π₀.₅ 代表了 π₀ 的一次重大演进,由 Physical Intelligence 开发,旨在解决机器人领域的一大挑战:开放世界泛化。虽然机器人在受控环境中可以完成令人印象深刻的任务,但 π₀.₅ 的设计目标是泛化到训练中从未见过的全新环境和情境。
正如 Physical Intelligence 所解释的,根本挑战不在于完成需要敏捷或灵巧的任务,而在于泛化——即在新环境中用新物体正确执行任务的能力。设想一台正在给不同家庭打扫卫生的机器人:每个家庭的物体各不相同,摆放位置也各异。泛化必须在多个层面上实现:
π₀.₅ 的突破性创新在于异构数据源协同训练。该模型从以下数据中学习:
这种多样化的训练数据组合构建了一个“课程”,使模型能够在物理、视觉和语义层面上同时实现泛化。
按照我们的 安装指南 安装 LeRobot。
运行以下命令安装 Pi0.5 的依赖:
pip install -e ".[pi]"如果你通过 PyPI 安装了 LeRobot:
pip install 'lerobot[pi]'要在你的 LeRobot 配置中使用 π₀.₅,请将 policy 类型指定为:
policy.type=pi05在 lerobot/libero 上 fine-tune LIBERO 基础模型——该 dataset 是下方结果对应的 demonstration 数据的约 1.9 GB 视频编码副本。
它携带了 π₀.₅ 需要读取的键,这些也是 LIBERO 环境在评估时需要生成的键:
| 特征 | dataset 中的形状 | π₀.₅ 的使用方式 |
|---|---|---|
observation.images.image | 256×256×3, agentview | 调整为 224×224 |
observation.images.image2 | 256×256×3, wrist | 调整为 224×224 |
observation.state | 8 | 离散化为 256 个区间并写入提示中 |
action | 7 | 内部填充至 32;损失只使用前 7 个维度 |
这里不需要 --rename_map — 键已经匹配;如果你的键不同,请参阅重命名映射与空相机。
π₀.₅ 使用受门控的 [google/paligemma-3b-pt-224](https://huggingface.co/google/paligemma-3b-pt-224) tokenizer — 请在 Hub 上接受其许可证,并在训练前使用 `hf auth login` 登录。
面向单个 80 GB GPU 设计:
lerobot-train \
--dataset.repo_id=lerobot/libero \
--policy.type=pi05 \
--policy.pretrained_path=lerobot/pi05_libero_base \
--policy.normalization_mapping='{"ACTION": "MEAN_STD", "STATE": "MEAN_STD", "VISUAL": "IDENTITY"}' \
--policy.n_action_steps=10 \
--policy.empty_cameras=1 \
--policy.freeze_vision_encoder=false \
--policy.train_expert_only=false \
--policy.gradient_checkpointing=true \
--policy.dtype=bfloat16 \
--policy.device=cuda \
--policy.push_to_hub=false \
--output_dir=./outputs/pi05_libero \
--job_name=pi05_libero \
--batch_size=64 \
--num_workers=8 \
--steps=30000 \
--save_freq=5000 \
--seed=1000均值/标准差归一化,而非 π₀.₅ 的分位数默认设置 — 与 pi05_libero_finetuned_v044 一致,下方结果正是基于该 checkpoint 测得的。
--policy.n_action_steps=10 和 --policy.empty_cameras=1 是显式设置的,因为 --policy.pretrained_path 只加载权重 — lerobot/pi05_libero_base 同时存储两者,否则它们会回退到 50 和 0(参见加载 checkpoint)。
然后使用 lerobot-eval 评估一个 checkpoint,并与参考成功率进行比较 — 参见 LIBERO。
π₀.₅ 使用分位数对 STATE 和 ACTION 进行归一化,因此你的 dataset 的 meta/stats.json 需要包含 q01 和 q99。较旧的 dataset 只有 min/max/mean/std,会在第一个批次上失败:
ValueError: QUANTILES normalization mode requires q01 and q99 stats重新计算它们:
lerobot-edit-dataset \
--repo_id your_dataset \
--new_repo_id your_dataset \
--operation.type recompute_stats \
--operation.overwrite true结果会写入 $HF_LEROBOT_HOME/your_dataset,而不是 --dataset.repo_id 读取的缓存 — 因此请使用 --dataset.root=$HF_LEROBOT_HOME/your_dataset 训练,或在上面添加 --push_to_hub true。
或者保持 dataset 不变,直接传入 --policy.normalization_mapping='{"ACTION": "MEAN_STD", "STATE": "MEAN_STD", "VISUAL": "IDENTITY"}'。
录制、恢复和合并操作会聚合各 episode 摘要中的分位数,因此 meta/stats.json 最终保存的是保守的包络(q <= 50 取 min,q > 50 取 max),而不是整个 dataset 的分位数。要估算后者,请使用滑动直方图扫描每一个 episode:
python src/lerobot/scripts/augment_dataset_quantile_stats.py \
--repo-id=your_dataset \
--overwrite \
--skip-images当只需要重新计算 STATE/ACTION 时,--skip-images 会保留现有的图像统计信息并避免下载或解码视频数据,--root 则读取本地 dataset 而不是 Hub。这些值是直方图估计值,存在离散化和重新分箱误差,因此可能与保守值不同——这会改变 π₀.₅ 的归一化目标,进而改变其损失规模。已经保存在现有 checkpoint 中的统计信息不受影响。
同样的 fine-tune,但冻结 VLM:内存占用更低,但会牺牲一些成功率。将 --dataset.repo_id 换成你自己的 dataset。
lerobot-train \
--dataset.repo_id=lerobot/libero \
--policy.type=pi05 \
--policy.pretrained_path=lerobot/pi05_libero_base \
--policy.normalization_mapping='{"ACTION": "MEAN_STD", "STATE": "MEAN_STD", "VISUAL": "IDENTITY"}' \
--policy.n_action_steps=10 \
--policy.empty_cameras=1 \
--policy.freeze_vision_encoder=true \
--policy.train_expert_only=true \
--policy.gradient_checkpointing=true \
--policy.dtype=bfloat16 \
--policy.device=cuda \
--policy.push_to_hub=false \
--output_dir=./outputs/pi05_libero_expert \
--job_name=pi05_libero_expert \
--batch_size=64 \
--num_workers=8 \
--steps=30000 \
--save_freq=5000 \
--seed=1000--policy.compile_model=true:启用模型编译以加快训练--policy.gradient_checkpointing=true:在训练期间显著减少内存占用--policy.dtype=bfloat16:使用混合精度训练以提高效率--batch_size=64:训练的批次大小,请根据你的 GPU 内存进行调整--policy.pretrained_path=lerobot/pi05_base:你想要 fine-tune 的基础 π₀.₅ 模型,可选值有: Pi05 可以选择性地学习 action 前缀条件化,以实现高效的 Real-Time Chunking,该方法遵循 Training-Time Action Conditioning for Efficient Real-Time Chunking 一文。
将 policy.rtc_training_max_delay 设置为预期的最大 inference latency(以
控制器步数计):
lerobot-train \
--dataset.repo_id=${HF_USER}/my_dataset \
--policy.type=pi05 \
--policy.pretrained_path=lerobot/pi05_base \
--policy.rtc_training_max_delay=10 \
--policy.dtype=bfloat16 \
--policy.device=cuda \
--batch_size=8 \
--steps=30000 \
--output_dir=outputs/pi05_rtc \
--job_name=pi05_rtc默认值为 0,这会禁用训练时 RTC,并保持标准
Pi05 目标不变。配置的延迟必须小于 chunk_size。训练期间,Pi05 会为每个示例独立采样一个干净的前缀长度,
并只计算剩余后缀部分的流损失。
显式使用经过 RTC 训练的 checkpoint:
lerobot-rollout \
--strategy.type=base \
--policy.path=outputs/pi05_rtc/checkpoints/last/pretrained_model \
--inference.type=rtc \
--inference.rtc.mode=trained \
--inference.rtc.execution_horizon=10 \
--robot.type=so100_follower \
--robot.port=/dev/ttyACM0 \
--task="pick up the cube" \
--fps=50 \
--device=cuda将 inference.rtc.execution_horizon 设置在 checkpoint 的 rtc_training_max_delay 和 chunk_size - rtc_training_max_delay 之间,并将 inference.queue_threshold 设置为至少 rtc_training_max_delay。一次性的
延迟尖峰超出训练范围时会丢弃该块并重试;rollout
只有在延迟持续超出范围时才会以显式错误停止。默认的 --inference.rtc.mode=guided 仍可用于普通 checkpoint。
这两种形式不可互换:
--policy.path | --policy.pretrained_path | |
|---|---|---|
| 加载内容 | 权重以及checkpoint 的 config.json | 仅权重 |
| 特征名称 | 来自 checkpoint | 来自你的 dataset,经 --rename_map 之后 |
存储的设置,例如 n_action_steps | 继承 | 重置为默认值 |
--policy.type | 必须省略 | 必需 |
--rename_map | 当你的相机键不同时需要 | 支持规范化 dataset 键 |
当原始 dataset 的特征名称与 policy
特征名称不一致时,请结合 --rename_map 使用以上任意一种加载形式。例如,RoboMME fine-tune 命令在将原始 image、wrist_image、 state 和 actions 列映射过来的同时,用 --policy.pretrained_path 初始化权重。
| 参数 | 默认值 | 描述 |
|---|---|---|
freeze_vision_encoder | false | 不冻结视觉编码器 |
train_expert_only | false | 不冻结 VLM,训练所有参数 |
💡 提示:设置 train_expert_only=true 会冻结 VLM,只训练 action expert 和投影层,从而以更低的内存占用进行 fine-tune。
Pi05 可以选择性地使用基于 MEM 的短视界视觉和本体感觉上下文。两条路径默认都是关闭的,因此 现有 checkpoint 和训练命令会保留单帧 Pi05 行为。
这里只实现了 MEM 的短视界记忆——即第 III-C 部分的视频编码器和第 III-D 部分的本体感觉投影。MEM 的长视界 语言 记忆(第 III-B 部分)没有实现,该机制由高层 policy 预测下一步的 子任务,并生成到目前为止所发生事件的压缩自然语言摘要。在论文的消融实验中,单靠视频记忆只能恢复完整 MEM 在长视界任务上的一部分任务进度。
在从未预训练过记忆的 checkpoint 上进行 fine-tune 时引入记忆,也对应论文中较弱的
MEM-Posttrain-Only消融。MEM 的核心成果来自在机器人和非机器人视频的多样混合数据上预训练视频编码器,而目前没有任何公开的 Pi05 checkpoint 提供这种数据。
fine-tune 时通过以下方式启用:
lerobot-train \
--dataset.repo_id=your_dataset \
--policy.type=pi05 \
--policy.pretrained_path=lerobot/pi05_base \
--policy.use_visual_memory=true \
--policy.memory_frames=6 \
--policy.memory_stride=30 \
--policy.memory_temporal_attention_every=4 \
...memory_frames 包含当前 observation。memory_stride 以 dataset 帧为单位,而非秒,因此请根据 dataset 的 fps 进行缩放:MEM
在相隔一秒的六个 observation 上进行预训练,对于 30 fps dataset(默认)来说为 memory_stride=30,
但对于像 lerobot/robomme 这样的 10 fps dataset 则为 memory_stride=10。
每第四个 SigLIP 层都会用 MEM 的组合时空注意力替换其注意力:匹配的补丁 token 之间的因果时间注意力,与标准空间注意力组合,并复用预训练的投影,因此视觉塔不会增加任何可学习参数。最后一个此类层运行完成后,过去帧的 token 会被丢弃,从而保持下游语言/action 前缀的长度不变。
episode 开头不可用的历史会被填充并掩码。在 inference 时,Pi05 在内部维护相同的步幅图像历史,并在 policy 每次被重置时将其清空。
历史本体感觉是一个独立选项:
--policy.use_proprioceptive_memory=true启用后,每个保留的帧会添加一个投影的连续 state token,同时离散化的 state 会从文本提示中移除,使 state 恰好被表示一次(MEM 第 III-D 部分)。这会改变提示格式,因此
请从训练一开始就启用它,而不是中途启用。视觉和
本体感觉记忆使用相同的 memory_frames 和 memory_stride 设置,
但每条路径都可以独立启用。请使用所选记忆选项进行训练或 fine-tune;只在 inference 时启用它们,不会让单帧 checkpoint 获得学习到的记忆行为。
在 PEFT 下,proprio_history_proj 会通过 modules_to_save 进行完整训练并保存,因为它没有可适配的预训练权重。
inference 时,MEM 保持一个批处理历史队列,并假定批次中的每一行
共享 episode 边界。lerobot-eval 通过在每次批量 rollout 之前及重置向量环境之前调用 policy.reset() 来满足这一点。不支持在异步向量批次中独立自动重置行;请启动一次新的 rollout,让完整的 policy 和 action 队列
一起被重置。
默认情况下,π₀.₅ 预测 absolute action。你可以启用relative action,让模型预测相对于当前机器人 state 的偏移量。这在某些配置下可以提高训练稳定性。
要使用 relative action,请先通过 CLI 在相对空间中重新计算 dataset 统计信息:
lerobot-edit-dataset \
--repo_id your_dataset \
--operation.type recompute_stats \
--operation.relative_action true \
--operation.chunk_size 50 \
--operation.relative_exclude_joints "['gripper']" \
--push_to_hub true或者在 Python 中实现等效操作:
from lerobot.datasets import LeRobotDataset, recompute_stats
dataset = LeRobotDataset("your_dataset")
recompute_stats(dataset, relative_action=True, chunk_size=50, relative_exclude_joints=["gripper"])
dataset.push_to_hub()chunk_size 应与 policy 的 chunk_size 匹配(π₀.₅ 默认为 50)。relative_exclude_joints 列出应保持在绝对空间的关节名称(例如 gripper 命令)。使用 --push_to_hub true 将更新后的统计信息上传到 Hub。
然后启用 relative action 进行训练:
lerobot-train \
--dataset.repo_id=your_dataset \
--policy.type=pi05 \
--policy.use_relative_actions=true \
--policy.relative_exclude_joints='["gripper"]' \
...π₀.₅ 在 Libero benchmark 套件上展现了强劲的性能。为了比较和测试其在 LeRobot 中的实现,我们在 Libero dataset 上额外 fine-tune libero 基础模型 6k 步,并将结果与 OpenPI 参考结果进行了比较。
| benchmark | LeRobot 实现 | OpenPI 参考 |
|---|---|---|
| Libero Spatial | 97.0% | 98.8% |
| Libero Object | 99.0% | 98.2% |
| Libero Goal | 98.0% | 98.0% |
| Libero 10 | 96.0% | 92.4% |
| 平均 | 97.5% | 96.85% |
这些结果证明了 π₀.₅ 在各种机器人操作任务中的强大泛化能力。要复现这些结果,你可以按照 Libero 一节中的说明操作。
该模型遵循 Apache 2.0 许可证,与原始 OpenPI 仓库 保持一致。
在 GitHub 上更新