• Как исправить неправильное обновление весов в реализации back propagation?

    riZe_0
    @riZe_0 Автор вопроса
    Смог решить проблему. Ошибка оказалась в двух местах:

    1. Неправильно обновлял входные веса:
    self.weights_input_hidden -= theta * hidden_delta * X

    В переменной hidden_delta хранился вектор, который получался при перемножении вектора ошибок с учетом bias на выходные значения скрытого слоя.
    По идее получалось так, что когда я обновлял входные веса, я еще распространял ошибку смещения скрытого слоя, когда его учитывать не надо было.

    2. После обучения нейронной сети:
    for i in range(len(y)):
        xor.train(X[i], y[i], 10000)

    Здесь я брал один объект и передавал в функцию train, где один объект проходил по циклу:
    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)

    Получилось так, что один объект мог обучаться 10 тысяч раз, и каждый раз веса всей сети менялись для одного объекта.

    В итоге исправленный код будет выглядеть так:
    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
    
        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)
            self.hidden_layer_output_bias = np.concatenate((self.hidden_layer_output, [-1])) # Добавил bias для скр.слоя
            
            self.output_layer_activation = np.dot(self.weights_hidden_output, self.hidden_layer_output_bias)
            output = self.sigmoid(self.output_layer_activation)
            
            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 @ self.weights_hidden_output
            hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden_layer_output_bias)
    
            self.weights_hidden_output -= (output_delta * self.hidden_layer_output_bias) * theta
            self.weights_input_hidden -= (X.reshape(3, 1) * hidden_delta[:-1]).T * theta
            
        def train(self, X, y, theta=0.1):
            output = self.feedforward(X)
            self.back_prop(X, y, output, theta)
                    
            
    X = np.array([[0, 0, -1],
                  [0, 1, -1],
                  [1, 0, -1],
                  [1, 1, -1]])
    
    y = np.array([[0], [1], [1], [0]]) 
    
    xor = NeuralNetwork(2, 2, 1)
    epochs = 10000
    
    for epoch in range(epochs):
        for i in range(len(X)):
            xor.train(X[i], y[i])
    
    for x in X:
        print(f"{x} -> {xor.feedforward(x)}")
    Ответ написан
    Комментировать