SunboxDev commited on
Commit
a3d8a06
·
verified ·
1 Parent(s): be79065

Create README.md

Browse files
Files changed (1) hide show
  1. README.md +342 -0
README.md ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - ru
4
+ tags:
5
+ - wiki
6
+ - ru_wiki
7
+ - wikipedia
8
+ ---
9
+ # SunboxDevLLM - Русскоязычная языковая модель
10
+
11
+ Модель доступна для использования: **[chat.sunbox.dev](https://chat.sunbox.dev)**
12
+
13
+ Репозиторий: **[GitHub](https://github.com/it-efrem/llm)**
14
+
15
+ Decoder-only Transformer языковая модель, построенная полностью с нуля — BPE-токенизатор, архитектура модели, цикл обучения и генерация — на Python + PyTorch (~2500 строк кода).
16
+
17
+ ## Архитектура
18
+
19
+ | Компонент | Решение | Обоснование |
20
+ | ------------ | ----------------------------------- | --------------------------------------------------- |
21
+ | Нормализация | **RMSNorm** (pre-norm) | Стандарт LLaMA/Mistral, ~10-15% быстрее LayerNorm |
22
+ | Позиции | **RoPE** (split + cat, без complex) | Лучшая экстраполяция длины, совместимость с MPS/AMP |
23
+ | FFN | **SwiGLU** (3 проекции) | Выше качество при том же вычислительном бюджете |
24
+ | Attention | **F.scaled_dot_product_attention** | Flash Attention на CUDA, math fallback на MPS |
25
+ | Генерация | **KV cache** (prefill + decode) | O(S) на новый токен вместо O(S²) |
26
+ | Веса | **Weight tying** (embed ↔ lm_head) | Экономия ~24.6M параметров |
27
+ | AMP | autocast + GradScaler | CUDA и MPS (PyTorch 2.2+) |
28
+
29
+ ## Конфигурации модели
30
+
31
+ | Вариант | d_model | heads | layers | ff_dim | Параметры |
32
+ | -------- | ------- | ----- | ------ | ------ | --------- |
33
+ | **Full** | 768 | 12 | 12 | 2048 | ~110M |
34
+
35
+ ## Установка
36
+
37
+ ```bash
38
+ # Клонировать репозиторий и перейти в корень проекта (имя папки может отличаться)
39
+ cd llm
40
+
41
+ # Создать виртуальное окружение
42
+ python3 -m venv .venv
43
+ source .venv/bin/activate
44
+
45
+ # Установить зависимости
46
+ pip install -r requirements.txt
47
+ ```
48
+
49
+ Чекпоинты весов (`models/*.pt`) не коммитятся (см. `.gitignore`). Для примеров ниже положите файлы `base_step_15000.pt` и `chat_step_500.pt` в каталог `models/` или передайте свой путь в `--checkpoint`. Для BPE нужен `data/vocab.json` из того же обучения (или `--vocab`), если путь из чекпоинта на этой машине не существует.
50
+
51
+ ### Зависимости
52
+
53
+ | Пакет | Обязательный | Назначение |
54
+ | -------------------- | :----------: | --------------------------------------------------- |
55
+ | `torch>=2.2.0` | да | PyTorch (CUDA / MPS / CPU) |
56
+ | `numpy>=1.20` | да | Memmap для pretokenized-корпусов |
57
+ | `regex>=2023.0` | да | Unicode-aware pre-tokenization (GPT-2 паттерн) |
58
+ | `transformers>=4.20` | нет | Адаптер HuggingFace-токенизатора (`--tokenizer`) |
59
+ | `tokenizers>=0.15` | нет | Быстрое BPE-обучение через Rust (`train_bpe_hf.py`) |
60
+ | `gensim>=4.0` | нет | Парсинг дампа Wikipedia (`data/wiki_download.py`) |
61
+
62
+ ## Быстрый старт
63
+
64
+ ### Полный пайплайн одной командой
65
+
66
+ ```bash
67
+ bash run_train.sh
68
+ ```
69
+
70
+ Скрипт выполнит: обучение BPE-токенизатора → pre-training на Wikipedia → fine-tuning на чат-корпусе.
71
+
72
+ ### Пошаговый запуск
73
+
74
+ #### 1. Обучение BPE-токенизатора
75
+
76
+ ```bash
77
+ # Собственная реализация (чистый Python, ~20-50x быстрее наивного алгоритма)
78
+ python train_bpe.py --corpus data/wiki_text/corpus.txt --vocab-size 32000
79
+
80
+ # Или через HuggingFace tokenizers (Rust, ~100-1000x быстрее на больших корпусах)
81
+ python train_bpe_hf.py --corpus data/wiki_text/corpus.txt --vocab-size 32000
82
+ ```
83
+
84
+ #### 2. Pretokenization корпуса (для больших датасетов)
85
+
86
+ Для корпусов >1 GB рекомендуется pretokenization — после неё обучение стартует мгновенно:
87
+
88
+ ```bash
89
+ python pretokenize_corpus.py \
90
+ --corpus data/wiki_text/corpus_15gb.txt \
91
+ --output data/corpus_15gb.bin \
92
+ --workers 8
93
+ ```
94
+
95
+ #### 3. Pre-training
96
+
97
+ ```bash
98
+ # На текс��овом корпусе (токенизация при старте)
99
+ python train.py --corpus data/wiki_text/corpus.txt \
100
+ --batch-size 32 --max-steps 100000 --save-every 5000
101
+
102
+ # На pretokenized-корпусе (мгновенный старт)
103
+ python train.py --pretokenized data/corpus_15gb.bin \
104
+ --batch-size 64 --grad-accum 4 --max-steps 30000
105
+
106
+ # С ранней остановкой по perplexity
107
+ python train.py --pretokenized data/corpus_15gb.bin \
108
+ --stop-at-perplexity 10.0
109
+ ```
110
+
111
+ #### 4. Fine-tuning на чат-корпусе
112
+
113
+ ```bash
114
+ # --init-from загружает только веса модели (свежий optimizer/scheduler)
115
+ python train.py --corpus data/wiki_text/corpus_chat.txt --chat \
116
+ --init-from models/base_step_15000.pt \
117
+ --lr 1e-4 --batch-size 16 --max-steps 2000 --save-every 250
118
+
119
+ # --resume загружает полное состояние (продолжение прерванного обучения)
120
+ python train.py --corpus data/wiki_text/corpus_chat.txt --chat \
121
+ --resume models/chat_step_500.pt \
122
+ --max-steps 3000
123
+ ```
124
+
125
+ ## Генерация текста
126
+
127
+ ### Рекомендованные параметры
128
+
129
+ Параметры подобраны тестированием на `base_step_15000` (pre-trained) и `chat_step_500` (chat fine-tuned)
130
+ на 8 различных промптах по 9 конфигурациям каждый. Значения по умолчанию в коде (`GenerateConfig`)
131
+ установлены как универсальный компромисс: `temperature=0.5`, `repetition_penalty=1.15`.
132
+
133
+ | Режим | temperature | repetition_penalty | top_p | Комментарий |
134
+ | --------------------------- | :---------: | :----------------: | :---: | -------------------------------------------- |
135
+ | **Текст** (pre-trained) | 0.3 | 1.2 | — | Максимально связные дополнения, минимум шума |
136
+ | **Чат** (fine-tuned) | 0.5 | 1.1 | — | Лучший баланс точности и разнообразия |
137
+ | **Универсальный** (default) | 0.5 | 1.15 | — | Разумный компромисс для обоих режимов |
138
+ | Креативный | 0.7 | 1.15 | 0.9 | Больше разнообразия, выше риск галлюцинаций |
139
+
140
+ Примеры запуска с оптимальными параметрами:
141
+
142
+ ```bash
143
+ # Дополнение текста (pre-trained checkpoint)
144
+ python generate.py --checkpoint models/base_step_15000.pt \
145
+ --prompt "Москва — столица" --temperature 0.3 --repetition-penalty 1.2 --stream
146
+
147
+ # Чат (fine-tuned checkpoint) — оптимальные параметры
148
+ python generate.py --checkpoint models/chat_step_500.pt \
149
+ --chat --temperature 0.5 --repetition-penalty 1.1
150
+
151
+ # Без явных параметров — используются defaults из GenerateConfig
152
+ python generate.py --checkpoint models/chat_step_500.pt \
153
+ --prompt "Искусственный интеллект — это" --stream
154
+ ```
155
+
156
+ ### Одиночный prompt
157
+
158
+ ```bash
159
+ # Streaming (токены выводятся по одному)
160
+ python generate.py --checkpoint models/chat_step_500.pt \
161
+ --prompt "Москва — столица" --stream
162
+
163
+ # Полный ответ сразу (без --stream)
164
+ python generate.py --checkpoint models/chat_step_500.pt \
165
+ --prompt "Москва — столица" --max-tokens 100
166
+ ```
167
+
168
+ ### Prompt из файла
169
+
170
+ ```bash
171
+ python generate.py --checkpoint models/chat_step_500.pt \
172
+ --prompt-file my_prompt.txt --stream
173
+ ```
174
+
175
+ ### Интерактивный чат
176
+
177
+ ```bash
178
+ # Базовый режим (каждый вопрос независимый)
179
+ python generate.py --checkpoint models/chat_step_500.pt \
180
+ --chat --temperature 0.5 --repetition-penalty 1.1
181
+
182
+ # С сохранением контекста (sliding window по границам реплик)
183
+ python generate.py --checkpoint models/chat_step_500.pt \
184
+ --chat --keep-history
185
+ ```
186
+
187
+ Пример сессии:
188
+
189
+ ```
190
+ === Chat Mode (type 'quit' to exit) ===
191
+
192
+ You: Что такое машинное обучение?
193
+ Assistant: Машинное обучение — раздел ИИ: алгоритмы, которые улучшают своё поведение
194
+ на основе данных без явного программирования каждого шага.
195
+
196
+ You: Что такое фотосинтез?
197
+ Assistant: Фотосинтез — процесс образования органических веществ из CO₂ и воды
198
+ на свету при участии хлорофилла. Выделяется кислород.
199
+
200
+ You: quit
201
+ ```
202
+
203
+ ### Параметры генерации
204
+
205
+ | Параметр | По умолчанию | Описание |
206
+ | ---------------------- | :----------: | --------------------------------------------------------- |
207
+ | `--temperature` | 0.5 | Температура сэмплирования (ниже = детерминированнее) |
208
+ | `--top-k` | — | Ограничение по top-k токенам |
209
+ | `--top-p` | — | Nucleus sampling (top-p) |
210
+ | `--max-tokens` | 256 | Максимум новых токенов |
211
+ | `--repetition-penalty` | 1.15 | Штраф за повторения (1.0 = выкл, рекомендуется 1.1-1.2) |
212
+ | `--stream` | off | Потоковый вывод токенов |
213
+ | `--chat` | off | Интерактивный чат-режим |
214
+ | `--keep-history` | off | Сохранение контекста диалога между репликами |
215
+ | `--vocab` | auto | Путь к vocab.json (если чекпоинт обучен на другой машине) |
216
+
217
+ ## Параметры обучения
218
+
219
+ | Параметр CLI | Конфиг | По умолчанию | Описание |
220
+ | ---------------------- | -------------------- | :----------: | ---------------------------------- |
221
+ | `--max-steps` | `max_steps` | 23000 | Максимум шагов |
222
+ | `--batch-size` | `batch_size` | 32 | Размер батча |
223
+ | `--lr` | `learning_rate` | 6e-4 | Learning rate |
224
+ | `--grad-accum` | `grad_accum_steps` | 4 | Gradient accumulation |
225
+ | `--warmup` | `warmup_steps` | 2000 | Шаги warmup |
226
+ | `--save-every` | `save_every_steps` | 2000 | Частота сохранения |
227
+ | `--seq-len` | `max_seq_len` | 1024 | Длина контекста |
228
+ | `--no-amp` | `use_amp` | True | Отключить AMP |
229
+ | `--stop-at-loss` | `stop_at_loss` | — | Ранняя остановка по loss |
230
+ | `--stop-at-perplexity` | `stop_at_perplexity` | — | Ранняя остановка по val perplexity |
231
+
232
+ LR scheduler: linear warmup → cosine annealing (single cycle).
233
+
234
+ ## Подготовка данных
235
+
236
+ ### Скачивание Wikipedia
237
+
238
+ ```bash
239
+ python data/wiki_download.py --max-mb 500 --corpus-file data/wiki_text/corpus.txt
240
+ ```
241
+
242
+ ### Очистка корпуса
243
+
244
+ Удаляет блоки EasyTimeline, галереи, лишние пустые строки:
245
+
246
+ ```bash
247
+ python clean_corpus.py --input data/wiki_text/corpus.txt \
248
+ --output data/wiki_text/corpus_cleaned.txt --remove-gallery
249
+
250
+ # Только статистика без записи
251
+ python clean_corpus.py --dry-run
252
+ ```
253
+
254
+ ### Обрезка по размеру
255
+
256
+ ```bash
257
+ python trim_corpus.py --input data/wiki_text/corpus_cleaned.txt \
258
+ --output data/wiki_text/corpus_500mb.txt --mb 500
259
+ ```
260
+
261
+ ### Генерация чат-корпуса
262
+
263
+ ```bash
264
+ python data/wiki_text/generate_chat_corpus.py
265
+ ```
266
+
267
+ Создаёт `corpus_chat.txt` из пула Q&A-пар на основе seed-данных (столицы, события, персоны и т.д.).
268
+
269
+ ## Структура проекта
270
+
271
+ ```
272
+ llm/
273
+ ├── config.py # ModelConfig, TrainConfig, GenerateConfig, PathsConfig
274
+ ├── train.py # CLI обучения
275
+ ├── generate.py # CLI генерации и интерактивного чата
276
+ ├── train_bpe.py # Обучение BPE (собственная реализация)
277
+ ├── train_bpe_hf.py # Обучение BPE (HuggingFace Rust backend)
278
+ ├── pretokenize_corpus.py # Pretokenization корпуса в .bin (multiprocessing)
279
+ ├── clean_corpus.py # Очистка wiki-корпуса
280
+ ├── trim_corpus.py # Обрезка корпуса по размеру
281
+ ├── run_train.sh # Полный пайплайн одной командой
282
+
283
+ ├── model/
284
+ │ ├── transformer.py # TransformerLM (блоки + lm_head + weight tying)
285
+ │ ├── block.py # DecoderBlock (pre-norm) + SwiGLUFFN
286
+ │ ├── attention.py # MultiHeadAttention (RoPE + SDPA + KV cache)
287
+ │ ├── rope.py # Rotary positional embeddings
288
+ │ ├── norm.py # RMSNorm
289
+ │ └── kv_cache.py # KV cache для генерации
290
+
291
+ ├── tokenizer/
292
+ │ ├── vocab.py # Словарь (tuple pair keys, без overflow)
293
+ │ ├── bpe.py # BPETokenizer (pre-tokenize + merge ranks + LRU)
294
+ │ ├── bpe_train_fast.py # Быстрое обучение BPE (doubly-linked list + heap)
295
+ │ ├── pretokenizer.py # GPT-2 regex word splitter
296
+ │ └── hf_adapter.py # Адаптер HuggingFace-токенизатора
297
+
298
+ ├── data/
299
+ │ ├── wiki_dataset.py # WikiChunkDataset + PretokenizedDataset (memmap)
300
+ │ ├── chat_dataset.py # ChatChunkDataset (маскирование loss на user-части)
301
+ │ ├── wiki_download.py # Скачивание/парсинг дампа Wikipedia
302
+ │ └── wiki_text/ # Корпуса и генераторы чат-данных
303
+
304
+ ├── training/
305
+ │ ├── trainer.py # AMP, gradient accumulation, валидация, логирование
306
+ │ ├── checkpoint.py # Сохранение/загрузка полного состояния
307
+ │ └── scheduler.py # Warmup + CosineAnnealingWarmRestarts
308
+
309
+ ├── models/ # *.pt в .gitignore — веса кладутся локально
310
+ │ ├── base_step_15000.pt # Pre-trained checkpoint (Wikipedia 15GB)
311
+ │ └── chat_step_500.pt # Fine-tuned checkpoint (chat corpus)
312
+
313
+ ├── inference/
314
+ │ └── generator.py # KV cache prefill/decode, streaming, sampling
315
+
316
+ └── utils/
317
+ ├── device.py # Детекция CUDA/MPS/CPU и платформенные настройки
318
+ └── log_setup.py # Конфигурация логирования
319
+ ```
320
+
321
+ ## Совместимость
322
+
323
+ | Платформа | Поддержка | Особенности |
324
+ | ----------------------------- | :-------: | ------------------------------------------------------ |
325
+ | **CUDA GPU** (A100, V100, T4) | полная | Flash Attention, GradScaler, pin_memory, num_workers=4 |
326
+ | **Apple MPS** (M1/M2/M3/M4) | полная | SDPA math fallback, unified memory, num_workers=0 |
327
+ | **CPU** | базовая | bfloat16 autocast где поддерживается |
328
+
329
+ ## Отличия от оригинального llm
330
+
331
+ 1. **CUDA-совместимость**: единый `get_device()` с приоритетом CUDA > MPS > CPU
332
+ 2. **BPE без overflow**: tuple-ключи `(id_a, id_b)` вместо bit-shift (vocab > 65536)
333
+ 3. **Быстрый BPE encode**: pre-tokenization (GPT-2 regex) + merge rankings + LRU cache
334
+ 4. **RoPE вместо sinusoidal**: лучшая экстраполяция, без отдельного embedding-слоя
335
+ 5. **RMSNorm вместо LayerNorm**: быстрее, соответствует LLaMA/Mistral
336
+ 6. **SwiGLU вместо GELU FFN**: выше качество при том же compute
337
+ 7. **KV cache при генерации**: O(S) на токен вместо O(S²) полного re-forward
338
+ 8. **Weight tying**: embed и lm_head разделяют веса, экономия ~24.6M параметров
339
+ 9. **Полное состояние чекпоинтов**: модель + optimizer + scheduler + scaler + step
340
+ 10. **Grad norm до clipping**: точный мониторинг здоровья градиентов
341
+ 11. **Pre-tokenized datasets**: O(1) `__getitem__`, корректное маскирование loss для чата
342
+ 12. **GPT-2 инициализация**: `N(0, 0.02)` + residual scaling `0.02 / sqrt(2N)`