
В llama.cpp добавили поддержку MTP Qwen3.6. Дополнительные слои Multi-Token Prediction позволяют сгенерировать сразу несколько токенов за 1 проход, что ускоряет генерацию в 1.5-2 раза. Качество при этом остается lossless. Для моделей, которые не имеют встроенного MTP, есть альтернативы в лице EAGLE-3 и DFlash.
TL;DR: Скачать кванты с именем MTP:
И запускать:.\llama-server -m "Qwen3.6-27B-UD-Q4_K_XL.gguf" --spec-type draft-mtp --spec-draft-n-max 4
Что такое MTP
Multi-Token Prediction (MTP) представляют собой дополнительные слои на выходе модели которые работают со скрытым состоянием этой же модели, эти слои обучаются вместе с моделью и они обучаются предсказывать несколько следующих токенов.
Стандартный авторегрессионный трансформер, он же LLM, после прямого прохода имеет выходной слой со скрытым состоянием, которое преобразуют в логиты вероятностей следующего токена. Это только 1 следующий токен, но скрытое состояние может нести информацию о нескольких следующих шагах.
Слои MTP представляют собой несколько голов MTP, которые учатся независимо предсказывать t+1, t+2, t+k следующие токены из одного скрытого состояния. Количество голов определяет сколько можно предсказать следующих токенов.
В llama.cpp поддержку MTP добавили для Qwen3.6: https://github.com/ggml-org/llama.cpp/pull/22673
Для Gemma4 и других моделей поддержка в разработке.
EAGLE-3
Если у модели нет MTP голов, можно применить другой схожий принцип. Скрытое состояние уже содержит информацию о следующих токенах, и можно обучить внешний блок, который научится извлекать из этого состояния информацию. Таким образом можно для любой модели предсказывать k следующих токенов аналогично MTP.
В методе EAGLE-3 создается и обучается 1 легковесная голова, которая добавляет вконце модели, и, в отличии от MTP, это всего 1 голова, которая используется рекурсивно для предсказания k токенов.
Для популярных моделей уже созданы eagle3 модули, которые нужно скачивать отдельно. Также для этого метода важно качество датасета для обучения eagle3.
Поддержка в llama.cpp в статусе черновика: https://github.com/ggml-org/llama.cpp/pull/18039
DFlash
Развивая идеи извлечения токенов из скрытого состояния и пытаясь обойти медленную скорость авторегрессивного трансформера, в котором каждый новый токен зависит от предыдущего и генерация идёт один за другим, был представлен способ блочной диффузии.
В DFlash параллельно за один раз предсказывается сразу блок токенов размером от 8 до 16 за раз. Как и в случае EAGLE-3, DFlash создает и обучает отдельный драфтер, блок диффузий. Метод похож на способ генерации изображений в Stable Diffusion или на LLM Gemini Diffusion.
Этот способ дает наибольшее ускорение среди всех вариантов, до 8 раз.
Поддержка в llama.cpp в статусе черновика: https://github.com/ggml-org/llama.cpp/pull/22105
Теоретический максимум tg t/s
Генерация LLM зависит линейно от скорости памяти, и теоретический максимум генерации можно рассчитать по формуле:
Скорость памяти делить на количество активных параметров. Активные параметры зависят от архитектуры модели, в Dense размер активных будет равен размеру модели. а в MoE или Gemma4 E4B, количество активных параметров будет значительно меньше размера модели. На скорость t/s влияют именно задействованные активные параметры каждого шага.
На примере 4060 ti 16 Гб, у которой скорость VRAM 288 Гб или 268 GiB/s можно сравнить теоретические расчёты и практические. Возьмём модель Qwen3.6-27B, она весит 54 GiB, в кванте UD-Q3 13.5 GiB и влезает в GPU целиком. В таком случае максимально возможная скорость не будет превышать 19.8 t/s. Реальная скорость ниже, так как происходит деквантование весов и прочие вычисления. Реальная скорость составила 17.11 t/s.
На GPU вы ограничены скоростью памяти, а не количеством вычислительных ресурсов, и у вас остаются ресурсы, чтобы за 1 проход перемножать матрицы прямого прохода LLM для параллельных запросов.
Как работает спекулятивное декодирование
Все 3 метода извлекают следующие токены из скрытого состояния основной модели, но нужно узнать, что эти токены предсказаны правильно, ведь если принимать их как есть, то очень быстро выдача будет состоять из некачественных токенов.
Основная идея спекулятивного декодирования заключается в том, что вы можете сгенерировать k следующих токенов и основная модель, используя общий KV-кэш, запустит k параллельных вычислений, проверяя все предложенные токены на совпадение их тому, что предложила бы основная модель.
В этом примере суммарная скорость 8 запросов превосходит одиночный запрос в 7 раз, 20 t/s против 144 t/s, в llama.cpp количество параллельных запросов указывается через параметр --parallel N. В зависимости от архитектуры модели и запаса мощности GPU, одна GPU позволяет параллельно производить вычисления примерно со скоростью одиночного запроса.
Тут важно отметить, что основная модель не смотрит на токены черновика последовательно и каким-то образом решает принять их или нет. Как в примере выше, основная модель запускает параллельные генерации, и последовательности для генерации создаются из предложенных токенов черновика.
Допустим, черновик предложил A, B, C, D, E. Основная модель создает и генерирует:
-
base + A + ?
-
base + A + B + ?
-
base + A + B + … + E + ?
Основная модель запускает генерацию для всех последовательностей и для каждой из них добавляет 1 новый токен. Если этот новый токен совпадает, то текущая цепочка принимается, если и следующий токен совпадает, то следующая более длинная цепочка тоже принимается. И так далее пока не появится несовпадающий токен.
Если черновик предложил цепочку из 4 токенов и вся она была принята, то за 1 проверку мы принимает эти 4 токена + 1 новый, так как и для полной цепочки тоже был запущено параллельное выполнение и сгенерировался 1 новый настоящий токен. И поэтому, даже если будут отвергнуты все токены черновика, то это настоящий +1 токен будет добавлен в результат и такой вариант не дает должен давать просадку скорости даже если отвергнуты все токены черновика. Но при условии, что запаса вычислительных ресурсов хватает.
lossless или токены без потери качества
MTP, EAGLE-3, DFlash должны выдавать качество идентичное оригинпалу. Но как проверить, так ли это? В интернете бытуют разные мнения на этот счет, и я сам не был уверен до конца в этом вопросе. Можно прогонять тесты и сравнивать результаты, или можно заглянуть в исходники llama.cpp и посмотреть как реализован механизм принятия токенов.
Нас интересует файл sampling.cpp, где происходит фаза верификации:
std::vector<llama_token> common_sampler_sample_and_accept_n(struct common_sampler * gsmpl, struct llama_context * ctx, const std::vector<int> & idxs, const llama_tokens & draft, bool grammar_first) { GGML_ASSERT(idxs.size() == draft.size() + 1 && "idxs.size() must be draft.size() + 1"); std::vector<llama_token> result; result.reserve(idxs.size()); size_t i = 0; for (; i < draft.size(); i++) { const llama_token id = common_sampler_sample(gsmpl, ctx, idxs[i], grammar_first); common_sampler_accept(gsmpl, id, true); result.push_back(id); if (draft[i] != id) { break; } } if (i == draft.size()) { const llama_token id = common_sampler_sample(gsmpl, ctx, idxs[i], grammar_first); common_sampler_accept(gsmpl, id, true); result.push_back(id); } return result;}
-
Для каждого токена draft[i] основная модель вычисляет параллельные вероятности.
-
Сэмплер выбирает новый токен каждого параллельного потока.
-
Если новый токен не совпадает с draft[i], то цикл сразу же прерывается.
-
Если совпадает, то токен добавляется в финальную последовательность.
if (draft[i] != id) { break;}
Прерывание цикла при расхождение токенов явное, никак исключений или вероятностей тут не предусмотрено. Это гарантирует идентичность результата, значит спекулятивное декодирование сохраняет lossless качество при использовании черновика.
Как установить llama.cpp и выжать из неё больше
В предыдущей статье я уже писал о том, как установить свежую llama.cpp и как добиться лучших показателей скорости, в целом это простая процедура, но чтобы не повторяться:

Добавлю только, что вам стоит попробовать не только кванты UD, но и кванты от Bartowski, которые могут показать себя лучше: https://huggingface.co/bartowski
И также ollama на днях отказалась от изолированной библиотеки GGLM от разработчиков llama.cpp, и перешла на llama.cpp напрямую.
Где взять кванты для MTP, Eagle3, DFlash
Обычно из GGUF вырезались слои MTP, если у модели они были, чтобы не занимали лишнее место. Qwen3.6 является такой моделью, старые кванты не имеют слоев MTP, хотя оригинальная модель их имела.
С появлением поддержки в llama.cpp эти слои начали возвращать, но в виде отдельных квантов. Все кванты находятся на https://huggingface.co/
Нужно ввести в поиск имя модели и добавить к нему MTP:
Тоже самое для Eagle3 и DFlash:
Для Qwen3.6 MTP можно взять, например, кванты от Unsloth:
Как запустить MTP
На данный момент в llama.cpp по умолчанию включен режим fit, который автоматически всё настроит так, чтобы максимально эффективно нагрузить GPU используя ncmoe. Поэтому активировать fa, настраивать ncmoe или включать cmoe, указывать максимум для ngl и t вручную не требуется.
Это имеет смысл, если вам нужна VRAM для других задач, тогда переключившись на cmoe, можно высвободить много VRAM не особо потеряв в скорости. Или можно указать -fitt N — указать сколько свободной VRAM оставлять в МБ при автонастройке.
Подробнее про разницу между cmoe и ncmoe я рассказывал в статье: Запускаем GPT-OSS-120B на 6 Гб GPU и ускоряем до 30 t/s. Вам нужна RAM, а не VRAM. Параметр -cmoe для ускорения
Если вы скачает модель со слоями MTP, то по умолчанию она запуститься как обычная модель, чтобы активировать MTP нужно явно указать --spec-type draft-mtp и через --spec-draft-n-max 4 указать сколько следующих токенов предсказывать. Размер draft-n-max стоит подбирать в диапазоне количества голов MTP у модели.
Пример запуска, где будет предсказываться 4 дополнительных токена и автонастройка будет оставлять свободными 4 Гб VRAM:
.\llama-server -m "Qwen3.6-27B-MTP-UD-Q4_K_XL.gguf" --spec-type draft-mtp --spec-draft-n-max 4 -fitt 4096
Сравнение скорости
У Qwen3.6 есть 4 головы MTP, вроде как по оригинальной задумке они должны динамически подстраиваться от 2 до 4. В llama.cpp нет такой опции, поэтому нужно будет явно указать какое-то значение.
Тестировать будем Qwen3.6 27B UD-Q4_K_XL и Qwen3.6-35B-A3B-UD-Q4_K_XL. Замеры произведены на 5090, цифры и проценты ускорения на другом оборудование могут отличаться.
Во всех случаях промпт с реддита:
Write a single HTML file with a full-page canvas and no libraries. Simulate a realistic side-view of a moving car as the main subject. Keep the car visible in the foreground while the background landscape scrolls continuously to create the feeling that the car is driving forward. Use layered scenery for depth: nearby ground, roadside elements, trees, poles, and distant hills or mountains should move at different speeds for a natural parallax effect. Animate the wheels spinning realistically and add subtle body motion so the car feels connected to the road. Let the environment pass smoothly behind it, with repeating but varied scenery that makes the movement feel believable. Use cinematic lighting and a cohesive sky, such as sunset, dusk, or daylight, to enhance atmosphere. The overall motion should feel calm, immersive, and realistic, with a seamless looping animation.

Результат для кода в диапазоне draft-n-max от 1 до 7:
Спекулятивное декодирование работает для разных задач по разному и нет универсального значения для MTP. Проверим перевод, сочинение истории на русском и работу в агенте, где заданием будет перегнать старый c++ opengl проект в html.
Для MoE, где активных параметров мало, эффективность будет ниже, так как вычисление 3B в целом имеет высокую скорость и без черновиков. Для Qwen3.6-35B-A3B-UD-Q4_K_XL на задаче кода ускорение всего 33%:
Для перевода ускорение не особо существенно и составляет 7-12%. А вот для сочинения истории произошла деградация на 10-17%. Это может быть связано с тем, что для вычисления MoE GPU не может переиспользовать уже выбранные активные веса, так как для каждого токена задействуются разные эксперты.
Выводы
MTP работает лучше чем черновая маленькая модель, так как обучалось вместе с моделью и новые токены извлекаются из скрытого состояния оригинальной модели, и само MTP весит меньше черновых моделей.
Ускорение зависит от архитектуры модели, от количества активных параметров:
-
Для Dense, где все параметры активные, дает более стабильное ускорение, даже на задачах творчества, для программирования ускорение достигает 2х раз, для творческих задач 33%, для перевода 83%.
-
Для MoE моделей с малым числом активных параметров MTP работает не столь эффективно, 33% для кода, для перевода 12% и неожиданное — деградация на творческий задачах на 10%.
Для моделей которые не имеют MTP есть альтернативные варианты: EAGLE-3 и DFlash.
Изучение исходного кода llama.cpp подтвердило, что качество генерации не страдает и остается lossless при включении MTP.
ссылка на оригинал статьи https://habr.com/ru/articles/1036120/