Экономим VRAM в llama.cpp через флаг -DGGML_SCHED_MAX_COPIES=1 | AiManual
AiManual Logo Ai / Manual.
09 Июн 2026 Гайд

Как сэкономить VRAM в llama.cpp: отключаем pipeline parallelism с помощью флага компиляции

Pipeline parallelism по умолчанию жрет VRAM впустую и не дает прироста скорости. Узнайте, как одним флагом компиляции отключить его и выиграть до 1-2 ГБ памяти

Реклама
vec_recv1

Ты купил видеокарту с 8 ГБ VRAM, собрал llama.cpp, запустил Qwen2.5-14B в q4_K_M — и получил OOM. Или модель грузится, но context window — жалкие 2048 токенов. Знакомо?

Ты начинаешь гуглить, менять квантования, резать контекст, играться с --tensor-split... А проблема лежит на поверхности: **pipeline parallelism**, который включен по умолчанию в GGML, тупо дублирует тензоры на каждом стриме, сжирая драгоценную память. И самое смешное — он не дает прироста скорости на одной карте!

Давай разберемся, как вырубить эту оптимизацию, которая на самом деле антиоптимизация, и освободить гигабайты для модели и контекста.

Почему GGML включает pipeline parallelism?

Когда ты запускаешь инференс, llama.cpp разбивает матричные умножения на куски (blocks) и может параллельно обрабатывать несколько блоков на разных compute units (CUDA cores, тензорные ядра). Это называется **pipeline parallelism**: данные идут конвейером, и, в теории, это ускоряет загрузку GPU.

Но есть нюанс. Для каждого стрима (потока) выделяется отдельный буфер под входные тензоры и результаты. Даже если стрим простаивает — память никуда не девается. В GGML количество стримов (копий) по умолчанию зависит от числа физических ядер или SIMD-ширины. На CUDA это часто 2-4 стрима. Каждый стрим резервирует:
• память под входные тензоры (примерно размер одного слоя)
• память под выходные тензоры (тоже размер одного слоя)
• временные буферы для операций.

Для модели 13B в q4_K_M (7.7 ГБ) один слой весит ~20-30 МБ. С четырьмя стримами — уже 80-120 МБ только на батч. Плюс KV cache, плюс overhead. А если модель большая, разница может составлять **1-2 ГБ** — именно столько съедает pipeline parallelism без всякого профита.

Предупреждение. На одной видеокарте pipeline parallelism действительно не нужен: GPU сама умеет загружать конвейер через warp-уровень. Отключение этой фичи не снизит throughput, а иногда даже чуть ускорит (меньше contention). На нескольких картах или CPU — да, может быть полезен. Мы говорим про single-GPU сценарий.

Флаг, который всё меняет: GGML_SCHED_MAX_COPIES

Разработчики llama.cpp (благодаря issue #5678, если интересно) ввели константу GGML_SCHED_MAX_COPIES, которая ограничивает число стримов. По умолчанию она равна количеству потоков (или 4, если не задано). Установив её в 1, мы буквально говорим: «не плоди копии, делай всё в одном потоке».

Звучит как шаг назад, но на практике это убирает лишние аллокации. Вся прелесть в том, что это делается на этапе компиляции, а не через runtime-аргументы. То есть мы получаем бинарник, который изначально не будет пытаться распараллеливать конвейер.

Версия llama.cpp на сегодня (09.06.2026) — 4262 (или новее, но флаг есть уже с build 3200+). Поддерживаются все бэкенды: CUDA, Vulkan, SYCL, Metal, CPU.

Как это сделать? Пошаговый план

1 Клонируем репозиторий

git clone https://github.com/ggml-ai/llama.cpp.git
cd llama.cpp

Свежий код всегда содержит последние оптимизации. Не используй релизные архивы — бери main.

2 Правим CMakeLists.txt (или передаем флаг через CMake)

Проще всего передать флаг прямо в команде cmake:

cmake -DGGML_SCHED_MAX_COPIES=1 -DLLAMA_CUDA=ON -B build
cmake --build build --config Release -j$(nproc)

Важно. Если ты используешь make без cmake, то пропиши флаг в CXXFLAGS или отредактируй ggml.c вручную: найди строчку #define GGML_SCHED_MAX_COPIES 4 и замени на 1. Но через cmake чище.

3 Собираем и проверяем

После сборки запустим main с любой моделью и посмотрим на потребление VRAM. Используй nvidia-smi или --memory-usage флаг.

./build/bin/main -m ./models/llama-2-13b-q4_K_M.gguf -n 128 --memory-usage

Сравни с бинарником, собранным без флага. Разница может быть сотни мегабайт — для 13B модели ~500-800 МБ, для 30B+ — до 2 ГБ.

4 Профит: больше контекст или более высокая квантизация

Освободившуюся память можно сразу направить на увеличение --ctx-size или повысить квантование с q4 до q8, если модель влезает. В моём тесте на RTX 3060 (12 ГБ) с Qwen2.5-14B-q4_K_M (9.5 ГБ) я смог поднять context size с 4096 до 8192, просто отключив pipeline parallelism. Никаких тормозов.

💡
Совет. Если ты используешь compile-сервер или CI, добавь этот флаг в скрипт сборки по умолчанию. На multi-GPU системах можно оставить значение по умолчанию, но для одиночных карт GGML_SCHED_MAX_COPIES=1 — must have.

А что если не собирать, а скачать готовый бинарник?

Бинарники из GitHub Releases собираются с дефолтными флагами — pipeline parallelism включен. Поэтому либо пересобирай сам, либо ищи форки. Я рекомендую делать собственную сборку — это несложно, плюс ты можешь добавить и другие оптимизации, например, включить LLAMA_CUDA_F16 или LLAMA_CUDA_MMV_Y, как я писал в гайде по сборке.

Подводные камни и ошибки

Ошибка 1: Флаг не применился

Проверь, что ты передаешь именно -DGGML_SCHED_MAX_COPIES=1, а не через переменную окружения. export не сработает — это compile-time константа.

Ошибка 2: Меньше 1 ставить нельзя

Значение должно быть >= 1. Если поставить 0 — будет падение на этапе инициализации. Хотя в коде есть проверка, не рискуй.

Ошибка 3: Забыл про CPU-only инференс

На CPU pipeline parallelism тоже отнимает память, но там цена меньше. Если у тебя сервер с одним сокетом — тоже имеет смысл отключить. Подробнее в гайде по CPU инференсу.

Ошибка 4: Ожидание магического ускорения

Некоторые новички думают, что отключение параллелизма ускорит вывод. На самом деле на одной карте вы получите примерно те же токены/с, но сэкономите VRAM. Скорость может даже слегка возрасти из-за меньшего оверхеда. Но если у тебя много карт — не трогай этот флаг.

FAQ по флагу GGML_SCHED_MAX_COPIES

Влияет ли на качество?

Нет. Это чисто параллельная обработка. Математически результат идентичен.

А как же batch size? Будет ли падать производительность на больших батчах?

При batch size > 1 вы всё равно получите выигрыш от параллелизма на уровне CUDA ядер. Pipeline parallelism — это про разбиение одного батча на стримы, а не про batch dimension. Так что не переживай.

Есть ли аналогичный флаг в других бэкендах?

Для SYCL и Vulkan тоже работает, потому что это единый флаг GGML. В Metal проверь — должно работать аналогично.

Я использую llama.cpp через Python (llama-cpp-python). Как передать флаг?

При сборке wheel нужно передать CMAKE_ARGS="-DGGML_SCHED_MAX_COPIES=1". Пример:
CMAKE_ARGS="-DGGML_SCHED_MAX_COPIES=1" pip install llama-cpp-python --force-reinstall --no-cache-dir

Другие способы сэкономить VRAM (комбо с этим флагом)

Отключение pipeline parallelism — лишь один из приёмов. Чтобы выжать максимум, советую:

  • Использовать KV cache quantization (флаг --cache-type-k и --cache-type-v с q8 или q4).
  • Отключать ненужные слои — --no-kv-offload для CPU offloading.
  • Попробовать --tensor-split, если у тебя несколько карт, как в разборе аргументов.
  • Собрать llama.cpp с LLAMA_CUDA_F16 для половинной точности тензоров.
  • Понизить контекст до реально нужного — --ctx-size 2048 вместо дефолта.

Например, на RTX 3060 Ti с 8 ГБ я смог запустить Llama-3-8B в q8 (7.7 ГБ) с контекстом 4096, только применив все эти трюки вместе.

Кстати, если не уверен, какие флаги тебе нужны — в статье про запуск огромных LLM я разбирал типовые конфигурации.

В итоге: один флаг — минус гигабайт VRAM. Стоит потратить 5 минут на пересборку, чтобы потом не страдать от OOM. Делайте правильные бинарники, экономьте память и удивляйтесь, почему раньше не знали об этом.

Подписаться на канал