Есть реализация логической операции XOR с помощью нейронной сети, обучение - back propagation, язык - python:
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.weights_input_hidden = np.random.rand(input_size + 1, hidden_size).T
self.weights_hidden_output = np.random.rand(hidden_size + 1, output_size).T
#print('Веса входного слоя (weights_input)=\n', self.weights_input_hidden) # w_jh
#print('Веса выходного слоя (weights_hidden)=\n', self.weights_hidden_output, '\n') # w_hm
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
return x * (1 - x)
# Прямой ход
def feedforward(self, X):
self.hidden_layer_activation = np.dot(self.weights_input_hidden, X)
self.hidden_layer_output = self.sigmoid(self.hidden_layer_activation) # u_h / sigma_h
self.hidden_layer_output_bias = np.concatenate((self.hidden_layer_output, [-1]))
self.output_layer_activation = np.dot(self.weights_hidden_output, self.hidden_layer_output_bias)
output = self.sigmoid(self.output_layer_activation) # a_m / sigma_m
return output
# Обратный ход
def back_prop(self, X, y, output, theta):
output_error = output - y
output_delta = output_error * self.sigmoid_derivative(output)
hidden_error = output_delta.dot(self.weights_hidden_output)
hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden_layer_output_bias)
self.weights_hidden_output -= theta * output_delta * self.hidden_layer_output_bias
self.weights_input_hidden -= theta * hidden_delta * X
def train(self, X, y, epochs, theta=0.01):
X = np.concatenate((X, [-1]))
for epoch in range(epochs):
output = self.feedforward(X)
self.back_prop(X, y, output, theta)
X = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
y = np.array([[0], [1], [1], [0]])
xor = NeuralNetwork(2, 2, 1)
for i in range(len(y)):
xor.train(X[i], y[i], 10000)
for x in X:
x = np.concatenate((x, [-1]))
print(f"{x} -> {xor.feedforward(x)}")
Проблема:
После обучения сети получается неправильный ответ (если значение xor.feedforward > 0.5, 1, 0). Пробовал вариант с добавлением смещения в виде отдельной переменной, пробовал даже без самого смещения - ответ неверный.
Подозреваю, что проблема в обновлении весов в функции back_prop, но где именно и почему я понять не в состоянии. Чувствую, что ответ лежит на поверхности.
Теорию брал из лекций К.В.Воронцова 2014 года на youtube.
Сам алгоритм из лекции: