Обратное распространение ошибки применяет цепное правило слой за слоем, от выхода обратно к входам. В сети n входов, h скрытых нейронов и один выход, все с сигмоидной активацией (σ(z) = 1 / (1 + e^(-z))):
- скрытый слой: a_j = σ(inputs · hidden_weights[j] + hidden_biases[j])
- выход: y = σ(a · output_weights + output_bias)
- потери: L = (y - target)²
Градиенты:
- delta_out = 2 × (y - target) × y × (1 - y)
- Выходной слой: dL/doutput_weights[j] = delta_out × a_j и dL/doutput_bias = delta_out
- delta_j = delta_out × output_weights[j] × a_j × (1 - a_j)
- Скрытый слой: dL/dhidden_weights[j][i] = delta_j × inputs[i] и dL/dhidden_biases[j] = delta_j
Реализуйте backprop_gradients(inputs, hidden_weights, hidden_biases, output_weights, output_bias, target).
Выходные данные
Верните матрицу из h + 1 строк:
- Строка j (для каждого скрытого нейрона j по порядку): n градиентов
hidden_weights[j], затем градиентhidden_biases[j]. - Последняя строка: h градиентов
output_weights, затем градиентoutput_bias.
Ограничения
1 ≤ n, h ≤ 20
-5 ≤ каждый вход, вес и смещение ≤ 5
0 ≤ target ≤ 1
Примеры
Ввод:
inputs = [1.0]
target = 1.0
output_bias = 0.0
hidden_biases = [0.0]
hidden_weights = [
[0.0]
]
output_weights = [0.0]
Ожидаемый вывод:
expected = [
[0.0, 0.0],
[-0.125, -0.25]
]
Ввод:
std::vector<double> inputs = {1.0};
double target = 1.0;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0};
std::vector<std::vector<double>> hidden_weights = {
{0.0}
};
std::vector<double> output_weights = {0.0};
Ожидаемый вывод:
std::vector<std::vector<double>> expected = {
{0.0, 0.0},
{-0.125, -0.25}
};
Ввод:
double[] inputs = new double[] {1.0};
double target = 1.0;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0};
double[][] hidden_weights = new double[][] {
new double[] {0.0}
};
double[] output_weights = new double[] {0.0};
Ожидаемый вывод:
double[][] expected = new double[][] {
new double[] {0.0, 0.0},
new double[] {-0.125, -0.25}
};
Пояснение
a = σ(0) = 0.5 и y = σ(0) = 0.5. delta_out = 2 × (0.5 - 1) × 0.25 = -0.25. Строка выхода: [-0.25 × 0.5, -0.25] = [-0.125, -0.25]. delta_1 = -0.25 × 0 × 0.25 = 0, поэтому скрытая строка равна [0, 0]: нулевой выходной вес блокирует градиент.
Ввод:
inputs = [1.0, 0.0]
target = 0.0
output_bias = -1.0
hidden_biases = [0.0, 0.0]
hidden_weights = [
[0.0, 1.0],
[0.0, -1.0]
]
output_weights = [1.0, 1.0]
Ожидаемый вывод:
expected = [
[0.0625, 0.0, 0.0625],
[0.0625, 0.0, 0.0625],
[0.125, 0.125, 0.25]
]
Ввод:
std::vector<double> inputs = {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
std::vector<double> hidden_biases = {0.0, 0.0};
std::vector<std::vector<double>> hidden_weights = {
{0.0, 1.0},
{0.0, -1.0}
};
std::vector<double> output_weights = {1.0, 1.0};
Ожидаемый вывод:
std::vector<std::vector<double>> expected = {
{0.0625, 0.0, 0.0625},
{0.0625, 0.0, 0.0625},
{0.125, 0.125, 0.25}
};
Ввод:
double[] inputs = new double[] {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
double[] hidden_biases = new double[] {0.0, 0.0};
double[][] hidden_weights = new double[][] {
new double[] {0.0, 1.0},
new double[] {0.0, -1.0}
};
double[] output_weights = new double[] {1.0, 1.0};
Ожидаемый вывод:
double[][] expected = new double[][] {
new double[] {0.0625, 0.0, 0.0625},
new double[] {0.0625, 0.0, 0.0625},
new double[] {0.125, 0.125, 0.25}
};
Пояснение
Оба скрытых значения равны σ(0) = 0.5, поэтому y = σ(0.5 + 0.5 - 1) = 0.5 и delta_out = 2 × 0.5 × 0.25 = 0.25. Строка выхода: [0.125, 0.125, 0.25]. Каждое delta_j = 0.25 × 1 × 0.25 = 0.0625, что даёт скрытые строки [0.0625, 0, 0.0625] (второй вход равен 0).
Как подступиться
Сначала попробуйте сами, затем открывайте подсказки по одной.
Подсказка 1
Начните с выходного нейрона, а затем используйте этот сигнал, чтобы вычислить вклад каждого hidden neuron.
Подсказка 2
Нужен один delta для выходного слоя и один delta для каждого hidden neuron, оба на основе производных sigmoid.
Подсказка 3
Будьте внимательны и используйте собственный выходной вес каждого hidden neuron при обратном распространении ошибки к нему.
Ожидаемая сложность
время O(hn), доп. память O(hn)
Ссылки
Это задание адаптировано для CodeUtility. Следуйте условию и ограничениям выше.