Вы хотите создать настраиваемую среду с несколькими агентами? Вы видели видео Open AI, где агенты сотрудничают, чтобы прятаться, и хотят сделать что-то подобное?

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

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

Весь код для этой статьи доступен на моем GitHub.

Пользовательская среда

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

0: Пустая область, агенты могут туда идти

1: Агент 1, который попытается найти выход

2: Агент 2, который также попытается найти выход

3: Ловушки, если агент пойдет туда, он проиграет игру

4: Выход, обратите внимание, мы сделали 2 выхода из нашего лабиринта.

Агент 1 начнет движение, затем наступит очередь агента 2 и так далее, пока кто-нибудь не проиграет или не выиграет игру. Например после первого хода:

Некоторые правила, которые мы добавим:

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

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

Код

Хватит объяснений, давайте код. Код находится в моем GitHub, вы можете клонировать и запускать его, мы объясним это в этой главе.

Env.py

Сначала в env.py импортируем то, что нам понадобится:

import gym
from gym import spaces
import numpy as np

Наш env на самом деле является классом:

class MazeEnv(gym.Env):
def __init__(self):
self.action_space = spaces.Discrete(4)
self.observation_space = spaces.Box(low=0,
high=4,
shape=(5, 4),
dtype=np.int16)
self.reward_range = (-200, 200)
self.current_episode = 0
self.success_episode = []

Наше действие: 0, 1, 2 или 3. 0 означает движение вверх, 1 означает движение вправо, 2 означает движение вниз, 3 означает движение влево.

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

Метод reset ()

def reset(self):
self.current_player = 1
# P means the game is playable, W means somenone wins, L someone lose
self.state = ‘P’
self.current_step = 0
self.max_step = 30
self.world = np.array([[1, 0, 0, 2],
[0, 0, 0, 0],
[0, 3, 4, 3],
[0, 4, 0, 0]])
return self._next_observation()

Функция reset () сбрасывает наш лабиринт в начале каждого эпизода, Здесь мы можем изменить наш начальный лабиринт. После этого мы могли бы попробовать более сложный лабиринт, изменив self.world.

Метод _next_observation ()

def _next_observation(self):
obs = self.world
obs = np.append(obs, [[self.current_player, 0, 0, 0]], axis=0)
return obs

Метод _next_observation () создает наше наблюдение. Наше наблюдение содержит лабиринт, а также агента, который может перемещать этот ход (текущего игрока).

Метод _take_action ()

def _take_action(self, action):
current_pos = np.where(self.world == self.current_player)
if action == 0:
next_pos = (current_pos[0] — 1, current_pos[1])
if next_pos[0] >= 0 and int(self.world[next_pos]) == 0:
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
elif next_pos[0] >= 0 and int(self.world[next_pos]) in (1, 2):
pass
elif next_pos[0] >= 0 and (int(self.world[next_pos]) == 3):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘L’
elif next_pos[0] >= 0 and (int(self.world[next_pos]) == 4):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘W’
elif action == 1:
next_pos = (current_pos[0], current_pos[1] + 1)
if next_pos[1] < 3 and int(self.world[next_pos]) == 0:
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
elif next_pos[1] < 3 and int(self.world[next_pos]) in (1, 2):
pass
elif next_pos[1] < 3 and (int(self.world[next_pos]) == 3):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘L’
elif next_pos[1] < 3 and (int(self.world[next_pos]) == 4):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘W’
elif action == 2:
next_pos = (current_pos[0] + 1, current_pos[1])
if next_pos[0] <= 3 and int(self.world[next_pos]) == 0:
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
elif next_pos[0] <= 3 and int(self.world[next_pos]) in (1, 2):
pass
elif next_pos[0] <= 3 and (int(self.world[next_pos]) == 3):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘L’
elif next_pos[0] <= 3 and (int(self.world[next_pos]) == 4):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘W’
elif action == 3:
next_pos = (current_pos[0], current_pos[1] — 1)
if next_pos[1] >= 0 and int(self.world[next_pos]) == 0:
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
elif next_pos[1] >= 0 and int(self.world[next_pos]) in (1, 2):
pass
elif next_pos[1] >= 0 and (int(self.world[next_pos]) == 3):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘L’
elif next_pos[1] >= 0 and (int(self.world[next_pos]) == 4):
self.world[next_pos] = self.current_player
self.world[current_pos] = 0
self.state = ‘W’

Здесь нет ничего интересного, просто нужно выполнить действие, а затем изменить позицию играющего агента.

Метод step ()

def step(self, action):
self._take_action(action)
self.current_step += 1
print(self.world)
if self.state == “W”:
print(f’Player {self.current_player} won’)
reward = 200
done = True
elif self.state == ‘L’:
print(f’Player {self.current_player} lost’)
reward = -200
done = True
elif self.state == ‘P’:
reward = -1
done = False
if self.current_step >= self.max_step:
done = True
if self.current_player == 1:
self.current_player = 2
else:
self.current_player = 1
if done:
self.render_episode(self.state)
self.current_episode += 1
obs = self._next_observation()
return obs, reward, done, {}

После проверки, выиграл ли агент или проиграл, мы меняем current_player (помните, что это пошаговая игра). Наша награда будет высокой, если агент найдет выход (+200), очень низкой, если он найдет ловушку (-200), и немного низкой (-1), если он двинулся без выигрыша или проигрыша. Мы делаем это, чтобы он как можно быстрее нашел выход.

Метод render_episode ()

def render_episode(self, win_or_lose):
self.success_episode.append(
‘Success’ if win_or_lose == ‘W’ else ‘Failure’)
file = open(‘render/render.txt’, ‘a’)
file.write(‘ — — — — — — — — — — — — — — — — — — — — — -\n’)
file.write(f’Episode number {self.current_episode}\n’)
file.write(f’{self.success_episode[-1]} in {self.current_step} steps\n’)
file.close()

Он предоставит нам простой файл render.txt в папке рендеринга, чтобы увидеть результат каждого эпизода.

Вот и все ! У нас есть собственная среда.

Файл main.py

У нас есть файл env.py без настраиваемой среды, давайте обучим наших агентов.
Сначала давайте импортируем то, что нам нужно:

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

Мы будем использовать PPO2 (Proximal Policy Optimization из stable_baselines).

env = DummyVecEnv([lambda: MazeEnv()])
model = PPO2(MlpPolicy, env, learning_rate=0.001)
model.learn(500000)

Мы создаем экземпляр MazeEnv (), а затем заставляем его учиться в течение 500 000 временных шагов (мы заявили, что эпизод может длиться не более 30 временных шагов).

Результат

Сначала это будет сочетание успеха и неудачи:

Именно после ~ 6700 серий мы постоянно видим лучшее решение за 6 шагов:

Заключение

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

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

Следующая статья, чтобы сделать сотрудничество необходимым для выхода из лабиринта!