Почему эта функция обратного распространения из нейронной сети в python 3.7 не работает? - PullRequest
0 голосов
/ 10 февраля 2020

Я хочу создать простой перцептрон с нуля в python, чтобы попытаться понять механизм, лежащий в основе нейронных сетей.

класс нейросети:

import numpy as np


def sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))


def sigmoid_derivative(x):
    return sigmoid(x) * (1 - sigmoid(x))


def cost_derivative(output_activations, label):
    return output_activations - label


class NeuralNetwork:

    def __init__(self, layer_sizes):
        weight_shapes = [(a, b) for a, b in zip(layer_sizes[1:], layer_sizes[:-1])]
        self.num_layers = len(layer_sizes)
        self.weights = [np.random.standard_normal(s) / s[1] ** .5 for s in weight_shapes]
        self.biases = [np.zeros((s, 1)) for s in layer_sizes[1:]]

    def forward(self, images):
        for w, b in zip(self.weights, self.biases):
            images = sigmoid(np.matmul(w, images) + b)
        return images

    def backward(self, image, label):
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        nabla_b = [np.zeros(b.shape) for b in self.biases]

        activation = image
        activations = [image]
        zs = []
        for w, b in zip(self.weights, self.biases):
            z = np.matmul(w, activation) + b
            zs.append(z)
            activation = sigmoid(z)
            activations.append(activation)

        delta = cost_derivative(activations[-1], label) * sigmoid_derivative(zs[-1])
        nabla_b[-1] = delta
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())

        for layer in range(2, self.num_layers):
            z = zs[-1]
            sp = sigmoid_derivative(z)
            delta = np.dot(self.weights[-layer + 1].transpose(), delta) * sp
            nabla_w[-1] = np.dot(delta, activations[-layer - 1].transpose())
            nabla_b[-1] = delta

        return nabla_w, nabla_b

    def update(self, images, labels, learning_rate):
        nable_w = [np.zeros(w.shape) for w in self.weights]
        nable_b = [np.zeros(b.shape) for b in self.biases]
        for i, l in zip(images, labels):
            delta_nabla_w, delta_nabla_b = self.backward(i, l)
            nable_w = [nw + dnw for nw, dnw in zip(nable_w, delta_nabla_w)]
            nable_b = [nb + dnb for nb, dnb in zip(nable_b, delta_nabla_b)]
        self.weights = [w - (learning_rate / len(images)) * nw for w, nw in zip(self.weights, nable_w)]
        self.biases = [b - (learning_rate / len(images)) * nb for b, nb in zip(self.biases, nable_b)]

    def train(self, images, labels, epochs, learning_rate):
        for e in range(epochs):
            self.update(images, labels, learning_rate)
            print('Epoch {0} completed'.format(e))

    def evaluate(self, images, labels):
        predictions = self.forward(images)
        num_correct = sum([np.argmax(a) == np.argmax(b) for a, b in zip(predictions, labels)])
        print('{0}/{1} accuracy: {2}%'.format(num_correct, len(images), (num_correct / len(images)) * 100))

класс программы:

import basic_neural_network.neuralnetwork as nn
import numpy as np

with np.load('mnist.npz') as data:
    training_images = data['training_images']
    training_labels = data['training_labels']
    test_images = data['test_images']
    test_labels = data['test_labels']

layer_size = (784, 16, 16, 10)

net = nn.NeuralNetwork(layer_size)
net.train(training_images, training_labels, 10, 0.1)
print(net.evaluate(test_images, test_labels))

Этот код основан на серии YouTube (https://www.youtube.com/watch?v=bVQUSndDllU) и git репозиторий-концентратор (https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network.py)

Каким-то образом вычисление в функции обратного распространения всегда выдает

ValueError: operands could not be broadcast together with shapes (16,1) (10,1)

Through простое наблюдение Я вижу, что sp и np.dot(self.weights[-layer + 1].transpose(), delta) в строке 49 нельзя умножать вместе, так как их размеры не одинаковы. Эта разница связана с функцией sigmoid_derivative(z), поскольку z уже меньше np.dot(self.weights[-layer + 1].transpose(), delta). Но я не понимаю, почему это происходит, и где я ошибся, насколько я знаю, именно так предполагается рассчитывать обратное распространение.

Я пытался изменить 2 в for l oop в строке 46 до 4, что заставило его работать, но сеть не изменилась, после 600 эпох она все еще имела 10% успеха. И я попытался изменить индекс z = zs[-1] в строке 47, но это вызвало больше ValueErrors в других частях программы.

...