5 февраля вышла статья про DFlash — способ ускорить генерацию у любой языковой модели, не трогая саму модель, — а следом NVIDIA выложила бенчмарки с заголовком «до 15× выше пропускная способность», и это тот тип цифры, ради которой стоит остановить всё и проверить. Мы взяли драфтер DFlash для Gemma 4 26B — он лежит в том же репозитории, откуда качается сама модель, — прогнали на своём стенде и получили 2,31× — ровно до тех пор, пока на карте висит один запрос. После четырёх одновременных запросов DFlash начинает проигрывать обычной модели по суммарной пропускной способности, на восьми — в полтора раза.
Ниже — как это устроено, откуда берутся 15×, и почему наш график расходится с вендорским не потому, что кто-то соврал.
Как DFlash ускоряет генерацию
Обычная модель декодирует авторегрессивно: один проход по всем весам — один токен. На батче из одного запроса это чудовищно неэффективно. Чтобы посчитать единственный токен, GPU обязан прокачать через себя все веса модели, и упирается он не в вычисления, а в пропускную способность памяти. Арифметические блоки при этом почти простаивают.
Спекулятивное декодирование продаёт этот простой. Маленькая «черновая» модель быстро предлагает сразу несколько следующих токенов, а большая проверяет весь блок за один проход — тот самый проход, который она всё равно собиралась сделать ради одного токена. Совпавший префикс принимается целиком, первое расхождение обрубает хвост. Схема математически честная: распределение выхода не меняется, ускорение бесплатное по качеству.
Узкое место тут — сам черновик. Классические методы вроде EAGLE-3 генерируют его тоже авторегрессивно, то есть последовательно: пять черновых токенов — пять маленьких проходов. Идея DFlash в том, чтобы заменить черновую модель блочной диффузионной: она выдаёт весь блок за один проход, параллельно, а не по одному токену. Плюс её кормят внутренними признаками из большой модели, чтобы черновик лучше попадал в контекст. В статье авторы заявляют шестикратное ускорение без потери качества и до 2,5× преимущества над EAGLE-3.

В нашем случае черновик — это отдельный диффузионный модуль на 451 МБ, пристёгнутый к MoE-модели на 26B параметров с 4B активных. У нас он попадал в продолжение примерно в четверти случаев, а средняя длина принятого блока вышла 2,06 токена: то есть за один проход большой модели выходит в среднем два токена вместо одного.
Откуда взялись 15×
Цифра настоящая, но её надо читать вместе с условиями. 15× NVIDIA получила на gpt-oss-120b, восьми DGX B300 и TensorRT-LLM, и не «вообще», а в конкретной точке кривой Парето — там, где на каждого пользователя приходится 500–600 токенов в секунду. Это режим предельной отзывчивости, в котором обычное авторегрессивное декодирование почти нежизнеспособно: чтобы выдать столько токенов одному пользователю, приходится держать батч почти пустым и жечь карту впустую. DFlash в этой точке действительно рвёт базовую линию, потому что сравнивают его с заведомо неэффективным режимом работы.
Стоит сдвинуться в нормальный режим — и множитель садится. В той же статье NVIDIA приводит таблицу при сопоставимой конкурентности: в среднем 2,3× для gpt-oss-120b и 2,8× для Llama 3.1 8B. На одиночном запросе и одной карте — 5,8× на Math500 и 4,4× на MBPP для Gemma-4 31B — соседки по семейству той модели, которую взяли мы. То есть вендорские же данные дают разброс от 1,8× до 15× в зависимости от того, где мерить, и 15× — это самый край.
Что получилось у нас
Мы мерили суммарную скорость генерации на своём стенде, наращивая число одновременных запросов. Базовая линия — Gemma 4 26B без спекуляции, вторая колонка — та же модель с DFlash.

Стенд: одна NVIDIA RTX 6000 PRO, драйвер 610.57.04, CUDA UMD 13.3, инференс в Docker 29.7.2 — llama.cpp server-cuda, сборка 10711. Модель gemma-4-26B-A4B-it-Q4_0, KV-кэш q4_0, 512 токенов на запрос, длина черновика --spec-draft-n-max 4.
| Одновременных запросов | База, ток/с | DFlash, ток/с | Отношение |
|---|---|---|---|
| 1 | 180,8 | 418,0 | 2,31× |
| 2 | 325,8 | 519,3 | 1,59× |
| 3 | 440,8 | 480,3 | 1,09× |
| 4 | 517,3 | 522,3 | 1,01× |
| 6 | 674,7 | 581,5 | 0,86× |
| 8 | 779,4 | 538,2 | 0,69× |

Читать этот график интереснее не по отношению, а по форме двух кривых. База растёт почти линейно: 181 → 326 → 441 → 517 — карта постепенно загружается, каждый добавленный запрос приносит почти столько же токенов, сколько первый. DFlash выходит на полку сразу после первого запроса и дальше болтается в коридоре 480–580, куда бы мы ни двигали конкурентность. Перелом — около 4,1 запроса. И даже левый край нашего графика вдвое с лишним ниже вендорских 5,8× на соседней модели того же семейства: у NVIDIA — Math500 на своём стенде, у нас — смешанная нагрузка на одной карте.
Важная деталь: проигрывает здесь сервер целиком, а не отдельный пользователь. Скорость одного потока у DFlash не опускалась ниже базовой ни в одной точке развёртки — на восьми параллельных запросах вышел паритет, 98,8 против 97,5 ток/с на поток. Просаживается именно суммарная пропускная способность: карта тратит такты на черновики, которые тут же выбрасываются.
Почему конкурентность съедает ускорение
Обе техники живут за счёт одного и того же ресурса — простаивающих арифметических блоков GPU, — и поэтому не складываются, а конкурируют.
Спекуляция тратит этот простой на черновые токены, часть которых заведомо пойдёт в мусор: блок почти всегда обрубается не на последней позиции, и всё, что за обрывом, посчитано впустую. При одном запросе это ничего не стоит — арифметические блоки всё равно простаивали, выброшенные вычисления бесплатны.
Батчинг тратит тот же простой на чужие настоящие токены. Восемь параллельных запросов гоняют веса через память один раз на всех и считают восемь полезных токенов за проход — ни один не выбрасывается. Как только батч заполняет карту, узкое место переезжает из памяти в вычисления, и вот тогда выброшенные черновые токены перестают быть бесплатными: они отъедают такты у реальной работы. Отсюда и полка на нашем графике, и падение ниже базовой линии.
Это не дефект DFlash, это его границы применимости — и индустрия про них знает. Продакшен-стеки умеют сами отключать спекуляцию при росте конкурентности; порог часто ставят в районе 32 одновременных последовательностей.
Честная оговорка: наш перелом наступает намного раньше типичных для индустрии тридцати с лишним запросов. Это не опровержение вендорских цифр, а другая точка на той же кривой: другое железо — одна карта, а не восемь B300 на Blackwell Ultra, и другой стек — llama.cpp вместо TensorRT-LLM. На восьми B300 с TensorRT-LLM полка окажется заметно правее. Смысл замера не в том, что NVIDIA завысила, а в том, что множитель нельзя переносить со стенда вендора на свой кластер.
Почему прирост есть только на математике и коде
Второе, что видно на замерах: ускорение сильно зависит от того, о чём спрашивать. Внятный прирост мы получили на математических задачах и на генерации кода. На свободном тексте он не просто исчезает, а уходит в минус.
Вот отдельный прогон на том же стенде, разложенный по типам задач: один запрос на карте, 1024 токена, черновик длиной до 15 токенов — заметно жаднее, чем в таблице выше. Третья строка — режим mtp, второй способ спекуляции, который мы гоняли за компанию.
| Режим | Математика | Код | Проза | Среднее | К базе |
|---|---|---|---|---|---|
| База | 188,0 | 189,6 | 189,4 | 189,0 | — |
| DFlash | 303,9 | 254,5 | 179,1 | 245,8 | 1,30× |
| MTP | 211,7 | 175,0 | 143,7 | 176,8 | 0,94× |
Математика — 1,62×, код — 1,34×, проза — 0,95×: на свободном тексте DFlash уже не помогает, а мешает, и средние 1,30× держатся исключительно на первых двух колонках. У mtp математика вытянула всего 1,13×, а код и проза ушли в минус — в среднем он проигрывает базовой линии, и дальше мы его не рассматривали.
Заодно эта таблица объясняет, почему здесь 1,30×, а в развёртке выше — 2,31×: дело в длине черновика. Пятнадцать токенов мы взяли из примеров в документации, и это оказался худший из проверенных вариантов: те же 1024 токена на n-max=4 дают 330,6 ток/с против 245,8 на n-max=15. Чем длиннее черновик, тем больше вычислений сгорает при отказе, так что заявленный размер блока — верхняя граница, а не рекомендация.
Механика та же — доля принятых черновиков. Черновая модель угадывает продолжение тем лучше, чем меньше в нём энтропии. В выкладке или в коде следующие токены жёстко заданы синтаксисом и шаблоном: закрывающая скобка, имя переменной, знак равенства, стандартный заголовок функции. В живой прозе на каждом шаге десятки равновероятных продолжений, черновик мажет на второй-третьей позиции, блок обрубается — и мы платим за весь просчитанный блок ради одного-двух принятых токенов. Русский добивает ещё и токенизацией: на то же слово уходит больше токенов, значит больше шансов промахнуться внутри блока.
Это ровно то, что видно в вендорских наборах: DFlash тестируют на Math500, GSM8K, HumanEval и MBPP — самых предсказуемых текстах, какие есть. У самой же NVIDIA на «писательских» задачах множитель падает до 1,8× против 2,6× на коде. Есть и внутреннее ограничение: точность черновика падает к концу блока — по данным авторов второй версии метода, с 99,5% на первой позиции до 87,8% на седьмой.
Побочная находка: квантованный KV-кэш стоит 39% скорости
Пока подбирали настройки, наткнулись на вещь, к DFlash отношения не имеющую, но куда более дешёвую в исправлении. Мы держали KV-кэш квантованным (--cache-type-k/v q4_0) — ради длинного контекста. Замена его на f16 подняла базовую линию со 189,0 до 263,1 ток/с, то есть на 39%, вообще без всякой спекуляции; на восьми параллельных запросах — 917 против 784.
Бесплатным этот выигрыш не бывает: f16-кэш занимает примерно вчетверо больше памяти, и на карте поменьше он вместе с моделью и длинным контекстом просто не поместится — придётся выбирать между контекстом и скоростью. Но порядок величины показателен: прежде чем прикручивать спекуляцию, стоит посмотреть, не отдал ли ты те же 39% на квантовании кэша.
И это же — иллюстрация главного тезиса статьи. На q4_0-кэше лучший вариант DFlash давал 1,75× к базовой линии, на f16 — уже 1,35×. Чем аккуратнее выжат базовый инференс, тем меньше остаётся выжать спекуляции.
Что это меняет
DFlash — хорошая инженерия с узкой областью применения, а не бесплатное ускорение для всех. Он окупается там, где важна скорость для одного пользователя, а не суммарная пропускная способность железа: локальный запуск на одной карте, ассистент в IDE, автодополнение кода, вызовы инструментов у агента. Во всех этих сценариях карта и правда недогружена, и спекуляция забирает себе простой, который иначе пропал бы зря. Причём чем медленнее карта, тем спекуляция выгоднее: чем дороже обходится шаг целевой модели, тем больше окупается черновик.
Там, где на карте живёт очередь из пользователей — то есть в любом публичном сервисе, — выгоднее обычный батчинг, и включённая спекуляция начинает мешать. Вывод для нас практический и скучный: свою конфигурацию надо мерить самому, на своих задачах, своих языках и своей реальной конкурентности. Один множитель из пресс-релиза не переносится никуда.
Где посмотреть на скорость у нас
Мы этот вывод применили к себе. В GPTunneL есть Grom 1.5 — наша собственная модель на нашем железе, и мы гнались там ровно за тем, что чувствует пользователь: первый токен примерно через 500 мс и до 120 токенов в секунду в потоке. Достигнуто это не спекуляцией, а тем, что мы контролируем весь стек: балансировщик разводит запросы по пулам под вес задачи, префикс диалога лежит в памяти GPU, а размер модели подобран под то железо, на котором она реально крутится.



