Cheat sheets

Fine-Tuning with LoRA

Add LoRA adapters, load a 4-bit base for QLoRA, mask SFT labels, train, merge and debug. PyTorch, PEFT and bitsandbytes.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

Tasks#

TaskCode
Add LoRA to a modelmodel = get_peft_model(model, lora_config)
Show trainable sharemodel.print_trainable_parameters()
Load the base in 4-bitBitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4")
Count trainable paramscount_parameters(model)
Save the adapter onlymodel.save_pretrained("./lora-adapter")
Merge the adapter into Wmerge_lora_weights(model)
Skip masked labels in the lossF.cross_entropy(..., ignore_index=ignore_index)
Head-only trainingfreeze_body(model)

From Lesson 11.08, 19.39 code/main.py, 19.38 code/main.py

LoRA path in one layer#

mergeInput xFrozen Wout x inAr x in,Gaussian initBout x r, zeroinitScalealpha / rAddWx + scaled BAxOutput yMerged W'W + (alpha/r)BAmergeInput xFrozen Wout x inAr x in, Gaussian initBout x r, zero initScalealpha / rAddWx + scaled BAxOutput yMerged W'W + (alpha/r) BA

From Lesson 11.08

LoRA from scratch#

class LoRALayer(nn.Module):
def __init__(self, in_features, out_features, rank=8, alpha=16):
super().__init__()
self.scaling = alpha / rankalpha / r
self.A = nn.Parameter(torch.randn(in_features, rank) * (1 / math.sqrt(rank)))
self.B = nn.Parameter(torch.zeros(rank, out_features))BA starts at zero
def forward(self, x):
return (x @ self.A @ self.B) * self.scalingscaled low-rank update
class LinearWithLoRA(nn.Module):
__init__ wraps linear and builds self.lora
for param in self.linear.parameters():
param.requires_grad = Falsefreeze W
def forward(self, x):
return self.linear(x) + self.lora(x)Wx + scaled BAx

From Lesson 11.08, 11.08 code/lora.py

QLoRA with PEFT#

bnb_config = BitsAndBytesConfig(load_in_4bit=True,4-bit base
bnb_4bit_quant_type="nf4",NF4 levels
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True)quantize the scales too
model = AutoModelForCausalLM.from_pretrained("<model>",
quantization_config=bnb_config, device_map="auto")
lora_config = LoraConfig(task_type=TaskType.CAUSAL_LM, r=16,
lora_alpha=32, lora_dropout=0.05,
target_modules=["q_proj", "v_proj"])query and value
model = get_peft_model(model, lora_config)adds A and B
model.save_pretrained("./lora-adapter")10-100MB adapter

From Lesson 11.08

One SFT training step#

1Templateeach pair becomes <INST> instruction <RESP>response.2Tokenizebyte ids plus INST_ID = 256, RESP_ID = 257,PAD_ID = 258.3Collatesft_collate pads each batch to its longestsequence.4Masklabels get -100 on instruction, padding and theboundary.5Forwardthe model sees the full sequence, instructionincluded.6Lossshifted_loss predicts position i+1 withignore_index=-100.7StepAdam updates the body. Exact-match runs everyfifth epoch.

From Lesson 19.39, 19.39 code/main.py

Key formulas#

LoRA forward
y = Wx + BAx with W frozen.
Scaled update
y = Wx + \frac{\alpha}{r} \cdot BAx
Parameter count
rank r trains 2 \cdot r \cdot d parameters instead of d^2.
Example
r=16 on 4096x4096 trains 131,072 of 16,777,216. That is 0.78%.
Merge
W' = W + (\alpha/r) \cdot BA. Same size, no inference overhead.
Full fine-tune memory
8B in fp16 is about 56GB with gradients and Adam states.

From Lesson 11.08, Lesson 10.06

Tips#

  • Try prompt engineering first, then RAG, then fine-tuning.
  • Evaluate every 100 steps on a held-out set. Keep the best checkpoint.
  • Compare base plus prompt against base plus LoRA on 200+ held-out examples.
  • On 800 examples, train the head only with a frozen body.
  • Track raw text loss. A rise above 10-15% means SFT is too aggressive.

From Lesson 11.08, 11.08 outputs/skill-fine-tuning-guide.md, Lesson 19.38, Lesson 10.06

Defaults#

SettingDefaultNote
r16safe start for most tasks
lora_alpha322 x rank, alpha = rank is conservative
lora_dropout0.050.1 below 5K examples
target_modulesq_proj, v_projadd more only if quality is low
QLoRA learning rate2e-4higher than full fine-tuning
LoRA fp16 learning rate5e-5
Full SFT learning rate2e-5Llama 2 Chat, 15x below pre-training
Epochs1-3more risks overfitting

From 11.08 outputs/skill-fine-tuning-guide.md, 11.08 outputs/prompt-lora-advisor.md, Lesson 11.08, Lesson 10.06

Troubleshooting#

SymptomCauseFix
NaN losses with Llama modelspad token not setset the pad token
Loss does not decreaselearning rate too low for LoRAtry 2e-4
Loss falls, eval quality badoverfittingfewer epochs, more dropout, more data
Weak on complex tasksrank too low or wrong targetstry r=32 or add MLP layers
General skills drop after SFTlearning rate too highuse 1e-5 to 5e-5 and 1-3 epochs
Model predicts the instructionno loss maskset -100 on instruction and padding
OOM on long sequencesoptimizer states exceed GPU memoryuse optim="paged_adamw_8bit"

From 11.08 outputs/skill-fine-tuning-guide.md, Lesson 11.08, Lesson 10.06, Lesson 19.39

Abbreviations#

LoRA
Low-Rank Adaptation. Freeze W, train A and B.
QLoRA
Quantized LoRA. 4-bit NF4 base, fp16 adapters.
NF4
Normal Float 4. 16 levels at normal quantiles.
PEFT
Hugging Face library for LoRA, QLoRA, DoRA and IA3.
TRL
Hugging Face trainers for SFT, DPO, GRPO, PPO and ORPO.
SFT
Supervised Fine-Tuning on instruction and response pairs.
ChatML
role format with <|im_start|> and <|im_end|> tokens.
Double quantization
quantizes the per-block scales to fp8.

From Lesson 11.08, Lesson 10.06

Questions#

Why is B zero at init?
BA starts at zero. Training starts from the original behavior.
What does alpha do?
It scales the update by alpha / r, apart from the base learning rate.
Merge or keep separate?
Keep separate to serve many tasks. Merge for one model.
Why mask the instruction?
Unmasked, the model learns to predict the instruction and the response signal gets smaller.
When not to fine-tune?
When a prompt works, when you need facts (use RAG) or below 500 examples.

From Lesson 11.08, Lesson 19.39, 11.08 outputs/skill-fine-tuning-guide.md

Choose a method#

ChoiceUse when
Full fine-tune, about 56GB for 7BVRAM >= 2x model size in fp16
LoRA on fp16 base, about 18GBVRAM >= model size in fp16
QLoRA on 4-bit base, about 6GBVRAM >= model size / 4
r=16multi-domain tasks, instruction following, chat
r=32code generation, complex reasoning, math

From 11.08 outputs/prompt-lora-advisor.md, Lesson 11.08