Гайды

Flash Attention и квантизация KV-кэша: как выиграть память

Две настройки, дающие самый большой выигрыш видеопамяти при почти нулевой потере качества. Точные флаги для llama.cpp и Ollama и расчёт экономии по четырём связкам.

Если вам не хватает памяти под нужный контекст, есть ровно две настройки, которые стоит включить прежде всего остального. Они не требуют менять модель, не портят качество заметным образом и включаются одной строкой.

Нужны они не всем: если модель и контекст помещаются с запасом, оставьте всё как есть — выигрыш в скорости от Flash Attention существует, но он скромнее, чем выигрыш в памяти, ради которого сюда обычно приходят.

#Что понадобится

  • Сборка движка с поддержкой этих режимов. В llama.cpp они есть давно; конкретное поведение флагов между версиями менялось, и --help вашей сборки — единственный надёжный источник.
  • Понимание, сколько памяти у вас уходит на контекст. Считается по формуле объёма KV-кэша: удвоенное произведение слоёв, KV-голов и размера головы, умноженное на длину контекста. Разбор — в материале о том, почему большой контекст съедает видеопамять.

#Шаг 1. Понять, что делает каждая настройка

Flash Attention — другой способ вычислять внимание. Обычная реализация строит промежуточную матрицу размером «контекст на контекст» и держит её в памяти; Flash Attention считает результат блоками, не материализуя эту матрицу целиком. Экономятся и обращения к памяти, и сама память — причём выигрыш растёт с длиной контекста.

Важно: результат математически эквивалентен обычному вниманию. Это не приближение и не упрощение, качество ответов не меняется. Что вообще такое механизм внимания — в справке об attention.

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

Связь между ними практическая: в llama.cpp квантизация кэша значений требует включённого Flash Attention. Поэтому включают их вместе.

#Шаг 2. Включить в llama.cpp

./build/bin/llama-cli -m models/llama-3.1-8b-instruct-q4_k_m.gguf -ngl 99 -c 32768 -fa -ctk q8_0 -ctv q8_0

Разбор: -fa включает Flash Attention, -ctk q8_0 задаёт восьмибитное хранение ключей, -ctv q8_0 — значений. Допустимые типы: f16 (по умолчанию), q8_0, q4_0.

В свежих сборках -fa принимает явное значение (on, off, auto) — проверьте --help. Остальные флаги разобраны в гайде по llama.cpp без магии.

#Шаг 3. Включить в Ollama

Здесь это переменные окружения, а не параметры модели:

OLLAMA_FLASH_ATTENTION=1 OLLAMA_KV_CACHE_TYPE=q8_0 ollama serve

Для постоянной работы переменные задаются в конфигурации сервиса. На Linux с systemd:

systemctl edit ollama

и добавить строки Environment="OLLAMA_FLASH_ATTENTION=1" и Environment="OLLAMA_KV_CACHE_TYPE=q8_0". На Windows — через переменные окружения пользователя с последующим перезапуском службы. Где задаются остальные параметры — в материале о параметрах Ollama, которые действительно влияют на результат.

#Шаг 4. Посчитать выигрыш

Таблица ниже — расчёт по формуле объёма KV-кэша, а не замер на конкретной машине: восьмибитное хранение вдвое сокращает байт на элемент, четырёхбитное — вчетверо. Экономия от самого Flash Attention сверх этого зависит от реализации и длины контекста и в таблицу не включена.

Модель и контекст Кэш f16 Кэш q8_0 Кэш q4_0 Экономия на q8_0
Llama 3.1 8B, 8k 1,0 ГиБ 0,5 ГиБ 0,25 ГиБ 0,5 ГиБ
Llama 3.1 8B, 32k 4,0 ГиБ 2,0 ГиБ 1,0 ГиБ 2,0 ГиБ
Qwen2.5 14B, 32k 6,0 ГиБ 3,0 ГиБ 1,5 ГиБ 3,0 ГиБ
Qwen2.5 32B, 32k 8,0 ГиБ 4,0 ГиБ 2,0 ГиБ 4,0 ГиБ

Что здесь смотреть: последний столбец на длинном контексте. Два-четыре освободившихся гигабайта — это разница между «модель 14B не влезает в карту на 12 ГБ» и «влезает с рабочим контекстом». Ни одна другая настройка не даёт столько без потери качества.

На коротком контексте выигрыш скромный — половина гигабайта. Поэтому включать эти настройки ради принципа смысла нет: они окупаются там, где контекст велик.

#Проверка результата

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

nvidia-smi --query-gpu=memory.used --format=csv

Разница должна примерно совпасть с расчётом из таблицы. Если не совпала — флаг не применился.

Проверка вторая: скорость не упала. Замерьте до и после:

./build/bin/llama-bench -m models/llama-3.1-8b-instruct-q4_k_m.gguf -ngl 99 -c 32768 -p 512 -n 128 -fa

Обычно скорость с Flash Attention растёт, особенно на длинном контексте. Падение — повод проверить, поддерживает ли ваш бэкенд этот режим эффективно.

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

#Что может пойти не так

Флаг не поддерживается сборкой. Не все бэкенды реализуют Flash Attention одинаково: на CUDA и Metal он зрелый, на других — зависит от версии. Если движок ругается на флаг, проверьте --help.

Квантизация значений не работает без Flash Attention. В llama.cpp это связанные настройки. Включайте -fa вместе с -ctv.

Скорость упала после включения. Встречается на бэкендах, где режим реализован не оптимально. Замерьте оба варианта и оставьте лучший: экономия памяти не стоит двукратной потери скорости.

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

В Ollama переменные не применились. Они читаются сервисом при старте, а не при запросе. После изменения службу нужно перезапустить, а не просто выполнить ollama run.

#Частые вопросы

#Портит ли Flash Attention качество ответов?

Нет. Это другой способ вычислить тот же результат, математически эквивалентный обычному вниманию. Разница только в том, сколько промежуточных данных при этом хранится в памяти.

#Насколько ухудшает качество квантизация KV-кэша?

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

#Почему эти настройки не включены по умолчанию?

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

#Что включать первым, если памяти не хватает?

Сначала Flash Attention с восьмибитным кэшем — они почти бесплатны по качеству. Только если этого мало, переходите к сокращению контекста, более жёсткой квантизации весов и смене модели.

#Есть ли смысл включать это на коротком контексте?

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

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт