AI Engineering & LLMs (50 Qs)•Part 5: Model Customization, Fine-Tuning & Evaluation
QLoRA (Quantized Low-Rank Adaptation): 4-bit NormalFloat (NF4) & Paged Optimizers
1. Breaking the Fine-Tuning Barrier
While LoRA reduces trainable parameter memory, the base model weights still had to reside in 16-bit precision in VRAM. QLoRA (Dettmers et al.) enables fine-tuning a 65B/70B parameter model on a single 48GB GPU without performance degradation through three fundamental innovations:
scss
QLoRA Innovations
│
┌──────────────────────────────────┼──────────────────────────────────┐
▼ ▼ ▼
4-bit NormalFloat (NF4) Double Quantization (DQ) Paged Optimizers
Information-theoretically Quantizes the quantization Spills optimizer states
optimal distribution for constants themselves, to CPU RAM during memory
zero-mean Gaussian weights. saving 0.37 bits/param. spikes to prevent OOM.
2. 4-bit NormalFloat (NF4) vs. Standard INT4
- Standard neural network weights follow a normal distribution centered at zero.
- Standard uniform INT4 quantization assigns bins evenly across linear intervals, wasting resolution in high-probability tails.
- NF4 constructs 16 quantization bins where each bin has an equal number of expected data points, maximizing information entropy.
3. Production QLoRA Configuration with Hugging Face PEFT
python
import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# 1. Configure 4-bit NormalFloat Quantization
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16
)
# 2. Load Base Model in 4-bit
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Meta-Llama-3-70B",
quantization_config=bnb_config,
device_map="auto"
)
model = prepare_model_for_kbit_training(model)
# 3. Attach LoRA Adapters
peft_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, peft_config)
print(f"Trainable params: {model.print_trainable_parameters()}")