# Compatibilité ascendante

## Migration de la normalisation de politique (PR #1452)

**Changement majeur** : les politiques LeRobot ne disposent plus de couches de normalisation intégrées dans leurs poids. La normalisation est désormais gérée par des composants externes `PolicyProcessorPipeline`.

### Qu'est-ce qui a changé ?

|                            | Avant la PR #1452                                  | Après la PR #1452                                               |
| -------------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
| **Emplacement de la normalisation** | Intégré dans les poids du modèle (`normalize_inputs.*`) | Composants externes de `PolicyProcessorPipeline`                |
| **Dict d'état du modèle**       | Contient les statistiques de normalisation                | **Poids propres uniquement** - pas de paramètres de normalisation         |
| **Utilisation**                  | `policy(batch)` gère tout               | `preprocessor(batch)` → `policy(...)` → `postprocessor(...)` |

### Impact sur les modèles existants

- Les modèles entraînés **avant** la PR #1452 ont la normalisation intégrée dans leurs poids
- Ces modèles nécessitent une migration pour fonctionner avec le nouveau système `PolicyProcessorPipeline`
- La migration extrait les statistiques de normalisation et crée des pipelines de processeur distincts

### Migration des anciens modèles

Utilisez le script de migration pour convertir les modèles avec normalisation intégrée :

```shell
python src/lerobot/processor/migrate_policy_normalization.py \
    --pretrained-path lerobot/act_aloha_sim_transfer_cube_human \
    --push-to-hub \
    --branch migrated
```

Le script :

1. **Extracts** les statistiques de normalisation à partir des poids du modèle
2. **Crée** des pipelines de préprocesseur et de postprocesseur externes
3. **Supprime** les couches de normalisation des poids du modèle
4. **Sauvegarde** des pipelines de modèle et de processeur propres
5. **Pushes** vers le Hub avec création automatique de PR

### Utilisation de modèles migrés

```python
# New usage pattern (after migration)
from lerobot.policies import make_policy, make_pre_post_processors

# Load model and processors separately
policy = make_policy(config, ds_meta=dataset.meta)
preprocessor, postprocessor = make_pre_post_processors(
    policy_cfg=config,
    dataset_stats=dataset.meta.stats
)

# Process data through pipeline
processed_batch = preprocessor(raw_batch)
action = policy.select_action(processed_batch)
final_action = postprocessor(action)
```

## Refonte de l'API matériel

La PR [#777](https://github.com/huggingface/lerobot/pull/777) améliore la calibration de LeRobot mais n'est **pas rétrocompatible**. Voici un aperçu des modifications apportées et de la manière de continuer à travailler avec les jeux de données créés avant cette pull request.

### Qu'est-ce qui a changé ?

|                                   | Avant la PR #777                                    | Après la PR #777                                                |
| --------------------------------- | ------------------------------------------------- | ------------------------------------------------------------ |
| **Plage conjointe**                   | Degrés `-180...180°`                             | **Plage normalisée** Articulations : `–100...100` Pince : `0...100` |
| **Position zéro (SO100 / SO101)** | Bras entièrement déployé horizontalement                   | **Au milieu de la plage pour chaque articulation**                    |
| **Gestion des limites**             | Mesures logicielles pour détecter les retours à ±180 ° | Aucune logique de retour à zéro n'est nécessaire en raison du zéro à mi-échelle            |

---

### Impact sur les jeux de données existants

- Les trajectoires enregistrées créées **avant** la PR #777 seront rejouées de manière incorrecte si elles sont chargées directement :
  - Les angles articulaires sont décalés et normalisés de manière incorrecte.
- Tous les modèles directement affinés ou entraînés sur les anciennes données devront avoir leurs entrées et sorties converties.

### Utilisation de jeux de données créés avec l'ancien système de calibration

Nous fournissons un script d’exemple de migration pour rejouer un épisode enregistré avec l’étalonnage précédent, ici : `examples/backward_compatibility/replay.py`. Ci-dessous, nous vous guidons à travers les modifications apportées dans le script d’exemple pour faire fonctionner les jeux de données d’étalonnage précédents.

```diff
+   key = f"{name.removeprefix('main_')}.pos"
    action[key] = action_array[i].item()
+   action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
+   action["elbow_flex.pos"] -= 90
```

Décomposons cela. La nouvelle base de code utilise le suffixe `.pos` pour les observations de position et nous avons supprimé le préfixe `main_` :

```python
key = f"{name.removeprefix('main_')}.pos"
```

Pour `"shoulder_lift"` (id = 2), la position 0 est modifiée de -90 degrés et le sens est inversé par rapport à l’ancienne calibration/code.

```python
action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
```

Pour `"elbow_flex"` (id = 3), la position 0 est modifiée de -90 degrés par rapport à l’ancienne calibration/code.

```python
action["elbow_flex.pos"] -= 90
```

Pour utiliser la normalisation en degrés, nous définissons ensuite l'option `--robot.use_degrees` sur `true`.

```diff
python examples/backward_compatibility/replay.py \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5A460814411 \
    --robot.id=blue \
+   --robot.use_degrees=true \
    --dataset.repo_id=my_dataset_id \
    --dataset.episode=0
```

### Utilisation de politiques entraînées avec le système de calibration précédent

Les politiques produisent des actions dans le même format que les jeux de données (`torch.Tensors`). Par conséquent, les mêmes transformations doivent être appliquées.

Pour trouver ces transformations, nous recommandons de rejouer d'abord un épisode du jeu de données sur lequel votre politique a été entraînée, en utilisant la section ci-dessus. Ensuite, ajoutez ces mêmes transformations à votre script d'inférence (illustré ici pour un script qui appelle `predict_action`, comme les exemples de `evaluate.py` dans `examples/`) :

```diff
action_values = predict_action(
    observation_frame,
    policy,
    get_safe_torch_device(policy.config.device),
    preprocessor,
    postprocessor,
    policy.config.use_amp,
    task=single_task,
    robot_type=robot.robot_type,
    )
    action = {key: action_values[i].item() for i, key in enumerate(robot.action_features)}

+   action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
+   action["elbow_flex.pos"] -= 90
    robot.send_action(action)
```

Si vous avez des questions ou rencontrez des problèmes de migration, n'hésitez pas à les poser sur [Discord](https://discord.gg/s3KuuzsPFb)

