Квантование LLM
GPTQ · AWQ · vLLM

алгоритмы сжатия весов, механизмы инференса и требованиям к видеокартам для запуска языковых моделей

Что такое квантование

Языковые модели хранят параметры в float32 (4 байта) или float16 (2 байта). При 7 миллиардах параметров это 14–28 ГБ VRAM только на веса. Квантование заменяет числа с плавающей точкой целыми числами меньшей разрядности — int8 или int4.

🎯

Цель

Уменьшить объём памяти, занимаемый весами модели, без значительной потери качества ответов.

⚙️

Механизм

Числа FP16 (диапазон ≈ −65k…+65k) маппируются в INT4 (0..15) через масштабирующий коэффициент и нулевую точку.

📐

Типы

Post-Training Quantization (PTQ) — без дообучения. Quantization-Aware Training (QAT) — квантование в процессе обучения.

🧮

Форматы

W4A16 — веса int4, активации fp16. W8A8 — оба в int8. W4A8 — смешанный. GPTQ и AWQ используют W4A16.

Сколько памяти занимает модель?

Примерный расчёт: количество параметров × байт на параметр + overhead KV-кэша.

VRAM_weights ≈ N_params × bytes_per_param Пример: 7B × 2 байта (FP16) = 14 ГБ  |  7B × 0.5 байта (INT4) = 3.5 ГБ
⚠️
VRAM ≠ только веса. К весам добавляется KV-кэш (растёт с длиной контекста), активации при форвард-пассе и overhead фреймворка. Реальное потребление на 15–30% выше расчётного по весам.

GPTQ — Post-Training Quantization

Generative Pre-Trained Transformer Quantization. Опубликован в 2022 году (Frantar et al., ETH Zurich). Использует информацию о кривизне функции потерь (гессиан) для компенсации ошибок квантования слой за слоем.

Математическая основа

GPTQ решает задачу послойного сжатия: для каждого линейного слоя L найти квантованные веса Ŵ, минимизирующие ошибку на выходах слоя.

argmin_Ŵ ‖WX − ŴX‖²_F W — исходные веса, X — входные активации с калибровочного набора данных, F — норма Фробениуса
GPTQ — алгоритм OBQ + оптимизации
  • Калибровочный набор данных Прогоняют небольшое число токенов (обычно 128–1024) через модель в float16, чтобы получить реальные активации X для каждого слоя.
  • Вычисление обратного гессиана H⁻¹ Для каждого слоя вычисляется H = 2 X Xᵀ — матрица, описывающая чувствительность ошибки к изменению каждого веса. Вычисляется и кешируется H⁻¹ (псевдообратная матрица по методу Чолесского).
  • Последовательное квантование столбцов Веса квантуются столбец за столбцом. После квантования каждого столбца оставшиеся веса корректируются с использованием H⁻¹, чтобы компенсировать внесённую ошибку.
  • Lazy batch updates Для ускорения веса обновляются не по одному, а группами по 128 столбцов (block quantization). Это позволяет эффективно использовать матричные операции GPU.
  • Cholesky reformulation Авторы переформулируют задачу через разложение Чолесского, что позволяет вычислить H⁻¹ быстро и численно стабильно. В итоге 175B GPT-3 квантуется за ~4 часа на одном A100.

Практическое использование (AutoGPTQ / transformers)

Quantize model with AutoGPTQ python
from transformers import AutoTokenizer
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

# 1. Загрузить модель и токенизатор
model_id = "meta-llama/Llama-2-7b-hf"
tokenizer = AutoTokenizer.from_pretrained(model_id)

# 2. Конфиг квантования
quantize_config = BaseQuantizeConfig(
    bits=4,           # INT4 — оптимальный баланс
    group_size=128,  # размер группы весов (128 стандарт)
    desc_act=False,  # desc_act=True даёт лучшее качество, но медленнее
)

# 3. Загрузить модель для квантования
model = AutoGPTQForCausalLM.from_pretrained(model_id, quantize_config)

# 4. Калибровочные данные (128 примеров достаточно)
examples = [tokenizer("Hello, my name is", return_tensors="pt")]

# 5. Квантовать (занимает 5–60 минут в зависимости от модели)
model.quantize(examples)

# 6. Сохранить
model.save_quantized("./llama2-7b-gptq-4bit", use_safetensors=True)
Load quantized GPTQ model for inference python
from transformers import AutoTokenizer, AutoModelForCausalLM

# Transformers >= 4.40 поддерживает GPTQ нативно
tokenizer = AutoTokenizer.from_pretrained("./llama2-7b-gptq-4bit")
model = AutoModelForCausalLM.from_pretrained(
    "./llama2-7b-gptq-4bit",
    device_map="auto",
    torch_dtype="auto"
)

inputs = tokenizer("Расскажи о квантовании весов:", return_tensors="pt").to("cuda")
output = model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(output[0], skip_special_tokens=True))
ℹ️
Параметр group_size: определяет, сколько весов делят один масштабирующий коэффициент. Меньший group_size (64 или 32) даёт лучшее качество, но увеличивает объём квантованной модели. Стандарт — 128. При group_size=−1 используется один коэффициент на весь слой (максимальное сжатие, наибольшие потери).

AWQ — Activation-Aware Weight Quantization

Опубликован MIT Han Lab в июне 2023, получил Best Paper Award на MLSys 2024. Ключевая идея: не все веса одинаково важны — 1% «салиентных» весов критичен для качества, и их нужно защитить от квантования.

Фундаментальное наблюдение

Авторы обнаружили: если отсортировать веса по величине соответствующих активаций, примерно 1% весов имеют аномально высокие активации. Квантование этих весов вызывает непропорционально большой рост perplexity.

Importance(w_i) ≈ |w_i| × mean(|x_i|) w_i — вес, x_i — активации, соответствующие этому весу на калибровочных данных
AWQ — алгоритм масштабирования
  • Сбор активационной статистики Прогоняют небольшой калибровочный набор (128–1024 токенов). Для каждого нейрона записывается среднее абсолютное значение активации mean(|x_i|). Этот шаг лёгкий — не нужен полный гессиан как в GPTQ.
  • Поиск оптимального масштабирующего вектора s AWQ ищет вектор масштабов s для каждого канала входа. Перед квантованием вес умножается на s, а активации делятся на s. Это перераспределяет диапазон значений в пользу важных весов. Поиск s выполняется grid-поиском или градиентной оптимизацией.
  • Эквивалентное преобразование y = (W·diag(s)) · (diag(s)⁻¹·x). Первый множитель — масштабированные веса (их квантуют). Второй — компенсируется в предыдущем слое (LayerNorm или Linear). Итог: веса квантованы, но информация о важных каналах сохранена в масштабе.
  • Квантование масштабированных весов После нахождения s веса W·diag(s) квантуются в INT4 простым round-to-nearest — без необходимости вычислять гессиан. Это делает AWQ значительно быстрее GPTQ по времени квантования.

Практическое использование (AutoAWQ)

Quantize model with AutoAWQ python
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model_path = "meta-llama/Llama-2-7b-hf"
quant_path = "./llama2-7b-awq-4bit"

# Конфиг квантования AWQ
quant_config = {
    "zero_point": True,   # ассиметричное квантование
    "q_group_size": 128,  # стандартный размер группы
    "w_bit": 4,            # 4-битные веса
    "version": "GEMM"      # GEMM (batch) или GEMV (single token)
}

# Загрузить модель
model = AutoAWQForCausalLM.from_pretrained(model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)

# Квантовать (быстрее GPTQ — нет вычисления гессиана)
model.quantize(tokenizer, quant_config=quant_config)

# Сохранить
model.save_quantized(quant_path)
tokenizer.save_pretrained(quant_path)
💡
GEMM vs GEMV: Версия GEMM оптимизирована для батч-инференса (несколько запросов одновременно). GEMV — для одного токена за раз (streaming). Для продакшн-серверов используйте GEMM, для локального запуска — GEMV.

GPTQ vs AWQ vs GGUF

Три наиболее распространённых подхода к квантованию. Правильный выбор зависит от задачи: серверный инференс, локальный запуск или edge-устройства.

🔵

GPTQ

  • МетодSecond-order (Hessian)
  • Скорость квантованияМедленно
  • Качество при 4-bitХорошее
  • Поддержка vLLM✓ Да
  • Поддержка CUDA✓ Нативная
  • Поддержка CPU✗ Нет
  • Размер модели~5.99 ГБ (7B)
  • Лучшее применениеGPU-серверы, vLLM
🟣

AWQ

  • МетодActivation-aware scaling
  • Скорость квантованияБыстро
  • Качество при 4-bitОтличное
  • Поддержка vLLM✓ Да
  • Поддержка CUDA✓ Нативная
  • Поддержка CPU✗ Нет
  • Размер модели~5.7 ГБ (7B)
  • Лучшее применениеGPU-серверы, edge

Сводная таблица методов

Метод Разрядность Алгоритм Скорость инфер. Потеря качества Где работает Типичный размер 7B
FP16 (base) 16 bit — Baseline Нет CUDA / Metal ~14 ГБ
GPTQ 2–8 bit OBQ + Hessian +15–30% Небольшая GPU (CUDA) ~3.5–6 ГБ
AWQ 4 bit Activation scaling +20–40% Минимальная GPU (CUDA) ~3.5–5.7 ГБ
GGUF Q4_K_M 4 bit K-quant блоки Зависит от CPU Минимальная CPU + GPU (offload) ~4.4 ГБ
bitsandbytes NF4 4 bit Normal float + DQ Медленнее FP16 Небольшая GPU (CUDA) ~4–5 ГБ
FP8 (W8A8) 8 bit Native hardware +50–80% H100 Минимальная H100 / H200 / A100 ~7 ГБ
ℹ️
AWQ vs GPTQ на практике (2024–2026): AWQ, как правило, даёт немного лучшее качество при той же разрядности, потому что защищает наиболее важные веса. GPTQ более гибкий (поддерживает 2–8 бит), AWQ ограничен 4 битами. Для серверного деплоя через vLLM оба хорошо поддерживаются.

vLLM — High-Throughput LLM Serving

Open-source фреймворк для серверного инференса LLM. Разработан в UC Berkeley Sky Computing Lab, впервые представлен в сентябре 2023 на конференции SOSP. Решает две проблемы: фрагментацию памяти KV-кэша и недоиспользование GPU при статическом батчинге.

24×
больше throughput vs HF Transformers
<4%
потерь памяти KV-кэша
10k+
публичных MCP-серверов с поддержкой
70%
снижение задержки у Salesforce (продакшн)

Проблема: KV-кэш и фрагментация памяти

При авторегрессивной генерации модель предсказывает токены по одному. Чтобы не пересчитывать attention для всех предыдущих токенов, их Key/Value тензоры кешируются в GPU памяти. Проблемы традиционного подхода:

❌

Internal fragmentation

Память выделялась заранее под максимальную длину последовательности. Запрос на 50 токенов занимал память как 2048 — большая её часть тратилась впустую.

❌

External fragmentation

После завершения запросов в GPU памяти оставались «дыры» разного размера, которые не использовались новыми запросами.

❌

Static batching

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

PagedAttention & Continuous Batching

Два механизма, которые делают vLLM эффективным. PagedAttention заимствует идею виртуальной памяти из операционных систем. Continuous batching решает проблему простоя GPU.

PagedAttention: виртуальная память для KV-кэша

// Архитектура PagedAttention
Request A
500 токенов
→
Logical block table
A: [0,1,2,5,8]
→
Physical blocks
GPU memory
Request B
100 токенов
→
Logical block table
B: [3,4]
→
Shared blocks
(prefix caching)
PagedAttention — принцип работы
  • Разбивка KV-кэша на страницы (blocks) Весь GPU-пул KV-памяти делится на физические блоки фиксированного размера — по умолчанию 16 токенов на блок (параметр --block-size). Блоки не обязаны быть непрерывными в физической памяти.
  • Логическая таблица блоков на запрос Каждая последовательность имеет логическую таблицу блоков — индекс физических блоков, где хранятся её K и V тензоры. Аналог page table в ОС.
  • Динамическое выделение памяти Память выделяется по мере генерации токенов — только когда нужен новый блок. Нет предварительного резервирования под max_length. Потери памяти ограничены <4% (только последний неполный блок).
  • Copy-on-Write для beam search При beam search несколько лучей могут делить одни и те же блоки KV-кэша (если начало последовательности одинаковое). Блок копируется только при расхождении лучей — prefix sharing из коробки.

Continuous Batching: итерационное планирование

Iteration-level scheduler
  • Три очереди планировщика waiting (новые запросы, ждут prefill) → running (активно генерируют токены) → swapped (вытесненные в CPU память при нехватке GPU). После каждого forward-прохода планировщик переоценивает все три очереди.
  • Немедленное освобождение завершённых запросов Как только запрос генерирует EOS-токен, его физические блоки немедленно возвращаются в пул свободной памяти. GPU не простаивает, ожидая других.
  • Preemption при нехватке памяти Если для нового блока нет места, планировщик может вытеснить (swap) менее приоритетные запросы на CPU через PCIe. При освобождении места они возвращаются обратно.
  • Chunked Prefill Длинные промпты (prefill) нарезаются на чанки и обрабатываются совместно с текущими decode-запросами. Это снижает задержку первого токена (TTFT) без просадки throughput.

Дополнительные механизмы vLLM

⚡

Speculative Decoding

Небольшая draft-модель генерирует несколько токенов, основная — проверяет их за один проход. Ускоряет генерацию при малой нагрузке.

🔧

CUDA Graphs

Записывает последовательность CUDA операций в граф и воспроизводит его без CPU-overhead. Снижает задержку при маленьких батчах.

💾

Prefix Caching

Одинаковые системные промпты (system prompt) кешируются между запросами. При повторном запросе с тем же началом prefill не пересчитывается.

🌐

Tensor Parallelism

Автоматически распределяет модель по нескольким GPU через параметр --tensor-parallel-size. Веса каждого слоя делятся между картами.

Запуск vLLM

Установка и запуск vLLM сервера bash
# Установка (требует CUDA 12.1+, Python 3.9–3.12)
pip install vllm

# Запуск OpenAI-совместимого API сервера
vllm serve meta-llama/Llama-3-8B-Instruct \
    --dtype auto \
    --api-key token-123

# С квантованием AWQ
vllm serve TheBloke/Llama-2-7B-Chat-AWQ \
    --quantization awq \
    --dtype half

# С квантованием GPTQ
vllm serve TheBloke/Llama-2-13B-chat-GPTQ \
    --quantization gptq \
    --dtype half \
    --max-model-len 4096

# Мультигпу: 2 карты через tensor parallelism
vllm serve meta-llama/Llama-2-70b-hf \
    --tensor-parallel-size 2 \
    --dtype auto
Запрос к vLLM через OpenAI API python
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="token-123",
)

response = client.chat.completions.create(
    model="meta-llama/Llama-3-8B-Instruct",
    messages=[{"role": "user", "content": "Объясни квантование LLM"}],
    max_tokens=512,
    temperature=0.7,
)
print(response.choices[0].message.content)

Какая видеокарта нужна для LLM

Два ключевых параметра: объём VRAM (определяет, какую модель можно загрузить) и пропускная способность памяти в ГБ/с (определяет скорость генерации токенов). VRAM определяет потолок, пропускная способность — реальную скорость.

⚠️
Правило 2 байта на параметр (FP16): 7B модель = ~14 ГБ, 13B = ~26 ГБ, 70B = ~140 ГБ. При INT4 — примерно вдвое меньше. К этому добавляется KV-кэш: при длине контекста 4096 токенов для Llama-2-7B — ещё ~1.5 ГБ, для 70B — ~6–8 ГБ.

Характеристики основных видеокарт

GPU VRAM Пропускная способность FP16 TFLOPS Тип памяти Категория Цена (ориент.)
RTX 3060
12 GB
360 GB/s 12.7 GDDR6 Бюджетная ~$280
RTX 3090
24 GB
936 GB/s 35.6 GDDR6X Consumer ~$700–900 (б/у)
RTX 4070 Ti Super
16 GB
672 GB/s 40.0 GDDR6X Consumer ~$800
RTX 4090
24 GB
1,008 GB/s 82.6 GDDR6X Consumer High-End ~$1,600
RTX 5090
32 GB
1,792 GB/s ~209 GDDR7 Consumer Flagship ~$2,000
RTX A6000 Ada
48 GB
960 GB/s 91.1 GDDR6 Workstation ~$5,000
L40S
48 GB
864 GB/s 91.6 GDDR6 Datacenter ~$7,000–9,000
A100 40GB
40 GB
1,555 GB/s 77.0 HBM2e Enterprise ~$10,000–14,000
A100 80GB
80 GB
1,935 GB/s 77.0 HBM2e Enterprise ~$15,000–20,000
H100 SXM
80 GB
3,350 GB/s ~400 (FP8: 3958) HBM3 Enterprise ~$30,000–40,000
H200
141 GB
4,800 GB/s ~400 (FP8: 3958) HBM3e Enterprise Flagship ~$80,000+

Соответствие моделей и GPU (2026)

Модель Параметры FP16 (без сжатия) INT8 / Q8 INT4 / Q4 (AWQ/GPTQ) Рекомендации GPU
Phi-3 Mini, Gemma 2B, Qwen 1.5 1.8B 1.8–3B ~4–6 ГБ ~2–3 ГБ ~1–2 ГБ RTX 3060 12GB и выше, GTX 1080 Ti
Llama 3.2 3B, Phi-3 Small 3–4B ~6–8 ГБ ~4–5 ГБ ~2–3 ГБ RTX 3060 12GB комфортно
Llama 3 8B, Mistral 7B, Qwen2 7B 7–8B ~14–16 ГБ ~8–9 ГБ ~4–5 ГБ RTX 4070 Ti 16GB (FP16), RTX 3060 12GB (INT4)
Llama 3.1 8B (32K контекст) 8B ~18–20 ГБ ~12 ГБ ~6–7 ГБ RTX 4090 24GB (FP16), RTX 3060 12GB (INT4)
Phi-3 Medium 14B, Qwen2 14B 13–14B ~26–28 ГБ ~14 ГБ ~8–9 ГБ RTX 4090 24GB (INT8), RTX 3060 12GB (INT4, тесно)
Qwen 3 32B, DeepSeek-R1 32B 32B ~64 ГБ ~32 ГБ ~18–20 ГБ L40S 48GB / 2×RTX 4090 (INT4), A100 80GB (FP16)
Llama 3.1 70B, Qwen2 72B 70–72B ~140 ГБ ~70 ГБ ~35–40 ГБ 2×L40S / A100 80GB (INT4), 2×A100 80GB (FP16)
Llama 4 Scout (109B MoE, 17B active) 109B total ~218 ГБ — ~55 ГБ H100 80GB (INT4), 4×A100 80GB (FP16)
DeepSeek V3 / R1 (671B MoE) 671B total, 37B active >700 ГБ ~335 ГБ ~335 ГБ (FP8) 8×H200 141GB минимум
Llama 3.1 405B 405B ~810 ГБ ~405 ГБ ~200 ГБ 4×H200 / 8×H100 (INT4)
💡
MoE-модели (DeepSeek, Llama 4 Scout): у них большое общее число параметров, но в каждый forward-проход активируется только часть (Active Parameters). Для инференса важно уметить в VRAM именно все веса модели, даже если активных параметров меньше — роутер всё равно должен загрузить все экспертные веса.

Скорость генерации: tokens/sec по GPU

GPU Llama 3 8B (FP16) Llama 3 8B (INT4 AWQ) Llama 2 13B (INT4) Llama 2 70B (INT4, multi-GPU)
RTX 3060 12GB — (не влезает) ~20–30 tok/s — (не влезает) —
RTX 4070 Ti 16GB ~40–55 tok/s ~60–80 tok/s ~35–45 tok/s —
RTX 4090 24GB ~80–120 tok/s ~140–180 tok/s ~40–50 tok/s ~15–25 tok/s (offload)
2× RTX 4090 48GB ~140–200 tok/s ~220–280 tok/s ~90–120 tok/s ~35–45 tok/s
A100 80GB ~200–280 tok/s ~280–350 tok/s ~150–200 tok/s ~30–40 tok/s (1 GPU, INT4)
H100 SXM 80GB ~400–600 tok/s ~600–800 tok/s ~300–450 tok/s ~80–120 tok/s (1 GPU, INT4)
H200 141GB ~500–700 tok/s ~700–900 tok/s ~400–550 tok/s ~150–200 tok/s (1 GPU)
ℹ️
Важно: цифры — ориентировочные для single-request инференса. При batched serving (несколько запросов одновременно через vLLM) throughput растёт, но latency на запрос увеличивается. Реальные цифры зависят от длины контекста, batch size, фреймворка и конкретной модели.

Системная RAM и хранилище

Модель Системная RAM (минимум) Рекомендованная RAM Место на диске (FP16) Место на диске (INT4)
7–8B 16 ГБ 32 ГБ ~14–16 ГБ ~4–5 ГБ
13–14B 32 ГБ 64 ГБ ~26–28 ГБ ~8–9 ГБ
32–34B 64 ГБ 128 ГБ ~64–68 ГБ ~18–22 ГБ
70B 64 ГБ 128 ГБ ~140 ГБ ~35–40 ГБ

Системная RAM нужна для загрузки файлов модели перед переносом на GPU, CPU-offload слоёв, и работы ОС. NVMe SSD обязателен — загрузка 70B модели с HDD займёт 10+ минут, с NVMe — 1–2 минуты.

Установка и запуск: пошагово

Вариант 1: vLLM + AWQ модель (GPU-сервер)

Полный стек: vLLM + квантованная модель bash
# Требования: NVIDIA GPU CUDA 12.1+, Python 3.10+

# 1. Установить vLLM
pip install vllm

# 2. Запустить с AWQ моделью (Llama 3 8B AWQ, ~5GB VRAM)
vllm serve solidrust/Meta-Llama-3-8B-Instruct-hf-AWQ \
    --quantization awq \
    --dtype half \
    --max-model-len 8192 \
    --port 8000

# 3. Тест
curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "solidrust/Meta-Llama-3-8B-Instruct-hf-AWQ",
        "messages": [{"role": "user", "content": "Hello!"}]
    }'

Вариант 2: llama.cpp + GGUF (CPU / гибридный режим)

llama.cpp для CPU или частичного GPU offload bash
# Сборка с поддержкой CUDA
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j

# Скачать GGUF модель с HuggingFace
# Пример: Llama-3.2-3B-Instruct Q4_K_M (~2GB)
wget https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_K_M.gguf

# Запуск с GPU offload (ngl = number of GPU layers)
./build/bin/llama-cli \
    -m Llama-3.2-3B-Instruct-Q4_K_M.gguf \
    -ngl 33 \
    -p "Объясни что такое квантование:"

Выбор формата по задаче

🖥️

Локальный запуск (одна карта)

Используйте GGUF через Ollama или llama.cpp. Простейшая установка, поддержка CPU offload, хорошее качество при Q4_K_M.

🚀

Серверный инференс (GPU)

vLLM с AWQ или GPTQ моделями. Высокий throughput, поддержка батчинга, OpenAI-совместимый API, tensor parallelism.

🍎

Apple Silicon

llama.cpp с Metal backend или Ollama. Unified memory позволяет запускать большие модели — M4 Max 128GB вмещает Llama 3 70B Q4.

☁️

Облако (A100/H100)

vLLM + FP8 (H100) или AWQ/GPTQ (A100). Для 70B и больше — обязательно multi-GPU с tensor parallelism.

💡
Итоговое правило: если у вас одна потребительская карта до 24 ГБ — GGUF Q4_K_M через Ollama/llama.cpp для простоты, или AWQ через vLLM для максимальной скорости на CUDA. Для продакшн-сервера с несколькими пользователями — vLLM с AWQ или FP8 (на H100) даст наилучший throughput на доллар.