VerifiedarXiv:2305.1431429 min
Training · LLMs

QLoRA: Efficient Finetuning of Quantized LLMs

Finetune a 65B model on one 48 GB GPU by storing the frozen model in 4 bits.

The pretrained weights stay frozen in NormalFloat, a 4-bit format fitted to bell-shaped weight distributions, and a small 16-bit LoRA adapter trains through them.

Explaining the paperQLoRA: Efficient Finetuning of Quantized LLMsDettmers, Pagnoni, Holtzman, Zettlemoyer · University of Washington · NeurIPS 2023 · arXiv:2305.14314 ↗

Ordinary 16-bit finetuning of LLaMA 65B needs more than 780 GB of GPU memory, about ten 80 GB cards. QLoRA needs less than 48 GB, and the authors used it to train a 65B chatbot in 24 hours on a single GPU.

A pretrained language model becomes useful for a particular job (following instructions, answering in a house style, chatting) by finetuning: more gradient steps on data for that job. In May 2023, finetuning LLaMA 65B required a multi-GPU server. Quantization, storing weights in fewer bits, already shrank models for inference, but methods such as LLM.int8() and SmoothQuant were built for the forward pass of a finished model and, in the paper's words, "break down during training". The one earlier study of backpropagating through quantized weights beyond 1B parameters, SwitchBack (Wortsman et al., 2023), used 8 bits.

QLoRA (Dettmers, Pagnoni, Holtzman and Zettlemoyer) keeps the pretrained model frozen and stored in 4 bits per weight, and trains a small set of new 16-bit weights, a LoRA adapter, by backpropagating through the 4-bit model. On LLaMA 7B to 65B, the result matches the same adapters trained on a 16-bit model. The memory saving let the authors finetune more than 1,000 models for the study, and train Guanaco, a chatbot family whose 65B member took 24 hours on one GPU.

The page follows the method in the order its parts depend on each other: where finetuning memory goes, what LoRA removes and what it leaves, block-wise quantization, the NormalFloat (NF4) data type, double quantization of the scales, one complete layer forward and backward, paged optimizers, the training recipe, and then the results and the Guanaco evaluation.

Where finetuning memory goes

Finetuning with the Adam optimizer keeps four kinds of numbers in GPU memory. Three of them scale with the number of trained parameters:

That is 12 bytes per parameter, and for 65 billion parameters it reproduces the paper's number exactly:

65×109 params×12 bytes=780 GB65\times10^{9}\ \text{params}\times 12\ \text{bytes} = 780\ \text{GB}

The fourth kind, activations, are the intermediate outputs saved on the forward pass for use in the backward pass. They grow with batch size and sequence length rather than parameter count, and the 780 GB does not include them. Of the 12 bytes, 10 exist only because the weight is being updated: the gradient and the two Adam moments outweigh the weight five to one. (Mixed-precision setups that also keep a 32-bit master copy of every weight, the accounting in ZeRO, need 16 bytes per parameter, which would be 1,040 GB here.)

Figure 1 splits the memory three ways for each LLaMA size. Slide to 65B and the full-finetuning bar runs off the chart; the other two bars are the subject of the next section.

Figure 1 · the memory of finetuning

QLoRA · 4-bit NF4 + DQ · The frozen base drops to 4-bit (33.5 GB); with the adapter's 9.6 GB that is 43.1 GB before activations, leaving about 5 GB of a 48 GB card.

GPU memory to finetune LLaMA three ways, before activations. Full 16-bit: weight, gradient and two Adam moments for every parameter, 12 bytes each. 16-bit LoRA: the base is frozen and 16-bit, plus the adapter's own training state. QLoRA: the same, with the frozen base in 4-bit. Drag the size; tap a row or a button for its breakdown.

What LoRA saves, and what it leaves on the GPU

LoRA (Low-Rank Adaptation, Hu et al., 2021) freezes every pretrained weight matrix W\mathbf{W} and learns a correction next to it, factored into two thin matrices. A linear layer that computed Y=XW\mathbf{Y}=\mathbf{X}\mathbf{W} now computes

Y=XW+s XL1L2\mathbf{Y} = \mathbf{X}\mathbf{W} + s\,\mathbf{X}\mathbf{L}_1\mathbf{L}_2
(1)

with W∈Rh×o\mathbf{W}\in\mathbb{R}^{h\times o} frozen and only L1∈Rh×r\mathbf{L}_1\in\mathbb{R}^{h\times r} and L2∈Rr×o\mathbf{L}_2\in\mathbb{R}^{r\times o} trained. The rank rr is small; QLoRA uses r=64r=64. The scalar ss is α/r\alpha/r, and with QLoRA's α=16\alpha=16 it is 16/64=0.2516/64=0.25. By the convention LoRA and its PEFT implementation use, L1\mathbf{L}_1 starts random and L2\mathbf{L}_2 starts at zero, so L1L2=0\mathbf{L}_1\mathbf{L}_2=0 at step zero and training starts exactly at the pretrained model.

For a concrete size, take the query projection of LLaMA 7B, a 4096×40964096\times4096 matrix of 16.8 million weights. At r=64r=64, L1\mathbf{L}_1 is 4096×644096\times64 and L2\mathbf{L}_2 is 64×409664\times4096, together 524,288 numbers, one thirty-second of the matrix. Gradients and Adam moments are needed only for those 524,288. QLoRA puts an adapter on every linear layer of every transformer block (the four attention projections and the three MLP matrices), because the paper finds that 4-bit finetuning matches 16-bit when every linear layer has an adapter, whatever the rank: the original LoRA recipe adapted only the query and value projections, and with adapters on all layers the choice of rr "is unrelated to final performance". By our count from LLaMA 65B's layer sizes, adapters on all 80 blocks come to about 800 million parameters, 1.2% of the model. The paper's own memory example uses a smaller adapter: for LLaMA 7B, an adapter sized at the common 0.2% of the model's weights takes only 26 MB, while the input gradients flowing through it take 567 MB.

Freezing removes the gradient and optimizer state for the 65 billion base weights, but the base still has to sit in GPU memory for every forward pass. In 16-bit that is 65×109×265\times10^9\times2 bytes = 130 GB, more than two 48 GB cards, which is the middle bar of Figure 1. QLoRA stores that frozen base in 4 bits instead (about 33.5 GB at 65B, counting the scales) without hurting the finetuned model.

Why 4 bits and not a more cautious 8? An 8-bit base at 65B is 65 GB, still over a 48 GB card. The results section shows that 4-bit NF4 already matches 16-bit after finetuning, so stopping at 8 would cost memory and buy nothing measurable.

How block-wise absmax quantization works

Quantization maps each high-precision number to one of a small set of codes. The scheme everything here builds on is absmax quantization. For signed 8-bit integers with codes −127-127 to 127127, find the largest magnitude in the tensor and scale so that it lands on the top code:

XInt8=round⁡ ⁣(127absmax(X) X)=round⁡(c⋅X)\mathbf{X}^{\text{Int8}} = \operatorname{round}\!\Big(\tfrac{127}{\text{absmax}(\mathbf{X})}\,\mathbf{X}\Big) = \operatorname{round}(c\cdot\mathbf{X})XInt8=round⁡ ⁣(127absmax(X) X)=round⁡(c⋅X)\begin{aligned}\mathbf{X}^{\text{Int8}} &= \operatorname{round}\!\Big(\tfrac{127}{\text{absmax}(\mathbf{X})}\,\mathbf{X}\Big)\\ &= \operatorname{round}(c\cdot\mathbf{X})\end{aligned}
(2)

The number c=127/absmaxc=127/\text{absmax} is the quantization constant, or scale, and it is stored next to the codes. Dequantization divides by it: XInt8/c\mathbf{X}^{\text{Int8}}/c. Multiplying and dividing by cc cancel, so the rounding is the only step that loses information. Codes run −127-127 to 127127, so one of the 256 byte values (−128-128) goes unused.

A worked example: X=[0.62, −1.18, 0.033, 2.54]\mathbf{X}=[0.62,\,-1.18,\,0.033,\,2.54] has absmax 2.54, so c=50c=50 and the codes are [31, −59, 2, 127][31,\,-59,\,2,\,127]. Dividing by 50 gives back [0.62, −1.18, 0.04, 2.54][0.62,\,-1.18,\,0.04,\,2.54], with an error only on the third value. Now replace 2.54 with an outlier, 25.4. The scale drops to c=5c=5, the step between codes grows to 0.2, and the decoded tensor is [0.6, −1.2, 0, 25.4][0.6,\,-1.2,\,0,\,25.4]: the 0.033 has rounded to zero. One large value sets the step size for every other value in the tensor, and in a large tensor most values end up on the few codes nearest zero.

Block-wise quantization limits the damage. Flatten the tensor, cut it into contiguous blocks of BB values, and give each block its own scale cic_i. A tensor of b×hb\times h values becomes n=(b×h)/Bn=(b\times h)/B blocks, and an outlier stretches only the scale of its own block. QLoRA uses B=64B=64 for the weights. A camera that sets one exposure for the whole frame from a single streetlight renders everything else black; metering each tile of the frame separately confines the problem to the tile that holds the light.

Figure 2 zooms in on ordinary weights near zero and the 16 code positions of a 4-bit grid (the 8-bit case looks the same with more lines). In whole-tensor mode, drag the outlier outward and count how many codes the ordinary weights still reach. Then switch to per-block mode, where the outlier sits in some other block.

Figure 2 · why blocks
Ordinary weights (teal dots) and the 16 code positions (amber lines) of a 4-bit grid. With one scale for the whole tensor, a distant outlier spreads the codes until the weights round to a few of them. Per block, this block's scale is set by its own largest value and most of the 16 codes are in use. Drag the outlier; toggle the mode.

These are weight outliers. The more extreme outliers that SmoothQuant and LLM.int8() deal with live in the activations. QLoRA never quantizes activations: it stores only the weights in 4 bits and converts them back to 16-bit before every matrix multiply, so activation outliers never pass through its quantizer.

NormalFloat: a 4-bit type for normally distributed weights

Absmax fixes the scale of the codes but not where the 16 codes of a 4-bit type sit inside [−1,1][-1,1]. Trained weights are roughly normal: crowded near zero with thin tails. The paper checks this on LLaMA 7B with a Shapiro-Wilk test per hidden unit and finds 7.5% of units non-normal at a 5% significance level, about 2.5 points above the false-positive rate. A uniform grid (Int4) puts as many codes in the sparse tails as in the dense center, so a few center codes absorb most of the weights.

NormalFloat (NF4) places the codes at quantiles of a standard normal: cut the bell into 16 slices of equal probability mass rather than equal width, and put one code in each. Near zero the slices are narrow and the codes close together; in the tails the slices are wide. NF4 specializes the block-wise quantile quantization of Dettmers et al. (2022) to a fixed normal, so the codes are computed once and every block reuses them. The paper writes each code as the midpoint of two adjacent quantiles:

qi=12(Q(i2k+1)+Q(i+12k+1))q_i = \tfrac{1}{2}\Big(Q\big(\tfrac{i}{2^k+1}\big) + Q\big(\tfrac{i+1}{2^k+1}\big)\Big)
(3)

where QQ is the inverse CDF (quantile function) of N(0,1)\mathcal{N}(0,1) and k=4k=4 bits. Figure 3 compares where NF4, Int4 and FP4 (a 4-bit float with 2 exponent bits and 1 mantissa bit) put their codes on the same bell. The shading of each bin shows how much of the weight mass that one code has to represent. Move the pointer across the axis to drop a weight and read its rounding error.

Figure 3 · NF4 vs a uniform grid
RMS error 0.0343
The bell is a block of weights after absmax normalization. A 4-bit type gets 16 codes (amber). NF4 places them at normal quantiles, dense near zero. Int4 spaces them evenly, leaving its outer codes in near-empty tails and overloading the center. FP4 clusters toward zero, less than NF4. Brighter bins carry more of the weight; the readout gives RMS rounding error.

On this bell (standard deviation 0.36 after normalization, so the block maximum sits about 2.8 standard deviations out) the RMS rounding errors are 0.0343 for NF4, 0.0385 for Int4 and 0.0393 for FP4.

The paper calls NF4 information-theoretically optimal for normal data. The phrase has a narrow meaning: with equal-mass bins, every one of the 16 codes is used equally often, so a stored code carries the full log⁡216=4\log_2 16 = 4 bits of information. That maximizes the entropy of the codes. Minimum rounding error is a different objective, and the quantizer that achieves it (Lloyd-Max) puts each code at the mean of its bin and does not make the bins equal-mass.

Two details of the type. It is asymmetric: 7 negative codes, an exact 00, and 8 positive codes, 16 in all, with the exact zero there so that padding and true zeros are stored without error. And the bins are equal-mass only in the idealization. Each block is divided by its own maximum, so the normalized values are not exactly N(0,1)\mathcal{N}(0,1) scaled to [−1,1][-1,1], and Yoshida (2023) measured per-code usage between 2% and 9% at block size 64 instead of a uniform 6.25%. Yoshida argues this departure helps, because it keeps more precision for the rare large weights.

The 16 values themselves do not come from equation (3) as written: its first and last terms are Q(0)=−∞Q(0)=-\infty and Q(1)=+∞Q(1)=+\infty. The released code takes quantiles between 0.5 and an offset of 0.9677083 instead, and rescales so the extreme codes are exactly ±1\pm1. This reproduces the published table to about seven decimal places:

# the 16 NF4 values (bitsandbytes create_normal_map, functional.py:169)
# equation (3) taken literally asks for Q(0) = -inf and Q(1) = +inf
offset = 0.9677083                              # = ((1-1/30) + (1-1/32)) / 2
pos = norm.ppf(linspace(offset, 0.5, 9)[:-1])   # 8 positive quantiles
neg = -norm.ppf(linspace(offset, 0.5, 8)[:-1])  # 7 negative quantiles
codes = sort([*neg, 0.0, *pos])                 # 7 neg + exact 0 + 8 pos = 16
codes = codes / max(abs(codes))                 # absmax-normalize: ends at -1, +1

The result runs −1.0, −0.6962, …, −0.0911, 0, 0.0796, …, 0.7230, 1.0. A stored weight is a 4-bit index into this table, and decoding multiplies the table entry by the block's scale.

One block, encoded and decoded

Encoding a block of 64 weights takes four steps. (1) Compute the block's absmax and keep it as the scale. (2) Divide every weight by it, which puts the block in [−1,1][-1,1]. (3) Replace each normalized value by the index of the nearest NF4 value; bitsandbytes orders the table ascending, so index 0 is −1-1, index 7 is the exact zero and index 15 is +1+1. (4) To decode, look up the table entry and multiply by the scale. Storage for the block is 64 four-bit indices, which is 32 bytes, plus the scale.

Figure 4 does this for a block drawn from a normal with standard deviation 0.02, about the spread of LLaMA's weights. Each teal bar is an original weight and the amber tick on it is its decoded value. Pick a weight with the slider or by tapping its bar and follow it through the four steps; "new block" draws another 64.

Figure 4 · one block through NF4
Top: 64 weights of one block (teal bars) and their decoded values (amber ticks); the dashed lines are ±\pmabsmax. Middle: the 16 NF4 values, the selected weight divided by absmax, and the value it rounds to. Bottom: the four steps with numbers, and the block's RMS error. Choose a weight with the slider or by tapping a bar.

Two things to read off the figure. The weight with the largest magnitude always decodes exactly, because it normalizes to ±1\pm1 and both are codes. And the RMS error stays a few percent of the block's absmax whatever block you draw, because the codes move with each block's own scale.

Double quantization

Each block of 64 weights carries its own 32-bit scale, which adds 32/64=0.532/64=0.5 bits to every weight, so a "4-bit" model actually costs 4.5 bits per weight. Smaller blocks track outliers better but pay this overhead more often; larger blocks are cheaper and let an outlier degrade more weights.

Double Quantization quantizes the scales. LLaMA 65B has 65×109/6465\times10^9/64, about 1.02 billion, block scales, and those numbers form a tensor of their own. QLoRA stores each one as an 8-bit float, in blocks of 256 scales, with one 32-bit scale per block of 256. The scales are all positive, so their mean is subtracted first to center them around zero and allow a symmetric quantizer. The weights themselves stay 4-bit NF4; only the scales change. The overhead per weight becomes

864⏟8-bit scale per 64+3264×256⏟32-bit scale per 64⋅256=0.125+0.00195=0.127\underbrace{\tfrac{8}{64}}_{\text{8-bit scale per 64}} + \underbrace{\tfrac{32}{64\times 256}}_{\text{32-bit scale per }64\cdot256} = 0.125 + 0.00195 = 0.127864⏟8-bit scale per 64+3264×256⏟32-bit scale per 64⋅256=0.125+0.00195=0.127\begin{aligned}&\underbrace{\tfrac{8}{64}}_{\text{8-bit scale per 64}} + \underbrace{\tfrac{32}{64\times 256}}_{\text{32-bit scale per }64\cdot256}\\ &= 0.125 + 0.00195 = 0.127\end{aligned}
(4)

bits per parameter, down from 0.5, a saving of 0.373 bits on every weight. At 65B that is 0.373×65×109/8≈30.373\times65\times10^9/8\approx3 GB (dividing by 8 converts bits to bytes). Counted directly: the 1.02 billion scales take 4.06 GB at 32 bits, and 1.02 GB at 8 bits plus 16 MB for the 4 million second-level scales. The total storage drops from about 4.5 to about 4.127 bits per weight, which is the 33.5 GB base in Figure 1. Figure 5 plots both overheads against block size.

Figure 5 · the cost of the scales
0.500 → 0.127 bits/param
Scale overhead in bits per weight against block size (log axis), over the sizes bitsandbytes accepts. 32-bit scales cost 32/B32/B; double quantization costs 8/B+32/(256B)8/B + 32/(256B). The readout adds the 4-bit code for the total per weight and converts the saving to GB at 65B. Drag the block size.

At B=32B=32 plain scales would cost a full extra bit per weight and double quantization brings that to 0.254; at B=4096B=4096 both are under 0.01 bits but each scale covers 4,096 weights, so a single outlier coarsens all of them. At B=64B=64, double quantization cuts the scale overhead from 0.5 to 0.127 bits per weight. The paper reports no performance degradation from 8-bit scales in blocks of 256.

How QLoRA works: one layer, forward and backward

QLoRA uses two data types. The storage type, 4-bit NF4, holds the frozen weights in GPU memory. The compute type, 16-bit BFloat16 (BF16), is what every matrix multiply runs in. When a layer needs its weight, the weight is dequantized from 4-bit to BF16, used, and discarded; no 16-bit copy of the base is ever stored. Writing equation (1) with that conversion made explicit gives the forward pass of one linear layer:

YBF16=XBF16doubleDequant⁡(c1,c2,WNF4)+s XBF16L1BF16L2BF16\mathbf{Y}^{\text{BF16}} = \mathbf{X}^{\text{BF16}}\operatorname{doubleDequant}(c_1, c_2, \mathbf{W}^{\text{NF4}}) + s\,\mathbf{X}^{\text{BF16}}\mathbf{L}_1^{\text{BF16}}\mathbf{L}_2^{\text{BF16}}YBF16=XBF16doubleDequant⁡(c1,c2,WNF4)+s XBF16L1BF16L2BF16\begin{aligned}\mathbf{Y}^{\text{BF16}} &= \mathbf{X}^{\text{BF16}}\operatorname{doubleDequant}(c_1, c_2, \mathbf{W}^{\text{NF4}})\\ &\quad + s\,\mathbf{X}^{\text{BF16}}\mathbf{L}_1^{\text{BF16}}\mathbf{L}_2^{\text{BF16}}\end{aligned}
(5)

The scalar ss is the LoRA scale from (1). The paper prints this equation without it, but its own equation for LoRA has it and the released code applies α/r\alpha/r. The function doubleDequant⁡\operatorname{doubleDequant} undoes both rounds of quantization:

doubleDequant⁡(c1,c2,WNF4)=dequant⁡(dequant⁡(c1,c2), WNF4)=WBF16\operatorname{doubleDequant}(c_1, c_2, \mathbf{W}^{\text{NF4}}) = \operatorname{dequant}\big(\operatorname{dequant}(c_1, c_2),\ \mathbf{W}^{\text{NF4}}\big) = \mathbf{W}^{\text{BF16}}doubleDequant⁡(c1,c2,WNF4)=dequant⁡(dequant⁡(c1,c2), WNF4)=WBF16\begin{aligned}&\operatorname{doubleDequant}(c_1, c_2, \mathbf{W}^{\text{NF4}})\\ &= \operatorname{dequant}\big(\operatorname{dequant}(c_1, c_2),\ \mathbf{W}^{\text{NF4}}\big)\\ &= \mathbf{W}^{\text{BF16}}\end{aligned}
(6)

Read it from the inside. The inner dequant⁡(c1,c2)\operatorname{dequant}(c_1, c_2) uses the 32-bit second-level scales c1c_1 to recover the block scales from their 8-bit form c2c_2. The outer dequant⁡\operatorname{dequant} then uses those recovered scales to turn each 4-bit index into a BF16 weight, as in step 4 of Figure 4. The subscripts run opposite to the order of quantization: c2c_2 holds the first-level scales, one per 64 weights, and c1c_1 holds the second-level scales, one per 256 of those. The two nested dequants are the two rounds of double quantization; the weight is dequantized once.

The backward pass has two jobs at each layer. It computes the gradients for this layer's adapter, ∂E/∂L1\partial E/\partial \mathbf{L}_1 and ∂E/∂L2\partial E/\partial \mathbf{L}_2, which the optimizer uses to update them. And it computes the gradient with respect to the layer's input, ∂E/∂X\partial E/\partial \mathbf{X}, which the layer below needs for its own adapter. That input gradient is ∂E/∂Y\partial E/\partial \mathbf{Y} multiplied by W⊤\mathbf{W}^\top (plus the adapter's term), so the 4-bit weight is dequantized again on the backward pass. The weight gradient ∂E/∂W\partial E/\partial\mathbf{W} is never formed, because W\mathbf{W} is never updated. This is also why no straight-through estimator or other trick for differentiating through rounding is needed: the rounding was applied once, when the model was loaded, and no later computation needs its derivative.

Figure 6 shows the two paths. Toggle to the backward pass to see the gradient update the adapter and pass through, but not into, the frozen weight.

Figure 6 · one QLoRA layer
two paths, summed
The input X feeds two paths that are summed: the frozen base W, stored in 4-bit NF4 and dequantized to BF16 for its matmul, and the trainable adapter in BF16. On the backward pass the adapter is updated and the gradient only passes through W on its way to X; W receives no weight gradient.

Continuing the LLaMA 7B example: the 4096×40964096\times4096 query projection is 33.6 MB in 16-bit and 8.7 MB in NF4 with double quantization, with 262,144 block scales (one per 64 weights). Its rank-64 adapter is 1 MB in BF16 and is the only part of the layer with a gradient and optimizer state. In code, with the gradient written out by hand:

# one QLoRA linear layer.  storage: 4-bit NF4.  compute: bf16.
def forward(x, W_nf4, c1, c2, L1, L2, s):     # x, L1, L2 are bf16
    W = double_dequant(c1, c2, W_nf4)         # 4-bit -> bf16, on the fly
    return x @ W + s * (x @ L1) @ L2           # frozen base + adapter

def backward(dy, x, W_nf4, c1, c2, L1, L2, s):
    W = double_dequant(c1, c2, W_nf4)         # dequantize again for dx
    dx  = dy @ W.T + s * (dy @ L2.T) @ L1.T    # passes THROUGH frozen W
    dL1 = s * x.T @ (dy @ L2.T)                # only the adapter gets
    dL2 = s * (x @ L1).T @ dy                  # gradients; dW is never formed
    return dx, dL1, dL2

double_dequant is called in both forward and backward, and backward returns no dW, so per training step the base is read twice and never written.

Paged optimizers

With the base at 33.5 GB and the adapter's weights, gradients and Adam state at about 9.6 GB (our estimate for 800 million adapter parameters at 12 bytes each), a 65B QLoRA run on a 48 GB card has roughly 5 GB left for activations. That is enough on average, because gradient checkpointing keeps only a few saved activations on the forward pass and recomputes the rest during the backward pass. The recomputation comes in bursts, though, and a mini-batch with a long sequence produces a large burst. One such burst past 48 GB ends the run with an out-of-memory error, even if every other step fits.

Paged optimizers handle the bursts with NVIDIA unified memory, which lets the GPU and CPU share an address space and moves pages between them on demand, as an operating system swaps RAM pages to disk. QLoRA allocates the optimizer state in this paged memory. Adam's moments are not touched during the forward and backward passes, so when the GPU runs out, those pages are evicted to CPU RAM; they are paged back in for the optimizer update step, by which time the activations have been freed. The footprint during normal steps is unchanged; during a burst, optimizer pages move to the CPU instead of the run crashing.

Figure 7 runs eight training steps on a 48 GB card with the sizes above. Step 6 holds a long sequence. Play it with the regular optimizer, then with the paged one, and watch the CPU lane under the axis during step 6.

Figure 7 · paging optimizer state during a memory spike
step 8
GPU memory across eight steps of a 65B QLoRA run: 4-bit base, adapter, Adam state and activations (illustrative sizes). The regular optimizer stops at the step-6 burst. The paged optimizer moves part of the Adam state to CPU RAM (below the axis) during the burst and back for the update. Play, scrub, or switch.

The paper does not measure paging overhead in detail, because paging happens only on rare long-sequence mini-batches; for 65B models on 48 GB GPUs at batch size 16 it found the same training speed as with regular optimizers. It states that paged optimizers are needed for 33B on a single 24 GB GPU and 65B on a single 48 GB GPU; its memory appendix notes that the 33B model "does not quite fit" into 24 GB without them.

The training recipe

The paper's settings (App. B.2) are the same for every dataset apart from batch size and step count: NF4 with double quantization, BF16 compute, LoRA r=64r=64 and α=16\alpha=16 on all linear layers, LoRA dropout 0.1 up to 13B and 0.05 for 33B and 65B, Adam with β2=0.999\beta_2=0.999, gradient norm clipped at 0.3, and a constant learning rate of 2×10−42\times10^{-4} for 7B and 13B and 1×10−41\times10^{-4} for 33B and 65B. Group-by-length batching puts examples of similar length together, which reduces padding and makes the loss curve oscillate. The Guanaco runs on OASST1 used batch size 16 for 1,875 steps at every model size. In the Hugging Face stack, which ships bitsandbytes and PEFT support for all three pieces, the recipe is a few configuration objects:

# QLoRA with transformers + peft + bitsandbytes (paper App. B.2 settings, 65B)
bnb = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",               # NormalFloat, not FP4
    bnb_4bit_use_double_quant=True,          # quantize the block scales too
    bnb_4bit_compute_dtype=torch.bfloat16,   # dequantize to bf16 for matmuls
)
model = AutoModelForCausalLM.from_pretrained(name, quantization_config=bnb)
model = prepare_model_for_kbit_training(model)   # turns on grad checkpointing
lora = LoraConfig(r=64, lora_alpha=16, lora_dropout=0.05,   # 0.1 up to 13B
                  target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                                  "gate_proj", "up_proj", "down_proj"])
model = get_peft_model(model, lora)              # s = 16 / 64 = 0.25
args = TrainingArguments(optim="paged_adamw_32bit",   # paged optimizer
                         learning_rate=1e-4,          # 2e-4 for 7B and 13B
                         lr_scheduler_type="constant", max_grad_norm=0.3,
                         adam_beta2=0.999, group_by_length=True, bf16=True)

How 4-bit finetuning compares with 16-bit

Two claims need to hold: NF4 has to be a better 4-bit type than the alternatives, and a model finetuned on a 4-bit base has to reach 16-bit quality.

For the first, the paper quantizes pretrained OPT, BLOOM, LLaMA and Pythia models from 125M to 13B parameters and measures perplexity on Pile Common Crawl, a measure of how well the model predicts held-out text where lower is better. Averaged over models: Int4 34.34, FP4 with 2 exponent bits (E2M1) 31.07, FP4 with 3 exponent bits (E3M0) 29.48, and NF4 with double quantization 27.41. NF4 comes out best here, as it did in Figure 3. Int4 and FP4 swap places, though: on Figure 3's bell Int4 rounds slightly more accurately than FP4, but in the full models both FP4 variants give lower perplexity than Int4.

For the second, Figure 8 plots 5-shot accuracy on MMLU, a multiple-choice exam over 57 subjects where "5-shot" means five solved examples are placed in the prompt, for LLaMA 7B to 65B finetuned with LoRA on Alpaca and on FLAN v2. Only the data type of the frozen base differs between the three lines: BF16, FP4, or NF4 with double quantization, with identical adapters.

Figure 8 · 4-bit recovers 16-bit
NF4 gap to 16-bit: -0.2
5-shot MMLU against LLaMA size, averaged over the Alpaca and FLAN v2 finetunes (Table 4). All three use 16-bit LoRA adapters; only the frozen base's data type changes. BF16 is the target, NF4 + DQ tracks it, FP4 sits lower at 7B and 33B. Drag the size to read the gaps.

Over all eight runs the means are 53.0 for BF16, 53.1 for NF4 with double quantization and 52.2 for FP4. The paper summarizes FP4 as about one percentage point behind and NF4 as fully recovering 16-bit LoRA. The FP4 gap is largest at 7B (1.2 points on Alpaca, 1.6 on FLAN v2) and 33B (1.8 and 2.0); at 65B on FLAN v2 FP4 scores 63.3 against BF16's 62.5.

The comparison in Figure 8 is against 16-bit LoRA, not against full finetuning. Full 16-bit finetuning, where every weight is trained, was replicated only on RoBERTa-large (GLUE) and on T5 models from 80M to 3B parameters (Super-NaturalInstructions); there, 16-bit, 8-bit and 4-bit adapters all matched it. Full finetuning at 11B and above needs more than one server of GPUs, so at 7B to 65B the paper tests 4-bit QLoRA against 16-bit LoRA, and its limitations section states that it did not establish parity with full 16-bit finetuning at 33B and 65B. The abstract's "while preserving full 16-bit finetuning task performance" is stronger than what the body shows at those sizes.

Guanaco and the chatbot evaluation

Guanaco is LLaMA finetuned with QLoRA on OASST1, the OpenAssistant conversation dataset, keeping only the top-ranked reply at each level of each conversation tree: 9,209 examples. Training is ordinary supervised learning with a cross-entropy loss. There is no reinforcement learning from human feedback (the reward-model stage of InstructGPT and of learning from human preferences). The paper includes an RLHF model for comparison: Open Assistant, a LLaMA 33B trained with RLHF on the same OASST1 data.

The main benchmark is the Vicuna set of 80 prompts. GPT-4 scores ChatGPT's answer and the model's answer out of ten each, and the model's score is reported as a percentage of ChatGPT's, averaged over both orders of presentation. Table 6 of the paper:

99.3% is below ChatGPT, since the relative score can exceed 100% when a model outscores ChatGPT. In the Elo tournament judged by GPT-4 (models play pairwise matches and win rates become chess-style ratings), Guanaco 65B is ahead of ChatGPT on the Vicuna prompts, 1022 to 966. On the Open Assistant (OA) benchmark, 953 prompts built from every user message in the OASST1 validation conversations, it is behind, 1008 to 1015. The confidence intervals are wide and many models overlap, so "close to ChatGPT" describes the result better than "beats ChatGPT".

The paper also measures the evaluation itself. GPT-4 favors whichever response appears first in the prompt: for Guanaco 65B the score is 96.7% with ChatGPT's answer first and 101.9% with Guanaco's first. It favors its own outputs, rating GPT-4 at Elo 1348 where human raters give 1176, about 20% more win probability. Human raters agree with each other moderately (Fleiss κ=0.42\kappa=0.42), and GPT-4 agrees with the human majority less at the level of single examples (κ=0.25\kappa=0.25). At the level of whole systems the rankings agree better: Kendall τ=0.43\tau=0.43, Spearman 0.55.

On data, a 9k-example dataset (OASST1) produced a better chatbot than a 450k-example subsample of FLAN v2. FLAN v2 gave the best MMLU scores and the worst Vicuna scores: Guanaco 65B reaches 99.3% where the FLAN v2 65B finetune reaches 48.4%. The paper concludes that strong MMLU performance does not imply strong Vicuna performance, or the reverse.

Provenance Verified against primary literatureHow we verify
LoRA (Hu et al., 2021)The frozen base plus trainable low-rank adapter that QLoRA quantizes. The zero-initialized L2 is LoRA and PEFT convention; the QLoRA paper does not describe initialization.
Quantile quantization (Dettmers et al., 2022)Equal-mass bins from the 8-bit optimizers paper; NF4 fixes the target distribution to a normal.
LLM.int8() / SmoothQuant / GPTQ (2022)Inference-time quantization. SwitchBack (Wortsman et al., 2023) is the one prior study of backpropagation through quantized weights beyond 1B parameters, and it is 8-bit.
bitsandbytes functional.py:938-940, 747-748Double quantization in code: subtract one mean over all of a tensor's block scales, quantize the result in blocks of 256 with the library's 8-bit dynamic data type, add the mean back on dequantization. The paper calls this format 8-bit floats.
QLoRA App. B.2r = 64, alpha = 16, adapters on all linear layers, dropout 0.1 up to 13B and 0.05 for 33B/65B, constant learning rate 2e-4 (7B/13B) or 1e-4 (33B/65B), max grad norm 0.3, Adam beta2 0.999, group-by-length batching.
This page, Figures 1 and 7Adapter sizes are our estimate from LLaMA dimensions (about 800M adapter parameters at 65B, 12 bytes each to train). Figure 7's activation sizes are illustrative.
correctionThe paper's equation for the 16 NF4 values, (3) here and (4) in the paper, cannot be evaluated as written: its first and last terms are the 0th and 100th percentiles of a normal, which are minus and plus infinity. The published values (App. E) come from bitsandbytes create_normal_map, which takes 8 positive and 7 negative quantiles between 0.5 and an offset of 0.9677083, adds an exact zero, and divides by the largest value so the ends sit at -1 and +1. That procedure reproduces App. E to about 1e-7, and this page teaches it. The function's docstring says "8 negative and 9 positive"; its code builds 7 and 8.

Questions you might still have

?

If NF4 is "information-theoretically optimal," is it the best possible 4-bit type?
Not by rounding error. "Optimal" here means maximum entropy: equal-mass bins make all 16 codes equally likely, so each stored code carries a full 4 bits. The quantizer that minimizes rounding error (Lloyd-Max) puts codes at bin means and does not use equal-mass bins. In practice NF4 bins hold between 2% and 9% of a block's weights rather than 6.25% each, and Yoshida (2023) argues that this helps by keeping precision on rare large weights.

?

Is the base model updated during QLoRA training?
No. The 4-bit base is dequantized to BF16 on every forward pass and again on every backward pass, so the gradient can pass through it to the adapters in earlier layers, but its own weight gradient is never computed and its stored values never change. Only the LoRA adapters are trained.

?

Does QLoRA match full 16-bit finetuning at 65B?
Not shown. Parity with full finetuning was replicated up to 3B parameters (RoBERTa-large and T5). At 7B to 65B, 4-bit QLoRA matches 16-bit LoRA, adapters on a 16-bit base, which isolates the effect of the 4-bit data type. The paper's limitations section says parity with full finetuning at 33B and 65B was not established.

?

Did Guanaco beat ChatGPT?
Close, not decisively. Its 99.3% Vicuna score is just under ChatGPT. It is ahead on the GPT-4-judged Elo for the Vicuna prompts (1022 to 966) and behind on the Open Assistant benchmark (1008 to 1015). The intervals are wide, and GPT-4 as a judge favors whichever answer comes first and its own outputs.

?

How is QLoRA different from LoRA, and from inference quantization like SmoothQuant?
LoRA freezes the base and trains an adapter but keeps the base in 16-bit, 130 GB for a 65B model. QLoRA stores that frozen base in 4-bit NF4, about 33.5 GB. SmoothQuant and LLM.int8() quantize a finished model for faster inference, including its activations; QLoRA quantizes only the weights, converts them to BF16 before every matmul, and trains through them. The LoRA and SmoothQuant explainers on this site cover those methods.

?

Is QLoRA faster than LoRA?
No. QLoRA saves memory, and every matmul still runs in BF16, with an extra dequantization of each weight on the forward and backward pass. The paper reports no runtime degradation against a 16-bit baseline, and the same speed for paged and regular optimizers on 65B at batch size 16.

?

Why not quantize the base to 8 bits instead?
An 8-bit LLaMA 65B is 65 GB, over a single 48 GB card. 4-bit NF4 with double quantization is about 33.5 GB, and after finetuning it matches the 16-bit base on MMLU, so 8 bits would cost memory without a measured gain.

Footnotes & further reading

  1. The paper: Dettmers, Pagnoni, Holtzman, Zettlemoyer, QLoRA: Efficient Finetuning of Quantized LLMs (University of Washington, NeurIPS 2023). Code and bitsandbytes.
  2. The adapter method it builds on: Hu et al., LoRA: Low-Rank Adaptation of Large Language Models (2021). Our explainer: LoRA.
  3. Block-wise quantile quantization, which NF4 specializes to a fixed normal: Dettmers et al., 8-bit Optimizers via Block-wise Quantization (2022), and the 4-bit inference study, The case for 4-bit precision (2022).
  4. The exact NF4 values come from create_normal_map in bitsandbytes, not from equation (3) literally. On what "information-theoretically optimal" does and does not mean, see Yoshida, NF4 Isn't Information Theoretically Optimal (and that's Good) (2023).
  5. The inference-quantization line QLoRA contrasts with: Dettmers et al., LLM.int8() (2022), and SmoothQuant. The one prior method that also backpropagates through quantized weights beyond 1B parameters is Wortsman et al., Stable and low-precision training (SwitchBack, 2023).
  6. Memory accounting: gradient checkpointing, Chen et al., Training deep nets with sublinear memory cost (2016), and our explainer, gradient checkpointing; the optimizer, Adam; the 16-byte mixed-precision accounting, ZeRO.
  7. Guanaco's data and evaluation: Köpf et al., OpenAssistant Conversations (2023), and the Vicuna GPT-4 evaluation protocol, Vicuna (2023). The base model family: LLaMA.