Что такое Attention?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Attention механизм: полный разбор
Attention (внимание) — один из самых важных механизмов в современном глубоком обучении. Без него не было бы Transformer'ов, BERT, GPT, LLM.
Основная идея: Очень просто
Аналогия из жизни:
Когда вы читаете текст, вы не обращаете одинаковое внимание на все слова. Вы фокусируетесь на важные слова.
"Кот сидит на красивом матраце и СЛАДКО спит."
Внимание распределяется:
- "кот" — 30% (кто?)
- "сидит" — 5% (как-то не главное)
- "красивом" — 2% (описание)
- "спит" — 50% (главное действие!)
- "сладко" — 13% (как спит)
Attention механизм делает то же самое для нейронных сетей.
Три компонента Attention
Query (Q) — запрос ("что я ищу?")
"Дай мне важную информацию на позиции i"
Key (K) — ключи ("у кого это есть?")
"Вот список всех позиций с описанием"
Value (V) — значения ("вот что я тебе дам")
"Вот реальные данные с каждой позиции"
Как работает Attention Step-by-Step
Шаг 1: Вычисляем сходство (Score)
Score = Q · K^T / sqrt(d_k)
Это показывает, как сильно Query "интересует" каждый Key
Пример:
Query: "спит"
Keys: ["кот", "сидит", "матрац", "сладко"]
Score("спит", "кот") = 0.5 (кот спит - связь есть)
Score("спит", "сидит") = 0.7 (сидит + спит - близко по смыслу)
Score("спит", "матрац") = 0.1 (не связано)
Score("спит", "сладко") = 0.8 (сладко спит - очень связано)
Шаг 2: Нормализуем (Softmax)
Attention_weights = softmax(Score)
Это даёт вероятности (сумма = 1)
Пример:
Score: [0.5, 0.7, 0.1, 0.8]
↓ softmax
Attention_weights: [0.15, 0.25, 0.10, 0.50]
(Всё в сумме даёт 1.0)
Шаг 3: Взвешиваем Value'ы
Output = Attention_weights · V
Мы берём значения, но в пропорции внимания
Пример:
Attention_weights: [0.15, 0.25, 0.10, 0.50]
Values: [
[1, 0, 0], # "кот" embedding
[0, 1, 0], # "сидит" embedding
[0, 0, 1], # "матрац" embedding
[1, 1, 0] # "сладко" embedding
]
Output = 0.15*[1,0,0] + 0.25*[0,1,0] + 0.10*[0,0,1] + 0.50*[1,1,0]
= [0.65, 0.75, 0.10]
Результат: микс информации, но больше от "сладко" (50% внимания)
Формулы Attention
Scaled Dot-Product Attention:
Attention(Q, K, V) = softmax(Q·K^T / √d_k)·V
где:
d_k = размер Key (для масштабирования)
√d_k = делим на корень, чтобы gradients не взрывались
Пример в коде (PyTorch)
import torch
import torch.nn.functional as F
# Входные данные
Q = torch.randn(batch_size=32, seq_len=10, d_model=64) # Query
K = torch.randn(batch_size=32, seq_len=10, d_model=64) # Key
V = torch.randn(batch_size=32, seq_len=10, d_model=64) # Value
# Attention
def scaled_dot_product_attention(Q, K, V, mask=None):
# Шаг 1: Score = Q · K^T
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(Q.size(-1))
# Shape: (batch, seq_len, seq_len)
# Маскирование (опционально, для каузальности)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Шаг 2: Attention weights = softmax(scores)
attention_weights = F.softmax(scores, dim=-1)
# Shape: (batch, seq_len, seq_len)
# Шаг 3: Output = attention_weights · V
output = torch.matmul(attention_weights, V)
# Shape: (batch, seq_len, d_model)
return output, attention_weights
output, weights = scaled_dot_product_attention(Q, K, V)
Multi-Head Attention
Проблема Single-Head Attention: Одна голова "внимания" может фокусироваться только на один аспект.
Решение: несколько "голов"
Вместо одного attention механизма,
мы запускаем h независимых attention'ов:
Head 1: Фокусируется на синтаксис
Head 2: Фокусируется на семантику
Head 3: Фокусируется на грамматику
Потом конкатенируем результаты
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
self.num_heads = num_heads
self.d_model = d_model
assert d_model % num_heads == 0
self.d_k = d_model // num_heads
# Линейные слои для Q, K, V
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) # Output projection
def forward(self, Q, K, V):
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)
# Shape: (batch, num_heads, seq_len, d_k)
# Attention для каждой головы
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
attention = F.softmax(scores, dim=-1)
context = torch.matmul(attention, V)
# Объединяем головы обратно
context = context.transpose(1, 2).contiguous()
context = context.view(batch_size, -1, self.d_model)
# Final linear projection
output = self.W_o(context)
return output
Зачем нужен √d_k?
Проблема без масштабирования:
# Без √d_k
scores = torch.matmul(Q, K.transpose(-2, -1)) # Большие числа!
# Пример
Q = torch.randn(1, 10, 512) # d_k = 512
K = torch.randn(1, 10, 512)
scores = torch.matmul(Q, K.transpose(-2, -1))
# scores имеет масштаб ~512 (очень большие значения!)
# softmax(большие числа) → один элемент близко к 1, остальные к 0
# Это "резкое" внимание, градиенты убывают
С масштабированием:
d_k = 512
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)
# scores имеет масштаб ~1
# softmax(нормальные числа) → распределение более мягкое
# Лучше градиенты для обучения
Где используется Attention
1. Transformer'ы (Self-Attention)
Каждое слово "смотрит" на все остальные слова
Q = K = V = input
2. Seq2Seq (Cross-Attention)
Декодер (Query) смотрит на энкодер (Key, Value)
Q = decoder_state
K, V = encoder_output
3. Vision Transformer'ы
Вместо слов — patches изображения
Attention помогает модели связать части картинки
4. LLM'ы (GPT, BERT, LLaMA)
Вся архитектура построена на self-attention
Каждый token смотрит на предыдущие токены (или все)
Визуальный пример Attention
СловоTEST: "The cat sat on the mat"
Когда модель обрабатывает слово "mat":
Attention distribution:
"The" [0.05]
"cat" [0.10]
"sat" [0.05]
"on" [0.05]
"the" [0.15]
"mat" [0.60] ← максимум на себя!
Модель сфокусирована на "mat" (60%),
немного на "the" (15%),
и немного на "cat" (10%)
Плюсы и минусы Attention
Плюсы:
- Может захватывать долгосрочные зависимости
- Параллельная обработка (в отличие от RNN)
- Интерпретируемо (видим, на что смотрит модель)
- Масштабируется на длинные последовательности (относительно)
Минусы:
- O(n²) памяти (пропорционально длине последовательности в квадрате)
- Для очень длинных текстов может быть медленным
- Требует много данных для обучения
Итог
Attention = селективная фокусировка на важную информацию
Формула:
Attention(Q, K, V) = softmax(Q·K^T / √d_k)·V
1. Q и K определяют, что важно
2. V содержит реальные значения
3. softmax даёт вероятности внимания
4. Результат — взвешенная сумма V
Это позволило перейти от RNN (последовательно, медленно) к Transformer'ам (параллельно, быстро, масштабируемо) и создало революцию в NLP.