21. Ajuste fino del SO-ARM con Isaac GR00T
Capítulo 21 del curso para principiantes de SO-ARM Physical AI — monta el entorno Isaac-GR00T, ajusta GR00T N1.5 sobre tu dataset de SO-ARM con la configuración so100_dualcam, y ejecuta la inferencia con el servidor GR00T y el cliente de control SO-100, en estación de trabajo o Jetson AGX Thor.
21.1 Elige tu vía de entrenamiento
21.1 Elige tu vía de entrenamiento
Este capítulo sigue la vía Isaac-GR00T de la guía oficial de ajuste SO101 de NVIDIA — la misma receta del tutorial de Seeed SO101 + GR00T en Jetson Thor. Tres formas de conseguir el cómputo:
| Vía | Hardware | Notas |
|---|---|---|
| Estación local | Clase RTX 4090 / A6000 (Ampere+, ~25GB VRAM) | Lo que asume este capítulo |
| NVIDIA Brev en la nube | Un navegador | Los mismos comandos en un notebook; exporta y descarga el checkpoint |
| Sin GPU | — | Salta al Capítulo 22: la vía sin código de SenseCraft Robotics |
El entrenamiento o ajuste de GR00T requiere GPU con arquitectura Ampere o posterior (p. ej. RTX A6000, RTX 4090). V100 (Volta) no está soportado.
21.2 Montar el entorno
21.2 Montar el entorno
Crea un entorno dedicado (separado del lerobot está bien):
git clone https://github.com/NVIDIA/Isaac-GR00T
cd Isaac-GR00T
conda create -n gr00t python=3.10
conda activate gr00t
pip install --upgrade setuptools
pip install -e .[base]
pip install --no-build-isolation flash-attn==2.7.1.post4
flash-attn es el paso que más suele fallar — debe coincidir con tu build de PyTorch/CUDA. Si compila con error: revisa python -c "import torch; print(torch.version.cuda)", instala ninja y packaging primero, y reintenta.
El modelo fundacional se descarga automáticamente de Hugging Face al primer uso: nvidia/GR00T-N1.5-3B.
21.3 Ajuste fino sobre tu dataset de SO-ARM
21.3 Ajuste fino sobre tu dataset de SO-ARM
Con el dataset del Capítulo 20 listo (aquí ./demo_data/so101-table-cleanup/ — sustituye por tu ruta):
python scripts/gr00t_finetune.py \
--dataset-path ./demo_data/so101-table-cleanup/ \
--num-gpus 1 \
--output-dir ./so101-checkpoints \
--max-steps 10000 \
--data-config so100_dualcam \
--video-backend torchvision_av
Parámetros clave:
--dataset-path: tu carpeta LeRobot (la del Capítulo 20);--data-config so100_dualcam: la configuración estándar de dos cámaras del SO-ARM;--max-steps: 10,000 es un buen primer punto para ~50 episodios;--video-backend torchvision_av: el backend de decodificación;- Para ajustar desde un modelo base guardado localmente, añade
--base-model-path ./pretrained/GR00T-N1.5-3B.
El ajuste por defecto requiere ~25GB de VRAM. Si no te llega, añade --no-tune_diffusion_model — congela la cabeza DiT y entrena menos, pero cabe en tarjetas menores.
Vigila la pérdida como en el Capítulo 15; espera un tiempo por paso notablemente mayor que ACT — el modelo tiene ~3.000 millones de parámetros.
Exportar desde un notebook en la nube (vía Brev)
La barra lateral de Jupyter no navega dentro de las carpetas de entrenamiento. Comprime primero el checkpoint en .zip o .tar.gz y descarga el archivo desde la interfaz del notebook.
21.4 Ejecutar la inferencia: servidor + cliente de control
21.4 Ejecutar la inferencia: servidor + cliente de control
La inferencia mueve el brazo real sin humano en el bucle. Despeja el espacio, aleja las manos y ten lista la opción de cortar la corriente.
Para el mejor rendimiento, replica el montaje de la recolección lo más fielmente posible — mismas cámaras, mismas posiciones, misma luz. La generalización del modelo es limitada.
Terminal 1 — lanza el servicio de inferencia GR00T:
python scripts/inference_service.py --server \
--model_path ./so101-checkpoints \
--embodiment-tag new_embodiment \
--data-config so100_dualcam \
--denoising-steps 4
Terminal 2 — lanza el cliente de control (el ejemplo oficial SO-100, escrito para este brazo):
python examples/SO-100/eval_lerobot.py \
--robot.type=so100_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=my_awesome_follower_arm \
--robot.cameras="{ wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, front: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
--policy_host=0.0.0.0 \
--lang_instruction="Grab pens and place into pen holder."
Notas:
- Sustituye
index_or_pathpor tus índices — búscalos conls /dev/video*olerobot-find-cameras opencv. Deben ser las mismas vistas (frontal + lateral/pinza) que en el dataset. - Cambia
--lang_instructionpor la frase exacta de tu dataset — el condicionamiento lingüístico en vivo (Capítulo 18). - Cliente y servidor pueden correr en la misma máquina, o el servidor en otra máquina con GPU / Jetson Thor de la red.
21.5 Despliegue en el borde con Jetson AGX Thor
21.5 Despliegue en el borde con Jetson AGX Thor
Jetson AGX Thor aporta cómputo suficiente para correr la inferencia de GR00T N1.5 en el borde. Todas las dependencias vienen en una imagen Docker dedicada:
sudo docker run --rm -it \
--network=host \
-e NVIDIA_DRIVER_CAPABILITIES=compute,utility,video,graphics \
--runtime nvidia \
--privileged \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v /etc/X11:/etc/X11 \
--device /dev/nvhost-vic \
-v /dev:/dev \
<image_name>:<tag>
Dentro del contenedor:
git clone https://github.com/NVIDIA/Isaac-GR00T.git
cd Isaac-GR00T
pip install --upgrade setuptools
pip install -e .[thor]
El ajuste (opcional, si lo saltaste en la nube) usa el mismo gr00t_finetune.py de 21.3; luego corre el mismo par servidor + cliente de 21.4. El recorrido completo de Jetson Thor — flasheo, entorno, recolección, entrenamiento en Brev, despliegue — está en el tutorial completo: Ajusta GR00T N1.5 para LeRobot SO-ARM y despliégalo en Jetson Thor.
21.6 Vía alternativa: la política groot de LeRobot
21.6 Vía alternativa: la política groot de LeRobot
Si prefieres quedarte en la cadena LeRobot de la Etapa 3, la política --policy.type=groot también sirve (requiere flash-attn y GPU CUDA):
pip install "lerobot[groot]"
accelerate launch \
--num_processes=1 \
$(which lerobot-train) \
--output_dir=outputs/train/groot_so101 \
--save_checkpoint=true \
--batch_size=64 \
--steps=20000 \
--policy.type=groot \
--policy.repo_id=${HF_USER}/groot_so101 \
--dataset.repo_id=seeedstudio123/test \
--wandb.enable=true
Exige más entorno que ACT/Pi0 — el consejo oficial se mantiene: primero ACT de extremo a extremo, luego GR00T. La evaluación usa la receta familiar lerobot-record ... --policy.path del Capítulo 16.
21.7 Evaluación e iteración
21.7 Evaluación e iteración
Reusa íntegro el marco del Capítulo 16 — criterios, inicios variados, tasa de éxito, clasificación de fallos — con dos añadidos propios de VLA:
- Matriz de instrucciones: evalúa cada frase de tarea de tu dataset; una VLA debe cambiar de comportamiento al cambiar la frase;
- Sonda de instrucción no grabada: prueba una frase que no registraste — donde acierte, es generalización lingüística; donde falle, aparece la frontera de distribución del Capítulo 18. Responde a los fallos con datos, no con esperanza.
21.8 FAQ de solución de problemas
21.8 FAQ de solución de problemas
| Problema | Solución |
|---|---|
| Fallo/descarga lenta del modelo | Descarga manual nvidia/GR00T-N1.5-3B y pasa --base-model-path |
Fallo al compilar flash-attn | Revisa el par PyTorch/CUDA; instala ninja + packaging; usa la versión fijada 2.7.1.post4 |
| CUDA OOM al ajustar | Añade --no-tune_diffusion_model; reduce el batch |
| V100 rechazada | Esperado — se requiere Ampere+ |
| El cliente no alcanza al servidor | --policy_host debe ser la IP alcanzable del servidor; revisa firewall/puerto |
| El brazo se mueve pero ignora la tarea | Claves de cámara o frase distintas del dataset — reglas de los Capítulos 19-20 |