редакции
Как мы запустили Qwen3.6-27B на Tesla V100 32GB
Несколько месяцев назад мы переехали с OpenAI API на собственный инференс. Причины банальные: оплата в рублях, данные в России, предсказуемая стоимость. Железо — Dell PowerEdge T440 с одной Tesla V100 SXM2-32GB. Карточка старая, но 32 гигабайта HBM2 до сих пор позволяют запускать приличные модели.
В этой статье расскажу, как мы перешли с vLLM на llama.cpp, подключили Multi-Token Prediction и получили ~45 tok/s вместо ~27 — на том же железе, без апгрейда.
С чего начинали
Изначально всё крутилось на vLLM с моделью Qwen3.6-27B в квантовании Q6_K от lmstudio-community. Скорость была ~27 токенов в секунду, VRAM занято 23.6 GB из 32, контекст 32K.
Работало нормально, но хотелось быстрее. Пользователи в чат-виджете замечают паузу, когда модель думает дольше 2-3 секунд.
Почему V100, а не что-то новее
Tesla V100 — это архитектура Volta (sm_70), 2017 год. Новые потребительские карты типа RTX 4090 дешевле и быстрее на токен, но у V100 SXM2 есть своё преимущество: 32 GB HBM2 с пропускной способностью 900 GB/s. Для LLM-инференса пропускная способность памяти важнее вычислительной мощности — модели при генерации упираются именно в memory bandwidth.
Поэтому на V100 32GB можно комфортно запускать 27B модели в Q6_K (22.5 GB), чего не сделаешь на большинстве потребительских карт с 16-24 GB.
Но есть нюанс: V100 не поддерживает CUDA 13.x. Строго CUDA 12.6, и llama.cpp нужно собирать с флагом -DCMAKE_CUDA_ARCHITECTURES=70.
Переход с vLLM на llama.cpp
vLLM отличный фреймворк, но для single-GPU сетапа llama.cpp оказался проще в управлении и дал сравнимую скорость. Плюс — нативная поддержка GGUF и MTP прямо в mainline ветке начиная с версии v9976.
Сборка под V100: cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=70 cmake —build build —config Release -j$(nproc)
Базовый запуск модели: ./llama-server \ -m /opt/models/qwen36-27b/Qwen3.6-27B-Q6_K-ggml.gguf \ -ngl 99 \ -c 32768 \ —port 8080 \ —host 0.0.0.0 \ —jinja \ —reasoning off \ —alias qwen3.6 \ —parallel 2
Флаг —reasoning off отключает внутренний chain-of-thought у Qwen3.6 — без него модель тратит лишние токены на «размышления» перед ответом, что замедляет диалоговые задачи.
Скорость на этом этапе: ~27 tok/s. То же самое что на vLLM.
Multi-Token Prediction — главный трюк
MTP (Multi-Token Prediction) — это архитектурная особенность ряда современных моделей, в том числе Qwen3.6. Модель обучена предсказывать не один следующий токен, а сразу несколько. llama.cpp умеет это эксплуатировать через speculative decoding с MTP-головами.
Как это работает: черновая MTP-голова (отдельный небольшой файл) предлагает 2-3 следующих токена, основная модель их верифицирует за один проход. Если угадала — принимаем все, если нет — откатываемся к последнему корректному. На диалоговых задачах acceptance rate обычно 35-45%.
Нюанс с совместимостью. Существует сторонний форк am17an с поддержкой MTP, но он несовместим с архитектурой Qwen3.6 — при запуске segfault. Нужен именно mainline llama.cpp v9976+, там MTP реализован нативно через —spec-type draft-mtp.
Нюанс с весами. MTP-файл для Qwen3.6 есть только у ggml-org на HuggingFace. У lmstudio-community его нет. Мы скачали Q8_0 и переквантовали в Q4_0 через —allow-requantize: ./llama-quantize —allow-requantize \ Qwen3.6-27B-Q8_0.gguf \ mtp-Qwen3.6-27B-Q4_0.gguf Q4_0
Финальный запуск с MTP: ./llama-server \ -m /opt/models/qwen36-27b/Qwen3.6-27B-Q6_K-ggml.gguf \ -md /opt/models/qwen36-27b/mtp-Qwen3.6-27B-Q4_0.gguf \ —spec-type draft-mtp \ —spec-draft-n-max 3 \ -ngl 99 \ -c 32768 \ —port 8080 \ —host 0.0.0.0 \ —jinja \ —reasoning off \ —alias qwen3.6 \ —parallel 2
Результат
Прирост ~67% на том же железе. MTP съел всего 1.3 GB VRAM на черновые веса, взамен дал стабильный буст генерации.
На практике пользователь видит первый токен примерно через секунду, дальше текст течёт заметно быстрее чем при ~27 tok/s. Для чат-виджета это ощутимая разница.
Подводные камни
- CUDA версия. V100 = sm_70 = CUDA 12.x максимум. Не пытайтесь ставить CUDA 13.x — не заведётся.
- Форк vs mainline. Если гуглите MTP для llama.cpp и находите форк am17an — проверьте совместимость с вашей моделью до компиляции. Для Qwen3.6 он не работает.
- Источник MTP-весов. Берите только у ggml-org. У других источников MTP-файла просто нет.
- Q6_K — потолок для 32GB. Q8 (29 GB) + KV-cache на 32K контекст = выходит за 32 GB. Q6_K (22.5 GB) с запасом позволяет держать нормальный контекст и 2 параллельных слота.
- systemd и порядок запуска. GPU инициализируется не мгновенно после ребута. Если llama-server стартует раньше чем nvidia-persistenced поднял карту — сервис упадёт. Фиксится через After=nvidia-persistenced.service и ExecStartPre=/bin/sleep 5 в юните.
Итого
Если у вас есть V100 32GB и вы на llama.cpp — попробуйте MTP. Это бесплатный прирост скорости без замены железа и без деградации качества (черновые токены верифицирует та же основная модель Q6_K).
Весь стек работает как OpenAI-совместимый API на порту 8080 — меняете только base_url и api_key в своём коде, всё остальное без изменений.
Если интересно как устроен сам чат-виджет поверх этого API — пишите в комментарии, расскажу отдельно.