Великі мовні моделі (LLM) сьогодні - це не лише про мільярди параметрів і глибоке навчання, а й про складні виклики масштабування інференсу. Реальний світ вимагає від них швидких відповідей у режимі реального часу для тисяч користувачів одночасно, і щоб задовольнити ці вимоги, доводиться залучати дедалі більше графічних процесорів, оптимізувати пам’ять, шукати компроміси між затримкою й пропускною здатністю, а подекуди й розподіляти одну модель на кілька GPU - гуртом, бо інакше ніяк.
Сучасні великі мовні моделі перетворилися на монстрів, здатних з легкістю завантажувати сотні тисяч графічних адаптерів, тисячі юнітів серверних стійок, споживаючи мегавати електроенергії. Монстри у навчанні породжують менших братів – монстрів логічного висновку (інференсу). «Великими» вважаються моделі на кілька сотень мільярдів параметрів (DeepSeek-V3, 671 мільярд, з них 37 активних). У розряд «середніх» потрапляють LLM з 70 мільярдами.

Специфіка використання LLM вимагає достатнього швидкого (в ідеалі, в режимі реального часу) відгуку - ніхто не захоче спілкуватися з чат-ботом із затримками у хвилини. А якщо додаток на базі LLM масштабується до тисяч одночасних користувачів, формулювання висновків може вимагати великих кластерів графічних процесорів.
Як працює масштабування інференсу з використанням декількох GPU?
У 1967 році Джин Амдал сформулював закон, виявивши просте, але непереборне обмеження зростання продуктивності при розпаралелюванні обчислень: «Якщо завдання поділяється на кілька частин, сумарний час його виконання на паралельній системі не може бути меншим за час виконання найповільнішого фрагмента».
Та частина програми, яку неможливо розпаралелити, обмежує загальне прискорення. Будь-яка велика математична чи інженерна задача зазвичай складається з кількох частин, що можуть виконуватися паралельно, та кількох, які виконуються лише послідовно. Цей зв'язок описується рівнянням:

де:
- S — теоретичне максимальне прискорення;
- f — частка послідовних обчислень (які не можна розпаралелити);
- 1 – f — частка обчислень, що може бути виконана паралельно;
- p — кількість паралельних виконавчих елементів (процесорів, вузлів тощо).
Приріст ефективності залежить від алгоритму задачі й обмежений згори для будь-якого завдання. Не завжди доцільно збільшувати кількість паралельних виконавців (процесорів) в обчислювальній системі: існують накладні витрати (час, необхідний для передачі даних між вузлами), а також обмеження масштабованості. Починаючи з певного моменту, додавання нових вузлів може навіть збільшувати загальний час розрахунку.

На малюнку зображений розподіл умовної програми машинного навчання на кілька паралельних пристроїв. Частини програми, сині блоки, виконуються послідовно (отримання даних, попередня обробка запиту, ініціалізація паралельних вузлів). Помаранчеві блоки представляють обчислення, які можуть відбуватися одночасно (проходження запиту через модель). Ми обмежені доступними вузлами для одночасної обробки запитів. Якщо кількість запитів перевищує кількість пристроїв, вони виконуються послідовно.
Стає зрозумілим, чому при розподілу трафіку запитів на два графічних процесори час проходження не скорочується вдвічі (в наведеному прикладі маємо прискорення на третину, S = 1.33). При паралельній обробці завжди будуть послідовні операції та накладні витрати на розпаралелювання.
Хоча будь-яке прискорення є гарною новиною, для оцінки справжньої привабливості об'єднання графічних процесорів потрібно враховувати додаткові метрики інференсу.
Затримка та пропускна здатність
Це два фундаментальні показники продуктивності, що використовуються для оцінки обчислювальних систем. Інференс не виняток.
Затримкою називають очікування відгуку, час, необхідний для проходження однієї одиниці даних через систему від джерела до місця призначення. В інференсі LLM це час між кожним наступним токеном, який видає наша модель.
Пропускна здатність кількісно визначає швидкість, з якою дані можуть бути оброблені або передані протягом заданого періоду часу. Для нашого випадку це кількість токенів за секунду, що видаються моделлю. Вища пропускна здатність вказує на спроможність нашої системи ефективно обробляти більший обсяг запитів.
Ці два значення є нерозривно пов'язаними: зменшення затримки зазвичай призводить до збільшення пропускної здатності. Існують способи їх індивідуального налаштування.
Розмір пакета
LLM складаються з численних послідовних матричних множень. При обробці на масово паралельних пристроях, таких як GPU, на обробку пакета запитів витрачається ненабагато більше часу, ніж на проходження одиничного запиту (до певної міри).
Якщо обробляти кілька вхідних запитів одночасно, з низькими витратами на час виконання, можна швидко примножувати токени, що проходять через нашу модель та виводяться з неї за одиницю часу. На послідовному процесорі, такому як CPU, усі кроки виконувалися б послідовно, уповільнено.

Малюнок відображає сутність множення матриць. Тут A – пакети вхідних даних, B – ваги моделі. Збільшуючи розмір вхідного пакета (розмірність М матриці вхідних даних А), ми можемо прискорювати інференс, збільшуючи пропускну здатність системи.
Квантування
В системі з обмеженою пропускною здатністю багато часу витрачається на переміщення великих блоків даних для обробки, що призводить до черг та вузьких місць. LLM навчаються з використанням 32-розрядної або 16-розрядної точності. Це означає, що кожен параметр моделі представлений або 32, або 16 бітами. Зменшення розміру даних – законний і ефективний інструмент зменшення затримки і підвищення швидкості при інференсі, в систему із заданою пропускною здатністю. Квантування дозволяє «запхати джина в лампу», забезпечуючи можливість використання великих моделей на обмежених ресурсах GPU. 32-бітна модель вимагає 4 ГБ пам'яті для кожного мільярда параметрів, 16-бітна - 2ГБ, 8-бітна - 1ГБ та … LLM вміщується в телефоні.
Кешування
У основі LLM лежать трансформерні архітектури, а їх ключовим компонентом є механізм уваги (Attention Mechanism). У цьому механізмі для кожного токена (слова або частини слова) послідовно обчислюються три вектори:
• Query (Q) – запит
• Key (K) – ключ
• Value (V) – значення
Коли LLM генерує текст, він робить це авторегресивно, токен за токеном. Щоразу, коли генерується новий токен, модель має "передивитись " всю попередню послідовність (запит та вже згенеровані токени), щоб визначити, який токен генерувати наступним.
При інференсі відбувається багато повторюваних обчислень. Без KV Cache при генерації кожного нового токена моделі доводилося б перераховувати вектори Q, K і V для всієї вже існуючої послідовності токенів - вкрай неефективно та повільно, оскільки обсяг обчислень зростає квадратично з довжиною послідовності.
Кеш – наш інструмент зменшення затримки та збільшення пропускної здатності.
Джерела оптимізації
Загалом ми маємо три параметри для оптимізації пропускної спроможності та затримки інференсу LLM: розмір пакету, квантування, кешування. Квантування дозволяє зменшити вимоги до апаратної складової – пам'яті GPU, і то до певних меж - адже відповідь на запитання, скільки буде 2х2: «більше трьох, але менше п'яти» нас навряд чи влаштує. Два інші параметри потребують збільшення життєвого простору, пам'яті GPU. Пакетам потрібен простір для роботи.
Грубо розмір моделі можна порахувати наступним чином:
Розмір (у ГБ) = Параметри (в мільярдах) * Розмір даних (у байтах)
Імператив будь-якого «інференсиста»: модель має поміститися у пам’ять графічного процесора, VRAM. Наприклад, модель Llama2-13b з 13 мільярдами параметрів з точністю fp32 має розмір 52 ГБ, для fp16 – 26 ГБ. Такі апетити значно обмежують коло придатних GPU. Ба більше, для великих пакетів і кешів потрібен додатковий обсяг VRAM. Для моделі з 13 мільярдами параметрів один токен вимагає 1 МБ відеопам'яті для обчислень, що «ковзають». Якщо наш запит з 128 токенів (приблизно 90 англійських слів або близько 70 українських) і ми очікуємо відповіді на 128 токенів, то тільки це вимагає 256 МБ простору. А якщо нас, допитливих, 50 душ, то 12 ГБ типової відеокарти RTX5070 закінчуються навіть без завантаження моделі.
Коли потрібно збільшувати пропускну спроможність (тобто розмір пакету через складність нашого запиту чи кількості клієнтів/запитів, що обслуговуються), потрібна карта з великим об ‘ємом пам'яті.
Або розподіл моделі по кількох GPU.
Стратегії багатопроцесорного розподілу
Найпростіший підхід – повторення моделі на кількох графічних процесорах. Модель повністю завантажується в кожну карту, а система черг розподіляє запити на кожну з моделей. Плюс – простота реалізації. Мінус - модель повинна «влазити» цілком, VRAM використовується нераціонально (у кожному GPU одні й ті ж ваги моделі з'їдають пам'ять, зменшуючи її для «великих пакетів» та кешу).
Другий варіант – розбити нашу модель на частини та розділити частини між GPU. Цей спосіб значно складніший у «математиці» та програмуванні, додає накладні витрати на взаємодію - оскільки необхідно постійно поєднувати резуультати обчислень перед переходом до наступного етапу/шару. Однак він дозволяє використовувати моделі, значно більші за VRAM одного адаптера і працювати з великими пакетами даних.
Реалізації розподілу
Паралелізм даних – це реалізація стратегії повторення. Різні фрагменти даних обробляються на репліках нашої моделі.
Паралелізм конвейєра – це реалізація стратегії розбиття, шари моделі поділяються між GPU. Це досить простий підхід: після того, як один пристрій завершив обробку свого фрагмента моделі, проміжні дані передаються наступному пристрою. Розбити модель вийде, а ось з паралелізмом виникнуть проблеми – кожен пристрій повинен чекати завершення попереднього, в результаті більшу частину часу GPU простоюватимуть, чекаючи один одного.
Тензорний паралелізм – це теж реалізація стратегії розбиття, але замість розбиття по шарах розбиваються «внутрішарові» великі матриці.

Подібність множення матриць і звичайних чисел (за винятком комутативності) дозволяє спростити розрахунки: частини матриці можна обчислювати одночасно, а проміжні тензори об'єднувати для отримання повного результату. Таким чином ми максимально завантажуємо тензорні ядра їхньою улюбленою роботою – множенням та додаванням матриць, хоча виникають деякі накладні витрати на синхронізацію тензорів.
Спостереження практиків
Щоб не було боляче дивитися на помилку Out of Memory, модель повинна поміщатися у VRAM. Якщо модель міститься у пам'ять карти, розподіл обчислень по кількох GPU малоефективний – транспортні видатки нівелюють паралелізм. Єдиним виправдовуванням є необхідність збільшення розміру пакета. У цьому випадку можна використовувати режим паралельної обробки даних на GPU навіть більших, ніж потрібно моделі.
Якщо модель не вміщується в пам'ять однієї карти, вибору немає, тензорний паралелізм на допомогу. І тут треба розуміти:
- вище за «Амдалівське» обмеження не стрибнути
- швидше за все затримка у «кластері» зросте
- зросте розмір робочого пакета, можна обслужити більше користувачів чи розширити контекст
- екзотичні методи пакетування, не той фреймворк, не в тому місці, можуть перетворити кластер на гарбуз.
Побудова багатопроцесорних рішень на кількох GPU - правильний і найчастіше єдиний шлях, благо всі відкриті LLM підтримують тензорний паралелізм. Досить широко застосовується тензорний паралелізм разом із паралелізмом даних.
Тільки повне розуміння архітектури додатків у широкому контексті дозволить правильно оцінити вимоги до апаратної частини. Реалізація вимог у металі – якщо й не мистецтво, то, найчастіше за все, евристичний процес.
За мотивами та з використанням матеріалів
Захищені ноутбуки Getac B360 - нове покоління мобільної продуктивності для роботи в екстремальних умовах