0

我收到此索引的超出范围错误。我明白错误在说什么,我正在调用一个不在索引中的值。但我不明白为什么这么说。我已经添加了代码以及最后有问题的部分。

from game import *
import math as math
import random as rand

class RandomPlayer:

    def __init__(self, i):
        self.i = i

    def get_move(self, board, snake):
        r = rand.randint(0,3)
        return MOVES[r]

class GeneticPlayer:

    def __init__(self, pop_size, num_generations, num_trails, window_size, hidden_size, board_size, mutation_chance=0.1, mutation_size=0.1):
            self.pop_size = pop_size
            self.num_generations = num_generations
            self.num_trails = num_trails
            self.window_size = window_size
            self.hidden_size = hidden_size
            self.board_size = board_size

            self.mutation_chance = mutation_chance
            self.mutation_size = mutation_size

            self.display = False

            self.current_brain = None
            self.pop = [self.generate_brain(self.window_size**2, self.hidden_size, len(MOVES)) for _ in range(self.pop_size)]

    def generate_brain(self, input_size, hidden_size, output_size):
        hidden_layer1 = np.array([[rand.uniform(-1, 1) for _ in range(input_size + 1)] for _ in range(hidden_size)])
        hidden_layer2 = np.array([[rand.uniform(-1, 1) for _ in range(hidden_size + 1)] for _ in range(hidden_size)])
        output_layer = np.array([[rand.uniform(-1, 1) for _ in range(hidden_size + 1)] for _ in range(output_size)])
        return[hidden_layer1, hidden_layer2, output_layer]

    def get_move(self, board, snake):
        input_vector = self.proccess_board(board, snake[-1][0], snake[-1][1], snake[-2][0], snake[-2][1])
        hidden_layer1 = self.current_brain[0]
        hidden_layer2 = self.current_brain[1]
        output_layer = self.current_brain[2]

        hidden_result1 = np.array([math.tanh(np.dot(input_vector, hidden_layer1[i])) for i in range(hidden_layer1.shape[0])] + [1])
        hidden_result2 = np.array([math.tanh(np.dot(hidden_result1, hidden_layer2[i])) for i in range(hidden_layer2.shape[0])] + [1])
        output_result = np.array([np.dot(hidden_result2, output_layer[i]) for i in range(output_layer.shape[0])])

        max_index = np.argmax(output_result)
        return MOVES[max_index]

    def proccess_board(self, board, x1, y1, x2, y2):
        input_vector = [[0 for _ in range(self.window_size)] for _ in range(self.window_size)]

        for i in range(self.window_size):
            for j in range(self.window_size):
                ii = x1 + i - self.window_size//2
                jj = y1 + j - self.window_size//2

                if ii < 0 or jj < 0 or ii >= self.board_size or jj >= self.board_size:
                    input_vector[i][j] = -1
                elif board[ii][jj] == FOOD:
                    input_vector[i][j] = 1
                elif board[ii][jj] == EMPTY:
                    input_vector[i][j] = 0
                else:
                    input_vector[i][j] = -1
            if self.display:
                print(np.array(input_vector))
            input_vector = list(np.array(input_vector).flatten()) + [1]
            return np.array(input_vector)

    def reproduce(self, top_25):
        new_pop = []
        for brain in top_25:
                new_pop.append(brain)
        for brain in top_25:
            new_brain = self.mutate(brain)
            new_pop.append(new_brain)
        for _ in range(self.pop_size//2):
            new_pop.append(self.generate_brain(self.window_size**2, self.hidden_size, len(MOVES)))
        return new_pop

    def mutate(self, brain):
        new_brain = []
        for layer in brain:
                new_layer = np.copy(layer)
                for i in range(new_layer.shape[0]):
                    for j in range(new_layer.shape[1]):
                        if rand.uniform(0,1) < self.mutation_chance:
                            new_layer[i][j] += rand.uniform(-1,1)*self.mutation_size
                new_brain.append(new_layer)
                return new_brain

    def one_generation(self):
        scores = [0 for _ in range(self.pop_size)]

        max_score = 0
        for i in range(self.pop_size):
            for j in range(self.num_trails):
                self.current_brain = self.pop[i]
                game = Game(self.board_size, 1, [self])
                outcome = game.play(False, termination=True)
                score = len(game.snakes[0])
                scores[i] += score

                if outcome == 0:
                    print("Snake", i, "made it to the last turn")

                if score > max_score:
                    max_score = score
                    print(max_score, "at ID", i)

        top_25_indexes = list(np.argsort(scores))[3*(self.pop_size//4):self.pop_size]

        print(scores)
        top_25 = [self.pop[i] for i in top_25_indexes][::-1]
        self.pop = self.reproduce(top_25)

    def evolve_pop(self):
        for i in range(self.num_generations):
            self.one_generation()
            print("gen", i)

        key = input("enter any character to display boards")
        for brain in self.pop:
            self.display = True
            self.current_brain = brain
            game = Game(self.board_size, 1, [self], display=True)
            gui = Gui(game, 800)
            game.play(True, termination=True)
            print("Snake length", len(game.snakes[0]))

当前的大脑指数是给我错误的那个

def get_move(self, board, snake):
        input_vector = self.proccess_board(board, snake[-1][0], snake[-1][1], snake[-2][0], snake[-2][1])
        hidden_layer1 = self.current_brain[0]
        hidden_layer2 = self.current_brain[1]
        output_layer = self.current_brain[2]

        hidden_result1 = np.array([math.tanh(np.dot(input_vector, hidden_layer1[i])) for i in range(hidden_layer1.shape[0])] + [1])
        hidden_result2 = np.array([math.tanh(np.dot(hidden_result1, hidden_layer2[i])) for i in range(hidden_layer2.shape[0])] + [1])
        output_result = np.array([np.dot(hidden_result2, output_layer[i]) for i in range(output_layer.shape[0])])

        max_index = np.argmax(output_result)
        return MOVES[max_index]

这是堆栈跟踪

Traceback (most recent call last):
  File "C:\Users\samue\Documents\snake\main.py", line 19, in <module>
    gen_player.evolve_pop()
  File "C:\Users\samue\Documents\snake\players.py", line 122, in evolve_pop
    self.one_generation()
  File "C:\Users\samue\Documents\snake\players.py", line 103, in one_generation
    outcome = game.play(False, termination=True)
  File "C:\Users\samue\Documents\snake\game.py", line 106, in play
    moves = self.move()
  File "C:\Users\samue\Documents\snake\game.py", line 51, in move
    move_i = self.players[i].get_move(self.board, snake_i)
  File "C:\Users\samue\Documents\snake\players.py", line 42, in get_move
    hidden_layer2 = self.current_brain[1]
4

1 回答 1

0

问题是第二代人口的成员没有正确形成。这是由于mutate函数中的错误而发生的。目前,变异的“大脑”只有一个列表元素,因为 for 循环提前退出。这是由return new_brain线的位置引起的。更改最后一行的缩进应该可以解决它。

def mutate(self, brain):
    new_brain = []
    for layer in brain:
        new_layer = np.copy(layer)
        for i in range(new_layer.shape[0]):
            for j in range(new_layer.shape[1]):
                if rand.uniform(0, 1) < self.mutation_chance:
                    new_layer[i][j] += rand.uniform(-1, 1) * self.mutation_size
        new_brain.append(new_layer)
    return new_brain  # <---- DEDENT THIS LINE

此外,有两件事可能有助于防止未来出现此类错误:

  1. 当你的函数开始变得过于嵌套时,将它分解成更小的部分
  2. 使用列表推导并使用内置库函数,这样它就不会太嵌套

在这种情况下,我可能会将逻辑重写为 amutate_brain和这样的mutate_layer函数:

import itertools


def mutate_layer(self, layer):
    # start with a non-mutated copy
    new_layer = np.copy(layer)

    # iterate through each cell of the layer
    rows = new_layer.shape[0]
    cols = new_layer.shape[1]
    for i, j in itertools.product(range(rows), range(cols)):
        # the cell has an independent random chance of mutating
        if rand.uniform(0, 1) < self.mutation_chance:
            new_layer[i][j] += rand.uniform(-1, 1) * self.mutation_size

    return new_layer


def mutate_brain(self, brain):
    return [mutate_layer(layer) for layer in brain]
于 2020-12-31T03:11:20.843 回答