docs(core): expand docstrings for PositionalEmbeddings module

- docs: update and clarify docstrings for PositionalEmbeddings class and methods (__init__, forward)
- explain motivation, mathematical formulas, usage examples, architectural options (learned vs sinusoidal), external references
- no API or code changes

This makes the positional encoding component easier to understand and use for all transformer practitioners.
This commit is contained in:
Sergey Penkovsky
2025-10-16 14:09:05 +03:00
parent 0832d78acf
commit 8018efae2a

View File

@@ -4,35 +4,67 @@ from torch import nn, Tensor
class PositionalEmbeddings(nn.Module): class PositionalEmbeddings(nn.Module):
""" """
Обучаемые позиционные эмбеддинги (learnable positional embeddings). PositionalEmbeddings — классические позиционные эмбеддинги для трансформеров (absolute sinusoidal or learned).
Позиционные эмбеддинги используются в нейросетях для передачи информации Назначение:
о позиции элементов в последовательности (например, в Transformer). -----------
- Добавляет или конкатенирует форму позиционной информации к каждому входному токену (since Transformer cannot distinguish positions otherwise).
- Используется во всех \"ранних\" трансформерах (GPT, BERT, T5), чаще всего в виде learnable или синусоидальных embeddings.
Научная суть: Архитектурные варианты:
- Трансформеры не используют рекуррентность, а значит сами по себе не различают порядок слов. -----------------------
- Позиционные эмбеддинги добавляются к токеновым, чтобы сеть понимала, в каком месте последовательности находится каждый токен. - Learnable positional embeddings (как в GPT-2): обычный nn.Embedding инициализируется случайно, и веса учатся вместе с моделью.
- Обычно реализуются как отдельная матрица (nn.Embedding), которая обучается вместе с моделью (это learnable вариант, как в GPT и BERT). - Sinusoidal positional encoding (как в оригинальном Transformer): не имеет параметров, а создаётся по заданной формуле sin/cos(ω*x).
Args: Принцип работы:
max_seq_len (int): максимальная длина последовательности ---------------
emb_size (int): размер вектора позиции - Для каждой позиции t заполняется вектор emb_size длиной по формуле (или выбирается из weight matrix).
- Эти вектора можно либо складывать с токеновыми эмбеддингами, либо конкатенировать.
- Позволяет attention-механизму \"понимать\" порядок токенов/слов в последовательности.
Пример использования: Формулы (Or: Vaswani et al., 2017):
>>> pos_encoder = PositionalEmbeddings(max_seq_len=100, emb_size=256) ------------------------------------
>>> # Получить эмбеддинги для последовательности из 10 элементов PE(pos, 2i) = sin(pos / 10000^{2i/d})
>>> embeddings = pos_encoder(10) # Tensor shape: [10, 256] PE(pos, 2i+1) = cos(pos / 10000^{2i/d})
>>> # Использование в модели где d = emb_size, pos = позиция (int), i = индекс пары компонент.
>>> class MyModel(nn.Module):
... def __init__(self): Аргументы конструктора:
... super().__init__() -----------------------
... self.pos_emb = PositionalEmbeddings(100, 256) max_seq_len: int — максимально поддерживаемая длина последовательности
... def forward(self, x): emb_size: int — размер возвращаемого positional vector для каждой позиции
... pos = self.pos_emb(x.size(1)) (иногда выбирается вариант — learnable или фиксация через sin/cos)
... return x + pos # Добавляем позиционную информацию
Пример:
-------
>>> 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): 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__() super().__init__()
self.max_seq_len = max_seq_len self.max_seq_len = max_seq_len
self.emb_size = emb_size self.emb_size = emb_size
@@ -42,20 +74,23 @@ class PositionalEmbeddings(nn.Module):
def forward(self, seq_len: int, start_pos: int = 0) -> Tensor: 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] -----------
torch.Tensor — positional embeddings формы [seq_len, emb_size]
Raises:
IndexError: Если seq_len выходит за допустимые границы
Пример: Пример:
>>> 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: if seq_len < 1 or seq_len > self.max_seq_len:
raise IndexError(f"Длина {seq_len} должна быть от 1 до {self.max_seq_len}") raise IndexError(f"Длина {seq_len} должна быть от 1 до {self.max_seq_len}")