Quantized loading

Hugging Face Transformers · Advanced · 14 min

Quantization lets a 7B-parameter model run in about 5 GB instead of 14 GB of GPU memory.

Weights normally take 2 bytes each in bf16, so a 7B model needs about 14 GB just for weights. Quantization stores weights in fewer bits: 8-bit halves that, 4-bit quarters it, at a modest accuracy cost.

Transformers loads quantized models through a quantization_config:

bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4",
                         bnb_4bit_compute_dtype=torch.bfloat16,
                         bnb_4bit_use_double_quant=True)
model = AutoModelForCausalLM.from_pretrained(repo, quantization_config=bnb, device_map="auto")

bitsandbytes quantizes on the fly at load time, needs no calibration, and is the basis of QLoRA. nf4 is a 4-bit type designed for normally distributed weights; the compute dtype is what matmuls run in after dequantization.

Other families:

  • Pre-quantized checkpoints (GPTQ, AWQ, compressed-tensors, FP8, MXFP4) load directly from repos that ship them; the config is read from the checkpoint. They are often faster for inference than bitsandbytes.
  • torchao offers int8/int4 and float8 quantization integrated with torch.compile.

Trade-offs: lower bits mean less memory but some quality loss; speed depends on kernels and hardware, and quantized inference is not always faster than bf16. Evaluate on your task. Note the old load_in_8bit=True keyword on from_pretrained is gone; always use a config object.

Example

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig

repo = "Qwen/Qwen2.5-7B-Instruct"

bnb4 = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
    repo, quantization_config=bnb4, device_map="auto")   # needs a CUDA GPU

print(f"{model.get_memory_footprint() / 1e9:.1f} GB")    # roughly 5 GB vs ~15 GB in bf16

bnb8 = BitsAndBytesConfig(load_in_8bit=True)
# model8 = AutoModelForCausalLM.from_pretrained(repo, quantization_config=bnb8, device_map="auto")

# pre-quantized checkpoints carry their own config:
# AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct-AWQ", device_map="auto")

Remember

  • Pass a quantization_config (e.g. BitsAndBytesConfig) to from_pretrained
  • 4-bit NF4 with bf16 compute is the common QLoRA setup
  • Pre-quantized GPTQ/AWQ/FP8 checkpoints load directly and are often faster

Watch out for

  • Expecting quantization to always speed up inference; it mainly saves memory and speed depends on kernels.

Check yourself

  1. Roughly how much GPU memory do the weights of an 8B-parameter model take in 4-bit?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: huggingface.co/docs/transformers/quantization/overview