PEFT Explained: LoRA vs. QLoRA for Efficient Model Tuning
Quick Answer / TL;DR
PEFT is a family of methods that keep the pretrained model frozen and train only a small set of new parameters. LoRA is the most common one: it inserts small, trainable low-rank matrices into the model, which cuts memory use sharply while staying close to full fine-tuning on most tasks. QLoRA builds on LoRA by storing the frozen base model in 4-bit precision, which is what lets you fine-tune large models on a single GPU. The trade-off is speed: the 4-bit weights have to be dequantized on the fly, so each training step is slower than plain LoRA.
The idea behind PEFT
Fully fine-tuning a large language model means updating every weight, billions of parameters, along with their gradients and optimizer states. In practice that requires multi-GPU setups, a lot of memory bandwidth, and a correspondingly large bill. It also carries a risk: when you move all of the weights at once on a narrow task, the model can drift away from the general knowledge it picked up during pretraining, a problem known as catastrophic forgetting.
Parameter-Efficient Fine-Tuning (PEFT) takes a different route. It freezes the pretrained model and trains only a small number of additional parameters on top. Because the base weights never change, the memory needed for gradients and optimizer states collapses, and the original model is preserved as-is. LoRA and QLoRA are the two methods you will reach for most often, and the rest of this post compares them.
LoRA: Low-Rank Adaptation
LoRA is the most widely used PEFT method, and it rests on a simple observation: the weight update a model needs to learn a new task has a low intrinsic dimension, so it can be approximated cheaply. Rather than updating a full weight matrix (say 4096 × 4096), LoRA freezes that matrix and learns two much smaller ones in its place, for example 4096 × 16 and 16 × 4096, whose product stands in for the update. Only those small matrices are trained.
- When to use it: LoRA is a good fit when you have a mid-to-high-end GPU (roughly 24GB of VRAM is enough for a 7B model in 16-bit) and want fast iteration with accuracy close to full fine-tuning on most tasks.
- What you get: the result is a small adapter file, often only tens of megabytes, that is loaded on top of the base model at inference time. Since the base model is untouched, you can keep several adapters around and switch behaviors without holding multiple full copies of the model.
The catch with LoRA
LoRA cuts the number of trainable parameters dramatically, but it does nothing about the base model itself, which still has to sit in GPU memory at full 16-bit precision. If the base model alone does not fit in your VRAM, LoRA will still run out of memory.
QLoRA: Quantized LoRA
QLoRA was designed to remove exactly that bottleneck. It stores the frozen base model in 4-bit precision using a data type called 4-bit NormalFloat (NF4), which is tuned for the roughly normal distribution of model weights. Quantizing the base model to 4-bit cuts its memory footprint by about 4x compared to 16-bit, and the LoRA adapters are still trained in full precision on top.
- When to use it: reach for QLoRA when memory is the binding constraint. The original paper fine-tuned a 65B model on a single 48GB GPU; the same idea lets you fit a 7B model on a 12GB consumer card, or a 70B-class model on a single 48GB card, where plain LoRA would not fit.
- How it gets there: beyond NF4, QLoRA uses double quantization (quantizing the quantization constants themselves to save a little more memory) and paged optimizers (offloading optimizer state to system RAM during memory spikes so training does not crash).
The catch with QLoRA
The memory savings cost you speed. On the forward and backward passes the 4-bit weights have to be dequantized back to 16-bit to do the math, and that overhead makes each step slower than plain LoRA. The reported slowdown varies widely with hardware, model, and library maturity, from a few percent to around 30%, so it is worth benchmarking on your own setup rather than assuming a fixed number.
Choosing between them
The choice is mostly about your hardware budget. If you have GPUs to spare and care most about iteration speed, LoRA is the simpler, faster option. If you are working on a single consumer card, or pushing toward the largest model you can fit, QLoRA trades some speed for the memory headroom that makes the run possible at all. Both belong to the same shift: for most teams, full-parameter fine-tuning is no longer the default, and a frozen base model with a small set of trained parameters does the job at a fraction of the cost.
Related Cookbooks
The Math of DPO, Explained | SR Cookbooks
A step-by-step mathematical derivation of Direct Preference Optimization (DPO), showing how the partition function cancels and verifying the implicit reward gradient in Python.
Fixing EOS Errors: Why Fine-Tuned Models Talk to Themselves | SR Cookbooks
A technical guide to fixing the infinite generation bug in SFT by properly mapping EOS tokens and chat templates in Hugging Face.
How to Train Custom Tokens with LoRA | SR Cookbooks
Learn how to fix untrained embedding errors when adding custom tokens to an LLM vocabulary during PEFT and LoRA fine-tuning.