Перейти к содержанию

Квантизация LLM

~9 минут чтения

Предварительно: базовые понятия о нейросетях, инференсе LLM


Зачем это нужно

Llama 3.1 70B в FP16 занимает 140 GB -- не влезает даже на 2x A100 (80 GB). Квантизация до INT4 сжимает до 35 GB -- запускается на одном GPU. Качество при этом падает на 1-3% по бенчмаркам.

Аналогия: представьте фотографию 50 мегапикселей. Для Instagram достаточно 2 мегапикселей -- визуально разницу не увидите, но файл в 25 раз меньше. Квантизация делает то же самое с весами: снижает "разрешение" чисел (FP16 -> INT4), сохраняя смысл.

Ключевой вопрос: какие веса можно округлить безболезненно, а какие -- нет. AWQ и GPTQ отвечают на него по-разному.


Обзор

Квантизация -- снижение точности весов модели для уменьшения памяти и ускорения инференса.

\[ \text{Memory} = \text{Params} \times \text{Bytes per weight} \]
Precision Bytes/param 7B model 70B model
FP32 4 28 GB 280 GB
FP16/BF16 2 14 GB 140 GB
INT8 1 7 GB 70 GB
INT4 0.5 3.5 GB 35 GB

Comparison Table (2026)

Method Primary Hardware Quantization Memory Reduction Throughput
GGUF CPU, Apple M-series 4-bit 40-50% 35-45 tok/s
GPTQ GPU (NVIDIA/AMD) 8/4/3/2-bit 40-50% 50-60 tok/s
AWQ GPU, Edge 4-bit, FP8 40-50% 45-55 tok/s
Marlin GPU (kernel) - - 2-10× faster
FP8 H100/MI300X 8-bit 50% Near-FP16

1. Baseline Quantization

Symmetric Quantization

\[ \text{scale} = \frac{\max(|W|)}{2^{b-1} - 1}, \quad \text{zero\_point} = 0 \]
\[ W_q = \text{round}(W / \text{scale}) \]

Symmetric pitfall

Если веса не центрированы вокруг нуля — тратится битовый диапазон.

Asymmetric Quantization

\[ \text{scale} = \frac{\max(W) - \min(W)}{2^b - 1} \]
\[ \text{zero\_point} = \text{round}(-\min(W) / \text{scale}) \]
\[ W_q = \text{round}(W / \text{scale}) + \text{zero\_point} \]

Advantage: Использует полный битовый диапазон.

Limitation: Оба метода treat все веса одинаково, но некоторые важнее других.


2. AWQ (Activation-Aware Weight Quantization)

Paper: Lin et al., MLSys 2024 — arXiv:2306.00978

Core Insight

\[ Y = W \times X \]

Если \(X\) (activation) большой — ошибка в \(W\) усиливается.

Key Insight

Защитить "salient" веса через масштабирование — не все веса одинаково важны.

Finding Salient Weights

# Activation magnitudes per input channel
s_x = mean(|X|, dim=0)  # shape: (in_features,)

Каналы с высоким \(s_x\) — важные, ошибки в их весах больше влияют на output.

Per-Channel Scaling

\[ Q(W \times s) \times (X / s) \approx W \times X \]

Где \(s = s_x^\alpha\) — per-channel scaling factor.

Alpha (α) parameter: - α = 0: Без scaling = baseline quantization - α = 1: Maximum protection - 0 < α < 1: Balance (оптимален ~0.5)

Optimization Problem

\[ s^* = \arg\min_\alpha \|Q(W \times \text{diag}(s_x^\alpha)) \times (X / s_x^\alpha) - W \times X\|^2 \]

AWQ Process

  1. Calibration: Run 128-512 samples → collect activation stats
  2. Search: Find optimal α per layer
  3. Scale: Multiply weights by \(s = s_x^\alpha\)
  4. Quantize: Asymmetric group-wise quantization
  5. Store: Quantized weights + scaling factors

3. GPTQ (General Post-Training Quantization)

Paper: Frantar et al., arXiv:2210.17323

Core Insight

Quantize weights one at a time, adjust remaining weights to compensate error.

Uses Hessian matrix for second-order information.

Hessian Matrix

For squared error loss: $$ H = 2 \times X \times X^T $$

  • Diagonal H[i][i]: Sensitivity of output to weight column i
  • Off-diagonal H[i][j]: How weight columns i and j interact

Error Compensation

After quantizing weight at column \(q\) with error \(\delta_q\):

\[ w_i \leftarrow w_i - \frac{\delta_q}{H[q][q]} \times H[q][i] \]

Column-wise Quantization

Key: Quantize columns left-to-right, adjust only unquantized columns.

Quantization grid (scale, zero-point): Calculated row-wise or group-wise Actual quantization: Column-by-column with error compensation

Lazy Batching

  1. Quantize batch of B columns (typically 128)
  2. Accumulate update terms
  3. Apply all updates at once

Reduces memory operations by factor of B.

GPTQ Process

  1. Calibration: Run 128-1024 samples → compute Hessian
  2. Cholesky: Decompose H for numerical stability
  3. Grid calculation: Per-row or per-group scale/zero-point
  4. Column-wise quantization: Process in batches with error compensation
  5. Store: Quantized weights + scales + zero-points

4. GGUF (GPT-Generated Unified Format)

Developer: llama.cpp team (Georgi Gerganov)

Purpose

CPU + Apple M-series optimized format with GPU offload support.

File Format

GGUF File Structure:
├── Header (magic, version, tensor count)
├── Metadata (key-value pairs)
├── Tensor Info (names, types, dimensions)
└── Tensor Data (quantized weights)

Quantization Types

Type Bits/weight Quality Speed
Q4_0 4.0 Low Fast
Q4_K_M ~4.5 Good Fast
Q5_K_M ~5.5 Better Medium
Q6_K 6.0 High Slower
Q8_0 8.0 Best Slowest

When to Use GGUF

  • CPU inference
  • Apple M-series (Metal support)
  • Mobile / Edge devices
  • Limited GPU memory
  • Cross-platform compatibility

Usage Example

# Convert to GGUF
python convert-hf-to-gguf.py /path/to/model --outfile model-f16.gguf --outtype f16

# Quantize
./llama-quantize model-f16.gguf model-q4_k_m.gguf Q4_K_M

# Run
./llama-cli -m model-q4_k_m.gguf -p "Hello" -n 128

5. Marlin Kernel

Paper: Frantar et al., PPoPP 2025 — arXiv:2408.11743

Not a quantization method — optimized CUDA kernel for running quantized models.

Speedup

Method Standard With Marlin Speedup
GPTQ 276 tok/s 712 tok/s 2.6×
AWQ 68 tok/s 741 tok/s 10.9×

Key Optimizations

  1. Async-Copy (Bypass L1): DRAM → L2 → SMEM directly
  2. L2 Cache Optimization: 80-95% hit rate vs 30-50%
  3. Double Buffering: Load tile B while computing tile A
  4. Fused Dequantization: Dequantize + compute in same kernel
  5. Warp-Level Parallelism: Coalesced memory access

6. FP8 Quantization (2025-2026)

Format

E4M3: 1 sign + 4 exponent + 3 mantissa (for activations) E5M2: 1 sign + 5 exponent + 2 mantissa (for gradients)

Hardware Support

  • NVIDIA H100/H200 (native FP8 tensor cores)
  • AMD Instinct MI300X
  • Intel Gaudi2

Training with FP8

Papers (Jan 2026): - "FP8-RL: Practical Low-Precision Stack for LLM RL" — arXiv:2601.18150 - "Jet-RL: On-Policy FP8 Reinforcement Learning" — arXiv:2601.14243 - "MOSS: Efficient FP8 LLM Training" — OpenReview Dec 2025

Benefits

  • 2× memory reduction vs FP16
  • Near-FP16 quality
  • Faster training on H100

Challenges

  • Train-inference mismatch
  • Numerical stability
  • Requires careful scaling

7. HeRo-Q (Jan 2026)

Paper: arXiv:2601.21626

Hessian-based stable low-bit quantization. Outperforms GPTQ, AWQ, SpinQuant on Llama and Qwen models. Better numerical stability via Hessian analysis. Best for ultra low-bit (2-3 bit) quantization.


8. BitsandBytes (NF4)

Developer: Tim Dettmers

Key Feature

On-the-fly quantization during model loading — no pre-quantized files needed.

NF4 vs FP4

NF4 (NormalFloat4): Optimized for Gaussian-distributed weights - More levels near zero (where most weights are) - Less error for neural networks

FP4 (FloatingPoint4): Standard floating point - Uniformly spaced in log scale - General purpose

Double Quantization

Quantize the quantization constants (absmax values) for extra compression.

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)

9. Benchmark Results (Qwen2.5-32B on H200)

Perplexity (Wikitext-2)

Method Perplexity vs FP16
FP16 9.42 Baseline
AWQ-4bit 9.58 +1.7%
GPTQ-4bit 9.61 +2.0%
GGUF-Q4_K_M 9.72 +3.2%
bnb-NF4 9.68 +2.8%

HumanEval Pass@1

Method Score vs FP16
FP16 51.2% Baseline
AWQ-4bit 49.8% -1.4%
GPTQ-4bit 50.1% -1.1%
Marlin-GPTQ 50.1% -1.1%

Inference Speed (ShareGPT)

Method Throughput Latency (TTFT)
FP16 52 tok/s 1.8s
GPTQ 276 tok/s 0.9s
AWQ 68 tok/s 1.2s
Marlin-GPTQ 712 tok/s 0.4s
Marlin-AWQ 741 tok/s 0.4s
GGUF (GPU) 180 tok/s 0.6s

10. Decision Framework

By Hardware

graph TD
    START{"Hardware?"} -->|"CPU / Apple M"| GGUF["GGUF"]
    START -->|"GPU"| GPU{"GPU tier?"}
    GPU -->|"High-end (H100/H200)"| HI["GPTQ + Marlin or FP8"]
    GPU -->|"Consumer GPU"| CON["AWQ or GPTQ"]
    style GGUF fill:#e8f5e9,stroke:#4caf50
    style HI fill:#e8eaf6,stroke:#3f51b5
    style CON fill:#fff3e0,stroke:#ef6c00

By Use Case

Use Case Recommended
Production inference GPTQ + Marlin
Edge/Mobile GGUF or AWQ
Instruction-tuned models AWQ
Maximum quality GPTQ (4-bit) or FP8
Quick deployment BitsandBytes (load_in_4bit)
Apple Silicon GGUF

By Priority

Priority Method
Quality GPTQ > AWQ > GGUF
Speed Marlin > GPTQ > AWQ > GGUF
Memory All 4-bit similar (~4× reduction)
Ease of use bnb > GGUF > AWQ > GPTQ

11. Code Examples

GPTQ Quantization

from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

# Quantization config
quantization_config = GPTQConfig(
    bits=4,
    dataset="c4",
    group_size=128,
    desc_act=False,
)

# Load and quantize
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B",
    quantization_config=quantization_config,
    device_map="auto",
)

AWQ Quantization

from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model = AutoAWQForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")

# Quantize
model.quantize(
    tokenizer,
    quant_config={
        "zero_point": True,
        "q_group_size": 128,
        "w_bit": 4,
    }
)

model.save_quantized("./llama-3.1-8b-awq")

vLLM with Quantization

from vllm import LLM

# Load pre-quantized AWQ model
llm = LLM(
    model="hugging-quants/Meta-Llama-3.1-8B-AWQ-INT4",
    quantization="awq",
    dtype="float16",
)

# Or GPTQ
llm = LLM(
    model="hugging-quants/Meta-Llama-3.1-8B-GPTQ-INT4",
    quantization="gptq",
    dtype="float16",
)

GGUF with llama.cpp

from llama_cpp import Llama

llm = Llama(
    model_path="./models/llama-3.1-8b-q4_k_m.gguf",
    n_ctx=4096,
    n_gpu_layers=35,  # Offload to GPU
)

output = llm("Q: Hello? A:", max_tokens=128)

Для интервью

Q: "Что такое квантизация и зачем она нужна для LLM?"

✅ Strong: "Квантизация снижает точность весов (FP16 -> INT4/INT8). Для 7B модели: FP16 = 14 GB, INT4 = 3.5 GB -- 4x экономия памяти. Два подхода: post-training quantization (PTQ) без дообучения и quantization-aware training (QAT) с дообучением. PTQ проще, QAT точнее. Основные методы: GPTQ (Hessian-based error compensation), AWQ (activation-aware scaling), GGUF (CPU-optimized format)."

❌ Red flag: "Квантизация делает модель меньше" (не объясняет как и какой ценой).

Q: "AWQ vs GPTQ -- в чем принципиальная разница?"

✅ Strong: "GPTQ -- second-order: квантизует веса по одному, компенсируя ошибку через Hessian (\(w_i \leftarrow w_i - \frac{\delta_q}{H[q][q]} \times H[q][i]\)). AWQ -- activation-aware: не все веса одинаково важны, защищает 'salient' веса через scaling (\(S_{ij} = |W_{ij}| \cdot \|X_j\|_2\)). GPTQ чуть точнее (perplexity +2.0% vs +1.7% для AWQ на Qwen2.5-32B), AWQ лучше для instruction-tuned моделей и проще в deployment."

❌ Red flag: "GPTQ лучше потому что использует Hessian" (AWQ сравнима по качеству и часто лучше для chat моделей).

Q: "Как задеплоить 70B модель на 24GB GPU?"

✅ Strong: "70B в FP16 = 140 GB. INT4 = 35 GB -- все еще > 24 GB. Варианты: (1) GPTQ 3-bit + Marlin kernel (24-28 GB, quality drop ~5%), (2) GGUF Q4_K_M с GPU offload (часть слоев на CPU), (3) tensor parallelism на 2x 24GB GPU в INT4. Оптимально: AWQ INT4 + 2 GPU + Marlin kernel = ~18 GB per GPU, throughput 700+ tok/s."

❌ Red flag: "Просто квантизовать в INT4 и загрузить" (не влезет -- 35 GB > 24 GB).

Q: "NF4 vs FP4 -- почему NF4 лучше для нейросетей?"

✅ Strong: "Веса нейросетей распределены по Гауссу -- больше значений около нуля, мало на краях. NF4 (NormalFloat4) оптимизирует уровни квантизации под это распределение: больше уровней около нуля, меньше на краях. FP4 распределяет уровни равномерно в log-scale. Результат: NF4 дает меньшую ошибку квантизации для типичных весов. Double quantization (квантизация absmax значений) дает дополнительные ~0.4 бита экономии."

INT4 != 4x speedup

Квантизация до INT4 дает 4x экономию памяти, но НЕ 4x speedup. Причина: LLM inference memory-bound (bottleneck = memory bandwidth, не compute). INT4 ускоряет только memory transfer. Реальный speedup: 1.5-2.5x на стандартном GPU. Для максимального speedup нужен специализированный kernel (Marlin: 2-10x) который fuses dequantization + computation. Правило: квантизация = memory savings first, speedup second.

Calibration data matters

GPTQ и AWQ требуют калибровочные данные (128-1024 примера). Если калибровка на C4 (English text), а модель для code generation -- quality drop будет БОЛЬШЕ чем в benchmarks. Всегда калибруйте на данных близких к target domain. WikiText-2 perplexity -- ориентир, не гарантия.


13. Formulas Summary

Asymmetric Quantization

\[\text{scale} = \frac{\max(W) - \min(W)}{2^b - 1}\]
\[W_q = \text{round}(W / \text{scale}) + \text{zero\_point}\]

AWQ Scaling

\[s = s_x^\alpha\]
\[Q(W \times s) \times (X / s) \approx W \times X\]

GPTQ Error Compensation

\[w_i \leftarrow w_i - \frac{\delta_q}{H[q][q]} \times H[q][i]\]

Memory Savings

\[\text{Memory} = \frac{P \times b}{8} \text{ bytes}\]

Where \(P\) = parameters, \(b\) = bits per weight


14. Sources & Further Reading

Papers

  1. GPTQ: Frantar et al. (2022) — arXiv:2210.17323
  2. AWQ: Lin et al. (2024) — arXiv:2306.00978
  3. Marlin: Frantar et al. (2025) — arXiv:2408.11743
  4. FP8-RL: arXiv:2601.18150 (Jan 2026)
  5. MOSS (FP8 Training): OpenReview Dec 2025
  6. HeRo-Q: arXiv:2601.21626 (Jan 2026)

Guides & Benchmarks

  1. JarvisLabs: "Complete Guide to LLM Quantization with vLLM" (Jan 2026)
  2. dasroot.net: "GGUF vs GPTQ vs AWQ Comparison" (Jan 2026)
  3. Kaitchup Index: Quantized LLM Leaderboard

Tools

  1. auto-gptq: github.com/AutoGPTQ/AutoGPTQ
  2. auto-awq: github.com/casper-hansen/AutoAWQ
  3. llama.cpp: github.com/ggml-org/llama.cpp
  4. bitsandbytes: github.com/bitsandbytes-foundation/bitsandbytes
  5. vLLM: github.com/vllm-project/vllm

See Also