Представьте задачу: есть куча роботов, и им всем надо куда‑то добраться, не столкнувшись с собратьями, а мы должны придумать для этого алгоритм. Это, если упрощПредставьте задачу: есть куча роботов, и им всем надо куда‑то добраться, не столкнувшись с собратьями, а мы должны придумать для этого алгоритм. Это, если упрощ

Нам не подошла ни одна среда для MARL в непрерывном пространстве — поэтому мы сделали CAMAR

2026/03/07 17:16
23м. чтение
Для обратной связи или замечаний по поводу данного контента, свяжитесь с нами по адресу [email protected]

Представьте задачу: есть куча роботов, и им всем надо куда‑то добраться, не столкнувшись с собратьями, а мы должны придумать для этого алгоритм. Это, если упрощать, и называется многоагентным планированием или MAPF — Multi‑Agent Pathfinding.

Обычно работу принято начинать с ограничения на то, что агенты двигаются только по квадратной сетке или графу. Но для реальных приложений нам, конечно, нужно переходить к непрерывному пространству, и тут кроется одна проблема. Многие из существующих сред и симуляторов либо слишком примитивны, либо настолько физически детальны, что проводить масштабные эксперименты в них слишком долго либо даже невозможно.

В общем, мы в команде «RL агенты» Лаборатории когнитивных систем искусственного интеллекта AIRI сделали свою среду‑бенчмарк под названием CAMAR, где можно обкатывать модели многоагентного обучения с подкреплением в непрерывном пространстве. Мы представили нашу статью про CAMAR на Main Track конференции AAAI‑2026 и на воркшопе WoMAPF’26 (тоже часть AAAI-2026). Заодно я, стажер‑исследователь команды и студент магистратуры ЦКМ МФТИ по имени Артём Пшеницын, решил рассказать о нашей разработке на Хабре.

1b5cf3a3abd8e63b1efe01922a5b64a3.png

Пару слов про MAPF

Итак, есть такая задача — многоагентное планирование. В классическом варианте рассматривают дискретную постановку, когда есть много мобильных роботов, они умеют перемещаться на одном общем графе или сетке. Мы задаем каждому роботу цель, куда ему нужно доехать, а также накладываем требование чтобы агенты не сталкивались, то есть, чтобы не было ситуаций, когда несколько агентов занимают одну и ту же клетку. Теперь вопрос — по какой последовательности клеток должны двигаться эти роботы от своих стартовых позиций при описанных условиях?

Это и есть в общих чертах задача MAPF. Мой коллега по команде уже довольно подробно рассказывал про эту задачу, зачем она нужна, а также про предложенный метод для её решения. Кому интересно узнать «а чего вообще происходит в MAPF» — прочитать можно здесь.

Довольно логичным расширением классики было отказаться от предположения, что роботы двигаются только по клеткам. Вообще, тут сразу стоит сказать, что есть и any‑angle постановки на «клетках», но сегодня мы поговорим немного о другом направлении — полностью непрерывной многоагентной навигации. Предположение, что агенты двигаются по клеткам, лишь задает определенную структуру‑правило того, где может оказаться робот в ближайшем будущем. Нам, вообще говоря, необязательно жить в классическом «клеточном» предположении, ведь и мы, люди, и роботы обычно не передвигаемся в мире по клеткам, так что по‑хорошему нужно учитывать явно кинетику и/или динамику того, как это происходит.

Изначально нам хотелось иметь удобную и, самое главное, быструю среду, в которой можно проводить масштабные RL‑эксперименты с методами для многоагентной навигации с непрерывными действиями. Многие из существующих сред и симуляторов либо дискретные и довольно далеки от реальных роботов, либо уже настолько близки к реальному миру, что становится тяжело и долго запускать большое количество экспериментов. В итоге решили сделать свою среду — сделали и оказалось, что она и хорошо закрывает наши потребности, и занимает любопытную нишу в мире MARL‑фреймворков.​

Да кто такой этот ваш MARL?

Когда стоит задача обучить агентов/роботов тому, чтобы они делали что‑то, что мы хотим, то один из подходов к решению — это RL или обучение с подкреплением. В нашем случае это образует отдельную подобласть — многоагентное обучение с подкреплением (Multi‑Agent Reinforcement Learning, MARL). MARL — это как RL, только для случая, когда одновременно несколько агентов действуют в общей среде, получают наблюдения, выбирают действия и учатся максимизировать некоторую награду (общую или индивидуальную). Это может быть кооперация (все хотят выиграть вместе), соревнование или что‑то посередине по типу движения роботов в общем пространстве, где каждый вроде как и стремится к своей цели, но при этом нельзя врезаться друг в друга. Наша цель — научить уже не одного агента решать задачу, а целую команду, причём часто с десятками или сотнями агентов и больше, действующих одновременно.

Обычно каждая среда представляет собой определенную проблему, которую предлагается решать через взаимодействие агента/агентов со средой. Таких сред существует несколько — SMAC, POGEMA, VMAS, MPE и другие — и мы дополняем этот список средой CAMAR, которая предлагает для решения задачу непрерывного многоагентного планирования. На самом деле мы провели более масштабное сравнение существующих сред, детали есть в нашей статье, здесь же просто покажу таблицу сравнения:

Сравнение различных MARL-сред и симуляторов по целому перечню критериев
Сравнение различных MARL‑сред и симуляторов по целому перечню критериев

Почему JAX

Исторически мы сначала смотрели в сторону VMAS: по духу он близок (непрерывный, агентов больше чем один), но на больших сценариях и особенно при росте числа агентов скорость быстро становится узким местом (сравнение с VMAS по скорости можно найти далее по тексту в соответствующем разделе), а нам хотелось реализовывать именно «массовые» сеттинги. Тогда мы полезли в JAX‑экосистему: где‑то было медленно (например, JaxNav), а где‑то, внезапно, очень быстро даже при масштабировании по агентам (MPE из JaxMARL), и это стало хорошим сигналом, что «MPE‑подобный» путь — реально рабочий. Если очень грубо описывать разницу подходов: VMAS можно воспринимать как «а что, если среду MPE расширить в сторону коллекции разнообразных сценариев с гетерогенными агентами на PyTorch», а CAMAR как «а что, если среду MPE расширить в сторону очень масштабных сценариев и больших лабиринтов на JAX».

Вообще, мы в команде не хотели писать новую среду, поэтому договорились, что, если за 2 недели не будет MVP среды, то мы идем дальше ковырять существующие фреймворки. Как нетрудно догадаться, за 2 недели все получилось. Первые зачатки CAMAR были не самыми простыми: вроде бы и написал код, проверил, что везде статика, но XLA вечно что‑то не нравится, и код не jit‑компилируется. Особенно когда начинаешь маскировать или резать массивы, и только потом узнаешь, что, чтобы взять срез массива по индексам, нужно использовать lax.dynamic_slice.

В итоге итеративно переписывая одни и те же вещи, пробуя разные JAX‑абстракции и функции приходишь от «написал код и молишься, что он будет хотя бы работать на GPU» к «здесь нужно использовать именно эту операцию, чтобы потом на этапе jit‑компиляции умный дядя JAX понял, как объединить эти вычисления с другими в один батч». При этом я бы не назвал себя адептом JAX«а, у меня до сих пор появляются моменты озарения, как управлять кодом, чтобы он был удобный, читаемый и быстрый».

Мам, я хочу писать код, нет, у нас есть Claude Code дома

Лирическое отступление. У читателя мог возникнуть вопрос — дэм, ты что сам пишешь код в 2026 году? Конечно нет, но начинал писать CAMAR я в самом начале 2025, тогда агенты только появлялись, и модели не умели писать код на JAX вообще (я пробовал🥺). Код просто не запускался, а если запускался, то не jit‑компилировался. И если тот же чатгпт за 10 итераций не мог написать хотя бы работающую версию кода (не говоря уже о скорости), то я за 2–3 итерации осознавал разные вещи и все делал. Но спасибо вайбкодингу за то что я смог повысить читаемость где‑то пяти процентов не core‑составляющей JAX кода в проекте, и большое спасибо автокомплиту, благодаря которому мои пальцы не отвалились печатать каждую букву.

Сейчас 2026 год. Если бы я начал вайбкодить CAMAR сейчас, получилось бы быстрее? Наверное да, но для этого также нужно понимать, какая бывает физика в разных симуляторах, знать о разных динамиках роботов, о процедурной генерации, как это все подружить, что из этого нужно потенциальному пользователю и так далее. Все эти детали зашиты в дизайн среды, а о том, как они устроены, я в том числе пишу далее.

Динамика

Как устроено правило, по которому агенты двигаются непрерывно? Вариантов существует много, но конкретно в CAMAR мы встроили два самых распространённых: голономную и Differential Drive динамику и возможность их смешивания. Кроме того, мы также дали возможность пользователям создавать свои виды динамик и всё кастомизировать. Пару слов о встроенных динамиках.

Голономная динамика — это правила движения агента, в рамках которых ограничения зависят только от координат. Традиционный голономный робот мгновенно меняет скорость. Мы же решили пойти чуть дальше и добавить немного реалистичности в эту динамику: сначала задаем действие в виде 2D‑силы \vec{f}_i^a(t), дальше обновляем скорость с учетом демпфирования, клипируем по модулю, а позицию интегрируем простым полуявным Эйлером. На этот же апдейт накладывается сглаженная контактная сила от коллизий с другими агентами и препятствиями \vec{f}_i^c(t) (к ней еще вернемся).

\begin{cases} \vec{v}_i(t+dt) = (1 - \texttt{damping}) \vec{v}_i(t) + \frac{\vec{f}_i^a(t) + \vec{f}_i^c(t)}{\texttt{m}} dt \\ \vec{v}_i(t+dt) := \begin{cases} \vec{v}_i(t+dt), \text{if } \| \vec{v}_i(t+dt) \| < \texttt{max\_speed} \\ \frac{\vec{v}_i(t+dt)}{\| \vec{v}_i(t+dt) \|} \cdot \texttt{max\_speed}, \text{otherwise.} \end{cases} \\ \vec{\text{pos}}_i(t+dt) = \vec{\text{pos}}_i(t) + \vec{v}_i(t+dt) dt \end{cases}

На самом деле, получившаяся динамика — общий случай голономной. Действительно, мы можем, выбрав параметр демпфирования равным единицу, полностью убрать инерцию и положить m=dt. В этом случае силы станут мгновенно менять скорость — как это происходит в чистой голономной динамике (но с учетом коллизий).

Differential Drive динамика — уже более приземленная модель мобильного робота: тут у агента есть позиция на плоскости и угол ориентации, а действие — это 2 числа: линейная и угловая скорости. Мы сначала клипируем эти значения по заданным ограничениям, потом считаем вектор скорости в декартовой системе координат, добавляя здесь вклад от коллизий (о которых, снова, позже). Наконец, позиция сдвигается вдоль этого вектора, а угол обновляется просто по угловой скорости.

\begin{cases} u_i(t) = \text{clip}(u_i^a(t), -\texttt{max\_u}, \texttt{max\_u}) \\ \omega_i(t) = \text{clip}(\omega_i^a(t), -\texttt{max\_w}, \texttt{max\_w}) \\ \vec{v}_i(t) = [u_i(t) \cos(\theta_i(t)); u_i(t) \sin(\theta_i(t)] + \frac{\vec{f}^c_i(t)}{m}dt\\ \vec{\text{pos}}_i(t + dt) = \vec{\text{pos}}_i(t) + \vec{v}_i(t) dt \\ \theta_i(t+dt) = \theta_i(t) + \omega_i(t)dt \end{cases}

Разные динамики можно смешивать — это соответствует случаю, когда в одной среде одни агенты едут по одному правилу, а другие — по‑другому (их ещё называют гетерогенными агентами). Выглядит это как‑то так:

c6f9c4b979903e9721adbb8e82cf1fff.png

Столкновения

Наконец, разберёмся с логикой столкновений и тем, зачем она вообще нужна. Уже в дискретном MAPF возникает классический вопрос: что делать, если два агента одновременно решили встать на одну и ту же клетку — кому её «отдать», кого остановить, кого откатить назад. В непрерывном мире эта проблема никуда не девается, просто меняет форму: агенты могут «залезать» друг в друга, пересекать препятствия и, в целом, вести себя физически некорректно, если явно не прописать, что считается допустимым, а что нет.

Самый удобный случай для проверки коллизий — когда все объекты круглые. Для двух кругов контакт полностью описывается расстоянием между центрами и суммой радиусов, без сложных кривых и многоугольников. В CAMAR мы сознательно приняли решение «округлить» всё: и агенты, и препятствия представлены кругами, чтобы упростить проверку столкновений и сделать ее хорошо векторизуемой.

При этом формулу контактной силы \vec{f}_i^c(t) мы не придумывали. Мы взяли подход из среды MPE, где также всё состоит из кругов, и используется гладкая функция «мягкого» контакта. Идея такая: пока расстояние между центрами больше или равно минимально допустимому (сумме радиусов), контактная сила равна нулю. Как только круги начинают пересекаться, появляется репульсивная сила, которая плавно растёт по мере проникновения одного круга в другой, без жёстких скачков и бесконечных значений. В CAMAR используется как раз эта формула: она задает силу столкновения между агентом и любым объектом, а итоговое воздействие на агента — это равнодействующая всех таких сил от соседей, добавленная к его управляющему действию в уравнениях движения.

А как ещё бывает?

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

Полноценные физические движки в играх и симуляторах решают эту проблему через довольно сложную геометрию контактов: считаются нормали, импульсы, трение, стэки из объектов, которые лежат друг на друге. Нам в CAMAR все это в полном виде не нужно. Цель среды — не максимально точная физика твердого тела, а реалистичное поведение в задачах многоагентной навигации: нужно надёжно запрещать агентам проезжать сквозь друг друга и препятствия, при этом сохранив простую математику и возможность эффективно параллелить расчеты на GPU.

Важно подчеркнуть, что в ряде других фреймворков (например, VMAS) используется более общий стек коллизий, включая рейтрейсинг и поддержку разных типов геометрии, но та же самая «мягкая» контактная функция из MPE служит одним из блоков. В CAMAR мы, наоборот, сознательно ограничились только кругами и только этим типом контактной силы: за счет этого получаем простую, устойчивую и гладкую модель столкновений, идеально подходящую под наши задачи масштабируемой многоагентной навигации.

Хорошо ли жить в мире только из кругов? Для навигации — более чем. Сложные формы препятствий можно аппроксимировать набором маленьких кругов, и симулятор этим активно пользуется: стены, колонны, «пещеры» и лабиринты собираются как плотные облака окружностей. Проблемы начинаются, если пытаться сделать одного агента составным из нескольких кругов: тогда при столкновениях нужно учитывать не только перенос, но и поворот, угловые скорости, моменты, иначе поведение будет слишком искусственным. Для этого пришлось бы возвращаться к полноценной контактной геометрии и более тяжёлым расчётам, то есть жертвовать скоростью (а мы на данный момент этого не хотим).

Всё же можно придумать, как делать агентов из набора кругов и сохранить некоторую реалистичность твердого тела, но пока что это не требуется. Сейчас основной челлендж в CAMAR — коллективное поведение и координация большого числа агентов, а не точный учёт формы корпуса каждого робота. Круги плюс мягкая контактная сила дают достаточно правдоподобный контакт для задач навигации, при этом позволяют сохранять высокую производительность симуляции, ради которой вся архитектура среды и проектировалась.

Карты для планирования

Вторая важная задача — процедурная генерация сценариев. Если хочется, чтобы агенты учились не «зазубривать» одну карту, а генерализоваться, им нужно во время обучения видеть разнообразные конфигурации препятствий, стартов и целей. Вместо того, чтобы руками придумывать каждый отдельный сценарий, гораздо удобнее задать процедурные генераторы карт и на их основе автоматически получать тысячи сценариев.

Самый простой вариант — дискретная сетка random_grid. Берём прямоугольную решетку, случайным образом превращаем некоторую долю клеток в препятствия, а на оставшиеся свободные клетки случайно расставляем агентов и их цели.

А если лабиринт получится несвязным?

Да, в таком подходе неизбежно будут появляться нерешаемые случаи, когда путь от старта к цели просто отсутствует. Это можно частично поправить, если перед расстановкой агентов запускать на сетке поиск в ширину, находить компоненты связности и уже внутри них размещать старты и цели, но такая проверка сильно замедляет генерацию. С другой стороны, решаемость можно в какой‑то степени контролировать гиперпараметром «доля занятых клеток», а небольшая примесь нерешаемых задач во время обучения может сработать, как регуляризация: агенту приходится сталкиваться с «плохими» ситуациями и учиться адекватно себя в них вести. Для тестирования при желании всегда можно использовать более дорогие генераторы, которые гарантируют связность или проверяют достижимость целей.

Это далеко не единственный сценарий, которые есть в CAMAR. Чтобы получить более структурированные и «осмысленные» лабиринты, мы используем генератор labmaze от DeepMind — набор алгоритмов, который строит карту из случайно расположенных прямоугольных комнат, соединенных коридорами, с дополнительными ограничениями на связность и форму итогового лабиринта. Такой сценарий в CAMAR называется labmaze_grid.

Но есть нюанс…

У labmaze есть один нюанс: он реализован на C с Python‑оберткой и не рассчитан на то, чтобы его вызывать внутри JAX‑ового jit‑скомпилированного кода. Переписать такой генератор «вручную» на чистом JAX под статические тензоры — кайфа не несет (навайбкодить можно, а зачем?). Поэтому мы выбрали гибридный подход: сначала оффлайн предгенерируем набор карт labmaze, сохраняем их в память, а во время обучения просто сэмплируем индекс карты и уже поверх неё быстро расставляем агентов и цели на свободных позициях. Разнообразие сценариев достигается за счёт двух уровней случайности: во‑первых, можно заранее нагенерировать довольно большой каталог разных лабиринтов, а во‑вторых, на каждой такой карте случайно переставлять старты и цели. Минус очевиден — эти карты надо держать в памяти, но по сравнению с выигрышем по скорости это не такая уж большая цена.

Мы также сделали, чтобы в CAMAR можно было легко использовать карты из известного MAPF‑бенчмарка MovingAI: можно просто указать их имена, и они автоматически скачаются в локальный .cache, после чего будут использоваться генератором сценариев. Дополнительно мы даём возможность управлять уровнем детализации этих карт: иногда нет смысла включать каждое дерево и камень как отдельный круг‑препятствие, потому что это сильно удорожает симуляцию. Можно слегка «огрубить» карту, уменьшив число объектов, и значительно выиграть в скорости, сохранив при этом общую топологию лабиринта.

Чтобы было удобно подключать свои варианты, в CAMAR есть API batched_string_grid: достаточно передать набор карт в текстовом виде (например, “.” — свободная клетка, “#” — препятствие), а дальше среда сама превратит их во внутренний формат и будет работать с ними так же, как с labmaze. Поверх той же идеи построен и более простой режим string_grid, когда у нас есть одна фиксированная карта, и мы хотим многократно генерировать на ней разные конфигурации агентов и целей.

cfe53874aae5fcd01de1e604950069f1.png

Все перечисленные выше генераторы (random_grid, labmaze_grid, string_grid, batched_string_grid, movingai), по сути, опираются на одну и ту же дискретную структуру: в основе лежит сетка, а уже поверх неё строятся непрерывные траектории агентов. При этом сами агенты в CAMAR двигаются по плоскости непрерывно, так что естественно захотеть ещё и карты с изначально непрерывной природой. Генерировать такие ландшафты — отдельная наука, но мы стартовали с достаточно классического инструмента и сделали генератор пещер caves_cont.

В качестве основы тут используется спектральный шум Perlin Noise, который давно и активно используется в разнообразных играх для генерации пещер, ландшафтов, рек и биомов. В простейшем виде 2D Perlin Noise дает непрерывное скалярное поле значений на плоскости: если визуализировать его в оттенках серого, получаются облака плавно меняющихся яркостей. Мы используем очень прямолинейный трюк, чтобы превратить это в карту препятствий: отсекаем слишком высокие и слишком низкие значения, а оставшуюся «среднюю» полосу интерпретируем как препятствия, в то время как остальные области считаем свободными. В результате появляются структуры, которые визуально напоминают пещеры и коридоры с неровными стенками.

33172c8a8c6028e582b8784d7ee5ae71.png

Управлять такими непрерывными генераторами заметно сложнее, чем сеточными: нужно подбирать частоту шума, пороги отсечки, масштаб, чтобы карты были и интересными, и в разумной доле случаев решаемыми. Мы подобрали набор параметров, при которых большая часть сгенерированных сценариев всё же имеет проходимые пути, но в отдельных случаях тупики и разрывы всё ещё встречаются.​

Для caves_cont, как и для random_grid, пока нет отдельного чекера пост‑генерации, который бы строго гарантировал связность и достижимость всех целей, зато генерация остается достаточно быстрой, чтобы использовать её прямо в цикле обучения. Если кто‑то захочет добавить этот функционал или новые генераторы — мы будем очень рады pull request’ам на гитхабе!

Куда смотрим и что учим

В RL среде ещё нужно задать функцию вознаграждения, которую агентам нужно максимизировать, и функцию наблюдения (для частичной наблюдаемости). Вот функция вознаграждения:

r_i(t) = r_{\text{all\_g}}(t) + r_{\text{on\_g}_i}(t) + r_{\text{collision}_i}(t) + r_{\text{g\_dist}_i}(t),

где

\begin{cases} r_{\text{all\_g}}(t) = + 0.5, \ \text{if } \forall i: \| \vec{x}_i(t) - \vec{x}_{\text{g}_i} \| \leq R_{\text{g}};\\ r_{\text{on\_g}_i}(t) = + 0.5, \ \text{if } \| \vec{x}_i(t) - \vec{x}_{\text{g}_i} \| \leq R_{\text{g}}; \\ r_{\text{collision}_i}(t) = - 1, \ \text{if } \exists j: \| \Delta \vec{x}_{ij}(t) \| < d_{\min}; \\ r_{\text{g\_dist}_i}(t) = + \texttt{shaping}  \left(\| \vec{x}_i(t-dt) - \vec{x}_{\text{g}_i} \| - \| \vec{x}_i(t) - \vec{x}_{\text{g}_i} \|\right) \end{cases}Вознаграждение и метрики: что именно мы учим

Функция вознаграждения должна кодировать ту задачу, которую мы хотим решать. В MARL принято два крайних варианта:

  • общая награда для всей команды;

  • индивидуальные награды для каждого агента.

В базовой версии CAMAR используется второй подход: у каждого агента своя скалярная награда на шаге. В него входят четыре основные составляющие:

  • r_{\text{on\_g}_i}(t)– положительный бонус за нахождение в окрестности своей цели (агент «доехал»);

  • r_{\text{collision}_i}(t)– штраф за столкновения с другими агентами или препятствиями;

  • r_{\text{g\_dist}_i}(t)– shaping‑компонента по изменению расстояния до цели: если агент приблизился — добавляем небольшой плюс, если отдалился — минус;

  • r_{\text{all\_g}}(t)– дополнительный коллективный бонус, когда все агенты достигли своих целей (поощрение глобальной координации).

Отдельно от функции вознаграждения, которая нужна в первую очередь для обучения и вычисления loss'а, в CAMAR считаются стандартные для многоагентной навигации метрики качества:

  • Success Rate (SR) — доля агентов, которые успели добраться до своих целей за отведённое время;

  • Flowtime (FT) — среднее по всем агентам время достижения цели (у недошедших берётся максимальная длина эпизода);

  • Makespan (MS) — максимальное время достижения цели по всем агентам (то есть когда «последний» доехал или когда эпизод закончился);

  • Coordination (CO) — мера того, насколько редко происходят коллизии, нормированная по числу агентов и длине эпизода.

Эти метрики используются в протоколах бенчмаркинга (у нас целых 3 протокола — Easy/Medium/Hard) и агрегируются при помощи стандартных в RL‑статистик (Interquartile Mean с бутстрепными доверительными интервалами), чтобы можно было честно сравнивать алгоритмы не только по «средней награде», но и по тому, насколько хорошо они реально доезжают до целей, насколько быстро и насколько аккуратно взаимодействуют друг с другом.

А тут функция наблюдения:

cf7213ebfee36d6642cbeed4acf24f82.pngНаблюдения: «почти LIDAR», но без рейтрейсинга

В частично обозримых средах для навигации обычно используют либо картиночные наблюдения (локальный «вид сверху»), либо LIDAR‑подобные: агент «видит» окрестность с помощью набора лучей‑дальномеров. В непрерывном мире координаты объектов естественно хранить как векторы в \mathbb{R}^2, а не индексы ячеек, и отсюда вылезают неприятные детали реализации. Чтобы построить изображение для каждого агента, нужно каждый шаг заново растеризовать локальное окружение на сетку, что довольно дорого и плохо скейлится на сотни агентов. LIDAR в лоб тоже не бесплатен: для лучевой модели придётся делать рейтрейсинг от каждого агента по всем лучам, тоже на каждый шаг.

В CAMAR в качестве дефолтного варианта мы пошли по пути «как LIDAR, но без лучей». Вокруг каждого агента задаётся окружность фиксированного радиуса — аналог дальности обзора. Затем для всех объектов (агенты и препятствия) мы смотрим, попадает ли их круг в эту зону, и, если да, считаем вектор проникновения: насколько «глубоко» объект зашёл внутрь радиуса обзора и в каком направлении он находится. Эти векторы нормализуются на радиус окна, так что компоненты попадают в диапазон [0,1], что удобно для нейросетевых моделей. Из всех кандидатов выбирается ограниченное число ближайших объектов (по модулю вектора), и их векторы конкатенируются в единый наблюдаемый вектор агента; плюс добавляется нормализованный вектор направления на свою цель. В итоге получается компактное, плавное по входам и хорошо обобщающее наблюдение, которое ведёт себя похоже на «лидарные» данные, но не требует ни растеризации, ни рейтрейсинга.​

Скорость

Теперь, когда понятно, какая крутая гибкая и кастомизируемая среда CAMAR, можно перейти к одному из ключевых параметров любой RL‑среды — скорости симуляции. В CAMAR мы измеряем, сколько шагов в секунду удаётся сделать (Steps per Second, SPS) в зависимости от трёх факторов: числа агентов, числа препятствий и числа параллельно запущенных сред. Для честного сравнения мы взяли фреймворк VMAS как наиболее похожий по духу (непрерывная физика, несколько агентов) и реализовали в нем сценарий, максимально близкий к одной из наших карт random_grid.

Вот, что показало сравнение:

f750565494992510c0dcb6c02af1d1af.png

Eсли смотреть на зависимость SPS от числа параллельных сред при фиксированном количестве агентов и препятствий, CAMAR довольно быстро выходит на плато порядка 50 000 шагов в секунду уже в районе нескольких сотен‑тысяч сред. В тех же условиях VMAS остаётся примерно на уровне ≈2700 SPS, то есть мы работаем быстрее почти в 20 раз на типичных конфигурациях. Формально, при линейном росте SPS в VMAS можно было бы догнаться до 50 000 SPS, но для этого потребовались бы десятки тысяч окружений, что в реальных обучающих пайплайнах почти не встречается. На практике это означает, что в CAMAR можно либо сильно ускорить обучение при фиксированном числе агентов, либо, что даже интереснее, учить стратегии с заметно большим количеством агентов за то же самое время.

В защиту VMAS

Важно при этом не делать неверный вывод, что «VMAS больше не нужен». У VMAS другая ниша: это гибкий фреймворк для широкого класса многоагентных задач, где число агентов невелико, но они могут быть сильно разнородными и решать самые разные задачи, далеко не всегда навигационные. CAMAR же сознательно сфокусирован на континуальной навигации и планировании, использует круговые объекты и специализированные генераторы карт ради максимальной производительности именно в этой подзадаче. Поддержка гетерогенных агентов у нас тоже есть, но дизайн среды заточен под «массовые» сценарии, где счёт идёт на десятки и сотни агентов.

Ну и, конечно, мы проверили CAMAR в более жестких условиях, чтобы понять, где примерно потолок производительности и докуда в рамках ресёрча мы вообще можем крутиться. При малом числе агентов (32, не так уж и много), но большом числе препятствий (до 10k объектов) среда всё равно держится на скоростях от 15k до 100k SPS; в сценариях с сотнями агентов SPS, ожидаемо, падает, но остается на уровне тысяч шагов в секунду. Ну и 1.4k SPS при 800 агентах — это всё равно, что в секунду получать 1.1M наблюдений, которые нужно кормить в модель. Так что, это всё еще очень большой поток данных, который среда может производить.

d17043a7b269e1ed7a2c419cf1379204.png

Эти результаты подтверждают основной вклад нашей работы: целью CAMAR было получить возможность проводить много быстрых экспериментов по многоагентной навигации и по многоагентному планированию с возможностью кастомизировать карты, динамики, чтобы можно было тестировать обучаемые алгоритмы в больших и насыщенных препятствиями сценах, где важны и число агентов, и богатство карты и так далее, и тому подобное — подробнее про это всё можно почитать у нас в статье и/или на гитхабе.

А я думала ̶с̶о̶в̶а̶ будут алгоритмы

Столько много буков я написал про то, что мы сделали среду, чтобы можно было взрастить разные алгоритмы, но может быть задача уже легко решается существующими алгоритмами? Ну, мы никогда так не думали, и CAMAR помог нам это доказать. Помимо собственно создания симулятора мы продемонстрировали, что среда готова к «боевому» использованию: мы погоняли целый зоопарк базовых методов. Получилось 6 RL‑only алгоритмов, 2 классических и 6 гибридов «планирование + RL» (по одному гибриду для каждого RL‑метода):

5f84709c06dbde785937d0c4a9777431.pngА конкретнее?
  1. Среди обучаемых методов мы брали многоагентные варианты PPO, SAC и DDPG: независимые (IPPO, IDDPG, ISAC), где для каждого агента своя критик‑модель и обучение идет целиком децентрализованно, и с централизованным критиком (MAPPO, MADDPG, MASAC), то есть где один общий критик получает на вход конкатенацию наблюдений всех агентов.

  2. В качестве «классики» использовали RRT+PD и RRT*+PD: для каждого агента на карте строится путь методом RRT или RRT* (без учёта других агентов, только статические препятствия), а затем по этому пути его ведёт простой PD‑регулятор. Такие агенты вообще «не видят» друг друга, но, что любопытно, даже эти очень простые методы дают ненулевую долю успеха.

  3. Гибридный класс — это те же MARL‑алгоритмы (IPPO, MAPPO, IDDPG, MADDPG, ISAC, MASAC), но с добавленной информацией от RRT*: в начале эпизода для каждого агента заранее строится дерево RRT* со стоимостями путей до целей (в star‑версии алгоритма мы также имеем доступ к эвристической оценке cost‑to‑go), и ближайшие точки полученного дерева (вместе с костами) подаем агентам вместе с дефолтным наблюдением простой конкатенаций. Идея в том, что вместо «слепого» PD‑регулятора, который просто цепляется за путь, теперь есть небольшая нейросеть, которая имеет всё необходимое, чтобы объезжать соседей и пользоваться планом от классического алгоритма как подсказкой направления, куда вообще надо ехать.

Если все эти аббревиатуры вы видите впервые и вам, то можно посмотреть например тут про RL , тут тоже про RL, а тут про RRT.

Что показали тесты?

Если коротко по главным выводам, то на относительно простых random_grid лучшим из MARL‑only методов оказался MAPPO (что довольно ожидаемо) — хороший success rate и мало столкновений. Гибрид RRT*+MAPPO даёт ещё более эффективные траектории по времени так же, как RRT*+IPPO улучшает базовый IPPO. Классический RRT*+PD без всякого обучения хорошо работает (так как хорошо справляется с глобальным планированием), но страдает по координации, поскольку вообще и не учитывает других агентов.

Off‑policy‑методы ведут себя не очень: добавление RRT* немного помогает ISAC и IDDPG, но на удивление ухудшает MASAC и MADDPG. Чтобы разобраться почему результаты становятся хуже мы провели еще серию экспериментов — можно почитать об этом в аппендиксе статьи. В более сложных labmaze_grid успех всех MARL‑бейзлайнов заметно падает (по идее, на этих картах нужно чуть больше уметь в глобальное планирование, а обычный MARL умеет больше в локальную навигацию), и там уже RRT*+PD оказывается сильнейшим (так как в текущих сценариях агентов всего лишь 8 или 32), что подчёркивает важность классического планирования. Ну, можно подытожить и сказать, что в целом MARL «есть куда расти».

Итог

Если подытоживать, CAMAR — это опенсорсная, специализированная среда для многоагентного обучения с подкреплением с непрерывными действиями, сфокусированная на задачах многоагентной навигации и планирования. В отличие от дискретных бенчмарков вроде POGEMA, здесь агенты двигаются в непрерывном мире, подчиняются разным динамикам, учитывают размеры, контактные силы и частичную обозреваемость, а карты задаются как процедурно сгенерированные лабиринты и пещеры, собранные из окружностей.

Мы хорошо постарались: подумали о том, как совместить кастомизацию на уровне карт, кастомизацию на уровне динамик, как всё это подружить вместе в JAX, и чтобы карты генерировались быстро, и чтобы наблюдения считались быстро, и чтобы симуляция бежала быстро. Показали, что CAMAR уже можно использовать для RL, можно сравниваться с классикой, можно легко дружить обучение с классикой, делать всякие разные эксперименты за адекватное время, масштабироваться по количеству агентов и ещё всякое.

Самое главное, чтобы это великолепие стало возможным, не выходя из дома одной среды — всё происходит в одном месте и позволяет честно сравнивать много чего. Лично я надеюсь, что это поможет сдвинуть классический MAPF к более реалистичным сеттингам, где уже могут контрибьютить и любители for/while, и любители fit/predict, и вообще может заинтересовать и робототехников, и RL‑щиков.

Чуть не забыл, чтобы вы не забыли: сюда на гитхабе справа сверху нужно нажать на звездочку, и тут сама статья, принятая и показанная на AAAI, призываю и читать, и цитировать. Кстати говоря, еще рекомендую посмотреть мощный репортаж нашего директора Александра Панова про то, как прошла сама эта конфа — Хабр.

Спасибо, всем, кто дочитал до сюда! Готов обсудить прочитанное в комментах.

Источник

Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу [email protected] для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.