Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Квантование LLM: GGUF, GPTQ и AWQ на практике

Квантование LLM: как сжать модель и не потерять качество

Квантование моделей: INT8/INT4, форматы GGUF, GPTQ и AWQ, влияние на качество и скорость, как выбирать квант под задачу и железо.

Прямой ответ

Квантование — уменьшение разрядности весов модели: вместо 16-битных чисел с плавающей точкой используются 8- или 4-битные целые. Практический эффект: модель 7B в FP16 занимает около 14 ГБ, в INT4 — около 4 ГБ. Это позволяет запускать модели на ноутбуке и ускоряет инференс за счёт меньшего объёма чтения памяти, который обычно и является узким местом.

Основные схемы:

  • INT8 (Llm.int8(), bitsandbytes). Почти без потери качества, даёт двукратное сжатие. Подходит, когда памяти впритык, а качество критично.
  • GPTQ. Постслойное квантование до 4 бит с компенсацией ошибки по вторым производным. Хорошо работает на GPU, требует калибровочного набора данных.
  • AWQ (Activation-aware Weight Quantization). Защищает небольшой процент «значимых» весов, определяемых по активациям; обычно сохраняет качество лучше GPTQ при той же разрядности.
  • GGUF (k-quants: Q4_K_M, Q5_K_S и др.). Формат контейнера llama.cpp с блочным квантованием: разные слои получают разную точность. Самый удобный путь для CPU и гибридного CPU+GPU запуска.

Как читать обозначения GGUF: Q4_K_M означает 4-битное квантование, k-quant-схему, средний (Medium) профиль распределения точности по слоям. S — меньше размер и чуть ниже качество, L — наоборот.

Что важно понимать:

  1. Квантование сжимает веса, а не активации и не KV-кэш. Память под контекст растёт линейно с длиной контекста и остаётся в высокой точности — при длинном контексте она может превышать объём весов. Как управлять контекстом — в статье про контекстное окно.
  2. Качество деградирует не линейно. Переход FP16 → Q8 почти незаметен, Q8 → Q5 малозаметен, Q5 → Q4 заметен на сложных задачах, Q3 и ниже — существенная потеря.
  3. Влияние зависит от задачи. Суммаризация и извлечение фактов деградируют медленнее, чем рассуждения и генерация кода.

Практика: выбор кванта под железо

Ориентировочные требования для модели 7–8B (веса + KV-кэш на контекст 8K):

Квант Размер весов Где запускается
Q8_0 ~8 ГБ GPU 12 ГБ, CPU с 16 ГБ RAM
Q5_K_M ~5.5 ГБ GPU 8 ГБ, CPU с 16 ГБ RAM
Q4_K_M ~4.5 ГБ GPU 6 ГБ, CPU с 8–16 ГБ RAM
Q3_K_M ~3.7 ГБ CPU с 8 ГБ RAM, компромисс по качеству

Практические шаги:

  1. Начинайте с Q4_K_M или Q5_K_M. Это точка баланса для большинства задач.
  2. Измеряйте на своих задачах, а не по средним бенчмаркам. Соберите набор из 20–50 реальных запросов и сравните ответы разных квантов — методика в статье про eval для LLM-приложений.
  3. Учитывайте разницу CPU/GPU. На CPU квантование даёт больший прирост скорости, потому что снимает ограничение пропускной способности памяти; на мощном GPU разница между Q8 и Q4 может быть небольшой.
  4. Проверяйте, что модель не «уехала» в swap. Если веса не помещаются в RAM, система начинает использовать диск, и скорость падает на порядок. Диагностика памяти — в статье про утечки и анализ памяти Python.

Запуск GGUF-модели:

# загрузка модели и запуск на CPU с частичным оффлоадом слоёв на GPU
./llama-cli -m qwen2.5-7b-instruct-q4_k_m.gguf \
  --ctx-size 8192 --n-gpu-layers 20 --threads 8

# проверка фактических характеристик запуска
./llama-cli -m model.gguf --verbose 2>&1 | grep -Ei "llama_|kv self|model size"

Практический сценарий: модель «поглупела» после перехода на Q4

Контекст: локальный ассистент для разбора логов; после замены Q5_K_M на Q4_K_M ответы стали хуже: модель путает имена сервисов и обрезает выводы.

  1. Проверка гипотезы. Прогоняем один и тот же набор из 30 запросов на Q5 и Q4 с одинаковыми параметрами генерации: в 6 случаях Q4 даёт неверный ответ, в 3 — теряет детали.
  2. Уточнение причины. Оказалось, что проблема усиливается на длинном входе: при 6K токенов контекста часть слоёв работает с меньшей точностью, а ошибки накапливаются. Дополнительно температура 0.9 усиливала расхождения, поэтому часть «поглупения» давали параметры генерации — см. sampling-параметры.
  3. Решение. Возвращаем Q5_K_M для задач разбора и оставляем Q4_K_M для коротких запросов (классификация, извлечение полей). Уменьшаем контекст до фактически необходимого: 4K вместо 8K.
  4. Проверка. На наборе из 30 запросов расхождение с эталоном падает с 6 до 1 случая; скорость остаётся приемлемой.
  5. Профилактика. Фиксируем правило: смена кванта — это изменение модели, поэтому требует прогона тестового набора, а не «просто поменять файл».

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

FAQ

Можно ли квантовать модель самостоятельно? Да: llama.cpp предоставляет llama-quantize для конвертации в GGUF, для GPTQ/AWQ есть реализации в экосистеме Hugging Face. Для GPTQ и AWQ нужен калибровочный набор — обычно несколько сотен примеров, близких к вашей задаче; без него качество заметно хуже.

Почему Q4_K_M иногда быстрее Q8, а иногда медленнее? Скорость упирается в чтение весов из памяти: меньше байт — быстрее. Но более агрессивные схемы квантования добавляют вычислительные операции на распаковку, поэтому на мощном GPU с быстрой памятью выигрыш может исчезнуть.

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

Что выбрать для серверного инференса с высокой нагрузкой? Для GPU-сервера обычно берут AWQ или GPTQ в связке с движком, поддерживающим непрерывное батчингирование, — например vLLM. Для CPU и гибридных сценариев — GGUF. Подробности сервинга — в статье про vLLM.

Источники: llama.cpp (GitHub), Hugging Face Transformers (quantization), AWQ paper — ссылки в шапке.