skip to content

Search

← The Engine Room

Part III — The Transformer-Industrial Complex (2020–2025)

PEFT and LoRA

Adapters, prompt and prefix tuning, the low-rank update, and QLoRA's NF4.

2019–2023 12 min read 4 papers

It is February 2019. BERT has made “pretrain then fine-tune” the default recipe in NLP, but the recipe has a hidden cost: fine-tuning copies the entire model, once per task, with a full set of gradients and optimizer state to match. A team of eight researchers proposes freezing the pretrained network almost entirely and inserting a small bottleneck module between its layers instead — the first widely cited attempt to make adaptation cheap rather than merely effective.

Where We Were

The transfer-learning recipe this book’s language-models volume traces in detail — pretrain a large network, then fine-tune all of its weights on a downstream task — treats every task as a reason to duplicate the model. For BERT-base’s 110 million parameters this was a nuisance; for GPT-2’s 1.5 billion, announced the same month as the adapters paper, it was a real storage and serving problem; by GPT-3’s 175 billion in May 2020, full fine-tuning per task had become impractical for most teams outside the largest labs.

The cost was not only disk space. This book’s chapter on optimizers shows that Adam-family optimizers keep two extra tensors — the first and second moment estimates — the same size as the parameters they are updating. Full fine-tuning a model with Adam means holding gradients and optimizer state for every one of its weights in accelerator memory at once, on top of the weights themselves. A lab that wanted to serve ten fine-tuned variants of the same base model needed either ten full copies on disk or ten full training runs’ worth of memory to produce them, with no way to share the pretrained weights across tasks at serving time.

Two questions followed from this cost. First: how much of a pretrained network actually needs to change to adapt it to a new task? Second: could the update itself be represented far more compactly than a full new copy of every weight matrix? The gap between “fine-tune everything” and “these two open questions” is where parameter-efficient fine-tuning (PEFT) begins.

Full fine-tuning stays the default until the models get too big to copy Two parameter-efficient methods arrive within two years, each paying for its savings somewhere else. Grey monospace text is the parameter count or cost each entry sets. 2018 BERT Full fine-tuning becomes the default one copy per task Feb 2019 GPT-2 1.5B parameters, one full copy per task language models Feb 2019 Adapters proposed Bottleneck modules per layer Houlsby et al. May 2020 GPT-3 175B parameters, full fine-tuning impractical language models Jan 2021 Prefix-tuning Learned virtual tokens Li and Liang the scale pressure cost hidden in latency cost hidden in context
Full fine-tuning stays the default until the models get too big to copy; two parameter-efficient methods arrive within two years, each paying for its savings somewhere else. PNG ↓

The Breakthrough

Adapters (Houlsby et al., 2019) answered the first question directly: insert a small bottleneck module — project down to a much smaller dimension, apply a nonlinearity, project back up, add the result back to the original activation — after every attention and feed-forward sublayer, and train only those bottlenecks while freezing the rest of the pretrained network. On GLUE, the paper reports landing “within 0.4% of the performance of full fine-tuning, adding only 3.6% parameters per task” across 26 diverse text-classification tasks. The pretrained backbone stayed shared across every task; only the small adapter modules differed.

Adapters left a residual cost, though: the extra bottleneck layers sit directly in the forward pass, so every inference call pays for two additional matrix multiplications per sublayer, however small. Prefix-tuning (Li & Liang, 2021) took a different route to the same goal, borrowing an idea from prompting rather than from module insertion: keep the language model’s parameters entirely frozen, and instead learn a short sequence of continuous vectors — “virtual tokens” — prepended to the keys and values that every attention layer attends to. The paper reports learning “only 0.1% of the parameters,” with performance “comparable” to full fine-tuning in the full-data setting and better than full fine-tuning in low-data settings, tested on GPT-2 for table-to-text generation and BART for summarization. Prefix-tuning added no new layers to the forward pass, but its learned prefix consumed part of the model’s finite context window at every step, a cost that grew with the number of virtual tokens.

By mid-2021 the field had two working PEFT methods, each solving part of the problem and each paying for it somewhere else: Adapters cost inference latency; prefix-tuning cost context length. LoRA (Hu et al., 2021) removed both costs by changing where the update lives rather than how it is computed. Instead of inserting a new module into the forward pass or prepending anything to the input, LoRA represents the update to an existing weight matrix as the product of two small matrices, added in parallel to the frozen original weight. Because the update is additive and linear, it can be computed alongside the frozen matrix during training and merged directly into it afterward — at inference time there is, per the paper, “no additional inference latency” at all. LoRA’s headline numbers: on GPT-3 175B, it “reduce[s] the number of trainable parameters by 10,000 times and the GPU memory requirement by 3 times” relative to full fine-tuning with Adam, while performing “on-par or better than fine-tuning” on RoBERTa, DeBERTa, GPT-2, and GPT-3.

The update to a weight is a separate, additive path The frozen weight and the low-rank update run in parallel, then sum, so a trained LoRA adapter can be merged in with no added inference cost. Input x activation Frozen weight W0 unchanged during training Low-rank A projects down to rank r Low-rank B projects back up to d Sum the paths W0 x + BAx Output h
The update to a weight is a separate, additive path; the frozen weight and the low-rank update run in parallel, then sum, with no added inference latency. PNG ↓

LoRA still assumed the frozen base weights sat in accelerator memory at full precision. QLoRA (Dettmers et al., 2023) removed that remaining assumption by compressing the frozen base model itself: quantize it to a 4-bit format called NF4 — the bit-level mechanics of low-bit quantization are this book’s quantization chapter — apply a second round of quantization to the quantization constants themselves (“double quantization”), and manage GPU memory spikes during training with paged optimizers that page optimizer state out to CPU memory on demand. LoRA adapters are then trained on top of this frozen, quantized base in ordinary 16-bit precision. The combination, per the paper, “reduces memory usage enough to finetune a 65B parameter model on a single 48GB GPU” while preserving the task performance of full 16-bit fine-tuning; the resulting Guanaco model family, fine-tuned in this way from LLaMA, reached “99.3% of the performance level of ChatGPT” on the Vicuna benchmark after “only requiring 24 hours of finetuning on a single GPU.”

Freezing the base at 4-bit is what fits a 65B model on one GPU Only the LoRA adapters, trained in ordinary precision on top of a quantized, frozen base, ever receive a gradient. Pretrained weights 65B parameters Quantize to NF4 frozen, 4-bit Attach LoRA adapters bf16, trainable Forward pass dequantize on the fly double quantization Paged optimizer memory spikes to CPU Gradients update only the LoRA adapters
Freezing the base at 4-bit is what fits a 65B model on one GPU; only the LoRA adapters ever receive a gradient. PNG ↓

The Mathematics

Adapters insert a bottleneck between a frozen sublayer’s output and the residual stream. For an activation h∈Rdh \in \mathbb{R}^d:

h′=h+f ⁣(h Wdown)Wuph' = h + f\!\left(h \, W_{\text{down}}\right) W_{\text{up}}
SymbolMeaning
hhActivation entering the adapter, from a frozen sublayer
h′h'Activation leaving the adapter, passed to the residual stream
WdownW_{\text{down}}Down-projection matrix, d×md \times m
WupW_{\text{up}}Up-projection matrix, m×dm \times d
ffNonlinearity inside the bottleneck
ddOriginal hidden dimension
mmBottleneck dimension, m≪dm \ll d

Prefix-tuning leaves every weight matrix untouched and instead prepends learned vectors to the keys and values an attention layer sees. For a layer with query QQ, key KK, and value VV, and a learned prefix of key/value vectors Pk,PvP_k, P_v of length ll:

Attn(Q,[Pk;K],[Pv;V])=softmax ⁣(Q [Pk;K]⊤dk)[Pv;V]\mathrm{Attn}\left(Q, [P_k; K], [P_v; V]\right) = \mathrm{softmax}\!\left(\frac{Q \, [P_k; K]^{\top}}{\sqrt{d_k}}\right) [P_v; V]
SymbolMeaning
Q,K,VQ, K, VQuery, key, and value matrices from the frozen attention layer
Pk,PvP_k, P_vLearned prefix key and value vectors, the only trainable parameters
llPrefix length, in virtual tokens
dkd_kKey dimension, used to scale the dot product

LoRA replaces both the extra module and the extra context tokens with a low-rank update added directly to an existing weight matrix. For a frozen weight W0∈Rd×kW_0 \in \mathbb{R}^{d \times k} and input xx:

h=W0x+ΔWx=W0x+αrBAxh = W_0 x + \Delta W x = W_0 x + \frac{\alpha}{r} B A x
SymbolMeaning
W0W_0Frozen pretrained weight matrix, d×kd \times k
xxInput activation to the layer
ΔW\Delta WThe trained update, represented as a low-rank product
A,BA, BLow-rank factor matrices, r×kr \times k and d×rd \times r
rrRank of the update, r≪min⁡(d,k)r \ll \min(d, k)
α\alphaScaling constant for the update magnitude
d,kd, kOutput and input dimensions of the original weight matrix

QLoRA changes none of this decomposition; it changes what W0W_0 costs to hold in memory. The total training memory is approximately:

Mtotal≈N⋅bbase8+NLoRA⋅badapter8(1+s)M_{\text{total}} \approx \frac{N \cdot b_{\text{base}}}{8} + \frac{N_{\text{LoRA}} \cdot b_{\text{adapter}}}{8} (1 + s)
SymbolMeaning
MtotalM_{\text{total}}Approximate total memory for weights and adapter optimizer state
NNNumber of parameters in the frozen base model
bbaseb_{\text{base}}Bits per base parameter, 4 for NF4
NLoRAN_{\text{LoRA}}Number of trainable LoRA adapter parameters
badapterb_{\text{adapter}}Bits per adapter parameter, typically 16
ssOptimizer-state multiplier, 2 for Adam’s two moment tensors

What It Enabled

The practical effect of this four-paper progression was to turn “fine-tune a large pretrained model” from a full-cluster job into something that fits, for the smaller end of the model range, on a single accelerator. QLoRA’s own headline result — a 65-billion-parameter model fine-tuned on one 48 GB GPU, reaching 99.3% of ChatGPT’s performance on the Vicuna benchmark after 24 hours of training — is the clearest evidence of how far the gap between “adapt a frontier-scale model” and “adapt it on hardware a single researcher can access” had closed.

MethodYearTrainable parametersAdded inference costFrozen-weight precision
Full fine-tuning—100%nonefull (16/32-bit)
Adapters2019~3.6% per taskextra forward-pass layersfull
Prefix-tuning2021~0.1%consumes context windowfull
LoRA2021far below 1%, merged into W0W_0none, merges into frozen weightfull
QLoRA2023same as LoRAnone4-bit NF4

LoRA’s mergeable, additive structure had a second consequence beyond raw memory savings: because BABA is a small, self-contained update, it can be stored, shipped, and swapped independently of the multi-gigabyte base model it modifies. That property underlies the open-weights fine-tuning ecosystem this book’s sister volume covers around Llama and the open-weight explosion and the practice of instruction-tuning open models on commodity hardware — a LoRA adapter for a 7B-parameter model is typically megabytes, not gigabytes, because it stores only AA and BB, not a second copy of W0W_0. The same additive structure crossed over into diffusion image models almost immediately, where it underlies the subject- and style-personalization techniques this book’s sister volume covers in personalization and LoRA — the math is identical, only the frozen base model differs. Serving many such adapters against one shared frozen base, in turn, is one of the problems this book’s inference-engines chapter returns to when it covers how a single deployment can multiplex requests across dozens of fine-tuned variants without holding dozens of full model copies in memory.

Two 2019 fixes converge on LoRA, which then fans out to four chapters Adapters and prefix-tuning each paid a cost somewhere; LoRA removed both, and QLoRA removed the memory floor underneath it. Adapters, 2019 costs inference latency Prefix tuning, 2021 costs context length LoRA no added cost either way QLoRA 4-bit frozen base Quantization chapter Chapter 15 Instruction tuning language models chapter Personalization and LoRA later chapter Inference engines Chapter 17
Two 2019 fixes converge on LoRA, which removes both their costs, and QLoRA then removes the memory floor underneath it. PNG ↓

Key Papers

PaperAuthorsYearLinkWhy it matters
Parameter-Efficient Transfer Learning for NLPHoulsby et al.2019arXiv:1902.00751Introduced bottleneck adapter modules; within 0.4% of full fine-tuning at 3.6% of the parameters per task
Prefix-Tuning: Optimizing Continuous Prompts for GenerationLi & Liang2021arXiv:2101.00190Learned continuous prefixes prepended to attention keys/values; 0.1% of parameters, no new layers
LoRA: Low-Rank Adaptation of Large Language ModelsHu et al.2021arXiv:2106.09685Low-rank additive update merged into frozen weights; 10,000x fewer trainable params, no inference latency
QLoRA: Efficient Finetuning of Quantized LLMsDettmers et al.2023arXiv:2305.143144-bit NF4 frozen base plus LoRA adapters; 65B-parameter fine-tuning on a single 48GB GPU

PM Lens

Papers referenced