AY-Robots veiledningsside for trening av GR00T N1.7 på en SO-100 arm, som viser det nødvendige GPU-nivået, datasettformatet og standardinnstillinger for treneren
GR00T N1.7SO-100FinjusteringLeRobotVLA

Hvordan trene GR00T N1.7 på ditt eget SO-100 datasett

AY-Robots ResearchAugust 23, 202628 min lesetid

En testet gjennomgang for finjustering av NVIDIA GR00T N1.7 på et SO-100 LeRobot datasett: ekte flagg, modality.json, v2.1-kravet, hva en kjøring koster, og fellene.

NVIDIA leverer et finjusteringseksempel for akkurat den armen du sannsynligvis eier. Inne i Isaac-GR00T-arkivet finnes det en mappe kalt demo_data/cube_to_bowl_5: fem episoder, 4 148 bilder ved 30 fps, allerede skrevet som LeRobot v2.1, med en matchende modalitetskonfigurasjon under examples/SO100/. Dens meta/info.json rapporterer robot_type: so101_follower, som i LeRobot er den samme konfigurasjonsklassen som so100_follower. Det er genuint nyttig, fordi det betyr at referansebanen for GR00T N1.7 på en seks-frihetsgrad hobbyarm vedlikeholdes av personene som skrev modellen. Det er ikke en nedskalert humanoid demo, det er den samme armen.

Den dårlige nyheten er avstanden mellom I recorded 60 episodes og the arm does the task. Det er omtrent seks steder hvor denne pipelinen feiler stille i stedet for høyt, og fire av dem ligger i filer de fleste aldri åpner: meta/modality.json, Python-datakonfigurasjonen, meta/relative_stats.json, og datasettets egen versjonsstreng. Denne guiden går gjennom den manuelle ruten fra start til slutt med de virkelige kommandoene, og viser deretter den samme jobben som et skjema på AY-Robots. Alt nedenfor ble sjekket mot Isaac-GR00T main-grenen per 20. august 2026 (n1.7-release-linjen) og lerobot 0.6.1, publisert til PyPI 3. august 2026. Oppstrøms beveger seg raskt, og der et flagg ble omdøpt, sier denne artikkelen det.

Hva du trenger å vite før du starter

  • GR00T N1.7 finjustering krever 40 GB eller mer VRAM. NVIDIA anbefaler H100- eller L40-noder. Et 24 GB RTX 4090 vil ikke gjøre denne jobben, selv om det vil trene SmolVLA og ACT.
  • Datasettet må være LeRobot v2 (v2.0 eller v2.1) pluss en GR00T-spesifikk meta/modality.json. Et LeRobot v3.0-datasett lastes ikke inn og må konverteres ned.
  • Inngangspunktet er gr00t/experiment/launch_finetune.py, en tyro CLI. Den har ingen --seed-flagg, så kjøringer er ikke bit-for-bit reproduserbare.
  • For en tilpasset arm er embodiment-taggen NEW_EMBODIMENT, og den taggen gjør --modality-config-path obligatorisk.
  • Den leverte SO-100-oppskriften forutsier armledd som RELATIVE deltaer og griperen som et ABSOLUTT mål. Å få den sammenkoblingen baklengs er en stille feil, ikke en feilmelding.
  • På AY-Robots er den samme jobben et skjema: 20000 trinn, batch 32, læringsrate 1e-4, omtrent 4 til 12 USD på A100 80 GB eller H100-nivået.

Hva GR00T N1.7 faktisk er

GR00T N1.7 er en syn-språk-handlingsmodell med dobbelt-systemoppsettet beskrevet i det originale GR00T N1-dokumentet: en syn-språk-modul som leser kameraene og instruksjonen, og en diffusjonstransformator som omdanner dette til en del kontinuerlige motorkommandoer. N1.7 erstattet den første halvdelen. Eagle-ryggraden fra N1.6 er borte, byttet ut med nvidia/Cosmos-Reason2-2B på en Qwen3-VL-arkitektur, og modellen ble forhåndstrent på omtrent 20 000 timer med egosentrisk menneskevideo i tillegg til robotdataene. NVIDIAs egen rapport angir tallet til 20 854 timer og rapporterer at å gå fra 1k til 20k timer mer enn dobler gjennomsnittlig oppgavefullføring.

Den andre halvdelen endret seg også, på måter som er viktige for din kjøring. Handlingshodet falt fra 32 diffusjonslag til 16, den predikerte handlingsbiten vokste fra 16 trinn til 40, og maksimal tilstands- og handlingsbredde gikk fra 29 til 132. Disse tre tallene kommer fra endringsloggen i depotets README; NVIDIAs egen lanseringspost beskriver fortsatt System 1 som en 32-lags DiT, så der de to er uenige, stol på depotet du er i ferd med å klone. Handlinger uttrykkes som standard i et relativt end-effektor-rom, deltaer fra den nåværende posituren snarere enn absolutte mål, noe som er det som lar manipulasjonsprioriteringer lært fra menneskevideo overføres til robotkontroll i det hele tatt. Selve hodet er en strømningsmatchende diffusjonstransformator, samme familie som Pi0.5, men med en annen ryggrad foran den. Hvis du fortsatt er på forrige generasjon, dekker N1.7 mot N1.5 om oppgraderingen rettferdiggjør å gjøre om pipelinen din.

EgenskapVerdiHvor det kommer fra
Parametere3,000,000,000Hugging Face model card
Syn-språk-ryggradnvidia/Cosmos-Reason2-2B (Qwen3-VL), gated on Hugging Facerepo README
HandlingshodeStrømningsmatchende diffusjonstransformator, 16 lag (N1.6 hadde 32)repo README
Predikert handlingshorisont40 trinn for basis-sjekkpunktet (N1.6 hadde 16)getting_started/policy.md and repo README
Maksimal tilstands- og handlingsbredde132 (N1.6 hadde 29)repo README
KodelisensApache 2.0Isaac-GR00T repository
VektlisensNVIDIA Open Model License Agreementmodel card
Latens, H100 80 GB, PyTorch eager, 4 denoising-trinn, 1 kamera85.8 ms ende til ende, 11.7 Hzmodel card timing table
Samme maskinvare, TensorRT full pipeline27.9 ms ende til ende, 35.9 Hzmodel card timing table
Latens AY-Robots oppgir for sin servert GR00T N1.7152 ms per handlingstrinnAY-Robots policy catalog

De siste tre radene forklarer det meste av skuffelsen folk rapporterer. Overskriftens 27.9 ms er en TensorRT-motor på en H100 med ett kamera og fire denoising-trinn. Ren PyTorch på samme kort er 85.8 ms, og modellkortet angir gapet til 3.08x. Ingen av tallene inkluderer et serving-lag, et andre kamera eller et nettverkshopp. De 152 ms per handlingstrinn som AY-Robots oppgir for sin servert GR00T N1.7 er tallet med serving i loopen, og en offentlig-internett rundtur kommer i tillegg til det. Mer om dette på slutten. For tallene ved siden av andre modeller, legger GR00T N1.7 mot Pi0.5 og GR00T N1.7 mot SmolVLA dem ut side ved side.

AY-Robots-modellsiden for GR00T N1.7 som viser antall parametere, GPU-nivå, inferensforsinkelse og modellens angitte styrker og begrensninger
Siden /policies/groot-n1-7 inneholder den samme spesifikasjonsstripen som du ellers ville satt sammen manuelt fra modellkortet og repoets README.

Hva kjøringen trenger før du skriver noe

KravFinjusteringInferens
VRAM, NVIDIA-veiledning40 GB eller mer, H100 eller L40 anbefales16 GB eller mer, et RTX 4090 fungerer
Python og CUDA på dGPU3.12 og CUDA 12.83.12 og CUDA 12.8
Videobakgrunntorchcodec 0.8.0, kun FFmpeg 4 til 7samme
DatasettformatLeRobot v2 pluss meta/modality.jsonikke aktuelt
Hugging Face-tilganggodkjent for nvidia/Cosmos-Reason2-2Bsamme
Andre verktøygit-lfs og uvuv
AY-Robots GPU-nivå for groot1.7-trenerenA100 80 GB eller H100 80 GBpod klargjøres automatisk
Den portbeskyttede ryggraden vil stoppe deg ved første kjøring

Hvert GR00T-sjekkpunkt, inkludert basis nvidia/GR00T-N1.7-3B, laster nvidia/Cosmos-Reason2-2B ved første bruk, og dette depotet er portbeskyttet. README beskriver feilen nøyaktig: modellastingen mislykkes med en GatedRepoError / 401 Client Error. Det den ikke nevner er når dette skjer, som er etter at du har leid kortet og kjøringen har startet. Be om tilgang på modellsiden, kjør deretter uv run huggingface-cli login eller eksporter HF_TOKEN før du leier noe.

Trinn 0: episodene selv

Alt nedenfor forutsetter at du allerede har spilt inn episoder. Hvis ikke, er det det virkelige første trinnet, og det er det som avgjør hvor godt resultatet kan bli, fordi imitasjonslæring ikke kan gjenopprette informasjon som ikke er i dataene. Kalibrer begge armene først, kjør deretter følgeren med en lederarm mens lerobot-record skriver parquet-filene og kamerastrømmene. Hvis kalibrering er feil, beskriver leddverdiene i datasettet ditt en litt annen robot enn den som senere vil utføre policyen, og ingen mengde trening fikser det.

bash
lerobot-record \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.id=my_follower_arm \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
    --teleop.type=so100_leader \
    --teleop.port=/dev/ttyACM1 \
    --teleop.id=my_leader_arm \
    --dataset.repo_id=${HF_USER}/cube-into-bowl \
    --dataset.num_episodes=60 \
    --dataset.single_task="put the cube in the yellow bowl" \
    --display_data=true
lerobot-record på en nåværende LeRobot. Episodelengden er som standard 60 s og tilbakestillingstiden er 60 s. so100_follower og so101_follower er begge registrert mot den samme LeRobot-konfigurasjonsklassen, derfor bruker Isaac-GR00T SO100-eksemplet so101-navnene; begge fungerer på en SO-100. Kameranavnene du velger her (front, wrist) er navnene som må dukke opp igjen i modality.json.

LeRobots eget råd er å spille inn minst 50 episoder med omtrent 10 per objektplassering, holde kameraene faste og holde gripeatferden konsistent. Legg til variasjon senere, ikke i starten. Tommelfingerregelen verdt å huske: hvis du ikke kunne utføre oppgaven selv fra kamerabildene alene, kan heller ikke policyen det. For det armspesifikke oppsettet, SO-100 komme i gang og SO-100 LeRobot-siden dekker porter, kalibrering og kamera-indekser. På AY-Robots kan du også gjøre dette over internett fra nettleseren ved hjelp av teleoperasjon og ta opp direkte fra økten.

Trinn 1: datasettet må være LeRobot v2.1

Dette er den vanligste hindringen. LeRobots nåværende CODEBASE_VERSION på main er v3.0, så alt du tar opp i dag med en nåværende verktøykjede kommer ut som v3.0. GR00Ts laster forventer v2. Repositoriet er eksplisitt om hvorfor: mange oppstrøms datasett som DROID, LIBERO og Bridge er publisert i v2, og native støtte for begge er planlagt, men ikke levert. Så konverteringen er opp til deg, og den kjører i sitt eget virtualenv av en konkret grunn: scripts/lerobot_conversion har sitt eget pyproject som krever Python 3.10 eller 3.11 og fester lerobot til én git-commit, mens Isaac-GR00T selv krever Python 3.12. Installer konverteren fra rotmappen til repositoriet, og du får gr00t pakken i stedet, noe som er feilen README advarer om. Hvis du er ny i formatet, forklarer LeRobot-datasett ordlisteoppføringen hva som faktisk er inni et slikt.

bash
# from the Isaac-GR00T repo root
cd scripts/lerobot_conversion
uv venv
source .venv/bin/activate
uv pip install -e . --verbose

# pulls the dataset from the Hub and writes a v2.1 copy into the default cache
python convert_v3_to_v2.py --repo-id <your-hf-user>/<your-dataset>

# or, back in the repo root, keep it next to the SO-100 example
uv run --project scripts/lerobot_conversion \
  python scripts/lerobot_conversion/convert_v3_to_v2.py \
  --repo-id <your-hf-user>/<your-dataset> \
  --root examples/SO100/my_dataset_lerobot
Konverteren tar --repo-id, en valgfri --root, og --force-conversion, som sletter eventuelle eksisterende lokale øyeblikksbilder og laster dem ned på nytt. Den skriver codebase_version: v2.1 inn i meta/info.json.
Konverteringen overskriver på stedet

Hvis v3.0-datasettet allerede eksisterer lokalt, bygger skriptet v2.1-layouten ved siden av det og bytter deretter: originalen flyttes til en søskenmappe med versjonen lagt til, <name>_v3.0, og den konverterte kopien tar den opprinnelige stien. (Skriptets egen docstring kaller den mappen _v30; koden legger til versjonsstrengen, så det du faktisk får er _v3.0.) Andre overraskelse: utdataene lander alltid under <root>/<repo-id>, så --root examples/SO100/my_dataset_lerobot gir deg examples/SO100/my_dataset_lerobot/<your-hf-user>/<your-dataset>, og den lengre stien er den --dataset-path ønsker senere. Når en treningsjobb avviser datasettet ditt på grunn av versjonsårsaker, lister siden om datasettet avvist som v3 de nøyaktige symptomene.

Strukturen GR00T ønsker etter konvertering er det klassiske v2-oppsettet: meta/info.json, meta/episodes.jsonl, meta/tasks.jsonl, parquet-filer under data/chunk-000/, MP4-filer under videos/chunk-000/observation.images./, og én ekstra fil som standard LeRobot ikke har. Den ekstra filen er der de fleste av de gjenværende feilene ligger.

Trinn 2: modality.json, de seks tallene som bestemmer alt

I et LeRobot-datasett lagres robotens tilstand og handling som flate float32-arrayer. For en SO-100 har begge formen [6]: fem armledd og en griper. Demodatasettet navngir dem shoulder_pan.pos, shoulder_lift.pos, elbow_flex.pos, wrist_flex.pos, wrist_roll.pos, gripper.pos, men disse navnene finnes i info.json og ingenting i parquet-filen sier hvilken indeks som er hvilken. meta/modality.json leverer denne tilordningen, og GR00T vil ikke trene uten den. Her er den som repositoryet leverer for SO-100, ordrett.

json
{
  "state": {
    "single_arm": {
      "start": 0,
      "end": 5
    },
    "gripper": {
      "start": 5,
      "end": 6
    }
  },
  "action": {
    "single_arm": {
      "start": 0,
      "end": 5
    },
    "gripper": {
      "start": 5,
      "end": 6
    }
  },
  "video": {
    "front": {
      "original_key": "observation.images.front"
    },
    "wrist": {
      "original_key": "observation.images.wrist"
    }
  },
  "annotation": {
    "human.task_description": {
      "original_key": "task_index"
    }
  }
}
examples/SO100/modality.json. Indekser er nullbaserte og følger Python-slicing, så single_arm er [0:5] og gripper er [5:6].

Kopier den inn i ditt konverterte datasett på meta/modality.json og gi videonøklene nytt navn til det kameraene dine faktisk heter. Hvis du spilte inn med et enkelt overliggende kamera kalt top, da er original_key observation.images.top og det vennlige navnet er det datakonfigurasjonen din vil referere til. De to må stemme overens, og ingen av dem sjekker den andre for deg. Språkannoteringen er verre, fordi den samme nøkkelen må vises tre steder.

LagFilSO-100-form brukt i repoet
Parquet-kolonnedata/chunk-*/episode_*.parquetannotation.human.task_description
modality.json-nøkkelmeta/modality.json, under "annotation", uten annotation.-prefiksethuman.task_description
modality_keys i datakonfigurasjonenyour so100_config.pyannotation.human.task_description
Hvorfor språk-nøkkelen forvirrer folk

Segmentene etter annotation. velges av den som har laget datasettet. SO-100 demo-data bruker annotation.human.task_description; LIBERO og SimplerEnv bruker annotation.human.action.task_description. Begge er gyldige. Hvis du kopierte en konfigurasjon fra et LIBERO-eksempel og pekte den mot ditt eget SO-100-opptak, løses språkanalen til ingenting, og modellen trener på en tom instruksjon. Tapet faller fortsatt. Policyen gjør fortsatt noe. Den ignorerer bare det du ba den om å gjøre.

Trinn 3: datakonfigurasjonen, relativ arm og absolutt griper

Modalitetskonfigurasjonen er en Python-fil snarere enn JSON, fordi den også bestemmer hvordan hver handlingsgruppe representeres. Dette er den delen av N1.7-arbeidsflyten som ikke eksisterte i samme form i N1.5, og den delen som er verdt å lese to ganger. Den leverte SO-100-konfigurasjonen forutsier de fem armleddene som RELATIVE deltaer fra gjeldende tilstand og griperen som en ABSOLUTE målposisjon, fordi et binært åpen-eller-lukket signal fungerer bedre som et mål enn som et delta.

python
from gr00t.configs.data.embodiment_configs import register_modality_config
from gr00t.data.embodiment_tags import EmbodimentTag
from gr00t.data.types import (
    ActionConfig, ActionFormat, ActionRepresentation, ActionType, ModalityConfig,
)

so100_config = {
    "video": ModalityConfig(
        delta_indices=[0],                       # current frame only
        modality_keys=["front", "wrist"],        # must match modality.json
    ),
    "state": ModalityConfig(
        delta_indices=[0],
        modality_keys=["single_arm", "gripper"],
    ),
    "action": ModalityConfig(
        delta_indices=list(range(0, 16)),        # predict 16 future steps
        modality_keys=["single_arm", "gripper"],
        action_configs=[
            ActionConfig(rep=ActionRepresentation.RELATIVE,   # arm joints
                         type=ActionType.NON_EEF,
                         format=ActionFormat.DEFAULT),
            ActionConfig(rep=ActionRepresentation.ABSOLUTE,   # gripper
                         type=ActionType.NON_EEF,
                         format=ActionFormat.DEFAULT),
        ],
    ),
    "language": ModalityConfig(
        delta_indices=[0],
        modality_keys=["annotation.human.task_description"],
    ),
}

register_modality_config(so100_config, embodiment_tag=EmbodimentTag.NEW_EMBODIMENT)
examples/SO100/so100_config.py, trimmet til det essensielle. NON_EEF betyr leddrom; EEF ville forventet en ni-dimensjonal vektor av x, y, z pluss en 6D rotasjon.

To detaljer her vil koste deg en dag hvis du ikke kjenner dem. For det første, action_configs er posisjonsbasert: dokumentasjonen krever samme lengde og samme rekkefølge som modality_keys, og de er tydelige på konsekvensen av å gjøre feil, som er at feil representasjon blir brukt uten varsel. Griperen din blir trent som et delta og armen din som et absolutt mål, og det er ingen feilmelding. For det andre, register_modality_config hevder at taggen ikke allerede er registrert, så en andre NEW_EMBODIMENT-konfigurasjon i samme Python-prosess dør med Embodiment tag ... already registered. Du kan ikke importere to av disse inn i ett skript. En tredje regel håndheves senere, ved utrulling: handlingens delta_indices må være det sammenhengende området som starter på null. Et spredt vindu som [0, 4, 8] avvises, fordi alt nedstrøms indekserer den predikerte biten lineært og ellers ville utført feil rader.

Endre delta_indices og du må regenerere statistikken

Normaliseringsstatistikk, spesielt meta/relative_stats.json, beregnes for den horisontlengden du hadde da du genererte dem. Forkort handlingshorisonten fra 16 til 8 uten å regenerere, og treningen dør med IndexError: boolean index did not match indexed array ... dimension is 8 but corresponding boolean dimension is 16. Løsningen er én kommando: python gr00t/data/stats.py --dataset-path <path> --embodiment-tag NEW_EMBODIMENT --modality-config-path examples/SO100/so100_config.py. Kjør den etter enhver endring i delta_indices.

Trinn 4: miljøet

N1.7 flyttet depotet til og Python 3.12. Den gamle conda pluss pip install -e . -stien eksisterer fortsatt i en skjult del av README, men den advarer om at GPU-avhengigheter, inkludert flash-attn og TensorRT, kan kreve manuell installasjon. Bruk uv med mindre du har en spesifikk grunn til å ikke gjøre det. Når det gjelder flash-attn, sparer én detalj forvirring: du vil se Installing flash-attn skrevet ut ved hver uv run. Den bygges ikke på nytt. uv re-validerer et URL-festet hjul som allerede er bufret, og det tar to eller tre sekunder.

  1. 1
    Installer git-lfs, deretter klon med submoduler

    git-lfs er påkrevd, ikke valgfritt. Uten det vil parquet-filene i demo_data/ lastes ned som pekerstubber, og demo-kjøringen vil mislykkes på et datasett som ser ut til å være til stede i filoversikten.

    bash
    sudo apt install git-lfs && git lfs install
    git clone --recurse-submodules https://github.com/NVIDIA/Isaac-GR00T
    cd Isaac-GR00T
  2. 2
    Installer uv og synkroniser miljøet

    Standardinstallasjonen trekker inn GPU-avhengighetene, inkludert flash-attn og TensorRT. På et ferskt A100- eller H100-bilde er dette det lengste enkelttrinnet, så gjør det før du begynner å vie oppmerksomhet til noe annet.

    bash
    curl -LsSf https://astral.sh/uv/install.sh | sh
    sudo apt-get update && sudo apt-get install -y ffmpeg
    uv sync --python 3.12
    uv run python -c "import gr00t; print('GR00T installed successfully')"
  3. 3
    Autentiser mot Hugging Face

    Gjør dette før den første treningslanseringen, ikke etter at den feiler åtte minutter ut i prosessen.

    bash
    uv run huggingface-cli login   # or: export HF_TOKEN=<your_token>
  4. 4
    Sanity-sjekk på de medfølgende SO-100 demo-dataene

    Før du rører ditt eget opptak, kjør 2000 trinn på demo_data/cube_to_bowl_5. Det er fem episoder, det fullføres raskt, og det beviser miljøet snarere enn dataene dine. Hvis denne kjøringen mislykkes, vil ingenting du gjør med datasettet ditt hjelpe.

    bash
    CUDA_VISIBLE_DEVICES=0 uv run python \
        gr00t/experiment/launch_finetune.py \
        --base-model-path nvidia/GR00T-N1.7-3B \
        --dataset-path demo_data/cube_to_bowl_5 \
        --embodiment-tag NEW_EMBODIMENT \
        --modality-config-path examples/SO100/so100_config.py \
        --num-gpus 1 \
        --output-dir /tmp/test_finetune \
        --max-steps 2000 \
        --global-batch-size 32 \
        --dataloader-num-workers 4
To miljøfeller som ser ut som modellfeil

FFmpeg 8. torchcodec 0.8.0 støtter kun FFmpeg 4 til 7, og Ubuntu 25.10 og nyere leveres med versjon 8. Feilen er Could not load libtorchcodec, som ser ut som en ødelagt installasjon snarere enn en versjonskonflikt. Installer en eldre kjøretid, for eksempel conda install -c conda-forge 'ffmpeg<8', og legg bibliotekene på LD_LIBRARY_PATH. CUDA_HOME er udefinert. Finjustering mislykkes fullstendig. Kjør bash scripts/deployment/dgpu/install_deps.sh én gang, eller bare export CUDA_HOME=/usr/local/cuda.

Trinn 5: `fine-tune`-kommandoen og hva dens flagg egentlig er satt til som standard

Bytt ut demo-datasettet med ditt eget og legg til de innstillingene du faktisk ønsker. Nedenfor er den fullstendige formen som repositoriet bruker i sin egen `new-embodiment`-veiledning, inkludert augmentering- og sjekkpunktflaggene som det korte README-eksemplet utelater. Dette er i snever forstand: språkryggraden og den visuelle koderen forblir frosne, og det som trenes er projektoren og diffusjonsaksjonshodet.

bash
export NUM_GPUS=1
CUDA_VISIBLE_DEVICES=0 uv run python \
    gr00t/experiment/launch_finetune.py \
    --base-model-path nvidia/GR00T-N1.7-3B \
    --dataset-path ./my_dataset_lerobot \
    --embodiment-tag NEW_EMBODIMENT \
    --modality-config-path examples/SO100/so100_config.py \
    --num-gpus $NUM_GPUS \
    --output-dir /tmp/so100 \
    --save-total-limit 5 \
    --save-steps 2000 \
    --max-steps 20000 \
    --use-wandb \
    --global-batch-size 32 \
    --color-jitter-params brightness 0.3 contrast 0.4 saturation 0.5 hue 0.08 \
    --dataloader-num-workers 4
Enkelt-GPU. For åtte kort, erstatt starteren med `uv run torchrun --nproc_per_node=8 --master_port=29500` og sett `--num-gpus 8`. Bruk `uv run torchrun`, ikke bare `torchrun`, ellers får du feil miljø.
FlaggStandard i FinetuneConfigHva det gjør
--global-batch-size64Total batch over alle GPU-er før gradientakkumulering. De medfølgende eksemplene bruker 32.
--learning-rate1e-4Samme verdi som AY-Robots sender for sin groot1.7-trener.
--max-steps10000Totalt antall optimaliseringstrinn. `examples/finetune.sh`-wrapperen er også satt til 10000 som standard.
--gradient-accumulation-steps1Multipliserer den effektive batchen. Verdier over 1 utløser en advarsel som forteller deg den akkumulerte størrelsen.
--save-steps and --save-total-limit1000 and 5Sjekkpunktfrekvens, og hvor mange som beholdes. Eldre slettes.
--weight-decay and --warmup-ratio1e-5 and 0.05Satt eksplisitt av `examples/finetune.sh` også.
--state-dropout-prob0.2 in the CLI, 0.8 in the model configSlipper tilfeldigvis proprioceptiv tilstand under trening. Senk den hvis oppgaven din er avhengig av tilstand.
--tune-llm and --tune-visualFalse and FalseRyggraden forblir frossen som standard.
--tune-projector and --tune-diffusion-modelTrue and TrueProjektoren og diffusjonsaksjonshodet er det som faktisk trenes.
--use-percentilesTrueNormaliser med q01 og q99 i stedet for rå min og maks.
--dataloader-num-workers2Lasteren er CPU-basert av design. Eksemplene øker dette til 4.
--seeddoes not existDet er ingen seed-flagg på denne CLI-en.

Den siste raden er ikke en skrivefeil. launch_finetune.py er en tyro CLI generert fra en dataklasse, og den dataklassen har ingen seed-felt. README-filen bemerker separat 5 til 6 prosent varians mellom kjøringer forårsaket av ikke-deterministisk bildeaugmentering. To kjøringer med identiske flagg vil ikke produsere identiske sjekkpunkter, noe som betyr mye når du prøver å avgjøre om en hyperparameterendring hjalp eller om du var heldig. Til sammenligning bruker lerobots egen trener standardinnstillingen seed 1000, og LeRobot GR00T-oppskriften sender --seed=42 eksplisitt.

Validering er av som standard, og det dokumenterte flagget finnes ikke på denne CLI-en

Finjustering kjører med eval_strategy="no", så det er ingen valideringstapskurve i det hele tatt. Du får treningstap og ingenting annet. Den nye-embodiment-guiden ber deg slå det på med --eval-strategy steps --eval-steps 500, men det flagget finnes ikke på launch_finetune.py: CLI-en genereres av tyro fra FinetuneConfig-dataklassen, og eval_strategy, eval_steps og eval_batch_size er felt i TrainingConfig i stedet. Standardverdiene der er "no", 500 og 2. For å nå dem, bruk det fullere inngangspunktet gr00t/experiment/launch_train.py, hvor det nestede flagget er --training.eval-strategy. Uansett forteller et fallende treningstap alene deg svært lite om generalisering, noe som er nøyaktig situasjonen beskrevet på tapet faller, men policyen gjør ingenting.

Hva en 20000-trinns kjøring koster

GR00T N1.7 trenger et 80 GB kort, så kostnadsspørsmålet har et snevert svar. På AY-Robots kjører groot1.7-treneren på A100 80 GB eller H100 80 GB-nivået, hvor en kjøring tar 3 til 6 timer til 1.20 til 2.00 USD per time på spotmarkedet. Det er omtrent 4 til 12 USD for standard 20000-trinns jobben. Den samme oppgaven på SmolVLA eller ACT lander på et 24 GB kort til 0.30 til 0.60 USD per time og 1 til 3 USD per kjøring. Det er den virkelige avveiningen: GR00T koster omtrent fire ganger så mye per forsøk, og du kan ikke kjøre det på 4090 under skrivebordet ditt.

ModellGPU-nivåTypisk kjøretidTypisk kostnadMinimum episoder
GR00T N1.7A100 80 GB or H100 80 GB3 to 6 hours4 to 12 USD50
GR00T N1.5A100 80 GB or H100 80 GB3 to 6 hours4 to 12 USD50
Pi0.5A100 80 GB or H100 80 GB3 to 6 hours4 to 12 USD50
SmolVLARTX 4090 or any 24 GB card2 to 5 hours1 to 3 USD30
ACTRTX 4090 or any 24 GB card2 to 5 hours1 to 3 USD50

Minimum 50-episode er et gulv, ikke et mål. NVIDIAs egen FAQ er mer krevende: omtrent 100 trajektorier for en enkel plukk-og-plasser-oppgave på et fast sted, 500 eller mer for komplekse eller flertrinns-scener, og 100 til 500 for finmanipulasjon. Hvis du sitter med 20 episoder, bruk ettermiddagen på å spille inn i stedet for kvelden på å finjustere. Den datainnsamlingsguiden dekker hva som skiller en nyttig episode fra en bortkastet,spill inn ditt første datasett er kortversjonen, og SO-100 datainnsamling er den armspesifikke.

Trinn 6: åpen-sløyfe evaluering før du rører armen

Ikke legg en fersk sjekkpunkt på en fysisk arm for å finne ut om treningen fungerte. Kjør den åpen-sløyfe evalueringen først. Den spiller av en innspilt episode, ber modellen om handlinger ved hvert trinn, og plotter prediksjon mot sannhet med MSE og MAE. Det koster ingenting og fanger opp kartleggingsfeilene fra trinn 2 og 3.

bash
uv run python gr00t/eval/open_loop_eval.py \
    --dataset-path ./my_dataset_lerobot \
    --embodiment-tag NEW_EMBODIMENT \
    --model-path /tmp/so100/checkpoint-20000 \
    --traj-ids 0 \
    --execution-horizon 16 \
    --steps 400 \
    --modality-keys single_arm gripper
Plott havner i /tmp/open_loop_eval/traj_<id>.jpeg med mindre du sender inn --save-plot-path. Standardverdier: --execution-horizon 16, --steps 200, --denoising-steps 4, --traj-ids 0.

Repositoriet nekter bevisst å publisere en mål-MSE for egendefinerte data, og det er riktig: tallet avhenger av dine handlingsenheter, din oppgave og din datasettstørrelse, så en terskel kopiert fra en annens arm betyr ingenting. Det som er meningsfullt er trenden. Her er referansekjøringen som repositoriet dokumenterer på en enkelt H100 med demo-datasettet på fem episoder og 2000 trinn.

SjekkpunktGjennomsnittlig MSE på traj 0Gjennomsnittlig MAE på traj 0
50087.55.63
100025.43.30
150013.22.18
200010.01.76

Formen er signalet, ikke de absolutte verdiene. Feilen bør falle jevnt etter hvert som akkumuleres. Gjennomsnittlig over alle fem treningsepisodene, i stedet for kun bane 0, scoret repoets siste sjekkpunkt omtrent 7.5 MSE og 1.5 MAE, så selv referansekjøringen leses annerledes avhengig av hvilke episoder du gjennomsnittsberegner. Registrer din egen grunnlinje på den umodifiserte demo-kommandoen før du endrer noe med dine egne data: hvis du ikke kan reprodusere en kjent-god kjøring, kan du ikke skille en oppsettfeil fra et dataproblem. Repositoriet kartlegger også de vanlige symptomene til årsaker, og hver av dem er operasjonelle snarere enn en modellfeil.

SymptomSannsynlig årsak
MSE flatt eller stigende over sjekkpunkterLæringsrate for lav, eller dataen lastes ikke i det hele tatt. Sjekk --dataset-path og datalaster-arbeiderne.
Prediksjonskurven er flat eller konstantmodality.json-nøkler eller --modality-config-path stemmer ikke overens. Handlingsnøklene er ikke mappet.
MSE enorm, eller NaN-tap under treningNormalisering av handling og tilstand. Verifiser meta/stats og at handlingsområdene er fysisk plausible.
Bra på traj 0, dårlig på tilbakeholdte episoderDatamangel, ikke en feil. Fem demoepisoder kan ikke generalisere.

Den andre ruten: lerobot-train i stedet for Isaac-GR00T

Den nåværende LeRobot-utgivelsen, 0.6.1 på PyPI siden 3. august 2026, tilbyr en annen og ganske annerledes måte å finjustere de samme basisvektene på. LeRobot eksponerer GR00T N1.7 som en policytype og trener den gjennom sitt eget lerobot-train-inngangspunkt. To ting er viktige her. LeRobot CLI er et sett med konsollskript, så alt du leser som sier python lerobot/scripts/train.py er utdatert og vil ikke kjøre. Og LeRobot fjernet GR00T N1.5-støtte fullstendig, og avviste N1.5-sjekkpunkter og -konfigurasjoner med en migreringsmerknad, så hvis du trenger N1.5 gjennom LeRobot må du låse til lerobot==0.5.1, den siste utgivelsen som støtter det, publisert 7. april 2026.

bash
pip install "lerobot[groot]" "lerobot[training]"
hf auth login

lerobot-train \
  --dataset.repo_id=$HF_USER/$DATASET_NAME \
  --dataset.image_transforms.enable=true \
  --policy.type=groot \
  --policy.device=cuda \
  --policy.base_model_path=nvidia/GR00T-N1.7-3B \
  --policy.embodiment_tag=new_embodiment \
  --policy.chunk_size=16 \
  --policy.n_action_steps=16 \
  --policy.use_relative_actions=true \
  --policy.relative_exclude_joints='["gripper"]' \
  --policy.use_bf16=true \
  --seed=42 \
  --batch_size=64 \
  --steps=20000 \
  --save_freq=5000 \
  --output_dir=$OUTPUT_DIR
LeRobot-native GR00T N1.7-oppskriften. Merk relative_exclude_joints: griperen er ekskludert fra relative handlinger, som er den samme beslutningen so100_config.py tar med ActionRepresentation.ABSOLUTE.
AspektIsaac-GR00T launch_finetune.pylerobot-train --policy.type=groot
DatasetversjonKun LeRobot v2, konvertering nødvendigNative LeRobot-datasett, ingen nedgradering
Modalitetskartleggingmeta/modality.json pluss en Python-datakonfigurasjoningen modality.json; oppførsel satt av --policy.*-flagg på kommandolinjen
Frøingen frøflagg i det hele tatt--seed, LeRobot standard 1000
Relative handlingerper-nøkkel ActionConfig i datakonfigurasjonen--policy.use_relative_actions pluss --policy.relative_exclude_joints
Publiserte referanseresultaterSO-100 open-loop MSE-trend på demodataLIBERO-suiter, 96,5 prosent gjennomsnitt over fire suiter
Distribusjonsstirun_gr00t_server.py pluss eval_so100.py over ZMQlerobot-rollout, med sanntids-chunking (queue_threshold bør forbli på eller under 5)
Kjøre finjusteringen selv
Fordeler
  • Hvert flagg er synlig og kan endres. Du kan frigjøre den visuelle koderen, flytte state_dropout_prob, eller forkorte handlingshorisonten.
  • Open-loop-plottene er lokale filer. Å diff'e checkpoint-5000 mot checkpoint-20000 er en skallkommando.
  • Du er ikke avhengig av at noen plattform forblir online, og sjekkpunktet ligger på disken din i et standardformat.
  • Repoets benchmark-eksempler for LIBERO, SimplerEnv og DROID gir deg kjente, gode kjøringer å reprodusere før du stoler på dine egne data.
Avveininger
  • Miljøet er mesteparten av arbeidet. FFmpeg-versjon, CUDA_HOME, git-lfs, den gatede ryggraden, torchcodec: ingen av disse er modellproblemer, og hver av dem stopper kjøringen.
  • Konverteringen fra v3.0 til v2.1 krever et separat virtuelt miljø med sitt eget installasjonstrinn, og den overskriver datasettkatalogen din på stedet.
  • GPU-leie faktureres når du starter feilsøking, ikke når trening starter, og ingenting stopper instansen når kjøringen er ferdig.
  • Ingen frø betyr ingen bit-for-bit reproduserbarhet, i tillegg til 5 til 6 prosent variasjon fra kjøring til kjøring fra augmentering alene.

To måter å få det samme sjekkpunktet på

Du leier GPU-en og eier hvert steg. Realistisk sett tar dette en ettermiddag første gang, og tjue minutter hver gang etter det.

  1. Ta opp episoder med lerobot-record på SO-100. Du får et LeRobot v3.0 datasett.
  2. Konverter det ned til v2.1 med scripts/lerobot_conversion/convert_v3_to_v2.py i sitt eget virtuelle miljø.
  3. Skriv meta/modality.json og en Python modalitetskonfigurasjon, registrert under EmbodimentTag.NEW_EMBODIMENT.
  4. Lei et 80 GB kort, klon med submoduler, uv sync, autentiser mot Hugging Face.
  5. Kjør launch_finetune.py, deretter open_loop_eval.py på flere sjekkpunkter, og sammenlign MSE-trenden før du rører maskinvaren.
  6. Trekk sjekkpunktet av maskinen før du ødelegger instansen, og bygg deretter serveringsbanen til armen.
Steget alle glemmer

Kopier sjekkpunktet fra den leide instansen før du slår den av. --save-total-limit 5 betyr også at eldre sjekkpunkter slettes etter hvert som treningen skrider frem, så sjekkpunktet du ønsket ved steg 5000 eksisterer kanskje ikke lenger ved steg 20000.

AY-Robots treningsmatrise med fem policy-modeller som rader og fire robotarmer som kolonner, der hver celle lenker til en spesifikk treningsguide
Treningsmatrisen: fem modeller mot fire armer. GR00T N1.7-raden dekker også SO-101, Koch v1.1 og LeKiwi.

Sette sjekkpunktet tilbake på armen

Isaac-GR00T bruker en server-klient-deling over ZMQ. Policyen kjører på GPU-en, og en tynn klient på robotmaskinen sender observasjoner og mottar handlingsbiter. SO-100-eksemplet er komplett nok til å kopiere: start run_gr00t_server.py med sjekkpunktet ditt og --embodiment-tag NEW_EMBODIMENT, kjør deretter eval_so100.py på robotsiden med seriellporten, robot-ID-en, kamera-indeksene og språkinstruksjonen. Kameranavnene i den kommandoen må samsvare med de vennlige navnene fra din modality.json, ikke OS-enhetstallene.

bash
# GPU side
uv run python gr00t/eval/run_gr00t_server.py \
  --model-path /tmp/so100/checkpoint-20000 \
  --embodiment-tag NEW_EMBODIMENT \
  --device cuda:0 \
  --host 0.0.0.0 --port 5555

# robot side, from gr00t/eval/real_robot/SO100
uv run --no-sync python eval_so100.py \
  --robot.type=so101_follower \
  --robot.port=/dev/ttyACM2 \
  --robot.id=orange_follower \
  --robot.cameras="{ front: {type: opencv, index_or_path: 6, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
  --policy_host=localhost --policy_port=5555 \
  --lang_instruction="put the cube in the yellow bowl"
--execution-horizon kontrollerer hvor mange av de forutsagte trinnene som utføres før omplanlegging. Det må være maksimalt policyens action_horizon, og det tallet er lengden på action delta_indices i din modalitetskonfigurasjon, ikke basemodellens. Den medfølgende SO-100-konfigurasjonen forutsier 16, så 16 er ditt tak; den grunnleggende nvidia/GR00T-N1.7-3B sjekkpunktet er konfigurert for 40, og policy.md sier tydelig at finjusterte sjekkpunkter kan avvike. Overskrider du det, får du en ValueError som navngir begge tallene. 8 er verdien dokumentasjonen foreslår for sanntidsdistribusjon. Det gamle flaggnavnet --action-horizon fungerer fortsatt, men advarer.
7.4 V, ikke 12 V

Mens du kobler armen opp igjen: SO-100 bruker Feetech STS3215 busservoer på en 7.4 V skinne. Å mate dem med 12 V ødelegger dem, og det er en enkel feil hvis du også eier en LeKiwi, hvis base kjører på 12 V mens armen ikke gjør det. Sjekk strømforsyningen før første oppstart, ikke etter røyken. Se SO-100 maskinvaresiden og SO-100 mot LeKiwi. Hvis armen slår seg på, men ingenting beveger seg, er servoen svarer ikke stedet å starte.

Nå den ærlige delen om hvor policyen kjører, fordi trening og serving har forskjellige maskinvarehistorier. Finjustering krever 40 GB eller mer. Inferens gjør det ikke: README angir det til 16 GB eller mer og nevner RTX 4090 eksplisitt, så et kort du allerede eier kan serve et sjekkpunkt det aldri kunne ha produsert. Det som avgjør om policyen føles responsiv er ikke VRAM, det er hvor serveren befinner seg. På AY-Robots er GR00T N1.7 kun skybasert, så kontrollsløyfen betaler en offentlig internett-tur-retur i tillegg til de 152 ms per handlingstrinn, og bare SmolVLA og ACT kjører også lokalt. For langsom plukking og plassering er en ekstern pod overlevelig. For alt reaktivt er det ikke: policyen blir nølende på en måte som ser nøyaktig ut som en treningsfeil og er ikke det. ACT på 20 ms per handlingstrinn er modellen som tåler den strammeste sløyfen, SmolVLA ligger på 245 ms, og ingen mengde latensjustering kjøper tilbake en tur-retur som allerede er brukt. Kjør din første policy går gjennom serveringssiden fra ende til ende.

Hva som faktisk går galt

  • GatedRepoError ved første kjøring. Du har ikke fått tilgang til nvidia/Cosmos-Reason2-2B, eller du autentiserte deg ikke. Dette skjer etter at GPU-klokken allerede har startet.
  • Datasett avvist ved lasting. Nesten alltid et v3.0-datasett. Konverter det ned. Se datasett avvist som v3.
  • IndexError om uoverensstemmende boolske dimensjoner. Du endret delta_indices og regenererte ikke statistikken.
  • Tom for minne ved batch 32. Reduser --global-batch-size og øk --gradient-accumulation-steps, eller reduser --num-shards-per-epoch, noe konfigurasjonen eksplisitt foreslår når VRAM er begrenset. Se tom for minne under trening.
  • Tapet faller, policyen gjør ingenting. Det er ingen valideringssplitt som standard, så en ren treningskurve beviser svært lite. Denne siden dekker diagnosen.
  • Fungerer i ditt oppsett og ingen andre steder. Forventet med et lite datasett filmet under én lysforhold. NVIDIA anbefaler fargejitter-augmentering pluss 20 til 50 episoder under forskjellige lysforhold. Mer her.
  • Griperen lukker aldri ordentlig. Sjekk at griperhandlingen er ABSOLUTT og armleddene RELATIVE, i den rekkefølgen i action_configs. Griperen lukker ikke lister opp de andre årsakene.
  • Et kamera faller stille ut midt under opptak. Episoden lagres fortsatt og videonøkkelen eksisterer fortsatt, derfor er denne ekkel. Kamera ikke oppdaget dekker det.

Hele indeksen over feilmoduser finnes på . Hvis du velger mellom modeller i stedet for å feilsøke en, og har benchmark-tall med kilder vedlagt, og er sammenligningen de fleste faktisk trenger, fordi det er valget mellom en modell du kan trene på kortet under pulten din og en du må leie en 80 GB node for å finjustere. For bakgrunn om hvorfor disse modellene oppfører seg som de gjør, er VLA-oversikten og komplett SO-100-guide verdt å lese først. Og hvis du ikke eier en arm ennå, strømmer en fysisk SO-100 uten registrering.

Hvor mange episoder trenger jeg før finjustering av GR00T N1.7 er verdt det?

AY-Robots setter et minimum på 50 episoder for groot1.7-treneren. NVIDIAs egen FAQ er mer krevende: omtrent 100 trajektorier for en enkel plukk-og-plasser-oppgave på et fast sted, 500 eller mer for komplekse eller flertrinns-scener, og 100 til 500 for finmanipulasjon. Under 50 er det nesten alltid bedre å registrere mer data enn å justere hyperparametere. Hvis suksessen flater ut etter det, anbefaler NVIDIA HG-DAgger: kjør policyen, grip inn når den feiler, og legg til disse korreksjonene i datasettet.

Hvorfor klarer ikke datasettet mitt å laste, og hvordan finner jeg ut hvilken versjon det er?

Åpne meta/info.json og les codebase_version. LeRobots nåværende CODEBASE_VERSION på main er v3.0, så alt som er registrert med en nylig verktøykjede er v3.0, og GR00T-lasteren forventer v2. Konverter med scripts/lerobot_conversion/convert_v3_to_v2.py fra Isaac-GR00T-repoet, som skriver codebase_version: v2.1 inn i det konverterte datasettet. Skriptet kjører i sitt eget virtualenv fordi det trenger en annen lerobot-versjon enn GR00T krever.

Kan jeg finjustere GR00T N1.7 på et RTX 4090?

Nei. NVIDIA anbefaler 40 GB eller mer VRAM for finjustering og nevner H100- eller L40-noder; andre kort fungerer, men tar mye lengre tid. Et 4090 har 24 GB. AY-Robots tilbyr kun GR00T N1.7 på A100 80 GB og H100 80 GB nivået av samme grunn. Inferens er en annen historie: 16 GB er nok til å kjøre modellen, så et 4090 kan kjøre en policy det ikke kan trene. Hvis du vil ha en VLA du kan trene på 24 GB, er det SmolVLA på omtrent 450 M parametere eller ACT på omtrent 80 M.

Hvorfor gir to kjøringer med identiske flagg forskjellige sjekkpunkter?

Fordi launch_finetune.py ikke har et seed. Det er en tyro CLI generert fra en dataclass som ikke inneholder et seed-felt, så ingenting fester RNG. Repoet bemerker separat 5 til 6 prosent varians mellom kjøringer forårsaket av ikke-deterministisk bildeaugmentering. Hvis reproduserbarhet er viktig, bruk LeRobot-ruten i stedet: lerobot-train tar --seed og den publiserte GR00T-oppskriften sender --seed=42.

Bør jeg bruke Isaac-GR00T eller lerobot-train?

Bruk Isaac-GR00T hvis du vil ha referanseimplementeringen, per-nøkkel-kontroll over handlingsrepresentasjon, TensorRT-eksport, eller benchmark-eksemplene for å reprodusere før du stoler på dine egne data. Bruk lerobot-train hvis datasettet ditt allerede er LeRobot v3.0 og du helst ikke vil konvertere det, hvis du vil ha et seed, eller hvis resten av stacken din allerede er LeRobot. Begge finjusterer de samme nvidia/GR00T-N1.7-3B-vektene. Merk at LeRobot droppet GR00T N1.5-støtte helt: N1.5-sjekkpunkter avvises med en migreringsmerknad, og du må låse lerobot==0.5.1 for å fortsette å bruke dem.

Trenger jeg virkelig et håndleddskamera i tillegg til et frontkamera?

Den leverte SO-100-konfigurasjonen bruker begge, og modality.json mapper front og håndledd som separate videonøkler. Du kan trene med ett kamera, og modellkortets latens-tabell er målt med ett kamera, men håndleddsvisningen er det som gir policyen brukbar informasjon om griperen i kontaktøyeblikket. Hvis griperen lukker seg på feil tidspunkt i dine rollouts, er et manglende eller dårlig rettet håndleddskamera en av de første tingene å sjekke.

Finjuster GR00T N1.7 på din SO-100 uten å bygge miljøet først

Velg modell, datasett og hyperparametere i et skjema. Backend leier en A100 80 GB eller H100 på spotmarkedet, kjører treneren med batch 32, læringsrate 1e-4 og 20000 trinn, og skriver sjekkpunkter til objektlagring. Omtrent 4 til 12 USD per kjøring.

Åpne GR00T N1.7 treningsguide

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started