Пропуск 90% работы по деквантизации ускорил декодирование LLM на 22,8%

Обложка: Пропуск 90% работы по деквантизации ускорил декодирование LLM на 22,8%

Три строчки кода в ядре flash attention — и декодирование большой языковой модели ускоряется на 22,8%. Без потери качества, без переобучения, без изменений в архитектуре модели.

Независимый разработчик Tom Turney опубликовал метод sparse V dequantization — оптимизацию для инференса LLM с квантизированным KV-кешем. Вместо того чтобы ускорять деквантизацию каждого значения, он предложил пропускать деквантизацию целиком для позиций, где вес внимания пренебрежимо мал. На Apple M5 Max с моделью Qwen 3.5 35B (MoE) метод дал прирост +22,8% к скорости декодирования на контексте 32K токенов. Перплексия осталась неизменной, а точность поиска needle-in-a-haystack выросла с 7/9 до 9/9.

Ключевые выводы

— Узкое место квантизированного KV-кеша — не то, как вы деквантизуете, а то, сколько значений вы деквантизуете.
— При длинном контексте (32K+) более 90% весов внимания пренебрежимо малы — их деквантизацию можно пропустить.
— Метод работает с любой схемой квантизации KV-кеша: TurboQuant, q8_0, q4_0, NVFP4.
— Реализация — 3 строки в ядре flash attention. Не нужно ни переобучение, ни калибровочные данные.
— NIAH-тест улучшился: 9/9 вместо 7/9. Пропуск деквантизации убирает квантизационный шум от позиций, которые ничего не вносят в результат.

Проблема — узкое место деквантизации

Чтобы понять суть открытия, нужно разобраться в контексте. Современные LLM при генерации текста хранят промежуточные вычисления в так называемом KV-кеше (key-value cache). Это массив ключей (K) и значений (V), которые модель использует в механизме внимания — чтобы при генерации каждого нового токена не пересчитывать всю историю диалога.

Проблема: KV-кеш растёт линейно с длиной контекста и при 32K токенов занимает гигабайты памяти. Решение — квантизация: сжатие значений из 16-битного формата в 3-4 бита. TurboQuant от Google (ICLR 2026) сжимает KV-кеш в 4,6 раза с потерей перплексии всего ~1%. Но при декодировании каждый сжатый блок нужно деквантизовать — преобразовать обратно в числа с плавающей точкой. И на длинных контекстах это становится узким местом.

На Apple M5 Max деквантизация TurboQuant занимает 14-34% времени декодирования. На контексте 32K токенов скорость декодирования падает с 78,3 tok/s (потолок без деквантизации) до 47,0 tok/s — штраф в 40%.

14 попыток, которые провалились

Прежде чем найти решение, Turney перебрал 14 альтернативных реализаций деквантизации на Apple Silicon: регистровые массивы, битовую арифметику, SIMD-шаффлы, FMA без ветвлений, слитые блочные операции. Ни одна не обогнала базовую таблицу подстановки (LUT) в константной памяти GPU.

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

Решение — не ускорять, а пропускать

Ключевое наблюдение: в flash attention ядре веса внимания (softmax) вычисляются из ключей (K) до того, как начинается работа со значениями (V). То есть на момент деквантизации V мы уже знаем, какие позиции контекста получили значимый вес внимания, а какие — нет.

Что такое разреженность внимания? Когда модель генерирует следующий токен, механизм внимания (softmax) распределяет вероятность по всем предыдущим позициям контекста. При коротком контексте внимание распределено относительно равномерно. Но чем длиннее контекст, тем более концентрированным оно становится: модель «смотрит» на несколько десятков ключевых позиций, а 90%+ получают веса ниже 10-6 — они практически ничего не вносят в итоговый результат.

Sparse V dequantization использует этот факт: если вес внимания для позиции ниже порога (10-6), её деквантизация и аккумуляция пропускаются целиком.

Вся реализация — три строки в Metal-ядре:

			const float attn_weight = float(ss[NE*cc + ty]);
if (attn_weight < 1e-6f) continue;
// ... existing V dequant and accumulation ...
		

Это экономит чтения из константной памяти (обращения к LUT), ALU-операции (извлечение индексов, применение знака, умножение на норму) и чтения из глобальной памяти устройства.

Принципиальное отличие от 14 провалившихся подходов: они пытались сделать каждую из N операций быстрее (ограничено аппаратным полом). Sparse V убирает (1-p) x N операций целиком — и выигрыш растёт с длиной контекста, потому что разреженность внимания растёт.

Результаты

Скорость декодирования (M5 Max, Qwen 3.5 35B MoE)

Эффект sparse V масштабируется с длиной контекста — чем длиннее контекст, тем больше позиций пропускается:

  • Короткий контекст: +1,4% (внимание плотное, мало что пропускать)
  • 4K: +4,0%
  • 8K: +7,2%
  • 16K: +12,9%
  • 32K: +22,8% (с 47,0 до 57,7 tok/s)

При 32K токенов отношение к несжатому q8_0 улучшилось с 0,76x до 0,93x — почти паритет.

Качество: перплексия и retrieval

Перплексия при включении sparse V остаётся численно идентичной варианту без него. На корпусе wikitext-103 (50 чанков, контекст 32K, CI +/-0.021) дельта составила ровно 0,0000. Это подтверждено на всех протестированных длинах контекста: 8K, 16K, 32K.

Ещё более неожиданный результат — в тесте needle-in-a-haystack (NIAH). Этот тест проверяет, может ли модель найти конкретный факт, спрятанный в длинном контексте:

  • Без sparse V: 7/9 (q8_0 тоже 7/9)
  • С sparse V: 9/9 (100%)

Гипотеза автора: позиции с пренебрежимо малым весом внимания вносят практически нулевой полезный сигнал, но при деквантизации добавляют квантизационный шум. Sparse V убирает этот шум — и соотношение сигнал/шум улучшается.

Почему это работает для любой квантизации

Sparse V работает не на уровне конкретного формата квантизации, а на уровне механизма внимания. Метод использует веса softmax как сигнал для пропуска вычислений — а softmax одинаков вне зависимости от того, как именно сжаты K и V.

Автор валидировал метод на трёх форматах KV-кеша с разной стоимостью деквантизации:

  • turbo3 (3,5 бита, TurboQuant) — +22,8% на 32K, перплексия без изменений
  • q8_0 (8 бит) — +5% к декодированию, перплексия идентична
  • q4_0 (4 бита) — перплексия идентична, скорость в пределах шума

Закономерность: чем дороже деквантизация, тем больше выигрыш. turbo3 использует Walsh-Hadamard-преобразование и полярную декомпозицию — тяжёлые операции, поэтому выигрыш максимален. q4_0 использует простое масштабирование — пропуск дешёвой операции даёт мало. Но в обоих случаях метод не ухудшает ни перплексию, ни retrieval.

Это означает, что sparse V можно включить по умолчанию для любого формата квантизации KV-кеша в llama.cpp — как безусловную оптимизацию, которая ничего не стоит на коротком контексте и даёт ощутимый выигрыш на длинном.

FAQ

Не сломает ли пропуск позиций качество генерации?

Нет. Порог 10-6 выбран консервативно. При контексте 32K с 32 головами внимания вклад пропущенной позиции в итоговый вектор — менее одной миллионной от максимума. Перплексия во всех экспериментах осталась численно идентичной — дельта 0,0000 на 50 чанках wikitext-103.

Почему нельзя пропускать и K-деквантизацию?

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

Работает ли это на NVIDIA GPU?

Эксперименты проводились на Apple Silicon (M5 Max, M2 Pro). Реализация — Metal-ядро для llama.cpp. На CUDA профиль узкого места другой (NVIDIA использует тензорные ядра и HBM вместо unified memory), но сам принцип — пропуск работы для позиций с малым весом внимания — универсален. Портирование на CUDA и ROCm автор указывает как следующий шаг.

Выводы

Sparse V dequantization — элегантное решение, которое меняет вопрос с «как деквантизовать быстрее?» на «нужно ли деквантизовать вообще?». Метод использует информацию, которая уже есть в ядре flash attention — веса softmax — как бесплатный сигнал для пропуска вычислений.

Главная ценность подхода — не конкретный прирост в 22,8%, а более широкая идея attention-aware computation: использование собственных паттернов разреженности модели для оптимизации ядер инференса. Чем длиннее контекст, тем сильнее разреженность — и тем больше выигрыш. Именно при тех длинах контекста, где узкое место деквантизации наиболее болезненно.

Код и бенчмарки: TheTom/turboquant_plus (бенчмарки и диагностика), TheTom/llama-cpp-turboquant (реализация, ветка experimental_decode_speed_tests).

Обсуждение на r/LocalLLaMA.

Источник: Sparse V Dequantization — документация turboquant_plus.