Я прогнал топ выдачи Google по «llm vram calculator» — от самого навороченного до однокнопочных. Все ошибаются в одном и том же: ни один не моделирует, что движок резервирует почти всю память под пул заранее, а не раздаёт её под KV по мере запросов. Ответ «сколько запросов влезет» из-за этого всегда мимо.
Наивное большинство спотыкается ещё и о геометрию KV: на DeepSeek-V2-Lite обычная формула завышает память почти на порядок (в 7–11 раз). Разбираю обе ловушки и сверяю числа с живым vLLM.
Ошибка №1: движок забирает память заранее
Пишете две строки:
from vllm import LLMllm = LLM("meta-llama/Meta-Llama-3-8B-Instruct")
Кажется, что движок положит веса, а остаток раздаст под KV по мере запросов. Так не делает ни один современный движок. vLLM при старте резервирует большой кусок VRAM под пул и пейджит KV внутрь него — флаг gpu_memory_utilization, дефолт 0.92. У SGLang то же зовётся mem_fraction_static (по умолчанию авто, около 0.9), у TensorRT-LLM — kv_cache_free_gpu_mem_fraction. Веса грузятся внутрь этого куска, KV живёт в остатке после весов и overhead; свободные ~8% VRAM под KV не пойдут никогда.
Ёмкость KV-пула поэтому считается так:
KV-пул = util · VRAM − веса − overhead
Если вы гоняете vLLM в проде, эту долю вы и так держите в голове: gpu_memory_utilization вы задаёте сами, а зачем пул выделяется одним куском, объясняет PagedAttention (arXiv:2309.06180).
Проверить, что пул посчитан верно, можно не арендуя GPU. vLLM при старте печатает строку # GPU blocks: N. Это и есть размер KV-пула. ridgepoint предсказывает то же число заранее:
llama-3-8b, 1× A100, ctx 8192: наивная формула без util обещает ~60 запросов; с поправкой на util — 54, замер vLLM — 55. Тот самый множитель, что вы и так держите в голове. С первой ошибкой всё.
Ошибка №2: геометрия KV, которую в уме не посчитать
KV на токен зависит от архитектуры внимания, и на этом спотыкается большинство калькуляторов (лучшие — вроде apxml — MLA всё же распознают). У обычной GQA-модели байты на токен считаются как 2·n_kv·head_dim·L·p. У DeepSeek с MLA внимание сжато в латент, и формула другая: (d_c + d_rope)·L·p, где d_c — размерность сжатого латента, d_rope — rope-часть.
Посчитаем DeepSeek-V2-Lite руками, из его config.json:
MLA (правильно): (512 + 64)·27·2 = 31 104 Б/токеннаивная формула: 2·n_kv(16)·head_dim·27·2 head_dim=128 (hidden/heads): → 221 184 Б/токен = завышение 7.1× head_dim=192 (qk_nope+rope): → 331 776 Б/токен = завышение 10.7×
Калькулятор, который трактует MLA как обычное внимание, подставляет 2·n_kv·head_dim. Смотря какой head_dim он возьмёт, KV завышается в 7–11 раз. Точный множитель зависит от его допущения, но порядок один, и он задокументирован в самой DeepSeek-V2 (arXiv:2405.04434): MLA сжимает KV в разы. И промах тут в обратную сторону от первой ошибки: вы решите, что модель требует почти на порядок больше карт, зря откажетесь её ставить или арендуете стойку вместо одной GPU.
С MoE та же ловушка: у DeepSeek-V2-Lite веса 16B (total), а активны 2B. Память платите за 16, скорость считаете по 2, перепутать легко.
Опираюсь я тут на измеренное: настоящие 31 104 Б/токен сняты с живого vLLM (40.79 ГиБ / 1 408 144 токенов), а (512+64)·27·2 сверьте сами. Инструмент берёт любой org/model с HuggingFace, читает конфиг и применяет формулу под конкретную архитектуру (GQA, MLA, MoE определяются сами):
Ради этого случая инструмент и писался.
Насколько числам можно верить
Наивная прикидка, ridgepoint и живой vLLM (замер на RunPod, vLLM 0.28, util 0.90):
|
1× A100-80GB, ctx 8192 |
наивно |
ridgepoint |
замер vLLM |
|---|---|---|---|
|
llama-3-8b (GQA) |
~60 |
54 |
55 |
|
DeepSeek-V2-Lite (MLA·MoE) |
GQA-формула → 16–24 |
171 |
172 |
|
llama-3-70b AWQ |
~15 |
12 |
13 |
Оговорю рамки. Память я сверял с логами vLLM и nvidia-smi на четырёх моделях трёх архитектур (GQA, MLA, MoE) на A100, плюс перенос на H100: по байтам расхождение 1–4% и всегда чуть ниже замера, то есть недооцениваю. Счётчики запросов в таблице округлены до целого, поэтому там разрыв может выглядеть крупнее (12 против 13 — это те же байты). Это n=4, не закон природы; полный predict-vs-measured лежит в репозитории (calibration/CALIBRATION.md). Побайтовый KV точен арифметически, если верно определена архитектура — ровно это определение и делает инструмент. Интервал overhead (1.5·1.8·2.2 в выводе — активации плюс CUDA-графы) уже эмпирика, её я и калибровал, отсюда полоса low/best/high. Дефолт vLLM с тех пор уехал с 0.90 на 0.92, значит реальный пул чуть больше моих чисел — я и здесь недооцениваю.
Где инструмент не помогает
Скорость. TTFT и утилизацию компьюта (MFU, model FLOPs utilization) замерить чисто не вышло: удалённый бенчмарк мешает префилл с сетью, поэтому в выводе они помечены ~MFU literature — цифры из литературы, сам я их не мерил. Пропускную способность памяти при декоде (MBU, memory-bandwidth utilization ≈ 0.62) померил, этой цифре верю. Throughput под смешанной нагрузкой (--max-num-seqs, разные длины) v0 не считает, это следующая версия. И числа пока калиброваны на vLLM: SGLang с TensorRT-LLM пейджат KV в такой же пул, но коэффициенты под них я ещё не мерил.
Что показал прогон
Взял то, что видит обычный человек в выдаче — и pre-grab движка не моделирует никто, даже лучший из них.
apxml реально силён: распознаёт MLA, считает framework overhead, умеет KV-квант. Но Concurrent Users — это ползунок на вход, а память он складывает как «веса + активации + KV + overhead < VRAM». Что vLLM заберёт gpu_memory_utilization заранее и сколько запросов влезет в оставшийся пул — не моделирует.
smcleod и NyxKrage проще: Model + KV = Total, без overhead и без MLA (значит, на DeepSeek — те самые 7–11×). Проверьте сами за минуту по ссылкам.
И это не про «старьё»: механизм публичен с PagedAttention (2023), а тулы 2026 года его всё равно не берут.
Попробовать на своём. GPU не нужен
pip install ridgepointridgepoint fit deepseek-ai/DeepSeek-V2-Lite --gpu h100-80gb:1 --ctx 8192
Считает локально, на ноутбуке: тянет с HuggingFace только config.json и индекс safetensors (пара КБ), больше ничего никуда не уходит (python/ridgepoint/hf.py). Жечь GPU-часы не нужно.
Дальше подставляйте что нужно. Любой HF-репозиторий подтянет конфиг сам. Карта задаётся флагом --gpu a100-80gb:1 или h100-80gb:2, а ridgepoint devices найдёт локальные. Движок — --engine vllm|sglang|llamacpp; SGLang уже работает (пул тот же pre-grab), но помечен uncalibrated — коэффициенты под него на железе я ещё не мерил. Если удобнее из кода — есть библиотечный вызов ridgepoint.fit("llama-3-70b", "a100-80gb", count=2).
Ядро на Rust считает только числа и в сеть не ходит. HF-адаптер живёт снаружи, на Python.
Что дальше
v0 узкий: память и ёмкость, пока два движка (vLLM и llama.cpp). Но внутри уже не наивно — веса и KV-кэш квантуются раздельно (--kv-cache-dtype fp8 вдвое увеличивает KV-ёмкость пула; кто ставит fp4-веса при fp16-кеше, обычно этого не осознаёт), а MLA/MoE/GQA определяются сами. В очереди, по одному измеренному куску за релиз:
-
Докалибровать движки на железе. SGLang уже запускается (
--engine sglang), но покаuncalibrated— с него и начну (сам его предпочитаю), дальше TensorRT-LLM и TGI. Пул у всех один и тот же pre-grab, отличаются только коэффициенты. -
Полный шкаф железа и квантов: Blackwell, H200, MI300X, NVLink. Заодно покажу, как FP8/FP4 двигают обе оси roofline — байты весов вниз и пиковые FLOPs вверх.
-
Скорость замером на поде, а не из литературы. Сейчас в выводе там заглушка
~MFU literature, вы её видели. -
Несколько GPU: TP/PP/EP. В замерах уже вижу, что активации шардятся, а CUDA-графы на карту нет.
-
Спек-декодинг. Он переводит decode из memory-bound в compute-bound, тащит тебя к тому самому ridge point, в честь которого инструмент назван.
-
Mamba/SSM, sliding-window, гибриды — где KV перестаёт расти линейно по контексту.
-
Оффлоуд KV в CPU/NVMe и деньги: $/1М токенов против облачного API.
Код лежит открыто: github.com/Isk4R1oT/ridgepoint. Буду рад звезде, а ещё больше — issue с моделью, на которой мои числа разошлись с вашим vLLM.
Вопрос к тем, кто гоняет vLLM в проде: сверьте # GPU blocks из своего лога старта с тем, что предскажет ridgepoint fit на вашей модели. Совпало? И ловили ли OOM там, где по расчёту всё влезало?
ссылка на оригинал статьи https://habr.com/ru/articles/1079788/