Проблема затухающего и взрывного градиента

Затухающие и взрывные градиенты — фундаментальные проблемы при обучении многослойных нейронных сетей с использованием обратного распространения ошибки (backpropagation). В библиотеке Synaptic.js их проявление напрямую связано с архитектурой сети, выбором функций активации и инициализацией весов.

Механизм возникновения

При обучении сети методом обратного распространения ошибка, вычисленная на выходном слое, распространяется обратно через все слои сети. Обновление весов происходит по формуле:

[ w_{ij} = -]

где () — скорость обучения, (E) — функция ошибки. Производная функции активации (’(x)) участвует в расчёте градиента на каждом слое:

[ ^l = ’(z^l) (^{l+1} W^{l+1})]

Если (’(z^l)) принимает значения сильно меньше 1 (например, у сигмоиды при больших (|z|)), произведение градиентов через слои ведёт к затуханию градиента. Напротив, большие значения производных или больших весов могут вызвать взрыв градиента.

Проявление в Synaptic

В Synaptic.js веса по умолчанию инициализируются случайными значениями в диапазоне [-1,1]. Для сети с большим числом слоев или при использовании сигмоидальной функции активации это часто приводит к:

  • Медленной или полной остановке обучения (затухание градиента)
  • Резким колебаниям ошибки и нестабильному поведению весов (взрыв градиента)

Классическая сигмоида и тангенс гиперболический особенно чувствительны к этой проблеме:

const { Layer, Network } = require('synaptic');

let inputLayer = new Layer(3);
let hiddenLayer = new Layer(5);
let outputLayer = new Layer(2);

inputLayer.project(hiddenLayer);
hiddenLayer.project(outputLayer);

let myNetwork = new Network({
    input: inputLayer,
    hidden: [hiddenLayer],
    output: outputLayer
});

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

Методы борьбы с проблемой

1. Инициализация весов Для уменьшения затухания градиента используют специальные схемы инициализации, например Xavier (Glorot) или He initialization, которые подбирают диапазон весов в зависимости от числа входов и выходов слоя:

[ w ]

В Synaptic веса можно переназначить вручную:

hiddenLayer.list.forEach(neuron => {
    neuron.connections.inputs.forEach(conn => {
        conn.weight = Math.random() * 0.1 - 0.05;
    });
});

2. Выбор функции активации ReLU (Rectified Linear Unit) и его модификации уменьшают эффект затухания градиента, так как производная равна 1 для положительных значений. В Synaptic можно реализовать кастомную функцию активации:

Layer.prototype.reLU = function(x) {
    return Math.max(0, x);
};

3. Нормализация данных Входные данные должны быть масштабированы, чтобы сигмоида или tanh работали в зоне, где их производная не близка к нулю. Для Synaptic это означает приведение значений к диапазону [0,1] или [-1,1].

4. Регулировка скорости обучения Слишком большой () приводит к взрывному градиенту, слишком маленький — к затухающему. В Synaptic скорость обучения задаётся при обучении через Trainer:

myTrainer.train(trainingSet, {
    rate: 0.01, // оптимальное значение подбирается экспериментально
    iterations: 20000,
    error: 0.005,
    shuffle: true
});

5. Градиентное отсечение (Gradient Clipping) При взрывном градиенте полезно ограничивать максимальное значение изменения веса:

neuron.connections.inputs.forEach(conn => {
    conn.weight = Math.max(-1, Math.min(1, conn.weight));
});

Влияние глубины сети

С увеличением числа скрытых слоёв проблема затухающего градиента проявляется сильнее. В Synaptic можно построить глубокую сеть через массив скрытых слоёв, но необходимо тщательно подбирать функции активации, инициализацию и нормализацию:

let hiddenLayers = [];
for (let i = 0; i < 10; i++) {
    hiddenLayers.push(new Layer(50));
}

inputLayer.project(hiddenLayers[0]);
for (let i = 0; i < hiddenLayers.length - 1; i++) {
    hiddenLayers[i].project(hiddenLayers[i+1]);
}
hiddenLayers[hiddenLayers.length-1].project(outputLayer);

Каждое соединение должно учитывать возможность затухания градиента и корректироваться через весовую инициализацию и регуляризацию.

Практические рекомендации

  • Предпочтение ReLU и его вариаций для глубоких сетей
  • Инициализация весов с учётом числа входов и выходов слоя
  • Масштабирование входных данных
  • Контроль скорости обучения
  • Возможность применения градиентного отсечения

Эти методы позволяют снизить негативное влияние затухающих и взрывных градиентов и добиться стабильного обучения даже для сложных сетевых архитектур в Synaptic.js.