Lesson 26 LoRA & QLoRA
Theme:
Lesson 26 · Slide 1

LoRA & QLoRA

Parameter-efficient fine-tuning: adapt billion-parameter models on a single GPU by training less than 1% of all weights.

Learning Objectives

Module 5 — Fine-Tuning: This lesson focuses on the two most popular parameter-efficient fine-tuning methods. GPU access (Colab T4 or better) is recommended for the lab.
Lesson 26 · Slide 2

The Problem with Full Fine-Tuning

Full fine-tuning updates every parameter in the model. For a 7B-parameter model, that means storing optimizer states, gradients, and a full copy of every weight — often requiring 60–120 GB of VRAM.

Full Fine-Tuning Costs

  • 7B model: ~56 GB VRAM (fp16 + AdamW states)
  • 13B model: ~104 GB VRAM
  • 70B model: ~560 GB VRAM
  • Multiple A100 80GB GPUs required

PEFT Alternative

  • 7B + LoRA: ~16 GB VRAM
  • 7B + QLoRA: ~6 GB VRAM
  • Trainable params: 0.1–1% of total
  • Single consumer GPU sufficient

Parameter-Efficient Fine-Tuning (PEFT) methods freeze the original weights and train only a small number of additional parameters, achieving comparable quality at a fraction of the cost.

Lesson 26 · Slide 3

LoRA: Low-Rank Adaptation

The key insight: weight updates during fine-tuning have low intrinsic rank. Instead of updating a full d x d weight matrix W, LoRA decomposes the update into two small matrices.

The LoRA Decomposition

Original: h = W·x   (W is d×d, e.g. 4096×4096)

With LoRA: h = W·x + (B·A)·x   where A is r×d, B is d×r

W is frozen. Only A and B are trained. With r=16 and d=4096, trainable params per layer = 2 × 16 × 4096 = 131,072 instead of 16,777,216 — a 128x reduction.

Visual Intuition

Imagine the frozen weight matrix W as a large wall of bricks. LoRA adds a thin “bypass channel” alongside it: data flows through A (compress to rank r), then through B (expand back to full dimension). The original wall stays untouched.

Lesson 26 · Slide 4

Rank, Alpha & Target Modules

Choosing the Rank (r)

RankTrainable Params (per layer pair)Use Case
r = 4~33KSimple tasks, style transfer, single-domain adaptation
r = 8~66KGeneral-purpose fine-tuning (most common default)
r = 16~131KComplex tasks, multi-task learning
r = 32~262KLarge domain shift, approaching full FT quality

Alpha Parameter

Alpha controls the scaling factor of the adapter: scaling = alpha / r. A common rule of thumb is to set alpha = 2 × r (e.g., r=16, alpha=32). Higher alpha means a stronger adapter signal relative to the frozen weights.

Target Modules

LoRA can be applied to any linear layer, but common targets in transformer attention are:

Notes: Starting with q_proj + v_proj is a safe default. Add more target modules if quality is insufficient. More targets = more trainable params = more VRAM.
Lesson 26 · Slide 5

QLoRA: 4-Bit Quantization + LoRA

QLoRA (Dettmers et al., 2023) takes LoRA further by quantizing the frozen base model to 4 bits while keeping the LoRA adapters in higher precision. Three key innovations:

NF4 Data Type

NormalFloat4 — an information-theoretically optimal 4-bit data type for normally distributed weights. Better than uniform int4 quantization because neural network weights follow a roughly Gaussian distribution.

Double Quantization

Quantizes the quantization constants themselves. Each block of 64 weights uses a single fp32 scale factor; double quantization compresses those scale factors with a second round of quantization, saving ~0.37 bits per parameter.

Paged Optimizers

Uses NVIDIA unified memory to page optimizer states to CPU RAM when GPU memory is full. This prevents out-of-memory crashes during gradient spikes without permanently moving data off GPU. Enabled via optim="paged_adamw_32bit" in the Trainer.

Together these techniques let you fine-tune a 65B-parameter model on a single 48GB GPU — or a 7B model on a free Colab T4 (16GB).

Lesson 26 · Slide 6

PEFT Library Setup

HuggingFace's peft library makes LoRA and QLoRA configuration straightforward.

LoRA Configuration

from peft import LoraConfig, get_peft_model, TaskType

lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                          # rank
    lora_alpha=32,                 # scaling factor
    lora_dropout=0.05,             # regularization
    target_modules=["q_proj", "v_proj"],
    bias="none",
)

model = get_peft_model(base_model, lora_config)
model.print_trainable_parameters()
# trainable params: 6,553,600 || all params: 6,744,682,496 || trainable%: 0.0971

QLoRA: Add BitsAndBytes Quantization

from transformers import BitsAndBytesConfig
import torch

bnb_config = 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(
    "meta-llama/Llama-2-7b-hf",
    quantization_config=bnb_config,
    device_map="auto",
)
Lesson 26 · Slide 7

Full FT vs LoRA vs QLoRA

AspectFull Fine-TuningLoRA (fp16)QLoRA (4-bit)
VRAM (7B model)~56 GB~16 GB~6 GB
Trainable params100%0.1–1%0.1–1%
Training speedBaseline~1.5x faster~1.2x faster*
QualityBest (ceiling)95–100% of full FT90–99% of full FT
Adapter sizeFull model copy10–100 MB10–100 MB
ServingLoad full modelMerge into base or swap adaptersMerge into base or swap adapters
Multi-taskSeparate model per taskSwap adapters, share baseSwap adapters, share base

*QLoRA training can be slightly slower than fp16 LoRA because of quantization/dequantization overhead during the forward pass, but the massive VRAM savings usually make it worthwhile.

Adapter Serving Advantage

With LoRA, you can serve one base model + many small adapters for different tasks or customers. Adapter swapping takes milliseconds. This is the foundation of multi-tenant fine-tuning platforms.

Lesson 26 · Slide 8

Lab & Homework

Lab Exercises

  1. LoRA Setup — configure PEFT LoRA on a pre-trained model, inspect trainable parameters
  2. QLoRA Quantization — load a model in 4-bit with bitsandbytes, add LoRA adapters
  3. Train on a Small Dataset — fine-tune on an instruction dataset using the HuggingFace Trainer
  4. Merge & Save — merge the trained adapter into the base model and save for inference

Homework Tasks

  1. Experiment with different rank values (r=4, 8, 16, 32) and measure validation loss. Find the sweet spot for your dataset.
  2. Compare memory usage between LoRA and QLoRA using nvidia-smi. Document the difference.
  3. Apply LoRA to additional target modules (all attention + MLP) and compare quality vs the default q_proj + v_proj.

Lab Files

lab.py lab_answer.py
1 / ?