Это продолжение предыдущей статьи, в которой мы рассмотрели простую игру с обучением с подкреплением (RL), в которой зеленый шар научился достигать небольшого круга в центре холста за 200 шагов. Мы написали алгоритм Q-обучения и визуализировали его с помощью графического интерфейса на основе Tkinter.

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

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

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

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

Хорошо, давайте посмотрим, как мы изменим код в предыдущей статье, чтобы заставить эту работу работать.

Возможные шаги теперь объявлены как

mov_list = [-40,-20,20,40]

вместо [-20, -10, 10, 20], которые мы использовали раньше. Удвоив размер шага, мы уменьшили пространство поиска в 4 раза для одного шара. Таким образом, для системы с двумя шарами пространство поиска в 16 раз меньше. Даже после этого наше пространство поиска будет 202500 вместо 1800, как было раньше.

Затем мы вводим проверку на столкновение с мячом и штраф за столкновение.

# Check if green ball hit the red ball
if (pos_x1 == pos_x2) and (pos_y1 == pos_y2):
   collision = 1
   reward = -200
   print("green collision", pos_x1, pos_y1, pos_x2, pos_y2)
   green_collision_count += 1

Награда за достижение круга - 100. Изначально я установил штраф за столкновения до -25. Без какого-либо обучения столкновения произошли 40% раз. Около 20% были из-за того, что зеленый шар перешагнул через красный шар (GBC, столкновение зеленого шара), в то время как остальные 20% были из-за того, что красный шар столкнулся с зеленым (RBC). Для нас попадание зеленого шара в красный - важная статистика. Даже после 100000 игр GBC составляли примерно 15%. Почему обучение предотвращению столкновений было таким медленным?

Вскоре я понял, что зеленый шар был полностью мотивирован стремлением достичь центра, что было продиктовано гораздо более высокой наградой по сравнению со штрафом за столкновение. Ага! Единственная причина, по которой количество GBC уменьшилось с 20 до 15%, было в том, что мяч быстро достигал центра, вместо того, чтобы беспорядочно перемещаться, и, следовательно, имел меньше шансов случайным образом поразить красный шар. Итак, на следующем шаге мы устанавливаем штраф за столкновения до -200.

Для РБК штрафов нет. С новым штрафным баллом GBC снизился до 0% в течение 20 000 игр. Это могло быть сделано намного раньше, но я проверил только после 20k шагов. Я был настроен оптимистично, но не настолько!

Весь код моделирования доступен здесь, а код для визуализации доступен в том же репозитории здесь.

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

Мы попробуем реализовать эту же игру с использованием DQN в другой статье.