Страница руководства AY-Robots по обучению GR00T N1.7 на манипуляторе SO-100, показывающая требуемый уровень GPU, формат набора данных и параметры тренера по умолчанию
GR00T N1.7SO-100Тонкая настройкаLeRobotVLA

Как обучить GR00T N1.7 на собственном наборе данных SO-100

AY-Robots ResearchAugust 23, 202628 мин чтения

Проверенное пошаговое руководство по тонкой настройке NVIDIA GR00T N1.7 на наборе данных LeRobot SO-100: реальные флаги, modality.json, требование v2.1, стоимость запуска и подводные камни.

NVIDIA поставляет пример тонкой настройки именно для того манипулятора, который у вас, вероятно, есть. Внутри репозитория Isaac-GR00T находится папка под названием demo_data/cube_to_bowl_5: пять эпизодов, 4148 кадров при 30 fps, уже записанных в формате LeRobot v2.1, с соответствующей конфигурацией модальности в examples/SO100/. Его meta/info.json сообщает robot_type: so101_follower, что в LeRobot является тем же классом конфигурации, что и so100_follower. Это действительно полезно, потому что это означает, что эталонный путь для GR00T N1.7 для шести-степеней свободы любительского манипулятора поддерживается людьми, которые написали модель. Это не уменьшенная демонстрация гуманоида, это тот же манипулятор.

Плохая новость заключается в расстоянии между I recorded 60 episodes и the arm does the task. Существует около шести мест, где этот конвейер завершается сбоем тихо, а не громко, и четыре из них находятся в файлах, которые большинство людей никогда не открывают: meta/modality.json, конфигурация данных Python, meta/relative_stats.json, и собственная строка версии набора данных. Это руководство описывает ручной маршрут от начала до конца с реальными командами, а затем показывает ту же задачу в виде формы на AY-Robots. Все нижеизложенное было проверено на соответствие основной ветке Isaac-GR00T по состоянию на 20 августа 2026 года (линия n1.7-release) и lerobot 0.6.1, опубликованному в PyPI 3 августа 2026 года. Разработка идет быстро, и если какой-либо флаг был переименован, об этом говорится в данной статье.

Что нужно знать перед началом работы

  • Для тонкой настройки GR00T N1.7 требуется 40 GB или более видеопамяти. NVIDIA рекомендует узлы H100 или L40. RTX 4090 с 24 GB не справится с этой задачей, хотя она может обучать SmolVLA и ACT.
  • Набор данных должен быть LeRobot v2 (v2.0 или v2.1) плюс GR00T-специфичный meta/modality.json. Набор данных LeRobot v3.0 не загружается и должен быть преобразован в более раннюю версию.
  • Точкой входа является gr00t/experiment/launch_finetune.py, CLI tyro. У него нет флага --seed, поэтому запуски не являются побитово воспроизводимыми.
  • Для пользовательского манипулятора тег воплощения — NEW_EMBODIMENT, и этот тег делает --modality-config-path обязательным.
  • Поставляемый рецепт SO-100 предсказывает суставы манипулятора как RELATIVE дельты, а захват — как ABSOLUTE цель. Обратное сопоставление является тихим сбоем, а не ошибкой.
  • На AY-Robots та же задача представляет собой форму: 20000 steps, batch 32, learning rate 1e-4, примерно от 4 до 12 USD на уровне A100 80 GB или H100.

Что на самом деле представляет собой GR00T N1.7

GR00T N1.7 — это визуально-языковая модель действий с двухсистемной архитектурой, описанной в оригинальной статье GR00T N1: визуально-языковой модуль, который считывает данные с камер и инструкцию, и диффузионный трансформер, который преобразует это в блок непрерывных моторных команд. N1.7 заменил первую половину. Бэкенд Eagle из N1.6 был удален, заменен на nvidia/Cosmos-Reason2-2B на архитектуре Qwen3-VL, и модель была предварительно обучена на примерно 20 000 часах эгоцентрического человеческого видео в дополнение к данным робота. В собственном отчете NVIDIA эта цифра составляет 20 854 часа и сообщается, что переход от 1 тыс. до 20 тыс. часов более чем удваивает среднее выполнение задач.

Вторая половина также изменилась, и эти изменения важны для вашего запуска. Голова действий уменьшилась с 32 диффузионных слоев до 16, предсказанный блок действий увеличился с 16 шагов до 40, а максимальная ширина состояния и действия увеличилась с 29 до 132. Эти три числа взяты из журнала изменений в README репозитория; собственный пост NVIDIA о запуске по-прежнему описывает Систему 1 как 32-слойный DiT, поэтому в случае расхождений доверяйте репозиторию, который вы собираетесь клонировать. Действия по умолчанию выражаются в относительном пространстве конечного эффектора, дельтах от текущей позы, а не абсолютных целях, что позволяет вообще переносить априорные знания о манипуляциях, полученные из человеческого видео, в управление роботом. Сама голова представляет собой сопоставление потоков диффузионный трансформер, того же семейства, что и Pi0.5, но с другим бэкендом перед ним. Если вы все еще используете предыдущее поколение, N1.7 против N1.5 описывает, оправдывает ли обновление переделку вашего конвейера.

СвойствоЗначениеИсточник
Параметры3,000,000,000Hugging Face model card
Визуально-языковой бэкендnvidia/Cosmos-Reason2-2B (Qwen3-VL), gated on Hugging Facerepo README
Голова действийFlow-matching diffusion transformer, 16 layers (N1.6 had 32)repo README
Горизонт предсказанных действий40 steps for the base checkpoint (N1.6 had 16)getting_started/policy.md and repo README
Максимальная ширина состояния и действия132 (N1.6 had 29)repo README
Лицензия на кодApache 2.0Isaac-GR00T repository
Лицензия на весаNVIDIA Open Model License Agreementmodel card
Задержка, H100 80 ГБ, PyTorch eager, 4 шага денойзинга, 1 камера85.8 ms end to end, 11.7 Hzmodel card timing table
То же оборудование, полный конвейер TensorRT27.9 ms end to end, 35.9 Hzmodel card timing table
Задержка, которую AY-Robots указывает для своего обслуживаемого GR00T N1.7152 ms per action stepAY-Robots policy catalog

Эти последние три строки объясняют большую часть разочарования, о котором сообщают люди. Заявленные 27.9 ms — это движок TensorRT на H100 с одной камерой и четырьмя шагами денойзинга. Обычный PyTorch на той же карте дает 85.8 ms, и карточка модели указывает на разрыв в 3.08x. Ни одно из этих чисел не включает слой обслуживания, вторую камеру или сетевой переход. 152 ms на шаг действия, которые AY-Robots указывает для своего обслуживаемого GR00T N1.7, — это показатель с обслуживанием в цикле, и к этому добавляется время кругового обхода по публичному интернету. Подробнее об этом в конце. Что касается чисел рядом с другими моделями, GR00T N1.7 против Pi0.5 и GR00T N1.7 против SmolVLA представляют их рядом.

Страница модели AY-Robots для GR00T N1.7, показывающая количество параметров, уровень GPU, задержку вывода и заявленные сильные стороны и ограничения модели
Страница /policies/groot-n1-7 содержит ту же полосу спецификаций, которую вы в противном случае собирали бы вручную из карточки модели и файла README репозитория.

Что требуется для запуска, прежде чем вы что-либо напечатаете

ТребованиеДообучениеВывод
VRAM, рекомендации NVIDIA40 ГБ или более, рекомендуется H100 или L4016 ГБ или более, работает RTX 4090
Python и CUDA на dGPU3.12 и CUDA 12.83.12 и CUDA 12.8
Видео бэкендtorchcodec 0.8.0, только FFmpeg от 4 до 7то же
Формат набора данныхLeRobot v2 плюс meta/modality.jsonнеприменимо
Доступ к Hugging Faceодобрено для nvidia/Cosmos-Reason2-2Bто же
Другие инструментыgit-lfs и uvuv
Уровень GPU AY-Robots для тренера groot1.7A100 80 ГБ или H100 80 ГБпод автоматически выделяется
Закрытая основа остановит вас при первом запуске

Каждый чекпоинт GR00T, включая базовый nvidia/GR00T-N1.7-3B, при первом использовании загружает nvidia/Cosmos-Reason2-2B, и этот репозиторий является закрытым. В README точно указана причина сбоя: загрузка модели завершается ошибкой GatedRepoError / 401 Client Error. Что не упоминается, так это когда это происходит, а именно после того, как вы арендовали карту и запуск начался. Запросите доступ на странице модели, затем выполните uv run huggingface-cli login или экспортируйте HF_TOKEN, прежде чем что-либо арендовать.

Шаг 0: сами эпизоды

Все нижеизложенное предполагает, что у вас уже есть записанные эпизоды. Если нет, то это настоящий первый шаг, и именно он определяет, насколько хорошим может быть результат, потому что обучение с имитацией не может восстановить информацию, которой нет в данных. Сначала откалибруйте обе руки, затем управляйте ведомой рукой с помощью ведущей руки пока lerobot-record записывает файлы parquet и потоки с камер. Если калибровка неточна, значения суставов в вашем наборе данных описывают немного другого робота, чем тот, который позже будет выполнять политику, и никакое количество обучения это не исправит.

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 на текущем LeRobot. Длина эпизода по умолчанию составляет 60 с, а время сброса — 60 с. so100_follower и so101_follower зарегистрированы в одном и том же классе конфигурации LeRobot, поэтому в примере Isaac-GR00T SO100 используются имена so101; оба работают на SO-100. Имена камер, которые вы выбираете здесь (front, wrist), должны снова появиться в modality.json.

Собственный совет LeRobot — записывать не менее 50 эпизодов, примерно по 10 на каждое местоположение объекта, держать камеры неподвижными и сохранять постоянное поведение захвата. Добавляйте вариации позже, а не в начале. Стоит запомнить эмпирическое правило: если вы не смогли выполнить задачу самостоятельно, используя только изображения с камеры, то политика тоже не сможет. Для настройки, специфичной для манипулятора, начало работы с SO-100 и страница LeRobot для SO-100 охватывают порты, калибровку и индексы камер. На AY-Robots вы также можете сделать это через интернет из браузера, используя телеуправление и записывать прямо из сессии.

Шаг 1: набор данных должен быть LeRobot v2.1

Это самое распространенное препятствие. Текущая CODEBASE_VERSION LeRobot в основной ветке — это v3.0, поэтому все, что вы записываете сегодня с помощью текущего набора инструментов, выходит как v3.0. Загрузчик GR00T ожидает v2. Репозиторий явно объясняет причину: многие вышестоящие наборы данных, такие как DROID, LIBERO и Bridge, опубликованы в v2, и нативная поддержка обоих планируется, но еще не реализована. Таким образом, преобразование лежит на вас, и оно выполняется в собственном виртуальном окружении по конкретной причине: scripts/lerobot_conversion имеет свой собственный pyproject, который требует Python 3.10 или 3.11 и привязывает lerobot к одному коммиту git, в то время как сам Isaac-GR00T требует Python 3.12. Установите конвертер из корня репозитория, и вы получите пакет gr00t вместо того, что является ошибкой, о которой предупреждает его README. Если вы новичок в формате, набор данных LeRobot запись в глоссарии объясняет, что на самом деле находится внутри.

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
Конвертер принимает `--repo-id`, необязательный `--root` и `--force-conversion`, который удаляет любой существующий локальный снимок и загружает его заново. Он записывает `codebase_version: v2.1` в `meta/info.json`.
Преобразование перезаписывает на месте

Если набор данных v3.0 уже существует локально, скрипт создает макет v2.1 рядом с ним, а затем меняет их местами: оригинал перемещается в соседнюю папку с добавленной версией, <name>_v3.0, а преобразованная копия занимает исходный путь. (Собственный docstring скрипта называет эту папку _v30; код добавляет строку версии, поэтому вы фактически получаете _v3.0.) Второй сюрприз: вывод всегда попадает в <root>/<repo-id>, поэтому --root examples/SO100/my_dataset_lerobot дает вам examples/SO100/my_dataset_lerobot/<your-hf-user>/<your-dataset>, и этот более длинный путь является тем, что позже требуется для --dataset-path. Когда задание обучения отклоняет ваш набор данных по причинам версии, страница «набор данных отклонен как v3» перечисляет точные симптомы.

Структура, которую GR00T ожидает после преобразования, — это классический макет v2: meta/info.json, meta/episodes.jsonl, meta/tasks.jsonl, файлы parquet в data/chunk-000/, файлы MP4 в videos/chunk-000/observation.images./, и один дополнительный файл, которого нет в стандартном LeRobot. В этом дополнительном файле кроется большинство оставшихся проблем.

Шаг 2: modality.json, шесть чисел, которые решают всё

В наборе данных LeRobot состояние робота и действие хранятся в виде плоских массивов float32. Для SO-100 оба имеют форму [6]: пять суставов руки и захват. Демонстрационный набор данных называет их shoulder_pan.pos, shoulder_lift.pos, elbow_flex.pos, wrist_flex.pos, wrist_roll.pos, gripper.pos, но эти имена находятся в info.json, и ничто в файле parquet не указывает, какой индекс соответствует чему. meta/modality.json предоставляет это сопоставление, и GR00T не будет обучаться без него. Вот тот, который поставляется в репозитории для SO-100, дословно.

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. Индексы начинаются с нуля и соответствуют срезам Python, поэтому single_arm — это [0:5], а gripper — [5:6].

Скопируйте его в ваш преобразованный набор данных по адресу meta/modality.json и переименуйте ключи видео в соответствии с фактическими названиями ваших камер. Если вы записывали с помощью одной верхней камеры под названием top, тогда original_key это observation.images.top а понятное имя — это то, на что будет ссылаться ваша конфигурация данных. Эти два значения должны совпадать, и ни одно из них не проверяет другое за вас. Языковая аннотация хуже, потому что один и тот же ключ должен появляться в трех местах.

УровеньФайлФорма SO-100, используемая в репозитории
Столбец Parquetdata/chunk-*/episode_*.parquetannotation.human.task_description
Ключ modality.jsonmeta/modality.json, под "annotation", без префикса annotation.human.task_description
modality_keys в конфигурации данныхyour so100_config.pyannotation.human.task_description
Почему языковой ключ вызывает затруднения

Сегменты после annotation. выбираются автором набора данных. Демонстрационные данные SO-100 используют annotation.human.task_description; LIBERO и SimplerEnv используют annotation.human.action.task_description. Оба варианта действительны. Если вы скопировали конфигурацию из примера LIBERO и указали ее на свою собственную запись SO-100, языковой канал не разрешится ни во что, и модель будет обучаться на пустой инструкции. Потери все равно уменьшаются. Политика все равно что-то делает. Она просто игнорирует то, что вы ей сказали сделать.

Шаг 3: конфигурация данных, относительная рука и абсолютный захват

Конфигурация модальности — это файл Python, а не JSON, потому что она также определяет, как представляется каждая группа действий. Это та часть рабочего процесса N1.7, которая не существовала в той же форме в N1.5, и та часть, которую стоит прочитать дважды. Поставляемая конфигурация SO-100 предсказывает пять суставов манипулятора как RELATIVE дельты от текущего состояния, а захват как ABSOLUTE целевую позицию, потому что бинарный сигнал открытия/закрытия лучше работает как цель, чем как дельта.

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, сокращено до самого необходимого. NON_EEF означает пространство суставов; EEF ожидало бы девятимерный вектор x, y, z плюс 6D вращение.

Две детали здесь обойдутся вам в день, если вы их не знаете. Во-первых, action_configs является позиционным: документация требует той же длины и того же порядка, что и modality_keys, и они прямо говорят о последствиях ошибки: неправильное представление применяется без уведомления. Ваш захват обучается как дельта, а ваш манипулятор — как абсолютная цель, и при этом нет сообщения об ошибке. Во-вторых, register_modality_config утверждает, что тег еще не зарегистрирован, поэтому вторая конфигурация NEW_EMBODIMENT в том же процессе Python завершается с ошибкой Embodiment tag ... already registered. Вы не можете импортировать две такие конфигурации в один скрипт. Третье правило применяется позже, при развертывании: delta_indices должны быть непрерывным диапазоном, начинающимся с нуля. Разреженное окно, такое как [0, 4, 8], отклоняется, потому что все последующие компоненты индексируют предсказанный фрагмент линейно и в противном случае выполняли бы неправильные строки.

Измените delta_indices, и вам придется перегенерировать статистику

Статистика нормализации, в частности meta/relative_stats.json, вычисляется для той длины горизонта, которая была у вас при их генерации. Сократите горизонт действий с 16 до 8 без перегенерации, и обучение завершится с ошибкой IndexError: boolean index did not match indexed array ... dimension is 8 but corresponding boolean dimension is 16. Решение — одна команда: python gr00t/data/stats.py --dataset-path <path> --embodiment-tag NEW_EMBODIMENT --modality-config-path examples/SO100/so100_config.py. Запускайте ее после любого изменения delta_indices.

Шаг 4: окружение

N1.7 переместил репозиторий в uv и Python 3.12. Старый путь через conda плюс pip install -e . все еще существует в свернутом разделе README, но предупреждает, что зависимости GPU, включая flash-attn и TensorRT, могут потребовать ручной установки. Используйте uv, если у вас нет особой причины не делать этого. Что касается flash-attn, одна деталь поможет избежать путаницы: вы увидите Installing flash-attn выводимым при каждом uv run. Это не пересборка. uv повторно проверяет закрепленный по URL wheel, который уже кэширован, и это занимает две-три секунды.

  1. 1
    Установите git-lfs, затем клонируйте с подмодулями

    git-lfs является обязательным, а не опциональным. Без него файлы parquet в demo_data/ загружаются как заглушки-указатели, и демонстрационный запуск завершается ошибкой на наборе данных, который выглядит присутствующим в списке файлов.

    bash
    sudo apt install git-lfs && git lfs install
    git clone --recurse-submodules https://github.com/NVIDIA/Isaac-GR00T
    cd Isaac-GR00T
  2. 2
    Установите uv и синхронизируйте окружение

    Установка по умолчанию подтягивает зависимости GPU, включая flash-attn и TensorRT. На чистом образе A100 или H100 это самый долгий отдельный шаг, поэтому выполните его, прежде чем обращать внимание на что-либо еще.

    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
    Аутентификация в Hugging Face

    Сделайте это до первого запуска обучения, а не после того, как оно завершится ошибкой через восемь минут.

    bash
    uv run huggingface-cli login   # or: export HF_TOKEN=<your_token>
  4. 4
    Проверка работоспособности на поставляемых демонстрационных данных SO-100

    Прежде чем использовать собственную запись, выполните 2000 шагов на demo_data/cube_to_bowl_5. Это пять эпизодов, они быстро завершаются и подтверждают работоспособность окружения, а не ваших данных. Если этот запуск завершится ошибкой, ничто, что вы сделаете с вашим набором данных, не поможет.

    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
Две ловушки окружения, которые выглядят как ошибки модели

FFmpeg 8. torchcodec 0.8.0 поддерживает только FFmpeg от 4 до 7, а Ubuntu 25.10 и более поздние версии поставляются с версией 8. Ошибка Could not load libtorchcodec выглядит как сломанная установка, а не конфликт версий. Установите более старую среду выполнения, например conda install -c conda-forge 'ffmpeg<8', и добавьте ее библиотеки в LD_LIBRARY_PATH. CUDA_HOME не установлен. Тонкая настройка полностью завершается ошибкой. Запустите bash scripts/deployment/dgpu/install_deps.sh один раз, или просто export CUDA_HOME=/usr/local/cuda.

Шаг 5: команда тонкой настройки и реальные значения по умолчанию для ее флагов

Замените демонстрационный набор данных на свой и добавьте нужные вам параметры. Ниже приведена полная форма, которую репозиторий использует в своем собственном руководстве по новой реализации, включая флаги аугментации и контрольных точек, которые отсутствуют в кратком примере README. Это в узком смысле: языковая основа и визуальный кодировщик остаются замороженными, а обучаются проектор и диффузионная головка действий.

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
Одна GPU. Для восьми карт замените запускающий скрипт на uv run torchrun --nproc_per_node=8 --master_port=29500 и установите --num-gpus 8. Используйте uv run torchrun, а не просто torchrun, иначе вы получите неправильное окружение.
ФлагЗначение по умолчанию в FinetuneConfigЧто он делает
--global-batch-size64Общий размер пакета данных для всех GPU до накопления градиента. В поставляемых примерах используется 32.
--learning-rate1e-4То же значение, которое AY-Robots использует для своего тренера groot1.7.
--max-steps10000Общее количество шагов оптимизатора. Оболочка examples/finetune.sh также по умолчанию использует 10000.
--gradient-accumulation-steps1Умножает эффективный размер пакета. Значения выше 1 выдают предупреждение о накопленном размере.
--save-steps and --save-total-limit1000 and 5Частота сохранения контрольных точек и их количество. Старые удаляются.
--weight-decay and --warmup-ratio1e-5 and 0.05Также явно устанавливается в examples/finetune.sh.
--state-dropout-prob0.2 in the CLI, 0.8 in the model configСлучайным образом отбрасывает проприоцептивное состояние во время обучения. Уменьшите его, если ваша задача сильно зависит от состояния.
--tune-llm and --tune-visualFalse and FalseЯдро по умолчанию остается замороженным.
--tune-projector and --tune-diffusion-modelTrue and TrueПроектор и диффузионная головка действий — это то, что фактически обучается.
--use-percentilesTrueНормализовать с помощью q01 и q99 вместо необработанных минимума и максимума.
--dataloader-num-workers2Загрузчик по умолчанию основан на CPU. В примерах это значение увеличивается до 4.
--seeddoes not existВ этом CLI нет флага seed.

Эта последняя строка — не опечатка. launch_finetune.py — это CLI tyro, сгенерированный из класса данных, и этот класс данных не имеет поля seed. В файле README отдельно отмечается 5–6-процентная дисперсия между запусками, вызванная недетерминированной аугментацией изображений. Два запуска с идентичными флагами не дадут идентичных контрольных точек, что очень важно, когда вы пытаетесь решить, помогло ли изменение гиперпараметра или вам просто повезло. Для сравнения, собственный тренажер lerobot по умолчанию использует seed 1000, а рецепт LeRobot GR00T явно передает --seed=42 явно.

Валидация по умолчанию отключена, а документированный флаг отсутствует в этом CLI

Тонкая настройка выполняется с eval_strategy="no", поэтому кривой потерь валидации вообще нет. Вы получаете только потери обучения и ничего больше. Руководство по новому воплощению предписывает включить его с помощью --eval-strategy steps --eval-steps 500, но этот флаг отсутствует в launch_finetune.py: CLI генерируется tyro из класса данных FinetuneConfig, а eval_strategy, eval_steps и eval_batch_size являются полями TrainingConfig. Их значения по умолчанию там: "no", 500 и 2. Чтобы получить к ним доступ, используйте более полную точку входа gr00t/experiment/launch_train.py, где вложенный флаг — --training.eval-strategy. В любом случае, падение потерь обучения само по себе очень мало говорит о генерализации, что в точности соответствует ситуации, описанной в потери падают, но политика ничего не делает.

Сколько стоит запуск на 20000 шагов

GR00T N1.7 требуется карта на 80 ГБ, поэтому вопрос стоимости имеет узкий ответ. На AY-Robots тренажер groot1.7 работает на уровне A100 80 ГБ или H100 80 ГБ, где запуск занимает от 3 до 6 часов по цене от 1.20 до 2.00 USD в час на спотовом рынке. Это примерно от 4 до 12 USD за стандартную задачу на 20000 шагов. Та же задача на SmolVLA или ACT выполняется на карте 24 ГБ по цене от 0.30 до 0.60 USD в час и от 1 до 3 USD за запуск. В этом и заключается реальный компромисс: GR00T стоит примерно в четыре раза дороже за попытку, и вы не сможете запустить его на 4090 под своим столом.

МодельУровень GPUТипичное время выполненияТипичная стоимостьМинимум эпизодов
GR00T N1.7A100 80 GB or H100 80 GBот 3 до 6 часовот 4 до 12 USD50
GR00T N1.5A100 80 GB or H100 80 GBот 3 до 6 часовот 4 до 12 USD50
Pi0.5A100 80 GB or H100 80 GBот 3 до 6 часовот 4 до 12 USD50
SmolVLARTX 4090 or any 24 GB cardот 2 до 5 часовот 1 до 3 USD30
ACTRTX 4090 or any 24 GB cardот 2 до 5 часовот 1 до 3 USD50

Минимум в 50 эпизодов — это нижний предел, а не цель. Собственный FAQ NVIDIA более требователен: примерно 100 траекторий для простого захвата и размещения в фиксированном месте, 500 или более для сложных или многошаговых сцен, и от 100 до 500 для точной манипуляции. Если у вас всего 20 эпизодов, потратьте день на запись, а не вечер на настройку. Руководство по сбору данных описывает, что отличает полезный эпизод от бесполезного, запишите свой первый набор данных — это краткая версия, а сбор данных SO-100 — это версия для конкретной руки.

Шаг 6: оценка в разомкнутом контуре, прежде чем вы прикоснетесь к руке

Не устанавливайте свежий контрольную точку на физическую руку, чтобы узнать, сработало ли обучение. Сначала запустите оценку в разомкнутом цикле. Она воспроизводит записанный эпизод, запрашивает у модели действия на каждом шаге и строит график предсказаний в сравнении с истинными значениями с использованием MSE и MAE. Это ничего не стоит и позволяет выявить ошибки сопоставления из шагов 2 и 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
Графики сохраняются в /tmp/open_loop_eval/traj_<id>.jpeg, если вы не укажете --save-plot-path. Значения по умолчанию: --execution-horizon 16, --steps 200, --denoising-steps 4, --traj-ids 0.

Репозиторий намеренно отказывается публиковать целевое значение MSE для пользовательских данных, и это правильное решение: число зависит от ваших единиц действия, вашей задачи и размера вашего набора данных, поэтому порог, скопированный с чужой руки, ничего не значит. Что имеет значение, так это тенденция. Вот эталонный запуск, который репозиторий документирует на одном H100 с демонстрационным набором данных из пяти эпизодов и 2000 шагов.

Контрольная точкаСредний MSE на траектории 0Средний MAE на траектории 0
50087.55.63
100025.43.30
150013.22.18
200010.01.76

Форма является сигналом, а не абсолютными значениями. Ошибка должна неуклонно снижаться по мере накопления шагов обучения. Усредненный по всем пяти эпизодам обучения, а не только по траектории 0, итоговый контрольный пункт репозитория показал примерно 7.5 MSE и 1.5 MAE, поэтому даже эталонный запуск интерпретируется по-разному в зависимости от того, какие эпизоды вы усредняете. Запишите свой собственный базовый показатель на неизмененной демонстрационной команде, прежде чем что-либо менять в своих данных: если вы не можете воспроизвести заведомо рабочий запуск, вы не сможете отличить ошибку настройки от проблемы с данными. Репозиторий также сопоставляет общие симптомы с причинами, и каждая из них является операционной, а не ошибкой модели.

СимптомВероятная причина
MSE остается неизменным или растет на контрольных точкахСкорость обучения слишком низка, или данные вообще не загружаются. Проверьте --dataset-path и рабочие процессы загрузчика данных.
Кривая предсказания плоская или постояннаяКлючи modality.json или --modality-config-path не совпадают. Ключи действий не сопоставлены.
MSE огромен, или потеря NaN во время обученияНормализация действий и состояний. Проверьте meta/stats и убедитесь, что диапазоны действий физически правдоподобны.
Хорошо на траектории 0, плохо на отложенных эпизодахНедостаток данных, а не ошибка. Пять демонстрационных эпизодов не могут обеспечить обобщение.

Другой путь: lerobot-train вместо Isaac-GR00T

Текущий релиз LeRobot, 0.6.1 на PyPI с 3 августа 2026 года, предлагает второй и совершенно иной способ тонкой настройки тех же базовых весов. LeRobot предоставляет GR00T N1.7 как тип политики и обучает его через свою собственную точку входа lerobot-train. Здесь важны две вещи. CLI LeRobot — это набор консольных скриптов, поэтому все, что вы читаете, где говорится python lerobot/scripts/train.py, устарело и не будет работать. И LeRobot полностью удалил поддержку GR00T N1.5, отклоняя контрольные точки и конфигурации N1.5 с примечанием о миграции, поэтому, если вам нужен N1.5 через LeRobot, вам придется закрепить версию lerobot==0.5.1, последний релиз, который его поддерживает, опубликованный 7 апреля 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
Рецепт GR00T N1.7, нативный для LeRobot. Обратите внимание на relative_exclude_joints: захват исключен из относительных действий, что соответствует решению, принятому so100_config.py с ActionRepresentation.ABSOLUTE.
АспектIsaac-GR00T launch_finetune.pylerobot-train --policy.type=groot
Версия набора данныхТолько LeRobot v2, требуется конвертацияНативный набор данных LeRobot, без понижения версии
Сопоставление модальностейmeta/modality.json плюс конфигурация данных Pythonбез modality.json; поведение задается флагами --policy.* в командной строке
Зернофлаг зерна отсутствует--seed, по умолчанию LeRobot 1000
Относительные действияActionConfig для каждого ключа в конфигурации данных--policy.use_relative_actions плюс --policy.relative_exclude_joints
Опубликованные эталонные результатыТенденция MSE SO-100 в разомкнутом контуре на демонстрационных данныхНаборы LIBERO, в среднем 96,5 процента по четырем наборам
Путь развертыванияrun_gr00t_server.py плюс eval_so100.py через ZMQlerobot-rollout, с чанкингом в реальном времени (queue_threshold должен оставаться на уровне 5 или ниже)
Самостоятельный запуск дообучения
Преимущества
  • Каждый флаг виден и изменяем. Вы можете разморозить визуальный кодировщик, изменить state_dropout_prob или сократить горизонт действий.
  • Графики разомкнутого контура — это локальные файлы. Сравнение checkpoint-5000 с checkpoint-20000 — это команда оболочки.
  • Вы не зависите от того, что какая-либо платформа остается онлайн, и контрольная точка хранится на вашем диске в стандартном формате.
  • Примеры бенчмарков репозитория для LIBERO, SimplerEnv и DROID дают вам заведомо хорошие запуски для воспроизведения, прежде чем вы доверитесь своим собственным данным.
Компромиссы
  • Окружение — это большая часть работы. Версия FFmpeg, CUDA_HOME, git-lfs, gated backbone, torchcodec: ни одна из этих проблем не связана с моделью, и каждая из них останавливает выполнение.
  • Преобразование из v3.0 в v2.1 требует отдельного виртуального окружения со своим шагом установки, и оно перезаписывает ваш каталог набора данных на месте.
  • Аренда GPU начинает тарифицироваться, когда вы начинаете отладку, а не когда начинается обучение, и ничто не останавливает экземпляр после завершения выполнения.
  • Отсутствие зерна означает отсутствие побитовой воспроизводимости, вдобавок к 5-6-процентной вариативности между запусками только из-за аугментации.

Два способа получить одну и ту же контрольную точку

Вы арендуете GPU и контролируете каждый шаг. Реалистично, в первый раз это займет полдня, а затем — двадцать минут каждый раз.

  1. Записывайте эпизоды с помощью lerobot-record на SO-100. Вы получите набор данных LeRobot v3.0.
  2. Преобразуйте его до версии v2.1 с помощью scripts/lerobot_conversion/convert_v3_to_v2.py в отдельном виртуальном окружении.
  3. Напишите meta/modality.json и конфигурацию модальности на Python, зарегистрированную под EmbodimentTag.NEW_EMBODIMENT.
  4. Арендуйте карту на 80 ГБ, клонируйте с подмодулями, выполните uv sync, пройдите аутентификацию в Hugging Face.
  5. Запустите launch_finetune.py, затем open_loop_eval.py на нескольких контрольных точках и сравните тенденцию MSE, прежде чем приступать к работе с оборудованием.
  6. Скопируйте контрольную точку с машины, прежде чем уничтожить экземпляр, затем постройте путь обслуживания к манипулятору.
Шаг, о котором все забывают

Скопируйте контрольную точку с арендованного экземпляра, прежде чем выключить его. --save-total-limit 5 также означает, что старые контрольные точки удаляются по мере обучения, поэтому контрольная точка, которую вы хотели на шаге 5000, может больше не существовать на шаге 20000.

Матрица обучения AY-Robots с пятью моделями политик в строках и четырьмя роботизированными манипуляторами в столбцах, каждая ячейка ссылается на конкретное руководство по обучению
Матрица /train: пять моделей против четырех манипуляторов. Строка GR00T N1.7 также охватывает SO-101, Koch v1.1 и LeKiwi.

Возвращение контрольной точки на манипулятор

Isaac-GR00T использует разделение клиент-сервер по ZMQ. Политика выполняется на GPU, а тонкий клиент на машине робота отправляет наблюдения и получает фрагменты действий. Пример SO-100 достаточно полон для копирования: запустите run_gr00t_server.py с вашей контрольной точкой и --embodiment-tag NEW_EMBODIMENT, затем запустите eval_so100.py на стороне робота с использованием последовательного порта, идентификатора робота, индексов камеры и языковой инструкции. Имена камер в этой команде должны соответствовать дружественным именам из вашего modality.json, а не номерам устройств ОС.

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 контролирует, сколько из предсказанных шагов выполняется до повторного планирования. Оно должно быть не более action_horizon политики, и это число является длиной action delta_indices в вашей конфигурации модальности, а не базовой модели. Поставляемая конфигурация SO-100 предсказывает 16, поэтому 16 — ваш потолок; базовая контрольная точка nvidia/GR00T-N1.7-3B настроена на 40, и policy.md прямо заявляет, что тонко настроенные контрольные точки могут отличаться. Превысьте его, и вы получите ValueError, указывающий оба числа. 8 — это значение, которое документация предлагает для развертывания в реальном времени. Старое имя флага --action-horizon по-прежнему работает, но выдает предупреждение.
7.4 В, а не 12 В

Пока вы снова подключаете манипулятор: SO-100 использует шинные сервоприводы Feetech STS3215 на шине 7.4 В. Подача на них 12 В выводит их из строя, и это легко допустить, если у вас также есть LeKiwi, чья база работает от 12 В, а манипулятор — нет. Проверьте питание перед первым включением, а не после появления дыма. См. страницу оборудования SO-100 и SO-100 против LeKiwi. Если манипулятор включается, но ничего не движется, сервопривод не отвечает — это то, с чего стоит начать.

Теперь честная часть о том, где выполняется политика, потому что обучение и обслуживание имеют разные требования к оборудованию. Для тонкой настройки требуется 40 ГБ или более. Для инференса — нет: README указывает 16 ГБ или более и явно называет RTX 4090, так что карта, которая у вас уже есть, может обслуживать контрольную точку, которую она никогда не смогла бы произвести. Что определяет, насколько отзывчивой кажется политика, это не VRAM, а то, где находится сервер. На AY-Robots GR00T N1.7 доступен только в облаке, поэтому цикл управления оплачивает круговой путь через публичный интернет в дополнение к 152 мс на каждый шаг действия, и только SmolVLA и ACT также работают локально. Для медленного захвата и перемещения удаленный под является приемлемым. Для чего-либо реактивного — нет: политика становится нерешительной таким образом, что это выглядит в точности как сбой обучения, но таковым не является. ACT со скоростью 20 мс на шаг действия — это модель, которая допускает самый короткий цикл, SmolVLA работает со скоростью 245 мс, и никакое количество настройка задержки не компенсирует уже потраченный круговой путь. Запустите свою первую политику подробно описывает сторону обслуживания от начала до конца.

Что на самом деле идет не так

  • GatedRepoError при первом запуске. Вам не был предоставлен доступ к nvidia/Cosmos-Reason2-2B, или вы не прошли аутентификацию. Это происходит после того, как тактовая частота GPU уже запущена.
  • Набор данных отклонен при загрузке. Почти всегда это набор данных v3.0. Преобразуйте его в более раннюю версию. См. отклонение набора данных как v3.
  • IndexError о несоответствии булевых размерностей. Вы изменили delta_indices и не перегенерировали статистику.
  • Недостаточно памяти при пакете 32. Уменьшите --global-batch-size и увеличьте --gradient-accumulation-steps, или уменьшите --num-shards-per-epoch, что явно предлагается в конфигурации при ограниченной VRAM. См. недостаток памяти во время обучения.
  • Потери падают, политика ничего не делает. По умолчанию нет разделения на валидацию, поэтому чистая кривая обучения мало что доказывает. Эта страница описывает диагностику.
  • Работает в вашей настройке и нигде больше. Ожидаемо для небольшого набора данных, снятого при одном условии освещения. NVIDIA рекомендует аугментацию с цветовым дрожанием плюс от 20 до 50 эпизодов при различном освещении. Подробнее здесь.
  • Захват никогда не закрывается должным образом. Убедитесь, что действие захвата является ABSOLUTE, а суставы манипулятора — RELATIVE, именно в таком порядке в action_configs. Захват не закрывается перечисляет другие причины.
  • Камера незаметно отключается в середине записи. Эпизод все равно сохраняется, и ключ видео все еще существует, поэтому это неприятно. Камера не обнаружена описывает это.

Полный индекс режимов отказа находится на . Если вы выбираете между моделями, а не отлаживаете одну, и содержат эталонные показатели с прикрепленными источниками, а — это сравнение, которое на самом деле нужно большинству людей, потому что это выбор между моделью, которую можно обучить на карте под вашим столом, и моделью, для тонкой настройки которой нужно арендовать узел с 80 ГБ. Для получения информации о том, почему эти модели ведут себя так, как они ведут, и стоит прочитать в первую очередь. И если у вас еще нет манипулятора, транслирует физический SO-100 без регистрации.

Сколько эпизодов мне нужно, прежде чем тонкая настройка GR00T N1.7 станет целесообразной?

AY-Robots устанавливает жесткий минимум в 50 эпизодов для тренера groot1.7. Собственный FAQ NVIDIA более требователен: примерно 100 траекторий для простого захвата и размещения в фиксированном месте, 500 или более для сложных или многошаговых сцен, и от 100 до 500 для тонкой манипуляции. При количестве менее 50 почти всегда лучше записать больше данных, чем настраивать гиперпараметры. Если после этого успех стабилизируется, NVIDIA рекомендует HG-DAgger: запустить политику, вмешаться при ее сбое и добавить эти исправления в набор данных.

Почему мой набор данных не загружается, и как определить его версию?

Откройте meta/info.json и прочитайте codebase_version. Текущая CODEBASE_VERSION LeRobot в main — v3.0, поэтому все, что записано с помощью недавнего набора инструментов, является v3.0, а загрузчик GR00T ожидает v2. Преобразуйте с помощью scripts/lerobot_conversion/convert_v3_to_v2.py из репозитория Isaac-GR00T, который записывает codebase_version: v2.1 в преобразованный набор данных. Скрипт запускается в собственном виртуальном окружении, потому что ему нужна другая версия lerobot, чем та, которую использует GR00T.

Могу ли я тонко настроить GR00T N1.7 на RTX 4090?

Нет. NVIDIA рекомендует 40 ГБ или более VRAM для тонкой настройки и называет узлы H100 или L40; другие карты работают, но занимают гораздо больше времени. У 4090 есть 24 ГБ. AY-Robots предлагает GR00T N1.7 только на уровне A100 80 ГБ и H100 80 ГБ по той же причине. Инференс — это другая история: 16 ГБ достаточно для обслуживания модели, поэтому 4090 может запускать политику, которую она не может обучить. Если вы хотите VLA, который можно обучить на 24 ГБ, это SmolVLA с примерно 450 млн параметров или ACT с примерно 80 млн.

Почему два запуска с идентичными флагами дают разные контрольные точки?

Потому что launch_finetune.py не имеет seed. Это CLI tyro, сгенерированный из класса данных, который не содержит поля seed, поэтому ничто не фиксирует ГСЧ. Репозиторий отдельно отмечает 5-6-процентную дисперсию между запусками, вызванную недетерминированной аугментацией изображений. Если воспроизводимость важна, используйте вместо этого путь LeRobot: lerobot-train принимает --seed, а опубликованный рецепт GR00T передает --seed=42.

Стоит ли использовать Isaac-GR00T или lerobot-train?

Используйте Isaac-GR00T, если вам нужна эталонная реализация, поключевой контроль над представлением действий, экспорт TensorRT или примеры бенчмарков для воспроизведения, прежде чем доверять своим собственным данным. Используйте lerobot-train, если ваш набор данных уже LeRobot v3.0 и вы не хотите его конвертировать, если вам нужен seed, или если остальная часть вашего стека уже LeRobot. Оба тонко настраивают одни и те же веса nvidia/GR00T-N1.7-3B. Обратите внимание, что LeRobot полностью прекратил поддержку GR00T N1.5: контрольные точки N1.5 отклоняются с примечанием о миграции, и вам придется зафиксировать lerobot==0.5.1, чтобы продолжать их использовать.

Действительно ли мне нужна наручная камера, а также фронтальная камера?

Поставляемая конфигурация SO-100 использует обе, и modality.json сопоставляет переднюю и наручную камеры как отдельные видеоключи. Вы можете обучать с одной камерой, и таблица задержек карты модели измеряется с одной камерой, но вид с запястья дает политике полезную информацию о захвате в момент контакта. Если захват закрывается не в то время в ваших прогонах, отсутствующая или плохо нацеленная наручная камера — одна из первых вещей, которые нужно проверить.

Тонкая настройка GR00T N1.7 на вашем SO-100 без предварительной сборки окружения

Выберите модель, набор данных и гиперпараметры в форме. Бэкенд арендует A100 80 ГБ или H100 на спотовом рынке, запускает тренажер с пакетом 32, скоростью обучения 1e-4 и 20000 шагами, и записывает контрольные точки в объектное хранилище. Примерно от 4 до 12 USD за запуск.

Открыть руководство по обучению GR00T N1.7

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started