Что такое RNN (Recurrent Neural Network)?

«Что такое RNN (Recurrent Neural Network)?» — вопрос из категории Нейронные сети и Deep Learning, который задают на 30% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

RNN (Recurrent Neural Network) — это архитектура нейронных сетей, разработанная для обработки последовательных данных, где порядок элементов имеет значение. Её ключевая особенность — наличие скрытого состояния (hidden state), которое передается от одного шага последовательности к следующему, создавая подобие "памяти" о предыдущих элементах.

Основная идея: На каждом шаге t сеть получает вход x_t и предыдущее скрытое состояние h_{t-1}, чтобы вычислить новое скрытое состояние h_t и, часто, выход y_t.

Математически (для простой RNN-ячейки): h_t = tanh(W_{xh} * x_t + W_{hh} * h_{t-1} + b_h)

Проблемы классических RNN и их решения:

  1. Проблема исчезающих/взрывающихся градиентов: при обратном распространении ошибки через много временных шагов градиенты могут стать аномально малыми или большими, что мешает обучению.
  2. Решение: использование более сложных ячеек с механизмами управления памятью:
    • LSTM (Long Short-Term Memory): имеет три "ворота" (input, forget, output) и cell state, что позволяет лучше сохранять информацию на длинных дистанциях.
    • GRU (Gated Recurrent Unit): упрощенная версия LSTM с двумя воротами, часто работает быстрее и требует меньше данных.

Пример реализации простой RNN на PyTorch для классификации тональности текста:

import torch
import torch.nn as nn

class SentimentRNN(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.rnn = nn.RNN(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, output_dim) # output_dim=1 для бинарной классификации

    def forward(self, text):
        # text shape: [batch_size, seq_length]
        embedded = self.embedding(text) # [batch_size, seq_length, embed_dim]
        output, hidden = self.rnn(embedded)
        # Берём скрытое состояние с последнего шага
        return self.fc(hidden.squeeze(0))

# Пример инициализации
model = SentimentRNN(vocab_size=10000, embed_dim=100, hidden_dim=256, output_dim=1)

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