GR00T N1.7 파인튜닝 가이드 — ROBOTIS FFW_SG2 · L-Table Pick & Place

이미 만든 LeRobot 데이터셋 (JSHNSL/ffw_sg2_ltable_merge, 596 ep · 19-dim · cam_head 1대)으로 NVIDIA GR00T N1.7 (3B VLA) 을 파인튜닝하고 ROBOTIS cyclo_intelligence 로 배포하기까지의 처음부터 끝까지.

관련: LeRobot 정책(ACT/VQ-BeT/Diffusion) 전체 파이프라인은 → JSHNSL/humanoid-imitation-learning

☁️ EC2(40GB+ GPU)에서 diffusion head까지 제대로 학습하려면EC2.md (tmux · 인스턴스 선택 · 과금 주의 · action head 학습).


이 repo에 든 설정 파일 (터미널에서 바로 받기)

편집 없이 그대로 쓰는 완성본 2개. 다른 컴퓨터에서도 아래 한 줄이면 받아진다.

파일 무엇 놓을 위치
modality.json 19-dim · 카메라 1대 modality <데이터셋>/meta/modality.json
ffw_sg2_ltable_config.py embodiment config (NEW_EMBODIMENT) <Isaac-GR00T>/examples/CYCLO/ffw_sg2_ltable/

curl (제일 간단):

BASE=https://huggingface.co/JSHNSL/gr00t-ffw-sg2-finetune/resolve/main

# 데이터셋 meta/ 로
curl -fsSL "$BASE/modality.json" \
     -o ~/groot_data/JSHNSL/ffw_sg2_ltable_merge/meta/modality.json

# Isaac-GR00T examples 로
mkdir -p ~/Isaac-GR00T/examples/CYCLO/ffw_sg2_ltable
curl -fsSL "$BASE/ffw_sg2_ltable_config.py" \
     -o ~/Isaac-GR00T/examples/CYCLO/ffw_sg2_ltable/ffw_sg2_ltable_config.py

또는 hf CLI (repo 통째로):

hf download JSHNSL/gr00t-ffw-sg2-finetune modality.json ffw_sg2_ltable_config.py --local-dir ./gr00t_cfg
# 받은 뒤 각 위치로 복사

배치는 아래 3단계에 상세히 있다 (curl 대신 파일 직접 편집 옵션 포함).


이 가이드가 전제하는 것

항목
데이터셋 JSHNSL/ffw_sg2_ltable_merge (LeRobot v3.0)
state / action 19-dimarm_left(8) · arm_right(8) · head(2) · lift(1) (odometry 없음)
카메라 1대observation.images.cam_head (376×672)
베이스 모델 nvidia/GR00T-N1.7-3B (3B) + 백본 nvidia/Cosmos-Reason2-2B (gated)
학습 코드 ROBOTIS 포크 ROBOTIS-GIT/Isaac-GR00T-n1.7

⚠️ NVIDIA 원본이 아니라 ROBOTIS 포크를 써야 한다. 배포하는 cyclo_intelligence가 이 포크를 서브모듈로 쓰므로, 같은 코드로 학습해야 체크포인트가 로드된다.


0. 사전 준비

GPU

요구
파인튜닝 40GB+ 권장 (H100 / L40 / A100). A6000도 됨(느림)
추론 16GB+

GR00T N1.7은 3B지만 기본 설정이 VLM 백본을 얼리고(tune_llm=False, tune_visual=False) projector + diffusion action head만 학습한다. 그래서 24GB에서도 --global_batch_size 를 낮추면 될 여지가 있다 (스모크 테스트에서 실측). RTX 5090(32GB)에서 batch 8 = 31GB 사례 있음.

gated 백본 승인 (필수)

GR00T의 VLM 백본 Cosmos-Reason2-2B 는 접근 승인이 필요하다. → https://huggingface.co/nvidia/Cosmos-Reason2-2B 에서 로그인 후 "Agree and access repository" 클릭.

토큰

export HF_TOKEN=hf_당신토큰      # gated 백본 다운로드용 (read 토큰으로 충분)

1. Isaac-GR00T 설치 (ROBOTIS 포크)

git-lfs 먼저 (필수 — 클론 전에)

sudo apt install git-lfs && git lfs install

안 하면 demo_data/·wheel 파일이 LFS 포인터(수십 바이트) 로 받아져 uv syncInvalid zip file structure 로 실패한다.

클론 + 커밋 고정

cd ~
git clone --recurse-submodules https://github.com/ROBOTIS-GIT/Isaac-GR00T-n1.7.git Isaac-GR00T
cd Isaac-GR00T
git checkout e81d02b5c561dfafd0556f2a4a602016e670920c   # cyclo_intelligence 서브모듈과 동일 커밋

배포 쪽이 쓰는 커밋: cd ~/cyclo_intelligence && git submodule status cyclo_brain/policy/groot/Isaac-GR00T

환경 — Docker 권장

호스트 CUDA가 13이어도 컨테이너가 CUDA 12.8을 자체 포함하므로 안전하다.

cd ~/Isaac-GR00T
bash docker/build.sh          # nvidia/cuda:12.8.0 기반, flash-attn 등 포함
docker images | grep gr00t

uv로 호스트에 직접 설치도 가능하다:

curl -LsSf https://astral.sh/uv/install.sh | sh
sudo apt-get install -y ffmpeg
uv sync --python 3.10            # dGPU x86_64 = Python 3.10

단 호스트 CUDA 13이면 Triton 패치가 필요할 수 있다: uv run bash scripts/patch_triton_cuda13.sh


2. 데이터 다운로드 + v3.0 → v2.0 변환

GR00T는 LeRobot v2 포맷을 쓴다. 변환 스크립트가 HF에서 받아서 변환까지 한다. 별도 uv 환경을 쓴다 (lerobot 버전이 본체와 다름):

sudo apt-get install -y ffmpeg      # 비디오 재인코딩에 필요 (아직 안 했으면)

cd ~/Isaac-GR00T/scripts/lerobot_conversion
uv venv && source .venv/bin/activate
uv pip install -e .
GIT_LFS_SKIP_SMUDGE=1 uv pip install \
  "lerobot @ git+https://github.com/huggingface/lerobot.git@c75455a6de5c818fa1bb69fb2d92423e86c70475"

python convert_v3_to_v2.py \
  --repo-id JSHNSL/ffw_sg2_ltable_merge \
  --root ~/groot_data

deactivate

결과:

~/groot_data/JSHNSL/ffw_sg2_ltable_merge        ← v2.0  (이걸 학습에 씀)
~/groot_data/JSHNSL/ffw_sg2_ltable_merge_v3.0   ← 원본 v3.0 백업

확인:

ls ~/groot_data/JSHNSL/ffw_sg2_ltable_merge/meta/
# info.json  episodes.jsonl  tasks.jsonl  stats.json ...

GPU 불필요. 596ep 비디오 재인코딩이라 시간이 걸린다.


3. 설정 파일 2개 — 이 repo에서 받아서 배치 (편집 불필요)

ROBOTIS의 examples/CYCLO/ffw_sg2_rev122-dim(+odometry) · 카메라 3대(+wrist) 를 요구하는데 우리 데이터는 19-dim · 카메라 1대다. 그대로 쓰면 없는 차원/비디오 키를 참조해 깨진다. → odometry 빼고 카메라 1대로 맞춘 완성본 2개를 이 repo에 넣어뒀다. 편집 없이 받아서 배치만 하면 된다.

파일 놓을 위치
modality.json <데이터셋>/meta/modality.json
ffw_sg2_ltable_config.py <Isaac-GR00T>/examples/CYCLO/ffw_sg2_ltable/
BASE=https://huggingface.co/JSHNSL/gr00t-ffw-sg2-finetune/resolve/main
DS=~/groot_data/JSHNSL/ffw_sg2_ltable_merge

# ① modality.json → 데이터셋 meta/
curl -fsSL "$BASE/modality.json" -o "$DS/meta/modality.json"

# ② config.py → Isaac-GR00T examples/CYCLO/ffw_sg2_ltable/
mkdir -p ~/Isaac-GR00T/examples/CYCLO/ffw_sg2_ltable
curl -fsSL "$BASE/ffw_sg2_ltable_config.py" \
     -o ~/Isaac-GR00T/examples/CYCLO/ffw_sg2_ltable/ffw_sg2_ltable_config.py

확인:

cat "$DS/meta/modality.json"                                        # 19-dim, cam_left_head 1개
ls ~/Isaac-GR00T/examples/CYCLO/ffw_sg2_ltable/                     # ffw_sg2_ltable_config.py

modality.json 은 모델 비디오 키를 cam_left_head 로 두고 데이터 소스만 우리 observation.images.cam_head 로 가리킨다 → 배포 시 cyclo_intelligence 의 카메라 이름과 바로 맞는다. config.py 는 embodiment NEW_EMBODIMENT 로 등록한다.

참고 — 파일을 직접 만들고 싶으면 이 repo의 두 파일 내용을 그대로 쓰면 된다. Docker로 학습한다면 ~/Isaac-GR00T/examples/CYCLO 를 컨테이너에 마운트(4단계 스모크 참고)하므로, 호스트에 배치하면 컨테이너에서 보인다.


4. 스모크 테스트 (1스텝) — 설정 검증 + VRAM 실측

진짜 학습 전에 데이터·modality·embodiment 가 맞는지 1스텝만 돌린다.

Docker 컨테이너 진입 — ⚠️ /workspace 전체를 마운트하지 말 것 (이미지의 .venv 를 덮어써 torch 를 못 찾는다). 필요한 것만 하위 경로로 마운트:

docker run -it --rm --gpus all \
    --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 \
    -e HF_TOKEN="$HF_TOKEN" \
    -v ~/.cache/huggingface:/root/.cache/huggingface \
    -v ~/groot_data:/workspace/groot_data \
    -v ~/Isaac-GR00T/examples/CYCLO:/workspace/examples/CYCLO \
    gr00t

컨테이너 안에서 환경 확인 후 스모크:

python -c "import torch; print(torch.__version__, torch.cuda.is_available())"   # True

python gr00t/experiment/launch_finetune.py \
  --base_model_path nvidia/GR00T-N1.7-3B \
  --dataset_path /workspace/groot_data/JSHNSL/ffw_sg2_ltable_merge \
  --embodiment_tag NEW_EMBODIMENT \
  --modality_config_path examples/CYCLO/ffw_sg2_ltable/ffw_sg2_ltable_config.py \
  --num_gpus 1 --output_dir /tmp/groot_smoke \
  --max_steps 1 --global_batch_size 1 --dataloader_num_workers 0

다른 터미널에서 VRAM 실측 (24GB로 되는지 여기서 결정):

watch -n1 nvidia-smi --query-gpu=memory.used,memory.total --format=csv

여기까지 통과하면 데이터·설정이 다 맞은 것이다.


5. 실제 파인튜닝 — VRAM에 따라 명령이 다르다

GR00T 3B 파인튜닝에서 메모리를 가르는 건 어느 부분을 학습하느냐(--tune-*) 다. 기본값은 VLM 백본을 얼리고(--no-tune-llm --no-tune-visual) projector + diffusion action head를 학습한다. 그중 diffusion action head가 실제 로봇 동작을 만든다 → 이걸 학습해야 "진짜 성능"이 나온다.

Ⓐ 40GB+ GPU (권장 — 제대로 학습) · A100/L40S/H100/RTX PRO 6000

python gr00t/experiment/launch_finetune.py \
  --base_model_path nvidia/GR00T-N1.7-3B \
  --dataset_path /workspace/groot_data/JSHNSL/ffw_sg2_ltable_merge \
  --embodiment_tag NEW_EMBODIMENT \
  --modality_config_path examples/CYCLO/ffw_sg2_ltable/ffw_sg2_ltable_config.py \
  --num_gpus 1 --output_dir /workspace/groot_data/out/ffw_sg2_ltable \
  --max_steps 20000 --save-steps 2000 \
  --global_batch_size 16 --dataloader_num_workers 8

action head까지 학습(기본값). batch 16~32. 이게 정석.

Ⓑ 24GB GPU (실측 — 파이프라인 검증용) · RTX 4090/5000급

24GB에선 action head를 켜면 OOM이다 (batch 1로도 18MB 부족 — 실측). → head를 얼려서(projector만) 돌린다:

export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True

python gr00t/experiment/launch_finetune.py \
  --base_model_path nvidia/GR00T-N1.7-3B \
  --dataset_path /workspace/groot_data/JSHNSL/ffw_sg2_ltable_merge \
  --embodiment_tag NEW_EMBODIMENT \
  --modality_config_path examples/CYCLO/ffw_sg2_ltable/ffw_sg2_ltable_config.py \
  --num_gpus 1 --output_dir /workspace/groot_data/out/ffw_sg2_ltable \
  --max_steps 500 --save-steps 500 \
  --global_batch_size 1 --gradient-accumulation-steps 16 \
  --dataloader_num_workers 8 \
  --no-tune-diffusion-model

⚠️ --no-tune-diffusion-model = action head 안 배움. 파이프라인·배포 경로 검증엔 좋지만 grasp 성능은 기대하지 말 것. 제대로 하려면 Ⓐ (40GB+).

인자 메모
--max_steps / --save-steps --save-steps 를 꼭 낮출 것. 기본 1000이라 그보다 짧게 돌리면 체크포인트가 안 생긴다
--global_batch_size 40GB=16~32, 24GB=1
--gradient-accumulation-steps 배치 쪼개 유효 배치 유지 (오타 주의: accumulation)
--no-tune-diffusion-model 24GB에서 OOM 회피용. 성능은 희생
--num_gpus 다중 GPU: torchrun --nproc_per_node=N ... --num_gpus N

⚠️ docker run -it --rm 로 붙어 있으면 그 터미널을 닫는 순간 컨테이너·학습이 사라진다. 긴 학습은 호스트에서 tmux 로 감싸거나, 컨테이너를 -d 로 띄우고 docker exec 로 들어가서 돌릴 것.

학습이 끝나면 출력 폴더 확인 (호스트):

sudo ls ~/groot_data/out/ffw_sg2_ltable/
# config.json  model-0000N-of-000NN.safetensors  model.safetensors.index.json  experiment_cfg/  processor/  checkpoint-N/

6. 눈으로 평가 — open-loop (로봇 없이, 그림)

정답 액션 vs 정책 예측을 겹쳐 그린다. 로봇·오케스트레이터 없이 정책 단독으로 돈다. 컨테이너 안에서:

python gr00t/eval/open_loop_eval.py \
  --dataset-path /workspace/groot_data/JSHNSL/ffw_sg2_ltable_merge \
  --embodiment-tag NEW_EMBODIMENT \
  --model-path /workspace/groot_data/out/ffw_sg2_ltable \
  --traj-ids 0 --action-horizon 16 \
  --save-plot-path /workspace/groot_data/eval

--modality-config-path 인자는 없다 (modality는 체크포인트의 experiment_cfg 에서 읽음). 결과: ~/groot_data/eval/traj_0.jpeg — 19개 관절 정답(파랑) vs 예측(주황) + MSE. 곡선이 겹치면 잘 배운 것. (projector-only면 많이 어긋난다 — 정상)


7. 학습 결과 HuggingFace에 올리기 (선택)

다른 컴퓨터/로봇 PC에서 받아 쓰려면 HF에 올린다. 컨테이너 안에서 (write 토큰 필요):

hf auth login          # write 토큰 (안 되어 있으면)
python -c "from huggingface_hub import whoami; print(whoami()['name'])"   # JSHNSL 확인

python -c "
from huggingface_hub import create_repo, upload_folder
repo = 'JSHNSL/groot_ffw_ltable'
create_repo(repo, repo_type='model', exist_ok=True)
upload_folder(
    folder_path='/workspace/groot_data/out/ffw_sg2_ltable',
    repo_id=repo, repo_type='model',
    ignore_patterns=['checkpoint-*', 'training_args.bin', 'wandb_config.json'],
)
print('done ->', repo)
"

ignore_patternscheckpoint-*(중복 12GB)·학습 잔여물 제외 → 추론에 필요한 것만 (~12.5GB) 올라간다.

받을 때 (배포할 PC에서):

hf download JSHNSL/groot_ffw_ltable \
    --local-dir ~/cyclo_intelligence/docker/huggingface/lerobot/JSHNSL/groot_ffw_ltable

8. 배포 (cyclo_intelligence) — 실물 로봇 PC

cyclo_intelligence 캐시는 호스트에 마운트돼 있다: ~/cyclo_intelligence/docker/huggingface → 컨테이너 /root/.cache/huggingface. → docker cp(심볼릭 링크로 실패함) 대신 호스트에서 직접 복사한다.

SRC=~/groot_data/out/ffw_sg2_ltable
DST=~/cyclo_intelligence/docker/huggingface/lerobot/JSHNSL/groot_ffw_ltable
sudo mkdir -p "$DST"

# 추론에 필요한 것만 (checkpoint-N 중복·학습 잔여물 제외)
sudo cp -a "$SRC"/config.json \
           "$SRC"/model-*.safetensors \
           "$SRC"/model.safetensors.index.json \
           "$SRC"/experiment_cfg \
           "$SRC"/processor \
           "$DST"/

웹 UI → Inference → 모델 타입 N1.7 (GR00T 그룹) → User JSHNSL → Policy groot_ffw_ltableLoad

⚠️ "Loading" 에서 안 넘어가면 → groot_server 수동 기동

GR00T는 별도 엔진 groot_server 를 쓴다 (LeRobot은 lerobot_server). 오케스트레이터가 자동 기동에 실패하면 Loading에서 멈춘다. 직접 띄우면 된다 (호스트):

docker start groot_server
docker logs -f groot_server 2>&1 | grep -v "Service call timed out"

로그에 이게 뜨면 로드 성공:

Loading GR00T policy from: /workspace/model/groot/groot_ffw_ltable
Policy info: {'video': ['cam_left_head'], 'state': ['arm_left','arm_right','head','lift'], ...}

→ modality(19-dim/카메라1개)를 정확히 읽었다는 뜻. 웹 UI가 Inference로 넘어간다.

GR00T 엔진은 모델의 modality 설정을 그대로 따라간다odometry 없으면 /odom 안 읽고, 카메라도 모델이 요구하는 것만 구독. 19-dim/카메라1개 그대로 동작한다. ⚠️ 실제 로봇 움직임은 실물 로봇+카메라가 연결된 로봇 PC에서만 의미 있다 (로봇 없으면 mock).


자주 걸리는 것 (실전에서 겪은 것들)

증상 원인 / 해결
변환 Permission denied: ~/groot_data/JSHNSL Docker(root)가 먼저 만들어 root 소유 → sudo chown -R $USER:$USER ~/groot_data ~/.cache/huggingface
uv sync Invalid zip file structure wheel이 LFS 포인터 → git lfs install && git lfs pull 후 재시도
컨테이너에서 No module named 'torch' -v ~/Isaac-GR00T:/workspacevenv 덮어씀/workspace 전체 말고 하위 경로만 마운트
401 gated repo Cosmos-Reason2-2B 백본 승인 안 됨 → HF에서 Agree + HF_TOKEN 전달
Isaac pip packaging._structures 손상 -m ensurepip --upgrade, 또는 get-pip.py --ignore-installed (⚠️ --force-reinstall 은 또 죽음)
CUDA OutOfMemory (optimizer.step) 24GB면 --no-tune-diffusion-model + PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True. 그래도면 40GB+ GPU
Unrecognized options: --gradient-accmulation-steps 오타. --gradient-accumulation-steps (u 빠짐)
학습했는데 출력에 config만 있고 모델 없음 --save-steps--max_steps 보다 커서 저장 전에 끝남 → --save-steps 낮추기
docker cp ... path escapes from parent 출력의 심볼릭 링크 때문 → 호스트 마운트에 직접 cp (8단계)
웹 UI Loading 무한 groot_server 자동 기동 실패 → docker start groot_server
uv run 마다 Installing flash-attn... 정상 (캐시 재검증, 2~3초). 재빌드 아님

GPU별 정리

GPU VRAM action head 학습 방법
RTX 5000 Blackwell 등 24GB ❌ (OOM) Ⓑ projector-only (검증용)
A100 / L40S / H100 40~80GB Ⓐ 정석
RTX PRO 6000 Blackwell 96GB Ⓐ, batch 크게. 로컬에서 EC2 없이

나중에 wrist 카메라를 추가하면

ffw_sg2_rev1 (22-dim + 카메라 3대) 에 가까워진다. modality.jsonvideo 에 2개, config.pymodality_keys 에 2개를 더한다. 단 데이터 596ep 재생성이 필요하다. (현재 단일 cam_head 는 grasp 시 근접 시야가 부족해 폐루프 성능에 한계가 있다.)

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading