Баг нейросети. Как решить?

Я сделал нейронную сеть, которая играет в змейку. На вход нейросети я даю координаты змейки и координаты еды, а на выходе должен получить направление. Т.е на выходе 2 нейрона, один отвечает за направление по координате y(0 - вниз, 1 - вверх), а второй, соответственно за направление по координате x(0 - влево, 1 - вправо). Но когда я запускаю игру, то нейросеть сначала нормально работает, но змейка начинает ползать по кругу. Как решить проблему?
Я новичок, так что не бейте сильно :)
Вот код:

import pygame
import random
import numpy as np

# AI
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt

# model = keras.models.load_model('aisnake.h5')

x_train = []
y_train = []

for i in range(1001):
    snake_x = random.randrange(10, 630, 10)
    food_x = random.randrange(10, 630, 10)
    snake_y = random.randrange(10, 470, 10)
    food_y = random.randrange(10, 470, 10)
    # right - 1 | left - 0
    # up -1 | down - 0
    if snake_x > food_x:
        if snake_y > food_y:
            result_x = 0
            result_y = 1
            x_train.append([1/snake_x, 1/food_x, 1/snake_y, 1/food_y])
            y_train.append([result_x, result_y])
    elif snake_x < food_x:
        if snake_y < food_y:
            result_x = 1
            result_y = 0
            x_train.append([1/snake_x, 1/food_x, 1/snake_y, 1/food_y])
            y_train.append([result_x, result_y])
    elif snake_x == food_x and snake_y == food_y:
        continue
    elif snake_x == food_x or snake_y == food_y:
        continue

x_train = np.array(x_train)
y_train = np.array(y_train)

model = keras.Sequential()
model.add(layers.Dense(2, input_shape=(4,), activation="sigmoid"))
model.add(layers.Dense(2, activation="sigmoid"))
model.add(layers.Dense(2))
opt = keras.optimizers.Adam(learning_rate=0.1)
 
model.compile(
    optimizer=opt,
    loss='mse',
    metrics=["accuracy"])
 
history = model.fit( x_train, y_train, batch_size=100, epochs=1000)

plt.plot(history.history['loss'], label='Ошибок')
plt.plot(history.history['accuracy'], label='Угадываний')
plt.xlabel('Эпоха обучения')
plt.ylabel('Значение')
plt.legend()
plt.show()
# model.save('aisnake.h5')

# initialize pygame
pygame.init()

# create display & run update
width = 640
height = 480
display = pygame.display.set_mode((width, height))

pygame.display.update()
pygame.display.set_caption("AIsnake by Ovsyanka")

# define colors
colors = {
    "snake_head": (0, 200, 0),
    "snake_tail": (102, 102, 51),
    "apple": (255, 0, 0)
}

# snake position with offsets
snake_pos = {
    "x": width/2-10,
    "y": height/2-10,
    "x_change": 0,
    "y_change": 0
}

# snake el size
snake_size = (10, 10)

# current snake movement speed
snake_speed = 10

# snake tails
snake_tails = []

for i in range(3):
    snake_tails.append([snake_pos["x"] + 10*i, snake_pos["y"]])

# food
food_pos = {
    "x": round(random.randrange(0, width - snake_size[0]) / 10) * 10,
    "y": round(random.randrange(0, height - snake_size[1]) / 10) * 10,
}

food_size = (10, 10)
food_eaten = 0

# mode
AI = 1

# score
score = 0
pygame.display.set_caption("AIsnake by Ovsyanka | SCORE = " + str(score))
pygame.display.update()

# start loop
game_end = False
clock = pygame.time.Clock()

while not game_end:
    # game loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_end = True
        elif AI == 0:
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT and snake_pos["x_change"] == 0:
                    # move left
                    snake_pos["x_change"] = -snake_speed
                    snake_pos["y_change"] = 0

                elif event.key == pygame.K_RIGHT and snake_pos["x_change"] == 0:
                    # move right
                    snake_pos["x_change"] = snake_speed
                    snake_pos["y_change"] = 0

                elif event.key == pygame.K_UP and snake_pos["y_change"] == 0:
                    # move up
                    snake_pos["x_change"] = 0
                    snake_pos["y_change"] = -snake_speed

                elif event.key == pygame.K_DOWN and snake_pos["y_change"] == 0:
                    # move down
                    snake_pos["x_change"] = 0
                    snake_pos["y_change"] = snake_speed
    # clear screen
    display.fill((51,51,51))

    # move snake tails
    ltx = snake_pos["x"]
    lty = snake_pos["y"]

    for i,v in enumerate(snake_tails):
        _ltx = snake_tails[i][0]
        _lty = snake_tails[i][1]

        snake_tails[i][0] = ltx
        snake_tails[i][1] = lty

        ltx = _ltx
        lty = _lty

    # draw snake tails
    for t in snake_tails:
        pygame.draw.rect(display, colors["snake_tail"], [
            t[0],
            t[1],
            snake_size[0],
            snake_size[1]])

    # draw snake
    snake_pos["x"] += snake_pos["x_change"]
    snake_pos["y"] += snake_pos["y_change"]

    # barrier
    if(snake_pos["x"] < 0 or snake_pos["x"] > 630):
        print('Вы врезались в стену!')
        print('Максимальный рекорд: ' + str(score))
        quit = True
    
    if(snake_pos["y"] < 0 or snake_pos["y"] > 470):
        print('Вы врезались в стену!')
        print('Максимальный рекорд: ' + str(score))
        quit = True
    
    pygame.draw.rect(display, colors["snake_head"], [
        snake_pos["x"],
        snake_pos["y"],
        snake_size[0],
        snake_size[1]])

    # draw food
    for i, v in enumerate(snake_tails):
        if(snake_pos["x"]+snake_pos["x_change"] == snake_tails[i][0]
                and snake_pos["y"]+snake_pos["y_change"] == snake_tails[i][1]):
                    food_pos.clear()
                    food_pos = {
                        "x": round(random.randrange(0, width - snake_size[0]) / 10) * 10,
                        "y": round(random.randrange(0, height - snake_size[1]) / 10) * 10,
                    }
    pygame.draw.rect(display, colors["apple"], [
        food_pos["x"],
        food_pos["y"],
        food_size[0],
        food_size[1]])

    if AI == 1:
        pred = model.predict(np.array([[1/snake_pos['x'], 1/food_pos['x'], 1/snake_pos['y'], 1/food_pos['y']]]))
        for i in pred:
            pred_x = i[0]
            print(pred_x)
            pred_y = i[1]
            print(pred_y)
            if pred_x > 0.5:
                pred_x = 1
            elif pred_x < 0.5:
                pred_x = 0
            if pred_y > 0.5:
                pred_y = 1
            elif pred_y < 0.5:
                pred_y = 0
        if pred_x == 1 and snake_pos["x_change"] == 0:
            # move right
            snake_pos["x_change"] = snake_speed
            snake_pos["y_change"] = 0
        elif pred_x == 0 and snake_pos["x_change"] == 0:
            # move left
            snake_pos["x_change"] = -snake_speed
            snake_pos["y_change"] = 0
        elif pred_y == 0 and snake_pos["y_change"] == 0:
            # move down
            snake_pos["x_change"] = 0
            snake_pos["y_change"] = snake_speed
        elif pred_y == 1 and snake_pos["y_change"] == 0:
            # move up
            snake_pos["x_change"] = 0
            snake_pos["y_change"] = -snake_speed

    # detect collision with food
    if(snake_pos["x"] == food_pos["x"]
        and snake_pos["y"] == food_pos["y"]):
        food_eaten += 1
        snake_tails.append([food_pos["x"], food_pos["y"]])

        food_pos = {
            "x": round(random.randrange(0, width - snake_size[0]) / 10) * 10,
            "y": round(random.randrange(0, height - snake_size[1]) / 10) * 10,
        }
        score += 1
        pygame.display.set_caption("AIsnake by Ovsyanka | SCORE = " + str(score))
        pygame.display.update()

    # detect collision with tail
    for i,v in enumerate(snake_tails):
        if(snake_pos["x"]+snake_pos["x_change"] == snake_tails[i][0]
            and snake_pos["y"]+snake_pos["y_change"] == snake_tails[i][1]):
            snake_tails = snake_tails[:i]
            print('Вы врезались в себя!')
            break

    pygame.display.update()
    
    # set FPS
    clock.tick(30)

# close app, if required
pygame.quit()
quit()

Ответы (1 шт):

Автор решения: Константин

Если выхода более 1-го надо ставить softmax на конце и оптимизацию binary_crossentropy.И хороший набор данных обеспечить.Я вообще против рандомного распределения.Но так нужно в keras больше работать, делать колбеки.И вообще я сейчас прототипирую свою сеть на основе разложения Фурье-она на простых примерах лучше показала чем keras даже с постоянной матрицой весов(сети).Так вот там например на 2 входа и 3 выхода-должна быть матрица сети:

W=[[1,2],
   [1,2],
   [1,2]]

И вообще должна обеспечиваться набором данных по комбинаторике(Фурье сеть это обходит),например для вектора логической операции И там 2 значения- и должно в сумме подаваться кейса 2^2=4. В keras если одного кейса не будет-будет неправильно отвечать на логическое И.Поэтому по правилу чтобы обучить сеть на картинке 32x32px (черно-белой 8-ми битовой) нужно 2^(32*32)=1_048_576 картинок.Поэтому не надо удивляться что ИНС без доработки - это полуфейк,соответственно и выводы ее.

→ Ссылка