# Politique π₀.₅ (Pi05)

π₀.₅ est un **modèle Vision-Language-Action avec généralisation en monde ouvert**, de Physical Intelligence. L'implémentation LeRobot est adaptée de leur dépôt open source [OpenPI](https://github.com/Physical-Intelligence/openpi).

## Aperçu du modèle

π₀.₅ représente une évolution significative par rapport à π₀, développé par [Physical Intelligence](https://www.physicalintelligence.company/blog/pi05) pour relever un défi majeur en robotique : la **généralisation en monde ouvert**. Bien que les robots puissent effectuer des tâches impressionnantes dans des environnements contrôlés, π₀.₅ est conçu pour se généraliser à des environnements et des situations entièrement nouveaux, jamais vus lors de l’entraînement.

### Le défi de la généralisation

Comme l’explique Physical Intelligence, le défi fondamental ne réside pas dans l’exécution de tâches d’agilité ou de dextérité, mais dans la généralisation, c’est-à-dire la capacité à exécuter correctement des tâches dans de nouveaux environnements avec de nouveaux objets. Pensez à un robot nettoyant différentes maisons : chaque maison contient des objets différents, placés à des endroits différents. La généralisation doit se produire à plusieurs niveaux :

- **Niveau physique** : Comprendre comment saisir une cuillère (par le manche) ou une assiette (par le bord), même avec des objets inconnus dans des environnements encombrés
- **Niveau sémantique** : Comprendre la sémantique de la tâche, où placer les vêtements et les chaussures (dans le panier à linge, pas sur le lit) et quels outils sont appropriés pour nettoyer les taches
- **Niveau environnemental** : s'adapter à des environnements réels « complexes » tels que les foyers, les supermarchés, les bureaux et les hôpitaux

### Co-entraînement sur des données hétérogènes

L'innovation majeure de π₀.₅ est le **co-entraînement sur des sources de données hétérogènes**. Le modèle apprend à partir de :

1. **Données Web multimodales** : légende d'images, question-réponse visuelle, détection d'objets
2. **Instructions verbales** : Des humains qui guident des robots à travers des tâches complexes, étape par étape
3. **Commandes de sous-tâches** : Étiquettes de comportement sémantique de haut niveau (par exemple, « prendre l'oreiller » pour un lit défait)
4. **Données robotiques multi-embodiments** : Données issues de différentes plateformes robotiques aux capacités variées
5. **Données multi-environnements** : Robots statiques déployés dans de nombreuses maisons différentes
6. **Données de manipulation mobile** : ~400 heures de démonstrations de robots mobiles

Ce mélange d'entraînement diversifié crée un « curriculum » qui permet la généralisation simultanée aux niveaux physique, visuel et sémantique.

## Prérequis d'installation

1. Installez LeRobot en suivant notre [Guide d'installation](./installation).
2. Installez les dépendances de Pi0.5 en exécutant :

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

   Si vous avez installé LeRobot depuis PyPI :

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

## Utilisation

Pour utiliser π₀.₅ dans votre configuration LeRobot, spécifiez le type de politique comme suit :

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

## Entraînement

### Démarrage rapide sur LIBERO

Effectuez le fine-tuning du modèle de base LIBERO sur [lerobot/libero](https://huggingface.co/datasets/lerobot/libero), une copie encodée en vidéo d’environ 1,9 Go des démonstrations à l’origine des [résultats ci-dessous](#libero-benchmark-results).

Il contient les clés que π₀.₅ lit, qui sont également celles que l’environnement LIBERO génère lors de l’évaluation :

| Fonctionnalité                     | Forme dans le jeu de données | Comment π₀.₅ le consomme                                    |
| --------------------------- | -------------------- | ------------------------------------------------------- |
| `observation.images.image`  | 256×256×3, agentview | redimensionné à 224×224                                      |
| `observation.images.image2` | 256×256×3, poignet     | redimensionné à 224×224                                      |
| `observation.state`         | 8                    | discrétisées en 256 classes et insérées dans le prompt   |
| `action`                    | 7                    | rempli jusqu'à 32 en interne ; la perte utilise les 7 premières dimensions |

**Aucun `--rename_map` n'est nécessaire ici** — les clés correspondent déjà ; consultez [Rename Map and Empty Cameras](./rename_map) si les vôtres diffèrent.

  π₀.₅ utilise le tokenizer [google/paligemma-3b-pt-224](https://huggingface.co/google/paligemma-3b-pt-224) sous licence — acceptez sa licence sur le Hub et connectez-vous avec `hf auth login` avant l’entraînement.

Dimensionné pour un GPU 80 Go unique :

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

**Normalisation par moyenne/écart-type, et non la [valeur par défaut par quantile](#quantile-statistics) de π₀.₅** — correspondant à [pi05_libero_finetuned_v044](https://huggingface.co/lerobot/pi05_libero_finetuned_v044), le point de contrôle sur lequel les résultats ci-dessous ont été mesurés.

**`--policy.n_action_steps=10` et `--policy.empty_cameras=1` sont explicites** car `--policy.pretrained_path` charge uniquement les poids — `lerobot/pi05_libero_base` stocke les deux, et ils retomberaient sinon sur `50` et `0` (voir [Chargement d'un point de contrôle](#loading-a-checkpoint)).

Évaluez ensuite un point de contrôle avec `lerobot-eval` et comparez-le aux taux de réussite de référence — voir [LIBERO](./libero).

### Statistiques de quantiles

π₀.₅ normalise `STATE` et `ACTION` à l'aide de quantiles, votre fichier `meta/stats.json` doit donc contenir `q01` et `q99`. Les anciens jeux de données ne contiennent que `min`/`max`/`mean`/`std` et échouent dès le premier lot :

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

Les recalculer :

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

**Le résultat est enregistré dans `$HF_LEROBOT_HOME/your_dataset`**, et non dans le cache lu par `--dataset.repo_id` — entraînez donc le modèle avec `--dataset.root=$HF_LEROBOT_HOME/your_dataset`, ou ajoutez `--push_to_hub true` ci-dessus.

Ou conservez le jeu de données tel quel et passez `--policy.normalization_mapping='{"ACTION": "MEAN_STD", "STATE": "MEAN_STD", "VISUAL": "IDENTITY"}'`.

Enregistrement, reprise et fusion des quantiles agrégés à partir des résumés par épisode, afin que `meta/stats.json` contienne une enveloppe conservatrice (`min` pour `q <= 50`, `max` pour `q > 50`) plutôt que des quantiles sur l'ensemble du jeu de données. Pour estimer ces derniers, parcourez chaque épisode avec un histogramme incrémental :

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

`--skip-images` conserve les statistiques d’images existantes et évite le téléchargement ou le décodage des données vidéo lorsque seuls `STATE`/`ACTION` doivent être recalculés, et `--root` lit un jeu de données local au lieu du Hub. Ces valeurs sont des estimations par histogramme, sujettes à des erreurs de discrétisation et de rebinning, elles peuvent donc différer des valeurs conservatrices — ce qui modifie les cibles normalisées de π₀.₅ et, par conséquent, l’échelle de sa perte. Les statistiques déjà enregistrées dans un point de contrôle existant ne sont pas affectées.

### Exemple de commande d'entraînement

Le même finetune avec le VLM figé : moins de mémoire, au prix d’un certain taux de réussite. Remplacez `--dataset.repo_id` par votre propre jeu de données.

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

### Paramètres d'entraînement clés

- **`--policy.compile_model=true`** : Active la compilation du modèle pour un entraînement plus rapide
- **`--policy.gradient_checkpointing=true`** : réduit considérablement l'utilisation de la mémoire pendant l'entraînement
- **`--policy.dtype=bfloat16`** : Utiliser l'entraînement en précision mixte pour l'efficacité
- **`--batch_size=64`** : Taille du lot pour l'entraînement, à adapter en fonction de la mémoire de votre GPU
- **`--policy.pretrained_path=lerobot/pi05_base`** : le modèle de base π₀.₅ que vous souhaitez affiner, les options sont :
  - [lerobot/pi05_base](https://huggingface.co/lerobot/pi05_base)
  - [lerobot/pi05_libero_base](https://huggingface.co/lerobot/pi05_libero_base) (entraîné spécifiquement sur le jeu de données Libero)
- **`--policy.optimizer_fused=true`** : Utilise AdamW fusionné pour des étapes d’optimiseur plus rapides ; ce drapeau est ignoré lors de la reprise d’une exécution

### RTC optionnel lors de l'entraînement

Pi05 peut apprendre de manière optionnelle un conditionnement par préfixe d’action pour un [Real-Time Chunking](./rtc) efficace, conformément à [Training-Time Action Conditioning for Efficient Real-Time Chunking](https://arxiv.org/abs/2512.05964). Définissez `policy.rtc_training_max_delay` sur le délai d’inférence maximal attendu en étapes du contrôleur :

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

La valeur par défaut est `0`, ce qui désactive le RTC pendant l'entraînement et laisse l'objectif standard de Pi05 inchangé. Le délai configuré doit être inférieur à `chunk_size`. Pendant l'entraînement, Pi05 échantillonne une longueur de préfixe propre indépendamment pour chaque exemple et calcule la perte de flux uniquement sur le suffixe restant.

Utilisez explicitement le checkpoint résultant avec le RTC entraîné :

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

Définissez `inference.rtc.execution_horizon` entre `rtc_training_max_delay` et `chunk_size - rtc_training_max_delay` du checkpoint, et `inference.queue_threshold` à au moins `rtc_training_max_delay`. Une pointe de latence unique dépassant la plage entraînée entraîne l’abandon de ce chunk et une nouvelle tentative ; le rollout s’arrête avec une erreur explicite uniquement si le délai reste hors de la plage. Le mode par défaut `--inference.rtc.mode=guided` reste disponible pour les checkpoints ordinaires.

### Chargement d'un point de contrôle

Les deux formes ne sont pas interchangeables :

|                                        | `--policy.path`                                | `--policy.pretrained_path`                |
| -------------------------------------- | ---------------------------------------------- | ----------------------------------------- |
| Chargements                                  | les poids **et** le `config.json` du point de contrôle | poids uniquement                              |
| Noms des fonctionnalités                          | à partir du point de contrôle                            | de votre jeu de données, après `--rename_map`   |
| Paramètres stockés, par exemple `n_action_steps` | hérité                                      | réinitialiser aux valeurs par défaut                     |
| `--policy.type`                        | doit être omis                                | requis                                  |
| `--rename_map`                         | nécessaire lorsque vos touches caméra diffèrent            | pris en charge pour la normalisation des clés de jeu de données |

Utilisez `--rename_map` avec l’une ou l’autre forme de chargement lorsque les noms des fonctionnalités du jeu de données brut diffèrent des noms des fonctionnalités de la politique. Par exemple, la commande de fine-tuning de RoboMME mappe ses colonnes brutes `image`, `wrist_image`, `state` et `actions` tout en initialisant les poids avec `--policy.pretrained_path`.

### Explication des paramètres d'entraînement

| Paramètre               | Par défaut | Description                                 |
| ----------------------- | ------- | ------------------------------------------- |
| `freeze_vision_encoder` | `false` | Ne pas geler l'encodeur visuel            |
| `train_expert_only`     | `false` | Ne figez pas le VLM, entraînez tous les paramètres |

**💡 Astuce** : Définir `train_expert_only=true` fige le VLM et entraîne uniquement l'expert d'action et les projections, permettant un affinement avec une consommation mémoire réduite.

## Mémoire d'observation à court terme (MEM)

Pi05 peut éventuellement utiliser un contexte visuel et proprioceptif à court horizon basé sur [MEM](https://arxiv.org/abs/2603.03596). Les deux chemins sont désactivés par défaut, de sorte que les points de contrôle et les commandes d'entraînement existants conservent le comportement Pi05 à image unique.

Ceci implémente uniquement la mémoire à court terme de MEM — l’encodeur vidéo de la section III-C et la projection proprioceptive de la section III-D. La mémoire à long terme _linguistique_ de MEM (section III-B), dans laquelle une politique de haut niveau prédit la sous-tâche suivante ainsi qu’un résumé en langage naturel compressé de ce qui s’est passé jusqu’à présent, n’est pas implémentée. Dans les ablations de l’article, la mémoire vidéo seule ne récupère qu’une partie de la progression sur les tâches de MEM complet pour les tâches à long terme.

Introduire la mémoire lors de l’ajustement fin à partir d’un point de contrôle pré-entraîné sans mémoire correspond également à l’ablation plus faible `MEM-Posttrain-Only` du papier. Les résultats principaux de MEM proviennent de la pré-entraînement de l’encodeur vidéo sur un mélange diversifié de vidéos robotiques et non robotiques, ce qu’aucun point de contrôle Pi05 public ne fournit actuellement.

Activez-le lors de l’ajustement fin avec :

```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` inclut l’observation actuelle. `memory_stride` est mesuré en **images du jeu de données**, et non en secondes, il faut donc l’adapter à la `fps` de votre jeu de données : MEM est pré-entraîné sur six observations espacées d’une seconde, ce qui correspond à `memory_stride=30` pour un jeu de données à 30 fps (la valeur par défaut) mais à `memory_stride=10` pour un jeu de données à 10 fps tel que `lerobot/robomme`.

Toutes les quatre couches SigLIP remplacent leur attention par l'attention espace-temps composée de MEM : une attention temporelle causale entre les jetons de patch correspondants, composée avec l'attention spatiale standard et réutilisant les projections pré-entraînées, de sorte qu'aucun paramètre apprenable n'est ajouté à la tour de vision. Les jetons des images précédentes sont supprimés une fois que la dernière couche de ce type a été exécutée, ce qui maintient la longueur du préfixe langage/action en aval inchangée.

L’historique indisponible au début d’un épisode est complété par des valeurs de bourrage et masqué. Lors de l’inférence, Pi05 maintient en interne le même historique d’images à pas et le réinitialise à chaque fois que la politique est réinitialisée.

La proprioception historique est une option indépendante :

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

Lorsqu’activé, un jeton d’état continu projeté est ajouté pour chaque frame conservée, et l’état discrétisé est retiré du prompt texte afin que l’état soit représenté exactement une fois (section III-D de MEM). Cela modifie le format du prompt, il convient donc de l’activer dès le début de l’entraînement plutôt qu’en cours de route. La mémoire visuelle et la mémoire proprioceptive utilisent les mêmes paramètres `memory_frames` et `memory_stride`, mais chaque chemin peut être activé indépendamment. Entraînez ou affinez le modèle avec les options de mémoire sélectionnées ; les activer uniquement lors de l’inférence ne confère pas au checkpoint mono-frame un comportement de mémoire appris.

Sous PEFT, `proprio_history_proj` est entraîné et enregistré en totalité via `modules_to_save`, car il ne possède pas de poids préentraînés à adapter.

À l’inférence, MEM conserve une file d’historique par lot et suppose que chaque ligne du lot partage les mêmes limites d’épisode. `lerobot-eval` satisfait cette condition en appelant `policy.reset()` avant chaque déroulement par lot et avant la réinitialisation de l’environnement vectoriel. La réinitialisation automatique indépendante des lignes dans un lot vectoriel asynchrone n’est pas prise en charge ; démarrez un nouveau déroulement afin que les files de politique et d’actions complètes soient réinitialisées ensemble.

## Actions relatives

Par défaut, π₀.₅ prédit des actions absolues. Vous pouvez activer les **actions relatives** afin que le modèle prédise des décalages par rapport à l'état actuel du robot. Cela peut améliorer la stabilité de l'entraînement pour certaines configurations.

Pour utiliser des actions relatives, recomputez d'abord les statistiques de votre jeu de données dans l'espace relatif via l'interface en ligne de commande :

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

Ou de manière équivalente en 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` doit correspondre au `chunk_size` de votre politique (50 par défaut pour π₀.₅). `relative_exclude_joints` énumère les noms d'articulations qui doivent rester dans l'espace absolu (par exemple, les commandes de pince). Utilisez `--push_to_hub true` pour téléverser les statistiques mises à jour sur le Hub.

Ensuite, entraînez avec les actions relatives activées :

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

## Résultats de performance

### Résultats du benchmark Libero

π₀.₅ a démontré de solides performances sur la suite de benchmarks Libero. Pour comparer et tester son implémentation LeRobot, nous avons effectué un fine-tuning du modèle de base libero pendant 6 000 étapes supplémentaires sur le jeu de données Libero, puis comparé les résultats aux résultats de référence OpenPI.

| Benchmark          | Implémentation de LeRobot | Référence OpenPI |
| ------------------ | ---------------------- | ---------------- |
| **Libero Spatial** | 97.0%                  | 98.8%            |
| **Libero Object**  | 99.0%                  | 98.2%            |
| **Objectif Libero**    | 98.0%                  | 98.0%            |
| **Libero 10**      | 96.0%                  | 92.4%            |
| **Moyenne**        | 97.5%                  | 96.85%           |

Ces résultats démontrent les fortes capacités de généralisation de π₀.₅ à travers diverses tâches de manipulation robotique. Pour reproduire ces résultats, vous pouvez suivre les instructions de la section [Libero](https://huggingface.co/docs/lerobot/libero).

## Licence

Ce modèle est soumis à la **licence Apache 2.0**, conformément au dépôt [OpenPI](https://github.com/Physical-Intelligence/openpi) d'origine.

