# EVO1

EVO1 est une politique Vision-Language-Action pour le contrôle de robots, construite autour d'un socle InternVL3 et d'une tête d'action continue par flow-matching. Cette intégration LeRobot expose EVO1 comme un type de politique standard, permettant ainsi de l'entraîner et de l'évaluer avec les API habituelles de jeu de données, de point de contrôle et de processeur de LeRobot.

## Aperçu du modèle

La politique intègre une ou plusieurs images de caméra et le prompt de la tâche linguistique avec InternVL3, remplit les vecteurs d'état/action du robot jusqu'aux dimensions maximales fixes, et prédit les futurs morceaux d'action avec une tête d'action de type flow-matching. Lors de l'inférence, la politique échantillonne un morceau d'action et renvoie `n_action_steps` actions de ce morceau avant de rééchantillonner.

### Ce que couvre l'intégration LeRobot

- Configuration standard `policy.type=evo1` via LeRobot
- Embedding d’images/texte avec InternVL3 et repli facultatif sur FlashAttention
- Contrôles de l’affinage par étapes pour les exécutions d’affinage de la tête d’action uniquement et de l’affinage VLM
- Prédiction d'action par correspondance de flux continue
- Sauvegarde/chargement de points de contrôle via les API de politique LeRobot
- Entraînement avec `lerobot-train` et évaluation avec les API d'inférence de politique standard

Le projet EVO1 plus large peut inclure des scripts d'entraînement et des outils de jeu de données supplémentaires. Cette page se concentre sur le chemin de la politique de contrôle robotique LeRobot.

## Prérequis d'installation

1. Installez LeRobot en suivant le [Guide d'installation](./installation).
2. Installer les dépendances d'EVO1 :

   ```bash
   pip install -e ".[training,evo1]"
   ```

   Pour l’entraînement et l’évaluation de LIBERO, installez également l’extra LIBERO :

   ```bash
   pip install -e ".[training,evo1,libero]"
   ```

3. Installez une roue `flash-attn` uniquement si elle est compatible avec votre pile Python, PyTorch, CUDA et GPU. EVO1 bascule sur l’attention standard lorsque `flash_attn` n’est pas disponible.

EVO1 utilise l’implémentation native d’InternVL de la bibliothèque `transformers` de Hugging Face, de sorte que `policy.vlm_model_name` doit pointer vers un checkpoint converti nativement, tel que `OpenGVLab/InternVL3-1B-hf` (notez le suffixe `-hf`). La première exécution télécharge le checkpoint VLM configuré, et les exécutions suivantes le réutilisent depuis le cache Hugging Face.

## Exigences en matière de données

EVO1 s'attend à un jeu de données LeRobot avec :

- Un à `policy.max_views` observations visuelles, par exemple `observation.images.image`
- `observation.state`
- `action`
- Une instruction de tâche linguistique dans le champ `task` du jeu de données, ou un autre champ configuré avec `policy.task_field`

Les vecteurs d'état et d'action sont complétés (padding) jusqu'à `policy.max_state_dim` et `policy.max_action_dim`. Les prédictions sont recadrées à la dimension d'action du jeu de données avant d'être renvoyées.

## Utilisation

Pour utiliser EVO1 dans une configuration LeRobot, spécifiez :

```python
policy.type=evo1
```

Par défaut, une nouvelle politique EVO1 initialise son VLM à partir de :

```python
policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf
```

Une fois un point de contrôle EVO1 au format LeRobot disponible, chargez-le avec :

```python
policy.path=your-org/your-evo1-checkpoint
```

## Entraînement

### Étape 1

L'étape 1 fige le VLM et entraîne la tête d'action :

```bash
lerobot-train \
  --dataset.repo_id=your_org/your_dataset \
  --policy.type=evo1 \
  --policy.training_stage=stage1 \
  --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
  --policy.device=cuda \
  --policy.chunk_size=50 \
  --policy.n_action_steps=50 \
  --policy.max_state_dim=24 \
  --policy.max_action_dim=24 \
  --policy.optimizer_lr=1e-5 \
  --batch_size=4 \
  --steps=5000 \
  --output_dir=./outputs/evo1_stage1
```

### Étape 2

L'étape 2 charge la politique de l'étape 1, mais démarre un nouvel optimiseur et un nouveau planificateur :

```bash
lerobot-train \
  --dataset.repo_id=your_org/your_dataset \
  --policy.path=./outputs/evo1_stage1/checkpoints/005000/pretrained_model \
  --policy.training_stage=stage2 \
  --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
  --policy.device=cuda \
  --policy.chunk_size=50 \
  --policy.n_action_steps=50 \
  --policy.max_state_dim=24 \
  --policy.max_action_dim=24 \
  --policy.optimizer_lr=1e-5 \
  --batch_size=4 \
  --steps=80000 \
  --output_dir=./outputs/evo1_stage2
```

Par défaut, `policy.training_stage` réapplique les valeurs par défaut de fine-tuning pour cette étape. C’est important lors du démarrage de l’étape 2 à partir d’un checkpoint de l’étape 1, car la configuration du checkpoint de l’étape 1 stocke les drapeaux de fine-tuning du VLM comme désactivés. Ces valeurs par défaut d’étape prennent le pas sur les drapeaux `policy.finetune_*` enregistrés ou fournis manuellement, sauf si `policy.apply_training_stage_defaults=false`. Définissez donc ce drapeau uniquement si vous contrôlez manuellement tous les drapeaux de fine-tuning.

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

| Paramètre                                     | Par défaut                     | Description                                                       |
| --------------------------------------------- | --------------------------- | ----------------------------------------------------------------- |
| `policy.vlm_model_name`                       | `OpenGVLab/InternVL3-1B-hf` | Point de contrôle InternVL3 converti nativement ou répertoire de modèle local  |
| `policy.training_stage`                       | `stage1`                    | `stage1` entraîne la tête d’action ; `stage2` ajuste finement les branches VLM  |
| `policy.apply_training_stage_defaults`        | `true`                      | Réapplique les valeurs par défaut de l’affinage par étapes après le chargement d’un point de contrôle    |
| `policy.vlm_num_layers`                       | `14`                        | Nombre de couches de langage InternVL3 conservées pour la politique           |
| `policy.dtype`                                | `bfloat16`                  | Type de données VLM demandé                                               |
| `policy.use_flash_attn`                       | `true`                      | Demande FlashAttention s'il est installé ; sinon, bascule      |
| `policy.enable_gradient_checkpointing`        | `true`                      | Active le checkpointing sur les modules InternVL3 pris en charge              |
| `policy.gradient_checkpointing_use_reentrant` | `false`                     | Paramètre de réentrance transmis au point de contrôle de gradient lorsqu'il est pris en charge |
| `policy.chunk_size`                           | `50`                        | Nombre d'actions futures prédites par bloc                      |
| `policy.n_action_steps`                       | `50`                        | Nombre d'actions consommées depuis un échantillon                   |
| `policy.max_state_dim`                        | `24`                        | Dimension de bourrage de l'état                                           |
| `policy.max_action_dim`                       | `24`                        | Dimension du padding des actions                                          |
| `policy.postprocess_action_dim`               | `null`                      | Dimension d'action optionnelle renvoyée après le post-traitement EVO1      |
| `policy.binarize_gripper`                     | `false`                     | Binarise le canal de pince post-traité pour une évaluation de type LIBERO |
| `policy.task_field`                           | `task`                      | Champ de lot utilisé comme invite de langue                           |

## Inférence

Essayez-le avec un point de contrôle EVO1 entraîné :

```bash
# --inference.type=rtc is optional
lerobot-rollout \
  --policy.path=your-org/your-evo1-checkpoint \
  --inference.type=rtc \
  ...
```

## Résultats

### Évaluation LIBERO

#### Résultat de référence

> [!NOTE]
> Le point de contrôle Stage-2 publié a passé la vérification de téléchargement propre et de déroulement : [`zuoxingdong/evo1_libero`](https://huggingface.co/zuoxingdong/evo1_libero), révision [`515921f4a2c1d3f3ad523721eafa26fdf2af315b`](https://huggingface.co/zuoxingdong/evo1_libero/commit/515921f4a2c1d3f3ad523721eafa26fdf2af315b). L'évaluation de téléchargement propre a utilisé la révision LeRobot [`e40b58a8dfa9e7b86918c374791599d070518d11`](https://github.com/huggingface/lerobot/commit/e40b58a8dfa9e7b86918c374791599d070518d11).

Le point de contrôle de l'étape 2, exécuté une seule fois à l'étape 70 000, a produit :

| Suite          | Épisodes réussis |  Épisodes | Taux de réussite |
| -------------- | ------------------: | --------: | -----------: |
| LIBERO Spatial |                 485 |       500 |        97.0% |
| LIBERO Object  |                 496 |       500 |        99.2% |
| Objectif LIBERO    |                 483 |       500 |        96.6% |
| LIBERO-10      |                 469 |       500 |        93.8% |
| **Ensemble**    |           **1,933** | **2,000** |   **96.65%** |

Ces résultats utilisent un seul point de contrôle entraîné et une graine d'évaluation `1000` ; il ne s'agit pas d'une moyenne multi-graines ni d'une estimation de confiance.

#### Recette d'entraînement de référence

Le point de contrôle publié enregistre la configuration complète et résolue de l’étape 2 dans [`train_config.json`](https://huggingface.co/zuoxingdong/evo1_libero/blob/515921f4a2c1d3f3ad523721eafa26fdf2af315b/train_config.json). L’exécution mesurée a utilisé deux GPU H100 avec deux processus DDP et un lot de 64 par processus, soit un lot global de 128. Les deux étapes ont utilisé la même topologie. Le VLM de base provient de la révision `014c0583a0d4bedf29fbe2dbff4f865eb998e171` de `OpenGVLab/InternVL3-1B-hf`. L’artefact publié n’enregistre pas le commit exact d’entraînement LeRobot ni son verrouillage de dépendances d’origine, les commandes ci-dessous reproduisent donc la configuration et la topologie enregistrées à partir d’un checkout actuel, plutôt que de reconstruire l’environnement logiciel bit par bit.

Depuis un dépôt source de LeRobot, installez les dépendances verrouillées et téléchargez cette révision exacte du VLM :

```bash
uv sync --locked --extra training --extra evo1 --extra libero
VLM_DIR=$(uv run hf download OpenGVLab/InternVL3-1B-hf \
  --revision=014c0583a0d4bedf29fbe2dbff4f865eb998e171)
```

L'étape 1 fige le VLM et entraîne la tête d'action pendant 5 000 étapes :

```bash
uv run accelerate launch --num_processes=2 -m lerobot.scripts.lerobot_train \
  --dataset.repo_id=lerobot/libero \
  --dataset.revision=a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 \
  --dataset.video_backend=torchcodec \
  --dataset.return_uint8=true \
  --dataset.image_transforms.enable=true \
  --dataset.use_imagenet_stats=true \
  --dataset.eval_split=0.0 \
  --policy.type=evo1 \
  --policy.training_stage=stage1 \
  --policy.apply_training_stage_defaults=true \
  --policy.vlm_model_name="${VLM_DIR}" \
  --policy.vlm_num_layers=14 \
  --policy.dtype=bfloat16 \
  --policy.device=cuda \
  --policy.use_amp=true \
  --policy.use_flash_attn=true \
  --policy.enable_gradient_checkpointing=true \
  --policy.gradient_checkpointing_use_reentrant=false \
  --policy.image_resolution='[448,448]' \
  --policy.chunk_size=50 \
  --policy.n_action_steps=50 \
  --policy.max_state_dim=24 \
  --policy.max_action_dim=24 \
  --policy.dropout=0.2 \
  --policy.optimizer_lr=1e-5 \
  --policy.optimizer_weight_decay=1e-3 \
  --policy.optimizer_grad_clip_norm=1.0 \
  --policy.scheduler_warmup_steps=1000 \
  --policy.push_to_hub=false \
  --use_policy_training_preset=true \
  --batch_size=64 \
  --steps=5000 \
  --save_checkpoint=true \
  --save_checkpoint_to_hub=false \
  --save_freq=2500 \
  --log_freq=10 \
  --env_eval_freq=0 \
  --num_workers=4 \
  --prefetch_factor=2 \
  --persistent_workers=true \
  --seed=1000 \
  --trackio.enable=false \
  --output_dir=./outputs/evo1-libero-stage1-g128-5k
```

L'étape 2 charge la politique de l'étape 1 mais démarre un nouvel optimiseur et un nouvel ordonnanceur. Elle entraîne le modèle pendant 80 000 étapes ; le point de contrôle signalé est celui enregistré à l'étape 70 000 :

```bash
uv run accelerate launch --num_processes=2 -m lerobot.scripts.lerobot_train \
  --dataset.repo_id=lerobot/libero \
  --dataset.revision=a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4 \
  --dataset.video_backend=torchcodec \
  --dataset.return_uint8=true \
  --dataset.image_transforms.enable=true \
  --dataset.use_imagenet_stats=true \
  --dataset.eval_split=0.0 \
  --policy.path=./outputs/evo1-libero-stage1-g128-5k/checkpoints/005000/pretrained_model \
  --policy.training_stage=stage2 \
  --policy.apply_training_stage_defaults=true \
  --policy.vlm_model_name="${VLM_DIR}" \
  --policy.vlm_num_layers=14 \
  --policy.dtype=float32 \
  --policy.device=cuda \
  --policy.use_amp=true \
  --policy.use_flash_attn=true \
  --policy.enable_gradient_checkpointing=true \
  --policy.gradient_checkpointing_use_reentrant=false \
  --policy.image_resolution='[448,448]' \
  --policy.chunk_size=50 \
  --policy.n_action_steps=50 \
  --policy.max_state_dim=24 \
  --policy.max_action_dim=24 \
  --policy.dropout=0.2 \
  --policy.optimizer_lr=1e-5 \
  --policy.optimizer_weight_decay=1e-3 \
  --policy.optimizer_grad_clip_norm=1.0 \
  --policy.scheduler_warmup_steps=1000 \
  --policy.push_to_hub=false \
  --use_policy_training_preset=true \
  --batch_size=64 \
  --steps=80000 \
  --resume=false \
  --save_checkpoint=true \
  --save_checkpoint_to_hub=false \
  --save_freq=10000 \
  --log_freq=10 \
  --env_eval_freq=0 \
  --num_workers=4 \
  --prefetch_factor=2 \
  --persistent_workers=true \
  --seed=1000 \
  --trackio.enable=false \
  --output_dir=./outputs/evo1-libero-stage2-g128-80k
```

#### Profil d'évaluation au format auteur

Le profil EVO1 LIBERO au format auteur utilise les noms bruts des fonctionnalités de caméra LIBERO (`observation.images.agentview_image` et `observation.images.robot0_eye_in_hand_image`), replanifie toutes les 14 actions et binarise la commande de la pince avant d’exécuter un pas dans le simulateur. Le post-processeur de politique EVO1 peut recadrer l’action 24D rembourrée vers l’espace d’actions 7D de LIBERO et appliquer cette binarisation de la pince. Pour évaluer un point de contrôle au format auteur dans le même réglage d’un épisode par tâche, conservez les noms bruts des caméras au lieu de la correspondance par défaut `image`/`image2` et définissez les drapeaux de post-traitement des actions LIBERO :

```bash
lerobot-eval \
  --policy.path=your-org/your-evo1-libero-checkpoint \
  --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
  --policy.device=cuda \
  --policy.use_flash_attn=true \
  --policy.n_action_steps=14 \
  --policy.postprocess_action_dim=7 \
  --policy.binarize_gripper=true \
  --env.type=libero \
  --env.task=libero_object \
  --env.camera_name_mapping="{agentview_image: agentview_image, robot0_eye_in_hand_image: robot0_eye_in_hand_image}" \
  --env.observation_height=448 \
  --env.observation_width=448 \
  --eval.batch_size=1 \
  --eval.n_episodes=1
```

#### Profil v3 natif `lerobot/libero`

La révision `a1aaacb7f6cd6ee5fb43120f673cebb0cfea7dd4` stocke les caractéristiques de la caméra sous la forme de `image` et `image2`. Cet exemple évalue les dix tâches LIBERO Object, en lançant chaque tâche dans un processus distinct :

```bash
export MUJOCO_GL=egl
export PYOPENGL_PLATFORM=egl

suite=libero_object
horizon=280
for task_id in {0..9}; do
  lerobot-eval \
    --policy.path=zuoxingdong/evo1_libero \
    --policy.pretrained_revision=515921f4a2c1d3f3ad523721eafa26fdf2af315b \
    --policy.vlm_model_name=OpenGVLab/InternVL3-1B-hf \
    --policy.device=cuda \
    --policy.use_amp=true \
    --policy.dtype=bfloat16 \
    --policy.use_flash_attn=false \
    --policy.enable_gradient_checkpointing=false \
    --policy.vlm_num_layers=14 \
    --policy.image_resolution='[448,448]' \
    --policy.max_text_length=1024 \
    --policy.chunk_size=50 \
    --policy.n_action_steps=14 \
    --policy.max_state_dim=24 \
    --policy.max_action_dim=24 \
    --policy.num_inference_timesteps=32 \
    --policy.postprocess_action_dim=7 \
    --policy.binarize_gripper=true \
    --policy.gripper_threshold=0.0 \
    --policy.gripper_below_threshold_value=-1.0 \
    --policy.gripper_above_threshold_value=1.0 \
    --env.type=libero \
    --env.task="${suite}" \
    --env.task_ids="[${task_id}]" \
    --env.camera_name=agentview_image,robot0_eye_in_hand_image \
    --env.camera_name_mapping="{agentview_image: image, robot0_eye_in_hand_image: image2}" \
    --env.control_mode=relative \
    --env.obs_type=pixels_agent_pos \
    --env.observation_width=448 \
    --env.observation_height=448 \
    --env.init_states=true \
    --env.episode_length="${horizon}" \
    --env.render_mode=rgb_array \
    --env.max_parallel_tasks=1 \
    --eval.n_episodes=50 \
    --eval.batch_size=1 \
    --eval.use_async_envs=false \
    --eval.recording=false \
    --seed=1000 \
    --output_dir="./outputs/evo1-libero-stage2-70k-eval/${suite}/task-${task_id}" \
    --job_name="evo1-libero-stage2-70k-${suite}-task-${task_id}"
done
```

Exécutez les dix identifiants de tâches de chaque suite avec ces horizons :

| `env.task`       | `env.episode_length` |
| ---------------- | -------------------: |
| `libero_spatial` |                `280` |
| `libero_object`  |                `280` |
| `libero_goal`    |                `300` |
| `libero_10`      |                `520` |

Définissez `suite` et `horizon` pour chaque ligne. Cela donne 500 épisodes par suite et 2 000 épisodes au total, tandis que le processus neuf par tâche de la boucle correspond à la topologie de réinitialisation du RNG mesurée.

## Références

- [dépôt EVO1](https://github.com/MINT-SJTU/Evo-1)
- [InternVL3-1B-hf](https://huggingface.co/OpenGVLab/InternVL3-1B-hf)

## Licence

Cette intégration LeRobot suit la licence Apache 2.0 utilisée par LeRobot. Consultez les pages des modèles EVO1 et InternVL3 en amont pour les licences des points de contrôle et des données publiés.

