← Назад к вопросам

Что такое проблемы взрывающегося и затухающего градиента?

2.7 Senior🔥 191 комментариев
#Глубокое обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Взрывающийся и затухающий градиент (Exploding & Vanishing Gradients)

Это две критические проблемы при обучении глубоких нейронных сетей (RNN, LSTM), особенно на последовательностях. Они приводят к неустойчивому обучению и плохой способности модели учить долгосрочные зависимости.

Суть проблемы

При обучении используется backpropagation — распространение ошибки назад через сеть:

Ошибка propagates: Output → Hidden → Input
         dL/dW = dL/dH * dH/dW

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

Затухающий градиент (Vanishing Gradient)

Проблема: Градиенты становятся меньше и меньше при распространении назад, близко к нулю.

Симптомы:

  • Первые слои сети практически не обновляются
  • Модель не учит долгосрочные зависимости
  • Loss плато на начальном уровне

Пример с RNN:

# Обновление весов в RNN:
# dW_hidden = dL/dH_t * dH_t/dW_hidden
#           = dL/dH_t * dH_t/dH_{t-1} * dH_{t-1}/dH_{t-2} * ... * dH_1/dW_hidden
#
# Если |dH_t/dH_{t-1}| < 0.1, то при 100 временных шагов:
# 0.1^100 ≈ 10^(-100)  <- градиент исчезает!

Где чаще всего:

  • RNN с функцией активации tanh или sigmoid
  • Глубокие сети без batch normalization
  • Долгие последовательности

Взрывающийся градиент (Exploding Gradient)

Проблема: Градиенты становятся огромными, обновления весов неконтролируемо большие.

Симптомы:

  • Веса становятся NaN (not a number)
  • Loss сразу же растёт до бесконечности
  • Training crashes

Пример:

# Если |dH_t/dH_{t-1}| > 1, то при 100 шагов:
# 2^100 ≈ 10^30  <- градиент взрывается!

Решения для затухающего градиента

1. LSTM и GRU вместо RNN

Эти архитектуры специально разработаны для решения проблемы затухания:

from tensorflow.keras.layers import LSTM, GRU
import tensorflow as tf

# RNN (уязвим к затуханию)
model_rnn = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(64, input_shape=(sequence_length, features))
])

# LSTM (имеет "cell state" - долговременную память)
model_lstm = tf.keras.Sequential([
    tf.keras.layers.LSTM(64, input_shape=(sequence_length, features))
])

# GRU (более простой, но эффективный)
model_gru = tf.keras.Sequential([
    tf.keras.layers.GRU(64, input_shape=(sequence_length, features))
])

2. ResNet - Skip Connections

Прямые связи через слои:

# В Keras используется Functional API
input_x = tf.keras.Input(shape=(100,))
x = tf.keras.layers.Dense(64, activation=relu)(input_x)
x = tf.keras.layers.Dense(64, activation=relu)(x)
x = tf.keras.layers.Add()([x, input_x])  # Skip connection
output = tf.keras.layers.Dense(10)(x)
model = tf.keras.Model(inputs=input_x, outputs=output)

3. Batch Normalization

Нормализует входы каждого слоя, стабилизирует градиенты:

model = tf.keras.Sequential([
    tf.keras.layers.Dense(128),
    tf.keras.layers.BatchNormalization(),  # Стабилизирует
    tf.keras.layers.Activation(relu),
    tf.keras.layers.Dense(64),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Activation(relu),
])

4. Хорошая инициализация весов

Xavier/He инициализация:

# He инициализация для ReLU
tf.keras.layers.Dense(64, 
    kernel_initializer=tf.keras.initializers.HeNormal())

# Xavier для tanh/sigmoid
tf.keras.layers.Dense(64,
    kernel_initializer=tf.keras.initializers.GlorotNormal())

Решения для взрывающегося градиента

1. Gradient Clipping

Обрезаем градиенты, если они превышают порог:

optimizer = tf.keras.optimizers.Adam()

# Clipping по норме
training_step = tf.keras.optimizers.Adam(
    clipnorm=1.0  # Обрезаем, если норма градиента > 1.0
)

# Clipping по значению
training_step = tf.keras.optimizers.Adam(
    clipvalue=0.5  # Все значения градиентов в [-0.5, 0.5]
)

2. Уменьшить learning rate

optimizer = tf.keras.optimizers.Adam(learning_rate=0.0001)  # Меньше lr

3. Уменьшить размер batch

Меньше образцов → меньше градиента

Практический пример мониторинга

import tensorflow as tf
from tensorflow.keras.callbacks import TensorBoard

model = tf.keras.Sequential([
    tf.keras.layers.LSTM(64, input_shape=(100, 32), return_sequences=True),
    tf.keras.layers.LSTM(32),
    tf.keras.layers.Dense(10, activation=softmax)
])

model.compile(
    optimizer=tf.keras.optimizers.Adam(clipnorm=1.0),  # Gradient clipping
    loss=categorical_crossentropy,
    metrics=[accuracy]
)

# TensorBoard для мониторинга gradient flow
callback = TensorBoard(log_dir=/logs, histogram_freq=1)

model.fit(
    X_train, y_train,
    epochs=50,
    batch_size=32,
    validation_data=(X_val, y_val),
    callbacks=[callback]
)

Чеклист при обучении глубокой сети

✅ Используй LSTM/GRU для RNN (или Transformer) ✅ Batch Normalization между слоями ✅ He/Xavier инициализацияGradient clipping если видишь NaN ✅ Skip connections в очень глубоких сетях ✅ Мониторь gradient flow в TensorBoard ✅ Начни с маленького learning rate ✅ Тестируй на коротких последовательностях сначала

Что такое проблемы взрывающегося и затухающего градиента? | PrepBro