Если вы читаете этот текст, скорее всего, вы уже пробовали запустить LLM самостоятельно и, вполне вероятно, столкнулись с одной из типичных проблем:
«Заказал GPU, загрузил модель, а она не влезла, хотя по расчетам памяти должно было хватить».
«Платим за A100, а реально используем лишь 30% ее мощности».
Привет, на связи Павел, ML-инженер в Cloud.ru. Я прошел через эти проблемы сам, поэтому не понаслышке знаю, как это может раздражать.
Сегодня на примере настройки фреймворка VLLM покажу, как запускать крупные языковые модели без переплат за GPU. Мы разберемся, как VLLM распределяет vRAM, какие его параметры действительно влияют на потребление памяти и производительность, и как с их помощью гибко управлять балансом между затратами, скоростью и качеством модели.

Чтобы эффективно управлять стоимостью инференса, важно понимать, из чего складывается работа LLM во время вывода. В отличие от стадии обучения, на этапе инференса не нужно выделять память под градиенты функции ошибки — это существенно снижает потребление видеопамяти. Тем не менее, нагрузка остается высокой и состоит из нескольких ключевых компонентов:
Веса модели — основная часть данных, хранящая обученные параметры.
KV-cache (Key-Value cache) — кеш промежуточных результатов механизма внимания, критичный для генерации последовательных токенов.
Буферы вычислений и CUDA Graphs — временные структуры, используемые для оптимизации скорости выполнения.
Давайте рассмотрим каждый из этих элементов подробнее.
Веса модели
Это наиболее очевидная часть — сами параметры модели. Размер весов модели можно оценить по количеству параметров и формату данных:
FP32 — 4 байта на параметр
BF16/FP16 — 2 байта на параметр
INT8 — 1 байт на параметр
INT4 (квантование) — 0.5 байта на параметр
Например, модель Llama-3 8B в формате BF16 занимает примерно:
8 * 10^9 параметров × 2 байта = 16 ГБ
Если же мы хотим более точно понимать размер модели в момент запуска, не скачивая веса, нужно знать размер и тип данных каждого тензора — эта информация хранится в начале GGUF-файла в раз��еле с метаданными. Перемножив размеры тензоров, мы получим количество чисел в каждом тензоре. А умножив затем тип данных на количество чисел в тензоре, узнаем, сколько места занимает один слой. Делаем так для всех слоев, складываем значения и получаем размер всей модели.
Для точной оценки без загрузки весов можно использовать transformers с init_empty_weights(). Под капотом веса модели будут размещены на meta-устройстве, особенностью которого является то, что каждый тензор PyTorch будет содержать информацию о размере и типе данных, но не будет выделять память под сами тензоры.
from transformers import AutoModel, AutoConfig
from accelerate import init_empty_weights
model_config = AutoConfig.from_pretrained("meta-llama/Meta-Llama-3-8B")
with init_empty_weights():
model = AutoModel.from_config(model_config)
KV-cache
KV-cache — это кеш, в котором хранятся вычисленные ключи (K) и значения (V) для каждого токена в контексте. Он позволяет избежать пересчета внимания на каждом шаге, но сильно увеличивает потребление памяти, особенно при длинных диалогах.
В VLLM используется PagedAttention, где память под KV-cache выделяется блоками и выделяется в последнюю очередь: после размещения весов модели, построения CUDA-графов и других компонентов. VLLM делит оставшуюся память на блоки, а затем проверяет, хватит ли их для указанной длины контекста. Формула вычисления размера одного блока выглядит следующим образом:
размер блока = 2 × block_size × num_kv_heads × head_size × num_hidden_layers × dtype_num_bytes
Где:
block_size — количество токенов в одном блоке (по умолчанию 16),
num_kv_heads — количество «голов» внимания для KV-cache,
head_size — размер одной «головы» внимания модели,
num_hidden_layers — количество скрытых слоев,
dtype_num_bytes — количество байт на одно число в формате KV-cache (2 для float16).
Опираясь на это, посчитаем размер блока и всего KV-сache, например, для Qwen3-32B. Его config.json выглядит следующим образом:
"hidden_size": 5120,
"num_attention_heads": 64,
"num_key_value_heads": 8,
"num_hidden_layers": 64,
"max_position_embeddings": 40960,
"head_dim": 128, // если такого поля нет, то ==> hidden_size / num_attention_heads = 5120 / 64 = 80
Пусть head_size = 128, dtype_bytes = 2 (bfloat16):
Размер одного блока = 2 × 16 × 8 × 128 × 2 = 65,536 байт = 64 КБ
Количество блоков = ceil(длина_контекста / block_size) = ceil(40 960 / 16) = 2 560
Общий объем KV-cache на один слой:
2 560 × 64 КБ = 160 МБ
На первый взгляд — мало. Но это на слой.
Полный размер KV-cache = размер одного блока × количество слоев × количество блоков
160 МБ × 64 слоя = 10 ГБ
Это уже значительная часть памяти. Для Qwen3-32B с 40K контекста нужно заложить еще ~10 ГБ только под KV-cache.
Буферы вычислений и CUDA Graphs
VLLM для ускорения использует CUDA Graphs, которые предварительно «запекают» последовательность GPU-операций. Это снижает задержку, но требует дополнительной памяти.
Размер буферов можно оценить по формуле:
буферы ≈ context_length × (hidden_size + intermediate_size) × dtype_bytes
Для Qwen3-32B:
hidden_size = 5 120
intermediate_size = 25 600 (в FFN)
dtype_bytes = 2
context_length = 40 960
Буферы ≈ 40 960 × (5 120 + 25 600) × 2 ≈ 40 960 × 30 720 × 2 ≈ 2 ГБ
Overhead и системные накладные расходы
На системные нужды (администрирование памяти, библиотеки, контейнеры) стоит заложить 5–10% от общего объема vRAM.
Итоговая формула потребления vRAM
Общая память = веса модели + KV-cache + буферы вычислений + overhead (~5%)
Для Qwen3-32B (BF16):
веса: 64 ГБ (32B × 2),
KV-cache (40К): ~10 ГБ,
буферы: ~2 ГБ,
итого: ~80 ГБ.
Из чего складывается цена инференса
Цена за использование модели напрямую зависит от типа GPU, количества потребляемой vRAM и времени работы модели. Формула выглядит следующим образом:
итоговая стоимость = vRAM (ГБ) × цена 1 ГБ vRAM GPU + (запросы (в млн) × 12.8 ₽/1 млн запросов) + KV-cache (ГБ) × 0.013 ₽/(ГБ×ч)
Попробуем посчитать цену одного инстанса Qwen3-32B без сжатий и с полным контекстом. Я делаю это в облачном сервисе для запуска и развертывания ML- и DL-моделей:
$(80 \times 4.35 + (5 \times 12.8) + 66 \times 0.013) \times 1 = 412.858 ₽
Где:
80 ГБ — количество vRAM в конфигурации GPU,
4.35 ₽ — цена за использование 1 ГБ GPU в час,
5 — запросы в миллионах,
66 ГБ — объем файлов весов модели,
1 — время в часах работы инференса.
Самый простой способ платить меньше — сократить время использования модели. В облаке есть режим serverless: когда модель простаивает, она уходит в сон, и оплата за этот период не начисляется. Когда появляются новые запросы — модель автоматически запускается заново.
На изображении ниже можно увидеть параметры масштабирования. Если минимальное количество экземпляров равно нулю, то модель будет работать в serverless-режиме, иначе минимум одна реплика модели всегда будет существовать.

При увеличении нагрузки возможно масштабирование модели вверх (будут запускаться дополнительные инстансы модели), вплоть пока количество моделей не достигнет максимального количества экземпляров. После того как нагрузка снизится, количество экземпляров снизится до минимального количества.
Второй вариант — уменьшить потребление видеопамяти. Об этом мы и поговорим подробно дальше.
Как уменьшить цену и не потерять в качестве
Уменьшение контекста модели
Это самый простой и безопасный способ. В таком случае не происходит никаких потерь точности модели от сжатия весов. Но этот способ подходит только тогда, когда нужно работать с небольшим объемом информации, и вы уверены, что уложитесь в короткий контекст, ни на процент не жертвуя при этом метриками модели.
Для этого в параметрах запуска модели нужно настроить параметр max_model_len, выставив его таким образом, чтобы он был больше, чем суммарный объем входных запросов в модель и ее возможный ответ. На изображении ниже показано, как это выглядит при создании инференса VLLM в облаке.

Использование квантованных моделей
В этом случае мы уменьшаем размер занимаемой vRAM непосредственно за счет сжатия весов модели. Изначально большинство моделей используют формат bfloat16, то есть 16 бит = 2 байта на один параметр. При квантовании этот параметр можно сжать вплоть до 1 бита на параметр, но я не рекомендую использовать квантование менее 4 бит на параметр — дальше качество сильно падает. Ниже изображены все GGUF квантизации модели Qwen-32b и сколько места будут занимать веса модели.

Используя квантование в 4 бита, мы можем снизить объем, занимаемый весами модели, вплоть до 4 раз — с 64 ГБ до ~18 ГБ.
VLLM может произвести квантование модели на лету, но для более высокого качества лучше использовать уже квантованные модели. Для них есть готовый раздел на Hugging Face. Он находится в правой боковой панели. Нажав на Quantization, вы увидите все квантизации модели.
Для примера возьмем ту же qwen/Qwen3-32B-FP8.

Квантование KV-cache
Помимо квантования самих весов, можно также квантовать и блоки KV-cache. Вместо 16 бит (bfloat16) их можно привести к формату FP8, тем самым снизив расходы на KV-cache в 2 раза: с 10 ГБ до 5 ГБ. При этом квантование KV-cache почти не ухудшает метрики модели и может применяться как к квантованным, так и к базовым моделям.
На изображении ниже можно увидеть список всех поддерживаемых форматов квантизации kv-cache в VLLM.

В общей сложности, применив квантование модели в FP8 и квантование KV-cache, можно запустить модель с полным контекстом на 40 ГБ vRAM, вместо изначальных 80 ГБ.
Что в итоге
Запуск LLM-моделей в облаке может быть достаточно гибким и эффективным — все зависит от того, насколько осознанно подходить к управлению ресурсами. На примере Qwen3-32B мы увидели, что изначальные требования к памяти (около 80 ГБ) ведут к высокой стоимости инференса — более 400 руб. в час при постоянной нагрузке.
Используя комбинацию простых, но мощных оптимизаций, можно сократить расходы в 2 раза и более, не сильно теряя при этом в качестве генерации:
квантование весов модели до FP8 сокращает объем;
квантование KV-cache до FP8 уменьшает потребление памяти под кеш;
оптимизация длины контекста — при необходимости дальнейшей экономии можно снизить max_model_len, особенно если полный контекст в 40К токенов не нужен;
serverless-режим позволяет платить только за активное время работы модели, а в периоды простоя полностью исключать затраты.
Экономить на инференсе LLM — не значит жертвовать качеством. Достаточно понимать, из чего складывается потребление памяти, и использовать доступные инструменты: квантование, управление контекстом и гибкое масштабирование.
С этими подходами вы можете запускать мощные модели даже в ограниченном бюджете — быстро, эффективно и без потерь.
alexzen
Если брать облако, то проще и дешевле использовать коммерческие LLM через API. Сложно придумать кейс, где выгоднее запускать большую модель на арендованном GPU.
starfair
Ну, так то да! Но это пока речь не идет о коммерчески значимых задачах, где утечка ваших данных критически важна. Тогда такая "экономия" может стать вам боком
alkons
Многим компаниям для критически важных систем нужен SLA , который не дают сервисы коммерческих моделей по API.