RNN и LSTM: нейросети с памятью
Чтобы учитывать порядок и контекст, нужна сеть, которая читает текст последовательно и помнит прочитанное; это рекуррентные сети (RNN).
Рекуррентная нейросеть (RNN) — сеть, которая обрабатывает последовательность по одному элементу, передавая на каждом шаге «память» (скрытое состояние) о ранее увиденном.
Зачем вообще читать последовательно
Bag-of-words терял порядок, n-граммы видели 1-2 слова, эмбеддинги описывали отдельные слова. Но смысл предложения — в порядке и связях. «Собака укусила человека» ≠ «человек укусил собаку». Хочется сеть, которая читает слова по очереди, как человек, и держит в уме контекст. Это и есть RNN.
Идея скрытого состояния (памяти)
RNN идёт по словам слева направо. На каждом шаге у неё есть скрытое состояние — вектор-«память», сжатый итог всего прочитанного. Получив новое слово, сеть обновляет память: новое состояние = функция(прошлое состояние, текущее слово). Так информация о начале предложения «протекает» до конца.
# Схематичная RNN: показываем, как обновляется память (без обучения)
def step(hidden, word_value):
# очень упрощённо: новая память = смесь старой и нового слова
return round(0.5 * hidden + 0.5 * word_value, 3)
# закодируем слова числами (как будто это их эмбеддинги-скаляры)
sentence = [("я", 0.2), ("очень", 0.6), ("рад", 0.9)]
hidden = 0.0
for word, value in sentence:
hidden = step(hidden, value)
print("прочитали '%s' -> память:" % word, hidden)
print("Итоговая память кодирует всё предложение:", hidden)
Вывод:
прочитали 'я' -> память: 0.1 прочитали 'очень' -> память: 0.35 прочитали 'рад' -> память: 0.625 Итоговая память кодирует всё предложение: 0.625
Это, конечно, карикатура (настоящая RNN использует матрицы и обучается), но механизм виден: память накапливает информацию по мере чтения, и каждое новое слово на неё влияет. Итоговое скрытое состояние — сжатое представление всего предложения, которое можно подать в классификатор.
Проблема длинных зависимостей
У простой RNN есть серьёзная беда. Информация о ранних словах с каждым шагом «размывается» — её перезаписывают новые слова. К концу длинного предложения память о начале почти исчезает. Технически это затухание градиента: при обучении сигнал, идущий назад через много шагов, становится исчезающе мал, и сеть не может выучить связь между далёкими словами.
Пример: «Кошка, которую я завёл прошлым летом в деревне у бабушки, … была чёрной». Чтобы согласовать «была чёрной» с «кошка», нужно помнить начало через десяток слов. Простая RNN это теряет.
LSTM: управляемая память
LSTM (Long Short-Term Memory) — улучшенная RNN с механизмом «ворот» (gates). Это маленькие обучаемые регуляторы, которые решают: что из новой информации запомнить, что из старой памяти забыть, что выдать наружу. Благодаря отдельной «ячейке памяти», которая обновляется аккуратно, LSTM держит важную информацию на много шагов и почти не страдает от затухания градиента.
| Ворота | Что решает |
| Forget gate | что из старой памяти забыть |
| Input gate | что из нового запомнить |
| Output gate | что выдать как результат шага |
Близкий родственник — GRU: похожая идея с меньшим числом ворот, быстрее. Долгое время LSTM/GRU были стандартом для текста: перевод, распознавание речи, генерация.
Что осталось нерешённым
LSTM смягчила проблему длинных зависимостей, но не убрала полностью: на очень длинных текстах память всё равно ограничена. И главное — RNN обрабатывает слова строго по очереди, шаг за шагом, поэтому её нельзя эффективно распараллелить на современных видеокартах. Эти два ограничения и подтолкнут к механизму внимания и трансформерам.
Итог
- RNN читает текст по словам, неся скрытое состояние — память о прошлом.
- Итоговое состояние — сжатое представление всей последовательности.
- Простая RNN забывает далёкое прошлое (затухание градиента).
- LSTM с воротами управляет памятью и держит длинные зависимости лучше.
- Остаются пределы: длина и невозможность распараллеливания.