Quantization reduces the precision of model weights from 16-bit floats to 8-bit or 4-bit integers. This halves (or quarters) memory usage and speeds up memory-bound inference. The challenge: preserving output quality.
Methods: (1) GPTQ — weight-only, layer-by-layer with Hessian info, (2) AWQ — activation-aware, protects salient weights, (3) GGUF — CPU-friendly mixed-precision, (4) bitsandbytes — NF4 datatype for QLoRA. Weight-only quantization (activations stay in fp16) is most common for LLMs.
Python — quantize with bitsandbytes#
- Good 4-bit methods (GPTQ, AWQ) usually lose little on standard benchmarks; maths, code and long-context tasks tend to degrade first. llama.cpp’s GGUF format runs 4-bit 70B models on machines with 64 GB of memory
- Memory: FP32→FP16 = 2×, FP16→INT8 = 2×, INT8→INT4 = 2×. A 70B model goes from 280 GB → 35 GB
- Speed: weight-only INT4 can be several times faster than FP16 at small batch sizes, where memory bandwidth is the bottleneck (AWQ reports over 3×; Lin et al. 2024)
- AWQ protects the most important weights using activation statistics — better quality than naive rounding
A 70B model needs 140 GB in fp16, 70 GB in int8 and 35 GB in int4. How it is quantized matters as much as the bit width: with a few outlier weights, one int4 scale for the whole tensor gives an average error of 87% of a weight’s size; a separate scale per group of 128 weights cuts it to 30%. Group-wise scales are why 4-bit models work.
- Average reconstruction error is not task quality; evaluate on the tasks you care about, including long-context and maths, which degrade first.
- Weight-only quantization saves memory and bandwidth; it speeds up compute-bound batches much less.
- Below 4 bits quality usually falls quickly (Dettmers & Zettlemoyer 2023).
sizes = {bits: 70e9 * bits / 8 / 1e9 for bits in (16, 8, 4)} # a 70B model, GB
rng = np.random.default_rng(1)
w = rng.normal(0, 0.02, 4_096)
w[::512] = 0.5 # a few outlier weights
def int4_error(w, group):
g = w.reshape(-1, group)
scale = np.abs(g).max(axis=1, keepdims=True) / 7
return np.abs(np.clip(np.round(g / scale), -7, 7) * scale - g).mean() / np.abs(w).mean()
per_tensor, per_group = int4_error(w, 4_096), int4_error(w, 128)Assumes import numpy as np. Configurations named after real models use their published shapes; other numbers are made up or simulated, as the comments say.
The same idea with a library
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
# 4-bit quantization (NF4 for QLoRA)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True, # quantize the quantization constants
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-70B",
quantization_config=bnb_config,
device_map="auto"
)
# 70B model now fits in ~35GB VRAM- E. Frantar, S. Ashkboos, T. Hoefler & D. Alistarh, “GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers”, ICLR, 2023
- J. Lin et al., “AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration”, Proceedings of Machine Learning and Systems 6, 2024
- T. Dettmers & L. Zettlemoyer, “The Case for 4-bit Precision: k-bit Inference Scaling Laws”, ICML, 2023
Last reviewed October 2026 · How this site checks its content · Report a mistake
1. Going from 16-bit to 4-bit weights shrinks weight memory to about…
Show answer
A. Four bits instead of sixteen. Group-wise schemes add a scale (and sometimes a zero point) per small block of weights.
2. Why do outlier weights make quantization harder?
Show answer
C. Per-group or per-channel scales, and keeping outliers in higher precision, limit the damage.
3. Why does weight-only quantization speed up token-by-token generation?
Show answer
C. At batch size 1 the GPU mostly waits for weights to arrive from memory; smaller weights arrive sooner.