02 - Jemné doladění transformátorů: LoRA, QLoRA a adaptéry
Předtrénované modely Transformer, jako jsou Llama 3, Mistral, GPT-4 a Claude, mají působivou znalost jazyka a uvažování, ale málokdy jsou připraveni pro použití pro konkrétní úkol. Abychom je přizpůsobili naší doméně, kterou je klasifikace obchodních e-mailů, generování kódu v proprietárním rámci nebo odpovídání na otázky lékařské, potřebujete dolaďování.
Problém je, že tyto modely mají miliardy parametrů: LLaMA 2 jich má 7 miliard v nejmenší verzi, 70 miliard v největší. Úplné doladění na LLaMA-7B vyžaduje asi 28 GB VRAM jen pro hmotnosti v FP32 a totéž pro stavy optimalizátoru Adama (první a druhý moment), plus paměť pro přechody a aktivace. In v praxi potřebujete 4x 80GB A100 pro jeden běh jemného doladění.
V tomto druhém článku seriálu Pokročilé Deep Learning a Edge Deployment, prozkoumáme techniky Parametrově efektivní jemné doladění (PEFT) že umožňují vám přizpůsobit modely s miliardami parametrů za použití zlomku zdrojů. Začneme od problému úplného doladění, poté podrobně rozebereme LoRA, QLoRA, DoRA a Adapter Layers, s plnou implementací v Pythonu pomocí HuggingFace PEFT.
Přehled série
| # | Položka | Soustředit |
|---|---|---|
| 1 | Mechanismus pozornosti v transformátorech | Samostatná pozornost, vícehlavá, kompletní architektura |
| 2 | Jste zde – Doladění pomocí LoRA, QLoRA a adaptérů | Parametrově efektivní jemné doladění |
| 3 | Kvantování modelů | INT8, INT4, GPTQ, AWQ |
| 4 | Prořezávání a komprese | Redukce parametrů, destilace |
| 5 | Destilace znalostí | Učitel-žák, předávání znalostí |
| 6 | Ollama a LLM Local | Lokální inference, optimalizace |
| 7 | Vision Transformer | ViT, DINO, klasifikace obrázků |
| 8 | Edge Deployment | ONNX, TensorRT, mobilní zařízení |
| 9 | NAS a AutoML | Hledání neuronové architektury |
| 10 | Benchmarking a optimalizace | Profilování, metriky, ladění |
Co se naučíte
- protože úplné doladění není udržitelné u modelů s miliardami parametrů
- Kompletní přehled technik PEFT: prefixové ladění, promptní ladění, adaptéry, LoRA
- Matematika LoRA: rozklad na nízké úrovni, škálování pomocí alfa, cílové moduly
- QLoRA: Jak zkombinovat 4bitovou kvantizaci s LoRA pro jemné doladění na spotřebitelských GPU
- DoRA: Rozklad hmotnosti na velikost a směr, který zlepšuje LoRA
- Vrstvy adaptérů: adaptéry s úzkým hrdlem, paralelní adaptéry, fúze adaptérů
- Kompletní praktická implementace s HuggingFace PEFT a SFTTrainer
- Příprava datové sady: formát Alpaca, šablona chatu, formát konverzace
- Ladění hyperparametrů: pořadí, alfa, rychlost učení, velikost dávky
- LoRA vs QLoRA vs DoRA vs úplné doladění srovnání se skutečnými benchmarky
- Hardwarové požadavky a omezení spotřebitelských GPU
1. Problém úplného doladění
Il úplné doladění jde o aktualizaci každý parametry předem trénovaného modelu při trénování na konkrétní datové sadě. Každá váha, od vrstvy vnoření na vrstvy upozorňujících hlav, je modifikován skrz zpětné šíření. Tento přístup fungoval skvěle pro velké modely mírný jako BERT (110 milionů parametrů), ale při škálování na miliardy se stává neudržitelným parametrů.
1.1 Výpočetní náklady
Abychom pochopili, proč je úplné doladění neúnosné, podívejme se na požadavky na paměť pro LLaMA 2 7B:
Úplné jemné doladění paměti (LLaMA 2 7B)
| Komponent | Vzorec | Paměť |
|---|---|---|
| Hmotnosti modelů (FP16) | 7B * 2 bajty | 14 GB |
| Přechody (FP16) | 7B * 2 bajty | 14 GB |
| Stavy optimalizátoru (Adam FP32) | 7B * 4 bajty * 2 (m, v) | 56 GB |
| Aktivace (batch_size=1) | Variabilní | ~8-16GB |
| Celkový | ~92-106 GB |
Žádný spotřebitelský GPU nezvládne 100 GB VRAM. Ani 80GB A100 je málo bez technik, jako je kontrola přechodu a smíšená přesnost. Pro LLaMA 70B mluvíme vyžaduje více než 1 TB paměti.
1.2 Katastrofické zapomínání
Druhým problémem úplného doladění je katastrofální zapomínání (katastrofální zapomnění). Když aktualizujeme všechny parametry na konkrétní datové sadě, model má tendenci zapomínat na znalosti získané během přípravy. Modelka doladěné na právních dokumentech mohou ztratit schopnost generovat Python kód resp odpovědět na otázky z historie.
To se děje proto, že úplné jemné doladění bez rozdílu mění všechny váhy, včetně těch, které kódují obecné jazykové znalosti. V praxi model přepíše své předchozí znalosti novými.
1.3 Úložiště více modelů
Pokud společnost potřebuje přizpůsobit stejný základní model 10 různým úkolům (klasifikace e-mailů, analýza sentimentu, lékařské otázky a odpovědi, generování zpráv atd.), úplné jemné doladění vyžaduje uložení 10 úplných kopií modelu: pro LLaMA 7B, to je 140 GB úložiště. S LoRA, jak uvidíme, každá adaptace vyžaduje pouze 10-50 MB, celkem 100-500 MB.
protože úplné jemné doladění neškáluje
| Problém | Úplné jemné doladění | PEFT (LoRA) |
|---|---|---|
| VRAM pro LLaMA 7B | ~100 GB | ~16-24GB |
| Tažné parametry | 7 000 000 000 | ~4 000 000 (0,06 %) |
| Úložný prostor pro přizpůsobení | 14 GB | 10-50 MB |
| Katastrofální zapomínání | Vysoké riziko | Minimální riziko |
| Požadovaný hardware | 4x A100 80GB | 1x RTX 3090 24GB |
2. Parametrově efektivní jemné ladění (PEFT): Přehled
Techniky PEFT sdílejí základní princip: místo toho aktualizujeme všechny parametry modelu, zmrazíme předem natrénované váhy a trénujeme pouze malá podmnožina dalších parametrů. To drasticky snižuje paměťové nároky, urychluje trénink a zachovává znalost základního modelu.
Taxonomie technik PEFT
| Technika | Kde to funguje | Extra parametry | Výhody |
|---|---|---|---|
| Rychlé ladění | Vstupní vložení | Měkké tokeny předvážené na vstupu | Velmi jednoduché, málo parametrů |
| Ladění prefixů | Každá vrstva pozornosti | Tažné předpony K,V | Výraznější než pohotové ladění |
| Vrstvy adaptéru | Mezi vrstvami Transformátoru | Vložené moduly úzkého hrdla | Flexibilní, modulární |
| LoRA | Stávající váhové matice | Nízké matice B a A | Nulová režie na závěr |
| QLoRA | Jako LoRA + kvantování | LoRA na 4bitovém modelu | Jemné ladění na spotřebitelských GPU |
| DoRA | Jako LoRA + rozklad | Velikost + směr | vynikající kvalita oproti LoRA |
2.1 Rychlé ladění
Il rychlé ladění (Lester et al., 2021) přidává soubor měkké žetony tažné na začátku vstupu. Tyto tokeny neodpovídají skutečným slovům ve slovní zásobě, ale jsou to spojité vektory, které se model učí během tréninku. Základní model zůstává zcela zamrzlé: natrénována jsou pouze vložení měkkých tokenů.
Input originale: [Classify this email: "Meeting at 3pm"]
Con prompt tuning: [T1][T2][T3]...[T20] [Classify this email: "Meeting at 3pm"]
^^^^^^^^^^^^^^^^^
20 soft tokens trainabili
(20 * d_model parametri = 20 * 4096 = 81.920 parametri)
Il modello base (7B parametri) e CONGELATO.
Solo 81.920 parametri vengono aggiornati.
Rychlé ladění funguje překvapivě dobře u velmi velkých modelů (>10B parametry), ale u menších modelů ztrácí na kvalitě. S T5-XXL (11B) je dosaženo rychlého ladění téměř identický výkon s úplným doladěním na SuperGLUE.
2.2 Ladění prefixů
Il ladění předpony (Li & Liang, 2021) rozšiřuje myšlenku rychlého ladění: místo přidávání soft tokenů pouze do vstupu přidává trénovatelné předpony do klíče (K) a hodnoty (V) z každá vrstva pozornosti. To dává model větší expresivní schopnost než jednoduché rychlé ladění.
Prompt Tuning:
Layer 1 Attention: Q=[input], K=[input], V=[input]
Layer 2 Attention: Q=[input], K=[input], V=[input]
Solo soft tokens preposti all'input iniziale.
Prefix Tuning:
Layer 1 Attention: Q=[input], K=[prefix_1 | input], V=[prefix_1 | input]
Layer 2 Attention: Q=[input], K=[prefix_2 | input], V=[prefix_2 | input]
...
Layer L Attention: Q=[input], K=[prefix_L | input], V=[prefix_L | input]
Prefissi trainabili a OGNI layer di attention.
Parametri: L * prefix_len * 2 * d_model (2 per K e V)
Esempio: 32 layer * 20 prefix * 2 * 4096 = 5.242.880 parametri
3. LoRA: Low-Rank Adaptation
LoRA (Hu et al., 2021) a nejpoužívanější a nejreprezentativnější technikou PEFT zlom v dolaďování velkých lingvistických modelů. Klíčová myšlenka je elegantní ve své jednoduchosti: místo přímé aktualizace váhových matic v Transformeru rozložíme aktualizaci na dvě matice nízké úrovně.
3.1 Intuice: Hypotéza vnitřní hodnosti
Výzkum (Aghajanyan et al., 2020) ukázal, že když doladíme na konkrétní úloze jsou aktualizace modelových vah soustředěny v a nízkorozměrný podprostor. Jinými slovy, matice aktualizace hmotnosti má a vnitřní hodnost mnohem nižší než jeho jmenovitá velikost.
Uvažujme hmotnostní matici W o rozměrech d x k (například projekce dotazů v LLaMA 7B pozornost: 4096 x 4096). Kompletní aktualizace by vyžadovalo pole 4096 x 4096 = 16 777 216 parametrů. Ale pokud aktualizace má nízkou vnitřní hodnost, můžeme ji aproximovat mnohem menší hodností r.
3.2 Matematika LoRA
Vzhledem k předem připravené hmotnostní matici W_0 o velikosti d x k, LoRA parametrizuje aktualizace jako produkt dvou nižších matic:
Základní vzorec LoRA
W = W_0 + \Delta W = W_0 + B \cdot A
Kde:
- W_0 \in \mathbb{R}^{d \times k} a předem připravenou (zmrazenou) hmotnostní matrici
- B \in \mathbb{R}^{d \times r} a sestupnou projekční matici
- A \in \mathbb{R}^{r \times k} a vzestupnou projekční matici
- r \ll \min(d, k) e il pořadí (obvykle 4, 8, 16, 32, 64)
S měřítkem: h = W_0 x + \frac{\alpha}{r} \cdot B A x
Kde \alpha a škálovací faktor, který řídí intenzitu adaptace.
Matrice originale W_0 (congelata):
k = 4096
+------------------+
| |
d = | W_0 | 16.777.216 parametri
4096| (CONGELATA) | Non viene aggiornata
| |
+------------------+
Aggiornamento LoRA (trainabile):
r = 16 k = 4096
+-----+ +------------------+
| | | |
d = | B | x r=16 | A |
4096| | | |
| | +------------------+
+-----+
65.536 65.536
B (d x r) A (r x k)
= 4096 * 16 = 16 * 4096
= 65.536 = 65.536
Totale LoRA: 131.072 parametri (0.78% di 16.777.216)
3.3 Inicializace
Inicializace A a B je zásadní. LoRA se inicializuje:
- A s jednotnou inicializací Kaiming (Gaussova distribuce)
- B se všemi nulami
To zajišťuje, že na začátku školení je příspěvek LoRA přesně nulový (B * A = 0), takže model vychází z chování předem trénovaného modelu. Trénink postupně mění B a A, aby se model přizpůsobil konkrétnímu úkolu.
3.4 Měřítko Alfa
Parametr \alpha (alfa) řídí intenzitu adaptace LoRA. Skutečný výstup je:
h = W_0 x + \frac{\alpha}{r} \cdot B A x
Zpráva \alpha / r funguje to jako rychlost učení pro LoRA. V praxi se často koná \alpha = 2r (například \alpha = 32 con r = 16), což má za následek faktor měřítka 2. To vám umožní změnit hodnost, aniž byste museli znovu upravovat rychlost učení.
3.5 Cílové moduly
LoRA se neaplikuje na všechny vrstvy Transformeru, ale pouze na konkrétní matice závaží. Výběr cílových modulů výrazně ovlivňuje kvalitu jemné doladění:
Cílové moduly pro běžné architektury
| Modul | Typ | Rozměry (LLaMA 7B) | Dopad |
|---|---|---|---|
q_proj |
Dotaz na pozornost | 4096 x 4096 | Vysoká – kontroluje, co model „hledá“ |
k_proj |
Klíč pozornosti | 4096 x 4096 | Vysoká – řídí způsob indexování tokenů |
v_proj |
Hodnota pozornosti | 4096 x 4096 | Vysoká – řídí extrahované informace |
o_proj |
Pozor Výstup | 4096 x 4096 | Střední |
gate_proj |
Brána FFN | 4096 x 11008 | Vysoká - řídí tok informací v FFN |
up_proj |
FFN nahoru | 4096 x 11008 | Středně vysoká |
down_proj |
FFN dolů | 11008 x 4096 | Střední |
3.6 Přesný výpočet tažných parametrů
Vypočítáme trénovatelné parametry pro LLaMA 2 7B s LoRA aplikovaným na q_proj a v_proj na všech 32 vrstvách:
LLaMA 2 7B: 32 layer, d_model = 4096
Con r = 16, target_modules = ["q_proj", "v_proj"]:
Per ogni layer:
q_proj LoRA: B (4096 x 16) + A (16 x 4096) = 65.536 + 65.536 = 131.072
v_proj LoRA: B (4096 x 16) + A (16 x 4096) = 65.536 + 65.536 = 131.072
Totale per layer: 262.144
Totale: 32 layer * 262.144 = 8.388.608 parametri (8.4M)
Rapporto: 8.4M / 6.738M (totale LLaMA 7B) = 0.12% dei parametri
Con target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]:
Per ogni layer: 7 moduli * 131.072 (media) = ~917.504
Totale: 32 * 917.504 = ~29.4M parametri = 0.44%
3.7 Výhoda odvozování: nulová režie
Klíčovou výhodou LoRA oproti Adaptérovým vrstvám je to, že neexistuje žádné vyvozování žádná výpočetní režie. Matice LoRA mohou být sloučeny ve váze základního modelu:
W_{merged} = W_0 + \frac{\alpha}{r} \cdot B \cdot A
Po sloučení má model přesně stejnou velikost a rychlost odvození původního modelu, ale s aktualizovanými váhami. To je nemožné s vrstvami adaptérů, které do modelu přidávají trvalé parametry.
4. QLoRA: Kvantovaná LoRA
QLoRA (Dettmers et al., 2023) a rozšíření LoRA, které kombinuje 4bitová kvantizace základního modelu s doladěním LoRA. To vám umožňuje vyladit modely s 65 miliardami parametrů na jediném 48GB GPU, dříve nemožný výsledek.
4.1 Tři inovace QLoRA
QLoRA představuje tři klíčové techniky:
Inovace QLoRA
- 4bitový NormalFloat (NF4): Nový optimalizovaný kvantovaný datový typ pro normálně rozložené závaží. Každá váha je mapována na jednu ze 16 hodnot (4 bity) vybráno pro minimalizaci kvantizační chyby na Gaussově rozdělení. NF4 překonává INT4 a FP4, protože váhy neuronových sítí přibližně následují normální distribuce.
- Dvojité kvantování: Kvantizační konstanty (jedna pro každou blok 64 vah) jsou samy kvantovány na 8 bitů. To šetří peníze dalších 0,37 bitů na parametr, asi 3 GB pro model 65B.
- Stránkované optimalizátory: Použít stránkovanou paměť (sjednocená paměť) GPU NVIDIA pro zvládnutí paměťových špiček během tréninku, pohybu v případě potřeby automaticky stavy optimalizace mezi GPU a CPU.
4.2 Jak NF4 funguje
Kvantování NF4 je založeno na pozorování, že váhy dobře trénovaných neuronových sítí sledují přibližně normální rozdělení s průměrem nula. NF4 dále rozděluje standardní normální rozdělení v 16 intervalech stejné pravděpodobnosti a přiřaďte a každý interval optimální hodnotu, která minimalizuje očekávanou chybu:
INT4 (equispaziato):
Livelli: [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
Problema: molti livelli nelle code (pochi pesi li), pochi al centro (molti pesi li)
NF4 (quantili normali):
Livelli: [-1.0, -0.6962, -0.5251, -0.3949, -0.2844, -0.1848, -0.0911, 0.0,
0.0796, 0.1609, 0.2461, 0.3379, 0.4407, 0.5626, 0.7230, 1.0]
Vantaggio: livelli densi dove ci sono più pesi (vicino a 0)
Risultato: NF4 produce errore di quantizzazione ~2x inferiore a INT4
4.3 Paměťová stopa QLoRA
Porovnání paměti: Full FT vs LoRA vs QLoRA (LLaMA 7B)
| Komponent | Full FT (FP16) | LoRA (FP16) | QLoRA (NF4) |
|---|---|---|---|
| Modelové váhy | 14 GB (FP16) | 14 GB (FP16) | 3,5 GB (NF4) |
| Přechody | 14 GB | ~16 MB | ~16 MB |
| Stavy optimalizátoru | 56 GB | ~64 MB | ~64 MB |
| Aktivace | ~12 GB | ~12 GB | ~6 GB |
| Celkový | ~96 GB | ~26 GB | ~10 GB |
S QLoRA je možné jemné doladění LLaMA 7B na jediném RTX 3090 (24 GB), a LLaMA 13B na jedné RTX 4090 (24 GB) s povoleným přechodem checkpointing.
5. DoRA: Weight-Decomposed Low-Rank Adaptation
DoRA (Liu et al., 2024) a vývoj LoRA, který rozkládá matrici závaží ve dvou složkách: velikost (velikost) e směr (směr). Tento rozklad je inspirován klasikou Weight Normalization od Salimans & Kingma (2016) a jejím cílem je zacelit mezeru v kvalitě mezi LoRA a úplným doladěním.
5.1 Intuice za DoRA
Analýza vzorců učení ukazuje zásadní rozdíl mezi plnými jemné doladění a LoRA: Úplné jemné doladění změní velikost i směr vah nezávisle, zatímco LoRA má tendenci je proporcionálně upravovat, omezuje jeho expresivitu.
5.2 Matematika DoRA
DoRA rozkládá předem trénovanou hmotnostní matici na:
Vzorec DoRA
W' = m \cdot \frac{W_0 + BA}{\|W_0 + BA\|_c}
Kde:
- m \in \mathbb{R}^{1 \times k} a (trénovatelný) vektor velikosti, inicializovaný s normami sloupce W_0
- W_0 + BA představuje aktualizovaný směr přes LoRA
- \|\cdot\|_c a sloupcová norma, která normalizuje každý sloupec na jednotkovou normu
- B e A jsou standardní matice LoRA (trénovatelné)
Tímto způsobem má DoRA dva nezávislé stupně volnosti:
- La směr a ovládané B a A (přesně jako v LoRA)
- La velikost a řízena vektorem m, který se může měnit bez ohledu na směr
5.3 Výhody DoRA oproti LoRA
Benchmark DoRA vs LoRA (rozumné uvažování, LLaMA-7B)
| Úkoly | LoRA (r=32) | DoRA (r=32) | Kompletní FT |
|---|---|---|---|
| BoolQ | 69,8 | 71,8 | 73,2 |
| PIQA | 82,1 | 83,2 | 83,9 |
| WinoGrande | 79,4 | 80,6 | 81,5 |
| HellaSwag | 83,6 | 84,4 | 85,1 |
| Průměrný | 78,7 | 80,0 | 80,9 |
DoRA snižuje mezeru mezi LoRA a úplným doladěním přibližně o 60–70 %, s režií minimálních parametrů (pouze dodatečný vektor m).
6. Vrstvy adaptéru
The Vrstvy adaptéru (Houlsby et al., 2019) byli mezi prvními navrhované techniky PEFT. Myšlenka je jednoduchá: vložte malé tažné moduly (adaptér) mezi stávajícími vrstvami Transformátoru při zachování původní váhy.
6.1 Adaptéry pro úzké hrdlo
Klasický adaptér a modul úzké místo se třemi složkami:
- Projekce dolů: zmenší velikost z d_model na d_bottleneck (např. 4096 -> 64)
- Nelinearita: typicky ReLU nebo GELU
- Up-projekce: obnoví původní velikost (např. 64 -> 4096)
- Zbytkové připojení: výstup adaptéru se přidá ke vstupu
Input x (dimensione d_model = 4096)
|
+----> Down-proj: W_down (4096 x 64) --> h (dimensione 64)
| |
| Non-linearita (GELU)
| |
| Up-proj: W_up (64 x 4096) <------+
| |
+------- (+) ----+ Residual Connection
|
Output (dimensione 4096)
Parametri per adapter: (4096 * 64) + (64 * 4096) = 524.288
Con 2 adapter per layer, 32 layer: 2 * 32 * 524.288 = 33.5M parametri
6.2 Srovnání: Adaptéry vs LoRA
Adaptéry vs LoRA: Klíčové rozdíly
| Charakteristický | Vrstvy adaptéru | LoRA |
|---|---|---|
| Režie při vyvozování | Ano (další vrstvy) | Ne (sloučení ve váhách) |
| Další latence | ~5-10% nárůst | 0% |
| Složitelnost | Vysoká (adaptér Fusion) | Průměr (součet LoRA) |
| Snadná implementace | Vysoký | Vysoký |
| Podpora knihovny | AdapterHub, PEFT | PEFT, unsloth, axolotl |
7. Praktická implementace s HuggingFace PEFT
Pojďme k praxi. V této části budeme implementovat jemné doladění modelu Transformer využívající LoRA a QLoRA s knihovnou HuggingFace PEFT. Použijeme Mistral 7B jako základní model a přizpůsobíme jej pro úlohu instrukce-odezva.
7.1 Nastavení a instalace
# Installazione delle librerie necessarie
# pip install torch transformers peft trl datasets accelerate bitsandbytes
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
)
from peft import (
LoraConfig,
get_peft_model,
prepare_model_for_kbit_training,
TaskType,
)
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
# Verifica GPU disponibile
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"VRAM: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB")
print(f"PyTorch: {torch.__version__}")
print(f"CUDA: {torch.version.cuda}")
7.2 Konfigurace LoRA
# Configurazione LoRA per Mistral 7B
lora_config = LoraConfig(
# Rango della decomposizione low-rank
# Valori tipici: 4 (minimo), 8 (buono), 16 (ottimo), 32 (alto), 64 (massimo)
r=16,
# Alpha: fattore di scaling. Il peso effettivo e alpha/r.
# Regola pratica: alpha = 2 * r
lora_alpha=32,
# Dropout applicato ai layer LoRA durante il training
# Aiuta a prevenire l'overfitting, specialmente con dataset piccoli
lora_dropout=0.05,
# Moduli del Transformer a cui applicare LoRA
# Per Mistral/LLaMA: q_proj, k_proj, v_proj, o_proj (attention)
# gate_proj, up_proj, down_proj (FFN)
target_modules=[
"q_proj", # Query projection - impatto alto
"k_proj", # Key projection - impatto alto
"v_proj", # Value projection - impatto alto
"o_proj", # Output projection - impatto medio
"gate_proj", # FFN gate - impatto alto
"up_proj", # FFN up projection - impatto medio-alto
"down_proj", # FFN down projection - impatto medio
],
# Tipo di task
task_type=TaskType.CAUSAL_LM,
# Bias: "none" (consigliato), "all", "lora_only"
bias="none",
)
# Stampa riepilogo configurazione
print(f"Rank: {lora_config.r}")
print(f"Alpha: {lora_config.lora_alpha}")
print(f"Scaling: {lora_config.lora_alpha / lora_config.r}")
print(f"Target modules: {lora_config.target_modules}")
print(f"Dropout: {lora_config.lora_dropout}")
7.3 Jemné doladění pomocí LoRA (FP16)
model_name = "mistralai/Mistral-7B-v0.3"
# Caricamento tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# Caricamento modello in FP16
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto", # Distribuzione automatica su GPU disponibili
attn_implementation="flash_attention_2", # Flash Attention per efficienza
)
# Applica LoRA al modello
model = get_peft_model(model, lora_config)
# Mostra parametri trainabili
model.print_trainable_parameters()
# Output: trainable params: 27,262,976 || all params: 7,268,633,600 || trainable%: 0.375%
# Configurazione training
training_args = SFTConfig(
output_dir="./results/mistral-lora",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # Effective batch size: 4 * 4 = 16
gradient_checkpointing=True, # Risparmia VRAM scambiando con tempo
optim="adamw_torch",
learning_rate=2e-4, # LR più alto rispetto al full FT
lr_scheduler_type="cosine",
warmup_ratio=0.03, # 3% degli step come warmup
weight_decay=0.001,
max_grad_norm=0.3,
logging_steps=10,
save_strategy="steps",
save_steps=100,
max_seq_length=2048,
fp16=True,
report_to="wandb", # Logging su Weights & Biases
seed=42,
)
7.4 Jemné ladění pomocí QLoRA (4bitové)
# Configurazione quantizzazione 4-bit (QLoRA)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # Carica pesi in 4-bit
bnb_4bit_quant_type="nf4", # NormalFloat 4-bit (migliore di INT4)
bnb_4bit_compute_dtype=torch.bfloat16, # Compute in BF16 (più stabile di FP16)
bnb_4bit_use_double_quant=True, # Double quantization (risparmia ~0.4 bit/param)
)
# Caricamento modello quantizzato
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
attn_implementation="flash_attention_2",
)
# Prepara il modello per il training k-bit
# Questo congela i pesi quantizzati e prepara i layer per LoRA
model = prepare_model_for_kbit_training(
model,
use_gradient_checkpointing=True,
)
# Applica LoRA (stessa configurazione di prima)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Output: trainable params: 27,262,976 || all params: 3,778,682,880 || trainable%: 0.721%
# Nota: il modello base ora occupa ~3.8GB invece di ~14GB
# Configurazione training QLoRA
training_args = SFTConfig(
output_dir="./results/mistral-qlora",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
gradient_checkpointing=True,
optim="paged_adamw_8bit", # Paged optimizer per gestire picchi di memoria
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
weight_decay=0.001,
max_grad_norm=0.3,
logging_steps=10,
save_strategy="steps",
save_steps=100,
max_seq_length=2048,
bf16=True, # BF16 per il compute (più stabile)
report_to="wandb",
seed=42,
)
8. Příprava datové sady
Kvalita doladění nesmírně závisí na kvalitě datové sady. V tomto Podívejme se, jak připravit data ve standardních formátech používaných pro jemné doladění společnosti LLM.
8.1 Formát alpaky
Formát alpaky (Stanford, 2023) je jedním z nejoblíbenějších pro jemné ladění LLM o úkolech s pokyny a odezvou. Každý příklad má tři pole:
def format_alpaca(example):
"""Converte un esempio nel formato Alpaca per il fine-tuning."""
if example.get("input", ""):
# Con input aggiuntivo
text = (
f"### Instruction:\n{example['instruction']}\n\n"
f"### Input:\n{example['input']}\n\n"
f"### Response:\n{example['output']}"
)
else:
# Solo istruzione e risposta
text = (
f"### Instruction:\n{example['instruction']}\n\n"
f"### Response:\n{example['output']}"
)
return {"text": text}
# Caricamento dataset
dataset = load_dataset("tatsu-lab/alpaca", split="train")
dataset = dataset.map(format_alpaca)
# Esempio di output formattato
print(dataset[0]["text"])
# ### Instruction:
# Give three tips for staying healthy.
#
# ### Response:
# 1. Eat a balanced and nutritious diet...
# 2. Exercise regularly...
# 3. Get enough sleep...
8.2 Šablony chatu (Mistral/ChatML)
Pro konverzační modely je vhodnější formát šablony chatu. Každý model má vlastní specifickou šablonu:
def format_chat_template(example, tokenizer):
"""Formatta l'esempio usando il chat template del modello."""
messages = [
{"role": "system", "content": "Sei un assistente esperto e disponibile."},
{"role": "user", "content": example["instruction"]},
{"role": "assistant", "content": example["output"]},
]
# Applica il chat template del tokenizer
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=False,
)
return {"text": text}
# Formato risultante per Mistral:
# <s>[INST] Sei un assistente esperto. [/INST]
# [INST] Give three tips for staying healthy. [/INST]
# 1. Eat a balanced diet...</s>
# Per ChatML (usato da molti modelli):
# <|im_start|>system
# Sei un assistente esperto.<|im_end|>
# <|im_start|>user
# Give three tips for staying healthy.<|im_end|>
# <|im_start|>assistant
# 1. Eat a balanced diet...<|im_end|>
8.3 Školení s SFTTrainer
from trl import SFTTrainer
# Dataset formattato
dataset = load_dataset("tatsu-lab/alpaca", split="train")
dataset = dataset.map(
lambda x: format_chat_template(x, tokenizer)
)
# Split train/eval
dataset = dataset.train_test_split(test_size=0.05, seed=42)
# Creazione trainer
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
)
# Avvio training
trainer.train()
# Salvataggio adattatore LoRA (solo ~50MB)
trainer.save_model("./results/mistral-qlora/final")
tokenizer.save_pretrained("./results/mistral-qlora/final")
9. Sloučení hmotnosti a nasazení
Po tréninku máme zmrazený základní model a malý adaptér LoRA. Pro nasazení můžeme tyto dva ponechat oddělené (užitečné pro přepínání mezi různé úpravy) nebo je sloučit do jednoho modelu.
9.1 Sloučení závaží LoRA do základního modelu
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
# Caricamento modello base (FP16 per il merge)
base_model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.3",
torch_dtype=torch.float16,
device_map="auto",
)
# Caricamento adattatore LoRA
model = PeftModel.from_pretrained(
base_model,
"./results/mistral-qlora/final",
)
# Merge LoRA nei pesi base
# Dopo il merge: W_merged = W_0 + (alpha/r) * B * A
model = model.merge_and_unload()
# Salvataggio modello merged
model.save_pretrained("./models/mistral-7b-finetuned")
tokenizer.save_pretrained("./models/mistral-7b-finetuned")
# Upload su HuggingFace Hub
model.push_to_hub("username/mistral-7b-finetuned")
tokenizer.push_to_hub("username/mistral-7b-finetuned")
print("Modello merged e caricato su HuggingFace Hub!")
9.2 Inference s jemně vyladěným modelem
from transformers import pipeline
# Pipeline di generazione
pipe = pipeline(
"text-generation",
model="./models/mistral-7b-finetuned",
torch_dtype=torch.float16,
device_map="auto",
)
# Generazione
messages = [
{"role": "system", "content": "Sei un assistente esperto di programmazione."},
{"role": "user", "content": "Spiega il pattern Repository in Python."},
]
output = pipe(
messages,
max_new_tokens=512,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
print(output[0]["generated_text"][-1]["content"])
10. Ladění hyperparametrů
Volba hyperparametrů je zásadní pro dosažení dobrých výsledků. Tady je návod praxe založená na zkušenostech komunity a publikovaných benchmarkech.
Průvodce hyperparametry LoRA
| Hyperparametr | Rozsah | Poradil | Poznámky |
|---|---|---|---|
| hodnost (r) | 4-256 | 16-64 | Zvýšení pro složité úkoly; r=8 často postačuje pro klasifikaci |
| alfa | 8-128 | 2 * pořadí | alpha/r a efektivní škálování; udržovat poměr konstantní při změně r |
| rychlost_učení | 1e-5 - 5e-4 | 2e-4 | Vyšší než plná FT (10-100x); snížit, pokud ztráta kolísá |
| velikost_dávky | 1-32 | 4-8 | Použijte gradient_accumulation k simulaci větších dávek |
| epochách | 1-5 | 2-3 | Pozor na nadměrné vybavení; sledovat ztrátu eval |
| warmup_ratio | 0,01-0,1 | 0,03 | Důležité pro stabilitu; vyšší s vysokým LR |
| odpadnutí | 0,0-0,1 | 0,05 | 0,0 pro velké datové sady, 0,1 pro malé datové sady |
| max_seq_length | 512-8192 | 2048 | Vyšší = více VRAM; přizpůsobit datové sadě |
Časté chyby při jemném ladění
- Příliš vysoká rychlost učení: ztráta kolísá nebo se liší. Řešení: Snižte LR 2-5x nebo zvyšte zahřívání
- Příliš nízké hodnocení: model se dostatečně neučí. Řešení: Zvyšte r z 8 na 16 nebo 32
- Příliš vysoké hodnocení: nadměrné vybavení, zejména u malých souborů dat. Řešení: Snižte r nebo zvyšte výpadek
- Několik epoch: podvybavení. Zkontrolujte, zda ztráta eval nadále klesá
- Příliš mnoho epoch: tréninková ztráta klesá, ale eval ztráta stoupá (přetažení)
- Nevyčištěná datová sada: duplikáty, chyby, nekonzistentní formátování snižují kvalitu
- Zapomeňte na přechodové kontrolní body: Okamžité OOM na velkých modelech
11. Benchmarky a srovnání
Jak si vybrat mezi LoRA, QLoRA, DoRA a úplným doladěním? Zde je systematické srovnání na základě veřejných benchmarků a komunitního testování.
Úplné srovnání: LoRA vs QLoRA vs DoRA vs Full FT
| Metrický | Kompletní FT | LoRA | QLoRA | DoRA |
|---|---|---|---|---|
| kvalita (MT-Bench) | 7.8 | 7.5 | 7.3 | 7.6 |
| VRAM (model 7B) | ~100 GB | ~26 GB | ~10 GB | ~26 GB |
| Rychlost tréninku (rel.) | 1,0x | 1,2x | 0,8x | 1,1x |
| Tažné parametry | 100 % | 0,1–0,5 % | 0,1–0,5 % | 0,1-0,5 % + t.t |
| Přizpůsobení úložiště | 14 GB | 10-50 MB | 10-50 MB | 10-50 MB |
| Inference nad hlavou | 0% | 0 % (sloučeno) | 0 % (sloučeno) | 0 % (sloučeno) |
| Minimální GPU (7B) | 4x A100 | 1x A100 40GB | 1x RTX 3090 | 1x A100 40GB |
12. Hardwarové požadavky
Výběr hardwaru závisí na modelu, který chcete doladit, a technice PEFT které používáte. Zde je praktický průvodce pro spotřebitelské a profesionální GPU.
Požadavky na GPU pro jemné ladění
| GPU | VRAM | LoRA (FP16) | QLoRA (4bitová) | Poznámky |
|---|---|---|---|---|
| RTX 3060 | 12 GB | až 3B | až 7B (seq 512) | Vstupní úroveň, omezená |
| RTX 3090 | 24 GB | až 7B | až 13B | Vynikající pro QLoRA 7B |
| RTX 4090 | 24 GB | až 7B | až 13B | Rychlejší než 3090, stejná VRAM |
| A100 40 GB | 40 GB | až 13B | až 34B | Profesionální standard |
| A100 80 GB | 80 GB | až 30B | až 70B | Ideální pro velké modely |
| H100 80 GB | 80 GB | až 30B | až 70B | Rychlejší než A100, podpora FP8 |
Tipy pro uživatele GPU
- Omezený rozpočet (RTX 3060 12GB): QLoRA na modelech 7B s seq_length=512, batch_size=1, gradient_accumulation=16
- Dobrý poměr kvalita/cena (RTX 3090/4090 24GB): QLoRA na modelech 7-13B s seq_length=2048, batch_size=4
- Cloud computing: Google Colab Pro (10 USD/měsíc) nabízí A100 40 GB pro omezené relace; RunPod a Lambda Labs pro náročné použití
- Vždy aktivovat: gradient_checkpointing=Pravda, stránkované optimalizátory, Flash Attention 2
13. Praktické případy použití
Podívejme se na některé konkrétní případy použití, kdy je jemné doladění pomocí LoRA obzvláště účinné.
13.1 Klasifikace textu
Pro klasifikační úkoly (analýza sentimentu, klasifikace témat, detekce spamu), LoRA je často výhodnější, protože:
- Úloha vyžaduje několik dalších parametrů (stačí r=4-8)
- Klasifikační datové sady jsou obvykle malé (příklady 1 000–50 000)
- Riziko nadměrného vybavení s vysokou a vysokou hodností
13.2 Generování kódu
Pro jemné doladění generování kódu (např. přizpůsobení modelu konkrétnímu jazyku nebo firemní smlouvy), doporučujeme:
- Vyšší hodnost (r=32-64), protože kód má větší strukturu a variabilitu
- Dokončete cílové moduly (všech 7 modulů Transformer)
- Vysoce kvalitní datové sady: dobře zdokumentovaný kód, s testy, konzistentní styl
- Dlouhé sekvence (max_seq_length=4096-8192) pro úplný kontext
13.3 Chatboti pro konkrétní doménu
Chcete-li vytvořit specializovaného chatbota (lékařská, právní, technická podpora):
- Konverzační datová sada ve formátu šablony chatu modelu
- Uveďte příklady odmítnutí („Na tuto otázku nemohu odpovědět“)
- Průměrné hodnocení (r=16–32)
- Ověřování s odborníky na domény, nejen automatické metriky
13.4 Shrnutí
Pro doladění souhrnných úkolů:
- Datový soubor s vysoce kvalitními páry (dokument, shrnutí).
- Dlouhé sekvence pro vstup (až 8192 tokenů)
- Středně vysoká pozice (r=16–32)
- Hodnocení pomocí metrik, jako je ROUGE a lidské hodnocení
14. Závěry a rozhodovací strom
Techniky PEFT zpřístupnily jemné ladění velkých jazykových modelů komukoli se spotřebitelským GPU. LoRA, QLoRA a DoRA představují nejmodernější pro parametricky efektivní jemné doladění, z nichž každý má své vlastní silné stránky.
Rozhodovací strom: Kdy použít co
| Situace | Doporučená technika | Motivace |
|---|---|---|
| GPU s < 16 GB VRAM | QLoRA | Pouze možnost pro modely 7B+ na spotřebním hardwaru |
| GPU s 24-40GB VRAM | LoRA (FP16) | Lepší kvalita než QLoRA, rychlejší trénink |
| Nejvyšší požadovaná kvalita | DoRA | Blíže k plnému FT, minimální režie na LoRA |
| Několik úprav stejného modelu | LoRA | Malé adaptéry (~50 MB), rychlé přepínání mezi úkoly |
| Malý model (< 1B parametrů) | Úplné jemné doladění | U malých modelů je plné FT často proveditelné a lepší |
| Jednoduchý úkol (klasifikace) | LoRA (r=4-8) | Nízká a dostatečná hodnost; vyvarujte se přemontování |
| Složitý úkol (generování kódu) | LoRA/DoRA (r=32-64) | Vysoká hodnost pro zachycení složitosti úkolu |
| Složení dovedností | Adaptér Fusion | Kombinujte více úprav strukturovaným způsobem |
Oblast efektivního a rychle se vyvíjejícího jemného ladění. Nové techniky jako Habaděj (Gradient Low-Rank Projection) e ReLoRA (iterativní trénink LoRA s rostoucím hodnocením) slibují další snížení mezera s úplným doladěním. Standardem však dnes zůstávají LoRA a QLoRA de facto pro doladění LLM s vyspělým ekosystémem knihoven (HuggingFace PEFT, Unsloth, Axolotl) a aktivní komunita.
V dalším článku série prozkoumáme Kvantování modelů: GPTQ, AWQ, INT8 a jak zmenšit velikost modelu o 75 % při zachování kvality pro produkční nasazení.
Zdroje a reference
- LoRA papíry: „LoRA: Low-Rank Adaptation of Large Language Models“ (Hu et al., 2021)
- Papíry QLoRA: „QLoRA: Efficient Finetuning of Quantized LLMs“ (Dettmers et al., 2023)
- Papír DoRA: „DoRA: Weight-Decomposed Low-Rank Adaptation“ (Liu et al., 2024)
- Papírové adaptéry: „Parameter-Efficient Transfer Learning“ (Houlsby et al., 2019)
- HuggingFace PEFT: https://github.com/huggingface/peft
- Unlenth: https://github.com/unslothai/unsloth (LoRA 2-5x rychlejší)
- TRL (Transformer Reinforcement Learning): https://github.com/huggingface/trl







