colibrì: движок GLM-5.2 на 744B параметров в чистом C без зависимостей
📂 Исходный код на GitHubЧистый C, ноль зависимостей: движок для локального запуска GLM-5.2 (744B MoE) стримингом экспертов с диска и int4-квантованием.
colibrì — это inference-движок на чистом C (~2400 строк в одном файле), который запускает модель GLM-5.2 (744B параметров, Mixture-of-Experts) на обычной машине с ~25 ГБ RAM. Никакого BLAS, никакого Python в рантайме, никакого GPU по умолчанию. Секрет в том, чтобы стримить экспертов с диска по требованию.
Главная идея
Модель на 744B параметров активирует лишь ~40B на каждый токен, и только ~11 ГБ из них меняются от токена к токену (это маршрутизируемые эксперты). Отсюда стратегия:
- Dense-часть (attention, shared experts, embeddings — ~17B параметров) живёт резидентно в RAM в int4 (~9.9 ГБ);
- 21 504 маршрутизируемых эксперта (75 MoE-слоёв × 256 + MTP-head, ~19 МБ каждый в int4) лежат на диске (~370 ГБ) и стримятся по требованию через LRU-кэш на каждый слой, опциональный hot-store и OS page cache как бесплатный L2.
Движок — один C-файл c/glm.c плюс небольшие заголовки. Требования: gcc с OpenMP, AVX2, от 16 ГБ RAM и ~370 ГБ int4-модели на локальном NVMe.
Что реализовано
- Точный forward GLM-5.2 (
glm_moe_dsa) — валидирован побайтово противtransformersoracle (teacher-forcing 32/32, greedy 20/20). - MLA attention с сжатым KV-cache: 576 float на токен вместо 32 768 (в 57× меньше — у GLM-5.2 64 головы и нет GQA).
- DeepSeek-V3-style sigmoid router, shared expert, первые 3 dense-слоя.
- Native MTP speculative decoding — собственная multi-token-prediction head GLM-5.2 (слой 78) генерит черновые токены, которые основная модель верифицирует одним батчем. Head обязан быть int8: при int4 acceptance падает до 0–4%, при int8 — 39–59%, 2.2–2.8 токена/forward. Без потерь в точной арифметике.
- Grammar-forced drafts (
GRAMMAR=file.gbnf) — для JSON/NDJSON, function calling и structured extraction грамматика сама служит источником драфтов: везде, где допускается ровно один легальный байт (скобки, кавычки, имена ключей), этот фрагмент инжектируется как pre-accepted draft с ~1.0 acceptance. - Целочисленные dot-ядра (Q8_0-style int8 activations, AVX2
maddubs): int8-матрицы в 1.4–2.5× быстрее (119 GFLOP/s). - MLA weight absorption (трюк DeepSeek) для decode: query поглощает
kv_b, контекст проецируется после attention. - Async readahead экспертов: пока умножается один блок, ядро уже читает следующий (
WILLNEED). - DSA sparse attention — индексер GLM-5.2: top-2048 causal key selection на слой.
- KV-cache persistence — разговоры открываются тёплыми между перезапусками движка: serve-режим дописывает сжатый MLA KV в
.coli_kvпосле каждого хода (~182 КБ/токен, crash-safe) и возобновляет при старте без re-prefill. Валидировано побайтово идентичным с непрерывной сессией. - Router-lookahead prefetch (
PILOT=1, экспериментально) — маршрутизация следующего слоя предсказуема на 71.6% из пост-attention состояния текущего; отдельный I/O-поток префетчит тех экспертов, пока текущий слой считается. - Byte-level BPE tokenizer на C (GPT-2-style, 320k merges).
Честные цифры
На dev-машине автора (WSL2, 12 ядер, 25 ГБ RAM, NVMe через VHDX, ~1 ГБ/с):
| Метрика | Значение |
|---|---|
| Модель на диске (int4) | ~370 ГБ |
| Резидентная RAM (dense, int4) | 9.9 ГБ |
| Время загрузки | ~30 с |
| Пиковый RSS во время чата | ~20 ГБ (авто-cap) |
| Холодная стоимость decode | ~11 ГБ чтений/токен (75 слоёв × 8 экспертов) |
| MTP-спекуляция (int8 head) | 2.2–2.8 токена/forward |
Это не быстро — ~0.05–0.1 tok/s на холодном старте. Но это 744B frontier-модель, отвечающая корректно на машине дешевле одного кулера H100. Тёплый кэш, закреплённые hot-эксперты и MTP заметно снижают латентность.
На лучшем железе комьюнити измеряло: M5 Max 128 ГБ с Metal — 2.06 tok/s, EPYC 7443 с 430 ГБ RAM — 1.00 tok/s (98% hit, диск устранён), 6× RTX 5090 с полным размещением — 6.84 tok/s decode.
Обучающийся кэш
Движок записывает, к каким экспертам реальная нагрузка обращается (.coli_usage рядом с моделью), и при старте автоматически закрепляет самые горячие в свободной RAM. colibrì буквально ускоряется, чем больше им пользуешься. Опциональная живая адаптация тиров (--repin N) заменяет холодые закреплённые эксперты на более горячие по затухающей session heat map.
Эксплуатация
cd c
./setup.sh # проверяет gcc/OpenMP, собирает, self-test
./coli convert --model /nvme/glm52_i4 # FP8→int4, пошардово, возобновляемо
COLI_MODEL=/nvme/glm52_i4 ./coli chat # RAM, кэш, MTP — всё определяется автоматически
Готовая int4-модель с int8 MTP-head доступна на Hugging Face — это пропускает шаг конвертации:
COLI_MODEL=/path/to/GLM-5.2-colibri-int4-with-int8-mtp ./coli chat
Важно: MTP-head обязан быть int8. Оригинальное зеркало с int4-head даёт 0% draft acceptance — спекуляция молча не включается.
OpenAI-совместимый API и веб-дашборд
coli serve держит один процесс с моделью и предоставляет text-only OpenAI-совместимый HTTP API: /v1/chat/completions, SSE streaming, изоляция KV-контекстов через cache_slot (до 16 независимых последовательностей), очередь FIFO с HTTP 429 при перегрузке.
Одна команда поднимает и API, и веб-консоль на одном порту:
./coli web --model <model-dir>
Дашборд показывает живые метрики токенов, панель железа и полосу тиров экспертов, а страница Brain отображает все 19 456 экспертов как живую кору: цвет = тир хранения, яркость = routing heat, эксперты текущего хода вспыхивают белым.
Бэкенды
- CUDA (опционально) — резидентные тензоры на GPU, streaming-эксперты остаются на CPU. На 6× RTX 5090 с авто-размещением всех экспертов — 6.00 tok/s decode при 100% hit.
- Metal (Apple Silicon, экспериментально) — batched SwiGLU, fused decode attention и prefill GEMM на GPU. На M4 Max 128 ГБ: 0.30 → 0.42 tok/s (~1.4×). Greedy-выход побайтово идентичен CPU.
- Windows 11 native (MinGW-w64) — вся специфика платформы изолирована в
compat.h, исходник движка не меняется. CUDA под Windows собирается в отдельнуюcoli_cuda.dll, хост грузит её черезLoadLibrary.
Лицензия
Apache 2.0. Веса GLM-5.2 выпущены Z.ai под MIT.
Источник: https://github.com/JustVugg/colibri