Как настроить, проверить и использовать настраиваемую среду в обучении с подкреплением с помощью Python

OpenAI’s Gym (со ссылкой на их веб-сайт): … набор инструментов для разработки и сравнения алгоритмов обучения с подкреплением. Он включает в себя моделируемые среды, начиная от очень простых игр и заканчивая сложными физическими движками, которые вы можете использовать для обучения алгоритмов обучения с подкреплением. Другой пакет OpenAI, Baselines, поставляется с рядом алгоритмов, поэтому обучение агента обучения с подкреплением с этими двумя библиотеками действительно несложно, оно занимает всего пару строк в Python.

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

Вы можете предположить, что можете просто следовать рекомендациям в Документации по тренажерному залу, но это не совсем правильно. Мне пришлось выследить и скомпилировать информацию из нескольких источников (документация, GitHub, Stack Overflow и т. Д.), Поэтому я решил, что должен написать чистое и простое резюме.

Помимо библиотеки OpenAI Gym, мы также собираемся использовать пакет под названием Stable Baselines - проект, который начался как форк алгоритмов обучения с подкреплением библиотеки OpenAI Baseline, с намерением сделать его более документированный и удобный для пользователя.

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

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

Что охватывает это руководство

Изучив руководство, вы сможете:

  1. Настройте индивидуальную среду, совместимую с тренажерным залом.
  2. Разрабатывайте и регистрируйте разные версии своей среды.
  3. Решите, что именно нужно поместить в класс среды - на мой взгляд, это самая сложная часть всего проекта!
  4. Обучите простой алгоритм Q-Learning в новой среде.
  5. Используйте стабильные базовые показатели в среде, используйте пакет, чтобы убедиться, что ваша настраиваемая среда согласована с тренажерным залом, и обучите более сложный алгоритм.

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

Что мы не будем рассказывать

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

Если вы не знакомы с этими терминами, существует масса хороших материалов. В Документации по стабильным базовым линиям есть список полезных ссылок, и я лично использовал код Раздела Q-Learning на deeplizard, там также есть приятные сводки по основам.

Установить пакеты

Прежде чем мы начнем работать, нам нужно установить Gym и Stable Baselines.

Спортзал

Все очень просто, вы можете следить за документацией. Самый удобный способ - использовать pip:

pip install gym

Вот и все.

Стабильные базовые показатели

Это посложнее. Для начала вам потребуются некоторые предварительные условия, посмотрите документацию. Как только это будет сделано, вы сможете pip install получить пакет. Если вы используете Mac, это все, что вам нужно сделать:

brew install cmake openmpi
pip install stable-baselines[mpi]

Теперь проблема возникает, когда вы начинаете использовать алгоритмы глубокого обучения, основанные на тензорном потоке - по состоянию на декабрь 2020 года пакет Stable Baselines поддерживает тензорный поток только до версии 1.15.0. На странице руководства по установке есть предупреждающее сообщение, и если вам интересно, вы можете узнать больше о причине проблемы на GitHub.

Суть в том, что вам нужна более старая версия tensorflow. Я не использовал tenorflow ни для чего другого, поэтому просто установил старую версию вот так:

pip install tensorflow==1.15.0

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

Файловая структура

Если вы попытаетесь создать настраиваемую среду из официального руководства, скорее всего, вы начнете с создания такой файловой структуры:

gym-basic/
  README.md
  setup.py
  gym_basic/
    __init__.py
    envs/
      __init__.py
      basic_env.py
      basic_env_2.py

Почему это важно?

Дело в том, что это не ... На самом деле вам не нужно беспокоиться обо всей этой файловой структуре, единственное, что действительно имеет значение, - это basic_env.py. Когда я начал работать над этим проектом, я предполагал, что когда вы позже создадите свою среду с помощью команды Gym:

env = gym.make(“gym_basic:basic-v0”)

в фоновом режиме происходит что-то волшебное, но мне кажется, что вы получите тот же результат, если просто инициируете объект из своего класса среды:

env = BasicEnv()

(Конечно, вам нужно сначала импортировать его.) Насколько я понимаю, главное преимущество регистрации вашей среды в пакете Gym заключается в том, что вы можете хранить все свои среды в одном месте, а также можете запускать базовые алгоритмы RL (исходный OpenAI и Стабильные базовые показатели аналогично) одной строкой:

python -m baselines.run --alg=<name of the algorithm> --env=<environment_id> [additional arguments]

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

Вы можете использовать документацию для этой части, или мой репозиторий GitHub, по сути, также является пользовательской средой Gym (если вы проигнорируете два Jupyter Notebooks). Вам необходимо настроить setup.py, два __init__.py и, что наиболее важно, файл (ы) среды, что мы и сделаем в следующем разделе. Обратите внимание на разницу между двумя __init__.py, они работают с разными версиями вашей среды.

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

gym-basic / setup.py

from setuptools import setup 
setup(name=’gym_basic’, version=’0.0.1', install_requires=[‘gym’] )

gym-basic / gym_basic / __ init__.py

from gym.envs.registration import register 
register(id='basic-v0',entry_point='gym_basic.envs:BasicEnv',) 
register(id='basic-v2',entry_point='gym_basic.envs:BasicEnv2',)

(У нас будет две среды: BasicEnv с id = 'basic-v0' и BasicEnv2 с id = basic-v2. Таким образом, вы можете хранить разные версии среды в одном реестре.)

тренажерный зал-базовый / gym_basic / envs / __ init__.py

from gym_basic.envs.basic_env import BasicEnv
from gym_basic.envs.basic_env_2 import BasicEnv2

README.md

Погодите, там был другой файл, уценка README, что мне туда вставить? Что ж, это просто ваш файл readme репозитория git, он не имеет ничего общего с вашей средой спортзала.

Как зарегистрировать вашу среду

Если у вас есть соответствующие файлы среды в папке envs (в нашем случае basic_env.py и basic_env_2.py), вы можете зарегистрировать свою среду. Просто перейдите в своем терминале к папке, содержащей gym-basic, и используйте pip:

pip install -e gym-basic

Если вы позже обновите .py файлы среды, среда должна обновиться автоматически.

Хорошо, мы зарегистрировали среду Gym. Наконец, мы можем сосредоточиться на важной части: классе среды.

Класс среды

Здесь, я думаю, документация спортзала вводит в заблуждение. В предоставленном ими шаблоне foo_env.py есть части, которые вам не нужно включать, и есть недостающие части, которые вам нужны. В Стабильных базах есть шаблон получше, но он все еще был мне не совсем понятен.

Еще раз, моя цель - создать здесь абсолютно минимальную среду.

Что вам нужно в тренажерном зале

  • Среда должна быть классом, унаследованным от gym.Env.
  • В __init__ вам нужно создать две переменные с фиксированными именами и типами. Вам нужны self.action_space и self.observation_space. Эти двое должны принадлежать к специальному классу спортзала, space, что не совсем сложно, но и не совсем однозначно. Взгляните на документацию, в основном есть два типа: одномерный, называемый Discrete, и n-мерный, называемый Box. В этом примере мы сохраним простоту и будем использовать только Discrete. (Можно возразить, что вы всегда можете перекодировать свои пробелы в одномерные идентификационные коды.)
  • Функция reset возвращает значение в пределах self.observation_space. Это функция, которая перезапускает среду, например, в начале игры. В своих средах я вызываю переменную, которая отслеживает текущее состояние… ну, state, но там нет никаких ограничений, вы можете называть это как угодно. Если мы используем Discrete пространство наблюдения, это state значение должно быть целым числом. С Box это может быть numpy.array.
  • Функция step имеет один входной параметр и требует значения действия, обычно называемого action, которое находится в пределах self.action_space. Подобно state в предыдущем пункте, action может быть целым числом или numpy.array. Это функция ответа, агент обеспечивает действие, которое они хотят предпринять, а среда возвращает состояние, в которое он их привел. Возвращаемое значение представляет собой четырехкортежный кортеж в следующем порядке (имя не имеет значения, но тип переменной имеет значение):
    - state, тот же тип переменной, что и возвращаемый функция сброса self.observation_space;
    - reward, число, информирующее агента о немедленных последствиях его действия;
    - done, логическое , значение TRUE, если среда достигла конечной точки и должна быть сброшена, или FALSE в противном случае;
    - info, словарь, который можно использовать для исправления ошибок, и насколько я знаете, базовые алгоритмы его не используют.
    Эти переменные необходимо указать, но не все они должны иметь «правильные» значения. Например, info может быть просто пустым словарем.

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

Что вам НЕ нужно в тренажерном зале

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

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

  • metadata = {‘render.modes’: [‘human’]}:
    Эта строка просто определяет возможные типы для вашей render функции (см. следующий пункт).
  • На самом деле вам не нужна render функция. Я имею в виду, естественно, что это удобно, когда вы пытаетесь исправить ошибку, но с точки зрения обучения алгоритма подкрепления, насколько я заметил, базовые алгоритмы не предполагают, что он есть, и они его не используют. Если подумать, цель render - просто преобразовать вашу state переменную в нечто более читаемое.
  • Точно так же вам не нужна функция close. На странице GitHub основной среды есть некоторые комментарии к этой функции, она будет вызываться для дополнительной очистки, когда среда закрывается или выбирается сборщиком мусора.
  • То же самое с функцией seed. Это будет полезно, если вы хотите обеспечить воспроизводимость в среде, использующей генераторы случайных чисел.

Обратите внимание, что в классе, от которого вы унаследованы (gym.env), будут реализованы эти функции, с одной строкой pass в каждой из них. Строго говоря, у вас всегда будут эти функции, но они вам ни для чего не нужны.

Пример среды

Хорошо, а теперь давайте посмотрим на настраиваемую среду! Как я упоминал ранее, это будет очень просто. Мы начинаем с состояния = 0, и агент может выбирать между 5 действиями, пронумерованными от 0 до 4. Если они выбирают действие = 2, они получают вознаграждение 1, в противном случае вознаграждение равно -1. (Если вы хотите увидеть что-то более сложное, взгляните на basic_env_2.py в моем репозитории на GitHub.)

То, как вы можете закодировать это как среду тренажерного зала:

import gym
class BasicEnv(gym.Env):
def __init__(self):
        self.action_space = gym.spaces.Discrete(5)
        self.observation_space = gym.spaces.Discrete(2)
def step(self, action):
        state = 1
    
        if action == 2:
            reward = 1
        else:
            reward = -1
            
        done = True
        info = {}
        return state, reward, done, info
def reset(self):
        state = 0
        return state

Вот и все, у вас есть тренажерный зал!

Обратите внимание, что state всегда находится в рамках функции, которая его использует, и это подразумевает, что если среда делает шаг (через функцию step), она перемещается с state 0 на 1, а затем «игра» немедленно заканчивается. . Таким образом, нет необходимости отслеживать state внутри объекта в этой простой игре, но, как правило, вам нужна переменная self.state.

Как упоминалось выше, вы можете создать объект с помощью

env = gym.make(“gym_basic:basic-v0”)

если вы зарегистрировали среду (см. раздел Структура файла выше), или просто с помощью

env = BasicEnv()

если вы его не зарегистрировали.

В оставшейся части сообщения я предполагаю, что env инициирован и является средой BasicEnv Gym.

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

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

Запустить эту проверку так же просто, как:

from stable_baselines.common.env_checker import check_env
check_env(env)

Если вы следовали руководству, функция ничего не вернет. Что немного странно, но означает, что все в порядке.

Вы можете проверить, что произойдет, если вы измените любой из элементов в своей среде. Например, если у вас нет функции reset, вы получите NotImplementedError. Если у вас нет правильных self.action_space и self.observation_space, например, если вы определили их как обычный список вместо специального класса space, вы получите следующую ошибку: AssertionError: The action space must inherit from gym.spaces.

Обратите внимание, как функция проверки не жаловалась на отсутствие того, что мы указали ранее как ненужные!

Тестирование с помощью простого алгоритма Q-Learning

Слежу за реализацией алгоритма Q-Learning от deeplizard. В этом разделе мы повторяем руководство, но заменяем среду своей собственной.

Как и в случае со встроенной средой, следующий раздел правильно работает в настраиваемой среде. Класс Gym space имеет атрибут n, который можно использовать для сбора размеров:

action_space_size = env.action_space.n
state_space_size = env.observation_space.n
q_table = np.zeros((state_space_size, action_space_size))
print(q_table)

возвращает:

[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

Это Q-значения состояния и действия окружающей среды. Обратите внимание, что первая строка, соответствующая состоянию 0, - единственная, о которой мы заботимся, вторая строка состояния 1 - это конечное состояние, там никаких действий предприниматься не будет. Я не уверен, является ли это обычной практикой или нет, мне казалось логичным держать конечное состояние отдельно.

Я не собираюсь копировать здесь весь код, обратитесь к моему репозиторию GitHub.

После обучения модели обновленные значения Q выглядят следующим образом:

[[-0.94185026 -0.89058101  1.         -0.92023356 -0.91137062]
 [ 0.          0.          0.          0.          0.        ]]

Это указывает на то, что модель действительно изучила среду и определила action = 2 как оптимальное действие, которое следует предпринять.

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

Тестирование с использованием алгоритма стабильных базовых показателей

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

Короче говоря, взяв код из Руководства по началу работы на Stable Baselines и заменив env нашим собственным (опять же, запустив env = gym.make(“gym_basic:basic-v0”) или env = BasicEnv(), этот код работает отлично:

from stable_baselines.common.policies import MlpPolicy
from stable_baselines.common.vec_env import DummyVecEnv
from stable_baselines import PPO2

model = PPO2(MlpPolicy, env, verbose=1)
model.learn(total_timesteps=10000)

obs = env.reset()
for i in range(10):
    action, _states = model.predict(obs)
    print(action)
    obs, rewards, dones, info = env.step(action)
    env.render()

(Наша функция render ничего не делает, поэтому я добавил строку, чтобы распечатать наше действие.)

Довольно обнадеживает то, что модель смогла научиться правильно играть в нашу игру и в каждом случае выбирает action = 2.

использованная литература