# 4. VLA 학습 실행 (GR00T Fine-tuning)

## VLA(Vision-Language-Action)란?

**VLA(Vision-Language-Action) 모델**은 시각 입력(카메라 이미지)과 언어 지시사항을 이해하고, 로봇의 행동(움직임)을 생성하는 멀티모달 기초 모델입니다. VLA는 기존의 이미지 분류나 객체 인식 모델과 달리, 로봇이 실제로 수행해야 할 **구체적인 작업**(로봇 팔의 위치, 속도, 힘 등)을 출력합니다.

### GR00T N1.7의 특징

| 항목             | 내용                                 |
| -------------- | ---------------------------------- |
| 모델 크기          | 3B 파라미터 (1.62B trainable, 51.54%)  |
| Backbone       | Cosmos-Reason2-2B (Qwen3-VL 아키텍처)  |
| Action 표현      | Relative EEF (현재 자세 대비 상대 변위)      |
| 사전학습 데이터       | 20K 시간 EgoScale 인간 영상 + 로봇 데모      |
| Fine-tuning 방식 | Projector + Diffusion Model 선택적 학습 |
| 지원 데이터셋        | LeRobot v2 포맷                      |

### Fine-tuning이 중요한 이유

사전학습된 GR00T 모델은 일반적인 로봇 작업에 잘 작동하지만, 특정 로봇 플랫폼(예: ALOHA, Mobile Manipulator)과 특정 작업(예: 서랍 열기, 물건 집기)에 대해서는 **커스텀 데이터셋으로 추가 학습**(Fine-tuning)이 필요합니다. 이렇게 하면:

1. **작업 특화 성능**: 모델이 특정 작업에 더 정확한 행동을 생성
2. **데이터 효율성**: 적은 데이터량(수백\~수천 샘플)으로 빠르게 학습 가능
3. **비용 효율성**: GPU 1개에서도 학습 가능하여 인프라 비용 절감

***

SLURM을 사용하여 GR00T VLA 모델의 Fine-tuning 작업을 제출합니다. HyperPod가 자동으로 GPU 노드를 프로비저닝하고, 학습이 끝나면 노드를 해제합니다.

***

## 4.1 학습 환경 준비

GR00T 학습에는 **Python 가상환경(venv) 방식**을 사용합니다. 컨테이너가 필요 없으며, FSx에 공유 환경을 한 번 설치하면 모든 노드에서 사용할 수 있습니다.

```bash
# GR00T 학습 환경 설치 (약 5-10분)
bash /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/scripts/setup_groot_env.sh
```

이 스크립트는 다음을 수행합니다:

* 시스템 패키지 설치 (`ffmpeg`, `git-lfs`)
* `uv` 패키지 매니저 설치
* Isaac-GR00T 저장소 클론 (`/fsx/scratch/Isaac-GR00T`)
* Python 3.10 가상환경 생성 (`/fsx/envs/gr00t`)
* GR00T 패키지 + 의존성 설치 (`bitsandbytes`, `flash-attn` 등)

### 설치 확인

```bash
source /fsx/envs/gr00t/bin/activate
python -c "import gr00t; print('GR00T OK')"
python -c "import torch; print(f'PyTorch {torch.__version__}, CUDA: {torch.cuda.is_available()}')"
```

{% hint style="info" %}
Head node(ml.m5.xlarge)에는 GPU가 없으므로 `CUDA: False`가 정상입니다. Compute node(GPU 인스턴스)에서는 `CUDA: True`가 됩니다. SLURM 작업은 GPU가 있는 compute node에서 실행됩니다.
{% endhint %}

### HuggingFace 토큰 설정 (필수)

GR00T N1.7은 **gated model**입니다. 학습 전 반드시 토큰을 설정하세요:

1. <https://huggingface.co/nvidia/GR00T-N1.7-3B> → "Request access" 클릭
2. <https://huggingface.co/nvidia/Cosmos-Reason2-2B> → "Request access" 클릭
3. <https://huggingface.co/settings/tokens> 에서 Read 권한 토큰 생성

```bash
# 토큰 저장 (학습 스크립트에서 자동으로 읽음)
echo "hf_xxxxxxxxxxxx" > /fsx/scratch/.hf_token
```

***

## 4.2 GR00T N1.7 Fine-tuning CLI

GR00T N1.7은 `gr00t.experiment.launch_finetune` 모듈로 fine-tuning을 수행합니다:

```bash
# 기본 fine-tuning 명령 (단일 GPU)
python -m gr00t.experiment.launch_finetune \
  --base-model-path nvidia/GR00T-N1.7-3B \
  --dataset-path /fsx/datasets/groot/demo_data \
  --embodiment-tag OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT \
  --num-gpus 1 \
  --global-batch-size 2 \
  --max-steps 2000 \
  --save-steps 2000 \
  --no-use-wandb \
  --output-dir /fsx/checkpoints/vla/groot-demo_data
```

**주요 파라미터:**

| 파라미터                            | 설명                                 | 기본값       |
| ------------------------------- | ---------------------------------- | --------- |
| `--base-model-path`             | 베이스 모델 (HuggingFace repo 또는 로컬 경로) | 필수        |
| `--dataset-path`                | LeRobot v2 포맷 데이터셋 경로              | 필수        |
| `--embodiment-tag`              | 로봇 플랫폼 태그                          | 필수        |
| `--num-gpus`                    | 사용할 GPU 수                          | 1         |
| `--global-batch-size`           | 글로벌 배치 크기                          | 2         |
| `--gradient-accumulation-steps` | Gradient accumulation 스텝           | 2         |
| `--max-steps`                   | 최대 학습 스텝                           | 10000     |
| `--save-steps`                  | 체크포인트 저장 주기                        | 2000      |
| `--save-total-limit`            | 최대 저장 체크포인트 수                      | 5         |
| `--output-dir`                  | 체크포인트 저장 경로                        | ./outputs |
| `--no-use-wandb`                | WandB 로깅 비활성화                      | -         |
| `--dataloader-num-workers`      | 데이터 로딩 워커 수                        | 2         |

### 지원되는 Embodiment Tags

| Tag                                     | Robot/Dataset           | 비고                          |
| --------------------------------------- | ----------------------- | --------------------------- |
| `OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT` | DROID dataset           | Zero-shot + Fine-tune       |
| `LIBERO_PANDA`                          | LIBERO simulation       | Fine-tune only              |
| `SIMPLER_ENV_GOOGLE`                    | SimplerEnv Google Robot | Fine-tune only              |
| `SIMPLER_ENV_WIDOWX`                    | SimplerEnv WidowX       | Fine-tune only              |
| `XDOF`                                  | Generic X-DOF           | Zero-shot                   |
| `NEW_EMBODIMENT`                        | Custom robot            | `--modality-config-path` 필요 |

***

## 4.3 SLURM 작업 제출

### 기본 학습 (데모 데이터)

```bash
# HuggingFace 토큰 설정 (필수)
export HF_TOKEN="hf_xxxxxxxxxxxx"
# 또는 이미 파일로 저장한 경우 자동으로 읽힘: /fsx/scratch/.hf_token

# 학습 작업 제출
sbatch /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/slurm-templates/vla/finetune_groot_venv.sbatch
```

기본 설정:

* Dataset: `/fsx/datasets/groot/demo_data` (Isaac-GR00T 내장 DROID 샘플)
* GPU: 1개 (A10G 24GB)
* Batch size: 2, Max steps: 2000

### 커스텀 설정으로 학습

환경 변수로 학습 파라미터를 조정할 수 있습니다:

```bash
# 테스트용 짧은 학습 (10 steps)
export HF_TOKEN="hf_xxxxxxxxxxxx"
export MAX_STEPS=10
export DATASET_PATH=/fsx/datasets/groot/demo_data
export EMBODIMENT_TAG=OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT

sbatch /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/slurm-templates/vla/finetune_groot_venv.sbatch
```

### run\_vla.sh 래퍼 사용 (선택)

```bash
# 래퍼 스크립트로 간편 제출
/fsx/scratch/aws-physical-ai-recipes/training/hyperpod/slurm-templates/vla/run_vla.sh \
  --model groot --dataset demo_data --max-steps 2000
```

작업 제출 시 출력:

```
Submitted batch job 12345
```

{% hint style="warning" %}
**HyperPod 노드 프로비저닝:** 작업 제출 시 HyperPod가 GPU 노드를 자동으로 프로비저닝합니다. 초기에는 `PD(Pending)` 상태를 유지하며, 노드 시작까지 수분이 걸릴 수 있습니다.
{% endhint %}

### 학습 환경 변수 목록

| 변수                  | 기본값                                        | 설명                                |
| ------------------- | ------------------------------------------ | --------------------------------- |
| `HF_TOKEN`          | (필수)                                       | HuggingFace 토큰                    |
| `NUM_GPUS`          | 1                                          | 사용할 GPU 수                         |
| `DATASET`           | demo\_data                                 | 데이터셋 이름 (/fsx/datasets/groot/ 하위) |
| `DATASET_PATH`      | /fsx/datasets/groot/${DATASET}             | 전체 경로 (DATASET보다 우선)              |
| `EMBODIMENT_TAG`    | oxe\_droid\_relative\_eef\_relative\_joint | 로봇 태그                             |
| `BASE_MODEL`        | nvidia/GR00T-N1.7-3B                       | 베이스 모델                            |
| `MAX_STEPS`         | 2000                                       | 학습 스텝                             |
| `GLOBAL_BATCH_SIZE` | 2                                          | 배치 크기                             |
| `GRAD_ACCUM`        | GLOBAL\_BATCH\_SIZE                        | Gradient accumulation             |
| `SAVE_STEPS`        | 2000                                       | 체크포인트 주기                          |
| `OUTPUT_DIR`        | /fsx/checkpoints/vla/groot-${DATASET}      | 저장 경로                             |

***

## 4.4 SLURM 개념 설명

HyperPod에서 학습 작업을 효율적으로 관리하기 위해 알아야 할 SLURM 명령:

### sbatch: 배치 작업 제출

```bash
# 스크립트 파일로 작업 제출
sbatch train_job.sh

# 인라인으로 작업 제출
sbatch << 'EOF'
#!/bin/bash
#SBATCH --nodes=1
#SBATCH --gres=gpu:1
echo "Hello from SLURM"
EOF
```

**주요 옵션:**

| 옵션             | 설명                             |
| -------------- | ------------------------------ |
| `--job-name`   | 작업 이름                          |
| `--partition`  | 작업 큐 (HyperPod Managed: `dev`) |
| `--nodes`      | 요청 노드 수                        |
| `--gres=gpu:N` | GPU 수 (N = 1, 2, 4, 8 등)       |
| `--time`       | 최대 실행 시간 (HH:MM:SS)            |
| `--output`     | 표준 출력 파일                       |
| `--error`      | 표준 에러 파일                       |

### squeue: 작업 큐 확인

```bash
# 모든 작업 확인
squeue

# 특정 작업 상태 확인
squeue -j <JOB_ID>

# 현재 사용자의 작업만 확인
squeue -u $USER

# 실시간 모니터링 (2초마다 새로고침)
watch squeue
```

출력 예:

```
             JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)
             12345       dev groot-fi ubuntu    R    10:25      1 ip-10-0-1-42
             12346       dev test-run ubuntu    PD       0:00      1 (Priority)
```

**상태 설명:**

| 상태          | 코드 | 의미                |
| ----------- | -- | ----------------- |
| Pending     | PD | GPU 노드 프로비저닝 대기 중 |
| Running     | R  | 학습 실행 중           |
| Completed   | CD | 정상 완료             |
| Failed      | F  | 오류로 종료            |
| Cancelled   | CA | 사용자가 취소           |
| Configuring | CF | 노드 설정 중           |

### scancel: 작업 취소

```bash
# 특정 작업 취소
scancel <JOB_ID>

# 사용자의 모든 작업 취소
scancel -u $USER
```

***

## 4.5 작업 모니터링

### 실시간 로그 확인

```bash
# 작업 로그 실시간 확인
tail -f /fsx/scratch/logs/groot-<JOB_ID>.out

# 에러 로그 확인
tail -f /fsx/scratch/logs/groot-<JOB_ID>.err

# 마지막 100줄 확인
tail -100 /fsx/scratch/logs/groot-<JOB_ID>.out
```

### 정상 학습 진행 시 로그 예시

```
==================================================
GR00T Fine-tuning Job (venv mode)
==================================================
Job ID: 31
Node: ip-10-0-1-153
Environment: /fsx/envs/gr00t
Base Model: nvidia/GR00T-N1.7-3B
Dataset: /fsx/datasets/groot/demo_data
Output: /fsx/checkpoints/vla/groot-demo_data
GPUs: 1
Max Steps: 2000
Batch Size: 2
Start: Mon May  4 04:52:08 UTC 2026
==================================================
...
🚀 Starting training...
  0%|          | 0/2000 [00:00<?, ?it/s]
 10%|█         | 1/10 [00:58<08:47, 58.65s/it]
 ...
100%|██████████| 10/10 [01:11<00:00,  2.07s/it]
Model saved to /fsx/checkpoints/vla/groot-demo_data
Training completed!
==================================================
Fine-tuning completed successfully
End: Mon May  4 04:57:43 UTC 2026
==================================================
```

### GPU 메모리 모니터링

작업이 Running 상태일 때 compute node에 SSH로 접속하여 확인:

```bash
# Head Node에서 compute node 확인
squeue  # NODELIST 컬럼에서 노드 IP 확인

# Compute node에 SSH 접속
ssh ubuntu@<COMPUTE_NODE_IP>
nvidia-smi
```

***

## 4.6 메모리 최적화 (자동 적용)

학습 스크립트(`finetune_groot_venv.sbatch`)는 **A10G (24GB)에서 OOM 없이 동작**하도록 다음 최적화를 자동 적용합니다:

| 최적화                       | 효과                         | 설명                              |
| ------------------------- | -------------------------- | ------------------------------- |
| BF16 model loading        | 모델 메모리 절반 (\~12GB → \~6GB) | `config.model.load_bf16 = True` |
| Gradient checkpointing    | 활성화 메모리 절약                 | 속도↓ 메모리↑ 트레이드오프                 |
| 8-bit PagedAdam optimizer | 옵티마이저 메모리 75% 감소           | `paged_adamw_8bit` 사용           |

이 최적화들은 `launch_finetune.py`를 runtime에 `sed`로 패치하는 방식으로 적용됩니다. 별도의 설정 없이 `sbatch`만 실행하면 됩니다.

{% hint style="info" %}
**메모리 요구사항:**

* 최적화 적용 시: \~16GB VRAM (A10G 24GB에서 충분)
* 최적화 미적용 시: \~30GB+ VRAM (A10G에서 OOM 발생)

멀티 GPU (4x A10G = 96GB) 환경에서는 최적화 없이도 동작하지만, 단일 GPU에서는 필수입니다.
{% endhint %}

***

## 4.7 체크포인트 확인

학습이 완료되면 체크포인트가 FSx에 저장되고, S3로 자동 익스포트됩니다:

```bash
# FSx에서 확인
ls -la /fsx/checkpoints/vla/groot-demo_data/

# 체크포인트 내용
ls /fsx/checkpoints/vla/groot-demo_data/checkpoint-2000/

# 파일 크기 확인
du -sh /fsx/checkpoints/vla/groot-demo_data/*
```

정상적으로 완료된 체크포인트 구조:

```
/fsx/checkpoints/vla/groot-demo_data/
└── checkpoint-2000/
    ├── config.json
    ├── model-00001-of-00002.safetensors
    ├── model-00002-of-00002.safetensors
    ├── model.safetensors.index.json
    ├── processor_config.json
    ├── statistics.json
    ├── training_args.bin
    └── ...
```

### S3 자동 익스포트 확인

FSx DRA를 통해 체크포인트가 자동으로 S3에 동기화됩니다 (수분 소요):

```bash
# S3에서 확인
aws s3 ls s3://${BUCKET}/checkpoints/vla/groot-demo_data/ --recursive --region us-east-1
```

***

## 4.8 Open-loop 추론 테스트

학습된 모델로 데이터셋 대비 추론 정확도를 확인합니다:

```bash
source /fsx/envs/gr00t/bin/activate
cd /fsx/scratch/Isaac-GR00T

python /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/examples/vla/verify_in_sim.py \
  --model-path /fsx/checkpoints/vla/groot-demo_data/checkpoint-2000 \
  --dataset-path /fsx/scratch/Isaac-GR00T/demo_data/droid_sample \
  --embodiment-tag OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT \
  --traj-ids 0 1 2
```

**예상 출력:**

```
Model: /fsx/checkpoints/vla/groot-demo_data/checkpoint-2000
Dataset: /fsx/scratch/Isaac-GR00T/demo_data/droid_sample
Embodiment: OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT
Trajectories: [0, 1, 2]
Action horizon: 16

Loading model...
Loading dataset...

  Trajectory 0:
    Steps evaluated: 7, MSE: 0.016083
  Trajectory 1:
    Steps evaluated: 7, MSE: 0.001609
  Trajectory 2:
    Steps evaluated: 7, MSE: 0.034067

Overall MSE: 0.017253 (+/- 0.013277)

Evaluation complete.
```

MSE가 작을수록 학습이 잘 된 것입니다. 2000 steps 이상 학습하면 MSE가 더 낮아집니다.

> `MAX_STEPS=10`으로 테스트한 경우 `checkpoint-10`을 사용하세요.

***

## 4.9 트러블슈팅

| 증상                        | 원인                       | 해결 방법                                                                                    |
| ------------------------- | ------------------------ | ---------------------------------------------------------------------------------------- |
| Job이 PD(Pending)에 멈춤      | GPU 용량 부족                | 잠시 대기하거나 다른 시간에 재시도. `ml.g5.4xlarge`로 충분                                                 |
| `CUDA out of memory`      | 메모리 최적화 미적용              | `GLOBAL_BATCH_SIZE=1`로 줄이거나, sbatch 스크립트의 sed 패치 적용 확인                                   |
| `OSError: gated repo`     | HF 토큰 미설정                | `echo "hf_xxx" > /fsx/scratch/.hf_token` 또는 `export HF_TOKEN=hf_xxx`                     |
| `RuntimeError: No FFmpeg` | ffmpeg 미설치               | `sudo apt-get install -y ffmpeg`                                                         |
| Virtual env not found     | setup\_groot\_env.sh 미실행 | `bash /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/scripts/setup_groot_env.sh` |
| 8-bit optimizer 패치 실패     | bitsandbytes 미설치         | `source /fsx/envs/gr00t/bin/activate && pip install bitsandbytes`                        |
| slurmd not running        | Compute node 초기화 미완료     | `ssh ubuntu@<node-ip> 'sudo systemctl restart slurmd'`                                   |
| 로그 파일이 비어있음               | 노드 프로비저닝 중               | `scontrol show job <JOB_ID>`로 상태 확인                                                      |

***

***

## 4.10 VLA Closed-loop 평가 (Advanced)

Open-loop 평가(MSE)는 모델이 데이터를 잘 피팅했는지 확인하지만, **실제로 로봇이 작업을 완수하는지**는 알 수 없습니다. Closed-loop 평가는 학습된 GR00T 정책을 시뮬레이션에서 실행하여 작업 성공률을 측정합니다.

### 평가 방식 비교

|       | Open-loop (4.8)             | Closed-loop (4.10)         |
| ----- | --------------------------- | -------------------------- |
| 방법    | 데이터셋 이미지 → 모델 → 예측 vs GT 비교 | 시뮬레이션 → 모델 → 로봇 제어 → 결과 관찰 |
| 측정    | MSE (수치)                    | 작업 성공률 (%)                 |
| 필요 환경 | GPU만                        | GPU + Isaac Sim            |
| 소요 시간 | 수초                          | 수분                         |

### 실행 (로컬 모델 + 데이터셋 비교)

`--dataset-path`를 지정하면 데이터셋의 궤적(trajectory)에 대해 open-loop 방식으로 예측 vs GT를 비교합니다:

```bash
source /fsx/envs/gr00t/bin/activate
cd /fsx/scratch/Isaac-GR00T

python /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/examples/vla/eval_closed_loop.py \
  --model-path /fsx/checkpoints/vla/groot-demo_data/checkpoint-2000 \
  --embodiment-tag OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT \
  --dataset-path /fsx/scratch/Isaac-GR00T/demo_data/droid_sample \
  --num-episodes 3
```

**예상 출력:**

```
GR00T policy loaded from /fsx/checkpoints/vla/groot-demo_data/checkpoint-2000
  Embodiment: EmbodimentTag.OXE_DROID_RELATIVE_EEF_RELATIVE_JOINT
  Modalities: ['video', 'state', 'action', 'language']

============================================================
GR00T Closed-loop Evaluation
============================================================
  Episodes: 3
  Max steps/episode: 300
  Instruction: pick up the object

--- Open-loop evaluation (vs dataset) ---
  Episode 0: steps_evaluated=7, MSE=0.005112
  Episode 1: steps_evaluated=7, MSE=0.002330
  Episode 2: steps_evaluated=7, MSE=0.012278

  Mean MSE: 0.0066

============================================================
Evaluation complete.
```

### 실행 (원격 GR00T 서버 연동)

GR00T 추론 서버가 별도 노드에서 실행 중인 경우:

```bash
python /fsx/scratch/aws-physical-ai-recipes/training/hyperpod/examples/vla/eval_closed_loop.py \
  --policy-host 10.0.1.100 \
  --policy-port 5555 \
  --instruction "pick up the cube" \
  --num-episodes 5
```

{% hint style="info" %}
`--dataset-path` 없이 실행하면 synthetic observation으로 closed-loop 구조를 테스트합니다. 완전한 closed-loop 시뮬레이션(Isaac Sim 환경에서 로봇 제어)은 [RL Track](/physical-ai-on-aws/physical-ai-on-aws-guide/hyperpod-distributed-training/5.-rl-training.md)의 Isaac Lab 환경에서 수행할 수 있습니다.
{% endhint %}

***

## References

* [NVIDIA GR00T Model Card](https://huggingface.co/nvidia/GR00T-N1.7-3B)
* [Isaac-GR00T Repository](https://github.com/NVIDIA/Isaac-GR00T)
* [SLURM Documentation](https://slurm.schedmd.com/)
* [AWS HyperPod User Guide](https://docs.aws.amazon.com/sagemaker/latest/dg/hyperpod.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hi-space.gitbook.io/physical-ai-on-aws/physical-ai-on-aws-guide/hyperpod-distributed-training/4.-vla-training.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
