Плотная 27B-модель Qwen3.8 на двух RTX 3090 в llama.cpp из коробки выдаёт 32 токена в секунду. Энтузиаст из Habr показал, что это не предел: те же веса с определёнными флагами запуска разгоняются до 75 ток/с — в 2.3 раза быстрее. Разбираем, какие приёмы для этого нужны и где они ломаются.
Почему 32 ток/с — это не «упёрлись в железо». Плотная модель на каждый токен читает все веса. Файл весит 24.1 ГБ, память 3090 — около 936 ГБ/с. При послойном разбиении карты работают по очереди: 12 ГБ / 936 ГБ/с ≈ 12.9 мс на карту, 25.7 мс на токен, потолок ≈ 39 ток/с. Из коробки — 32.4, то есть 83% от потолка. Сам потолок низкий, и его поднимают две вещи: читать веса на обеих картах одновременно и получать больше одного токена за проход.
| Режим | Генерация, короткий контекст | Генерация @ 130K | Генерация @ 240K | Два слота параллельно | Обработка промпта @ 40K | Обработка промпта @ 240K | VRAM |
|---|---|---|---|---|---|---|---|
| -sm layer | 58.5 | 41.4 | 34.4 | 36.3 + 36.3 | 1410 | 764 | 42.4 ГБ |
| -sm tensor | 74.7 | 58.9 | 55.4 | 47.4 + 50.3 | 1121 | 743 | 43.6 ГБ |
Приём 1: MTP-спекулятивное декодирование. В GGUF Qwen3.8 лежит слой Multi-Token Prediction (blk.64.nextn.*) — встроенная draft-модель. По умолчанию llama.cpp его не использует и пишет в лог unused tensor. Флаги: --spec-type draft-mtp --spec-draft-n-max 3 -ctkd q4_0 -ctvd q4_0. Эффект: 32.4 → 58.5 ток/с (послойный режим), ×1.8. Где ломается: KV-кэш черновика — отдельный, -ctk/-ctv на него не действуют; без -ctkd/-ctvd он хранится в f16 и молча ест VRAM. Глубина черновика больше 4 вредит: замеры 2 → 52.8, 3 → 57.3, 4 → 57.6, 6 → 54.3 ток/с. Выигрыш зависит от промпта: на коде и структурированном тексте черновик угадывает чаще, на свободном рассуждении — реже.
Включение MTP-спекулятивного декодирования ускорило генерацию до 58.5 ток/с (×1.8).
Приём 2: тензорный параллелизм. С build 10666 у --split-mode есть значение tensor — тензорный параллелизм через NCCL: обе карты считают каждый слой одновременно, вместо того чтобы работать по очереди. Флаг: -sm tensor. Плюс на контейнере обязательно --ipc=host (или --shm-size). Эффект (обе колонки с MTP, три прогона на точку, разброс ±1 ток/с): -sm layer даёт 58.5 на коротком контексте, -sm tensor — 74.7; на 130K — 41.4 против 58.9; на 240K — 34.4 против 55.4; два слота параллельно — 36.3+36.3 против 47.4+50.3. Обработка промпта при этом замедляется: −20% на 40K, −11% на 130K, −3% на 240K. Для интерактивной работы выгодно; для batch-прогонов коротких промптов — не факт. Где ломается: без --ipc=host первый же decode падает с CUDA error: unhandled system error в ggml_backend_cuda_comm_allreduce_nccl. -ts не работает: llama_params_fit is not implemented for SPLIT_MODE_TENSOR. Автоподбора нет, размер контекста подбирайте руками и проверяйте по nvidia-smi. backend sampling not supported в логе — не ошибка: сэмплирование уезжает на CPU, на скорости не сказалось. -sm row на этой конфигурации не работает вообще: error loading model: device CUDA0 does not support split buffers.
Приёмы 1 и 2 вместе (одни веса, один промпт): без MTP — 32.4 (layer) и 48.2 (tensor); с MTP — 58.5 (layer) и 74.8 (tensor). Итог: 74.8 ток/с на генерации, два запроса по 262 144 токена одновременно, качество на авторских тестах не изменилось.
Приём 3: выбор сборки GGUF. Два файла с одной меткой «Q6» могут быть устроены по-разному, и меньший не обязательно быстрее. Автор сравнил четыре сборки одной модели: unsloth Q8_0, bartowski Q8_0, bartowski Q6_K_L, orcarouter Uncensored (абляция). Качество: все четыре — 13/16 на авторском наборе, провалили одни и те же три задачи. Скорость в один день, одни аргументы: unsloth Q8_0 — 57.6, bartowski Q6_K_L — 60.2 ток/с. Гипотеза: таблицы тензоров двух файлов различаются — у bartowski Q6_K_L 37 типов квантования, у unsloth UD-Q6_K — 3; token_embd / output: Q8_0/Q8_0 против Q6_K/Q8_0. Это дымовой тест, не бенчмарк; perplexity не мерил.
Стенд автора: 2× RTX 3090 (24 ГБ, PCIe 4.0 x16, без NVLink), Threadripper 3960X, 121 ГБ RAM, Ubuntu 26.04, драйвер 595.71.05, llama.cpp — образ ghcr.io/ggml-org/llama.cpp:full-cuda, build 10666. На PCIe x8/x4 all-reduce дороже, результат может быть другим. Для практики: если у вас похожая конфигурация, попробуйте MTP и -sm tensor — это может дать значительный прирост без апгрейда железа.

