Как устроены RNN, LSTM и GRU? В чём между ними разница?

RNN (Recurrent Neural Networks), LSTM (Long Short-Term Memory) и GRU (Gated Recurrent Unit) — это типы рекуррентных нейронных сетей, предназначенных для обработки последовательностей, таких как текст, аудио или временные ряды. Все они используют скрытое состояние, передаваемое во времени от одного шага к другому, но различаются архитектурно и функционально, особенно в умении запоминать долгосрочные зависимости и избегать затухающего градиента.

RNN — Recurrent Neural Network

Принцип работы:

Обычная нейросеть (MLP) не может обрабатывать последовательные данные напрямую, т.к. не сохраняет контекст. RNN же имеет обратную связь во времени — каждый элемент последовательности обрабатывается шаг за шагом, передавая скрытое состояние от предыдущего шага к текущему.

На каждом временном шаге tt:

  • Вход: xtx_t

  • Скрытое состояние: hth_t

  • Обновление:
    ht=tanh⁡(Wxhxt+Whhht−1+b)h_t = \tanh(W_{xh} x_t + W_{hh} h_{t-1} + b)

  • Выход (опционально): yt=Whyhty_t = W_{hy} h_t

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

LSTM — Long Short-Term Memory

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

Основные компоненты:

Каждый LSTM-узел содержит:

  • ячейку памяти CtC_t

  • входной гейт iti_t

  • забывающий гейт ftf_t

  • гейт обновления (кандидатное состояние) C~t\tilde{C}_t

  • выходной гейт oto_t

Формулы:

ft=σ(Wf⋅[ht−1,xt]+bf)it=σ(Wi⋅[ht−1,xt]+bi)C~t=tanh⁡(WC⋅[ht−1,xt]+bC)Ct=ft∗Ct−1+it∗C~tot=σ(Wo⋅[ht−1,xt]+bo)ht=ot∗tanh⁡(Ct)\begin{align*} f_t &= \sigma(W_f \cdot [h_{t-1}, x_t] + b_f) \\ i_t &= \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) \\ \tilde{C}_t &= \tanh(W_C \cdot [h_{t-1}, x_t] + b_C) \\ C_t &= f_t * C_{t-1} + i_t * \tilde{C}_t \\ o_t &= \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) \\ h_t &= o_t * \tanh(C_t) \end{align*}

  • σ\sigma — сигмоида

  • ∗* — поэлементное умножение

Интерпретация:

  • ftf_t решает, какую часть старой памяти Ct−1C_{t-1} забыть.

  • iti_t контролирует, сколько новой информации добавить.

  • oto_t управляет, что из памяти выдать как выход.

  • Это позволяет LSTM долго сохранять релевантную информацию и игнорировать нерелевантную.

GRU — Gated Recurrent Unit

GRU — упрощённая версия LSTM, предложенная для снижения вычислительной нагрузки при сохранении эффективности.

Основные гейты:

  • гейт обновления ztz_t — как в LSTM: насколько обновлять скрытое состояние.

  • гейт сброса rtr_t — управляет забыванием предыдущего состояния.

Формулы:

zt=σ(Wz⋅[ht−1,xt])rt=σ(Wr⋅[ht−1,xt])h~t=tanh⁡(W⋅[rt∗ht−1,xt])ht=(1−zt)∗ht−1+zt∗h~t\begin{align*} z_t &= \sigma(W_z \cdot [h_{t-1}, x_t]) \\ r_t &= \sigma(W_r \cdot [h_{t-1}, x_t]) \\ \tilde{h}_t &= \tanh(W \cdot [r_t * h_{t-1}, x_t]) \\ h_t &= (1 - z_t) * h_{t-1} + z_t * \tilde{h}_t \end{align*}

Интерпретация:

  • GRU объединяет память и скрытое состояние (в отличие от LSTM, где они разделены).

  • Обновление производится по принципу: либо оставить старое, либо заменить новым.

  • Меньше параметров, быстрее обучение, подходит для задач с ограниченными ресурсами.

Сравнение RNN, LSTM и GRU

Характеристика RNN LSTM GRU
Количество гейтов 0 3 (forget, input, output) 2 (reset, update)
--- --- --- ---
Управление памятью Нет Да Да
--- --- --- ---
Проблема исчезающего градиента Да Частично решена Частично решена
--- --- --- ---
Долгосрочная память Плохо Хорошо Хорошо (но чуть хуже LSTM)
--- --- --- ---
Скорость обучения Быстрее (но хуже качество) Медленнее Быстрее, чем LSTM
--- --- --- ---
Количество параметров Меньше Больше Меньше, чем у LSTM
--- --- --- ---
Подходит для длинных последовательностей Плохо Лучше всего Хорошо, но зависит от задачи
--- --- --- ---
Интерпретируемость Простая Сложная, но гибкая Средняя
--- --- --- ---

Примеры в фреймворках

TensorFlow/Keras

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import SimpleRNN, LSTM, GRU

model = Sequential()

model.add(SimpleRNN(128, input_shape=(max_len, embedding_dim))) # RNN

\# model.add(LSTM(128)) # LSTM

\# model.add(GRU(128)) # GRU

PyTorch

import torch.nn as nn
rnn = nn.RNN(input_size=300, hidden_size=128)
lstm = nn.LSTM(input_size=300, hidden_size=128)
gru = nn.GRU(input_size=300, hidden_size=128)

Где применяются:

  • RNN:

    • Базовые задачи, короткие тексты, простые модели.

    • В наши дни почти не используется напрямую из-за ограничений.

  • LSTM:

    • Задачи с длинной памятью: перевод, генерация текста, временные ряды, биоинформатика.

    • Более стабильны при обучении на длинных последовательностях.

  • GRU:

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

    • Часто дает сравнимую точность с LSTM при меньших затратах.

Влияние длины последовательности

  • При коротких последовательностях различие между LSTM и GRU может быть несущественным.

  • При длинных — LSTM устойчивее, лучше передаёт информацию на десятки и сотни шагов назад.

  • GRU склонен быстрее «забывать», но делает это экономнее.

Важно понимать

  • LSTM и GRU — это решения для моделирования зависимостей во времени.

  • Они не параллелизуются по временной оси, как трансформеры (BERT, GPT), поэтому в современных NLP задачах часто заменяются на attention-based модели.

  • Тем не менее, в задачах временных рядов, аудио, IoT, сигналов — RNN и производные всё ещё активно применяются.