Обратное распространение и формы векторов не подходят - PullRequest
0 голосов
/ 30 января 2019

Это может быть глупый вопрос, но я застрял.Я пытаюсь написать простую нейронную сеть с прямой связью на Python.Мои входные, весовые и выходные слои объявляются так:

self.inp = np.zeros(21)
self.weights1 = np.random.rand(self.inp.shape[0],15) 
self.weights2 = np.random.rand(15, 15)
self.layer1 = self.sigmoid(np.dot(self.inp, self.weights1))
self.output = self.sigmoid(np.dot(self.layer1, self.weights2))

Сейчас я пытаюсь распространять данные, но размеры моих векторов не подходят.Вот моя функция backpropagate:

def backpropagate(self, dice, board):
    y = argmax(dice, self.moves)
    d_weights2 = np.dot(self.layer1.T, (2*(y - self.output) * self.sigmoidDerivative(self.output)))
    d_weights1 = np.dot(self.inp.T,  (np.dot(2*(y - self.output) * self.sigmoidDerivative(self.output), self.weights2.T) * self.sigmoidDerivative(self.layer1)))

    self.weights1 += d_weights1
    self.weights2 += d_weights2

Я получаю ошибку при вычислении d_weights1.Ошибка:

ValueError: shapes (21,) and (15,) not aligned: 21 (dim 0) != 15 (dim 0)

Как мне подогнать свои векторы?

Заранее спасибо!

РЕДАКТИРОВАТЬ:

По запросу, вотВесь класс:

import numpy as np
from TestValues import argmax, testfunctions, zero

class AI:

    def __init__(self):
        self.moves = []
        self.inp = np.zeros(21)
        self.weights1 = np.random.rand(self.inp.shape[0],21) 
        self.weights2 = np.random.rand(21, 15)
        self.output = np.zeros(15)

    def getPlacement(self, dice, board):
        self.feedforward(dice, board)
        self.backpropagate(dice, board)
        result = self.output
        for x in self.moves:
            result[x] = -1.
        move = np.argmax(result)
        self.moves.append(move)
        return move

    def feedforward(self, dice, board):
        i = 0
        for x in dice:
            self.inp[i] = x
            i += 1
        for x in board:
            self.inp[i] = x
            i += 1

        self.layer1 = self.sigmoid(np.dot(self.inp, self.weights1))
        self.output = self.sigmoid(np.dot(self.layer1, self.weights2))

    def backpropagate(self, dice, board):

        y = argmax(dice, self.moves)

        d_weights2 = np.dot(self.layer1.T, np.dot(2*(y - self.output), self.sigmoidDerivative(self.output)))
        d_weights1 = np.dot(self.inp.T,  (np.dot(2*(y - self.output) * self.sigmoidDerivative(self.output), self.weights2.T) * self.sigmoidDerivative(self.layer1)))

        print(self.weights2.shape)

        self.weights1 += d_weights1
        self.weights2 += d_weights2

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def sigmoidDerivative(self, x):
        return self.sigmoid(x) * (1 - self.sigmoid(x))

1 Ответ

0 голосов
/ 30 января 2019

Кажется, проблема в том, как вы инициализируете свой ввод.Вы производите массив формы (21,), а не (1, 21).Если вы планируете одновременно распространять множество обучающих примеров, это может стать очевидным в какой-то момент.Кроме того, часто бывает полезно попытаться отладить формы этих результирующих матриц.Мой d_weights2 был, например, один скаляр.И если вы не знакомы с матричной алгеброй, это очень полезно для понимания точечных произведений и того, что должно получиться.

Итак, проще говоря, просто инициализируйте так:

inp = np.zeros((1, 21))

Это дало мне разумные формы.


Кроме того, хотя и не CodeReview, я вынужден сказать что-то о вашем коде.Не повторяйся.При обратном распространении вы можете сначала рассчитать ошибку на уровне и использовать ее в обоих обновлениях.error = 2*(output - y) * d_logistic(output) Это также немного упростит ситуацию, если вы планируете расширить сеть, чтобы иметь любой произвольный размер, а не только два слоя.

И еще одна вещь, ваши функции sigmoid и sigmoidDerivative имеютбесполезно в классе.Попробуйте сделать их чистыми функциями, а не методами класса.

...