ПостСредне ⏱ ~6 мин

Оптимизация локальных LLM: ускоряем в 2-3 раза без апгрейда

Оглавление

Модель установлена, запущена, но работает медленно. 5 токенов в секунду — и ты смотришь на экран, как в 90-е на загрузку через dial-up. В этом посте — конкретные параметры и техники, которые реально ускоряют локальные LLM на CPU. Без магии, только измеряемый результат.

Что влияет на скорость

Прежде чем крутить параметры, нужно понимать, где теряется время. Генерация токенов в LLM — это последовательный процесс: каждый новый токен зависит от всех предыдущих. Поэтому есть два режима работы:

Prefill (обработка промпта) — модель читает ваш запрос и строит внутреннее представление. Здесь можно распараллелить вычисления, и скорость измеряется в тысячах токенов в секунду.

Generation (генерация ответа) — модель выдаёт токены один за другим. Здесь параллелизм ограничен, и скорость падает до единиц или десятков токенов в секунду.

Для QA-задач критична именно скорость генерации — мы не загружаем романы в контекст, но ждём, пока модель напишет тест-кейс или код.

Параметры llama.cpp, которые реально работают

1. Количество потоков (-t, --threads)

Самый очевидный параметр. По умолчанию llama.cpp использует все доступные ядра, но на практике оптимальное значение часто меньше максимума.

# Посмотреть количество ядер
sysctl -n hw.ncpu  # macOS
nproc              # Linux

# Запуск с разным количеством потоков
llama-cli -m model.gguf -t 4 --temp 0.7
llama-cli -m model.gguf -t 8 --temp 0.7
llama-cli -m model.gguf -t 16 --temp 0.7

Мои измерения на Intel i7-1265U (10 ядер, 12 потоков):

Потоки Скорость (ток/сек) Нагрузка CPU
4 5.2 45%
8 8.1 78%
12 8.5 95%
16 7.8 100%

Вывод: для этого CPU оптимум — 8 потоков. Больше — только нагрев и шум вентилятора, скорость не растёт. На вашем железе цифры будут другие, принцип тот же: найдите точку, где добавление потока перестаёт давать прирост.

2. Размер батча (-b, --batch-size)

Batch size — сколько токенов модель обрабатывает параллельно на этапе prefill. Для коротких промптов (наши QA-задачи) большой батч не нужен. Но если вы загружаете логи или ТЗ — имеет значение.

# По умолчанию 2048, для коротких промптов можно уменьшить
llama-cli -m model.gguf -b 512 --temp 0.7

# Для длинных документов — увеличить
llama-cli -m model.gguf -b 4096 --temp 0.7

Эффект заметен только на prefill. Для генерации ответа batch size не влияет.

3. GPU Offload (-ngl, --n-gpu-layers)

Самый мощный способ ускорения — перенос вычислений на GPU. Но здесь есть нюансы.

macOS с Apple Silicon: Unified Memory означает, что RAM и VRAM — это одно и то же. Ollama и llama.cpp автоматически используют GPU, если доступно. Параметр -ngl 999 говорит «offload все слои на GPU».

# Mac — offload всё на GPU
llama-cli -m model.gguf -ngl 999 --temp 0.7

# Если модель не помещается — уменьшайте
llama-cli -m model.gguf -ngl 20 --temp 0.7  # offload 20 слоёв

Windows с NVIDIA: нужны CUDA-драйверы и llama.cpp, собранный с поддержкой CUDA. Ollama делает это автоматически.

# Windows + NVIDIA — проверьте, что CUDA доступна
llama-cli -m model.gguf -ngl 999 --temp 0.7

# Если не работает — Ollama проще
ollama run my-model

Windows с Intel/AMD GPU: поддержка хуже. Попробуйте Vulkan-backend или оставайтесь на CPU.

Мои измерения на MacBook Air M4 (Qwen 3.5 9B):

Режим Скорость (ток/сек) Разница
CPU only 12 baseline
GPU 50% слоёв 22 +83%
GPU 100% слоёв 35 +192%

4. Размер контекста (-c, --ctx-size)

Большой контекст — это хорошо, но он требует памяти. И не только RAM: при генерации модель «освежает» весь контекст, что замедляет выдачу каждого нового токена.

# Минимальный контекст для чек-листов
llama-cli -m model.gguf -c 2048 --temp 0.7

# Средний — для анализа требований
llama-cli -m model.gguf -c 8192 --temp 0.7

# Большой — для логов и кодовой базы
llama-cli -m model.gguf -c 32768 --temp 0.7

Мои измерения (Qwen 3.5 9B на M4):

Контекст Скорость (ток/сек) Память
2K 38 4.2 GB
8K 35 5.1 GB
32K 28 7.8 GB
128K 18 14.2 GB

Вывод: для 90% QA-задач достаточно 8K контекста. 32K — если анализируете большие логи. 128K — редко нужен, и цена в скорости существенна.

5. Квантизация модели

Квантизация — это сжатие весов модели. Вместо 16 бит на параметр используется 4 или 5 бит. Потери качества минимальны (особенно для QA-задач), а выигрыш в скорости и памяти — колоссальный.

Основные форматы:

  • Q4_K_M — баланс качества и размера. Рекомендую как базовый.
  • Q5_K_M — чуть лучше качество, чуть больше размер. Если RAM позволяет.
  • Q3_K_M — агрессивное сжатие. Для слабого железа, но качество падает заметно.
  • Q6_K — максимальное качество при квантизации. Почти неотличим от оригинала.
  • FP16 — без сжатия. 4x больше памяти, минимальный выигрыш в качестве.

Мои измерения (Qwen 3.5 9B на M4):

Формат Размер Скорость Качество кода
Q3_K_M 3.8 GB 42 ток/с 65% компилируется
Q4_K_M 4.9 GB 38 ток/с 78% компилируется
Q5_K_M 5.9 GB 35 ток/с 82% компилируется
Q6_K 6.8 GB 32 ток/с 85% компилируется

Вывод: Q4_K_M — золотая середина. Q5_K_M — если у вас достаточно RAM и вы пишете много кода. Q3_K_M — только если совсем тесно.

Практические сценарии оптимизации

Сценарий 1: Корпоративный ноутбук, нужна максимальная скорость

Железо: Intel i7, 16 GB RAM, без дискретной GPU.

# Модель: Qwen 2.5 4B Q4_K_M (2.5 GB)
# Контекст: минимальный, только для чек-листов
# Потоки: 8 (оптимум для этого CPU)

llama-cli \
  -m qwen2.5-4b-q4_k_m.gguf \
  -t 8 \
  -c 4096 \
  -b 512 \
  --temp 0.7 \
  -p "Напиши чек-лист..."

# Ожидаемая скорость: 10-15 ток/сек

Сценарий 2: MacBook Air, нужен баланс

Железо: M2, 16 GB RAM.

# Модель: Qwen 3.5 9B Q4_K_M (5.8 GB)
# GPU offload: максимальный
# Контекст: средний

llama-cli \
  -m qwen3.5-9b-q4_k_m.gguf \
  -ngl 999 \
  -c 8192 \
  --temp 0.7 \
  -p "Напиши тест-кейс..."

# Ожидаемая скорость: 25-30 ток/сек

Сценарий 3: Максимальное качество кода

Железо: машина помощнее — MacBook Pro с 36 GB RAM. Это расчётный сценарий: у меня Air с 16 GB, а 14B в Q5 туда уже не влезает.

# Модель: Qwen 2.5 Coder 14B Q5_K_M (11 GB)
# GPU offload: полный
# Контекст: большой (можем себе позволить)

llama-cli \
  -m qwen2.5-coder-14b-q5_k_m.gguf \
  -ngl 999 \
  -c 16384 \
  --temp 0.3 \
  -p "Напиши Page Object для..."

# Ожидаемая скорость: 15-20 ток/сек
# Качество: максимальное

Оптимизация Ollama

Если используете Ollama — тоже есть рычаги. Создайте или отредактируйте Modelfile:

FROM ./models/qwen3.5-9b-q4_k_m.gguf

# Параметры генерации
PARAMETER temperature 0.7
PARAMETER num_ctx 8192
PARAMETER num_thread 8

# Оптимизации
PARAMETER num_batch 512
PARAMETER num_gpu 999

SYSTEM "Ты — QA automation engineer..."

Или передайте параметры при запуске:

OLLAMA_NUM_THREAD=8 OLLAMA_NUM_GPU=999 ollama run my-model

Техники, которые НЕ работают

Чтобы сэкономить ваше время — список того, что я проверил и что не дало результата:

  • Изменение seed (-s) — влияет только на случайность ответа, не на скорость
  • Отключение логов (--log-disable) — экономия наносекунд, не заметна
  • Использование FP32 вместо FP16 — только медленнее, качество не улучшается
  • «Оптимизированные» сборки из интернета — чаще всего вирусы или placebo

Измеряйте, не гадайте

Главное правило оптимизации — измеряйте, а не гадайте.

llama.cpp выводит скорость генерации в конце каждого запроса:

llama_print_timings:        load time = ...
llama_print_timings:      sample time = ...
llama_print_timings: prompt eval time = ...
llama_print_timings:        eval time = ...
llama_print_timings:       total time = ...
llama_print_timings:    tokens per second = 12.34

Фокусируйтесь на «tokens per second». Это ваша метрика успеха.

И помните: оптимизация — это компромисс. Максимальная скорость на слабом железе достигается ценой качества (меньшая модель, агрессивная квантизация). Максимальное качество — ценой скорости (большая модель, минимальная квантизация). Найдите свой баланс.

В следующем посте — практика. Конкретные промпты для генерации чек-листов, тест-кейсов, кода автотестов. Копируй и используй.

Назад

Обсуждение

Комментариев пока нет — начните тему.

Комментариев пока нет — начните тему.

Оставить комментарий

Комментарии публикуются сразу после отправки.