172 lines
7.8 KiB
Markdown
172 lines
7.8 KiB
Markdown
# Xenith
|
||
|
||
[]()
|
||
[]()
|
||
[]()
|
||
|
||
Трансформер на чистом C++: обучение и генерация текста на CPU, без внешних
|
||
зависимостей. Всё в одном бинарнике.
|
||
|
||
## Что внутри
|
||
|
||
Архитектура — как у LLaMA: pre-norm, RMSNorm, RoPE, SwiGLU, связанные
|
||
эмбеддинги (tied weights), каузальное внимание. Обучение — вручную
|
||
написанный обратный проход + AdamW. Никаких фреймворков.
|
||
|
||
| файл | что делает |
|
||
|---|---|
|
||
| `xenith/core/tensor.hpp` | матрицы, три формы GEMM, RMSNorm, RNG, пул потоков |
|
||
| `xenith/core/model.cpp` | конфигурация, инициализация, прямой проход, RoPE, Adam |
|
||
| `xenith/core/backward.cpp` | обратный проход (ручной, без автомиффов) |
|
||
| `xenith/core/trainer.cpp` | цикл обучения, расписание lr, чекпоинты, валидация |
|
||
| `xenith/core/generate.cpp` | генерация с KV-кэшем, temperature / top-k / top-p |
|
||
| `xenith/core/checkpoint.cpp` | формат `.xnh`, токенизатор, сохранение/загрузка |
|
||
| `xenith/core/gradcheck.cpp` | численная проверка градиентов + бенчмарк |
|
||
|
||
## Быстрый старт
|
||
|
||
```bash
|
||
# 1) активация окружения
|
||
source activate.sh
|
||
|
||
# 2) собрать модель из своего текста
|
||
Xenith new models/my.xnh --corpus data.txt \
|
||
--vocab 512 --embd 128 --layers 6 --heads 8 --ctx 256
|
||
|
||
# 3) обучить
|
||
Xenith train models/my.xnh --corpus data.txt \
|
||
--out models/my_trained.xnh --steps 5000 --batch 16 --lr 3e-4
|
||
|
||
# 4) сгенерировать
|
||
Xenith gen models/my_trained.xnh --prompt "Привет" --n 200 --temp 0.8
|
||
```
|
||
|
||
## Перед использованием ***Xenith*** желательно активировать окружение
|
||
|
||
### Команда активации окружения
|
||
```bash
|
||
# для bash
|
||
source activate.sh
|
||
|
||
# для zsh
|
||
source activate.zsh
|
||
|
||
# для fish
|
||
source activate.fish
|
||
```
|
||
|
||
## Команды
|
||
|
||
### new — создать модель
|
||
|
||
Читает корпус, строит по нему словарь, инициализирует веса случайно.
|
||
|
||
```
|
||
--corpus PATH текст (обязательно)
|
||
--out PATH файл модели (по умолчанию model.xnh)
|
||
--vocab N размер словаря (512)
|
||
--embd N ширина эмбеддинга (128)
|
||
--layers N число слоёв (4)
|
||
--heads N число голов (4). embd должен делиться на heads
|
||
--ctx N максимальный контекст (128)
|
||
--ffn N ширина FFN (0 = 4*embd)
|
||
--rope N база RoPE (10000)
|
||
--seed N зерно инициализации (1337)
|
||
--untied отдельная матрица выхода вместо связанной с эмбеддингом
|
||
--view-vocab вывести словарь нейросети
|
||
```
|
||
|
||
Словарь двухуровневый: частые слова берутся целиком, остальное режется на
|
||
символы. Так словарь остаётся маленьким, а любой текст кодируется без потерь —
|
||
модель может учить и слова, и буквы.
|
||
|
||
### train — обучить
|
||
|
||
```
|
||
--corpus PATH текст (обязательно)
|
||
--out PATH куда сохранить (по умолчанию перезаписывает входной файл)
|
||
--steps N шагов (1000)
|
||
--batch N батч (8)
|
||
--block N длина окна (64)
|
||
--lr F скорость (3e-4)
|
||
--wd F weight decay (0.01)
|
||
--clip F клип нормы градиента (1.0)
|
||
--warmup N прогрев (100)
|
||
--seed N зерно (1337)
|
||
--log-every N как часто печатать (50)
|
||
--ckpt-every N промежуточный чекпоинт каждые N шагов (0 = нет)
|
||
--val-every N валидация каждые N шагов (0 = нет)
|
||
--val-tokens N размер валидации (20000)
|
||
--threads N потоков (0 = все ядра)
|
||
--resume продолжить с сохранённого step
|
||
```
|
||
|
||
Прогрев + косинусное затухание до `lr * 0.1`. Промежуточные чекпоинты
|
||
пишутся как `models/my.xnh.step1500` — можно откатиться, если loss
|
||
развалился.
|
||
|
||
### gen — сгенерировать
|
||
|
||
```
|
||
--prompt STR стартовый текст
|
||
--n N сколько токенов (200)
|
||
--temp F температура; 0 = жадный выбор (0.8)
|
||
--top-k N top-k (40), 0 = выкл
|
||
--top-p F top-p (0.95), 1.0 = выкл
|
||
--seed N зерно
|
||
--no-stream не печатать в процессе
|
||
--batch "a;b;c" несколько промптов через ;
|
||
--show-tokens показать id токенов
|
||
```
|
||
|
||
### ollama — сгенерировать
|
||
|
||
```
|
||
--port PORT порт сервера (по умолчанию 11434)
|
||
--conf NAME.conf конфиг с настройками и списком моделей
|
||
```
|
||
|
||
### gradcheck - проверить градиенты численно
|
||
|
||
```
|
||
--fast эксперементаль флаг который ускоряет foreword примерно в x2-x5
|
||
```
|
||
|
||
### bench - замерить скорость форварда и шага обучения
|
||
|
||
```
|
||
--fast эксперементаль флаг который ускоряет foreword примерно в x2-x5
|
||
```
|
||
|
||
### info
|
||
|
||
```bash
|
||
Xenith info models/my.xnh # конфигурация и словарь
|
||
```
|
||
### update - проверка обновления
|
||
|
||
`gradcheck` стоит запускать после любой правки в `model.cpp` / `backward.cpp` —
|
||
он ловит ошибку в обратном проходе за секунды.
|
||
|
||
## Формат модели
|
||
|
||
Один файл `.xnh` содержит и словарь, и веса, и состояние оптимизатора.
|
||
При загрузке проверяется каждая размерность тензора, так что модель,
|
||
собранная с другими настройками, отвергается с понятной ошибкой, а не
|
||
молча портит вывод.
|
||
|
||
Совместимость с `models/test_model.bfr` (старый формат) **не** поддерживается:
|
||
там была другая раскладка весов.
|
||
|
||
## Что учесть
|
||
|
||
- **Скорость.** ~7600 ток/с на 4 ядрах для 4 слоёв × 64 измерения. С ростом
|
||
модели скорость падает квадратично по `embd` и линейно по слоям.
|
||
Замеряйте своим `bench`.
|
||
- **Форма входа.** `text`, `code`, `html` — чем однороднее корпус, тем
|
||
меньше словарь и тем быстрее обучение.
|
||
- **Количество данных.** Модель на 0.25 млн параметров хочет хотя бы
|
||
несколько мегабайт текста, иначе будет только запоминать.
|
||
- **Токенизатор** — слова + символы, не BPE. Для морфологически богатых
|
||
языков это проще, но экономнее BPE приходится платить длиной последовательности.
|