EnglishРусский Map

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
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