Гайды

Как измерить скорость локальной модели правильно

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

Обычный домашний замер выглядит так: человек запускает модель, просит написать что-нибудь, засекает секундомером и делит слова на секунды. Через неделю он меняет настройку, повторяет процедуру и делает вывод, что стало быстрее.

Вывод почти наверняка неверный. В первом замере модель грузилась с диска, во втором была уже в памяти. Первый запрос был длиннее второго. В первый раз был открыт браузер, во второй нет. Разница в 30%, которую он увидел, объясняется чем угодно, кроме той настройки, которую он менял.

Замер полезен только тогда, когда воспроизводим. Ниже — протокол, который это обеспечивает.

#Что понадобится

  • Утилита замера. В llama.cpp это llama-bench, собирается вместе с остальными бинарниками. Для Ollama штатного эквивалента нет, но её HTTP-API отдаёт нужную статистику.
  • Фиксированная модель и квантизация. Не «qwen2.5:7b», а конкретный файл с конкретным уровнем квантизации.
  • Десять минут без другой нагрузки на машину.

#Протокол из шести шагов

#Шаг 1. Зафиксировать конфигурацию письменно

До первого запуска запишите шесть параметров: модель и уровень квантизации, размер контекста, число слоёв на GPU, тип KV-кэша, версию движка, режим питания. Замер без этой записи бесполезен через неделю — вы не вспомните, с чем сравниваете.

Версию движка стоит записывать точно: изменения производительности между релизами llama.cpp бывают заметными, и сравнивать замеры, сделанные на разных версиях, некорректно.

#Шаг 2. Освободить машину

Закройте браузер и всё, что использует видеокарту. Проверьте, что память свободна:

nvidia-smi --query-gpu=memory.used,utilization.gpu --format=csv

Заодно убедитесь, что не запущен другой экземпляр модели: Ollama могла оставить веса загруженными после прошлого сеанса. Проверяется командой ollama ps.

Ноутбук подключите к сети: в режиме от батареи частоты урезаны, и замер будет описывать не то железо, которым вы пользуетесь.

#Шаг 3. Прогреть и отбросить первый прогон

Первый запуск читает веса с диска. На модели в 5 гигабайт это добавляет секунды, которые размазываются по результату и завышают его. Правило простое: первый прогон всегда отбрасывается, независимо от того, насколько он выглядит нормальным.

llama-bench делает прогрев самостоятельно. При ручном замере сделайте один холостой запрос и не учитывайте его.

#Шаг 4. Зафиксировать длину промпта и длину генерации

Это второй по частоте источник неверных выводов. Скорость обработки промпта и скорость генерации — разные величины, и обе зависят от длины. Запрос «привет» и запрос на две страницы дадут несравнимые результаты.

В протоколе фиксируются оба числа: сколько токенов на входе, сколько генерируется. Стандартные значения для сравнений — 512 токенов промпта и 128 токенов генерации; для проверки поведения на длинном контексте — 4096 и больше.

#Шаг 5. Повторить минимум три раза и взять медиану

Разброс между прогонами на одной и той же конфигурации — обычное дело: фоновая активность системы, тепловой режим, работа диска. Один прогон ничего не доказывает. Медиана из трёх-пяти устойчивее среднего, потому что не уезжает от одного неудачного замера.

#Шаг 6. Записать два числа, а не одно

Скорость обработки промпта и скорость генерации записываются раздельно и сравниваются раздельно. Настройка, ускорившая одно и замедлившая другое, — типичная ситуация, и усреднение её маскирует.

#Команды

#llama.cpp

./build/bin/llama-bench -m models/qwen2.5-7b-instruct-q4_k_m.gguf -ngl 99 -p 512 -n 128 -r 5

Флаг -r 5 задаёт число повторов. Вывод содержит две строки: pp512 — скорость обработки промпта в токенах в секунду, tg128 — скорость генерации.

Утилита умеет перебирать значения списком, и это её главная ценность: вместо пяти отдельных запусков вы получаете таблицу за один раз.

./build/bin/llama-bench -m models/qwen2.5-7b-instruct-q4_k_m.gguf -ngl 20,30,40,99 -p 512 -n 128

Так подбирается оптимальное число слоёв на видеокарте. Аналогично перебираются потоки (-t 4,8,12) и размеры батча. Разбор остальных флагов — в гайде по llama.cpp без магии.

#Ollama

Быстрый вариант — флаг подробного вывода, который печатает статистику после ответа:

ollama run qwen2.5:7b "Опиши устройство велосипедной втулки" --verbose

Точный вариант — через API, где числа приходят в машиночитаемом виде:

curl -s http://localhost:11434/api/generate -d '{"model":"qwen2.5:7b","prompt":"Опиши устройство велосипедной втулки","stream":false,"options":{"num_predict":128}}' > out.json

В ответе интересны четыре поля: prompt_eval_count и prompt_eval_duration для обработки запроса, eval_count и eval_duration для генерации. Длительности указаны в наносекундах, поэтому скорость считается так:

python -c "import json;d=json.load(open('out.json'));print('gen', d['eval_count']/d['eval_duration']*1e9); print('prompt', d['prompt_eval_count']/d['prompt_eval_duration']*1e9)"

Повторите запрос трижды, первый результат отбросьте, из оставшихся возьмите медиану.

#Проверка результата

Признак первый: разброс между повторами меньше 10%. Больший разброс означает, что на машине происходит что-то ещё, и замер недостоверен.

Признак второй: результат согласуется с расчётным потолком. Разделите пропускную способность памяти вашего устройства на вес модели в гигабайтах. Замеренная скорость генерации должна составлять 40–70% этого числа. Заметно выше — вы измерили не то (например, забыли, что модель кэширует ответ). Заметно ниже — есть проблема в конфигурации.

Признак третий: числа воспроизводятся завтра. Повторите замер на следующий день на той же конфигурации. Расхождение больше 10% означает, что вы не зафиксировали какое-то условие.

Что считать хорошим результатом в абсолютных величинах — в материале о том, сколько токенов в секунду это нормально.

#Что может пойти не так

Сравнение разных квантизаций как «до и после». В каталоге Ollama за коротким именем стоит конкретный квант; локальный файл GGUF может быть другим. Убедитесь командой ollama show, что сравниваете одинаковое.

Разный контекст. Значение по умолчанию в Ollama и значение, которое вы указали в llama.cpp, скорее всего, не совпадают. Задавайте контекст явно в обоих инструментах.

Термотроттлинг на длинных прогонах. На ноутбуках первые двадцать секунд идут быстрее последующих. Если вам важна устойчивая скорость, замеряйте несколько минут подряд, а не один короткий прогон.

Кэш промпта. Движки умеют переиспользовать уже обработанный префикс запроса. Повторный одинаковый запрос может дать нереалистично быструю обработку промпта. Меняйте текст запроса между повторами, сохраняя длину.

Сравнение с чужими числами из интернета. Даже корректный чужой замер сделан на другом железе, другой версии движка и, скорее всего, на английском тексте. Как читать такие публикации — в материале о том, как читать бенчмарки LLM.

#Частые вопросы

#Зачем измерять, если и так видно, что медленно?

Чтобы понять, куда двигаться. «Медленно» не отличает ситуацию «упёрлись в пропускную способность памяти» (лечится только сменой модели или железа) от ситуации «половина слоёв ушла на процессор» (лечится настройкой за минуту). Порядок диагностики — в материале о том, почему локальная модель тормозит.

#Сколько повторов достаточно?

Три как минимум, пять комфортно. Если разброс между ними превышает 10%, повторов нужно больше — либо, что вероятнее, нужно устранить постороннюю нагрузку.

#Почему llama-bench показывает больше, чем ощущается в чате?

Утилита замеряет чистую генерацию на фиксированной длине. В реальном диалоге добавляются обработка растущего контекста, накладные расходы клиента и сетевой обмен с локальным сервером. Расхождение в 10–20% нормально.

#Можно ли сравнивать замеры на разных моделях?

Только с оговоркой: скорость обратно пропорциональна размеру модели в памяти. Модель вдвое меньше при прочих равных даст примерно вдвое больше токенов в секунду. Сравнивать имеет смысл либо одну модель при разных настройках, либо разные модели с поправкой на их вес.

#Что важнее — скорость промпта или генерации?

Зависит от сценария. Для диалога короткими репликами важнее генерация. Для работы с документами, где в модель заливаются длинные тексты, обработка промпта определяет всё ощущение от инструмента. Механику обеих фаз разбирает материал о том, от чего зависит скорость LLM на процессоре.

Хотите ИИ, который помнит вас?

Persona держит контекст между чатами и работает на вашем железе — если развернуть её у себя и подключить локальную модель.

Создать аккаунт