К списку задач
Сложно Решено: 0 Процент решений: 0%

Обучите нейросеть решать XOR

Соберите всё вместе: обучите сигмоидную сеть 2-2-1 обратным распространением, пока она не выучит XOR.

Чему вы научитесь

  • Обучать небольшую сеть от начала до конца
  • Понять, почему XOR нужен скрытый слой
  • Объединять прямой и обратный проходы

Условие

XOR (исключающее ИЛИ) — классическая задача, которую не может решить один нейрон, но может решить сеть с одним скрытым слоем. Обучите сеть с 2 входами, 2 скрытыми нейронами и 1 выходом, все сигмоидные (σ(z) = 1 / (1 + e^(-z))), с функцией потерь L = (y - target)².

Обучающие данные, которые в каждой эпохе всегда используются в этом порядке:

входtarget
[0, 0]0
[0, 1]1
[1, 0]1
[1, 1]0

Для каждого примера:

  1. Прямой проход: a_j = σ(x₁ × hidden_weights[j][0] + x₂ × hidden_weights[j][1] + hidden_biases[j]), y = σ(a₁ × output_weights[0] + a₂ × output_weights[1] + output_bias)
  2. delta_out = 2 × (y - target) × y × (1 - y) и delta_j = delta_out × output_weights[j] × a_j × (1 - a_j), с весами до обновления на этом примере
  3. Обновите каждый параметр со скоростью обучения lr: output_weights[j] -= lr × delta_out × a_j, output_bias -= lr × delta_out, hidden_weights[j][i] -= lr × delta_j × x_i, hidden_biases[j] -= lr × delta_j

Реализуйте train_xor(hidden_weights, hidden_biases, output_weights, output_bias, learning_rate, epochs).

Выходные данные

После обучения верните предсказания сети y для входов [0, 0], [0, 1], [1, 0] и [1, 1] в этом порядке.

Ограничения

0 ≤ epochs ≤ 5000

0 < learning_rate ≤ 5

-2 ≤ каждый начальный вес и смещение ≤ 2

Примеры

Пример 1
Ввод:
epochs = 0
output_bias = 0.0
hidden_biases = [0.0, 0.3]
learning_rate = 1.5
hidden_weights = [
    [0.2, 0.8],
    [0.9, -0.7]
]
output_weights = [-0.6, 0.4]

Ожидаемый вывод:
expected = [0.482451, 0.436972, 0.494378, 0.452729]
Ввод:
long long epochs = 0;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0, 0.3};
double learning_rate = 1.5;
std::vector<std::vector<double>> hidden_weights = {
    {0.2, 0.8},
    {0.9, -0.7}
};
std::vector<double> output_weights = {-0.6, 0.4};

Ожидаемый вывод:
std::vector<double> expected = {0.482451, 0.436972, 0.494378, 0.452729};
Ввод:
long epochs = 0;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0, 0.3};
double learning_rate = 1.5;
double[][] hidden_weights = new double[][] {
    new double[] {0.2, 0.8},
    new double[] {0.9, -0.7}
};
double[] output_weights = new double[] {-0.6, 0.4};

Ожидаемый вывод:
double[] expected = new double[] {0.482451, 0.436972, 0.494378, 0.452729};

Пояснение

При 0 эпох ничего не обучается, поэтому результат — это просто прямой проход с начальными весами: примерно [0.482, 0.437, 0.494, 0.453]. Необученная сеть даёт почти одинаковый ответ на любой вход.

Пример 2
Ввод:
epochs = 2000
output_bias = 0.0
hidden_biases = [0.0, 0.3]
learning_rate = 1.5
hidden_weights = [
    [0.2, 0.8],
    [0.9, -0.7]
]
output_weights = [-0.6, 0.4]

Ожидаемый вывод:
expected = [0.015727, 0.982119, 0.985515, 0.013682]
Ввод:
long long epochs = 2000;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0, 0.3};
double learning_rate = 1.5;
std::vector<std::vector<double>> hidden_weights = {
    {0.2, 0.8},
    {0.9, -0.7}
};
std::vector<double> output_weights = {-0.6, 0.4};

Ожидаемый вывод:
std::vector<double> expected = {0.015727, 0.982119, 0.985515, 0.013682};
Ввод:
long epochs = 2000;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0, 0.3};
double learning_rate = 1.5;
double[][] hidden_weights = new double[][] {
    new double[] {0.2, 0.8},
    new double[] {0.9, -0.7}
};
double[] output_weights = new double[] {-0.6, 0.4};

Ожидаемый вывод:
double[] expected = new double[] {0.015727, 0.982119, 0.985515, 0.013682};

Пояснение

После 2000 эпох предсказания примерно равны [0.016, 0.982, 0.986, 0.014]: низкие для [0, 0] и [1, 1], высокие для [0, 1] и [1, 0]. Сеть выучила XOR.

Как подступиться

Сначала попробуйте сами, затем открывайте подсказки по одной.

Подсказка 1

Обрабатывайте все четыре XOR-примера в одном и том же фиксированном порядке на каждой эпохе и сразу обновляйте параметры после каждого.

Подсказка 2

Сначала выполните прямой проход, затем распространите ошибку выхода назад в оба скрытых нейрона с текущими весами, и только потом применяйте обновления.

Подсказка 3

Следите за производной sigmoid и за тем, что обновления скрытого слоя зависят от значений входа, поэтому при нулевых входах часть весов не меняется.

Ожидаемая сложность

время O(epochs), доп. память O(1)

Ссылки

Это задание адаптировано для CodeUtility. Следуйте условию и ограничениям выше.

Учитесь у других

Решения сообщества

Пока нет опубликованных решений. Решите задание, чтобы поделиться первым.