Hoppa till innehållet
AI-grafen
F· AI engineeringmodelltraning-finjustering· ca 90 min· volatil — kontrolleras ofta· verifierad 2026-09-20

LoRA — Low-Rank Adaptation

Kunna förklara varför LoRA fungerar (ΔW = BA), välja target modules och rank, finjustera en modell med LoRA och utvärdera med evals.

Förkunskaper

Intuition

Full finjustering av en 7B-modell uppdaterar 7 miljarder vikter och kräver optimizer-tillstånd för alla — ~100 GB. LoRA fryser modellen och lär bara en liten lågrangig uppdatering per matris: W′ = W + ΔW med ΔW = B·A, där A är r × d och B är d × r, r ≪ d (t.ex. 8–64). För d = 4096, r = 16: 131 k parametrar i stället för 16,8 M per matris.

Varför fungerar det? Finjustering ändrar modellen i få riktningar — ΔW har låg «intrinsisk rang». Hypotesen bekräftas empiriskt: LoRA når nära full finjustering på de flesta uppgifter.

Praktiskt: target modules = vilka matriser (q, k, v, o, och ofta även MLP-lagren — det senare hjälper mest när man har budget). α/r skalar uppdateringen; håll α ≈ 2r som start. Efter träning kan BA bakas in i W — noll extra inferenskostnad. QLoRA: basmodellen i 4-bit, LoRA i bf16 → 7B tränas på 8–10 GB GPU.

Mät mot basmodellen och mot full finjustering om möjligt; LoRA med för lågt r underpresterar på uppgifter som kräver ny kunskap.

Kod

from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
import torch

namn = "Qwen/Qwen2.5-1.5B"
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16)
m = AutoModelForCausalLM.from_pretrained(namn, quantization_config=bnb, device_map="auto")
m = prepare_model_for_kbit_training(m)

cfg = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05, task_type="CAUSAL_LM",
                 target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"])
m = get_peft_model(m, cfg)
m.print_trainable_parameters()      # ~1 % av parametrarna

# …vanlig träningsloop / Trainer på instruktionsdata (loss bara på svar), lr ~2e-4, 1–3 epoker…
m.save_pretrained("adapter/")       # bara A, B — några tiotal MB

# inferens: ladda bas + adapter, eller m.merge_and_unload() för att baka in

Labben lora-tiny-labb implementerar LoRA-lagret från grunden i NumPy/PyTorch och verifierar mot referens.

Härledning

Framåt: h=Wx+αrBAxh = Wx + \tfrac{\alpha}{r}BAx. Parametrar: r(din+dout)r(d_{in}+d_{out}) mot dindoutd_{in}d_{out}. Initiering: A∼N(0,σ2)A\sim\mathcal N(0,\sigma^2), B=0B = 0 → ΔW=0\Delta W = 0 vid start, modellen börjar exakt som basen. Gradienter: ∂L/∂B=αr δ (Ax)⊤\partial L/\partial B = \tfrac{\alpha}{r}\,\delta\,(Ax)^\top, ∂L/∂A=αr B⊤δ x⊤\partial L/\partial A = \tfrac{\alpha}{r}\,B^\top\delta\,x^\top där δ=∂L/∂h\delta = \partial L/\partial h — samma δ\delta som full finjustering, men projicerat. Minnesvinsten kommer främst från att optimizer-tillstånd (Adam: 2 × parametrar i fp32) bara behövs för A,BA, B. Rang-valet: effektiv rang av ΔW\Delta W vid full finjustering kan mätas via SVD; empiriskt räcker r∈[4,64]r\in[4, 64] för stil/format, högre för ny faktakunskap. Skalningen α/r\alpha/r gör att inlärningstakten inte behöver justeras när rr ändras (rsLoRA föreslår α/r\alpha/\sqrt r).

Behärskning innebär

  • Förklarar ΔW = BA, rank och skalning α/r
  • Väljer target modules och rank och motiverar
  • Finjusterar med LoRA/QLoRA och utvärderar mot basmodellen och full finjustering

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser