Deep Reinforcement Learning: как научить пауков ходить |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2020-01-07 14:20 Сегодня я расскажу, как я применил алгоритмы глубинного обучения с подкреплением для управления роботом. Вкратце, поведаю о том, как создать «чёрный ящик с нейросетями», который на входе принимает архитектуру робота, а на выходе выдаёт алгоритм, способный им управлять. Основой решения является алгоритм Advantage Actor Critic (A2C) с оценкой Advantage через Generalized Advantage Estimation (GAE). Под катом математика, реализация на TensorFlow и множество демок того, к каким способам ходьбы сошлись алгоритмы. Содержание: — Задача — Почему Reinforcement Learning? — Постановка задачи Reinforcement Learning — Policy gradient — Diagonal Gaussian Policies — Уменьшаем variance путём добавления критика — Подводные камни — Заключение Задача В этой статье будем учить робота ходить в симуляции MuJoCo. Пропустим описание шага с созданием модели робота и Python интерфейса к среде, т.к. там ничего интересного нет. Чтобы разобраться, достаточно посмотреть на демки в самой MuJoCo и исходники MuJoCo-сред в Gym OpenAI. На входе у агента будет множество чисел из MuJoCo: относительные позиции, углы вращения, скорости, ускорения частей тела робота, и т.д. В сумме порядка ~800 фичей. Используем Deep Learning подход и не будем разбираться, что они на самом деле означают. Главное, что в этом наборе чисел будет достаточно информации, чтобы агент мог понять, что с ним происходит. На выходе будем ожидать 18 чисел — количество степеней свободы робота, которые означают углы поворота шарниров, на которых закреплены конечности. И наконец, целью агента будет максимизировать суммарную награду (reward) за эпизод. Будем завершать эпизод, если робот упал или если прошло 3000 шагов (15 секунд). Каждый шаг будем награждать агента по следующей формуле: Т.е. целью агента будет увеличивать свою координату и не падать до конца эпизода. Итак, задача поставлена: найти функцию , для которой награда за эпизод будет наибольшей. Звучит не очень, правда? :) Посмотрим, как с такой задачей справится Deep Reinforcement Learning. Почему Reinforcement Learning? Современные подходы к решению задачи движения ходячих роботов состоят из классических практик робототехники из разделов optimal control и trajectory optimization: LQR, QP, выпуклая оптимизация. Подробнее: публикация коллектива Boston Dynamics о роботе Atlas. Эти техники являются своего рода «хардкодингом», поскольку требуют внесения многих деталей задачи напрямую в управляющий алгоритм. В них нет обучающихся систем — оптимизация происходит «на месте». С другой стороны, Reinforcement Learning (далее RL) не требует внесения гипотез в алгоритм, делая решение задачи более общим и масштабируемым. Постановка задачи Reinforcement Learning В задаче RL мы рассматриваем взаимодействие агента и среды как последовательность пар (state, reward) и переходы между ними — action. Определим терминологию:
Задача агента — максимизировать expected return: Теперь мы можем сформулировать задачу RL, найти: где — это оптимальная policy. Подробнее в материале от OpenAI: OpenAI Spinning Up. Policy gradient Примечательно, что строгая постановка задачи RL как задачи оптимизации даёт нам возможность использовать уже известные методы оптимизации, например градиентный спуск. Только представьте, как было бы классно, если бы могли брать градиент expected return по параметрам модели: . В таком случае, правилом обновления весов было бы просто: Именно в этом и заключается идея всех методов policy gradient. Строгий вывод этого градиента является несколько хардкорным. Не будем писать его здесь, а оставим ссылку на замечательный материал от OpenAI. Градиент выглядит вот так: Таким образом loss нашей модели будет таким: Напомним, что , а — это выход нашей модели в тот момент, когда она была в . Минус появился за счёт того, что мы хотим максимизировать . При обучении мы будем считать градиент на батчах и складывать их с целью уменьшить variance(шум данных за счёт стохастичности среды). Это уже рабочий алгоритм, называющийся REINFORCE. И он умеет находить решения для некоторых простых сред. Например, «CartPole-v1». Рассмотрим код агента:
У нас есть небольшой перцептрон такой архитектуры: (observation_space, 10, action_space)[для CartPole это (4, 10, 2)]. tf.multinomial позволяет выбрать действие взвешенно случайно. Для получения действия нужно вызвать:
И вот так будем его обучать:
Генератор батчей запускает агента в среде и копит данные для обучения. Элементами батча являются туплы такого вида: . Написать хороший генератор — отдельная задача, где основная сложность — относительная дороговизна вызова sess.run() по сравнению с одним шагом симуляции (даже MuJoCo). Для ускорения работы можно эксплуатировать тот факт, что нейронные сети запускаются на батчах, и использовать много параллельных сред. Даже последовательный запуск их в одном потоке даст значительное ускорение по сравнению с одной средой. Код генератора с использованием DummyVecEnv из OpenAI baselines
Полученный агент умеет играть в средах с конечным пространством действий. Такой формат не подходит для нашей задачи. Агент, управляющий роботом, должен выдавать вектор из , где — количество степеней свобод. (либо можно разбить пространство действий на промежутки и получить задачу с дискретным выходом) Diagonal Gaussian Policies Суть подхода Diagonal Gaussian Policies в том, чтобы модель выдавала параметры n-мерного нормального распределения, а именно — мат. ожидание и — стандартное отклонение. Как только агенту нужно будет сделать действие, будем спрашивать эти параметры у модели и брать случайную величину из этого распределения. Таким образом, мы сделали на выходе агента и сделали его стохастическим. Самое важное, что зафиксировав класс распределения на выходе, мы можем посчитать и, следовательно, policy gradient. Примечание: можно зафиксировать как гиперпараметр, тем самым уменьшив размерность выхода. Практика показывает, что это не наносит особого вреда, а, напротив, стабилизирует обучение. Подробнее о стохастических policy. Код агента:
Часть с обучением ничем не отличается. Теперь мы, наконец, можем посмотреть, как REINFORCE справится с нашей задачей. Здесь и далее цель агента — продвигаться вправо.
Медленно, но верно ползёт к своей цели. Reward-to-go Заметим, что в нашем градиенте есть лишние члены. А именно для каждого шага при взвешивании градиента логарифма мы используем суммарную награду за всю траекторию. Таким образом, оценивая действия агента его достижениями из прошлого. Звучит неправильно, не так ли? Поэтому вот это станет вот этим Найдите 10 отличий :) В то время как присутствие этих членов ничего не портит математически, это сильно зашумляет нам данные. Теперь при обучении агент будет обращать внимание только на те награды, которые получил после конкретного действия. Вследствие этого улучшения средний reward вырос. Один из полученных агентов научился использовать передние конечности для достижения своей цели:
Уменьшаем variance путём добавления критика Сутью дальнейших улучшений является уменьшение шума (variance), появляющегося из-за стохастичности переходов между состояниями среды. В этом нам поможет добавление модели, которая будет предсказывать среднюю сумму наград, полученных агентом, начиная с состояния до конца траектории, т.е. Value-функцию. Value-функция показывает expected return, если наша policy начнёт игру из конкретного состояния. То же самое с Q-функцией, только ещё фиксируем самое первое действие. Добавляем критика Так выглядит градиент при использовании reward-to-go: Теперь коэффициентом при градиенте логарифма является ни что иное, как сэмпл Value-функции. Мы взвешиваем градиент логарифма одним сэмплом из какой-то конкретной траектории, что не есть хорошо. Мы можем аппроксимировать Value-функцию какой-нибудь моделью, например нейронной сетью, и спрашивать необходимое значение у неё, тем самым ещё уменьшив variance. Назовём эту модель критиком (Critic) и будем учить её параллельно с policy. Таким образом, формулу градиента можно записать как: Мы уменьшили variance, но в то же время мы внесли bias в наш алгоритм, так как нейронные сети могут допускать ошибки при аппроксимации. Но компромисс в данной ситуации оказывается хорошим. Такие ситуации в машинном обучении называют bias-variance tradeoff. Критик будет учить Value-функцию регрессией по сэмплам reward-to-go, собранным в среде. В качестве функции ошибки возьмём MSE. Т.е. loss выглядит вот так: Код критика:
Цикл обучения теперь выглядит так:
Теперь батчи содержат ещё одно значение, value, посчитанное критиком в генераторе. В цикле ничто не ограничивает нас от обучения критика до сходимости, поэтому делаем несколько шагов градиентного спуска, тем самым улучшая аппроксимацию Value-функции и уменьшая bias. Однако такой подход требует большого размера батча, чтобы избежать переобучения. Аналогичное утверждение про обучение policy не верно. Она должна иметь моментальную обратную связь от среды для обучения, иначе мы можем оказаться в ситуации, когда мы штрафуем policy за действия, которые она бы уже совершать не стала. Алгоритмы с таким свойством называются on-policy. Baselines in Policy Gradients Можно показать, что в градиенте на место Value-функции допустимо ставить широкий класс других полезных функций от . Такие функции называются baselines. (Вывод этого факта) В качестве бейзлайнов хорошо себя показывают следующие функции: Источник: GAE paper. Разные бейзлайны дают разные результаты в зависимости от задачи. Наибольший профит как правило даёт Advantage-функция и её приближения. За этим даже есть небольшая интуиция. Когда мы используем Advantage, мы штрафуем агента пропорционально тому, насколько лучше или хуже среднего сам агент считает совершённое им действие. И чем лучше агент играет в среде, тем выше становятся его стандарты. Идеальный агент будет хорошо играть и оценивать все свои действия как имеющие Advantage равный 0 и, следовательно, иметь градиент равный 0. Оценка Advantage через Value-функцию Напомним определение Advantage: Не понятно, как учить такую функцию явно. На помощь придёт трюк, который сведёт подсчёт Advantage-функции к подсчёту Value-функции. Определим — Temporal Difference residual (TD-residual). Не сложно вывести, что такая функция аппроксимирует Advantage: Такое концептуально сложное изменение провоцирует не такое большое изменение в коде. Теперь вместо оценки Value-функции критиком будем подавать на обучение policy оценку Advantage. Полученный алгоритм называется Advantage Actor-Critic.
У полученных агентов можно наблюдать уверенную походку и синхронное использование конечностей:
Generalized Advantage Estimation Относительно недавно вышедшая статья (2018) "High-dimensional continuous control using generalized advantage estamation" предлагает ещё более эффективную оценку Advantage через Value-функцию. Она уменьшает variance ещё сильнее: где:
Интерпретацию можно найти в самой публикации. Реализация:
При использовании небольшого размера батча алгоритм сходился к некоторым локальным оптимумам. Здесь агент использует одну лапу как трость, а остальными отталкивается:
Здесь же агент не пришёл к использованию прыжков, а просто быстро перебирает конечностями. А также видно, как он ведёт себя, если запнётся — развернётся и продолжит бег:
Лучший агент, он же в самом начале статьи. Передвижение устойчивыми прыжками, во время которых от поверхности отрываются все конечности. Развитое умение балансировать позволяет агенту на полной скорости корректировать траекторию, если была допущена ошибка:
Подводные камни Машинное обучение славится размерностью пространства ошибок, которые можно совершить, и получить полностью не работающий алгоритм. Но RL поднимает проблему на совершенно новый уровень. Здесь описаны некоторые трудности, с которыми пришлось столкнулся при разработке.
Больше нюансов в Deep RL можно узнать из этой статьи: Deep Reinforcement Learning Doesn't Work Yet. Заключение Получившийся алгоритм убедительно решает поставленную задачу. Найдена функция , проворно и уверенно управляющая роботом. Логическим продолжением будет изучение близких родственников A2C, алгоритмов PPO и TRPO. Они улучшают sample efficiency, т.е. время сходимости алгоритма, и умеют решать более сложные задачи. Именно PPO + Automatic Domain Randomization недавно собрал Кубик Рубика на роботе. Здесь можно найти код из статьи: репозиторий. Надеюсь, вам понравилась статья и вы вдохновились тем, что уже сегодня умеет Deep Reinforcement Learning. Спасибо за внимание! Полезные ссылки:
Спасибо pinkotter за помощь с проектом. Источник: habr.com Комментарии: |
|