Xenith
Трансформер на чистом C++: обучение и генерация текста на CPU, без внешних зависимостей. Всё в одном бинарнике.
Что внутри
Архитектура — как у LLaMA: pre-norm, RMSNorm, RoPE, SwiGLU, связанные эмбеддинги (tied weights), каузальное внимание. Обучение — вручную написанный обратный проход + AdamW. Никаких фреймворков.
| файл | что делает |
|---|---|
xenith/core/tensor.h |
матрицы, три формы 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 |
численная проверка градиентов + бенчмарк |
Быстрый старт
# 1) собрать модель из своего текста
./bin/Xenith new models/my.xnh --corpus data.txt \
--vocab 512 --embd 128 --layers 6 --heads 8 --ctx 256
# 2) обучить
./bin/Xenith train models/my.xnh --corpus data.txt \
--out models/my_trained.xnh --steps 5000 --batch 16 --lr 3e-4
# 3) сгенерировать
./bin/Xenith gen models/my_trained.xnh --prompt "Привет" --n 200 --temp 0.8
Команды
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 конфиг с настройками и списком моделей
update - проверка обновления
info / gradcheck / bench
./bin/Xenith info models/my.xnh # конфигурация и словарь
./bin/Xenith gradcheck # градиенты против численных
./bin/Xenith bench models/my.xnh # скорость
gradcheck стоит запускать после любой правки в model.cpp / backward.cpp —
он ловит ошибку в обратном проходе за секунды.
Формат модели
Один файл .xnh содержит и словарь, и веса, и состояние оптимизатора.
При загрузке проверяется каждая размерность тензора, так что модель,
собранная с другими настройками, отвергается с понятной ошибкой, а не
молча портит вывод.
Совместимость с models/test_model.bfr (старый формат) не поддерживается:
там была другая раскладка весов.
Что учесть
- Скорость. ~7600 ток/с на 4 ядрах для 4 слоёв × 64 измерения. С ростом
модели скорость падает квадратично по
embdи линейно по слоям. Замеряйте своимbench. - Форма входа.
text,code,html— чем однороднее корпус, тем меньше словарь и тем быстрее обучение. - Количество данных. Модель на 0.25 млн параметров хочет хотя бы несколько мегабайт текста, иначе будет только запоминать.
- Токенизатор — слова + символы, не BPE. Для морфологически богатых языков это проще, но экономнее BPE приходится платить длиной последовательности.