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

Расскажите про архитектуру Transformer

2.0 Middle🔥 201 комментариев
#NLP и обработка текста#Глубокое обучение

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Архитектура Transformer

История и мотивация

Transformer — это архитектура глубокого обучения, предложенная в статье "Attention is All You Need" (Vaswani et al., 2017). Она полностью основана на механизме attention и стала основой для современных больших языковых моделей (GPT, BERT, LLaMA и др.).

Трансформер был создан для преодоления проблем рекуррентных сетей:

  • RNN обрабатывает последовательность последовательно (долго)
  • RNN страдает от затухающего градиента при длинных зависимостях
  • Сложно распараллелить обучение RNN

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

1. Позиционное кодирование (Positional Encoding)

Так как Трансформер обрабатывает слова параллельно (без рекурсии), нужно добавить информацию о позиции слова в последовательности.

import numpy as np
import torch

def positional_encoding(seq_len, d_model):
    """
    Создание матрицы позиционного кодирования.
    
    seq_len: длина последовательности
    d_model: размерность модели (обычно 512)
    """
    pos = np.arange(seq_len)[:, np.newaxis]  # (seq_len, 1)
    dim = np.arange(0, d_model, 2)[np.newaxis, :]  # (1, d_model//2)
    
    angle_rates = 1 / (10000 ** (dim / d_model))
    
    pe = np.zeros((seq_len, d_model))
    pe[:, 0::2] = np.sin(pos * angle_rates)  # чётные индексы: sin
    pe[:, 1::2] = np.cos(pos * angle_rates)  # нечётные индексы: cos
    
    return torch.from_numpy(pe).unsqueeze(0).float()  # (1, seq_len, d_model)

2. Multi-Head Attention (Многоголовый внимание)

Это сердце Трансформера. Позволяет моделировать разные виды зависимостей между словами.

import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads  # размерность каждой головы
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
    
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        """
        Scaled Dot-Product Attention:
        Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V
        """
        scores = torch.matmul(Q, K.transpose(-2, -1)) / np.sqrt(self.d_k)
        
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        
        attention_weights = torch.softmax(scores, dim=-1)
        output = torch.matmul(attention_weights, V)
        
        return output, attention_weights
    
    def forward(self, Q, K, V, mask=None):
        batch_size = Q.shape[0]
        
        # Линейные преобразования
        Q = self.W_q(Q)  # (batch, seq_len, d_model)
        K = self.W_k(K)
        V = self.W_v(V)
        
        # Разделение на num_heads
        Q = Q.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = K.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = V.view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        # (batch, num_heads, seq_len, d_k)
        
        # Attention для каждой головы
        attn_output, _ = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Конкатенация и финальная проекция
        attn_output = attn_output.transpose(1, 2).contiguous()
        attn_output = attn_output.view(batch_size, -1, self.d_model)
        output = self.W_o(attn_output)
        
        return output

3. Слой Feed-Forward Network

После Attention идёт полносвязная сеть с двумя слоями:

class FeedForwardNetwork(nn.Module):
    def __init__(self, d_model, d_ff):
        super().__init__()
        self.fc1 = nn.Linear(d_model, d_ff)  # обычно d_ff = 4 * d_model
        self.fc2 = nn.Linear(d_ff, d_model)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        return self.fc2(self.relu(self.fc1(x)))

4. Layer Normalization и Residual Connections

class TransformerEncoderBlock(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.attention = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = FeedForwardNetwork(d_model, d_ff)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # Multi-Head Attention с residual connection
        attn_output = self.attention(x, x, x, mask)
        x = x + self.dropout(attn_output)  # residual
        x = self.norm1(x)                   # layer norm
        
        # Feed-Forward с residual connection
        ff_output = self.feed_forward(x)
        x = x + self.dropout(ff_output)     # residual
        x = self.norm2(x)                   # layer norm
        
        return x

Полная архитектура Transformer

class Transformer(nn.Module):
    def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_seq_len, dropout=0.1):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.positional_encoding = positional_encoding(max_seq_len, d_model)
        
        self.encoder_layers = nn.ModuleList([
            TransformerEncoderBlock(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        
        self.decoder_layers = nn.ModuleList([
            TransformerEncoderBlock(d_model, num_heads, d_ff, dropout)
            for _ in range(num_layers)
        ])
        
        self.output_projection = nn.Linear(d_model, vocab_size)
    
    def forward(self, src, tgt, src_mask=None, tgt_mask=None):
        # Embedding + Positional Encoding
        src_embedded = self.embedding(src) + self.positional_encoding[:, :src.shape[1], :]
        tgt_embedded = self.embedding(tgt) + self.positional_encoding[:, :tgt.shape[1], :]
        
        # Encoder
        enc_output = src_embedded
        for layer in self.encoder_layers:
            enc_output = layer(enc_output, src_mask)
        
        # Decoder с Cross-Attention
        dec_output = tgt_embedded
        for layer in self.decoder_layers:
            dec_output = layer(dec_output, tgt_mask)  # Self-attention
            # Cross-attention между Decoder и Encoder
            dec_output = layer.attention(dec_output, enc_output, enc_output, None)
        
        # Output projection
        output = self.output_projection(dec_output)
        
        return output

Преимущества Transformer:

  1. Параллелизм: обрабатывает весь текст одновременно (не последовательно как RNN)
  2. Длинные зависимости: Attention может учитывать отношения между любыми токенами
  3. Масштабируемость: легко добавлять слои и голов без проблем с градиентами
  4. Универсальность: работает для машинного перевода, классификации, генерации текста

Сложность Transformer:

  • Временная сложность: O(n^2 * d) на слой (где n — длина последовательности, d — размерность)
  • Память: O(n^2) для матрицы Attention (проблема для очень длинных текстов)
  • Решение: sparse attention, linear attention, или окна внимания

Трансформер революционизировал NLP и стал основой для всех современных больших языковых моделей.

Расскажите про архитектуру Transformer | PrepBro