Fine-Tuning, and When Not ToLesson 20 of 84

Contents

Fine-Tuning, and When Not To

Lesson 20 of 84. Sign in to keep your place.

Module 3 · Full, LoRA and the parameter-efficient family

What LoRA is actually doing

9 min read

One 4,096 by 4,096 projection, adaptedNumbers storedShare of WFull update16,777,216a full matrix100%every entry free to moveLoRA at r = 16131,072two thin matrices0.78%a reweighting, not new machineryB is initialised to exactly zero, so BA is zero at step one and the model starts as the base model.That is why a LoRA cannot be worse on step one, and why it wants a learning rate ten to twenty timeshigher.
B is initialised to exactly zero, so BA is zero at step one and the model starts as the base model. That is why a LoRA cannot be worse on step one, and why it wants a learning rate ten to twenty times higher.

Figure

A correction, factored

Fine-tuning changes a weight matrix W into W + ΔW. LoRA’s observation is that for adapting a pretrained model to a task, ΔW does not need to be a full matrix. It can be the product of two thin ones.

Text
ΔW = B · A          A is r × k,  B is d × r,  r is small
W' = W + (α/r) · B · A

For a 4,096 × 4,096 projection, W has 16.8 million entries. With r = 16, A has 16 × 4,096 = 65,536 and B has 4,096 × 16 = 65,536, so ΔW is described by 131,072 numbers: 0.78% of the matrix it modifies.

W itself is frozen. It receives no gradient, needs no optimiser state, and can sit in 4-bit quantised form if you like. Only A and B are trained.

The two initialisations, and why they matter

A is initialised with small random values. B is initialised to exactly zero.

That means BA = 0 at step one, so W’ = W: the model at the start of training is bit-for-bit the base model. This is not a detail, it has three consequences you will meet:

  • There is no random perturbation to recover from. A LoRA run cannot make the model worse on step one, which full fine-tuning at a bad learning rate certainly can.
  • The adapter must travel from nothing to something within the run, which is why LoRA wants a learning rate ten to twenty times higher than full fine-tuning.
  • If you initialised both to zero, the gradient of both would be zero forever and nothing would ever train. The asymmetry is load-bearing.

The scaling factor

The α/r term multiplies the adapter’s contribution. The convention exists so that changing r does not silently change the magnitude of the update: double the rank and each individual entry of BA tends to shrink, and dividing by r compensates.

In practice people set α to r or to 2r and treat the pair as one decision. r=16, alpha=32 is the single most common configuration in the wild. The important thing is to know that α and the learning rate push in the same direction (doubling α at a fixed learning rate has an effect very like doubling the learning rate) so do not tune both at once and then wonder which mattered.

Why a low rank is enough

The intuition, which has empirical support and is not a theorem: adapting a pretrained model to a task appears to require far fewer degrees of freedom than the model has parameters. The pretrained weights already contain the representations; the adaptation is a comparatively simple reweighting of what is already there. Measurements of the “intrinsic dimension” of fine-tuning tasks found that surprisingly small subspaces suffice, and LoRA is that observation turned into a method.

The honest flip side: this is exactly why LoRA is poor at adding new capability. A rank-16 correction cannot install a language the base model never saw, or a modality it has no representations for. Low rank is enough when the thing you want is a reweighting, and it is not enough when the thing you want is new machinery. That is the mechanism behind the rule from module one: training teaches shape, not substance.

Seeing it in code

Python
from peft import LoraConfig, get_peft_model

cfg = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
                 target_modules=["q_proj","k_proj","v_proj","o_proj",
                                 "gate_proj","up_proj","down_proj"],
                 task_type="CAUSAL_LM")
model = get_peft_model(base, cfg)
model.print_trainable_parameters()
# trainable params: 41,943,040 || all params: 8,072,204,288 || trainable%: 0.5196

Run print_trainable_parameters() on every configuration before you launch. If it prints 0, your target_modules names do not match the architecture and you are about to train nothing for three hours: a failure that produces a perfectly flat, perfectly innocent-looking loss curve.

What you end up with

The artefact on disk is those A and B matrices: roughly 160 MB in bf16 for the 42M-parameter configuration above, against 16 GB for the base model. You can keep a dozen of them for different tasks, swap them at serving time, and email one to a colleague.

At inference you have a choice. Keep them separate and pay a small overhead for the extra matrix multiplications, or merge them: compute W + (α/r)BA once and write out a normal model with no adapter at all. Merging costs nothing at inference and loses the ability to swap. That choice, and what it does to a quantised base, is a lesson of its own later in the course.

Every lesson here is open. Your progress is recorded once you pass the Running Models Yourself exam.

Check your understanding

Why is B initialised to zeros while A gets small random values, rather than both being randomly initialised?

Pick the one you would defend. Your answer stays private.

Next lesson · 9 minChoosing rank, alpha and which modules to touch

Stuck on something?Ask Rafael, your AI tutor

How to cite: Addaly (2026) ‘What LoRA is actually doing’, in Fine-Tuning, and When Not To. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/fine-tuning/what-lora-is-doing (Accessed: 13 October 2026).