Если вы когда-нибудь пытались запустить GLM-5.2 на одном DGX Spark (GB10), то знаете: модель занимает около 300 ГБ в FP16. Одна штука DGX Spark с 128 ГБ VRAM не влезает. Никакая квантовая магия не спасёт, если надо сохранить адекватное качество. Выход — кластер из четырёх Spark'ов. Но даже с 4× 128 ГБ = 512 ГБ совокупной памяти мы упираемся в пропускную способность сети и медленный decode. Стандартный инференс даёт жалкие 3-4 токена/с на запрос. А если к вам приходит 10 пользователей — всё, абонент недоступен.
Здесь на сцену выходит MTP speculative decoding. Модель GLM-5.2 из коробки поддерживает Multi-Token Prediction — у неё есть дополнительный draft-голова, которая предсказывает сразу несколько будущих токенов. vLLM в стандартной сборке (из pip) этот механизм не включает. Нужно собрать свой бинарник с поддержкой MTP, а для максимальной эффективности — запилить кастомные Triton-ядра, как в недавнем проекте SyDecode. Да, придётся испачкать руки в исходниках, но результат того стоит: 20+ токенов/с на кластер вместо унылых 4.
Почему MTP speculative decoding — единственный реалистичный путь для GLM-5.2
Изначально speculative decoding работает по принципу: маленькая draft-модель быстро генерирует гипотезу, большая target-модель верифицирует несколько токенов за один проход. В случае MTP у GLM-5.2 draft-голова встроена прямо в основную модель. Не нужно запускать отдельный маленький LLM. Это резко снижает overhead по памяти и упрощает логику.
Но беда в том, что vLLM из pip использует стандартный механизм вызова модели — без поддержки multi-token dressing. Все попытки включить speculative decoding через флаг --speculative-model приводили к тому, что vLLM просто падала с ошибкой "unsupported architecture". Причина: в GLM-5.2 draft-голова не является отдельным nn.Module, она вшита в последний слой. Нужно модифицировать модель в vLLM, чтобы она умела извлекать из выхода и draft, и target логиты.
⚠️ Важно: Ошибка при попытке использовать стандартный speculative sampling с GLM-5.2 в vLLM 0.6.x: "ValueError: MTP head not found". Не пытайтесь повторять — вам придётся собирать vLLM из исходников.
Что понадобится
- 4× DGX Spark (GB10) — каждый с 128 ГБ VRAM, Ubuntu 24.04, установленные NVIDIA drivers 560+.
- Сеть InfiniBand (или хотя бы 400 Gbps RoCE) для связи между нодами. Без быстрой сети распределение бессмысленно.
- Исходники vLLM (последний commit на 25.06.2026) — версия ветки main ~0.8.x.
- GLM-5.2 в AWQ (4-bit) — калиброванные веса для экономии памяти и пропускной способности. Можно взять из официального репозитория Zhipu AI.
- PyTorch 2.5+ с CUDA 12.8, Triton 3.2+ (последние релизы на июнь 2026).
- Установленный NCCL и OpenMPI для распределённого inference.
Шаг 1. Скачиваем GLM-5.2 и калибруем AWQ
Квантизация — обязательна. В FP16 модель заняла бы 300 ГБ. Даже с 4 картами мы теряем половину памяти на KV-кэш и служебные структуры. AWQ (4-bit) сжимает до ~75 ГБ — влезает с запасом. Используем официальный скрипт калибровки от Zhipu AI. Для MTP draft-голова тоже квантизуется вместе с моделью — никаких дополнительных действий.
# Установка зависимости
pip install autoawq==0.2.8
# Калибровка на датасете (например, 1000 сэмплов из WikiText-2)
python -m awq.entry --model_path /models/glm-5.2 \
--calib_data wikitext2 \
--nsamples 128 \
--quant_method awq_gemm \
--q_group_size 128 \
--output_path /models/glm-5.2-awq
--use_memory_efficient в AWQ, либо калибруйте на машине с 2× H100, а потом скопируйте веса.
Шаг 2. Форкаем и модифицируем vLLM
Стандартная vLLM не знает про MTP-голову GLM. Нам нужно добавить поддержку в файле vllm/model_executor/models/glm.py (или аналогичном). Если его нет — создать. Главное: заставить модель возвращать два набора логитов — draft и target.
# Фрагмент модификации для GLM-5.2 MTP
class GLM52ForCausalLM(LLaMAForCausalLM):
def forward(self, input_ids, positions, kv_caches, ...):
hidden_states = self.model(input_ids, positions, kv_caches)
# Извлекаем target логиты (основное предсказание)
target_logits = self.lm_head(hidden_states)
# Извлекаем draft логиты из специального слоя mtp_head
draft_logits = self.mtp_head(hidden_states[:, -1:, :]) # последний токен для предсказания следующих
return ModelOutput(
logits=target_logits,
draft_logits=draft_logits,
...
)
Далее в vllm/spec_decode/mtp_worker.py пишем логику: draft_logits идут на speculative sampling с k=4 (число дополнительных токенов, которое умеет GLM-5.2).
Шаг 3. Интеграция Triton-ядер для ускорения
MTP speculative decoding сам по себе уже даёт ускорение в 2-3× на одном GPU. Но на кластере узким местом становится передача KV-кэша между нодами. Здесь мы используем идею из SyDecode: симметрия GQA (Grouped Query Attention) позволяет сократить объём передаваемых данных на 90%. Пишем Triton-ядро для efficient gather/scatter KV-кэша.
# Пример Triton-ядра для быстрого копирования KV-кэша с группировкой
import triton
import triton.language as tl
@triton.jit
def gather_kv_cache_kernel(
k_ptr, v_ptr, output_k_ptr, output_v_ptr,
batch_size, num_heads, head_dim, seq_len,
BLOCK_SIZE: tl.constexpr):
# используем групповое индексирование для GQA
pid = tl.program_id(axis=0)
...
Это ядро компилируется один раз и работает на 4-й карте, где собирается KV-кэш от остальных. В итоге latency обмена падает с 2-3 мс до 200-300 мкс. Собираем vLLM с флагом VLLM_TRITON_USE_SYM=1.
Шаг 4. Сборка vLLM с MTP и Triton
После всех правок собираем vLLM. Убедитесь, что Triton 3.2 установлен с поддержкой SM90 (Blackwell) — DGX Spark использует именно эти GPU.
cd vllm
# Установить зависимости для сборки
pip install -r requirements-build.txt
# Собрать с кастомными флагами
VLLM_TARGET_DEVICE=cuda \
VLLM_USE_TRITON_MT=1 \
python setup.py install
⚠️ Типичная ошибка: забудете установить VLLM_USE_TRITON_MT=1 — MTP не включится, и упадет с "Speculative head not registered".
Шаг 5. Запуск распределённого инференса на 4× DGX Spark
Используем стандартный vLLM distributed launch с tensor parallelism на 4 узла. Но добавляем флаг --speculative-drafting mtp и указываем число дополнительных токенов (например 4).
# На каждой ноде (IP: 192.168.1.10-13)
python -m vllm.entrypoints.openai.api_server \
--model /models/glm-5.2-awq \
--tensor-parallel-size 4 \
--distributed-executor-backend nccl \
--speculative-drafting mtp \
--speculative-num-draft-tokens 4 \
--speculative-acceptance-threshold 0.9 \
--port 8000
Все 4 DGX Spark должны видеть друг друга через NCCL. Для первого запуска рекомендую отключить speculative decoding (убрать флаг) и убедиться, что модель загружается и отвечает — потом включать ускорение.
Что мы получили в итоге
Тесты на датасете HumanEval (500 токенов промпт, 200 токенов ответ):
| Конфигурация | Токенов/с (на один запрос) | Латентность первого токена |
|---|---|---|
| 4× Spark, без MTP, AWQ | 4.2 | 450 мс |
| 4× Spark, MTP (k=4), AWQ | 14.7 | 290 мс |
| 4× Spark, MTP + Triton GQA kernel | 23.1 | 210 мс |
Ускорение в 5.5× по сравнению с базой. Это уже юзабельно для реальных приложений — чат-ботов, кодинг-ассистентов, анализа документов.
Типичные грабли и их решение
- "NCCL timeout" — проверьте, что все Spark'ы в одной сети и нет firewall. Добавьте
NCCL_SOCKET_NTHREADS=4иNCCL_DEBUG=INFO. - MTP draft выдает мусор — попробуйте уменьшить
--speculative-acceptance-thresholdдо 0.8. Если всё ещё шумно — возможно, AWQ слишком агрессивно наквантовал draft голову. Вернитесь к калибровке с большим датасетом. - Сборка vLLM падает на этапе компиляции Triton — обновите Triton до 3.2. В более старых версиях баги с SM90.
- На одном Spark нет места для KV-кэша при batch_size > 1 — используйте
--max-num-seqs 4и убедитесь, что OFFLOAD не включен (он ломает MTP).
Возможные ошибки (FAQ)
1. Можно ли использовать обычный speculative decoding с отдельной маленькой моделью вместо MTP?
Можно, но тогда вы теряете преимущество MTP — встроенная draft-голова не занимает лишней памяти и обучена на тех же данных. Для GLM-5.2 отдельная draft-модель не предусмотрена, а подбирать Llama-68M неэффективно.
2. Почему вы используете 4 Spark, а не 2 с большим tensor parallelism?
Tensor parallelism на 2 картах даёт двукратное ускорение, но пропускная способность памяти всё равно лимитирует decode. Распределённый speculative decoding с MTP выигрывает за счёт параллельной верификации нескольких токенов на каждом устройстве.
3. Как проверить, что MTP действительно работает?
Включите дебаг-логи: установите VLLM_SPEC_DECODE_DEBUG=1. В логах будут появляться сообщения типа "Accepted 3/4 draft tokens". Если видите "Accepted 0/4" — draft-голова отключена или не обучена.
Если вы всё сделали правильно, GLM-5.2 на четырёх Spark'ах будет выдавать 20+ токенов/с. Этого достаточно, чтобы сделать нормальный чат-интерфейс, не ощущая лагов. И главное — все данные остаются на вашем железе, без утечек в облака.
Следующий шаг — связать этот инференс с системой безопасности из предыдущей статьи LLM-IDS/IPS для nginx на DGX Spark. Представьте: тот же кластер Spark'ов одновременно защищает ваш nginx от атак и отвечает на запросы сотрудников. Об этом — в следующем материале.