Квантование LLM: полное руководство по снижению точности ради производительности

aillmopensourcehardware
← Back to Blog

Введение: почему квантование стало мейнстримом

Большие языковые модели 2024-2026 годов требуют несоразмерно много памяти. Модель Llama 3 70B в FP16 занимает 140 ГБ — больше, чем VRAM даже топовых серверных GPU. Квантование — техника снижения разрядности чисел — позволяет уместить 70B модель в 24 ГБ VRAM с минимальной потерей качества.

В 2023 году квантование было нишевой темой для энтузиастов. В 2026 году это обязательный этап деплоя LLM. vLLM, llama.cpp, TensorRT-LLM — все основные движки поддерживают квантованные модели. Но какой формат выбрать, сколько бит нужно и не убьёт ли INT8 качество модели?

Данное руководство проходит от теории к практике: от математики квантования до конкретных команд для генерации GGUF и загрузки в vLLM.

Основы — что происходит с числами при квантовании

От FP16 к INT4: путь сокращения разрядности

Стандартная модель в FP16 использует 16 бит на параметр. 70B параметров × 2 байта = 140 ГБ.

Формат Бит на параметр 7B модель 13B модель 70B модель
FP32 32 280 ГБ 560 ГБ 2.8 ТБ
FP16 / BF16 16 140 ГБ 260 ГБ 140 ГБ
FP8 8 70 ГБ 130 ГБ 70 ГБ
INT8 8 70 ГБ 130 ГБ 70 ГБ
NF4 4 35 ГБ 65 ГБ 35 ГБ
INT4 4 35 ГБ 65 ГБ 35 ГБ
INT2 2 17 ГБ 32 ГБ 17 ГБ

Ключевая идея: квантование — это отображение диапазона значений из высокого пространства в низкое. FP16 диапазон [-65504, 65504] сближается до 16 значений INT4 [-8, 7].

Математика линейного квантования

Простейшая формула:

quantized_value = round(float_value / scale) + zero_point

Где:

  • scale — коэффициент масштабирования (сколько FP16 единиц в одном INT4)
  • zero_point — смещение, позволяющее точно представить ноль

Обратное преобразование (деквантование):

float_value = (quantized_value - zero_point) * scale

Это означает, что деквантование — это просто умножение на скаляр и сдвиг. Обе операции крайне быстры на любом GPU/CPU.

Типы квантования в контексте LLM

Пер-тензорное (per-tensor): один scale для всего тензора весов. Быстро, но грубо. Подходит для FP8.

Пер-каналовое (per-channel): свой scale для каждого канала (строки или столбца матрицы). Точнее, но больше накладных расходов. Используется в AWQ и GPTQ.

Пер-блокное (per-block / per-group): scale для группы из N параметров. Например, per-token с group_size=128. Золотая середина между точностью и эффективностью. Используется в GGUF (Q4_K_M) и AWQ.

Основные методы квантования LLM

GGUF / llama.cpp (Q4_K_M, Q5_K_M, Q6_K)

Формат GGUF — де-факто стандарт для локального запуска на CPU и Apple Silicon. llama.cpp использует собственную систему квантования с группировкой.

Тег Описание Бит/параметр 7B размер Качество
Q2_K Экстремальное сжатие ~2.5 17 ГБ Низкое, галлюцинации
Q3_K_M Среднее сжатие ~3.3 24 ГБ Среднее
Q4_0 Базовое 4-бит 4.0 3.5 ГБ Хорошее
Q4_K_M Комбинированное 4-бит ~4.5 3.9 ГБ Очень хорошее
Q5_0 Базовое 5-бит 5.0 4.5 ГБ Отличное
Q5_K_M Комбинированное 5-бит ~5.5 4.8 ГБ Отличное
Q6_K 6-бит 6.1 5.7 ГБ Практически без потерь

Особенность Q4_K_M: смешивает 4-бит и 6-бит квантование. Важные слои (attention, output) остаются в Q6_K, а менее критичные — в Q4. Результат: качество Q5_K_M при размере Q4_K_M.

AWQ (Activation-aware Weight Quantization)

AWQ 2023 года — метод, который учитывает влияние весов на выходные активации. Не все веса одинаково важны: некоторые каналы влияют на качество сильнее других.

Алгоритм AWQ:

  1. Пропустить обучающую выборку через модель в FP16
  2. Измерить чувствительность каждого канала к квантованию
  3. Каналы с высокой чувствительностью оставить в FP16 (или INT8)
  4. Остальные каналы квантовать до INT4

Результат: AWQ-модели часто превосходят GGUF Q4_K_M по качеству при том же размере.

GPTQ (Generative Post-Training Quantization)

GPTQ от Intel (2022) — оптимизация по второму порядку. Использует матрицу Хаара для учёта корреляций между весами.

Преимущества GPTQ:

  • Лучшее качество при 4-битном квантовании
  • Широкая поддержка в ExLlamaV2 и TheBloke моделах
  • Статическое квантование — нет накладных расходов при инференсе

Недостатки:

  • Длительный процесс квантования (часы на GPU)
  • Требует обучающую выборку для калибровки
  • Не поддерживает смешанную точность так гибко, как GGUF

NF4 (Normal Float 4-bit)

NF4 — формат от DeepSpeed/Intel (2024), использующий 4-битные значения, распределённые по нормальному распределению.

Почему NF4 лучше INT4? Потому что веса нейросетей распределены близко к нормальному (гауссову) распределению. NF4 оптимизирует уровни квантования именно под эту распределительную функцию, давая ~0.3-0.5 BLEU преимущество над INT4 при том же количестве бит.

Используется в бинарах llama.cpp начиная с версии 1800+.

Как квантование влияет на качество модели

Метрики: perplexity и downstream задачи

Модель FP16 (baseline) INT4 (AWQ) INT4 (GPTQ) Q4_K_M (GGUF) Q6_K (GGUF)
Llama 3 8B 4.82 4.91 (+0.09) 4.88 (+0.06) 4.95 (+0.13) 4.84 (+0.02)
Mistral 7B 5.12 5.23 (+0.11) 5.18 (+0.06) 5.30 (+0.18) 5.15 (+0.03)
Mixtral 8x7B 4.55 4.67 (+0.12) 4.61 (+0.06) 4.72 (+0.17) 4.57 (+0.02)

Перплексия — не всё. Разница в 0.1 PPL на 7B модели может быть незаметна в чате, но критична для задач вроде генерации кода или перевода.

Тесты на реальных задачах (MMLU benchmark)

Модель FP16 AWQ INT4 GPTQ INT4 Q4_K_M Q6_K
Llama 3 8B 66.8 65.2 (-1.6) 66.0 (-0.8) 64.5 (-2.3) 66.1 (-0.7)
Mistral 7B Instruct 63.4 62.1 (-1.3) 62.8 (-0.6) 61.5 (-1.9) 62.9 (-0.5)

Вывод: Q6_K практически незаметен. AWQ и GPTQ лучше GGUF Q4_K_M. Разница между INT4 и FP16 — 1-2% на MMLU.

Качественные тесты: где квантование бросается в глаза

Генерация кода: квантование до INT4 снижает качество генерации кода на 5-8%. Модель чаще допускает синтаксические ошибки и теряет контекст в длинных функциях.

Многоязычность: для не-английских языков (русский, китайский, арабский) падение качества при INT4 более заметно — до 3-5% по BLEU на переводе.

Математика и логика: задачи на рассуждение ( GSM8K, MATH) теряют 2-4% accuracy при Q4_K_M. INT8 и Q6_K практически не влияют.

Творческие задачи: генерация стихов, историй, маркетинговых текстов — квантование почти не влияет (менее 1% разницы по оценке людей).

Практическое руководство — как квантовать свои модели

Шаг 1: Получение модели

# Скачиваем модель из Hugging Face
huggingface-cli download meta-llama/Llama-3.1-8B-Instruct \
  --local-dir ~/models/llama-3.1-8b

Шаг 2: Квантование в GGUF (для llama.cpp / Ollama)

# Конвертируем в GGUF и квантуем в Q4_K_M
python convert-hf-to-gguf.py ~/models/llama-3.1-8b \
  --outfile llama-3.1-8b-q4_k_m.gguf \
  --outtype f16

# Квантуем
./quantize llama-3.1-8b-q4_k_m.gguf llama-3.1-8b-q4_k_m.gguf Q4_K_M

Или проще через llama.cpp Python API:

from llama_cpp import Llama

llm = Llama(
    model_path="llama-3.1-8b-q4_k_m.gguf",
    n_gpu_layers=35,  # 0 = CPU only, -1 = all layers on GPU
    n_ctx=4096,
    verbose=False
)

output = llm.create_chat_completion(
    messages=[{"role": "user", "content": "Напиши функцию сортировки на Rust"}]
)

Шаг 3: Квантование в AWQ (для autoawq)

# Установка
pip install autoawq xformers

# Квантование
python -m awq.apply_awq \
  --model_path ~/models/llama-3.1-8b \
  --out_path llama-3.1-8b-awq-int4 \
  --q_bits 4 \
  --q_group_size 128

Шаг 4: Квантование в GPTQ (для exllamav2 / auto-gptq)

# Установка
pip install auto-gptq transformers accelerate

# Квантование с калибровкой на 256 примерах
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
from transformers import AutoTokenizer

model = AutoGPTQForCausalLM.from_pretrained("~/models/llama-3.1-8b")
tokenizer = AutoTokenizer.from_pretrained("~/models/llama-3.1-8b")

quantize_config = BaseQuantizeConfig(
    bits=4,
    group_size=128,
    desc_act=False,  # False = True для GPU > RTX 3090
)

model.quantize(dataset, quantize_config)
model.save_pretrained("~/models/llama-3.1-8b-gptq-int4")

Шаг 5: Проверка качества

# Сравнение FP16 vs квантованной на MMLU
from lm_eval import evaluator

# FP16
results_fp16 = evaluator.simple_evaluate(
    model="hf",
    model_args="pretrained=meta-llama/Llama-3.1-8B-Instruct",
    tasks=["mmlu"],
    batch_size=8
)

# Квантованная
results_q4 = evaluator.simple_evaluate(
    model="hf",
    model_args="pretrained=~/models/llama-3.1-8b-awq-int4",
    tasks=["mmlu"],
    batch_size=8
)

print(f"FP16 MMLU: {results_fp16['metrics']['mmlu']['exact_match,all']: .1f}")
print(f"AWQ INT4:  {results_q4['metrics']['mmlu']['exact_match,all']: .1f}")

Выбор формата под железо и сценарий

Решающая матрица: железо → формат

Ваше железо Формат Движок Почему
MacBook M2 (16 ГБ) Q4_K_M GGUF llama.cpp (Metal) Единственный формат, который работает эффективно на Apple Silicon
MacBook M2 (64 ГБ) Q6_K GGUF llama.cpp (Metal) Можно позволить себе Q6 — качество почти FP16
RTX 4060 (8 ГБ) AWQ INT4 или GPTQ INT4 ExLlamaV2 Максимальная скорость на NVIDIA с 4-бит
RTX 4090 (24 ГБ) AWQ INT4 vLLM vLLM отлично работает с AWQ, бэтчирование на высоте
RTX 3090 (24 ГБ) × 2 GPTQ INT4 vLLM (tensor parallel) GPTQ лучше оптимизирован для multi-GPU
Сервер A100 (80 ГБ) FP8 или FP16 TensorRT-LLM Нет смысла квантовать — память есть
Сервер A100 (40 ГБ) × 4 NF4 vLLM (PagedAttention) NF4 позволяет уместить 70B на 4×40 ГБ
Raspberry Pi 5 Q2_K или Q3_K GGUF llama.cpp (CPU) Минимальный размер при максимальном замедлении
Android телефон NF4 MLC LLM (TVM) MLC компилирует NF4 под ARM NEON

Компромиссы: что терять можно, а что нет

Можете терять качество:

  • Генерация описаний товаров
  • Чат-боты с быстрыми ответами
  • Идея-генераторы для маркетинга
  • Выбор: Q4_K_M или даже Q3_K_M

Нельзя терять качество:

  • Юридические консультации
  • Медицинские диагнозы
  • Финансовые рекомендации
  • Выбор: Q6_K или INT8

Продвинутые техники и антипаттерны

Продвинутые техники

Смешанное квантование (Mixed Precision)

Разные слои модели квантуются по-разному:

  • Слои embedding и lm_head — в FP16 (они критичны для качества)
  • Attention слои — в INT8
  • FFN слои — в INT4

Реализуется через llama.cpp с флагом --no-mmap и кастомным скриптом квантования.

KV Cache квантование

KV cache может занимать до 50% памяти при длинном контексте. Квантование KV cache до INT8:

  • Освобождает 50% VRAM для KV cache
  • Позволяет удвоить длину контекста
  • Практически незаметно для качества

vLLM поддерживает: --kv-cache-dtype fp8

Динамическое квантование (Dynamic Quantization)

Квантование происходит на лету при инференсе. Весы хранятся в INT4, деквантование происходит в специальном CUDA ядре.

Преимущество: нет необходимости хранить отдельные FP16 веса. Недостаток: накладные расходы на деквантование — 10-15% slowdown.

Антипаттерны

1. Квантовать без калибровки

Проблема: случайное квантование без калибровочной выборки снижает качество на 10-15% MMLU.

Решение: всегда использовать минимум 128 примеров для калибровки AWQ/GPTQ.

2. Использовать Q2_K для моделей > 13B

Проблема: 2-битное квантование убивает семантику больших моделей. Модель 70B в Q2_K генерирует бессмысленный текст.

Решение: минимум Q3_K_M для моделей > 13B, лучше Q4_K_M.

3. Смешивать форматы в одном проекте

Проблема: GGUF модель в vLLM не загрузится. AWQ модель в Ollama не загрузится.

Решение: выбрать один формат на весь проект. GGUF — для локального, AWQ/GPTQ — для GPU продакшена.

4. Забывать про group_size

Проблема: group_size=64 даёт лучшее качество, но медленнее на NVIDIA. group_size=128 — быстрее, но чуть хуже.

Решение: для NVIDIA использовать group_size=128, для CPU — group_size=64.

5. Квантовать модель, которая уже плоха в FP16

Проблема: квантование не исправляет плохую модель. Если FP16 модель даёт 40% на MMLU, INT4 даст 38%, а не 60%.

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

Заключение: правила квантования в 2026 году

Правило 1: Начните с GGUF Q4_K_M. Это самый универсальный формат, который работает везде.

Правило 2: Если вам нужна максимальная производительность на NVIDIA — выбирайте AWQ INT4 или GPTQ INT4.

Правило 3: Если качество критично — используйте Q6_K или INT8. Разница с FP16 менее 1% на MMLU.

Правило 4: Никогда не квантуйте без калибровки. Используйте минимум 128 примеров из вашей предметной области.

Правило 5: Квантуйте KV cache до FP8 — это бесплатный способ удвоить контекст без потери качества.

Квантование перестало быть компромиссом и стало стандартом. В 2026 году деплой LLM без квантования — это как деплой без HTTPS: технически возможно, но непростительно.