Today: fine-tuning, PEFT, LoRA, quantization, and QLoRA. One story. Lots of pictures. Hit Play on each demo.
Customer: “I bought shoes 20 days ago. Can I return them?”
Same return-policy question. Two different tools.
At answer time, search your PDF/wiki, paste the matching text into the prompt, ask the frozen model.
Changes: what the model sees right now (fresh facts).
Does not change: the model’s weights.
Train on your past chats so the model picks up your tone, format, and habits.
Changes: how the model behaves.
Weak at: facts that change every week (you would retrain).
| If you need… | Go with | Why |
|---|---|---|
| Up-to-date facts (menu, policy, prices) | RAG | Update the document. No retrain. |
| Citations / “show me the source” | RAG | You can point at the retrieved chunk. |
| Brand tone, empathy, reply format | Fine-tune | Behavior lives in the weights. |
| Domain slang / how your team talks | Fine-tune | Hard to enforce with retrieval alone. |
| Fresh facts + your voice | Both | Fine-tune the style. RAG the facts. |
You show it hundreds of real support chats. It picks up your tone, your short answers, and stable habits. For changing policy text, still prefer RAG.
PEFT = Parameter-Efficient Fine-Tuning. Lock the big brain. Only train small adapters.
Imagine one tiny layer with a 4×4 weight matrix. Full fine-tuning touches every cell. PEFT freezes those 16 cells and trains only a small adapter.
| Approach | What you train | Count |
|---|---|---|
| Full fine-tune | All of W (4×4) | 16 |
| PEFT (tiny adapter) | Adapter only (example size 4) | 4 |
| Savings | Frozen W never gets gradients | 75% fewer trainable params |
Before training the weights are W₀. After training they are W. Subtract them: ΔW = W − W₀. Full fine-tuning tries to learn that entire change sheet.
LoRA = Low-Rank Adaptation. Freeze W₀. Learn B and A only. The update is B × A.
Rule: each cell of ΔW is one number from B times one number from A.
ΔW[i, j] = B[i] × A[j]
Frozen W₀, LoRA update BA, input x. You can check every multiply by hand.
Input x = [2, 3]. Hit Play.
Now d is big and r stays small. For a 512×512 weight matrix with rank r = 8:
| What we store | Shape | Numbers |
|---|---|---|
| Full ΔW | 512 × 512 | 262,144 |
| LoRA B | 512 × 8 | 4,096 |
| LoRA A | 8 × 512 | 4,096 |
| LoRA total | B + A | 8,192 (about 3%) |
A 7B model in FP16 is about 14 GB just for weights. A free Colab T4 has about 15 GB total. You are one sneeze away from out-of-memory.
Goal: fit a big frozen base on a small GPU so QLoRA training is possible.
Think “lossy zip for numbers.” Same idea as JPEG for images: smaller file, almost the same picture.
Step 1 · few buckets (INT2 toy)
Step 2 · finer labels (INT8 math)
Freeze the model in 4-bit NF4. Attach LoRA adapters. Train only the adapters. Gradients never rewrite the base.
| LoRA | QLoRA | |
|---|---|---|
| Base | FP16 frozen | NF4 frozen |
| Adapters | train | train |
| 7B in training (ballpark) | ~16 GB+ (base + activations) | ~6 GB |
Memory ≈ (number of parameters) × (bytes per parameter). That one line explains why QLoRA fits on Colab.
| Setup | Bytes / param | 7B size |
|---|---|---|
| Base in FP16 (LoRA case) | 2 | 7e9 × 2 = 14 GB |
| Base in NF4 (QLoRA case) | 0.5 | 7e9 × 0.5 = 3.5 GB |
| LoRA adapters (example 24M) | 2 (FP16) | 24e6 × 2 ≈ 0.05 GB |
| QLoRA total (weights only) | NF4 base + FP16 adapters | ≈ 3.55 GB |
Next lab: Unsloth on Colab with Llama 3.2 3B and your own support-style examples.