#pytorch #reinforcement-learning #conv-neural-network #stable-baselines
#pytorch #подкрепление-обучение #conv-нейронная сеть #стабильные базовые показатели
Вопрос:
Я пытаюсь обучить агента играть в игру Connect4. Я нашел пример того, как его можно обучить. Представление платы — массив размером 1x6x7:
[[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 2]
[0 0 0 0 0 0 1]]]
Используется эта архитектура нейронной сети:
class Net(BaseFeaturesExtractor):
def __init__(self, observation_space: gym.spaces.Box, features_dim: int = 256):
super(Net, self).__init__(observation_space, features_dim)
# We assume CxHxW images (channels first)
# Re-ordering will be done by pre-preprocessing or wrapper
n_input_channels = observation_space.shape[0]
self.cnn = nn.Sequential(
nn.Conv2d(n_input_channels, 32, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=0),
nn.ReLU(),
nn.Flatten(),
)
# Compute shape by doing one forward pass
with th.no_grad():
n_flatten = self.cnn(th.as_tensor(observation_space.sample()[None]).float()).shape[1]
self.linear = nn.Sequential(nn.Linear(n_flatten, features_dim), nn.ReLU())
def forward(self, observations: th.Tensor) -> th.Tensor:
return self.linear(self.cnn(observations))
И он показал неплохие результаты в игре с агентом 2, который перемещается случайным образом:
Agent 1 Win Percentage: 0.59
Agent 2 Win Percentage: 0.38
Number of Invalid Plays by Agent 1: 3
Number of Invalid Plays by Agent 2: 0
Number of Draws (in 100 game rounds): 0
Здесь было предложено 3-уровневое представление в качестве одного из способов улучшения агента:
Я попытался реализовать это, и это пример нового 3-слойного представления платы:
[[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 1]]
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 1]
[0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 1]
[0 0 0 0 0 0 0]
[1 1 1 1 1 1 0]]]
Когда я запускаю это с текущей архитектурой нейронной сети, агент не может обучаться соответствующим образом:
Agent 1 Win Percentage: 0.0
Agent 2 Win Percentage: 0.0
Number of Invalid Plays by Agent 1: 100
Number of Invalid Plays by Agent 2: 0
Number of Draws (in 100 game rounds): 0
Здесь вы можете увидеть мой код.
Как вы можете видеть, теперь у меня 3 слоя вместо одного. Вот почему я попытался использовать Conv3d:
class Net(BaseFeaturesExtractor):
def __init__(self, observation_space: gym.spaces.Box, features_dim: int = 256):
super(Net, self).__init__(observation_space, features_dim)
# We assume CxHxW images (channels first)
# Re-ordering will be done by pre-preprocessing or wrapper
n_input_channels = observation_space.shape[0]
self.cnn = nn.Sequential(
nn.Conv3d(n_input_channels, 32, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.Conv3d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.Conv3d(64, 128, kernel_size=3, stride=1, padding=0),
nn.ReLU(),
nn.Flatten(),
)
# Compute shape by doing one forward pass
with th.no_grad():
n_flatten = self.cnn(th.as_tensor(observation_space.sample()[None]).float()).shape[1]
self.linear = nn.Sequential(nn.Linear(n_flatten, features_dim), nn.ReLU())
Когда я пытаюсь запустить этот код, он показывает эту ошибку:
Ошибка времени выполнения: ожидаемый 5-мерный ввод для 5-мерного веса [32, 1, 3, 3, 3], но вместо этого получил 4-мерный ввод размера [1, 3, 6, 7]
Мой вопрос: как я могу использовать слой Conv3D с вводом в форме 3x6x7?
Комментарии:
1. Я не думаю, что вам нужен conv3d здесь. Это все еще 2d с большим количеством входных каналов.
Ответ №1:
Комментарий от Shai верен. Здесь вам не нужно использовать слой Conv3D. Форма ваших фильтров Conv3D будет нарушать вычисление размера после применения сверточного фильтра, уменьшая по крайней мере 1 измерение до менее 1, поэтому вы получаете свою ошибку (вы не можете умножить на значение, которое не существует).
Простое использование исходной реализации модели должно работать для вас.
Подобно изображениям с 3 цветовыми полосами, они обычно не обрабатываются с помощью Conv3d (возможно, другой случай с гиперспектральными изображениями, но здесь это не актуально). Существует некоторое обсуждение того, как обрабатывать каждую из цветовых полос, и вы можете повлиять на это различными способами.
Например, настройка groups
аргумента слоя Conv2D при создании экземпляра изменит связи между in_channels
и out_channels
слоя, и которые свернуты с которым, согласно их документации: https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html .
Возможно, вы сможете оптимизировать это в своей модели или иным образом поэкспериментировать с ней.
В любом случае, вам подойдет простое использование существующей реализации с Conv2D. Conv3D обычно используется в случае 3 пространственных измерений, или иногда 2 пространственных и 1 временное измерение. Хотя ваш случай похож на ограниченную версию из 3 пространственных измерений, это не обязательно то же самое, что, скажем, 3D векторное поле потока жидкости в отношении того, как каждый «пиксель» имеет некоторую пространственную релевантность / корреляцию с соседними «пикселями». Ваши «пространственные пиксели» имеют несколько иной вид отображения релевантности или корреляции, чем этот.
Комментарии:
1. Да, я пытался обучить агента с помощью conv2d, однако он не может обучаться должным образом. Также я должен отметить, что 3-слойный ввод представляет собой представление доски 6×7 в игре Connect4. Первый слой предназначен для первого игрока, второй слой предназначен для второго игрока, а третий слой показывает возможные ходы для игрока с текущими ходами.
2. Спасибо за информацию о том, из чего состоит каждое представление платы. Не имея возможности обучаться должным образом, вы просто имеете в виду, что она не сходится или работает плохо? Если это так, вы можете попробовать изменить
groups
аргумент, чтобы он был эквивалентенin_channels
аргументу, или иным образом напрямую реализовать отдельные слои conv для обработки каждого из состояний платы (и последующего их объединения), чтобы гарантировать, что временное несоответствие можно разделить, а его актуальность может быть изучена моделью.3. Если вы решите сделать последнее, упомянутое в моем последнем комментарии, я бы перешел с использования
self.cnn = nn.Sequential(...)
на « self.conv1_p1 = nn.Conv2d(…) self.conv2_p1 = nn.Conv2d(…) self.conv1_p2 = nn.Conv2d(…) self.conv1_moves = nn.Conv2d(…)) « и т. Д. По сути, создание нескольких cnn. Вы также можете просто использовать несколькоnn.Sequential
моделей, а затем объединить их выходные данные вforward()
функции.