Я хочу создать простой перцептрон с нуля в 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
в других частях программы.