Нажмите здесь, чтобы опубликовать эту статью в LinkedIn »

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

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

Давайте начнем.

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

1. Настроить

Во-первых, давайте настроим импорт и некоторые переменные, которые мы будем использовать:

Последний пункт здесь новый, он позволит нам командовать SCV для сбора минералов.

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

И снова здесь есть новый ID юнита для определения местоположения минеральных пятен.

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

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

Вы можете заметить, что здесь отсутствуют некоторые действия, в этом уроке мы собираемся объединить последовательность действий (например, выбрать казармы, обучить морской пехотинец) в одно действие (например, поездить морского пехотинца). Я объясню это поподробнее.

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

2. Добавьте таблицу Q Learning

Как и в случае с моими предыдущими уроками, мы будем использовать Q Learning Table. Обратите внимание, что этот был обновлен для поддержки некоторых обновлений pandas, которые, казалось, вызывали проблемы у некоторых людей.

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

Меня всегда удивляло, как мало кода требуется, чтобы обучение с подкреплением работало!

3. Создайте агента.

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

Мы добавили несколько свойств cc_x и cc_y, чтобы отслеживать расположение командного центра.

Другое новое свойство move_number будет отслеживать позицию последовательности в многоступенчатом действии.

Этот код довольно крут, если sparse_agent_data.gz существует, он загрузит данные Q Learning Table из этого файла, что позволит вам возобновить обучение с предыдущей позиции. Если вам нужно остановить обучение или есть какая-то ошибка, которая вызывает сбой вашего агента, вы можете просто перезапустить его, и ваша история обучения не будет потеряна.

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

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

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

Здесь мы просто настраиваем несколько счетчиков, которые мы можем использовать для состояния и другого кода, который должен знать, что у нас есть. Более подробное объяснение вы можете прочитать здесь.

Хорошо, теперь у нас есть базовый агент, который должен работать, но ничего не достигает.

4. Добавьте первый шаг из многоступенчатых действий.

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

Основные действия, которые у нас будут:

  • Ничего не делать - ничего не делать за 3 шага
  • Постройте склад снабжения - выберите SCV, постройте склад снабжения, отправьте SCV на добычу полезных ископаемых.
  • Стройте казармы - выберите SCV, постройте казармы, отправьте SCV на добычу полезных ископаемых.
  • Постройте морской пехотинец - выберите все казармы, тренируйте морской пехотинец, ничего не делайте
  • Атака (x, y) - выбрать армию, координаты атаки, ничего не делать

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

Вставьте следующий код после строки barracks_count из предыдущего шага:

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

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

Теперь мы разделим нашу мини-карту на четыре квадранта и помечаем квадрант как «горячий», если он содержит какие-либо вражеские юниты. Если база находится в правом нижнем углу, мы инвертируем квадранты, чтобы все игры рассматривались с точки зрения верхней левой базы, независимо от фактического положения базы. Это должно помочь нашему агенту узнать больше.

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

Затем мы выбираем действие и выделяем любые координаты x и y, если они существуют.

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

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

Первым шагом для атаки на локацию является выбор армии.

5. Добавьте второй этап многоступенчатых действий.

Добавьте следующий код непосредственно под кодом из предыдущего шага:

Мы начинаем с увеличения номера хода и извлечения деталей нашего действия.

Второй шаг для создания базы снабжения - дать команду SCV построить склад в заданном месте. Используя наше сохраненное местоположение командного центра, мы сможем построить склад снабжения, даже если наш командный центр был разрушен.

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

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

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

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

Второе действие для атаки - просто приказать армии атаковать место на мини-карте.

Чтобы предотвратить случайный выбор SCV и попытку атаки с их помощью, мы проверяем поля single_select и multi_select, чтобы убедиться, что мы не выбрали SCV.

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

6. Добавьте последний шаг многоступенчатых действий.

Добавьте следующий код сразу после кода из предыдущего шага:

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

Все остальные пропущенные или недопустимые действия будут выполняться _NO_OP вызовом.

7. Обнаружение завершения игры

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

Добавьте следующий код в начало метода step () вашего агента после вызова super(SparseAgent, self).step(obs):

Как и вызов obs.first(), который мы сделали ранее, вызов obs.last() позволяет нам определить последний шаг игры в эпизоде.

К счастью для нас, DeepMind предоставляет нам необходимое вознаграждение в виде obs.reward. Это значение будет либо 1 для победы, -1 для проигрыша, либо 0 для патовой ситуации, или если эпизод достигнет 28 800 шагов.

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

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

Мы выводим данные Q Learning Table в формате gzip pickle, чтобы его можно было перезагрузить, если наш агент остановлен по какой-либо причине.

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

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

8. Запустите агент.

Чтобы запустить агент, выполните в командной строке следующее:

python -m pysc2.bin.agent \
--map Simple64 \
--agent sparse_agent.SparseAgent \
--agent_race T \
--max_agent_steps 0 \
--norender

После 1035 игр мой агентский рекорд выглядел так:

Я был очень впечатлен тем, что агент, использующий настройки по умолчанию, терял менее 50% времени. В моем следующем уроке я расскажу, как увеличить винрейт более чем на 70%.

Вы можете найти историю вознаграждений и окончательные данные Q Learning Table здесь.

Весь код из этого руководства можно найти здесь.

Если вам нравится этот урок, поддержите меня на Patreon. Также присоединяйтесь ко мне в Discord или подписывайтесь на меня в Twitch, Medium, GitHub, Twitter и YouTube.