Найти в Дзене
ТехноШаман

Пробую использовать нейросеть в игре. Часть 1.

Когда то я сделал на планшете игру, где нужно было из зенитки сбивать инопланетян и не попадать по дирижаблям. И НЛО и дирижабли летят слева направо. Скорость НЛО выше.
Теперь решил прикрутить к зенитке нейронную сеть.
Я не специалист в этой области , здесь я просто буду описывать своё опыт, свои трудности, которые возникали во время реализации этого проекта. Статья идёт в поддержку
Оглавление

Когда то я сделал на планшете игру, где нужно было из зенитки сбивать инопланетян и не попадать по дирижаблям. И НЛО и дирижабли летят слева направо. Скорость НЛО выше.

Теперь решил прикрутить к зенитке нейронную сеть.
Я не специалист в этой области , здесь я просто буду описывать своё опыт, свои трудности, которые возникали во время реализации этого проекта. Статья идёт в поддержку
видеоролика на YouTube.

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

-2

Честный способ

Первое что приходит в голову это подавать на вход нейросети изображение Но даже после оптимизации изображения потребуется огромное количество входных нейронов Вряд ли я это потяну с своим старым ноутбукам и интерпретатором pixilang. Но это был бы самый честный способ.

-3

На картинке представлен возможный вариант оптимизации изображения, перед подачей на нейросеть. Здесь использовался тот факт, что в картинке дирижабля доминирует красная, а у НЛО - зелёная составляющая.

Обходной путь

Но я со своими ресурсами пойду другим путём.

Будем на вход нейросети подавать параметры летящих объектов.
В качестве параметров можно использовать:

  • угол от зенитки до объекта
  • Y-координаты объекта (высоту)
  • X-координаты объекта
  • расстояние от зенитки до объекта.

Я буду на вход подавать X и Y координаты объекта.

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

Для одного объекта требуется 3 входных нейрона:

  • X координата
  • Y координата
  • скорость.

Так как у нас всего две скорости: 1 и 3 пикселя за кадр, то на вход, отвечающий за скорость, будем подавать либо 0 либо 1.

Теперь надо определиться с тем сколько объектов у нас будет находиться в воздухе. Хотелось бы задавать произвольное количество объектов.

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

-4

Вот такой вариант нейросети я рассматривал. Здесь я изобразил возможный вариант для двух дирижаблей и одной НЛО. Так как скорости и дирижаблей и НЛО фиксированные, то можно отказаться от входного нейрона скорости.

На выходе есть есть ещё один нейрон "огонь!". Это разрешение для выстрела. На выходе 1 - когда можно стрелять, 0 - нельзя, НЛО закрыт дирижаблями.

Мой путь

Но я пошёл более простым путем. Я создал небольшой нейросеть, рассчитанную на определения угла выстрела по одному объекту и буду гонять её по всем, интересующим меня, объектам.

-5

На вход будет 3 входных нейрона:

  • X-координата
  • Y-координаты
  • скорость

На выходе - угол выстрела.

Для нейронки я буду использовать унифицированную функцию relu и сломанную на уровне единицы.

-6

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

Обучение.

Я настроил зенитку так чтобы при подаче на неё числа от нуля до единицы она стреляла в заданном диапазоне. Определил рабочую зону где мы будем стрелять и теперь пора переходить к обучению.

Зенитка дала очередь от угла -0,1 до 1,1 с шагом 0,01
Зенитка дала очередь от угла -0,1 до 1,1 с шагом 0,01

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

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

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

Естественно, в большинстве случаев, у не обученной нейросети снаряд будет лететь совсем в другую сторону. У сети с функцией активации Relu снаряды летели влево, на выходе было меньше нуля. У сети с логистической функцией снаряды летели вверх, на выходе было было около 0,5.

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

Поправку я Вычисляю следующим образом.

Если снаряд поднялся выше объекта то я останавливаю моделирование беру разницу в X-координатах снаряда и цели делю её на 3000.
Величину в 3000 я подобрал из таких соображений. Если снаряд и цель оказались в разных концах игрового поля, то расстояние между ними будет максимум 1000 пикселей. Поправка окажется 0.3 , что не плохо при диапазоне зенитки от 0 до 1.

Чем больше расстояние между объектом и снарядом, тем больше будет величина поправки. То есть поправка пропорциональна расстоянию между объектом и снарядом. Если снаряд поднялся правее объекта, то поправка идёт со знаком минус.

Три варианта определения поправки
Три варианта определения поправки

Второй случай, это когда снаряд летит влево, угол выстрела меньше 0,45 и уже улетел левее объекта. Беру разницу в высоте объекта и снаряда делю на 3000. Это и будет поправка к углу выстрела.

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

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

Изначально я хотел использовать два выхода на нейронной сети. Один выход показывает угол, а второй показывает, попадёт ли снаряд.
В этом случае, при обучении, мы также подаём угол с поправкой, а на второй выходной нейрон подаём 0, если снаряд не попал в цель и 1, если попал. И здесь, видимо, возникнет такая ситуация. Угол выстрела потихоньку становится более правильным, веса приобретают правильные значения и в конце мы попадаем в цель, подаём на второй выход 1 (попали) и все веса сбиваются. Всё приходится начинать сначала.
Скорее всего сеть обучится, но потребует значительно больше времени на обучение.
Как вариант, можно сделать вторую маленькую независимую нейросеть, которая будет предсказывать "возможность попасть" и обучить её потом, по результатам работы первой сети.

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

-10

Часть 2. Продолжение + исходники.