Прочитав заголовок сообщения, вы, вероятно, спросите себя: WTF?
Эта статья посвящена одному: реализации алгоритма глубокого детерминированного градиента политики (DDPG). Что отличает его от других сообщений и руководств в блогах, так это то, как мы собираемся подойти к реализации.

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

Большинство руководств по RL сосредоточены исключительно на алгоритме - и они великолепны! Они лаконичны, содержат всего один или два файла и несколько строк кода. Я хотел бы быть менее кратким в этом посте. Алгоритм будет «чувствовать» второстепенным. Тем не менее, я надеюсь, что у вас появится хорошая интуиция в отношении DDPG, когда вы закончите читать. Заранее извиняюсь, это будет длинный пост.

Если в какой-то момент фрагменты кода перестают иметь смысл, вы можете вернуться к полному исходному коду на Github.

Обучение с подкреплением

Я предполагаю, что у нас есть лишь немного предварительных знаний о RL. Если это не так, есть поистине феноменальное руководство от @awjuliani, которое должно дать вам достаточно информации.

Алгоритм глубокого детерминированного градиента политики (DDPG)

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

Как я упоминал ранее, наша цель не обязательно заключается в реализации DDPG. Реализация алгоритма послужит платформой для демонстрации того, что я считаю передовой практикой разработки программного обеспечения при разработке обслуживаемой инфраструктуры. Учебное пособие, более ориентированное на основной алгоритм DDPG, можно найти в этой замечательной статье Патрика Эмами.

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

Мы собираемся держать все на высоком уровне. Не нужно говорить о аппроксиматорах функций, нейронных сетях, буферах воспроизведения, TensorFlow и т. Д. Мы будем говорить о «thingys» (множественное число от thing. )

Среда
Элемент, который позволяет использовать действие для перехода из текущего состояния в следующее состояние.

Актер
Вещь, имеющая состояние, предсказывает наилучшее действие, которое нужно предпринять.

Критик
Вещь, для которой задано состояние и предсказанное действие, возвращает, насколько «хорошо» это действие.

Алгоритм («Агент»)
1) среда сообщает агенту его текущее состояние. 2) Агент спрашивает субъекта, какое действие он должен предпринять с учетом текущего состояния. 3) Агент использует это действие для взаимодействия с средой. Это взаимодействие дает вознаграждение, следующее состояние и определение того, является ли следующее состояние конечным. 4) Агент использует вознаграждение для обучения критика. 5) Обученный критик может сказать действующему лицу, как выбрать еще лучшие действия в будущем. Это делается путем анализа того, как значение «доброты», возвращаемое критиком, изменяется, когда мы возимся (увеличиваем / уменьшаем) с действием ( градиент критика). 6) Asse (асс)

Вы не поверите, но у нас достаточно информации для реализации «труб» DDPG! Итак, давайте начнем с реализации агента. Если вы собираетесь писать код, вы можете настроить необходимые зависимости, запустив: pip install gym pytest mock в своем virtualenv.

Агент делает именно то, что мы описали в разделе «Алгоритм» выше. Чтобы упростить понимание, комментарии в коде - это именно то, что я написал в этом разделе.

Как вы, возможно, уже заметили, реализация указанного выше агента еще не завершена. В следующих нескольких разделах мы собираемся внести изменения, необходимые для создания работающего агента DDGP.

** Мы достигли того, о чем я действительно хочу поговорить в этом посте! **

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

Потягивая кофе, вы реализуете алгоритм RL, следя за чужой общедоступной работой Github. Вы хотите действительно учиться, чтобы избегать копирования и вставки. Как только вы попытаетесь запустить код в первый раз, вы столкнетесь с ошибками синтаксиса / интерпретатора / компиляции. Их очень легко исправить - просто следуйте указаниям в сообщении об ошибке. После 100-й попытки запуска ваш код запускается! Теперь вы терпеливо ждете 5 минут, 10 минут, 15 минут, чтобы ваша модель начала приносить разумные вознаграждения, но этого не происходит. Теперь вы можете сделать одно из трех: 1) плакать - я пробовал, и это не ускоряет сходимость вашей модели. 2) Клонируйте эталонное репо, запустите его, посмотрите, как модель успешно сойдется, а затем вернитесь к слезам. 3) Начните сначала, но на этот раз гораздо медленнее и используйте разделенный экран, ваш код слева и справочный код справа.

Я считаю, что мы можем уменьшить частоту возникновения описанной выше ситуации, написав тесты вместе с нашей реализацией модели.

Пока что мы написали базовый (неполный) агент. Давайте напишем несколько тестов, чтобы убедиться, что наш код ведет себя правильно, когда мы вносим изменения в агент.

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

Эпизоды
запуск нашего агента взаимодействует со средой только один раз. Агенты RL должны взаимодействовать с окружающей средой тысячи / миллионы раз. Эти взаимодействия происходят в эпизодах. Эпизоды имеют максимальную длину: сколько раз агент может взаимодействовать с окружающей средой. Одного эпизода (много взаимодействий) тоже недостаточно, нужно много эпизодов. В приведенном ниже коде показано, как мы модифицируем нашего текущего агента (и тест) для поддержки этого эпизодического поведения.

Добавьте следующий тест в agent_test.py

Если вы запустите agent_test.py, это не удастся. Нам еще предстоит реализовать поддержку аргументов episodes и episode_max_length (см. Код ниже).

Обратите внимание, что в приведенном ниже коде мы переименовали метод run в _run_helper и создали новый run метод, который вызывает _run_helper.

Если вы повторно запустите agent_test.py, все должно пройти успешно.

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

Вызов _run_helper теперь возвращается, если новое состояние является терминальным. Если это так, мы останавливаем текущий эпизод и переходим к следующему.

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

Целевой субъект и целевой критик
До сих пор мы использовали вознаграждение, предоставляемое окружающей средой, для непосредственного обучения критика: self._critic.train(self._state, action, reward).

Это ошибочно. Что мы действительно хотим сделать, так это объединить вознаграждение с оценочным значением того, насколько хорошо быть в следующем состоянии (значение Q следующего состояния). self._critic.train(self._state, action, reward + next_state_goodness). Как мы оцениваем, насколько хорошо быть в следующем состоянии? Сначала мы спрашиваем актера, какое действие лучше всего подходит для следующего состояния. Затем мы спрашиваем критика, насколько «хорошо» он оценивает это действие в следующем состоянии.

Ниже мы покажем, как мы изменим метод _run_helper, чтобы использовать reward + next_state_q_value для обучения критика (не используйте приведенный ниже код):

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

Ниже мы обновляем наш код (и тестируем), чтобы использовать эти «целевые» объекты актера и критика.

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

Резюме
Если я до сих пор не утомил вас, у вас должны быть следующие два файла:

Мы близки к работающему алгоритму DDPG - я пока упустил важные аспекты алгоритма в коде, такие как буфер воспроизведения, гиперпараметры и сами реализации актера и критика! Интегрировать недостающие компоненты будет довольно просто! Мы сделаем это в следующем посте!