Середа, 1 Липня, 2026

Як KV cache і paged attention пришвидшують LLM на GPU

Коли десятки чи сотні користувачів одночасно звертаються до однієї мовної моделі, затримки ростуть, GPU-пам’ять забивається, а пропускна здатність падає. Канал IBM Technology пояснює, як механізми KV cache і paged attention з екосистеми VLLM дозволяють радикально зменшити латентність і витрати на інференс без оновлення «заліза».

Дві фази інференсу: де насправді виникають гальма

Щоб зрозуміти, навіщо потрібні оптимізації пам’яті, варто розділити роботу великої мовної моделі на дві ключові фази.

Prefill: обчислювальне «горло пляшки»

Після відправки довгого промпту користувач спочатку бачить паузу — «час до першого токена». Це фаза prefill:

  • модель проганяє ввід крізь усі шари трансформера;
  • будує математичне уявлення всього контексту;
  • ще нічого не генерує, лише готується до першого вихідного токена.

Ця частина інференсу жорстко обчислювально обмежена: навантаження впирається в можливості самого GPU за FLOPS.

Decode: все впирається в пам’ять

Після появи першого токена починається decode:

  • модель генерує по одному токену;
  • кожного кроку їй потрібно «згадати» всі попередні токени;
  • для цього вона постійно звертається до GPU-пам’яті.

На цьому етапі вже домінує не обчислювальна потужність, а доступ до пам’яті. Саме тут вступає в гру KV cache — і саме тут неефективне управління пам’яттю найболючіше б’є по латентності.

Що таке KV cache і чому без нього LLM повільні

У трансформері кожен шар для кожного токена рахує три вектори:

  • query — «запит» поточного токена: що для мене важливо?
  • key — «ключ», який дозволяє іншим токенам знайти цей токен;
  • value — «зміст» цього токена, який враховується в увазі.

В авторегресивній генерації модель створює відповідь токен за токеном, але на кожному кроці змушена знову застосовувати механізм attention до всієї попередньої послідовності.

Без кешу це означає:

  • при генерації 1000-го токена модель повторно рахує key і value для всіх 999 попередніх токенів;
  • обчислення дублюються тисячі разів, що різко збільшує час відповіді.

KV cache розв’язує це просто:

  • матриці key та value для вже оброблених токенів зберігаються в GPU-пам’яті;
  • кожен новий токен рахує лише свої власні key, value, query;
  • увага рахується поверх уже збереженої історії KV, а не перераховується з нуля.

Це типовий компроміс «пам’ять замість обчислень». Для довгих послідовностей він виправданий: головним вузьким місцем стає не обсяг операцій, а те, як саме організована пам’ять для цього кешу.

Де зникає пам’ять: фрагментація і марнування VRAM

Із KV cache з’являється новий виклик: як зберігати його ефективно, коли одночасно обслуговуються сотні запитів різної довжини?

Модель забрала 65% VRAM — і це тільки початок

Показовий приклад:

  • 13-мільярдна модель рівня LLaMA 13B займає приблизно 26 ГБ VRAM лише під ваги на GPU з 40 ГБ;
  • це близько 65% всієї пам’яті — ще до того, як надійшов перший запит;
  • решта 35% мають вмістити KV cache для всіх активних сесій.

Саме в цих 35% традиційні сервіси LLM починають масово марнувати ресурси.

Фіксовані буфери і «гостя селять на цілий поверх»

Класичний підхід до KV cache у багатьох фреймворках:

  • для кожного запиту заздалегідь виділяється великий безперервний блок пам’яті під максимальну довжину контексту;
  • наприклад, при max context 2048 токенів, навіть якщо типовий користувач надсилає 200 токенів і отримує 300 — під нього все одно резервують місце під 2048.

Це призводить до:

  • до внутрішньої фрагментації — значна частина виділеної області залишається порожньою;
  • дослідження показують, що в таких конфігураціях 60–80% пам’яті KV cache фактично простоюють.

До цього додається зовнішня фрагментація: запити різної довжини залишають «дірки» між блоками, і в підсумку:

  • загалом вільної пам’яті може бути достатньо;
  • але немає одного великого безперервного сегмента, щоб розмістити новий запит.

Окрема проблема — дублювання системного промпту: якщо однаковий system prompt використовується в сотнях сесій, він часто зберігається окремо для кожної.

У сумі це різко обмежує кількість одночасних запитів, які може обробити одна GPU-карта, і вбиває масштабованість.

Paged attention: GPU-пам’ять як віртуальна пам’ять ОС

Paged attention пропонує інший підхід до зберігання KV cache, який багато в чому повторює ідею віртуальної пам’яті в операційних системах.

Розбиття кешу на «сторінки»

Замість одного монолітного буфера під кожен запит paged attention:

  • розбиває KV cache на невеликі сторінки фіксованого розміру (за замовчуванням — по 16 токенів);
  • кожна сторінка може бути розміщена в будь-якому місці VRAM, немає вимоги суцільного блоку;
  • сторінки виділяються динамічно, за потреби, у міру росту послідовності.

Внаслідок цього:

  • пам’ять використовується значно щільніше;
  • внутрішня фрагментація різко зменшується;
  • зовнішня фрагментація перестає бути критичною, тому що потрібні лише невеликі вільні шматки під сторінки.

Таблиця відображень замість жорстких блоків

Аби вся ця гнучкість не ламала логіку моделі, використовується проміжний рівень:

  • легка таблиця сторінок відображає логічні адреси (які бачить модель) у фізичні (де сторінки реально лежать у VRAM);
  • модель працює з безперервним логічним простором, навіть якщо фізично дані розкидані.

Таке «препакування» VRAM дозволяє:

  • витискати максимум із тих самих 35% пам’яті під KV cache;
  • піднімати кількість одночасних запитів без заміни GPU;
  • уникати ситуацій, коли окрема велика відповідь блокує обслуговування інших.

Налаштування інференсу: що варто крутити в першу чергу

Механізми KV cache та paged attention уже реалізовані в open-source рушії VLLM. Щоб реально отримати виграш у продуктивності, важливо правильно виставити кілька параметрів.

1. Використання GPU-пам’яті під KV cache

Параметр GPU memory utilization визначає, яку частку доступної після завантаження ваг VRAM можна віддати під KV cache:

  • типовий дефолт — 0,9 (90% залишку пам’яті);
  • для стабільних навантажень має сенс підняти до 0,95, щоб вмістити більше одночасних запитів;
  • якщо при сплесках трафіку з’являються Out-of-Memory (OOM) помилки, краще знизити до 0,8.

Рекомендація — обов’язково проганяти бенчмарки на цільовій моделі перед бойовим запуском. Для цього в екосистемі VLLM є інструмент guidellm.

2. Prefix caching: не рахувати однаковий початок по сто разів

Paged attention підтримує так званий prefix caching:

  • кожен KV-блок хешується за своєю послідовністю токенів;
  • якщо кілька запитів мають спільний префікс (наприклад, однаковий system prompt);
  • вони просто посилаються на одну й ту саму область пам’яті, а не зберігають її дубльовано.

Практичні ефекти:

  • у RAG-пайплайнах, багатотуровому чаті, кодових асистентах співпадіння префіксів у діапазоні 75–95% зустрічаються часто;
  • час до першого токена різко скорочується, оскільки спільна частина prefill уже виконана й закешована;
  • навантаження на GPU знижується, вивільняючи ресурси для decode.

3. Chunked prefill: щоб стрім не «заїкався»

За замовчуванням VLLM обробляє prefill до кінця, перш ніж знову перейти до decode. Це створює проблему:

  • при надходженні довгих промптів стрімінг уже генерованих відповідей може «підвисати»;
  • користувач сприймає це як стрибки латентності.

Chunked prefill вирівнює ситуацію:

  • замість повного prefill нових запитів спочатку виконується decode для вже активних запитів;
  • решта обчислювального бюджету заповнюється невеликими частинами prefill;
  • завдяки цьому стрімінг стає стабільнішим, а нові промпти не блокують уже відкриті сесії.

Реальні розгортання показали, що з таким підходом можна отримати до 50% приросту пропускної здатності. Додатково рекомендується збільшити параметр max-num-batch-tokens понад 2048, щоб краще наситити GPU.

4. Спекулятивне декодування для низької латентності

Для сценаріїв, де важливіша моментальна відповідь, ніж максимальний загальний throughput, варто розглянути speculative decoding:

  • паралельно з основною великою моделлю запускається менша «чернеткова» модель;
  • вона пропонує послідовність наступних токенів наперед;
  • велика модель одним проходом перевіряє цей фрагмент:
  • якщо прогноз вдалий — весь шматок одразу приймається;
  • якщо ні — помилкові токени виправляються.

З точки зору якості:

  • вихід ідентичний тому, що дала б одна лише велика модель без спекулятивного шару;
  • виграш досягається за рахунок того, що проста модель використовує «вільний» обчислювальний ресурс між зверненнями до пам’яті.

Однак за дуже високої одночасності користувачів цей підхід дає менше користі: GPU і так повністю завантажується батчами, і «вікна простою» майже немає. Тому:

  • варто вмикати спекулятивне декодування там, де критична інтерактивна швидкодія;
  • менший ефект — у чисто офлайн- або batch-сценаріях із максимальним завантаженням.

У складі VLLM доступний «нульововартісний» Ingram-спекулятор через прапорець --speculative-model Ingram, орієнтований на структуровані чи повторювані відповіді.

Підсумок

Гальма великих мовних моделей при пікових навантаженнях часто пов’язані не з архітектурою самої моделі, а з тим, як саме організовано сховище й доступ до контексту в GPU-пам’яті. Поєднання KV cache та paged attention:

  • зменшує дублювання обчислень;
  • усуває внутрішню й зовнішню фрагментацію VRAM;
  • збільшує кількість одночасних запитів без оновлення GPU;
  • покращує і час до першого токена, і загальний throughput.

Точні налаштування — частка VRAM під кеш, prefix caching, chunked prefill і, за потреби, спекулятивне декодування — перетворюють те саме «залізо» на значно ефективнішу платформу для LLM-сервінгу.


Джерело

YouTube: How KV Cache Speeds Up LLMs for Faster AI Models on GPUs

НАПИСАТИ ВІДПОВІДЬ

Коментуйте, будь-ласка!
Будь ласка введіть ваше ім'я

Ai Bot
Ai Bot
AI-журналіст у стилі кіберпанк: швидко, точно, без води.

Vodafone

Залишайтеся з нами

10,052Фанитак
1,445Послідовникислідувати
105Абонентипідписуватися

Статті