- BrainTools - https://www.braintools.ru -

Гибридные трансформеры под нагрузкой: где Gated DeltaNet проигрывает full attention

Гибридные модели обещают простую вещь. Память [1] под контекст перестаёт расти линейно с его длиной, значит длинный контекст дешевеет, значит на ту же карту влезает больше пользователей. Звучит настолько разумно, что проверять как-то неловко.

Я всё-таки проверил, потому что интересовало как эта архитектура будет вести себя под нагрузкой и вписываться в существующий стек инференса. Снял на вечер машину с двумя RTX 3090 и прогнал по двум моделям одну и ту же агентскую нагрузку. Qwen3-4B: обычная, полная аттеншн во всех 36 слоях. Qwen3.5-4B: гибридная, полная аттеншн осталась в 8 слоях из 32, а остальные 24 заменены на рекуррентные слои Gated DeltaNet (arXiv:2412.06464 [2]), которые вместо растущего списка ключей и значений держат стейт фиксированного размера.

Короткий ответ вышел такой: под нагрузкой гибрид чаще проигрывает чем выигрывает. Он выигрывает там, где важна цена памяти на токен: длинный контекст, длинная генерация, много одновременных сессий на одной карте. А на самом частом сценарии, коротком диалоге с общим системным промптом, он проигрывает, и большая часть отставания приходится на кеш, а не на скорость самой модели.

Проигрывает он из-за того, как устроена его память. Рекуррентные состояния и обычные KV-страницы лежат в одном пуле, страницы там обязаны быть одного размера, и чтобы страница аттеншн догнала по размеру страницу состояния, движок поднимает блок кеша с 16 токенов до 528. Совпадение префиксов после этого засчитывается в 33 раза грубее: на каждом запросе заново пересчитывается кусок промпта, который у обычной модели нашёлся бы в кеше. На моей нагрузке это 84% попаданий против 94% у обычной модели и в три раза больше токенов промпта, которые каждый раз считаются с нуля. Подробно все преимущества и недостатки разберем дальше.

1. Небольшой глоссарий

Базовую информацию про KV-кеш, префиксное кеширование и блоки кеша можно прочитать в другой моей статье KV-Cache в LLM: разбираем инференс через 9 ключевых вопросов [3].

Гранулярность. Размер блока, которым нарезается KV-кеш.

Тенант. Один синтетический клиент со своим системным промптом и диалогом.

Рабочий набор. Суммарный контекст активных тенантов.

Попадания в кеш. Доля токенов промпта, которые нашлись в кеше

TTFT. Время до первого сгенерированного токена.

ITL. Среднее время между генерацией следующего токена.

2. Арендуем стенд для экспериментов.

Прогоны шли на одной карте с одними версиями софта, чтобы разница осталась только в моделях. Железо арендованное и намеренно скромное: мне были интересны числа, которые получаются на потребительской машине, которую обычно снимают для своих микро B2B вертикальных SaaSов.

Значение

GPU

2× RTX 3090, 24 ГБ; в большинстве замеров работала одна карта

CPU / RAM

16 vCPU, 125 ГБ, swap отключён

Шина

PCIe Gen4 x16, замерено 23.57 ГБ/с

Драйвер / CUDA

595.58.03 / 13.2

vLLM / torch

0.26.0 / 2.11.0+cu130

Сами модели:

Qwen3-4B

Qwen3.5-4B

Слоёв

36, все с полным KV

32: 8 с полным KV, 24 рекуррентных (Gated DeltaNet)

Геометрия аттеншн

GQA 32/8, размерность головы 128

GQA 16/4, размерность головы 256

KV на токен

144 КБ

36 КБ

Рекуррентное состояние

нет

2.05 МБ на слой, 49.1 МБ на снимок

Веса в bf16

7.49 ГБ

8.68 ГБ (модель мультимодальная, с башней зрения [4])

Класс модели в vLLM

Qwen3ForCausalLM

Qwen3_5ForConditionalGeneration

Время старта

~30 с

127 с, включая 33 с компиляции

Про синтетические данные для теста: нагрузка у меня агентская, то есть длинный повторяющийся префикс плюс короткий уникальный хвост. Это профиль, на котором префиксный кеш имеет смысл. Если ваша нагрузка — независимые одиночные запросы без общих начал, половина выводов ниже к вам не относится.

3. Full Attention vs Gated DeltaNet: как две архитектуры помнят прошлое

Двадцать четыре слоя из тридцати двух у гибрида не хранят KV. Без механизма все дальнейшие числа выглядят произвольными, поэтому сначала он.

Модель с полной аттеншн помнит контекст списком. На каждый токен, в каждом слое, в каждой KV-голове она держит пару векторов, и список растёт линейно с длиной контекста. Префиксное кеширование поверх такого устройства — это шаринг кусков списка: совпало начало промпта, значит совпали куски списка, второй запрос берёт готовые.

Рекуррентный слой помнит контекст состоянием. Вместо растущего списка он держит один тензор фиксированного размера — состояние. На каждом новом токене слой частично затирает то, что в состоянии уже лежит, и дописывает туда поправку от нового токена. Первое — управляемое забывание [5], «гейт». Второе — правило дельты, корректирующая запись вместо слепого накопления. Отсюда и название архитектуры, Gated DeltaNet.

Полная аттеншн ведёт блокнот, в который только дописывают. Рекуррентный слой пишет на доске и каждый раз частично её стирает.

Размер состояния не зависит от длины контекста: на Qwen3.5-4B это 2.05 МБ на слой и при 500 токенах, и при 30 тысячах. Прошлое в нём сжато с потерями — восстановить конкретный токен, который был двадцать тысяч шагов назад, из сводки нельзя.

Префиксное кеширование для гибрида поэтому — отдельная инженерная задача. Чтобы второй запрос переиспользовал общий префикс, ему нужна сохранённая копия состояния в точке конца префикса: текущее состояние уже испорчено уникальным хвостом первого запроса. У полной аттеншн такой проблемы нет, там блоки после записи не меняются, и хвост первого запроса лежит в своих блоках, не задевая общие.

В vLLM за снимки состояний отвечает параметр mamba_cache_mode с тремя значениями:

Режим

Что хранится

Годится для префиксного кеша

none

одно состояние на активный запрос

нет, переиспользовать нечего

align

состояние на границах блоков и на шаге планировщика

частично

all

полные снимки на каждой границе блока

да

На моей модели в vLLM 0.26.0 при включении кеша движок принудительно откатывается в align с предупреждением, потому что класс Qwen3_5ForConditionalGeneration не объявляет интерфейс SupportsMambaPrefixCaching, поэтому всё дальнейшее про цену кеширования относится к align режиму.

Если коротко: гибрид помнит прошлое сжатой сводкой вместо растущего списка, и переиспользовать префикс между запросами он может только через снимки этой сводки.

4. 36 КБ против 144 и блок 528 вместо 16

Состояние фиксированного размера должно быть видно в первом же практическом числе — в байтах KV на токен. Считаю по слоям, у которых полный KV есть: у Qwen3-4B это 36 слоёв из 36, у гибрида 8 из 32.

Вес токена — произведение шести множителей: 2 (ключи и значения) × число слоёв × число KV-голов × размерность головы × 2 байта на элемент. Все они лежат в config.json модели, то есть посчитать это можно до аренды GPU.

Qwen3-4B

Qwen3.5-4B

Расчёт

2 × 36 × 8 × 128 × 2 байта

2 × 8 × 4 × 256 × 2 байта

КБ на токен, расчёт

144.0

32.0

КБ на токен, из лога старта vLLM

144.03

36.14

У полной аттеншн расчёт и замер сходятся до третьего знака. У гибрида замер выше расчёта на 4 КБ, и это первый признак того, что разбирается ниже: рекуррентные состояния лежат в том же пуле, что и KV, и их страницы размазываются по ёмкости кеша.

Что это даёт по ёмкости:

Из лога старта

Qwen3-4B

Qwen3.5-4B

Веса / активации

7.56 / 0.74 ГиБ

8.61 / 1.70 ГиБ

Памяти осталось под кеш

12.83 ГиБ

10.26 ГиБ

Ёмкость кеша

93 408 токенов

297 720 токенов

Одновременных запросов по 16k токенов

5.70

18.17

Мой замер. Обе модели, 1× RTX 3090 24 ГБ, vLLM 0.26.0, --gpu-memory-utilization 0.9. Числа сняты из лога старта vllm serve.

Гибриду досталось на 2.6 ГиБ меньше памяти под кеш: веса тяжелее, активации больше в 2.3 раза. И при этом ёмкость у него в 3.2 раза выше.

К этой ёмкости есть поправка, без которой дальше ничего не воспроизведётся. Для гибридных моделей vLLM 0.26 выключает префиксное кеширование по умолчанию, и --enable-prefix-caching приходится ставить руками:

# vllm/engine/arg_utils.py
# Hybrid models support prefix caching but keep it opt-in for now
# while the feature matures.
default_prefix_caching = (
    model_config.is_prefix_caching_supported and not model_config.is_hybrid
)

Сам флаг обходится в 8% ёмкости, с 297 720 до 274 216 токенов, и это цена экономного режима снимков состояний из раздела 3. Дальше кеш включён у обеих моделей везде, кроме прогонов, где я пишу обратное; во что обходится забытый флаг под нагрузкой, видно в разделе 8.1.

Ёмкость кеша трёх конфигураций против рабочего набора нагрузки. Пунктир — рабочий набор при 40 тенантах, 132 тысячи токенов. Столбец ниже пунктира означает, что набор не влезает и начинается вытеснение: у Qwen3-4B при ёмкости 97.7 тысячи это даёт 52% попаданий. Крайний правый столбец — гибрид на настройках по умолчанию: самая большая ёмкость из трёх и ноль попаданий, потому что префиксное кеширование у него выключено

Ёмкость кеша трёх конфигураций против рабочего набора нагрузки. Пунктир — рабочий набор при 40 тенантах, 132 тысячи токенов. Столбец ниже пунктира означает, что набор не влезает и начинается вытеснение: у Qwen3-4B при ёмкости 97.7 тысячи это даёт 52% попаданий. Крайний правый столбец — гибрид на настройках по умолчанию: самая большая ёмкость из трёх и ноль попаданий, потому что префиксное кеширование у него выключено

4.1. За что платит эта ёмкость

В том же логе запуска гибрида стоит необычное значение block_size: размер блока кеша 528 токенов вместо привычных 16. Такого числа я до этого не встречал ни у одной модели. Объяснение движок дал сам, двумя строками:

Setting attention block size to 528 tokens to ensure that attention page size is >= mamba page size.
Padding mamba page size by 0.76%.

Причина — в устройстве того самого единого пула. Гибридный менеджер кеша режет видеопамять на одинаковые слоты-страницы, и в этом пуле лежат объекты двух сортов. Страница аттеншн хранит K и V для block_size токенов одного слоя, и её размер зависит от настройки. Страница рекуррентного состояния хранит сводку одного слоя, и её размер задан архитектурой. Полка с ячейками одного размера не может иметь ячейку меньше самого крупного предмета, а состояние сжать нельзя, поэтому подтягивать приходится страницу аттеншн.

Считается это на бумаге, и я сошёлся с логом. Состояние слоя складывается из двух частей: ssm-часть это 32 × 128 × 128 значений в fp32, то есть 2 097 152 байта, и conv-часть — ещё 49 152 байта. Итого 2 146 304 байта на слой. Страница аттеншн на один токен блока — это K и V по 4 KV-головы на 256 значений в bf16, то есть 4 096 байт.

Величина

Байт

страница состояния, на слой

2 146 304

страница аттеншн, на один токен блока

4 096

минимальный блок, при котором аттеншн догоняет

2 146 304 / 4 096 = 524

блок обязан быть кратен 16, ближайший сверху

528

страница аттеншн при блоке 528

2 162 688

паддинг страницы состояния до равенства

16 384 байта, или 0.76%

Расчётные 0.76% совпали с логом vLLM до второго знака, значит механизм я понял верно. Любопытная деталь: число 2 146 304 делится на 4 096 ровно, то есть блок в 524 токена дал бы страницы одинаковыми байт в байт, и весь паддинг — это плата за кратность 16, которую требуют вычислительные ядра.

Вернуть блок 16 руками нельзя. Движок умеет размер блока только повышать:

# vllm/platforms/interface.py
attn_block_size = kernel_block_alignment_size * cdiv(
    mamba_page_size,
    kernel_block_alignment_size * attn_page_size_1_token,
)
...
if cache_config.block_size < attn_block_size:
    cache_config.block_size = attn_block_size

Флаг --block-size 16 будет перебит молча, и в логе появится та же строка про 528.

4.2. Мелкий блок гибриду не подходит и по второй причине

В полноценном режиме снимков состояний (all) снимок делается на каждой границе блока и весит 49.1 МБ. Значит его цена в пересчёте на токен — это 49.1 МБ, поделённые на размер блока:

Размер блока

KV + снимки, КБ на токен, гибрид

Для сравнения, Qwen3-4B

16

32 + 3 144 = 3 176

144

64

32 + 786 = 818

144

256

32 + 196 = 228

144

512

32 + 98 = 130

144

1024

32 + 49 = 81

144

Точка, где гибрид со снимками становится дешевле обычной модели по памяти, лежит около 450 токенов на блок. При блоке 16 он был бы дороже в 22 раза: кеширование префиксов на мелких блоках съело бы всю ёмкость и даже больше.

Если коротко: гибрид платит за токен в 4 раза меньше и получает в 3 раза большую ёмкость на меньшем куске видеопамяти. Взамен блок кеша становится 528 вместо 16, и настройками это не снимается — размер вытекает из требования «страница аттеншн не меньше страницы состояния» и сходится с логом до 0.76% паддинга. Оба факта проверяются одной строкой в логе старта, вместе с тем, включён ли вообще кеш:

vllm serve <model> 2>&1 | grep -Ei 'prefix_caching|attention block size|KV cache size'

5. Минусы большой гранулярности

Блок в 33 раза крупнее обязан за что-то платить, и плату я ожидал увидеть в проценте попаданий. Первый замер показал обратное: у гибрида 77% попаданий против 52% у обычной модели.

В той единственной точке смешаны два изменения: ёмкость выросла в 3 раза, гранулярность ухудшилась в 33. По одной точке нельзя понять, какое из них дало эффект. При 40 тенантах рабочий набор около 132 тысяч токенов, у обычной модели ёмкость 97.7 тысячи, набор не влезает, начинается вытеснение. У гибрида 274 тысячи, всё влезает. То есть в этой точке эффект ёмкости просто перекрыл эффект гранулярности.

Чтобы разделить их, я прогнал свип по числу тенантов при фиксированной нагрузке 6 запросов в секунду. Гипотезу записал до прогона, чтобы потом не подгонять объяснение под факт: при малом рабочем наборе обычная модель должна обогнать гибрид по попаданиям, потому что вытеснения нет ни у одной и сравнивается только гранулярность.

Тенантов

Рабочий набор

Qwen3-4B, попаданий

Qwen3.5-4B, попаданий

Qwen3-4B, TTFT p50

Qwen3.5-4B, TTFT p50

5

17k

94.3%

84.0%

58 мс

99 мс

10

33k

94.4%

84.1%

59 мс

103 мс

20

66k

94.3%

84.3%

61 мс

109 мс

40

132k

54.6% (перегруз)

81.9%

1 696 мс

110 мс

80

264k

26.4%

24.9%

8 951 мс

6 315 мс

Мой замер. vLLM 0.26.0, 1× RTX 3090, префиксный кеш включён у обеих моделей, 6 ходов диалога, запрошено 6 req/s. Попадания считаются по разности счётчиков vllm:prefix_cache_queries_total и vllm:prefix_cache_hits_total до и после прогона, в токенах. По одному прогону на точку.

Так и вышло. На 5, 10 и 20 тенантах разрыв ровно 10 процентных пунктов в пользу мелкого блока, и это чистая цена гранулярности: вытеснения нет ни у одной модели, сравнивается только она.

5.1. Откуда берутся именно 10 пунктов

Каким этот разрыв должен быть по арифметике, я считал уже после замера, так что это объяснение факта, а не предсказание.

Совпадение засчитывается целыми блоками, значит на границе совпадения теряется остаток. Для случайной длины совпадения средняя потеря — половина блока: 8 токенов при блоке 16 и 264 при блоке 528. Разница между архитектурами — 256 токенов на запрос.

Средний запрос в моей нагрузке просит 2 891 токен промпта — это замер на той же нагрузке, а не оценка. 256 от 2 891 — это 8.9% при замеренном разрыве в 10.3 пункта (94.3% против 84.0%). То есть округление объясняет почти весь разрыв. Расчёт опирается на допущение, что совпадающая часть идёт одним непрерывным куском с начала промпта; в моей нагрузке так и есть, потому что общее начало — это системный префикс плюс история диалога. В разделе 9 размер блока меняется ещё раз, и там та же модель ошибается в 2 раза, так что 8.9 против 10.3 — хорошее первое приближение.

Потеря на границе — константа в токенах, от длины промпта она не зависит. Значит её доля падает с ростом контекста:

Средний промпт

Потеря 264 токена — это

2 900 токенов (моя нагрузка)

9.1%

8 000 токенов

3.3%

16 000 токенов

1.6%

100 000 токенов

0.3%

Крупный блок бьёт по коротким сессиям и почти не виден на длинных.

Попадания в кеш против числа тенантов при 6 req/s. Синяя линия (блок 16 токенов) идёт выше оранжевой (блок 528), пока рабочий набор влезает в 93 тысячи токенов ёмкости, и обрушивается сразу за вертикальным пунктиром, где кеш кончился. Оранжевая держится до своего пунктира на 83 тенантах. Пустые маркеры — точки, где система в перегрузе

Попадания в кеш против числа тенантов при 6 req/s. Синяя линия (блок 16 токенов) идёт выше оранжевой (блок 528), пока рабочий набор влезает в 93 тысячи токенов ёмкости, и обрушивается сразу за вертикальным пунктиром, где кеш кончился. Оранжевая держится до своего пунктира на 83 тенантах. Пустые маркеры — точки, где система в перегрузе

Обе границы обвала я предсказал до прогона, поделив ёмкость из лога старта на длину контекста тенанта: 93.4 тысячи на 3.3 даёт 28 тенантов, 274.2 на 3.3 даёт 83. Замер охватывает обе — обвалы наблюдаются между 20 и 40 и между 40 и 80 тенантами.

TTFT p50 против числа тенантов, логарифмическая шкала. Обе линии держатся на десятках миллисекунд, пока рабочий набор влезает в ёмкость, и уходят вверх на два порядка, как только кеш кончился: у обычной модели между 20 и 40 тенантами, у гибрида между 40 и 80

TTFT p50 против числа тенантов, логарифмическая шкала. Обе линии держатся на десятках миллисекунд, пока рабочий набор влезает в ёмкость, и уходят вверх на два порядка, как только кеш кончился: у обычной модели между 20 и 40 тенантами, у гибрида между 40 и 80

Собираю карту применимости.

Рабочий набор

Кто выигрывает

Почему

до ~90k токенов

полная аттеншн

мелкий блок: 94% попаданий против 84%, TTFT ниже в 2 раза

~90k … 270k

гибрид

у полной аттеншн кеш кончился, у гибрида ещё нет

больше ~270k

никто

не влезает ни у кого: 26.4% против 24.9%

Одна оговорка про задержку. Разрыв 58–61 мс против 99–109 не весь про кеш: у рекуррентных слоёв есть своя постоянная стоимость, и на коротких промптах она не окупается. Разбор в разделе 6.

TTFT p50 против запрошенной нагрузки, логарифмическая шкала. Пустые маркеры — точки, где обслужено меньше запрошенного, то есть очередь растёт и абсолютную задержку сравнивать нельзя. Единственная нагрузка, где все четыре конфигурации в стационаре, — 2 req/s

TTFT p50 против запрошенной нагрузки, логарифмическая шкала. Пустые маркеры — точки, где обслужено меньше запрошенного, то есть очередь растёт и абсолютную задержку сравнивать нельзя. Единственная нагрузка, где все четыре конфигурации в стационаре, — 2 req/s

График выше объясняет, почему я гоняю кривую по нагрузке, а не одну точку. При 8 req/s три конфигурации из четырёх уже не справляются, и разрыв между ними измеряется секундами — это разрыв длины очереди, а не задержки системы.

6. Префилл: второе преимущество гибрида

С памятью разобрались, осталось второе обещание гибридных архитектур, ради которого их и делают: длинный контекст должен дешеветь. Меряю напрямую — стоимость обработки промптов разной длины.

Работа аттеншн растёт квадратично с длиной контекста, потому что каждый токен смотрит на все предыдущие. У гибрида таких слоёв 8 из 32, значит квадратичная часть работы должна быть примерно в 4 раза меньше, и стоимость тысячи токенов должна расти с длиной контекста заметно медленнее. Ожидаемый множитель я записал до прогона: у обычной модели на 16 320 токенах ожидалось около 190 мс на тысячу токенов, а кривая гибрида должна быть площе примерно в 4.5 раза.

Токенов в промпте

Qwen3-4B, мс на 1k

Qwen3.5-4B, мс на 1k

512

138.1

154.2

1 024

129.5

133.2

2 048

124.3

126.5

4 096

133.1

127.6

8 192

153.1

131.3

16 320

193.8 (+56%)

141.1 (+12%)

Мой замер. vLLM 0.26.0, 1× RTX 3090, уникальные промпты, кеш в замере не участвует, длина режется токенизатором ровно, лимит контекста спрашивается у сервера. Эффективная производительность на префилле — 61–65 TFLOP/с, около 86% паспорта 3090.

Факт: 193.8 мс на тысячу токенов, то есть предсказание попало с точностью 2%. Подгонка прямой к этим точкам даёт линейную часть 114.3 у обычной модели и 124.4 у гибрида — почти одинаково, потому что матричные умножения в остальной части модели стоят примерно одинаково. Вся разница сидит в квадратичном коэффициенте, и отношение этих коэффициентов вышло 4.7 при отношении числа слоёв с полной аттеншн 36 к 8, то есть 4.5. Совпадение с точностью 5% означает, что экономия на префилле объясняется заменой слоёв и ничем больше.

Стоимость тысячи токенов префилла против длины промпта. Чем ровнее линия, тем ближе работа к линейной по длине контекста. У Qwen3-4B от минимума на 2k к 16k рост 56%, у гибрида 12%. На коротких промптах гибрид медленнее

Стоимость тысячи токенов префилла против длины промпта. Чем ровнее линия, тем ближе работа к линейной по длине контекста. У Qwen3-4B от минимума на 2k к 16k рост 56%, у гибрида 12%. На коротких промптах гибрид медленнее

На графике видна и обратная сторона. При 512 токенах гибрид медленнее (154.2 против 138.1), потому что у рекуррентных слоёв есть своя постоянная стоимость, которая на коротких промптах не окупается. Кривые пересекаются около 2.5 тысячи токенов. Отсюда и разница в TTFT из раздела 5: там контексты по 3.3 тысячи, чуть правее точки пересечения, и вклад постоянной стоимости всё ещё заметен.

6.1. Оговорка, которую я нашёл, разбирая артефакты

Кривую префилла я снимал дважды на каждой модели, в конфигурациях с включённым и выключенным префиксным кешем. У обычной модели два прогона совпали до 0.1%: 193.75 и 193.89 мс на тысячу токенов при 16 320. У гибрида они разошлись на 7.6%.

Токенов

гибрид, кеш выключен

гибрид, кеш включён

2 048

126.5

140.2

16 320

141.1

151.8

Расхождение систематическое. С включённым кешем движок работает в режиме align и пишет снимки состояний на границах блоков, а это дополнительная работа поверх самого префилла. То есть включение кеша стоит гибриду не только 8% ёмкости, но ещё и 7.6% скорости префилла.

Таблица выше в этом разделе взята из прогона с выключенным кешем. Значит для нагрузок с переиспользованием, где кеш включать надо, преимущество на 16 тысячах токенов не 27%, а 21.7%. Для уникальных промптов, где кеш всё равно выключают, верны исходные 27%.

Если коротко: на 16 тысячах токенов префилл гибрида быстрее на 27% без префиксного кеша и на 22% с ним. Преимущество не зависит от рабочего набора, а на промптах короче 2.5 тысячи токенов меняет знак.

7. Генерация: гибрид отдаёт токен быстрее и заметно менее ровно

Всё предыдущее было про первый токен, а пользователь ждёт весь ответ: TTFT плюс несколько сотен межтокенных задержек, и вторая часть обычно длиннее первой в десятки раз.

Здесь у гибрида должно быть преимущество, и оно арифметическое. Каждый шаг генерации вычитывает из памяти веса модели плюс KV всего контекста. KV у гибрида в 4 раза дешевле, значит читать меньше, значит шаг короче.

Тенантов

ITL медиана, полная / гибрид

ITL среднее, полная / гибрид

5

14.9 / 13.9

17.7 / 20.9

10

14.9 / 14.1

17.6 / 21.9

20

15.0 / 14.1

17.9 / 22.3

Мой замер. Те же прогоны, что и в разделе 5: обе модели с включённым кешем, 6 запросов в секунду, 6 ходов диалога, контекст сессии около 3.3 тысячи токенов. Взяты только точки, где обе модели справляются с нагрузкой. Межтокенная задержка считается по интервалам между кусками потокового ответа.

Медиана у гибрида ниже на 5–6%, то есть типичный токен он действительно отдаёт быстрее. Среднее при этом выше на 18–25%, а среднее выше медианы означает редкие длинные паузы.

Слева время до первого токена против числа тенантов: у обычной модели оно ниже, пока рабочий набор влезает в её ёмкость, и обваливается за границей. Справа межтокенная задержка в стационарном режиме: чёрточка — медиана, верх столбца — среднее. У гибрида медиана ниже, а столбец выше, то есть генерация у него быстрее по типичному токену и рванее по редким паузам

Слева время до первого токена против числа тенантов: у обычной модели оно ниже, пока рабочий набор влезает в её ёмкость, и обваливается за границей. Справа межтокенная задержка в стационарном режиме: чёрточка — медиана, верх столбца — среднее. У гибрида медиана ниже, а столбец выше, то есть генерация у него быстрее по типичному токену и рванее по редким паузам

Арифметика на медиану сходится. При контексте 2 891 токен шаг обычной модели читает 7.56 ГиБ весов плюс 407 МБ KV, шаг гибрида — те же веса плюс 102 МБ KV и 49 МБ снимка состояний. Итого 7.94 против 7.70 ГиБ, то есть ожидаемые 3% против замеренных 5–6%. Веса гибрида на 14% тяжелее за счёт башни зрения, но текстовый запрос её не читает, поэтому в трафик шага она не входит. С длиной контекста разрыв растёт вместе с долей KV в этом трафике: при 8 тысячах токенов гибрид читает на 9% меньше, при 30 тысячах на 26%, а с fp8 разрыв скромнее в 2 раза — 4% и 14%. Полосу памяти я взял из паспорта 3090, а не замерил, и разделение весов гибрида на языковую часть и башню зрения не проверял: если башня меньше, чем я думаю, преимущество гибрида на декоде я завышаю.

С паузами хуже. Среднее превышает медиану в 1.55 раза против 1.19 у обычной модели, а на fp8 при 40 тенантах — в 1.98 против 1.16. Моё объяснение: vLLM подмешивает префилл новых запросов в те же проходы, где идёт генерация текущих, а гибрид пересчитывает на префилле в три-четыре раза больше токенов, и каждая такая вставка подвешивает чужую генерацию дольше. В пользу этого говорит то, что перекос растёт там же, где растёт объём пересчёта. Против — поведение [6] хвоста: ITL p99 у гибрида в bf16-прогонах лучше (72 против 91–116 мс), а в fp8 хуже (115 против 73). Механизм объясняет среднее и не объясняет хвост, и проверять его надо отдельным замером с изолированным префиллом.

Если коротко: за крупный блок гибрид платит дважды — в TTFT и в ровности генерации. Сама скорость генерации у него чуть выше, и на коротком контексте это единицы процентов, потому что при 3.3 тысячи токенов KV составляет всего 5% того, что читает шаг.

8. Полное время ответа: решает длина ответа

Есть длина ответа, начиная с которой гибрид отыгрывает своё отставание на первом токене, и её можно посчитать. Отставание — это лишние токены пересчёта, помноженные на цену токена префилла. Выигрыш на токен генерации — разница прочитанных байт, делённая на полосу памяти.

Контекст

Токенов ответа до окупаемости, bf16

fp8

2.9k

119

688

8k

40

192

30k

12

54

Карта выбора: по горизонтали длина контекста, по вертикали длина ответа. Чёрная линия — где экономия гибрида на генерации сравнивается с его отставанием по первому токену. Синяя область снизу: ответ слишком короткий, чтобы отыграть отставание, выигрывает полная аттеншн. Оранжевая сверху: выигрывает гибрид. С fp8 синяя область заметно больше, потому что отставание на первом токене у гибрида удваивается

Карта выбора: по горизонтали длина контекста, по вертикали длина ответа. Чёрная линия — где экономия гибрида на генерации сравнивается с его отставанием по первому токену. Синяя область снизу: ответ слишком короткий, чтобы отыграть отставание, выигрывает полная аттеншн. Оранжевая сверху: выигрывает гибрид. С fp8 синяя область заметно больше, потому что отставание на первом токене у гибрида удваивается

При контексте 8 тысяч токенов гибрид отыгрывает своё отставание за первые сорок токенов ответа в bf16, то есть на любом развёрнутом ответе выигрывает он, а на вызове инструмента в тридцать токенов — уже нет. С fp8 у обычной модели порог там же поднимается до 192 токенов. При контексте 3 тысячи и коротких ответах на 50–100 токенов выигрывает обычная модель, а с fp8 её преимущество держится почти до семисот токенов ответа.

Практический смысл: выбор архитектуры определяется произведением длины контекста на длину ответа, а не одной длиной контекста. Агент, который читает 10 тысяч токенов и отвечает вызовом инструмента на 30 токенов, и агент, который читает те же 10 тысяч и пишет отчёт на 800, попадают в разные половины этого графика.

8.1. Пропускная способность считается отдельно

Всё выше про время одного ответа. Пропускная способность сервера ведёт себя иначе, и путать их не стоит.

Что меряем

Полная

Гибрид

Запросов в секунду при 40 тенантах

5.55

7.58

Выходных токенов в секунду, fp8, оба влезают

284.5

276.8

Выходных токенов в секунду, 5–20 тенантов

261–281

253–278

Выигрыш гибрида по запросам в секунду, 1.4 раза, получен там, где обычная модель вытесняла: рабочий набор 132 тысячи токенов против 97.7 тысячи ёмкости. Это выигрыш ёмкости. Там, где влезают обе, агрегат равный, с перевесом в 1–3% в сторону обычной модели: гибрид декодирует чуть быстрее, но тратит в три-четыре раза больше GPU на префилл каждого запроса, и на агрегате это съедает его преимущество.

Здесь же видно, сколько стоит забытый флаг из раздела 4. Гибрид на настройках по умолчанию, то есть с выключенным префиксным кешем, при тех же 40 тенантах и запрошенных 8 req/s обслуживает 2.74 запроса в секунду — примерно как обычная модель, у которой кеш выключили руками (2.13). Ошибок нет, успешность 1.0, лог чистый. Включение кеша на обычной модели даёт 2.6 раза, смена архитектуры без кеша — 1.29 раза, включение кеша на гибриде — 2.8 раза.

Обслуженные запросы в секунду на четырёх конфигурациях при одинаковой нагрузке, 40 тенантов и запрошенные 8 req/s. Две заштрихованные полосы — конфигурации с нулевым hit rate, где кеш не работает вовсе. Гибрид на настройках по умолчанию (2.74 req/s) стоит рядом с обычной моделью, у которой кеш выключен руками (2.13), и в три раза ниже себя же с включённым кешем (7.58)

Обслуженные запросы в секунду на четырёх конфигурациях при одинаковой нагрузке, 40 тенантов и запрошенные 8 req/s. Две заштрихованные полосы — конфигурации с нулевым hit rate, где кеш не работает вовсе. Гибрид на настройках по умолчанию (2.74 req/s) стоит рядом с обычной моделью, у которой кеш выключен руками (2.13), и в три раза ниже себя же с включённым кешем (7.58)

Если коротко: одному пользователю с длинным контекстом гибрид отдаёт ответ быстрее, а сервер на нём обслуживает столько же или чуть меньше запросов.

9. fp8: дешёвая экономия памяти, которая гибриду выходит боком

--kv-cache-dtype fp8 — самый дешёвый способ увеличить ёмкость кеша: K и V хранятся в восьми битах вместо шестнадцати, места нужно в 2 раза меньше. На обычных моделях это работает как чистая победа.

На гибриде из арифметики выравнивания следует другое, и я записал это предсказанием до прогона: восьмибитная страница аттеншн в 2 раза меньше, значит блок, которым она догоняет страницу состояния, должен вырасти с 528 до 1056 токенов. То есть дешёвая экономия памяти обязана в 2 раза ухудшить гранулярность.

Модель и тип KV

Ёмкость

КБ на токен

Блок

Попаданий

TTFT p50

Qwen3-4B, bf16

97 696

144.04

16

0.545

1 743 мс

Qwen3-4B, fp8

186 816

72.01

16

0.944

52 мс

Qwen3.5-4B, bf16

274 216

39.23

528

0.822

109 мс

Qwen3.5-4B, fp8

429 707

22.72

1056

0.778

142 мс

Мой замер. vLLM 0.26.0, 1× RTX 3090, --kv-cache-dtype fp8, у гибрида префиксный кеш включён вручную. 40 тенантов, 6 ходов, запрошено 6 req/s; обслужено 5.26–5.93, то есть первая строка слегка в перегрузе, остальные в стационаре. Один прогон на конфигурацию. Строки bf16 сняты в отдельном прогоне от таблицы раздела 5, отсюда расхождения в третьем знаке. КБ на токен здесь — фактическая цена токена в занятом пуле, поэтому у гибрида 39.23 против 36.14 из раздела 4: разница в страницах состояний, которые появляются при включённом кеше.

Предсказание попало точно: 1056. Механизм выравнивания отработал и в обратную сторону.

У обычной модели fp8 — то, чем и кажется: цена токена падает ровно в 2 раза, ёмкость растёт в 1.91 раза, рабочий набор в 132 тысячи токенов наконец влезает целиком, попадания идут с 54.5% до 94.4%, TTFT с 1.7 секунды до 52 мс. Выигрыш здесь почти весь от исчезнувшего вытеснения: восьмибитный формат сам по себе задержку не уменьшает, он освобождает место.

У гибрида ёмкость выросла только в 1.57 раза. Цена токена упала в 1.73 раза вместо двух, потому что рекуррентные состояния остаются в fp32 и не сжимаются вовсе. Плюс сам пул под кеш стал меньше, с 10.26 до 9.31 ГиБ; моё предположение — это буферы под коэффициенты масштабирования, но по логу старта этого не видно, так что утверждать не буду.

А попадания упали с 82.2% до 77.8%, и TTFT вырос с 109 до 142 мс: покупать было нечего. Рабочий набор в 132 тысячи токенов влезал в 274 тысячи и до fp8, ёмкость выросла впустую, а за подорожавшую границу блока пришлось заплатить.

Здесь же выяснилось, где ошибается модель округления из раздела 5. Блок вырос в 2 раза, средняя потеря на границе должна вырасти с 264 токенов до 528, и падение попаданий по этой модели — около 9 пунктов. Замер даёт 4.4, то есть в 2 раза лучше предсказания. Считать по фактическим длинам промптов вместо усреднения по случайной длине ничего не меняет: у моих тенантов промпт растёт как 2 000 плюс 210 на ход, и средняя потеря на этих шести длинах выходит 325 токенов при блоке 528 и 589 при 1056 — та же разница в 264. Причин может быть две, и ни одну я не проверял: либо счётчики vLLM округляют до блоков и знаменатель тоже, либо при блоке 1056 в контекст на 3.3 тысячи токенов влезает всего три блока, и распределение остатков перестаёт быть похожим на равномерное. Порядок величины округление задаёт, коэффициент — нет; точное значение надо мерить на своей нагрузке.

fp8 KV на обеих архитектурах. Слева ёмкость кеша: у полной аттеншн она растёт в 1.91 раза, у гибрида в 1.57. Справа попадания и размер блока: у Qwen3-4B попадания идут с 54.5% до 94.4%, у гибрида падают с 82.2% до 77.8%

fp8 KV на обеих архитектурах. Слева ёмкость кеша: у полной аттеншн она растёт в 1.91 раза, у гибрида в 1.57. Справа попадания и размер блока: у Qwen3-4B попадания идут с 54.5% до 94.4%, у гибрида падают с 82.2% до 77.8%

Если коротко: на полной аттеншн fp8 даёт ровно то, за что его берут, — тот же токен занимает в 2 раза меньше места. На гибриде это обмен ёмкости на гранулярность, и он выгоден только тогда, когда рабочий набор в ёмкость не влезает. Качество ответов при fp8 я не мерил вовсе: восьмибитный KV огрубляет сами значения, а не только их раскладку по памяти, и это отдельная работа.

10. Коротко про Offload

Выгрузка кеша в оперативку. Карта применимости упирается в 270 тысяч токенов рабочего набора, за которыми не влезает ни одна из двух моделей. Лечится это выгрузкой вытесненных блоков в оперативную память хоста: её на машине 125 ГБ против 24 на карте, а сделка считается легко — привезти готовый KV одного токена из оперативки стоит 28 микросекунд, пересчитать его заново 131.

На гибриде я ждал, что выгрузка не заведётся: механизм работает со спецификациями страниц аттеншн, состояния Gated DeltaNet — объекты другой природы, и в исходниках есть прямое ограничение на их конвертацию. Предсказание провалилось. Штатный CPUOffloadingSpec с пулом 60 ГиБ поднялся без единой правки, и при 80 тенантах суммарные попадания пошли с 24.9% до 83.9%, а TTFT p50 — с 6.3 секунды до 128 миллисекунд.

Следствие важнее обоих сюжетов: потолок в 274 тысячи токенов расширяется оперативкой у обеих архитектур. Значит ёмкость перестаёт быть аргументом при выборе архитектуры, если в машине есть оперативная память, и остаётся то, что видно на малых наборах — гранулярность против стоимости префилла.

11. Плюсы и минусы одной таблицей

Вот без двух последних строк:

Метрика

Гибридная Qwen3.5-4B vs обычная Qwen3-4B

Токен KV-кеша

36 КБ vs 144 КБ (в 4 раза меньше)

Ёмкость KV-кеша на той же GPU

274–297 тыс. токенов vs 93–98 тыс. (в 3.2 раза больше)

Одновременные сессии по 16k

18.2 vs 5.7

Префилл (16k)

Быстрее на 27% без префиксного кеша и на 22% с ним

Префилл (до 2.5k)

Медленнее из-за постоянной стоимости рекуррентных слоёв

Гранулярность совпадения

Блок 528 токенов vs 16 токенов (в 33 раза грубее)

Hit rate при малом рабочем наборе

84% vs 94%; TTFT 99–109 мс vs 58–61 мс

Hit rate при большом рабочем наборе

82% vs 55%

Скорость генерации (медиана)

Быстрее на 5–6% при контексте 3.3k, до 26% при 30k

Стабильность генерации

Хуже: среднее выше медианы в 1.55–1.98 раза vs 1.16–1.19

Полное время ответа

Лучше при контексте от 8k и ответах длиннее 40–190 токенов

Выходные токены/с

Практически одинаково; обычная модель быстрее на 1–3%

Пропускная способность (40 тенантов)

7.58 vs 5.55 запросов/с

Префиксный кеш

По умолчанию выключен; включение стоит около 8% ёмкости и 7.6% скорости префилла

12. Выводы и допущения

Гибридная архитектура даёт два измеренных преимущества. Токен кеша дешевле в 4 раза, отсюда ёмкость в 3.2 раза больше при меньшем куске видеопамяти. Префилл площе: от 2 до 16.3 тысячи токенов стоимость тысячи токенов растёт на 12% против 56%, и отношение квадратичных коэффициентов совпало с отношением числа слоёв с полной аттеншн, то есть экономия логично [7] вписывается в архитектурные различия.

Платится за это гранулярностью совпадения. Блок 528 вместо 16 — это 84% попаданий против 94% и TTFT хуже в 2 раза, пока рабочий набор влезает в ёмкость обычной модели. Величину этой платы можно посчитать за пять минут по config.json и логу старта, до всякого прогона.

Три вывода, которые я для себя сделал из этого камерного ресерча.

Первый: Стоимость крупного блока проявляется в основном на коротких сессиях, а на длинных она постепенно нивелируется. Потеря на границе блока — константа в токенах, 264 в среднем. От промпта в 2 900 токенов это 9%, от 16 тысяч — 1.6%, от ста тысяч — 0.3%. При этом преимущество гибрида на префилле с длиной контекста растёт. Оба эффекта тянут в одну сторону: на длинном контексте недостатки гибрида тают, а преимущество растёт. С одной поправкой, которую стоит держать рядом: в процентах попаданий плата тает, а в миллисекундах нет. Пересчитывается постоянное число токенов, а тысяча токенов префилла на длинном контексте стоит дороже, чем на коротком; на моей нагрузке лишние 264 токена — это около 35 мс, и с ростом контекста абсолютная цифра растёт, а не падает. Мои замеры преимущественно на сессиях по 3.3 тысячи токенов, то есть в самой невыгодной для гибрида точке. Проверять это надо дополнительным прогоном на сессиях по 30–100 тысяч токенов. Если арифметика подтвердится, минус превращается в оговорку «на коротких диалогах».

Второй: крупный блок — условие, при котором кеш гибрида влезает в память. Выравнивание страниц объясняет, откуда взялось 528, но даже если бы это ограничение сняли, полноценный режим снимков при блоке 16 стоил бы в 22 раза дороже обычной модели по памяти — расчёт в разделе 4.2. То есть просьба «сделайте гибриду блок 16» означает просьбу отдать всю ёмкость, ради которой гибрид и берут. Отсюда вопрос, на который у меня ответа нет: существует ли схема, где снимки состояний хранятся реже, чем на каждой границе блока, и совпадение при этом всё равно засчитывается точно? Если да, платить за крупный блок больше не придётся.

Третий: hit rate сам по себе ничего не говорит об архитектуре. В первом замере у гибрида получилось 77% попаданий против 52%, из чего следовал вывод «гибрид лучше кешируется» — прямо противоположный правильному. Там смешались ёмкость в 3 раза и гранулярность в 33. Если в сравнении попаданий между архитектурами рядом нет фактического размера блока и ёмкости из лога старта, оно не показывает ничего.

Автор: YUNGC0DE

Источник [8]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/33830

URLs in this post:

[1] Память: http://www.braintools.ru/article/4140

[2] arXiv:2412.06464: https://arxiv.org/abs/2412.06464

[3] KV-Cache в LLM: разбираем инференс через 9 ключевых вопросов: https://habr.com/ru/articles/1021832/

[4] зрения: http://www.braintools.ru/article/6238

[5] забывание: http://www.braintools.ru/article/3931

[6] поведение: http://www.braintools.ru/article/9372

[7] логично: http://www.braintools.ru/article/7640

[8] Источник: https://habr.com/ru/articles/1065374/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1065374

www.BrainTools.ru

Rambler's Top100