Найти в Дзене
Nuances of programming

Автоматизация Doom с глубоким Q-обучением: реализация в Tensorflow

Оглавление

Источник: Nuances of Programming

Введение

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

Подходы ОО (в отличие от своих “офлайновых” братьев) позволяют по нарастающей обновлять значения состояний и поведения внутри, так называемых, пространственных эпизодов. Еще с ними удобно наблюдать за растущим постоянно уровнем производительности.

Эволюция в УВР (учёт временной разницы) привела к возрастающим оценкам и улучшению значений состояний и поведения. О Q-обучении узнали как о базе для подходов сферы обучения с подкреплением. Оно было нужно для симуляций игровых пространств, например, на таких платформах-“спортзалах”, как OpenAI Gym. Но в этой статье не будет обсуждения теоретических аспектов.

Способы ОО подходят высокодинамичным окружениям, где значения состояний и поведения постоянно обновляются во времени и в наборах оценок из-за быстрой ответной реакции внутри эпизодов (в том числе УВР). Возможно, самое важное то, что УВР — это основа Q-обучения, более продвинутого алгоритма для тренировки агентов, который имеет дело с игровыми окружениями, которые можно увидеть в OpenAI Atari Gym.

В этом материале изучим, как можно использовать Q-обучение для агента, который играет в классический шутер от первого лица вроде Doom. Будем делать это с помощью открытой библиотеки-враппера Vizdoomgym. Мы настроим вашего первого агента, а также заложим базу для дальнейшней работы.

-2

Выходя за пределы УВР: SARSA и Q-обучение

В УВР поведение агента циклично в пространстве в последовательности состояний (State), действий (Action) и наград (Reward).

В процессе УВР мы можем обновить значение предыдущего состояния сразу же, как только достигаем следующей стадии. Дальше мы расширяем объем своей модели, чтобы в нее входили значения состояния-действия, согласно подходу SARSA (“состояние-действие-награда-состояние-действие”), регламентированному алгоритму управления УВР, который нужен для оценки значений поведения.

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

Давайте сравним уравнения обновлений состояния-действия и состояния-значения УВР:

-3

Q-обучение отличается от SARSA принудительным выбором действия с текущим максимальным значением в процессе обновления. Так же происходит и в похожем подходе, который наблюдается в уравнениях оптимальности Беллмана.

Изучим алгоритм SANSA и Q-обучение на фоне метода Беллмана и его уравнений оптимальности:

-4

Любопытно, как обеспечивается полное исследование пространства состояний-действий, из-за чего нужно постоянно выбирать действия (с максимальным из существующих значений действий) для состояния. Теоретически мы можем игнорировать оптимальные действия, просто не проводя их оценку в первую очередь.

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

Теория закончилась, переходим к реализации.

Реализация

Наша реализация в Colaboratory от Google написана на Python с помощью Tensorflow. Ее можно найти на GradientCrescent Github.

Реализация с таким подходом достаточно непростая, поэтому давайте обобщим порядок необходимых действий:

1. Мы определяем нашу нейросеть глубокого Q-обучения. Это РНС, которая делает скриншоты во время игры и выводит вероятности для каждого из действий или Q-значений в игровом пространстве Ms-Pacman. Чтобы получить тензор вероятностей, нам не нужно добавлять никакой функции активации в финальный слой.

2. Так как для Q-обучения мы должны знать и текущие, и следующие состояния, нам стоит начать с генерации данных. Мы “скармливаем” предварительно обработанные входные изображения игровому пространству, предоставляем исходные состояния s нашей нейронной сети и получаем исходную вероятность распределения действий или Q-значений. До тренировки эти значения будут появляться случайно и неоптимально.

3. С тензором вероятностей мы готовы выбрать действие с текущей высшей вероятностью при помощи функции argmax() и использовать ее для создания правил эпсилон-жадного алгоритма.

4. Используя наши правила мы выбираем действие a, и оцениваем наше решение в окружении gym — чтобы получить информацию по новому состоянию s’ , награде r и информацию о том, закончился ли эпизод.

5. Мы сохраняем это сочетание информации в буфер в формате списка <s,a,r,s’,d> и повторяем шаги 2–4 для пресета с числами в промежутке времени, чтобы создать достаточно большой буферный датасет.

6. Как будет закончен 5-й шаг, двигаемся к генерации целевых y-значений, R’ и A’. Они нужны для расчета ошибки. Предыдущее — это просто уменьшенное значение R. Амы получаем A`, передавая S` в сеть.

7. У нас есть все компоненты пространства и мы готовы рассчитать ошибку для тренировки сети.

8. По окончании тренировки мы оцениваем производительность нашего агента в новом игровом эпизоде и записываем её.

Приступим-с. Вместе с Tensorflow 2 и окружениями из Colaboratory мы конвертировали код в совместимый с TF2 формат. Нам помог новый пакет compat.

Помните, что этот код не является нативным для TF2.

Импортируем все пакеты, без которых не обойтись, в том числе окружения OpenAI и Vizdoomgym, а также Tensorflow:

Определяем функцию предварительной обработки для нормализации и изменения наблюдений из нашего окружения gym, конвертируем их в одномерные тензоры:

Инициализируем окружение gym. Будем пользоваться сценарием получения здоровья Vizdoomgym. Его цель — собрать максимально возможное количество коробок здоровья, чтобы остаться в живых, пока он перемещается в квадратной комнате с опасной кислотой на полу.

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

Сырые наблюдения в качестве исходных данных
Сырые наблюдения в качестве исходных данных

Воспользуемся этим шансом для сравнения нашего оригинала и предварительно обработанных вводных изображений:

Вводные данные в виде предварительно обработанного изображения
Вводные данные в виде предварительно обработанного изображения

Теперь нам понадобится компоновка исходного фрейма в стек и композиция фрейма в конвейер предварительной обработки. Эти две техники появились в 2015 году благодаря Deepmind. Они нужны, чтобы давать временные и поведенческие ориентиры для вводных данных.

Применяем компоновку фрейма так: берём два исходных фрейма и возвращаем сумму поэлементных максимумов maxframe от них двух. Затем эти скомпонованные фреймы сохраняются в двухсторонней очереди или стеке, который автоматически убирает устаревшие записи с появлением новых.

Давайте определим нашу модель глубокой Q-нейросети. По сути это трёхслойная свёрточная нейросеть, которая получает на вход предварительно обработанные наблюдения вместе со сгенерированным плоским выводом, скормленным полносвязному слою, а в результате генерирует вероятность каждого действия в игровом пространстве.

Заметьте, что здесь нет слоев активации, иначе на выходе бы было бы бинарное распределение.

Теперь давайте определим гиперпараметры нашей модели и тренировочного процесса. Обратите внимание, что X_shape (None, 60, 80, 4) сейчас находится в расчете нашего стека с фреймами.

Вспомните, что Q-обучение требует, чтобы мы выбирали действия с самыми высокими значениями. Чтобы убедиться в том, что мы всё ещё смотрим каждую отдельную возможную комбинацию состояний-действий, мы сделаем так, чтобы наш агент следовал многослойным правилам эпсилон-жадной стратегии с долей обучения в 5%

Вспоминаем из уравнений выше, что обновление функции для Q-обучения требуют следующего:

  • текущее состояние s;
  • текущее действие a;
  • награда за текущее действие r;
  • следующее состояние s’;
  • следующее действие a’.

Чтобы поддерживать эти параметры на значимом уровне, нам нужно оценить свои текущие правила для набора параметров и сохранить все переменные в буфер. А уже оттуда во время тренировки мы будем визуализировать данные небольшими партиями.

Давайте теперь создадим буфер с простой функцией сэмплирования:

Дальше копируем параметры веса нашей исходной сети в итоговую сеть. Подход с двумя сетями позволяет генерировать данные во время тренировки при помощи существующих правил в процессе, в то время как параметры оптимизируются для итерации с новыми правилами, уменьшая колебания ошибки.

В конце мы также определим ошибку. Это всего-навсего квадратная разница целевого (с наивысшим значением действия) и предсказанного действий. Мы будем использовать оптимизатор ADAM (адаптивная оценка момента), чтобы минимизировать ошибку в процессе тренировки:

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

  • На каждом этапе мы передаём стек изображений в виде вводных данных внутрь нашей сети, чтобы генерировать вероятностное распределение доступных действий. Распределения генерируются до применения правил эпсилон-жадного к следующему действию.
  • Дальше мы вводим всё это в сеть и получаем информацию о следующем состоянии и сопутствующих наградах, сохраняя её в буфер. Обновляем стек и повторяем процесс столько раз, сколько шагов предопределено.
  • Когда буфер станет достаточно большим, мы отдаём следующие состояния в нашу сеть, чтобы получить следующее действие, и рассчитываем следующую награду, уменьшая текущую.
  • Мы генерируем итоговые Y-значения в процессе работы функции обновления Q-обучения и тренируем сеть.
  • Чтобы вывести улучшенные значения состояния-поведения для следующего правила, мы обновляем весовые параметры сети, уменьшая ошибки тренировки.

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

-7

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

Наконец, мы можем взять наш список фреймов и “скормить” их библиотеке skvideo.io  —  сгенерируем выходную видео-последовательность для изучения:

Посмотрим на нашего агента в действии!

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

Такая вот упаковка имплементации Q-обучения.

Надеюсь, вам понравилось читать и вы захотите погрузиться в теоретические аспекты применения ИИ.

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи Adrian Yijie Xu: Learning: An Implementation in Tensorflow.