Можете ли вы предоставить реализацию логической операции XOR с использованием нейронной сети, обученной методом обратного распространения ошибки на языке Python?
Обновление весов в методе обратного распространения ошибки может быть подвержено ряду ошибок. Вот некоторые распространенные подходы для исправления этих ошибок: 1. **Правильный расчет градиентов**: Убедитесь, что вы правильно вычисляете градиенты функции потерь по отношению к весам. Используйте правила дифференцирования корректно. 2. **Скорость обучения (learning rate)**: Подберите подходящее значение скорости обучения. Слишком большое значение может привести к расходимости, а слишком малое - к очень медліному обучению. 3. **Инициализация весов**: Не забывайте правильно инициализировать веса. Часто используют случайные значения или методы, такие как Xavier или He инициализация. 4. **Регуляризация**: Избегайте переобучения, используя регуляризацию, такую как L1 или L2, чтобы контролировать величину весов. 5. **Улучшение алгоритма оптимизации**: Вместо стандартного градиентного спуска используйте продвинутые оптимизаторы, такие как Adam или RMSProp, которые могут адаптивно изменять скорость обучения. 6. **Нормализация данных**: Убедитесь, что входные данные нормализованы, чтобы улучшить сходимость. Теперь давайте реализуем логическую операцию XOR с помощью нейронной сети, обученной методом обратного распространения ошибки на Python. Мы будем использовать библиотеку NumPy. ```python import numpy as np # sigmoid функция и её производная def sigmoid(x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(x): return x * (1 - x) # Входные данные для XOR X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) # Выходные данные для XOR y = np.array([[0], [1], [1], [0]]) # Установка случайного генератора np.random.seed(42) # Инициализация весов input_layer_size = 2 hidden_layer_size = 2 output_layer_size = 1 weights_input_hidden = np.random.uniform(size=(input_layer_size, hidden_layer_size)) weights_hidden_output = np.random.uniform(size=(hidden_layer_size, output_layer_size)) # Обучение сети learning_rate = 0.5 epochs = 10000 for epoch in range(epochs): # Прямое распространение hidden_layer_input = np.dot(X, weights_input_hidden) hidden_layer_output = sigmoid(hidden_layer_input) output_layer_input = np.dot(hidden_layer_output, weights_hidden_output) predicted_output = sigmoid(output_layer_input) # Обратное распространение ошибки error = y - predicted_output d_predicted_output = error * sigmoid_derivative(predicted_output) error_hidden_layer = d_predicted_output.dot(weights_hidden_output.T) d_hidden_layer = error_hidden_layer * sigmoid_derivative(hidden_layer_output) # Обновление весов weights_hidden_output += hidden_layer_output.T.dot(d_predicted_output) * learning_rate weights_input_hidden += X.T.dot(d_hidden_layer) * learning_rate # Тестирование сети print("Выходные данные после обучения:") print(predicted_output) ``` В этом коде мы создаем простую нейронную сеть с одним скрытым слоем и обучаем ее на входах для операции XOR. Мы используем сигмоидную функцию активации и обновляем веса с использованием метода обратного распространения ошибки. После обучения выполняется вывод предсказанных значений. Если вы запустите этот код, вы увидите выходные данные, которые должны быть достаточно близки к ожидаемым результатам логической операции XOR (0, 1, 1, 0) для входных данных (0,0), (0,1), (1,0) и (1,1).
Смог решить проблему. Ошибка оказалась в двух местах:
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)}")