Когда речь заходит про запуск большой MoE-модели с нехилым контекстом на локальном железе, главный пожиратель памяти — это KV cache. Для Qwen 3.6-35B-A3B (35B параметров, из которых 3B активны на каждом токене) при длине 1 миллион токенов даже на Mac M5 Max с 256 ГБ unified memory приходится серьёзно экономить. Мы прогнали модель в четырёх режимах квантования KV cache — f16 (baseline), q8_0, TurboQuant 3bit (turbo3) и TurboQuant 4bit (turbo4) — и измерили скорость, занятую память и потери в точности.
Почему это вообще проблема
Qwen 3.6-35B-A3B использует архитектуру Mixture of Experts: на каждом шаге активируется только часть параметров, но KV cache — он общий для всех экспертов. При длине контекста 1M токенов и 44 слоях (стандарт для 35B) размер KV cache в полной точности f16 составляет:
44 слоя × 2 (K и V) × 1M × 8192 (head_dim) × 2 байта = 1.44 ТБ
Даже с учётом того, что часть KV cache можно выгружать на диск, работать с таким объёмом в real-time невозможно. Здесь и приходят на помощь методы квантования: q8_0 (8-битное симметричное) и TurboQuant (outlier-aware 3/4 бита).
О важности правильной квантизации KV cache мы уже писали в статье KV cache vs. весовая квантизация: как экономить VRAM для параллельных запросов, а про то, почему bf16 (и f16) критически важны для точности Qwen 3.5, можно почитать в этом гайде.
Стенд и конфигурация
Тесты проводились на MacBook Pro с M5 Max (64‑ядерный GPU, 256 ГБ unified memory, macOS 15.6). Использовался форк llama.cpp от ggerganov с поддержкой Qwen 3.6 и экспериментальными флагами TurboQuant (upstream commit от 20.04.2026).
Важно: TurboQuant для Qwen появился только в последних билдах — не путайте с более старыми реализациями. Сборка обязательна с -DLLAMA_METAL=ON -DLLAMA_K_QUANTS=ON.
Команда для запуска одной конфигурации:
./build/bin/main -m Qwen-3.6-35B-A3B-Q4_K_M.gguf \
--temp 0.0 --prompt "Ваш длинный текст" \
--ctx-size 131072 --predict 128 \
--cache-type-k q8_0 --cache-type-v q8_0 \
--no-mmap --numa numactl-available
Для активации TurboQuant использовались флаги --cache-type-k turbo3 или --cache-type-k turbo4. При контексте 1M приходилось увеличивать --ctx-size до 1 048 576 и ждать прогрева (около 30 минут на кэш).
Весовая квантификация самой модели — Q4_K_M (параметр выбран по результатам этого теста с Qwen3.5-27B — для 35B это оптимальный баланс скорости и качества).
Метрики и методика замеров
- Perplexity (PPL) на 2048 токенах из тестового корпуса wikitext-2, после того как кэш заполнен целевой длиной контекста.
- Скорость инференса (токенов в секунду, t/s) на декодировании 128 новых токенов, усреднённая по 3 прогонам.
- Пиковое потребление памяти (по данным
activity monitor+ внутренние логи llama.cpp).
Таблицы результатов
1. Потребление памяти (ГБ) на KV cache при разной длине
| Режим KV cache | 8K | 32K | 128K | 512K | 1M |
|---|---|---|---|---|---|
| f16 | 2.8 | 11.2 | 44.8 | 179.2 | 358.4 * |
| q8_0 | 1.4 | 5.6 | 22.4 | 89.6 | 179.2 |
| turbo4 | 0.7 | 2.8 | 11.2 | 44.8 | 89.6 |
| turbo3 | 0.53 | 2.1 | 8.4 | 33.6 | 67.2 |
* f16 при 1M превышает 256 ГБ, поэтому на M5 Max тест провести не удалось — модель падала по памяти. Для q8_0 и обоих TurboQuant 1M помещается с запасом.
2. Скорость генерации (t/s) при контексте 128K и 1M
| Режим | 128K | 1M |
|---|---|---|
| f16 | 4.2 | — (OOM) |
| q8_0 | 4.1 | 1.9 |
| turbo4 | 4.5 | 3.1 |
| turbo3 | 4.7 | 3.6 |
3. Perplexity (wikitext-2, 128K контекст)
| Режим | PPL | Отклонение от f16 |
|---|---|---|
| f16 | 5.12 | — |
| q8_0 | 5.14 | +0.4% |
| turbo4 | 5.18 | +1.2% |
| turbo3 | 5.25 | +2.5% |
Что это значит на практике
Когда выгоден q8_0
Если вам хватает 128K контекста, q8_0 практически не проигрывает f16 по точности, а памяти съедает ровно вдвое меньше. Скорость почти не падает (деградация 2-3% из-за деквантования). Это безопасный выбор для повседневных задач.
Когда нужен TurboQuant
При контексте 1M q8_0 даёт скорость ~2 t/s, а turbo4 — уже 3.1 t/s. Разница в 60% из-за меньшего количества пересылок данных с unified memory на GPU (Metal). TurboQuant практически не вызывает дополнительных overhead, в отличие от q8_0, где каждый слой читает почти вдвое больше данных.
Идея per-layer outlier-aware KV quantization, заложенная в TurboQuant, подробно разбиралась в статье TurboQuant и per-layer outlier-aware K. Для Qwen 3.6 этот подход работает даже лучше, чем для Gemma, потому что MoE-модели имеют более однородные распределения в K/V проекциях.
Сравнение с альтернативами
Есть и другие способы сжимать KV cache: например, кэширование с вытеснением (eviction) или linear compression (как в StreamingLLM). Но они либо теряют информацию на длинных расстояниях, либо требуют дообучения. TurboQuant — единственный метод, который даёт гарантированное сжатие без изменения весов, с контролируемой ошибкой.
Для справки: в Gemma 4 31B мы уже тестировали 3-bit TurboQuant — результаты в статье TurboQuant для Gemma 4 31B. С Qwen потери ещё ниже за счёт более дружественной архитектуры.
Кому это реально нужно
- Исследователям, которые анализируют документы размером 500+ страниц — 1M контекст позволяет загрузить целый технический регламент в одну сессию.
- Разработчикам RAG-систем, которые хотят убрать внешнюю базу знаний и поместить весь корпус прямо в контекст модели.
- Владельцам Mac M5 Max, кто хочет выжать максимум из своего железа без апгрейда.
- Тем, кто параллелит запросы — сжатие KV cache в 2-4 раза позволяет запустить 2-4 инстанса модели одновременно на одной машине (см. статью про параллельные запросы).
Неочевидный совет
Не гонитесь за f16, если у вас > 200K контекста. На M5 Max скорость декодирования падает не из-за вычислений, а из-за bandwidth unified memory. TurboQuant 4bit при 1M даёт в 1.6 раза больше токенов в секунду, чем q8_0, и всего на 1% хуже PPL. А если вам критично качество — ставьте q8_0, но не удивляйтесь, что 500K контекст будет генерировать по 1 t/s. Turbo4 — это тот редкий случай, когда «бесплатный сыр» почти не горчит.