Home / Fundamentals / Post-training & Alignment

LoRA, QLoRA and parameter-efficient fine-tuning

The low-rank update and its initialization and scaling, parameter and memory arithmetic, which modules to adapt, QLoRA's 4-bit base, and serving many adapters.

11 min read

LoRA

Freeze the pre-trained weight W ∈ ℝ^{d_out × d_in} and learn a low-rank update:

h = W x + (α / r) · B A x,     A ∈ ℝ^{r × d_in},  B ∈ ℝ^{d_out × r}

Scroll sideways to see the whole diagram.

A LoRA-adapted linear layerComponents: Input x (d_in); W (frozen) (d_out × d_in); A (trainable) (r × d_in · random init); B (trainable) (d_out × r · zero init); h = Wx + (α/r)·BAx (merge: W + (α/r)BA). Flow: Input x to W (frozen); Input x to A (trainable); A (trainable) to B (trainable) (r-dim); W (frozen) to h = Wx + (α/r)·BAx; B (trainable) to h = Wx + (α/r)·BAx (× α/r).Input xd_inW (frozen)d_out × d_inA (trainable)r × d_in · random initB (trainable)d_out × r · zero inith = Wx + (α/r)·BAxmerge: W + (α/r)BAr-dim× α/r
A LoRA-adapted linear layer. The pre-trained weight W stays frozen. A trainable low-rank path projects the input down to r dimensions with A and back up with B; B starts at zero so training begins from the base model. The two paths are summed, and after training BA can be merged into W.
  • Initialization: A random (Gaussian or Kaiming), B = 0, so training starts exactly from the base model.
  • Scaling: α / r keeps the update's magnitude roughly independent of rank, so the learning rate needn't be retuned when changing r (rank-stabilized LoRA uses α / √r).
  • Merging: after training, W' = W + (α/r) B A can be folded into the weights: zero extra inference latency.

Arithmetic

Trainable parameters per adapted matrix: r · (d_in + d_out).

7B model (h = 4096, 32 layers, MLP width 11,008), r = 16:

q, k, v, o (4096 × 4096 each): 4 × 16 × 8192 ≈ 0.52M per layer
gate, up, down (4096 ↔ 11008): 3 × 16 × 15104 ≈ 0.73M per layer
All linear layers: ≈ 1.25M × 32 ≈ 40M parameters (~0.6% of 7B)

Memory: frozen bf16 base (14 GB) + adapters with Adam state (40M × 16 B ≈ 0.64 GB) + activations. Compared with ~112 GB of state for full fine-tuning.

Choices

  • Which modules: adapting all linear layers usually beats attention-only at the same parameter budget.
  • Rank: 8–64 is common; higher ranks for bigger distribution shifts (new domain, new language). LoRA learns less and forgets less than full fine-tuning; for large shifts (e.g. continued pre-training) full fine-tuning often wins.
  • Learning rate: around 10× higher than full fine-tuning (e.g. 1e-4 to 2e-4).

QLoRA

Quantize the frozen base to 4-bit NormalFloat (NF4, levels placed for normally distributed weights), keep LoRA adapters in bf16, and backpropagate through the dequantized base. Additions: double quantization of the scales and paged optimizer states. A 65B model can be fine-tuned on a single 48 GB GPU, with quality close to 16-bit LoRA.

Serving many adapters

Adapters are megabytes, so one base model can serve many tenants or tasks. Batched multi-adapter kernels apply each request's adapter within one batch (S-LoRA/Punica-style), with adapters cached in GPU memory and loaded on demand.

What to remember

  • h = Wx + (α/r)BAx, B initialized to zero, mergeable.
  • Parameters r(d_in + d_out) per matrix; ~0.5% of the model.
  • QLoRA = 4-bit frozen base + bf16 adapters.