mirror of
https://github.com/pese-git/simple-llm.git
synced 2026-01-23 13:03:55 +00:00
Документация и примеры: унификация путей, стабильная работа на CPU, расширенный корпус для токенизатора, end-to-end пайплайн обучения и генерации. Исправлены все ошибки с устройствами и индексами, добавлены проверки и диагностика prompt.
This commit is contained in:
63
README.md
63
README.md
@@ -3,6 +3,45 @@
|
||||
[]()
|
||||
[]()
|
||||
|
||||
> **Актуально для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Установка
|
||||
|
||||
### Через pip (локально)
|
||||
```bash
|
||||
pip install .
|
||||
```
|
||||
|
||||
### Через pip (с PyPI)
|
||||
```bash
|
||||
pip install simple-llm
|
||||
```
|
||||
|
||||
После установки вы сможете запускать примеры и использовать модули из любого места.
|
||||
|
||||
**Краткая инструкция по обучению на своих данных:**
|
||||
1. Обучите BPE-токенизатор на тексте (см. `simple_llm.tokenizer.bpe.BPE`).
|
||||
2. Токенизируйте корпус и создайте датасет через `GetData`.
|
||||
3. Инициализируйте модель `GPT` с нужными параметрами.
|
||||
4. Обучите модель одной строкой: `model.fit(train_loader, num_epoch=10)`.
|
||||
5. Для подробной инструкции и примеров см. [документацию](doc/train_on_custom_data_ru.md).
|
||||
|
||||
---
|
||||
|
||||
**Структура README:**
|
||||
- Обзор
|
||||
- Быстрый старт
|
||||
- Основные компоненты
|
||||
- Документация
|
||||
- Тестирование
|
||||
- Как внести вклад
|
||||
- Лицензия
|
||||
- [FAQ](#faq)
|
||||
|
||||
---
|
||||
|
||||
Простая и понятная реализация языковой модели GPT-стиля с нуля на PyTorch
|
||||
|
||||
## 🔍 Обзор
|
||||
@@ -114,5 +153,29 @@ pytest tests/
|
||||
4. Запушьте ветку (`git push origin feature/AmazingFeature`)
|
||||
5. Откройте Pull Request
|
||||
|
||||
---
|
||||
|
||||
## ❓ FAQ
|
||||
|
||||
**Q: Как установить Simple-LLM, чтобы работали все импорты?**
|
||||
A: Рекомендуется установить через pip (локально: `pip install .` или с PyPI: `pip install simple-llm`). Тогда все примеры и импорты будут работать из любой директории.
|
||||
|
||||
**Q: Как запустить Simple-LLM на CPU?**
|
||||
A: Передайте параметр `device="cpu"` при инициализации модели или обработке данных.
|
||||
|
||||
**Q: Как использовать свой датасет?**
|
||||
A: Используйте класс `GetData` из `simple_llm.data.get_data` для подготовки своих последовательностей. Следуйте формату `(input_ids, targets)`.
|
||||
|
||||
**Q: Где посмотреть примеры?**
|
||||
A: В папке [`example/`](./example/) есть скрипты генерации и обучения.
|
||||
|
||||
**Q: Ошибка CUDA out of memory!**
|
||||
A: Уменьшите размер batch_size или размерность модели, либо используйте CPU.
|
||||
|
||||
**Q: Как добавить новый модуль или улучшение?**
|
||||
A: Ознакомьтесь с документацией, следуйте рекомендациям по вкладу и открывайте Pull Request.
|
||||
|
||||
---
|
||||
|
||||
## 📜 Лицензия
|
||||
Распространяется под лицензией MIT. См. [LICENSE](./LICENSE)
|
||||
|
||||
30
data/corpus/corpus.txt
Normal file
30
data/corpus/corpus.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
Наука — это организованное стремление к познанию окружающего мира. Современные технологии позволяют анализировать большие объёмы данных и делать открытия в различных областях. Искусственный интеллект и машинное обучение становятся неотъемлемой частью нашей жизни, помогая автоматизировать рутинные задачи и открывать новые горизонты для исследований.
|
||||
|
||||
Образование играет ключевую роль в развитии общества. Благодаря доступу к информации, люди могут обучаться дистанционно, осваивать новые профессии и совершенствовать навыки.
|
||||
|
||||
Культура и искусство вдохновляют на творчество, объединяют людей и способствуют развитию критического мышления. Чтение книг, посещение театров и музеев обогащают внутренний мир каждого человека.
|
||||
|
||||
Здоровый образ жизни включает в себя правильное питание, физическую активность и заботу о психоэмоциональном состоянии. Регулярные занятия спортом укрепляют организм и повышают работоспособность.
|
||||
|
||||
Экология — важная сфера, требующая внимания каждого. Сохранение природы, рациональное использование ресурсов и снижение загрязнения окружающей среды — задачи, которые стоят перед современным обществом.
|
||||
|
||||
Азбука: А а Б б В в Г г Д д Е е Ё ё Ж ж З з И и Й й К к Л л М м Н н О о П п Р р С с Т т У у Ф ф Х х Ц ц Ч ч Ш ш Щ щ Ъ ъ Ы ы Ь ь Э э Ю ю Я я.
|
||||
|
||||
Латиница: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z.
|
||||
|
||||
Цифры: 0 1 2 3 4 5 6 7 8 9. Пример: В 2025 году 13 студентов успешно сдали экзамен по информатике.
|
||||
|
||||
Знаки препинания: . , ! ? : ; " ' ( ) [ ] { } < > — - _ / \ | @ # $ % ^ & * + = ~ `
|
||||
|
||||
Пример e-mail: test.user@example.com
|
||||
|
||||
Дата и время: 23 июля 2025 года, 14:30.
|
||||
|
||||
Математические выражения: x = y^2 + 3*z - (a/2).
|
||||
|
||||
Вопрос: Какой сегодня день недели? Ответ: Среда!
|
||||
|
||||
Спецсимволы в тексте: @home #важно $100 %успеха &друзья *звезда +плюс =равно ~волна `обратная кавычка`
|
||||
|
||||
"Каждый охотник желает знать, где сидит фазан" — известная фраза для проверки всех цветов радуги.
|
||||
|
||||
BIN
data/model/simple_llm_gpt.pth
Normal file
BIN
data/model/simple_llm_gpt.pth
Normal file
Binary file not shown.
BIN
data/tokenizer/bpe_tokenizer.json
Normal file
BIN
data/tokenizer/bpe_tokenizer.json
Normal file
Binary file not shown.
BIN
data/tokens/corpus_tokens.pkl
Normal file
BIN
data/tokens/corpus_tokens.pkl
Normal file
Binary file not shown.
@@ -1,52 +0,0 @@
|
||||
<mxfile>
|
||||
<diagram name="Page-1">
|
||||
<mxGraphModel dx="1200" dy="580">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="2" value="Начало" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="60" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="3" value="Разбить текст на символы" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="160" width="120" height="80"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="2" target="3" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="5" value="Подсчитать частоты пар" style="whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="280" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" value="" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="3" target="5" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="7" value="Выбрать наиболее частую пару" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="380" width="120" height="80"/>
|
||||
</mxCell>
|
||||
<mxCell id="8" value="" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="5" target="7" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="9" value="Заменить пару новым токеном" style="whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="500" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="10" value="" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="7" target="9" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="11" value="Достигнут лимит словаря?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="600" width="120" height="80"/>
|
||||
</mxCell>
|
||||
<mxCell id="12" value="" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9" target="11" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="13" value="Конец" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="720" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="14" value="Да" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="11" target="13" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
<mxCell id="15" value="Нет" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="11" target="5" edge="1">
|
||||
<mxGeometry relative="1"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -1,5 +1,26 @@
|
||||
# Byte Pair Encoding (BPE) Algorithm
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Этот документ подробно описывает алгоритм Byte Pair Encoding (BPE) — как он используется для токенизации текста, как устроен процесс обучения словаря и как происходит энкодинг/декодинг текста. Документ предназначен для пользователей Simple-LLM и всех, кто хочет понять внутреннюю механику BPE.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Введение
|
||||
- Основные понятия
|
||||
- Алгоритм работы (обучение словаря)
|
||||
- Псевдокод
|
||||
- Пример работы
|
||||
- Алгоритм энкодинга (токенизации)
|
||||
- Алгоритм декодирования
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Введение
|
||||
|
||||
Byte Pair Encoding (BPE) - это алгоритм компрессии данных, адаптированный для токенизации текста в обработке естественного языка. В контексте языковых моделей BPE используется для создания эффективного словаря подстрок (токенов).
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# Декодер Transformer
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Документ описывает работу декодера Transformer: архитектуру, алгоритм, пример использования, параметры и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Использование
|
||||
- Параметры
|
||||
- Особенности
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Декодер - ключевой компонент архитектуры Transformer, предназначенный для:
|
||||
- Генерации последовательностей (текст, код и др.)
|
||||
@@ -75,15 +94,40 @@ masked_output = decoder(x, mask)
|
||||
- Генерация текста
|
||||
- Кодогенерация
|
||||
|
||||
## Особенности реализации
|
||||
## Рекомендации
|
||||
- Используйте корректные маски для автопрегрессивного декодирования
|
||||
- Следите за размерностью входа и маски
|
||||
- Для сложных случаев используйте teacher forcing
|
||||
|
||||
1. **Масштабирование**:
|
||||
- Поддержка длинных последовательностей
|
||||
- Оптимизированные вычисления внимания
|
||||
---
|
||||
|
||||
2. **Обучение**:
|
||||
- Поддержка teacher forcing
|
||||
- Автопрегрессивное декодирование
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: Размерности не совпадают при подаче входа или маски
|
||||
**Возможные причины:**
|
||||
- Размерность входного тензора не совпадает с emb_size
|
||||
- Форма маски не совпадает с [seq_len, seq_len]
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что размерность входа и маски соответствует требованиям
|
||||
|
||||
### Ошибка: Модель не обучается (loss не уменьшается)
|
||||
**Возможные причины:**
|
||||
- Ошибка в подключении слоя к модели
|
||||
- Ошибка в маскировании (утечка будущего)
|
||||
|
||||
**Решение:**
|
||||
- Проверьте корректность маски
|
||||
- Проверьте, что параметры декодера передаются в оптимизатор
|
||||
|
||||
### Ошибка: CUDA out of memory
|
||||
**Возможные причины:**
|
||||
- Слишком большой batch_size, seq_len или emb_size
|
||||
|
||||
**Решение:**
|
||||
- Уменьшите batch_size, seq_len или emb_size
|
||||
|
||||
---
|
||||
|
||||
3. **Оптимизации**:
|
||||
- Кэширование ключей/значений
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# FeedForward - Прямая полносвязная сеть трансформера
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Документ описывает модуль двухслойной прямой полносвязной сети (Feed Forward) в трансформерах. Включает алгоритм, пример использования, параметры и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Пример использования
|
||||
- Параметры
|
||||
- Особенности
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Модуль реализует двухслойную нейронную сеть, которая:
|
||||
- Добавляет нелинейность в трансформер
|
||||
@@ -55,9 +74,40 @@ output = ff(x) # [1, 10, 512]
|
||||
| `emb_size` | int | Размерность входных/выходных векторов |
|
||||
| `dropout` | float | Вероятность dropout (0.0-1.0)|
|
||||
|
||||
## Особенности
|
||||
- Сохраняет размерность входа/выхода
|
||||
- Автоматически обрабатывает batch и последовательности
|
||||
## Рекомендации
|
||||
- Dropout обычно выбирают 0.1–0.3
|
||||
- Следите, чтобы emb_size совпадал с размерностью входа/выхода
|
||||
- Используйте режимы train/eval корректно
|
||||
- Для визуализации используйте [пример](/example/feed_forward_example.py)
|
||||
|
||||
---
|
||||
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: Размерности не совпадают при прямом проходе
|
||||
**Возможные причины:**
|
||||
- emb_size не совпадает с размерностью входных данных
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что emb_size слоя FeedForward совпадает с размерностью последнего слоя перед ним
|
||||
|
||||
### Ошибка: Модель не обучается (loss не уменьшается)
|
||||
**Возможные причины:**
|
||||
- Dropout слишком высокий
|
||||
- Ошибка в подключении слоя к модели
|
||||
|
||||
**Решение:**
|
||||
- Попробуйте уменьшить dropout
|
||||
- Проверьте, что слой FeedForward включён в модель и его параметры передаются в оптимизатор
|
||||
|
||||
### Ошибка: CUDA out of memory
|
||||
**Возможные причины:**
|
||||
- Слишком большой batch_size или размерность emb_size
|
||||
|
||||
**Решение:**
|
||||
- Уменьшите batch_size или emb_size
|
||||
|
||||
---
|
||||
- Поддерживает режимы train/eval
|
||||
|
||||
[Пример визуализации](/example/feed_forward_example.py)
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# Документация по GPT модели
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Этот документ подробно описывает архитектуру и практическое применение GPT (Generative Pre-trained Transformer) — авторегрессивной языковой модели, реализованной в Simple-LLM. Документ предназначен для разработчиков и исследователей, желающих понять детали реализации и настройки GPT-модели.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Общее описание
|
||||
- Архитектура и алгоритм
|
||||
- Практическое использование
|
||||
- Особенности генерации
|
||||
- Обучение модели
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## 1. Общее описание
|
||||
GPT (Generative Pre-trained Transformer) - это авторегрессивная модель генерации текста на основе архитектуры трансформера.
|
||||
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# HeadAttention - Механизм самовнимания одной головы
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Данный файл описывает реализацию механизма внимания одной головы (Single Head Attention) в трансформерах. Охватывает основные этапы вычислений, пример использования и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Пример использования
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Модуль реализует механизм внимания одной головы из архитектуры Transformer. Основные применения:
|
||||
- Моделирование зависимостей в последовательностях
|
||||
@@ -58,6 +75,42 @@ x = torch.randn(2, 10, emb_size)
|
||||
output = attn_head(x) # [2, 10, head_size]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: Размерности не совпадают при умножении матриц
|
||||
**Возможные причины:**
|
||||
- Несовпадение emb_size и head_size при инициализации
|
||||
- Некорректная форма входного тензора
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что emb_size делится на head_size без остатка
|
||||
- Убедитесь, что вход имеет форму [batch_size, seq_len, emb_size]
|
||||
|
||||
### Ошибка: CUDA out of memory
|
||||
**Возможные причины:**
|
||||
- Слишком большой batch_size или seq_len
|
||||
|
||||
**Решение:**
|
||||
- Уменьшите batch_size или seq_len
|
||||
|
||||
### Ошибка: Не работает маскирование
|
||||
**Возможные причины:**
|
||||
- Неправильная форма или тип маски
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что mask совпадает по размерности с attention scores
|
||||
|
||||
## Рекомендации по использованию
|
||||
- Следите, чтобы emb_size делился на head_size без остатка
|
||||
- Для визуализации весов используйте специализированные инструменты
|
||||
- Для сложных задач используйте MultiHeadAttention
|
||||
- Размер головы (`head_size`) обычно выбирают 64-128
|
||||
- Для длинных последовательностей (>512) используйте оптимизации:
|
||||
- Локальное внимание
|
||||
- Разреженные паттерны
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
### Ключевые компоненты
|
||||
@@ -73,11 +126,6 @@ output = attn_head(x) # [2, 10, head_size]
|
||||
- Поддерживает только causal-режим
|
||||
- Фиксированный максимальный размер последовательности
|
||||
|
||||
## Рекомендации по использованию
|
||||
1. Размер головы (`head_size`) обычно выбирают 64-128
|
||||
2. Для длинных последовательностей (>512) используйте оптимизации:
|
||||
- Локальное внимание
|
||||
- Разреженные паттерны
|
||||
3. Сочетайте с MultiHeadAttention для лучшего качества
|
||||
|
||||
[Дополнительные примеры](/example/attention_examples.py)
|
||||
|
||||
42
doc/index.md
Normal file
42
doc/index.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Навигация по документации Simple-LLM
|
||||
|
||||
> **Документация актуальна для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Архитектура GPT](./gpt_documentation_ru.md)
|
||||
- Описание, блок-схемы, режимы генерации, обучение, типовые ошибки
|
||||
- [Алгоритм BPE](./bpe_algorithm.md)
|
||||
- Теория, примеры, псевдокод, FAQ
|
||||
- [Обработка данных](./get_data_documentation_ru.md)
|
||||
- Форматы, примеры, рекомендации
|
||||
- [Обучение на своих данных](./train_on_custom_data_ru.md)
|
||||
- Подробная инструкция по обучению токенизатора и модели
|
||||
- [Внимание (Attention)](./head_attention_ru.md)
|
||||
- Описание механизма, формулы
|
||||
- [Мультиголовное внимание](./multi_head_attention_ru.md)
|
||||
- Теория, схемы
|
||||
- [Позиционные эмбеддинги](./positional_embeddings_ru.md)
|
||||
- Теория, примеры
|
||||
- [Токен-эмбеддинги](./token_embeddings_ru.md)
|
||||
- Описание, схемы, примеры
|
||||
- [Feed Forward слой](./feed_forward_ru.md)
|
||||
- Теория, формулы
|
||||
- [Декодер](./decoder_ru.md)
|
||||
- Архитектура, схема
|
||||
|
||||
---
|
||||
|
||||
## Как пользоваться документацией
|
||||
|
||||
- Для быстрого старта изучите [README.md](../README.md)
|
||||
- Для понимания архитектуры — [GPT](./gpt_documentation_ru.md) и [BPE](./bpe_algorithm.md)
|
||||
- Для деталей по каждому модулю — соответствующий файл из списка выше
|
||||
- Для практики — смотрите примеры в папке `example/`
|
||||
- Для тестирования — используйте тесты из папки `tests/`
|
||||
|
||||
---
|
||||
|
||||
**Если вы нашли ошибку или хотите предложить улучшение — создайте issue или pull request на GitHub!**
|
||||
@@ -1,5 +1,23 @@
|
||||
# MultiHeadAttention - Многоголовый механизм внимания
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Документ описывает реализацию многоголового механизма внимания (Multi-Head Attention) в трансформерах. Включает описание алгоритма, пример использования и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Пример использования
|
||||
- Параметры
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Модуль реализует ключевой компонент архитектуры Transformer, который:
|
||||
- Параллельно вычисляет несколько типов внимания
|
||||
@@ -58,6 +76,40 @@ output = mha(x) # [1, 50, 512]
|
||||
## Параметры
|
||||
| Параметр | Тип | Описание |
|
||||
|---------------|------|------------------------------|
|
||||
|
||||
## Рекомендации
|
||||
- Размерность emb_size должна делиться на num_heads * head_size
|
||||
- Для визуализации весов используйте специализированные инструменты
|
||||
|
||||
---
|
||||
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: Размерности не совпадают при разделении на головы
|
||||
**Возможные причины:**
|
||||
- emb_size не делится на num_heads * head_size
|
||||
- Некорректная форма входного тензора
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что emb_size = num_heads * head_size
|
||||
- Убедитесь, что вход имеет форму [batch_size, seq_len, emb_size]
|
||||
|
||||
### Ошибка: CUDA out of memory
|
||||
**Возможные причины:**
|
||||
- Слишком большой batch_size, seq_len или число голов
|
||||
|
||||
**Решение:**
|
||||
- Уменьшите batch_size, seq_len или num_heads
|
||||
|
||||
### Ошибка: Не работает маскирование
|
||||
**Возможные причины:**
|
||||
- Неправильная форма или тип маски
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что mask совпадает по размерности с attention scores
|
||||
|
||||
---
|
||||
|
||||
| `num_heads` | int | Количество голов внимания |
|
||||
| `emb_size` | int | Размерность входных эмбеддингов|
|
||||
| `head_size` | int | Размерность каждой головы |
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
# PositionalEmbeddings - Позиционные эмбеддинги
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Документ описывает работу слоя позиционных эмбеддингов в трансформерах. Включает алгоритм, пример использования, сравнение подходов и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Пример использования
|
||||
- Сравнение подходов
|
||||
- Оптимальные практики
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Позиционные эмбеддинги добавляют информацию о порядке элементов в последовательности. Критически важны для:
|
||||
- Transformer-архитектур
|
||||
@@ -50,7 +69,35 @@ class TransformerBlock(nn.Module):
|
||||
| Обучаемые | Да | Гибкость | Требует данных |
|
||||
| Синусоидальные | Нет | Хорошая обобщающая способность | Фиксированный паттерн |
|
||||
|
||||
## Оптимальные практики
|
||||
## Рекомендации
|
||||
- Для `max_seq_len` берите с запасом (+20%)
|
||||
- Размерность делайте равной размерности токенных эмбеддингов
|
||||
- Для длинных последовательностей комбинируйте с синусоидальными
|
||||
|
||||
---
|
||||
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: IndexError при запросе эмбеддингов
|
||||
**Возможные причины:**
|
||||
- seq_len превышает max_seq_len, заданный при инициализации слоя
|
||||
|
||||
**Решение:**
|
||||
- Увеличьте max_seq_len при создании слоя
|
||||
- Проверяйте длину входных данных заранее
|
||||
|
||||
### Ошибка: Размерности не совпадают при сложении с токенными эмбеддингами
|
||||
**Возможные причины:**
|
||||
- Размерность позиционных и токенных эмбеддингов не совпадает
|
||||
|
||||
**Решение:**
|
||||
- Убедитесь, что emb_size одинаков для обоих слоев
|
||||
|
||||
### Ошибка: Модель не обучается (позиционные эмбеддинги не обновляются)
|
||||
**Возможные причины:**
|
||||
- Параметры слоя не добавлены в оптимизатор
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что слой PositionalEmbeddings включён в модель и его параметры передаются в оптимизатор
|
||||
|
||||
---
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<mxfile>
|
||||
<diagram name="Token Embeddings Flow" id="0">
|
||||
<mxGraphModel>
|
||||
<root>
|
||||
<mxCell id="1"/>
|
||||
<mxCell id="2" parent="1"/>
|
||||
<mxCell id="3" value="Входные токены (индексы)" style="shape=rectangle" parent="2" vertex="1">
|
||||
<mxGeometry x="100" y="100" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="Lookup в таблице эмбеддингов" style="shape=rectangle" parent="2" vertex="1">
|
||||
<mxGeometry x="100" y="200" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="5" value="Выходные эмбеддинги" style="shape=rectangle" parent="2" vertex="1">
|
||||
<mxGeometry x="100" y="300" width="120" height="60"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" source="3" target="4" parent="2" edge="1"/>
|
||||
<mxCell id="7" source="4" target="5" parent="2" edge="1"/>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -1,5 +1,24 @@
|
||||
# TokenEmbeddings - Векторные представления токенов
|
||||
|
||||
> **Документ актуален для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
**Краткое summary:**
|
||||
Документ описывает слой преобразования индексов токенов в плотные векторные представления (эмбеддинги). Включает алгоритм, пример использования, параметры и типовые ошибки.
|
||||
|
||||
---
|
||||
|
||||
**Структура документа:**
|
||||
- Назначение
|
||||
- Алгоритм работы
|
||||
- Использование
|
||||
- Параметры
|
||||
- Особенности
|
||||
- Типовые ошибки и их решения
|
||||
|
||||
---
|
||||
|
||||
## Назначение
|
||||
Модуль `TokenEmbeddings` преобразует дискретные индексы токенов в плотные векторные представления (эмбеддинги). Это фундаментальный компонент большинства нейросетевых моделей для обработки естественного языка (NLP).
|
||||
|
||||
@@ -53,10 +72,38 @@ embeddings = embedding_layer(tokens) # векторные представле
|
||||
| vocab_size | int | Размер словаря (количество уникальных токенов) |
|
||||
| emb_size | int | Размерность векторных представлений |
|
||||
|
||||
## Особенности
|
||||
- **Автоматическое обучение**: Векторы адаптируются в процессе тренировки модели
|
||||
- **Эффективность**: Быстрое преобразование индексов в векторы
|
||||
- **Гибкость**: Может использоваться как самостоятельный слой или часть более сложной архитектуры
|
||||
## Рекомендации
|
||||
- Для больших словарей используйте размерность 256-1024
|
||||
- При использовании предобученных эмбеддингов можно заморозить слой (embedding_layer.requires_grad_(False))
|
||||
- Для обработки неизвестных токенов (OOV) резервируйте нулевой индекс
|
||||
|
||||
---
|
||||
|
||||
## Типовые ошибки и их решения
|
||||
|
||||
### Ошибка: Индекс токена вне диапазона словаря
|
||||
**Возможные причины:**
|
||||
- Входные индексы превышают vocab_size
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что все индексы < vocab_size
|
||||
- Добавьте обработку [UNK] токенов при необходимости
|
||||
|
||||
### Ошибка: Размерности не совпадают при сложении эмбеддингов с другими слоями
|
||||
**Возможные причины:**
|
||||
- emb_size не совпадает с размерностью других эмбеддингов
|
||||
|
||||
**Решение:**
|
||||
- Приведите размерности к одному значению во всех слоях
|
||||
|
||||
### Ошибка: Эмбеддинги не обучаются
|
||||
**Возможные причины:**
|
||||
- Параметры слоя не добавлены в оптимизатор
|
||||
|
||||
**Решение:**
|
||||
- Проверьте, что слой TokenEmbeddings включён в модель и его параметры передаются в оптимизатор
|
||||
|
||||
---
|
||||
|
||||
## Типичные сценарии использования
|
||||
1. Первый слой в нейросетевых моделях NLP
|
||||
|
||||
137
doc/train_on_custom_data_ru.md
Normal file
137
doc/train_on_custom_data_ru.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Обучение токенизатора и модели Simple-LLM на своих данных
|
||||
|
||||
> **Инструкция актуальна для Simple-LLM v1.0 (июль 2025)**
|
||||
|
||||
---
|
||||
|
||||
## Оглавление
|
||||
- [1. Подготовка корпуса](#1-подготовка-корпуса)
|
||||
- [2. Обучение BPE-токенизатора](#2-обучение-bpe-токенизатора)
|
||||
- [3. Токенизация корпуса](#3-токенизация-корпуса)
|
||||
- [4. Создание датасета](#4-создание-датасета)
|
||||
- [5. Обучение модели с помощью fit()](#5-обучение-модели-с-помощью-fit)
|
||||
- [6. Сохранение и генерация](#6-сохранение-и-генерация)
|
||||
- [7. Советы и FAQ](#7-советы-и-faq)
|
||||
|
||||
---
|
||||
|
||||
## 1. Подготовка корпуса
|
||||
- Соберите тексты в один или несколько `.txt` файлов.
|
||||
- Очистите данные при необходимости.
|
||||
|
||||
## 2. Обучение BPE-токенизатора
|
||||
```python
|
||||
import torch
|
||||
# Автоматический выбор устройства
|
||||
if torch.cuda.is_available():
|
||||
device = 'cuda'
|
||||
elif getattr(torch.backends, 'mps', None) and torch.backends.mps.is_available():
|
||||
device = 'mps' # Apple Silicon
|
||||
else:
|
||||
device = 'cpu'
|
||||
print(f"Используется устройство: {device}")
|
||||
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
|
||||
with open('corpus.txt', 'r', encoding='utf-8') as f:
|
||||
texts = f.readlines()
|
||||
|
||||
tokenizer = BPE(vocab_size=5000)
|
||||
tokenizer.train(texts, vocab_size=5000, min_freq=2)
|
||||
tokenizer.save('bpe_tokenizer.json')
|
||||
```
|
||||
|
||||
## 3. Токенизация корпуса
|
||||
```python
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
import pickle
|
||||
|
||||
tokenizer = BPE.load('bpe_tokenizer.json')
|
||||
with open('corpus.txt', 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
tokenized = [tokenizer.encode(line) for line in lines]
|
||||
|
||||
with open('corpus_tokens.pkl', 'wb') as f:
|
||||
pickle.dump(tokenized, f)
|
||||
```
|
||||
|
||||
## 4. Создание датасета
|
||||
```python
|
||||
from simple_llm.data.get_data import GetData
|
||||
import pickle
|
||||
|
||||
with open('corpus_tokens.pkl', 'rb') as f:
|
||||
tokenized = pickle.load(f)
|
||||
all_tokens = [token for line in tokenized for token in line]
|
||||
seq_len = 64
|
||||
dataset = GetData(data=all_tokens, seq_len=seq_len, device='cuda')
|
||||
```
|
||||
|
||||
## 5. Обучение модели с помощью fit()
|
||||
```python
|
||||
from torch.utils.data import DataLoader
|
||||
from simple_llm.transformer.gpt import GPT
|
||||
|
||||
loader = DataLoader(dataset, batch_size=32, shuffle=True)
|
||||
model = GPT(
|
||||
vocab_size=tokenizer.vocab_size,
|
||||
max_seq_len=seq_len,
|
||||
emb_size=256,
|
||||
num_heads=4,
|
||||
head_size=64,
|
||||
num_layers=4,
|
||||
device='cuda'
|
||||
)
|
||||
|
||||
# Обучение одной строкой!
|
||||
model.fit(
|
||||
train_loader=loader,
|
||||
valid_loader=None, # можно передать DataLoader для валидации
|
||||
num_epoch=10,
|
||||
learning_rate=1e-4
|
||||
)
|
||||
|
||||
print('Train loss:', model.train_loss)
|
||||
```
|
||||
|
||||
## 6. Сохранение и генерация
|
||||
```python
|
||||
import torch
|
||||
# Сохранить веса
|
||||
torch.save(model.state_dict(), 'simple_llm_gpt.pth')
|
||||
|
||||
# Генерация текста после обучения
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
|
||||
# Загрузим токенизатор и модель (если нужно)
|
||||
tokenizer = BPE.load('bpe_tokenizer.json')
|
||||
# model.load_state_dict(torch.load('simple_llm_gpt.pth')) # если требуется загрузка
|
||||
model.eval()
|
||||
|
||||
# Пример: сгенерировать продолжение для строки prompt
|
||||
prompt = "Привет, мир! "
|
||||
input_ids = torch.tensor([tokenizer.encode(prompt)], device=model._device)
|
||||
output = model.generate(
|
||||
x=input_ids,
|
||||
max_new_tokens=30,
|
||||
do_sample=True,
|
||||
temperature=1.0
|
||||
)
|
||||
# Декодируем результат
|
||||
result = tokenizer.decode(output[0].tolist())
|
||||
print("Сгенерированный текст:", result)
|
||||
```
|
||||
|
||||
## 7. Советы и FAQ
|
||||
- Используйте GPU для ускорения обучения.
|
||||
- Размер словаря токенизатора должен совпадать с vocab_size модели.
|
||||
- Для генерации текста используйте метод `generate` и декодируйте результат.
|
||||
- Для валидации можно передать valid_loader в fit().
|
||||
- Ошибки по размерностям чаще всего связаны с некорректными параметрами seq_len, batch_size или vocab_size.
|
||||
|
||||
---
|
||||
|
||||
**Полезные ссылки:**
|
||||
- [Документация по классу GetData](./get_data_documentation_ru.md)
|
||||
- [Документация по GPT](./gpt_documentation_ru.md)
|
||||
- [README.md](../README.md)
|
||||
50
example/generate_text.py
Normal file
50
example/generate_text.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Генерация текста с помощью обученной GPT-модели и токенизатора
|
||||
"""
|
||||
import torch
|
||||
from simple_llm.transformer.gpt import GPT
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
|
||||
if __name__ == "__main__":
|
||||
import torch
|
||||
# Определяем устройство
|
||||
#if torch.cuda.is_available():
|
||||
# device = 'cuda'
|
||||
#elif getattr(torch.backends, 'mps', None) and torch.backends.mps.is_available():
|
||||
# device = 'mps' # Apple Silicon
|
||||
#else:
|
||||
# device = 'cpu'
|
||||
device = 'cpu'
|
||||
print(f"Используется устройство: {device}")
|
||||
|
||||
# Загрузим токенизатор и модель
|
||||
tokenizer = BPE.load('data/tokenizer/bpe_tokenizer.json')
|
||||
model = GPT(
|
||||
vocab_size=tokenizer.vocab_size,
|
||||
max_seq_len=64,
|
||||
emb_size=256,
|
||||
num_heads=4,
|
||||
head_size=64,
|
||||
num_layers=4,
|
||||
device=device
|
||||
)
|
||||
model.load_state_dict(torch.load('data/model/simple_llm_gpt.pth', map_location=device))
|
||||
model.eval()
|
||||
|
||||
# Введите начальный текст
|
||||
prompt = "Привет, мир! "
|
||||
prompt_tokens = tokenizer.encode(prompt)
|
||||
print(f"Токены prompt: {prompt_tokens}")
|
||||
print(f"Размер словаря токенизатора: {tokenizer.vocab_size}")
|
||||
if any(idx >= tokenizer.vocab_size or idx < 0 for idx in prompt_tokens):
|
||||
print("ВНИМАНИЕ: В prompt есть токены с индексом вне диапазона словаря! Генерация невозможна.")
|
||||
exit(1)
|
||||
input_ids = torch.tensor([prompt_tokens], device=device)
|
||||
output = model.generate(
|
||||
x=input_ids,
|
||||
max_new_tokens=30,
|
||||
do_sample=True,
|
||||
temperature=1.0
|
||||
)
|
||||
result = tokenizer.decode(output[0].tolist())
|
||||
print("Сгенерированный текст:", result)
|
||||
25
example/tokenize_corpus.py
Normal file
25
example/tokenize_corpus.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
Токенизация текстового корпуса с помощью обученного BPE-токенизатора
|
||||
"""
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
import pickle
|
||||
|
||||
if __name__ == "__main__":
|
||||
import torch
|
||||
# Определяем устройство
|
||||
#if torch.cuda.is_available():
|
||||
# device = 'cuda'
|
||||
#elif getattr(torch.backends, 'mps', None) and torch.backends.mps.is_available():
|
||||
# device = 'mps' # Apple Silicon
|
||||
#else:
|
||||
# device = 'cpu'
|
||||
device = 'cpu'
|
||||
print(f"Используется устройство: {device}")
|
||||
|
||||
tokenizer = BPE.load('data/tokenizer/bpe_tokenizer.json')
|
||||
with open('data/corpus/corpus.txt', 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
tokenized = [tokenizer.encode(line) for line in lines]
|
||||
with open('data/tokens/corpus_tokens.pkl', 'wb') as f:
|
||||
pickle.dump(tokenized, f)
|
||||
print("Корпус токенизирован и сохранён в data/corpus_tokens.pkl")
|
||||
50
example/train_gpt_model.py
Normal file
50
example/train_gpt_model.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
Обучение GPT-модели на токенизированном корпусе
|
||||
"""
|
||||
import pickle
|
||||
from torch.utils.data import DataLoader
|
||||
from simple_llm.data.get_data import GetData
|
||||
from simple_llm.transformer.gpt import GPT
|
||||
|
||||
if __name__ == "__main__":
|
||||
import torch
|
||||
# Определяем устройство
|
||||
#if torch.cuda.is_available():
|
||||
# device = 'cuda'
|
||||
#elif getattr(torch.backends, 'mps', None) and torch.backends.mps.is_available():
|
||||
# device = 'mps' # Apple Silicon
|
||||
#else:
|
||||
# device = 'cpu'
|
||||
device = 'cpu'
|
||||
print(f"Используется устройство: {device}")
|
||||
|
||||
with open('data/tokens/corpus_tokens.pkl', 'rb') as f:
|
||||
tokenized = pickle.load(f)
|
||||
all_tokens = [token for line in tokenized for token in line]
|
||||
seq_len = 64
|
||||
dataset = GetData(data=all_tokens, seq_len=seq_len, device=device)
|
||||
loader = DataLoader(dataset, batch_size=32, shuffle=True)
|
||||
|
||||
# Загрузите токенизатор для определения размера словаря
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
tokenizer = BPE.load('data/tokenizer/bpe_tokenizer.json')
|
||||
|
||||
model = GPT(
|
||||
vocab_size=tokenizer.vocab_size,
|
||||
max_seq_len=seq_len,
|
||||
emb_size=256,
|
||||
num_heads=4,
|
||||
head_size=64,
|
||||
num_layers=4,
|
||||
device='cpu'
|
||||
)
|
||||
|
||||
model.fit(
|
||||
train_loader=loader,
|
||||
valid_loader=None,
|
||||
num_epoch=10,
|
||||
learning_rate=1e-4
|
||||
)
|
||||
print('Train loss:', model.train_loss)
|
||||
torch.save(model.state_dict(), 'data/model/simple_llm_gpt.pth')
|
||||
print("Модель обучена и сохранена в data/model/simple_llm_gpt.pth")
|
||||
23
example/train_tokenizer.py
Normal file
23
example/train_tokenizer.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Обучение BPE-токенизатора на текстовом корпусе
|
||||
"""
|
||||
from simple_llm.tokenizer.bpe import BPE
|
||||
|
||||
if __name__ == "__main__":
|
||||
import torch
|
||||
# Определяем устройство
|
||||
#if torch.cuda.is_available():
|
||||
# device = 'cuda'
|
||||
#elif getattr(torch.backends, 'mps', None) and torch.backends.mps.is_available():
|
||||
# device = 'mps' # Apple Silicon
|
||||
#else:
|
||||
# device = 'cpu'
|
||||
device = 'cpu'
|
||||
print(f"Используется устройство: {device}")
|
||||
|
||||
with open('data/corpus/corpus.txt', 'r', encoding='utf-8') as f:
|
||||
texts = f.readlines()
|
||||
tokenizer = BPE(vocab_size=5000)
|
||||
tokenizer.fit(" ".join(texts))
|
||||
tokenizer.save('data/tokenizer/bpe_tokenizer.json')
|
||||
print("Токенизатор обучен и сохранён в data/tokenizer/bpe_tokenizer.json")
|
||||
Reference in New Issue
Block a user