Что такое seq2seq архитектура?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Seq2Seq архитектура: от входа к выходу
Seq2Seq (Sequence-to-Sequence) — это архитектура нейронной сети, предназначенная для преобразования одной последовательности в другую. Она состоит из двух основных компонентов: энкодера и декодера, соединённых через вектор контекста.
Основные компоненты
1. Энкодер (Encoder)
Обрабатывает входную последовательность и преобразует её в вектор контекста (контекстный вектор):
import torch
import torch.nn as nn
# Энкодер на основе LSTM
class Encoder(nn.Module):
def __init__(self, input_dim, embedding_dim, hidden_dim):
super().__init__()
self.embedding = nn.Embedding(input_dim, embedding_dim)
self.lstm = nn.LSTM(
embedding_dim,
hidden_dim,
num_layers=2,
bidirectional=True,
batch_first=True
)
def forward(self, src):
# src shape: (batch_size, seq_len)
embedded = self.embedding(src) # (batch_size, seq_len, embedding_dim)
outputs, (hidden, cell) = self.lstm(embedded)
# hidden shape: (num_layers*2, batch_size, hidden_dim)
return hidden, cell, outputs
Энкодер последовательно обрабатывает входные токены и кодирует информацию в скрытых состояниях.
2. Вектор контекста
Последнее скрытое состояние энкодера или его комбинация — это вектор контекста, содержащий всю информацию о входной последовательности:
# После прохода энкодера получаем контекстный вектор
# shape: (num_layers*2, batch_size, hidden_dim)
context = hidden[-2:] if bidirectional else hidden[-1:]
3. Декодер (Decoder)
Принимает вектор контекста и генерирует выходную последовательность токен за токеном:
class Decoder(nn.Module):
def __init__(self, output_dim, embedding_dim, hidden_dim):
super().__init__()
self.embedding = nn.Embedding(output_dim, embedding_dim)
self.lstm = nn.LSTM(
embedding_dim,
hidden_dim,
num_layers=2,
batch_first=True
)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, trg, hidden, cell):
# trg shape: (batch_size, 1) - один токен
embedded = self.embedding(trg) # (batch_size, 1, embedding_dim)
output, (hidden, cell) = self.lstm(embedded, (hidden, cell))
# output shape: (batch_size, 1, hidden_dim)
logits = self.fc(output.squeeze(1)) # (batch_size, output_dim)
return logits, hidden, cell
Полная архитектура Seq2Seq
class Seq2Seq(nn.Module):
def __init__(self, encoder, decoder):
super().__init__()
self.encoder = encoder
self.decoder = decoder
def forward(self, src, trg, teacher_forcing_ratio=0.5):
# src shape: (batch_size, src_len)
# trg shape: (batch_size, trg_len)
batch_size = trg.shape[0]
trg_len = trg.shape[1]
# Энкодим входную последовательность
hidden, cell, _ = self.encoder(src)
# Убеждаемся, что hidden имеет правильный размер
hidden = hidden[-2:] if self.encoder.lstm.bidirectional else hidden
# Декодим токен за токеном
decoder_input = trg[:, 0].unsqueeze(1) # <START> токен
outputs = []
for t in range(1, trg_len):
logits, hidden, cell = self.decoder(decoder_input, hidden, cell)
outputs.append(logits)
# Teacher forcing: используем настоящий токен с вероятностью
if torch.rand(1).item() < teacher_forcing_ratio:
decoder_input = trg[:, t].unsqueeze(1)
else:
decoder_input = logits.argmax(dim=1).unsqueeze(1)
outputs = torch.stack(outputs, dim=1)
return outputs
Процесс обучения vs тестирования
Обучение (Teacher Forcing):
- Декодер получает настоящие токены из целевой последовательности
- Ускоряет обучение, но создаёт несоответствие с тестированием
Тестирование (Inference):
- Декодер использует свои собственные предсказания как входные данные
- Может привести к накоплению ошибок
Применение
Seq2Seq использовается в:
-
Машинный перевод (Machine Translation)
# Переводит английское предложение в французское src = tokenize("The cat sits on the mat") trg = model(src) # "Le chat est assis sur le tapis" -
Диалоговые системы (Chatbots)
- Входная последовательность: вопрос пользователя
- Выходная последовательность: ответ бота
-
Summarization (Суммаризация)
- Входная последовательность: длинный документ
- Выходная последовательность: краткое резюме
-
Question Answering
- Входная последовательность: вопрос
- Выходная последовательность: ответ
-
Code Generation
- Входная последовательность: описание функции
- Выходная последовательность: код
Проблемы базовой архитектуры
-
Узкое горлышко контекста — один вектор содержит всю информацию
- Решение: Attention Mechanism
-
Ванилирующие/взрывающиеся градиенты при обучении на длинных последовательностях
- Решение: gradient clipping, GRU/LSTM вместо RNN
-
Несоответствие обучения и тестирования (teacher forcing)
- Решение: Scheduled Sampling
Современное развитие: Attention и Transformers
# Современная архитектура использует Attention вместо простого контекстного вектора
# Decoder может "смотреть" на разные части входной последовательности
class AttentionDecoder(nn.Module):
def __init__(self, output_dim, embedding_dim, hidden_dim):
super().__init__()
self.embedding = nn.Embedding(output_dim, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)
self.attention = nn.MultiheadAttention(
hidden_dim,
num_heads=8,
batch_first=True
)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, trg, hidden, cell, encoder_outputs):
embedded = self.embedding(trg)
lstm_out, (hidden, cell) = self.lstm(embedded, (hidden, cell))
# Attention над encoder outputs
attn_out, _ = self.attention(
lstm_out, encoder_outputs, encoder_outputs
)
logits = self.fc(attn_out)
return logits, hidden, cell
Выводы
Seq2Seq революционизировала обработку естественного языка и стала основой для современных трансформеров. Хотя Pure Seq2Seq с LSTM сейчас заменяется Attention-based механизмами и Transformers, понимание её принципов критично для освоения современных NLP архитектур.