MoE CPU Offload (`--n-cpu-moe`)
- title
- MoE CPU Offload (
--n-cpu-moe) - type
- concept
- summary
- Разгрузка MoE в llama.cpp: attention в VRAM, неактивные эксперты в RAM через PCIe; +55-60% скорости по сравнению с наивной разгрузкой по слоям
- tags
- llm, local-models, llama-cpp, moe
- sources
- habr-local-llm-16gb-vram-gemma-qwen, habr-local-llm-quantization-deep-dive, reddit-qwen3-6-mtp-12gb-vram
- created
- 2026-05-13
- updated
- 2026-09-14
- lang
- ru
- translation_of
- moe-cpu-offload
- source_updated
- 2026-09-14
- translated
- 2026-09-14
- translator
- lllm/antigravity/gemini-3.7-flash-medium
--n-cpu-moe - флаг llama.cpp, который разделяет Mixture-of-Experts модель с учётом её архитектуры: слои attention остаются на GPU для каждого токена, а блоки экспертов можно вынести в системную RAM. Роутер активирует лишь несколько экспертов на токен, поэтому по PCIe передаются только они - трафик по шине остаётся достаточно низким, чтобы GPU не простаивал в ожидании весов.
Это работает намного лучше классической разгрузки через --n-gpu-layers, которая ничего не знает о структуре MoE и считает каждый слой монолитным. Послойная разгрузка помещает слои целиком (attention + все эксперты этого блока) либо на GPU, либо на CPU. Из-за этого нужный для следующего токена эксперт может оказаться в RAM, и решение роутера упрётся в ожидание полной передачи данных по PCIe.
Измеренный эффект
По результатам тестов Вячеслава на RTX 5070 Ti 16 GB (local-llm-16gb-vram-tests):
| Модель + режим | --n-gpu-layers |
--n-cpu-moe |
Прирост |
|---|---|---|---|
| Qwen 3.6 Fast | 41.3 t/s | 64.0 | +55% |
| Qwen 3.6 Thinking | 41.7 t/s | 66.7 | +60% |
| Qwen Coder Fast | 51.3 t/s | 57.6 | +12% |
| Qwen Coder Thinking | 53.0 t/s | 60.2 | +14% |
Размер прироста напрямую зависит от того, какая часть модели не влезает в видеопамять. Qwen 3.6 (всего 35B) вытесняет больше весов, чем Qwen Coder (всего 30B), поэтому грамотная организация выноса даёт ему более заметный выигрыш. Gemma 4 помещается в VRAM целиком и в разгрузке не нуждается.
Как это работает на практике
Используется связка из двух флагов:
--n-gpu-layers 99(или 999) - концептуально загрузить все слои на GPU. Для dense-моделей это привело бы к OOM, но в случае MoE ситуацию спасает следующий флаг.--n-cpu-moe N- выгрузить блоки экспертов для N слоёв с GPU в RAM.
Значение N подбирается эмпирически: задать начальное число, следить за VRAM через nvtop или аналоги, увеличивать N при OOM под нагрузкой и уменьшать, если остаётся запас. Схема калибровки от Вячеслава: целевая зона составляет 14.0-15.3 GB VRAM на пике, что оставляет 1-1.5 GB запаса под скачки KV cache.
Типичные настройки из статьи:
| Модель | --n-cpu-moe (32K ctx) |
--n-cpu-moe (256K ctx, KV q4_0) |
|---|---|---|
| Gemma 4 26B | 8 | 12 |
| Qwen 3.6 35B | 17 | 23 |
| Qwen Coder 30B | 17 | - |
Моделям Qwen требуется выгружать больше, так как их общий объём весов выше. Переход на контекст 256K требует добавить ещё 6 слоёв для Qwen и 4 для Gemma (у Gemma KV cache примерно в 4 раза больше на токен, поэтому большая часть бюджета уходит на KV; см. kv-cache-sizing).
Что это даёт
Именно это делает тесты написания кода из статьи на Хабре вообще осуществимыми. Без --n-cpu-moe модели на 30B и 35B либо не поместились бы в память, либо генерировали слишком медленно для практического использования. С этим флагом они выдают 60+ токенов/с на потребительской видеокарте стоимостью около 1000 долларов.
Более общий вывод (на который жалуется и Армин Ронахер) заключается в том, что эта ручка настройки существует, критически важна, но совершенно невидима для тех, кто запускает модели через Ollama или LM Studio. Подобные удобные обёртки её не предоставляют. Сборка llama.cpp из исходников и знание этого флага дают около +50% к производительности на подходящем классе моделей. Это и есть тот самый разрыв в качестве проработки ("polish gap"), о котором пишет Ронахер.
Семейство режимов
В llama.cpp теперь есть четыре связанных флага. Из ликбеза Вячеслава и обсуждения на Reddit:
| Флаг | Что делает | Сценарий использования |
|---|---|---|
-ngl N |
Загружает N слоёв на GPU, остальное на CPU | Dense-модели |
-ncmoe N |
Отправляет блоки экспертов N слоёв MoE на CPU | MoE, частичный вынос |
-cmoe |
Все веса экспертов MoE на CPU | MoE, минимум VRAM |
-fit (включён по умолчанию) |
Автоопределение MoE/Dense, выбор режима, оставляет ~1 GB свободными | Большинство пользователей |
-fitt N |
Как -fit, но оставляет N МБ свободными |
Нужен явный запас под KV cache или draft-модель |
-fit теперь включён по умолчанию. Он распознаёт архитектуру MoE и автоматически применяет -ncmoe; для Dense-моделей используется -ngl. Это поведение можно переопределить с помощью -cmoe, чтобы принудительно выгрузить всех экспертов на CPU. --fit-target 1024 резервирует заданный объём свободной VRAM (-fitt 1536 - явная форма -fit с целевым значением 1536 МБ).
Практическое следствие: в предыдущей статье с тестами флаг --n-cpu-moe 17 задавался вручную. С появлением -fit в современных версиях llama.cpp ручная настройка больше не нужна - достаточно указать --fit-target и доверить выбор движку. В конфигурации с Reddit используется -fitt 1536, чтобы оставить место под draft-головы MTP и 128K KV cache.
Почему этого нет в Ollama
Под капотом Ollama использует движок GGML от llama.cpp, поэтому она могла бы включать -ncmoe для MoE-моделей. Но она этого не делает. Ollama использует -ngl для всего подряд, включая MoE. Результат на RTX 4060 16GB с Qwen3.6-35B-A3B Q4_K_M (замеры Вячеслава):
| Движок | Режим | Скорость на контексте 4K | Скорость на контексте 32K |
|---|---|---|---|
| Ollama | -ngl |
16 t/s | 11 t/s |
| llama.cpp | -fit (авто -ncmoe) |
45 t/s | 36 t/s |
Трёхкратная разница вызвана исключительно выбором режима, а не самим движком. Если Ollama включит -ncmoe, разрыв исчезнет.
Связанные страницы
- mixture-of-experts - почему это возможно с точки зрения архитектуры
- kv-cache-sizing - вторая половина бюджета VRAM
- speculative-decoding - сочетается с этой техникой; бюджет
-fittдолжен покрывать и draft-головы - llama.cpp - движок инференса, реализующий этот подход
- qwen3-8-flash-next - пошаговая настройка
-ncmoeна одной RTX 5090 подняла скорость генерации с 11 до 52 t/s, а при одной лишней группе слоёв экспертов скорость упала до 3.7 t/s без каких-либо ошибок из-за неявного переполнения VRAM в системную память - deltafin - та же идея уровнем хранения ниже: потоковая загрузка маршрутизируемых экспертов Kimi K3 с SSD или по HTTP вместо системной RAM
- deltafin
- llama.cpp
- local-llm (jamesob)
- OpenCode
- Local LLMs Deep Dive — Quants, MoE Offload, REAP, ik_llama, Speculative Decoding
- LLMs: Intelligence vs. Cost
- KV Cache Sizing
- Coding-Agent Tests of Local LLMs on 16 GB VRAM
- Mixture of Experts (MoE)
- Qwen4: The Architecture of the Future (Qwen3.8-Flash-Next)
- REAP — Router-weighted Expert Activation Pruning
- 80 tok/s + 128K Context on 12GB VRAM — Qwen3.6 + MTP
- Speculative Decoding