Нужна помощь в разработке оценки пригодности для нейронной сети, основанной на алгоритме NEAT
Я работаю над нейронной сетью на основе алгоритм NEAT, который учится играть Atari Breakout клон в Python 2.7, и у меня есть все части, которые работают, но я думаю, что эволюция может быть значительно улучшен с лучшим алгоритмом расчета видовой пригодности.
Входы в нейронную сеть:
- Координата X центра лопасти
- X координата центра шара
- Координата Y центра шара
- шар dx (скорость в X)
- ball dy (скорость в Y)
Выходы:
- Переместить весло слева
- Переместить правую кнопку мыши.
- Не перемещайте весло
Параметры, которые я имею в распоряжении для расчета пригодности вида:
-
breakout_model.score
- int
: окончательный счет игры, которую играет вид
-
breakout_model.num_times_hit_paddle
- int
: количество раз, когда весло попало в мяч.
-
breakout_model.hits_per_life
- int
: количество раз, когда весло попало в мяч на всю жизнь, в виде списка; например первый элемент - это значение для первой жизни, 2-й элемент - это значение для 2-й жизни и т.д. до 4
-
breakout_model.avg_paddle_offset_from_ball
- decimal
: среднее линейное расстояние в направлении X между шаром и центром лопасти
-
breakout_model.avg_paddle_offset_from_center
- decimal
: среднее линейное расстояние в направлении X между центром кадра и центром лопасти
-
breakout_model.time
- int
: общая продолжительность игры, измеренная в кадрах
-
breakout_model.stale
- boolean
: была ли игра искусственно прекращена из-за застоя (например, мяч застревает, подпрыгивая прямо вертикально, а весло не двигается).
Если вы считаете, что мне нужно больше данных об окончательном состоянии игры, чем просто это, я, скорее всего, реализую способ получить ее очень легко.
Вот мой текущий расчет пригодности, который я не думаю, очень хорош:
def calculate_fitness(self):
self.fitness = self.breakout_model.score
if self.breakout_model.num_times_hit_paddle != 0:
self.fitness += self.breakout_model.num_times_hit_paddle / 10
else:
self.fitness -= 0.5
if self.breakout_model.avg_paddle_offset_from_ball != 0:
self.fitness -= (1 / self.breakout_model.avg_paddle_offset_from_ball) * 100
for hits in self.breakout_model.hits_per_life:
if hits == 0:
self.fitness -= 0.2
if self.breakout_model.stale:
self.fitness = 0 - self.fitness
return self.fitness
Вот что я думаю, что расчет пригодности должен выполняться семантически:
- Оценка, очевидно, должна оказать самое значительное влияние на общую пригодность. Может быть, оценка 0 должна слегка отрицательно повлиять на фитнес?
- Количество раз, когда весло попало в шарик за жизнь, должно иметь какой-то эффект, но не столь значимый вклад/вес. например если это число равно 0, оно даже не пыталось вообще ударить по мячу во время этой жизни, поэтому оно должно иметь отрицательный эффект.
- Количество раз, когда весло попало в общую сумму мяча, также должно иметь некоторый эффект, и его вклад должен основываться на счете. например если он не ударил по мячу много раз, а также не набрал много очков, это должно иметь значительный отрицательный эффект; если он не ударил по мячу много раз, но набрал большое количество очков, что должно иметь значительный положительный эффект. В целом, (я думаю), чем ближе к этому значению, тем выше оценка игры/веса, которое должно иметь значение для фитнеса.
- Среднее расстояние в направлении X между центром рамы и центром весла должно в основном стимулировать центральное положение покоя для лопатки
- Если игра была закончена искусственно из-за застоя, либо это должно иметь значительный отрицательный эффект, либо автоматически должно заставить фитнес быть 0.0; Я не уверен, какой случай будет лучше.
Я не уверен, как работать со всеми этими значениями, чтобы они влияли на общую пригодность соответственно.
Заранее благодарим за любую помощь, которую вы можете предоставить.
Ответы
Ответ 1
Я бы минимизировал условную логику в вашей фитнес-функции, используя ее только в тех случаях, когда вы хотите, чтобы показатель пригодности составлял 0 или серьезный штраф. Я бы просто решил, сколько веса каждый компонент оценки должен иметь и умножать. Отрицательные компоненты просто добавляют сложность для понимания функции фитнеса, без реальной выгоды; модель учится на относительной разнице в оценках. Поэтому моя версия функции будет выглядеть примерно так:
def fitness(...):
if total_hits == 0:
return 0
return (game_score/max_score) * .7 \
+ game_score/total_hits * .2 \
+ game_score_per_life/hits_per_life * .1
(Кроме того: я не включал "расстояние от центра кадра", потому что думаю, что обманывать, если оставаться рядом с центром - это хорошо, чтобы максимизировать эффективность игры, тогда агент должен узнать, что у него есть. Если вы проникнете весь интеллект в функцию фитнеса, ваш агент вообще не умный.)