diff --git a/.gitignore b/.gitignore index b7faf40..ed28ee2 100644 --- a/.gitignore +++ b/.gitignore @@ -205,3 +205,6 @@ cython_debug/ marimo/_static/ marimo/_lsp/ __marimo__/ + + +.vscode \ No newline at end of file diff --git a/doc/positional_embeddings_ru.md b/doc/positional_embeddings_ru.md new file mode 100644 index 0000000..34d0787 --- /dev/null +++ b/doc/positional_embeddings_ru.md @@ -0,0 +1,56 @@ +# PositionalEmbeddings - Позиционные эмбеддинги + +## Назначение +Позиционные эмбеддинги добавляют информацию о порядке элементов в последовательности. Критически важны для: +- Transformer-архитектур +- Моделей обработки текста (BERT, GPT) +- Задач с временными рядами + +## Алгоритм работы + +```mermaid +flowchart TD + A[Создание слоя] --> B[Запрос длины последовательности] + B --> C{Длина в допустимых пределах?} + C -->|Да| D[Генерация индексов 0..seq_len-1] + D --> E[Получение векторов из embedding-таблицы] + E --> F[Возврат эмбеддингов] + C -->|Нет| G[Ошибка IndexError] +``` + +1. **Инициализация**: + - Создается таблица размером `max_seq_len x emb_size` + - Каждая позиция получает уникальный обучаемый вектор + +2. **Работа**: + - Принимает длину последовательности `seq_len` + - Возвращает тензор формы `[seq_len, emb_size]` + +## Пример использования +```python +# Инициализация +pos_emb = PositionalEmbeddings(max_seq_len=512, emb_size=128) + +# Получение эмбеддингов для 50 элементов +embeddings = pos_emb(50) # shape: [50, 128] + +# Интеграция в модель +class TransformerBlock(nn.Module): + def __init__(self): + self.pos_emb = PositionalEmbeddings(512, 128) + + def forward(self, x): + pos = self.pos_emb(x.size(1)) # Добавляем к токенным эмбеддингам + return x + pos +``` + +## Сравнение подходов +| Метод | Обучаемость | Плюсы | Минусы | +|----------------------|-------------|--------------------------------|-----------------------| +| Обучаемые | Да | Гибкость | Требует данных | +| Синусоидальные | Нет | Хорошая обобщающая способность | Фиксированный паттерн | + +## Оптимальные практики +- Для `max_seq_len` берите с запасом (+20%) +- Размерность делайте равной размерности токенных эмбеддингов +- Для длинных последовательностей комбинируйте с синусоидальными diff --git a/doc/token_embeddings.md b/doc/token_embeddings.md new file mode 100644 index 0000000..e69de29 diff --git a/doc/token_embeddings_flow.drawio b/doc/token_embeddings_flow.drawio new file mode 100644 index 0000000..2f6e600 --- /dev/null +++ b/doc/token_embeddings_flow.drawio @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/simple_llm/embedding/positional_embeddings.py b/simple_llm/embedding/positional_embeddings.py new file mode 100644 index 0000000..0e4583f --- /dev/null +++ b/simple_llm/embedding/positional_embeddings.py @@ -0,0 +1,90 @@ +import torch +from torch import nn, Tensor + +class PositionalEmbeddings(nn.Module): + """ + Класс для создания позиционных эмбеддингов через nn.Embedding. + + Позиционные эмбеддинги используются в нейросетях для передачи информации + о позиции элементов в последовательности (например, в Transformer). + + Особенности: + - Создаёт обучаемые позиционные эмбеддинги фиксированной длины + - Поддерживает обработку последовательностей переменной длины + - Автоматически размещает вычисления на том же устройстве, что и параметры + + Args: + max_seq_len (int): Максимальная длина последовательности + emb_size (int): Размерность векторного представления позиций + + Пример использования: + >>> 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 # Добавляем позиционную информацию + """ + + def __init__(self, max_seq_len: int, emb_size: int): + super().__init__() + self.max_seq_len = max_seq_len + self.emb_size = emb_size + self.embedding = nn.Embedding( + num_embeddings=max_seq_len, + embedding_dim=emb_size + ) + + def forward(self, seq_len: int) -> Tensor: + """ + Возвращает позиционные эмбеддинги для заданной длины последовательности. + + Args: + seq_len (int): Длина последовательности (1 <= seq_len <= max_seq_len) + + Returns: + Tensor: Тензор позиционных эмбеддингов формы [seq_len, emb_size] + + Raises: + IndexError: Если seq_len выходит за допустимые границы + + Пример: + >>> pos_encoder = PositionalEmbeddings(100, 64) + >>> emb = pos_encoder(10) # Тензор 10x64 + """ + if seq_len < 1 or seq_len > self.max_seq_len: + raise IndexError(f"Длина {seq_len} должна быть от 1 до {self.max_seq_len}") + positions = torch.arange(seq_len, device=self.embedding.weight.device) + return self.embedding(positions) + +if __name__ == "__main__": + # Демонстрация работы + print("Пример использования PositionalEmbeddings:") + pos_emb = PositionalEmbeddings(max_seq_len=50, emb_size=128) + + # Пример 1: Базовое использование + print("\n1. Базовый пример:") + emb = pos_emb(10) + print(f"Форма выходного тензора: {emb.shape}") + print(f"Среднее значение: {emb.mean().item():.4f}") + + # Пример 2: Интеграция с моделью + print("\n2. Пример интеграции с моделью:") + class DemoModel(nn.Module): + def __init__(self): + super().__init__() + self.pos_emb = PositionalEmbeddings(50, 128) + + def forward(self, x): + pos = self.pos_emb(x.size(1)) + return x + pos # Добавляем позиционную информацию + + model = DemoModel() + input_tensor = torch.randn(2, 10, 128) # [batch, seq, features] + output = model(input_tensor) + print(f"Вход: {input_tensor.shape}, Выход: {output.shape}") \ No newline at end of file