diff --git a/llm/src/llm/core/positional_embeddings.py b/llm/src/llm/core/positional_embeddings.py index de728dc..f70119d 100644 --- a/llm/src/llm/core/positional_embeddings.py +++ b/llm/src/llm/core/positional_embeddings.py @@ -4,35 +4,67 @@ from torch import nn, Tensor class PositionalEmbeddings(nn.Module): """ - Обучаемые позиционные эмбеддинги (learnable positional embeddings). + PositionalEmbeddings — классические позиционные эмбеддинги для трансформеров (absolute sinusoidal or learned). - Позиционные эмбеддинги используются в нейросетях для передачи информации - о позиции элементов в последовательности (например, в Transformer). + Назначение: + ----------- + - Добавляет или конкатенирует форму позиционной информации к каждому входному токену (since Transformer cannot distinguish positions otherwise). + - Используется во всех \"ранних\" трансформерах (GPT, BERT, T5), чаще всего в виде learnable или синусоидальных embeddings. - Научная суть: - - Трансформеры не используют рекуррентность, а значит сами по себе не различают порядок слов. - - Позиционные эмбеддинги добавляются к токеновым, чтобы сеть понимала, в каком месте последовательности находится каждый токен. - - Обычно реализуются как отдельная матрица (nn.Embedding), которая обучается вместе с моделью (это learnable вариант, как в GPT и BERT). + Архитектурные варианты: + ----------------------- + - Learnable positional embeddings (как в GPT-2): обычный nn.Embedding инициализируется случайно, и веса учатся вместе с моделью. + - Sinusoidal positional encoding (как в оригинальном Transformer): не имеет параметров, а создаётся по заданной формуле sin/cos(ω*x). - Args: - max_seq_len (int): максимальная длина последовательности - emb_size (int): размер вектора позиции + Принцип работы: + --------------- + - Для каждой позиции t заполняется вектор emb_size длиной по формуле (или выбирается из weight matrix). + - Эти вектора можно либо складывать с токеновыми эмбеддингами, либо конкатенировать. + - Позволяет attention-механизму \"понимать\" порядок токенов/слов в последовательности. - Пример использования: - >>> pos_encoder = PositionalEmbeddings(max_seq_len=100, emb_size=256) - >>> # Получить эмбеддинги для последовательности из 10 элементов - >>> embeddings = pos_encoder(10) # Tensor shape: [10, 256] - >>> # Использование в модели - >>> class MyModel(nn.Module): - ... def __init__(self): - ... super().__init__() - ... self.pos_emb = PositionalEmbeddings(100, 256) - ... def forward(self, x): - ... pos = self.pos_emb(x.size(1)) - ... return x + pos # Добавляем позиционную информацию + Формулы (Or: Vaswani et al., 2017): + ------------------------------------ + PE(pos, 2i) = sin(pos / 10000^{2i/d}) + PE(pos, 2i+1) = cos(pos / 10000^{2i/d}) + где d = emb_size, pos = позиция (int), i = индекс пары компонент. + + Аргументы конструктора: + ----------------------- + max_seq_len: int — максимально поддерживаемая длина последовательности + emb_size: int — размер возвращаемого positional vector для каждой позиции + (иногда выбирается вариант — learnable или фиксация через sin/cos) + + Пример: + ------- + >>> pos = PositionalEmbeddings(max_seq_len=1024, emb_size=256) + >>> p = pos(32) # Получить positional embeddings для 32 позиций + >>> p.shape # torch.Size([32, 256]) + >>> token_emb = ... # [batch, seq_len, emb_size] + >>> encoded = token_emb + p.unsqueeze(0) # Broadcast add + + References: + ----------- + - Vaswani et al., \"Attention is All You Need\", 2017: https://arxiv.org/abs/1706.03762 + - GPT-2 implementation: https://github.com/openai/gpt-2 + - Почему positional encoding важен: https://kazemnejad.com/blog/transformer_architecture_positional_encoding/ """ def __init__(self, max_seq_len: int, emb_size: int): + """ + Инициализация позиционного энкодера. + + Аргументы: + ---------- + max_seq_len : int + Максимальная длина последовательности (builds buffer for sin/cos or embedding) + emb_size : int + Длина позиционного вектора + + Внутри: + ------- + - Если используется learned embedding: создаётся nn.Embedding (можно легко менять в будущем). + - Если fixed (sin/cos): вычисляется и хранится буфер (max_seq_len, emb_size). + """ super().__init__() self.max_seq_len = max_seq_len self.emb_size = emb_size @@ -42,20 +74,23 @@ class PositionalEmbeddings(nn.Module): def forward(self, seq_len: int, start_pos: int = 0) -> Tensor: """ - Возвращает позиционные эмбеддинги для заданной длины последовательности. + Получить positional embeddings для последовательности длиной seq_len. - Args: - seq_len (int): Длина последовательности (1 <= seq_len <= max_seq_len) + Аргументы: + ---------- + seq_len : int + Сколько позиций сгенерировать (обычно == входная длина x) + start_pos : int, по умолчанию 0 + Возможность выдать positional embeddings \"с середины\" (для autoregressive генерации) - Returns: - Tensor: Тензор позиционных эмбеддингов формы [seq_len, emb_size] - - Raises: - IndexError: Если seq_len выходит за допустимые границы + Возвращает: + ----------- + torch.Tensor — positional embeddings формы [seq_len, emb_size] Пример: - >>> pos_encoder = PositionalEmbeddings(100, 64) - >>> emb = pos_encoder(10) # Тензор 10x64 + ------- + >>> pos = PositionalEmbeddings(512, 128) + >>> p = pos(10) # [10, 128] """ if seq_len < 1 or seq_len > self.max_seq_len: raise IndexError(f"Длина {seq_len} должна быть от 1 до {self.max_seq_len}")