Реализация алгоритма обратного распространения для простой нейронной сети в python - PullRequest
0 голосов
/ 01 апреля 2020

Я прошел главы 1 и 2 этой книги и попытался написать свой собственный трехслойный NN со ссылками на код, который я получил, когда у меня возникли проблемы.

Вы можно увидеть код ниже для NN. Когда я запускаю его, я получаю неправильную ошибку измерения для точечного произведения в строке:

dw[-1] = np.dot(np.asmatrix(db[-1]), np.asmatrix(self.a[-2]).transpose()).

Это третье последнее уравнение в нижней части вопроса.

ValueError : формы (1,10) и (16,1) не выровнены: 10 (тусклый 1)! = 16 (тусклый 0).

Я не вижу, где я ошибся в Реализация

Из структуры сети я могу заранее определить, какие размеры матриц следует ожидать для параметров, используемых для расчетов. т.е. количество нейронов в слоях 1, 2 и 3: n = 784, 16, 10. Весовые матрицы в слоях 2 и 3: w = [16, 784], [10, 16]. Векторы смещения для слоев 2 и 3: b = [16, 1], [10, 1]. Взвешенные итоговые входные данные для слоев 2 и 3: z = [16, 1], [10, 1]. Векторы градиента для весов: dw = [16, 784], [10, 16] и векторы градиента для смещений: db = [16, 1], [10, 1]. Размеры для выходных массивов активации для слоев 1, 2 и 3 будут: a = [784, 1], [16, 1], [10, 1]

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

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

import random
import numpy as np


class NeuralNetwork:

    def __init__(self, inputs, targets, hidden, n_outputs, learning_rate, epochs, batch_size):

        # training and testing data
        self.training_inputs = inputs  # network inputs
        self.targets = targets  # target outputs for the training data
        self.n_data = len(self.training_inputs)  # number of training data

        # network structure
        self.n_inputs = len(self.training_inputs[0])  # number of input nodes
        self.hidden_layers = hidden  # list containing the number of neurons in each hidden layer. Layer number is the index.
        self.n_outputs = n_outputs  # number of outputs in the final layer
        n_nuerons = [[self.n_inputs], self.hidden_layers, [self.n_outputs]]
        self.layers = [x for s in n_nuerons for x in s]  # list of the number of neurons in each layer. Layer number is the index
        self.n_layers = len(self.layers)  # number of layers in the network

        # hyperparameters
        self.learning_rate = learning_rate
        self.epochs = epochs
        self.batch_size = batch_size  # batching is not implemented yet.. using online learning

        # initialise matrices
        self.b, self.z = [], []
        for neurons in self.layers[1:]:  # loop through all layers except the input network layer
            self.b.append(np.random.randn(neurons))  # biases
            self.z.append(np.zeros(neurons))  # layer weighted sum inputs
        self.a = [np.zeros(n) for n in self.layers]  # activation outputs - including inputs to network as activation outputs for layer 0
        self.w = [np.random.rand(self.layers[i + 1], self.layers[i]) - 0.5 for i in range(self.n_layers - 1)]  # weights

        self.train()

    def train(self):
        for epoch in range(self.epochs):
            random.shuffle(self.training_inputs)
            sum_error = 0
            for index in range(self.n_data):
                # forward pass
                x = self.training_inputs[index]
                self.a[0] = x
                outputs = self.feedforward(x)
                sum_error += sum(self.cost(outputs, index))
                # backward pass
                dw, db = self.backpropagation(index)
                self.update_weights(dw, db)
            print('>epoch=%d, error=%.3f' % (epoch, sum_error))

    def feedforward(self, output):
        for layer in range(self.n_layers - 1):
            self.z[layer] = np.dot(self.w[layer], self.a[layer]) + self.b[layer]  # layer inputs
            self.a[layer + 1] = self.sigmoid(self.z[layer])  # output activations
        return self.a[-1]

    def backpropagation(self, index):
        # initialise gradient matrices
        dw = [np.zeros(w.shape) for w in self.w]
        db = [np.zeros(n) for n in self.layers[1:]]

        # loop backwards through network layers
        for i in reversed(range(1, self.n_layers)):
            if i == self.n_layers - 1:
                # output layer
                db[-1] = (self.a[-1] - self.targets[index]) * self.sp(self.z[-1])
                dw[-1] = np.dot(np.asmatrix(db[-1]), np.asmatrix(self.a[-2]).transpose())
            else:
                # all other layers
                # NOTE: to compute the weight gradient vector for hidden layer 1 the inputs to the network are used as activation outputs
                db[i - 1] = np.multiply(np.dot(np.transpose(self.w[i]), db[i]), self.sp(self.z[i - 1]))
                dw[i - 1] = np.dot(np.asmatrix(db[i - 1]), np.asmatrix(self.a[i - 2]).transpose())

        return dw, db

    def update_weights(self, dw, db):
        self.w = np.array([w - self.learning_rate * nw for w, nw in zip(self.w, dw)])
        self.b = np.array([b - self.learning_rate * nb for b, nb in zip(self.b, db)])

    def cost(self, outputs, index):
        return (self.targets[index] - outputs) ** 2

    @staticmethod
    def sigmoid(z):
        return 1 / (1 + np.exp(-z))

    @staticmethod
    def sp(z):
        return z * (1.0 - z)


# Program driver
if __name__ == '__main__':
    data = np.load('mnist.npz')
    (training_images, test_images) = data['x_train'], data['x_test']
    (training_labels, test_labels) = data['y_train'], data['y_test']
    n_outputs = 10
    training_inputs = np.array([data.flatten() / 255 for data in training_images])
    training_targets = []
    for i in range(len(training_labels)):
        training_targets.append([1 if training_labels[i] == x else 0 for x in range(n_outputs)])
    nn = nn.NeuralNetwork(training_inputs, np.array(training_targets), [16], n_outputs, learning_rate=0.1, epochs=10, batch_size=100)

Backpropagation equations

Код включен github с включенным мнистом для всех, кому это может понадобиться. Любые комментарии, исправления, критика, все и вся приветствуются с целью изучения .. Спасибо!

...