# π₀.₅ (Pi05) 策略

π₀.₅ 是 Physical Intelligence 推出的**具备开放世界泛化能力的视觉-语言-动作模型**。LeRobot 的实现改编自其开源的 [OpenPI](https://github.com/Physical-Intelligence/openpi) 仓库。

## 模型概览

π₀.₅ 是 [Physical Intelligence](https://www.physicalintelligence.company/blog/pi05) 在 π₀ 基础上的一次重大演进，旨在解决机器人领域的一大挑战：**开放世界泛化**。尽管机器人在受控环境中能够执行令人印象深刻的任务，但 π₀.₅ 旨在泛化到训练期间从未见过的全新环境和情境。

### 泛化挑战

正如 Physical Intelligence 所述，根本挑战不在于执行需要敏捷性或灵巧性的任务，而在于泛化能力，即在新环境中针对新物体正确执行任务的能力。以机器人在不同家庭中进行清洁为例：每个家庭都有不同的物体，且摆放位置各异。泛化必须在多个层面实现：

- **物理层面**：理解如何拿起勺子（握住手柄）或盘子（握住边缘），即使是在杂乱环境中面对未见过的物体
- **语义层面**：理解任务语义，例如衣物和鞋子应放在哪里（洗衣篮，而不是床上），以及清洁溢出的液体时哪些工具是合适的
- **环境层级**：适应家庭、杂货店、办公室和医院等“杂乱”的真实世界环境

### 在异构数据上进行协同训练

π₀.₅ 的突破性创新在于**在异构数据源上进行协同训练**。该模型从以下方面学习：

1. **多模态网络数据**：图像描述、视觉问答、目标检测
2. **口头指令**：人类逐步指导机器人完成复杂任务
3. **子任务命令**：高层语义行为标签（例如，针对未整理的床铺，标签为“拿起枕头”）
4. **跨本体机器人数据**：来自具有不同能力的各种机器人平台的数据
5. **多环境数据**：部署在许多不同家庭中的静态机器人
6. **移动操作数据**：约 400 小时的移动机器人演示

这种多样化的训练混合数据构建了一个“课程”，使模型能够同时在物理、视觉和语义层面实现泛化。

## 安装要求

1. 按照我们的[安装指南](./installation)安装 LeRobot。
2. 运行以下命令安装 Pi0.5 的依赖项：

   ```bash
   pip install -e ".[pi]"
   ```

   如果您从 PyPI 安装了 LeRobot：

   ```bash
   pip install 'lerobot[pi]'
   ```

## 用法

要在您的 LeRobot 配置中使用 π₀.₅，请将策略类型指定为：

```python
policy.type=pi05
```

## 训练

### LIBERO 快速入门

在 [lerobot/libero](https://huggingface.co/datasets/lerobot/libero) 上微调 LIBERO 基础模型，该数据集是 [以下结果](#libero-benchmark-results) 背后演示数据的约 1.9 GB 视频编码副本。

它包含 π₀.₅ 读取的键，这些键也是 LIBERO 环境在评估时生成的：

| 功能                     | 数据集中的形状 | π₀.₅ 如何消费它                                    |
| --------------------------- | -------------------- | ------------------------------------------------------- |
| `observation.images.image`  | 256×256×3，agentview | 调整大小为 224×224                                      |
| `observation.images.image2` | 256×256×3，手腕     | 调整大小为 224×224                                      |
| `observation.state`         | 8                    | 离散化为 256 个区间并写入提示   |
| `action`                    | 7                    | 内部填充至 32；损失函数使用前 7 个维度 |

**此处无需使用 `--rename_map`** — 键名已经匹配；如果您的键名不同，请参阅 [Rename Map and Empty Cameras](./rename_map)。

  π₀.₅ 使用带门控的 [google/paligemma-3b-pt-224](https://huggingface.co/google/paligemma-3b-pt-224) 分词器——在训练前，请在 Hub 上接受其许可证，并使用 `hf auth login` 登录。

适用于单个 80 GB GPU：

```bash
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
```

**均值/标准差归一化，而非 π₀.₅ 的 [分位数默认值](#quantile-statistics)** — 与 [pi05_libero_finetuned_v044](https://huggingface.co/lerobot/pi05_libero_finetuned_v044) 保持一致，该检查点即为下文结果所基于的模型。

**`--policy.n_action_steps=10` 和 `--policy.empty_cameras=1` 是显式指定的**，因为 `--policy.pretrained_path` 仅加载权重——`lerobot/pi05_libero_base` 同时存储了这两项，否则它们将回退为 `50` 和 `0`（参见 [加载检查点](#loading-a-checkpoint)）。

然后使用 `lerobot-eval` 评估检查点，并与参考成功率进行比较——参见 [LIBERO](./libero)。

### 分位数统计

π₀.₅ 使用分位数对 `STATE` 和 `ACTION` 进行归一化，因此您的数据集的 `meta/stats.json` 需要包含 `q01` 和 `q99`。旧版数据集仅包含 `min`/`max`/`mean`/`std`，并在第一个批次时失败：

```
ValueError: QUANTILES normalization mode requires q01 and q99 stats
```

重新计算它们：

```bash
lerobot-edit-dataset \
    --repo_id your_dataset \
    --new_repo_id your_dataset \
    --operation.type recompute_stats \
    --operation.overwrite true
```

**The result lands in `$HF_LEROBOT_HOME/your_dataset`**, not the cache `--dataset.repo_id` reads — so train with `--dataset.root=$HF_LEROBOT_HOME/your_dataset`, or add `--push_to_hub true` above.

或者保持数据集不变，并传入 `--policy.normalization_mapping='{"ACTION": "MEAN_STD", "STATE": "MEAN_STD", "VISUAL": "IDENTITY"}'`。

记录、恢复并合并来自各回合摘要的聚合分位数，使 `meta/stats.json` 最终保存一个保守的包络（对于 `q <= 50` 使用 `min`，对于 `q > 50` 使用 `max`），而不是整个数据集的分位数。若要估算后者，请使用运行直方图扫描每个回合：

```bash
python src/lerobot/scripts/augment_dataset_quantile_stats.py \
    --repo-id=your_dataset \
    --overwrite \
    --skip-images
```

`--skip-images` 会保留现有的图像统计信息，并在仅需重新计算 `STATE`/`ACTION` 时避免下载或解码视频数据，而 `--root` 则从本地数据集读取，而非从 Hub 读取。这些值是直方图估计值，受离散化和重新分箱误差的影响，因此可能与保守值不同——这会改变 π₀.₅ 的归一化目标，进而影响其损失尺度。已保存在现有检查点内的统计信息不受影响。

### 训练命令示例

使用冻结的 VLM 进行相同的微调：内存占用更少，但成功率会有一定损失。请将 `--dataset.repo_id` 替换为您自己的数据集。

```bash
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`**：您想要微调的基础 π₀.₅ 模型，可选值为：
  - [lerobot/pi05_base](https://huggingface.co/lerobot/pi05_base)
  - [lerobot/pi05_libero_base](https://huggingface.co/lerobot/pi05_libero_base)（专门在 Libero 数据集上训练）
- **`--policy.optimizer_fused=true`**：使用融合版 AdamW 以加快优化器步骤；在恢复运行时，此标志将被忽略

### 可选的训练时 RTC

Pi05 可选择性地学习动作前缀条件，以实现高效的[实时分块](./rtc)，其方法遵循[Training-Time Action Conditioning for Efficient Real-Time Chunking](https://arxiv.org/abs/2512.05964)。请将`policy.rtc_training_max_delay`设置为控制器步数中预期的最大推理延迟：

```bash
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 的生成的检查点：

```bash
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` 设置在检查点的 `rtc_training_max_delay` 与 `chunk_size - rtc_training_max_delay` 之间，并将 `inference.queue_threshold` 设置为至少 `rtc_training_max_delay`。如果一次性延迟峰值超出训练范围，则会丢弃该 chunk 并重试；只有当延迟持续超出范围时，rollout 才会停止并抛出显式错误。默认的 `--inference.rtc.mode=guided` 仍然可用于普通检查点。

### 加载检查点

这两种形式不能互换：

|                                        | `--policy.path`                                | `--policy.pretrained_path`                |
| -------------------------------------- | ---------------------------------------------- | ----------------------------------------- |
| 加载                                  | 权重 **以及** 检查点的 `config.json` | 仅权重                              |
| 特征名称                          | 从检查点                            | 来自您的数据集，在 `--rename_map` 之后   |
| 存储的设置，例如 `n_action_steps` | 继承                                      | 重置为默认值                     |
| `--policy.type`                        | 必须省略                                | 必需                                  |
| `--rename_map`                         | 当您的相机按键设置不同时            | 用于规范化数据集键 |

当原始数据集的特征名称与策略的特征名称不一致时，请在任意一种加载形式中使用 `--rename_map`。例如，RoboMME 的微调命令在通过 `--policy.pretrained_path` 初始化权重时，会映射其原始的 `image`、`wrist_image`、`state` 和 `actions` 列。

### 训练参数详解

| 参数               | 默认 | 描述                                 |
| ----------------------- | ------- | ------------------------------------------- |
| `freeze_vision_encoder` | `false` | 不要冻结视觉编码器            |
| `train_expert_only`     | `false` | 不要冻结 VLM，训练所有参数 |

**💡 提示**：设置 `train_expert_only=true` 会冻结 VLM，仅训练动作专家（action expert）和投影层，从而允许以较低的内存占用进行微调。

## 短期观测记忆（MEM）

Pi05 可选择性地基于 [MEM](https://arxiv.org/abs/2603.03596) 使用短视距的视觉和本体感觉上下文。这两条路径默认均处于禁用状态，因此现有的检查点和训练命令将保留单帧 Pi05 的行为。

此实现仅包含 MEM 的短期记忆——即第 III-C 节中的视频编码器和第 III-D 节中的本体感觉投影。MEM 的长期_语言_记忆（第 III-B 节）尚未实现，该记忆通过高层策略预测下一个子任务，并生成对迄今为止所发生事件的压缩自然语言摘要。在论文的消融实验中，仅使用视频记忆在长时程任务上只能恢复完整 MEM 任务进度的一部分。

在从未经过内存预训练的 checkpoint 进行微调时引入内存，也对应于论文中较弱的 `MEM-Posttrain-Only` 消融实验。MEM 的主要成果来自于在机器人和非机器人视频的多样化混合数据上预训练视频编码器，而目前没有任何公开的 Pi05 checkpoint 提供这一条件。

在微调时，使用以下命令启用它：

```bash
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` 包含当前观测。 `memory_stride` 以 **数据集帧** 为单位，而非秒，因此请根据数据集的 `fps` 进行缩放：MEM 在相隔一秒的六个观测上进行预训练，对于 30 fps 的数据集（默认值），这对应 `memory_stride=30`；而对于 10 fps 的数据集（例如 `lerobot/robomme`），则对应 `memory_stride=10`。

每第四个 SigLIP 层将其注意力替换为 MEM 的复合时空注意力：在匹配的 patch token 之间执行因果时间注意力，并与标准空间注意力复合，同时复用预训练的投影，因此不会向视觉塔添加任何可学习参数。一旦最后一个此类层执行完毕，便会丢弃过去帧的 token，从而保持下游语言/动作前缀长度不变。

在回合开始时，不可用的历史数据会被填充并掩码。在推理阶段，Pi05 内部维护相同步长的图像历史，并在策略重置时将其清空。

历史本体感觉是一个独立的选项：

```bash
--policy.use_proprioceptive_memory=true
```

启用后，会为每个保留的帧添加一个投影连续状态标记，并从文本提示中移除离散化状态，从而确保状态仅被表示一次（MEM 部分 III-D）。这会改变提示格式，因此应在训练开始时启用，而非中途启用。视觉和本体感觉记忆使用相同的 `memory_frames` 和 `memory_stride` 设置，但这两条路径可以独立启用。请使用所选的记忆选项进行训练或微调；仅在推理时启用这些选项，无法使单帧检查点获得学习到的记忆行为。

在 PEFT 中，`proprio_history_proj` 会通过 `modules_to_save` 进行完整训练并保存，因为它没有可适配的预训练权重。

在推理阶段，MEM 维护一个批处理历史队列，并假设每个批次行共享相同的 episode 边界。`lerobot-eval` 通过在每次批处理 rollout 之前以及重置向量环境之前调用 `policy.reset()` 来满足这一要求。不支持在异步向量批次中独立地自动重置各行；请启动新的 rollout，以便完整的策略和动作队列能够一起重置。

## 相对动作

默认情况下，π₀.₅ 预测绝对动作。您可以启用**相对动作**，使模型预测相对于当前机器人状态的偏移量。这可以提高某些配置下的训练稳定性。

要使用相对动作，首先通过 CLI 在相对空间中重新计算数据集的统计数据：

```bash
lerobot-edit-dataset \
    --repo_id your_dataset \
    --new_repo_id your_dataset \
    --operation.type recompute_stats \
    --operation.overwrite true \
    --operation.relative_action true \
    --operation.chunk_size 50 \
    --operation.relative_exclude_joints "['gripper']" \
    --push_to_hub true
```

或者用 Python 等价地表示为：

```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` 应与策略的 `chunk_size` 保持一致（π₀.₅ 的默认值为 50）。`relative_exclude_joints` 列出了应保持在绝对空间中的关节名称（例如夹爪指令）。使用 `--push_to_hub true` 可将更新后的统计数据上传至 Hub。

然后启用相对动作进行训练：

```bash
lerobot-train \
    --dataset.repo_id=your_dataset \
    --policy.type=pi05 \
    --policy.use_relative_actions=true \
    --policy.relative_exclude_joints='["gripper"]' \
    ...
```

## 性能结果

### Libero 基准测试结果

π₀.₅ 在 Libero 基准测试套件上展现了出色的性能。为了对比并测试其 LeRobot 实现，我们在 Libero 数据集上对 libero 基础模型额外微调了 6k 步，并将结果与 OpenPI 的参考结果进行了比较。

| 基准测试          | LeRobot 实现 | OpenPI 参考 |
| ------------------ | ---------------------- | ---------------- |
| **Libero Spatial** | 97.0%                  | 98.8%            |
| **Libero Object**  | 99.0%                  | 98.2%            |
| **Libero 目标**    | 98.0%                  | 98.0%            |
| **Libero 10**      | 96.0%                  | 92.4%            |
| **平均值**        | 97.5%                  | 96.85%           |

这些结果展示了 π₀.₅ 在多种机器人操作任务中的强大泛化能力。要复现这些结果，您可以按照 [Libero](https://huggingface.co/docs/lerobot/libero) 部分中的说明进行操作。

## 许可证

该模型遵循 **Apache 2.0 许可证**，与原始的 [OpenPI 仓库](https://github.com/Physical-Intelligence/openpi) 保持一致。

