AWS показала полный цикл обучения робота на LeRobot и Hugging Face Storage Buckets

AWS показала полный цикл обучения робота на LeRobot и Hugging Face Storage Buckets

AWS опубликовала на блоге Hugging Face продолжение серии про Strands Robots, открытый SDK под лицензией Apache 2.0, который отдаёт абстракции робота, симуляцию и стек LeRobot как инструменты (AgentTools) для одного агента Strands. Первый пост серии вёл путь в одну сторону: фабрика Robot(), запись демонстрации в симуляции, прогон политики и перенос того же кода агента на физическую руку SO-101. Эта фабрика разрешает имя по реестру рук-манипуляторов, гуманоидов, мобильных платформ и кистей, так что SO-100 из примеров нового поста, одно из многих поддерживаемых воплощений, а полный список ведётся в каталоге роботов. Новый пост идёт по данным в обратную сторону, от первого записанного кадра до развёрнутой политики, и вводит в цепочку Hugging Face Storage Buckets: изменяемый, неверсионируемый репозиторий объектного хранилища на технологии Xet, о котором Hugging Face объявила в марте 2026 года. Такой бакет стоит рядом с репозиториями датасетов в том же пространстве имён hf:// и работает через ту же командную строку hf, поэтому становится рабочим слоем между днём, когда данные записали, и днём, когда на них учатся.

Проблема, с которой начинается гид, повторные переносы одних и тех же байтов. Прогнать цикл один раз (собрать эпизоды за день, обучить политику на растущем датасете, выкатить её на робота, забрать следующую партию записей), всё работает. Гонять его каждый день, и вы платите за одни и те же переносы снова и снова: записи растут, каждый прогон обучения копирует весь датасет на GPU перед стартом, а каждый новый чекпойнт уезжает наружу, пока обратно едет очередная партия записей.

Отдельный довод поста, почему в этом цикле нужен именно агент. Кто-то должен решать, какие эпизоды оставить, когда сцена изменилась достаточно, чтобы перезаписать её, хватает ли сегодняшней партии для обучения и какой чекпойнт заменит тот, что стоит на руке. За кампанию по сбору данных каждое такое решение возникает десятки раз, и каждое требует посмотреть на то, что вернулось, прежде чем уйдёт следующая команда. Именно это, пишет автор гида, и есть работа для агента.

Что получается на выходе: агент записывает LeRobotDataset по промпту на естественном языке, синхронизирует его в бакет и оттуда же читает обратно, покадрово, с декодированием видео с камер на лету и без локальной копии. Записывает и читает один и тот же объект Robot(), то есть сбор данных и обучение на них становятся двумя методами одного объекта поверх одного хранилища. Обученный чекпойнт разворачивается на том же Robot() сменой одного именованного аргумента, mode="real", а демонстрации, записанные уже на железе, возвращаются в тот же бакет. В коде весь цикл укладывается в несколько строк: sim = Robot("so100") (по умолчанию mode="sim", безопасный режим без железа), agent = Agent(tools=[sim]), один промпт «запиши демонстрацию с кубиком и синхронизируй её в my-org/robot-fave», а затем перебор батчей из sim.stream_dataset("my-org/robot-fave/cube_pick", repo_type="bucket").dataloader(batch_size=64).

Шаг первый, запись в бакет. LeRobot пишет запись как небольшой набор больших файлов, которые растут по ходу дела. Если складывать их в версионируемый репозиторий датасета, каждое добавление становится коммитом и каждая ревизия хранится, а сбору данных нужно обратное: место, куда можно писать байты и перезаписывать их на месте. Это и есть Storage Bucket, он лежит внутри вашего рабочего пространства Hugging Face и использует уже имеющиеся права, так что настраивать роли IAM (управление доступом), правила CORS (кросс-доменные запросы) и держать собственный сервис загрузки не нужно. В примере один промпт задаёт сцену, камеры, политику и запись: создать мир с роботом so100, добавить красный кубик и фронтальную камеру, начать запись (repo_id='local/cube_pick', root='/tmp/cube_pick', fps=30, overwrite=True, task='pick up the red cube'), прогнать фиктивную политику 60 шагов и остановить запись. Дальше вызов sync_dataset_to_bucket("/tmp/cube_pick", "my-org/robot-fave") проверяет датасет и заливает его через командную строку hf, отдельно от жизненного цикла записи, и возвращает адрес hf://buckets/my-org/robot-fave/cube_pick, путь вида hf://buckets/{bucket}/{run_id}, где run_id по умолчанию равен имени каталога датасета. Та же возможность есть у DatasetRecorder.sync_to_bucket(bucket, run_id=...), если вы управляете открытым рекордером напрямую, а stop_recording(bucket=...) синхронизирует данные в момент остановки активной записи. Бакет, рабочий слой, куда пишут в течение дня; для версионированного опубликованного артефакта по-прежнему вызывают push_to_hub(), формат в обоих случаях один и тот же. Путь по умолчанию использует фиктивную (mock) политику, она выдаёт суставные действия без обученной модели, поэтому эпизод структурно полон, но обучающими данными его назвать нельзя; для настоящего захвата в код подставляют create_policy("<hf_repo>"), а промпт, формат и синхронизация остаются прежними. Запись на физической SO-101 идёт через командную строку lerobot-record с парой «ведущий, ведомый» (--robot.type=so101_follower и --teleop.type=so101_leader) и параметрами --dataset.repo_id и --dataset.single_task; на диск ложится тот же формат, что в симуляции, поэтому в бакет её отправляет тот же вызов sync_dataset_to_bucket("./recordings", "my-org/robot-fave", run_id="run-021"), обёртка над командой hf sync ./recordings hf://buckets/my-org/robot-fave/run-021.

Шаг второй, хранение с дедупликацией на уровне байтов. Две неподвижные камеры, рука, восемь часов разбирающая один и тот же стол, и большая часть записанного оказывается пикселями, которые уже есть: то же освещение, то же шасси, тот же фон, и так тысячи эпизодов. На версионируемом репозитории всё хуже: изменение одного кадра в многогигабайтном видеофайле перезаливает файл целиком. Бакеты работают поверх Xet, который дедуплицирует загрузки на уровне байтов, применяя разбиение на блоки по содержимому (content-defined chunking): границы блоков следуют за содержимым, поэтому вставка нескольких байтов меняет только тот блок, куда они попали, а не сдвигает все границы после него. По собственным замерам Hugging Face, такое разбиение сокращает объём передаваемых данных на одну загрузку примерно вчетверо в масштабах всего Hugging Face Hub, а на планах Enterprise счёт выставляется по дедуплицированному объёму. Бенчмарки бакетов показывают это на одном файле: если отталкиваться от загрузки в 500 МБ, то изменение 1% байтов и повторная заливка перенесли 5,5 МБ, изменение 5%, 27,5 МБ, изменение 10%, 55 МБ. Без дедупликации на уровне блоков перезапись объекта означает отправку всех его байтов заново, независимо от того, изменились они или нет.

Насколько это экономит, зависит от раскладки файлов, а рекордер Strands Robots использует раскладку LeRobot: эпизоды уходят в шарды Parquet (data/chunk-000/file-000.parquet) и в шарды MP4 по каждой камере (videos/observation.images.front/chunk-000/file-000.mp4), причём новый файл заводится только когда текущий заполнен, по умолчанию это 100 МБ для Parquet с данными и 200 МБ для видео MP4. Поэтому синхронизация после дня записи заливает новые хвостовые шарды плюс один недозаполненный, который подрос, а не весь датасет; на следующий день дедупликацию снова берёт на себя Xet. Формат датасетов LeRobot к этому моменту используют более 90 000 датасетов и моделей на Hugging Face Hub от более чем 8 000 издателей (данные LeRobot Project Pulse), так что запись Strands Robots, ещё одна такая же, и всё, что умеет читать данные LeRobot, читает её без конвертации.

Минимальный набор для симуляционного пути, который, по словам гида, целиком запускается на ноутбуке: Python 3.12+ на Linux или macOS (Apple Silicon поддержан для бэкенда MuJoCo), совместимый со Strands провайдер модели для рассуждений агента (Amazon Bedrock с учётными данными AWS, API Anthropic, OpenAI или локально запущенная Ollama) и установка uv pip install -U "strands-robots[sim-mujoco,lerobot]>=0.5.1"; дополнение lerobot тянет сам LeRobot (>=0.6.1), а также datasets, av и torchcodec, поэтому запись и декодирование видео работают без дополнительной настройки. Запускается при этом именно цикл, а не рабочая политика. Для бакетов, железа и настоящих политик нужны аккаунт Hugging Face и токен с правом записи вместе с командной строкой hf (pip install -U "huggingface-hub>=1.6.0,<2.0.0", затем hf auth login), пара SO-101 «ведущий, ведомый» или другой поддерживаемый LeRobot робот с файлами калибровки в ~/.cache/huggingface/lerobot/calibration/, видеокарта NVIDIA для локального запуска моделей VLA (vision-language-action, «зрение, язык, действие») и кластер GPU, читающий данные с Hugging Face Hub, для обучения в масштабе. Сам шаг обучения требует установки uv pip install "lerobot[training]": записи и потоковому чтению она не нужна, но без неё trainer.train() возвращает не чекпойнт, а результат с ошибкой (руководство по устранению неполадок называет эту ошибку и нужную установку). Рабочий сопроводительный ноутбук к посту лежит по пути examples/notebooks/05_streaming_data_loop.ipynb.

Ключевые факты

  • Гид AWS на блоге Hugging Face собирает в один агентский цикл Strands Robots (открытый SDK от AWS, Apache 2.0), LeRobot и Hugging Face Storage Buckets: запись демонстрации → синхронизация в бакет → потоковое чтение датасета для обучения без локальной копии → развёртывание чекпойнта на том же объекте Robot() сменой одного аргумента на mode="real".
  • Storage Buckets, изменяемый, неверсионируемый репозиторий объектного хранилища на технологии Xet, объявленный Hugging Face в марте 2026 года; он живёт в том же пространстве имён hf:// рядом с репозиториями датасетов, работает через ту же командную строку hf и не требует ролей IAM, правил CORS и собственного сервиса загрузки.
  • Дедупликация на уровне байтов через разбиение на блоки по содержимому (content-defined chunking), по собственным замерам Hugging Face, сокращает объём передаваемых данных на одну загрузку примерно вчетверо в масштабах всего Hugging Face Hub; в бенчмарке на файле 500 МБ изменение 1% байтов перенесло 5,5 МБ, 5%, 27,5 МБ, 10%, 55 МБ. На планах Enterprise счёт выставляется по дедуплицированному объёму.
  • Раскладка LeRobot определяет экономию: эпизоды пишутся в шарды Parquet и шарды MP4 по каждой камере, новый файл заводится только когда текущий заполнен (по умолчанию 100 МБ для данных Parquet и 200 МБ для видео MP4), поэтому суточная синхронизация заливает новые хвостовые шарды и один подросший недозаполненный, а не весь датасет.
  • Формат датасетов LeRobot уже используют более 90 000 датасетов и моделей на Hugging Face Hub от более чем 8 000 издателей (LeRobot Project Pulse), поэтому запись Strands Robots читается любым инструментом для данных LeRobot без конвертации; путь по умолчанию использует фиктивную (mock) политику, датасет получается структурно корректным, но не пригодным для обучения.

Почему это важно

Гид закрывает не вопрос «как обучить политику», а вопрос «как гонять цикл сбор → обучение → развёртывание каждый день и не платить за одни и те же байты». Ответ состоит из трёх частей. Первая: Hugging Face Storage Buckets, о которых компания объявила в марте 2026 года, изменяемое неверсионируемое хранилище, куда можно писать и перезаписывать на месте, в отличие от версионируемого репозитория датасета, где каждое добавление становится коммитом и каждая ревизия хранится. Вторая: дедупликация на уровне байтов через Xet, по собственным замерам Hugging Face это примерно вчетверо меньше передаваемых данных на одну загрузку в масштабах всего Hugging Face Hub, а на одиночном файле в 500 МБ изменение 10% байтов стоит 55 МБ трафика вместо повторной отправки всех 500 МБ. Третья: обучение потоковым чтением прямо с Hub, без копирования всего датасета на GPU перед стартом. Всё это лежит на формате LeRobot, который уже используют более 90 000 датасетов и моделей от более чем 8 000 издателей, так что записи Strands Robots читаются существующей экосистемой без конвертации. Отдельный смысловой поворот: решения кампании по сбору данных, какие эпизоды оставить, когда перезаписать сцену, хватает ли партии для обучения, каким чекпойнтом заменить текущий, возникают десятками раз, и гид предлагает отдать их агенту, у которого запись и чтение данных, два метода одного объекта Robot().

Кому это важно

Командам, которые собирают реальные демонстрации на роботах и упираются не в алгоритмы, а в перекачку многогигабайтных видеозаписей: гид ровно про стоимость и организацию этого потока. Инженерам, обучающим политики на данных LeRobot и хранящим их на Hugging Face Hub, в том числе тем, кто на планах Enterprise, где счёт выставляется по дедуплицированному объёму. Владельцам SO-100, SO-101 и других поддерживаемых LeRobot роботов: фабрика Robot() разрешает имя по реестру рук-манипуляторов, гуманоидов, мобильных платформ и кистей, а полный перечень ведётся в каталоге роботов. Тем, кто строит агентов на стеке Strands от AWS и хочет получить робота как набор инструментов агента. И тем, у кого железа пока нет: путь по умолчанию, симуляция на MuJoCo, весь цикл запускается на ноутбуке с Python 3.12+ на Linux или macOS, включая Apple Silicon.

Как это применить

Симуляционный путь: поставить uv pip install -U "strands-robots[sim-mujoco,lerobot]>=0.5.1" (дополнение lerobot тянет LeRobot >=0.6.1, datasets, av и torchcodec), подключить совместимого со Strands провайдера модели, Amazon Bedrock с учётными данными AWS, API Anthropic, OpenAI или локальную Ollama, создать sim = Robot("so100") (по умолчанию mode="sim") и agent = Agent(tools=[sim]). Дальше один промпт на естественном языке задаёт всё: создать мир с роботом so100, добавить красный кубик и фронтальную камеру, начать запись (repo_id='local/cube_pick', root='/tmp/cube_pick', fps=30, overwrite=True, task='pick up the red cube'), прогнать политику 60 шагов и остановить запись. Готовый датасет уходит в хранилище вызовом sync_dataset_to_bucket("/tmp/cube_pick", "my-org/robot-fave"), он проверяет датасет и заливает его через командную строку hf, живя отдельно от сессии записи; альтернативы, DatasetRecorder.sync_to_bucket(bucket, run_id=...) для открытого рекордера и stop_recording(bucket=...) для синхронизации в момент остановки. Для бакетов нужны аккаунт Hugging Face, токен с правом записи и pip install -U "huggingface-hub>=1.6.0,<2.0.0" с последующим hf auth login. Обучение: sim.stream_dataset("my-org/robot-fave/cube_pick", repo_type="bucket").dataloader(batch_size=64) читает датасет обратно покадрово, с декодированием видео на лету и без локальной копии; первые два сегмента идентификатора, это бакет, всё остальное, путь внутри него. Для самого обучения дополнительно ставится uv pip install "lerobot[training]". Развёртывание, тот же Robot() со сменой одного именованного аргумента на mode="real". Вместо фиктивной политики для реального захвата подставляется create_policy("<hf_repo>"); запись на железе делается через lerobot-record с парой so101_leader и so101_follower, после чего в бакет её отправляет тот же sync_dataset_to_bucket("./recordings", "my-org/robot-fave", run_id="run-021") или напрямую hf sync ./recordings hf://buckets/my-org/robot-fave/run-021. Бакет остаётся рабочим слоем, а для публикуемой версионированной копии по-прежнему вызывается push_to_hub(). Всё это собрано в исполняемом ноутбуке examples/notebooks/05_streaming_data_loop.ipynb.

Можно ли доверять

Источник первичный: пост в серии AWS про Strands Robots, опубликованный на блоге Hugging Face, а сам SDK открыт под лицензией Apache 2.0 и сопровождается исполняемым ноутбуком, так что заявленный цикл проверяется запуском. При этом все цифры экономии, данные самого поставщика: и оценка «примерно вчетверо меньше передаваемых данных» подана как собственные замеры Hugging Face, и разбивка 5,5 / 27,5 / 55 МБ взята из бенчмарков бакетов Hugging Face, то есть измеряла экономию та же компания, что продаёт хранилище. Материал, практическое руководство, а не разбор внедрения: ни одного клиента, компании или рабочего развёртывания, где этот цикл уже используется, в тексте не названо. Дата анонса Storage Buckets дана только с точностью до месяца, март 2026 года. Наконец, сохранённый текст страницы обрывается на середине подписи к рисунку 2, поэтому шаги про потоковое обучение и возврат чекпойнта на железо известны по вступлению и примеру кода, но не по их собственным разделам.

Риски и подводные камни

Путь по умолчанию использует фиктивную (mock) политику: она выдаёт суставные действия без обученной модели, эпизод получается структурно полным, но обучающими данными не является, то есть «из коробки» запускается цикл, а не работающая политика. Свойство, которое делает бакет удобным для сбора, изменяемость и отсутствие версий, означает и отсутствие истории ревизий: для публикуемого версионированного артефакта всё равно нужен push_to_hub(). Экономия трафика зависит от раскладки файлов и от того, действительно ли содержимое повторяется: «примерно вчетверо», усреднение по всему Hugging Face Hub, а 5,5 / 27,5 / 55 МБ измерены на одном файле в 500 МБ, а не на датасете робота; биллинг по дедуплицированному объёму упомянут применительно к планам Enterprise. Стоимость самого хранилища пост не называет, цен и тарифов Storage Buckets в тексте нет, их придётся выяснять отдельно. Шаг обучения ставится отдельно: без lerobot[training] вызов trainer.train() вернёт не чекпойнт, а результат с ошибкой. Аппаратный путь добавляет требований: пара SO-101 «ведущий, ведомый» или другой поддерживаемый LeRobot робот с файлами калибровки в ~/.cache/huggingface/lerobot/calibration/, видеокарта NVIDIA для локального запуска моделей VLA и кластер GPU, читающий данные с Hugging Face Hub, для обучения в масштабе. Наконец, версии жёстко заданы, Python 3.12+, strands-robots >=0.5.1, LeRobot >=0.6.1, huggingface-hub >=1.6.0 и ниже 2.0.0, и несовпадение окружения здесь самый вероятный источник проблем при повторении.

«Без дедупликации на уровне блоков перезапись объекта означает отправку всех его байтов заново, независимо от того, изменились они или нет.»

— Гид AWS на блоге Hugging Face