Tüm rehberler
Rehber Yapay Zeka 03 · Eğitim

Fine-tuning
& LoRA.

Büyük modeli sıfırdan eğitmeden görev odaklı ince ayar yap. LoRA matematiğini matris rankından çöz, QLoRA ile 4-bit quantization ve adapter birleştirmeyi öğren.

00 Neden Fine-tuning?

Pre-trained modelin genel bilgisini belirli bir göreve ya da alana yönlendirmenin en etkili yolu.

GPT-2'den Llama 3'e kadar büyük dil modelleri, internet ölçeğinde metin üzerinde pre-training ile genel dil anlayışı kazanır. Ama bu modeller her görevi aynı kalitede yapmaz: bir hukuk bürosu için sözleşme taslağı hazırlamak, bir tıp asistanı için ICD kodlarını yorumlamak ya da özelleştirilmiş talimat formatını takip etmek pre-training verisiyle tam olarak kapsanmaz. İşte burada fine-tuning devreye girer.

Fine-tuning, mevcut ağırlıkları görev verinizle devam eğitimine tabi tutarak modelin o alana dair örüntüleri pekiştirmesini sağlar. Sıfırdan eğitimle karşılaştırıldığında çok daha az veri ve işlem gücü gerektirir: büyük modelin dil anlayışı korunurken üstüne görev bilgisi eklenir.

Fine-tuning'in Kullanım Alanları

Domain adaptation: Genel modeli tıp, hukuk veya finans literatürüne adapte et. Bu alanlardaki jargon, sözdizimsel yapı ve mantıksal çerçeve pre-training'de az temsil edilmiş olabilir.

Task specialization: Sınıflandırma, NER (isimlendirilmiş varlık tanıma), özetleme gibi tek bir göreve odaklan. Modelin tüm üretim kapasitesi bu göreve kanalize edilir.

Instruction following: Modele sistem promptlarına ve kullanıcı talimatlarına nasıl uyacağını öğret. ChatGPT ve Claude'un temelini oluşturan Instruction Tuning bu kategoriye girer.

Style alignment: Belirli bir yazım tarzı, ton veya format şablonunu öğret (kurumsal e-posta, teknik dokümantasyon, yaratıcı yazarlık).

Full Fine-tuning'in Maliyeti

GPT-3'ün 175 milyar parametresini tam olarak güncellemek için A100 GPU başına yaklaşık 1.2 TB GPU belleği gerekir — bu da tek bir ince ayar çalışması için yüzlerce GPU saati anlamına gelir. Llama 3 70B için bile bf16 hassasiyetiyle sadece model ağırlıklarını saklamak 140 GB bellek tutar; optimizer durumları, gradyanlar ve aktivasyon belleği eklendiğinde 400+ GB'a çıkar. Bu, küçük ekipler için pratik değildir.

Yaklaşım Karşılaştırması

Yöntem Güncellenen Parametre Min. VRAM (7B) Kalite Hız
Sıfırdan Eğitim 175B+ 1+ TB Maksimum Çok yavaş
Full Fine-tuning Tüm parametreler 80+ GB Çok yüksek Yavaş
LoRA ~0.1–1% 16–24 GB Yüksek Hızlı
QLoRA (4-bit) ~0.1–1% 6–10 GB Yüksek Orta
Prompt Engineering Hiç Inference belleği Sınırlı Anlık
NOT

PEFT (Parameter-Efficient Fine-Tuning) ailesi, LoRA'yı da kapsayan genel bir çatıdır. Adapter tuning, prefix tuning ve prompt tuning bu ailede yer alır. LoRA en yaygın ve başarılı yöntemdir.

01 Tam Fine-tuning

Tüm model parametrelerinin güncellenmesi — maksimum esneklik, maksimum maliyet.

Full fine-tuning'de modelin her katmanındaki her ağırlık güncellenir. Pre-trained ağırlıklar başlangıç noktası olarak kullanılır ve standart gradient descent ile görev verisine göre optimize edilir. Bu yaklaşım en yüksek performansı verir çünkü modelin her bölümü yeni göreve adapte olabilir.

Avantajlar ve Dezavantajlar

Avantaj: Modelin tüm kapasitesi görevinize yönelir. Çok spesifik domain shift (örneğin genel dil modelini yalnızca protein sekansı tahmininde kullanmak) için en iyi sonucu verir. Inference sırasında ek bellek veya hesaplama gerektirmez.

Dezavantaj: Catastrophic forgetting — eski görevlerdeki performans düşer. 7B model için 80+ GB GPU belleği, 13B için 160+ GB gerekir. Eğitim süresi uzar. Çok sayıda görev için ayrı model kopyaları saklanması gerekir — depolama maliyeti yüksektir.

Bellek Optimizasyon Teknikleri

Gradient checkpointing: İleri geçişte aktivasyonlar saklanmaz, geri yayılımda yeniden hesaplanır. Belleği ~%60 düşürür, hesaplama maliyetini ~%30 artırır.

Mixed precision (bf16/fp16): Ağırlıklar fp32 yerine bf16 tutulur. Bellek kullanımı yarıya düşer, modern GPU'larda (A100, H100) bf16 tensor çekirdekleri performansı artırır. fp16'ya göre bf16 tercih edilir: daha geniş dinamik aralık, overflow/underflow daha az.

Gradient accumulation: Küçük micro-batch'leri biriktirerek büyük effective batch size elde et. GPU'ya sığmayan büyük batch'lerin simülasyonu için kullanılır.

full_finetune.py
from transformers import (
    AutoModelForCausalLM, AutoTokenizer,
    TrainingArguments, Trainer,
    DataCollatorForLanguageModeling
)
from datasets import load_dataset
import torch

# Model ve tokenizer yükle
model_id = "meta-llama/Llama-3.2-3B"
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,   # mixed precision
    device_map="auto",
)

# Gradient checkpointing aktif et → bellek tasarrufu
model.gradient_checkpointing_enable()
model.config.use_cache = False  # checkpointing ile uyumsuz

# Veri seti yükle ve tokenize et
dataset = load_dataset("your_dataset", split="train")

def tokenize(examples):
    return tokenizer(
        examples["text"],
        truncation=True,
        max_length=2048,
        padding=False,
    )

tokenized = dataset.map(tokenize, batched=True)

# TrainingArguments — full FT için tipik değerler
args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,   # effective bs = 16
    learning_rate=2e-5,               # full FT için daha düşük
    bf16=True,
    logging_steps=10,
    save_strategy="epoch",
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
)

collator = DataCollatorForLanguageModeling(
    tokenizer, mlm=False
)

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=tokenized,
    data_collator=collator,
)

trainer.train()
DİKKAT

Full fine-tuning ile catastrophic forgetting yaşanabilir: orijinal instruction-following yetenekleri bozulabilir. Küçük, odaklı veri setleriyle dikkatli çalış. Validation loss ile orijinal benchmark performansını birlikte izle.

02 LoRA Matematiği

Düşük rank matris ayrışımı ile model ağırlıklarının neden küçük bir alt uzayda güncellenebileceğini anla.

LoRA (Low-Rank Adaptation), 2021 yılında Microsoft araştırmacıları tarafından önerilmiş ve büyük dil modellerinin fine-tuning maliyetini dramatik biçimde düşüren bir teknik. Temel fikir şu: büyük dil modellerinde fine-tuning sırasında ağırlık güncellemeleri düşük rank bir matris yapısına sahip. Yani tüm d×k matrisini güncellemek yerine, çok daha küçük iki matrisin çarpımı olan bir güncelleme yeterli.

Matematiksel Temel

Orijinal önceden eğitilmiş ağırlık matrisi W₀ ∈ ℝ^(d×k) olsun. Full fine-tuning'de güncelleme şöyle yazılır:

W = W₀ + ΔW          (full FT: ΔW ∈ ℝ^(d×k), rank(ΔW) = min(d,k))

LoRA: ΔW = B · A       (B ∈ ℝ^(d×r), A ∈ ℝ^(r×k), r << min(d,k))

Parametre sayısı karşılaştırması:
  Full FT  → d × k          (örnek: 4096 × 4096 = 16.7M)
  LoRA     → r×(d+k)        (r=16: 16×(4096+4096) = 131K)
  Oran     → %0.78 kadar az parametre!

Eğitim başlangıcında A matrisi rastgele (Gaussian dağılımla), B matrisi ise sıfır ile başlatılır. Bu sayede eğitim başında ΔW = B·A = 0, yani model tam olarak pre-trained ağırlıklarla başlar ve yavaş yavaş adapte olur.

Inference sırasında güncelleme doğrudan orijinal ağırlığa eklenir: W = W₀ + (α/r)·B·A. Buradaki α/r faktörü, LoRA güncellemesinin büyüklüğünü kontrol eden bir ölçek sabiti. Bu birleştirme işlemi sayesinde inference hızı hiç düşmez.

Neden Düşük Rank Yeterli?

Aghajanyan et al. (2020) çalışması, pre-trained modellerin fine-tuning sırasında düşük boyutlu bir intrinsic subspace'e yakınsadığını gösterdi. Yani yüksek boyutlu parametre uzayının yalnızca küçük bir alt kümesi gerçekten değişiyor. LoRA bu gözlemi parametre verimliliğine dönüştürür.

Rank Seçimi

Rank (r) Parametre (d=k=4096) Kullanım Senaryosu Kalite
4 32K Minimal adaptation, az veri Temel
8 65K Genel amaç, dengeli İyi
16 131K Standart seçim Yüksek
32 262K Karmaşık görevler Çok yüksek
64 524K Full FT'ye yakın Azalan getiri
NOT

LoRA genellikle Transformer'ın attention katmanlarındaki q_proj ve v_proj matrislerine uygulanır. Bazı araştırmalar tüm linear katmanlara uygulamanın daha iyi sonuç verdiğini gösterse de bellek kullanımı artar. Deneysel olarak karar ver.

03 LoRA Uygulaması

HuggingFace PEFT kütüphanesiyle LoRA adaptörü ekle ve yalnızca bu parametreleri eğit.

HuggingFace'in PEFT (Parameter-Efficient Fine-Tuning) kütüphanesi, LoRA dahil birçok PEFT yöntemini birkaç satır kodla uygulamana imkân tanır. Temel API son derece sezgisel: bir LoraConfig oluştur, get_peft_model ile base model'i sar, ardından normal eğitim döngüsüyle devam et.

Kurulum

terminal
pip install peft transformers accelerate datasets trl

LoraConfig Parametreleri

r LoRA rank — düşük değer = az parametre, az kapasite. Başlangıç için 16 önerilir.
lora_alpha Ölçek faktörü (α). Genellikle r ile aynı ya da 2×r. Güncellemenin büyüklüğünü α/r oranıyla ayarlar.
target_modules LoRA'nın uygulanacağı katman isimleri. Llama için ["q_proj","v_proj"] ya da tüm lineer katmanlar "all-linear".
lora_dropout LoRA katmanlarına uygulanan dropout oranı. Overfitting'e karşı 0.05–0.1 arasında seç.
bias "none" | "all" | "lora_only". Genellikle "none" — bias güncellenmez.
task_type CAUSAL_LM, SEQ2SEQ_LM, SEQ_CLS gibi görev tipi. Ağırlıkların nasıl uygulanacağını belirler.
lora_setup.py
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import get_peft_model, LoraConfig, TaskType
import torch

model_id = "meta-llama/Llama-3.2-3B-Instruct"

tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"   # causal LM için sağ padding

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)
model.config.use_cache = False

# LoRA konfigürasyonu
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules="all-linear",   # tüm lineer katmanlar
    lora_dropout=0.05,
    bias="none",
    task_type=TaskType.CAUSAL_LM,
)

# Base modeli LoRA adaptörüyle sar
model = get_peft_model(model, lora_config)

# Eğitilecek parametre sayısını göster
model.print_trainable_parameters()
# → trainable params: 39,976,960 || all params: 3,252,793,344 || trainable%: 1.2291

# Sadece LoRA parametreleri requires_grad=True
for name, param in model.named_parameters():
    if "lora" in name:
        print(f"{name}: {param.shape}")
        break
# → base_model.model.model.layers.0.self_attn.q_proj.lora_A.weight: (16, 3072)
NOT

PEFT modeli, orijinal modeli sararak çalışır. Eğitim sırasında base model ağırlıkları dondurulmuş (frozen) olarak kalır, yalnızca LoRA parametreleri gradient hesaplar. Bu sayede bellek ve hesaplama maliyeti dramatik biçimde düşer.

04 QLoRA — 4-bit + LoRA

Base modeli 4-bit quantize ederek bellek kullanımını düşür, LoRA ile verimli ince ayar yap.

Tim Dettmers et al. tarafından 2023'te yayımlanan QLoRA makalesi, tüketici GPU'larında (tek RTX 3090, RTX 4090) 65B parametreli modelleri fine-tune etmeyi mümkün kıldı. Temel fikir: base model ağırlıklarını 4-bit hassasiyetle sakla ve sadece LoRA adaptörlerini bf16 ile eğit. Geri yayılım sırasında 4-bit ağırlıklar anlık olarak bf16'ya dequantize edilir.

NF4 — Normal Float 4

Standart int4 ya da fp4 yerine QLoRA, NF4 (Normal Float 4) adlı özel bir veri tipi kullanır. NF4'ün tasarımı şu gözleme dayanır: pre-trained ağırlıklar normal dağılıma yakın. Bu dağılıma özel bir quantization grid, kuantizasyon hatasını minimize eder. Matematiksel olarak ağırlık değerleri, normal dağılımın eşit alanlarına karşılık gelen 16 sabit noktadan birine eşlenir.

Double Quantization

QLoRA ayrıca double quantization uygular: quantization sabitlerinin kendisi de quantize edilir. Bu, model ağırlığı başına ortalama 0.37 bit ek tasarruf sağlar.

qlora_setup.py
from transformers import (
    AutoModelForCausalLM, AutoTokenizer,
    BitsAndBytesConfig
)
from peft import get_peft_model, LoraConfig, prepare_model_for_kbit_training
import torch

model_id = "meta-llama/Llama-3.1-8B-Instruct"

# 4-bit quantization konfigürasyonu
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",          # Normal Float 4
    bnb_4bit_compute_dtype=torch.bfloat16, # hesaplama bf16
    bnb_4bit_use_double_quant=True,       # iç içe quantization
)

# Model 4-bit ile yükle
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    device_map="auto",
)

# 4-bit eğitim için hazırla (gradient checkpoint + cast)
model = prepare_model_for_kbit_training(model)

tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token

# LoRA adaptörü ekle
lora_config = LoraConfig(
    r=64,
    lora_alpha=128,
    target_modules="all-linear",
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# → trainable params: 167,772,160 || all params: 8,197,615,616 || trainable%: 2.05

VRAM Karşılaştırması — Llama 3.1 8B

Yöntem Precision VRAM (Model) VRAM (Eğitim) Donanım
Full FT bf16 16 GB 80+ GB 4× A100
LoRA bf16 16 GB 24–32 GB A100 40GB
QLoRA nf4 + bf16 5 GB 10–12 GB RTX 3090/4090
QLoRA (Unsloth) nf4 + bf16 4 GB 6–8 GB RTX 3080/4080
DİKKAT

4-bit quantization ile eğitim yalnızca CUDA GPU'larda çalışır. bitsandbytes kütüphanesi CPU veya MPS (Apple Silicon) üzerinde desteklenmez. Linux ve Windows CUDA ortamlarında çalışır.

05 SFTTrainer ile Eğitim

HuggingFace TRL'nin SFTTrainer'ı, talimat eğitimi için optimize edilmiş yüksek seviye API sunar.

HuggingFace TRL (Transformer Reinforcement Learning) kütüphanesi, LLM eğitimi için uzmanlaşmış trainer'lar barındırır. SFTTrainer, Supervised Fine-Tuning için özel olarak geliştirilmiştir. Standart Trainer'dan farkları şunlar: otomatik formatlama, packing desteği (kısa örnekleri birleştirerek GPU kullanımını artır), doğrudan PEFT entegrasyonu ve completion-only loss maskesi.

SFTTrainer vs Trainer

Özellik Trainer SFTTrainer
PEFT entegrasyonu Manuel Otomatik
Packing desteği Yok Var
Completion-only loss Manuel maske DataCollatorForCompletionOnlyLM
Formatlama Manuel tokenize formatting_func
sft_train.py
from transformers import (
    AutoModelForCausalLM, AutoTokenizer,
    BitsAndBytesConfig, TrainingArguments,
    EarlyStoppingCallback
)
from peft import LoraConfig, prepare_model_for_kbit_training
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
import torch

# ── 1. Model yükleme (QLoRA) ──────────────────────────────
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-3B-Instruct",
    quantization_config=bnb_config,
    device_map="auto",
)
model = prepare_model_for_kbit_training(model)

tokenizer = AutoTokenizer.from_pretrained(
    "meta-llama/Llama-3.2-3B-Instruct"
)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# ── 2. LoRA config ────────────────────────────────────────
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules="all-linear",
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# ── 3. Veri seti ──────────────────────────────────────────
dataset = load_dataset("timdettmers/openassistant-guanaco")
train_data = dataset["train"]
eval_data  = dataset["test"]

# ── 4. SFTConfig (= TrainingArguments alt sınıfı) ─────────
sft_config = SFTConfig(
    output_dir="./llama3-sft",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    bf16=True,
    logging_steps=25,
    save_strategy="steps",
    save_steps=500,
    eval_strategy="steps",
    eval_steps=500,
    load_best_model_at_end=True,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    max_seq_length=2048,
    packing=True,           # kısa örnekleri birleştir
    report_to="wandb",       # Wandb logging
)

# ── 5. Trainer ────────────────────────────────────────────
trainer = SFTTrainer(
    model=model,
    args=sft_config,
    train_dataset=train_data,
    eval_dataset=eval_data,
    peft_config=lora_config,
    tokenizer=tokenizer,
    callbacks=[EarlyStoppingCallback(early_stopping_patience=3)],
)

trainer.train()
trainer.save_model("./llama3-sft-final")
NOT

packing=True kısa örnekleri tek bir sequence'a birleştirir. Bu, özellikle kısa instruction örnekleriyle GPU doluluk oranını (utilization) önemli ölçüde artırır. Ancak örnekler arası dikkat akışı önlemek için attention mask'e dikkat et.

06 Veri Formatı

Instruction tuning için doğru veri formatı, model performansı üzerinde eğitim konfigürasyonundan çok daha büyük etki yaratır.

Eğitim verisi kalitesi, quantity'den daha önemli. 1000 adet yüksek kaliteli, tutarlı formatlı örnek, 100.000 gürültülü örneği geçebilir. Bu nedenle veri formatını anlamak kritik öneme sahip.

Alpaca Formatı

Stanford Alpaca projesiyle popülerleşen format. instruction, input, output alanlarından oluşur. Basit ve yaygın kullanılan klasik format.

alpaca_format.py
# Alpaca formatı — instruction + input + output
alpaca_template = """Below is an instruction that describes a task, \
paired with an input that provides further context. \
Write a response that appropriately completes the request.

### Instruction:
{instruction}

### Input:
{input}

### Response:
{output}"""

# Input olmayan durum için
alpaca_no_input = """Below is an instruction that describes a task. \
Write a response that appropriately completes the request.

### Instruction:
{instruction}

### Response:
{output}"""

def formatting_func(example):
    if example["input"]:
        return alpaca_template.format(**example)
    return alpaca_no_input.format(**example)

ChatML Formatı

OpenAI'ın geliştirdiği ChatML formatı, çok turlu konuşmaları ve system prompt'u açıkça destekler. Llama 3, Mistral ve çoğu modern model bu formatı kullanır.

chatml_format.py
# ChatML formatı — system + user + assistant rolleri
chatml_example = """<|im_start|>system
Sen yardımcı bir Türkçe asistansın.<|im_end|>
<|im_start|>user
Python'da bir liste nasıl sıralanır?<|im_end|>
<|im_start|>assistant
Python'da liste sıralamak için iki yol vardır:
1. list.sort() — in-place sıralar
2. sorted(list) — yeni liste döner<|im_end|>"""

# HuggingFace chat template API ile
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")

messages = [
    {"role": "system", "content": "Sen yardımcı bir asistansın."},
    {"role": "user",   "content": "Merhaba!"},
    {"role": "assistant", "content": "Merhaba! Nasıl yardımcı olabilirim?"},
]

formatted = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=False,
)
print(formatted)

Completion-Only Loss

Önemli bir ayrıntı: loss hesaplanırken yalnızca assistant yanıtı üzerinden kayıp hesaplandığında model daha iyi öğrenir. System ve user promptları için kayıp sıfıra maskelenir.

completion_only.py
from trl import DataCollatorForCompletionOnlyLM

# Llama 3 için assistant başlangıç token'ı
response_template = "<|start_header_id|>assistant<|end_header_id|>"

collator = DataCollatorForCompletionOnlyLM(
    response_template=response_template,
    tokenizer=tokenizer,
)

# SFTTrainer'a ver
trainer = SFTTrainer(
    ...,
    data_collator=collator,
    # packing=False olmalı completion-only ile
)
DİKKAT

Tüm örneklerde aynı formatı tutarlı biçimde uygula. Eğitim sırasında format karışıklığı modelin yanlış token'ları tahmin etmeye çalışmasına yol açar ve convergence'ı zorlaştırır.

07 Eğitim Hiper-parametreleri

LoRA fine-tuning için kanıtlanmış hiper-parametre aralıkları ve seçim mantığı.

Hiper-parametre seçimi model boyutuna, veri miktarına ve donanıma bağlıdır. Aşağıdaki değerler deneysel kanıta ve açık kaynak çalışmalarına dayalı başlangıç noktalarıdır. Her zaman küçük denemelerle doğrula.

Learning Rate

LoRA için önerilen aralık 1e-4 ila 2e-4. Full fine-tuning için tipik değer olan 1e-5 ile 2e-5'ten çok daha yüksek — çünkü yalnızca küçük bir adaptör eğitiliyor. Çok düşük LR yavaş convergence, çok yüksek LR instability yaratır. Cosine scheduler ile warmup kullanmak training stabilitesini artırır.

Batch Size ve Gradient Accumulation

Effective batch size = per_device_train_batch_size × gradient_accumulation_steps × gpu_count. Genellikle 16–64 arasında effective batch size önerilir. Örneğin: RTX 3090'da per_device=4, accumulation=4 → effective bs=16.

Parametre Tablosu

learning_rate LoRA için 1e-4 – 2e-4 arası. Full FT için 1e-5 – 5e-5. Cosine decay ile kullan.
num_train_epochs 1–3 epoch genellikle yeterli. Büyük veri setlerinde 1 epoch bile over-fit ettirebilir. Validation loss izle.
warmup_ratio 0.03 – 0.05 (toplam adımların %3–5'i). İlk adımlarda LR'yi sıfırdan hedefe yavaşça yükselt.
lr_scheduler_type "cosine" en yaygın ve etkili. "linear" daha basit ama genellikle daha kötü. "constant" küçük run'lar için.
max_seq_length Veri setinin maksimum token uzunluğuna göre ayarla. Uzun seq = daha az batch örneği = daha az GPU kullanımı.
weight_decay 0.001 – 0.01 arası. L2 regularizasyon. Overfitting'e karşı hafif etki.
adam_epsilon 1e-8 (varsayılan). bf16 eğitimde bazen 1e-6'ya yükseltmek stabililteyi artırır.

Önerilen Başlangıç Konfigürasyonu

Model Boyutu LR Batch Size Epochs LoRA r
1B–3B 2e-4 16 (eff.) 3 16
7B–8B 1.5e-4 16 (eff.) 2 16–32
13B 1e-4 8 (eff.) 2 32–64
70B 5e-5 4–8 (eff.) 1–2 64
NOT

Hiper-parametre araması için önce Learning Rate'i dene. Diğer parametreler sabitken LR sweeping (1e-5, 5e-5, 1e-4, 2e-4) genellikle en büyük etkiyi verir. WandB Sweeps veya Optuna ile otomatik arama yapabilirsin.

08 Unsloth ile Hızlandırma

Özel CUDA kernelleriyle 2x hızlı eğitim ve %70 daha az VRAM kullanımı.

Unsloth, 2024'te Daniel ve Michael Han kardeşler tarafından geliştirilen açık kaynak bir kütüphane. Triton ve özel CUDA kernelleri ile HuggingFace transformer'larının kritik noktalarını (attention, RoPE, backward pass) yeniden implement eder. Sonuç: standart QLoRA'ya kıyasla 2x daha hızlı eğitim ve %60–70 daha az VRAM kullanımı.

Nasıl Çalışır?

Unsloth'un kazancı birkaç yerden gelir: (1) Flash Attention 2 yerine daha optimize Triton kernelleri, (2) RoPE embedding hesaplamalarının kernel'e taşınması, (3) lm_head ve embedding'in birleştirilmesi, (4) gradient checkpoint'in daha akıllı uygulanması. Bu optimizasyonlar matematiksel sonucu değiştirmez — aynı gradyanlar, aynı yakınsama.

Desteklenen Modeller

Llama 2/3, Mistral, Mixtral, Gemma, Gemma 2, Phi-3, Qwen 2, Falcon ve TinyLlama. FastLanguageModel API, AutoModel'in drop-in replacement'ıdır.

terminal
pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes
unsloth_train.py
from unsloth import FastLanguageModel
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
import torch

# ── 1. Model ve tokenizer — Unsloth API ──────────────────
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Llama-3.2-3B-Instruct",
    max_seq_length=2048,
    dtype=None,          # otomatik tespit
    load_in_4bit=True,   # QLoRA modu
)

# ── 2. LoRA adaptörü — Unsloth'un get_peft_model'i ───────
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                     "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0,          # Unsloth optimizasyonu için 0 önerilir
    bias="none",
    use_gradient_checkpointing="unsloth",  # özel implement
    random_state=3407,
)

# ── 3. Chat template formatı ──────────────────────────────
from unsloth.chat_templates import get_chat_template
tokenizer = get_chat_template(tokenizer, chat_template="llama-3")

def formatting_prompts_func(examples):
    convos = examples["conversations"]
    texts  = [tokenizer.apply_chat_template(c, tokenize=False,
              add_generation_prompt=False) for c in convos]
    return {"text": texts}

dataset = load_dataset("mlabonne/FineTome-100k", split="train")
dataset = dataset.map(formatting_prompts_func, batched=True)

# ── 4. Eğitim ─────────────────────────────────────────────
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    args=SFTConfig(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        max_steps=60,           # hızlı test için
        learning_rate=2e-4,
        fp16=not torch.cuda.is_bf16_supported(),
        bf16=torch.cuda.is_bf16_supported(),
        logging_steps=1,
        optim="adamw_8bit",     # 8-bit Adam → daha az bellek
        seed=3407,
        output_dir="outputs",
    ),
)

trainer_stats = trainer.train()
print(f"Eğitim süresi: {trainer_stats.metrics['train_runtime']:.1f}s")
NOT

Unsloth'ta lora_dropout=0 önerilir çünkü özel kernel optimizasyonları sıfır-dropout varsayımı üzerine kurulu. Dropout gerekliyse standart PEFT'e geri dön. Ayrıca use_gradient_checkpointing="unsloth" seçeneği 30 katmana kadar unlocked katman kullanarak %30 daha az VRAM sağlar.

09 Adapter Birleştirme

LoRA ağırlıklarını base modele entegre et ve PEFT bağımlılığı olmadan deploy et.

Eğitim sonunda iki seçeneğin var: adaptörü ayrı tut veya base modele birleştir. Ayrı tutmak, birden fazla adaptörü dinamik olarak değiştirmene izin verir — birden fazla fine-tuned versiyon için tek base model tutabilirsin. Birleştirmek ise inference'ı hızlandırır ve PEFT kütüphane bağımlılığını kaldırır.

merge_and_unload()

merge_and_unload fonksiyonu ΔW = B·A hesaplar ve bunu orijinal W₀'a ekler: W_final = W₀ + (α/r)·B·A. Sonuç, PEFT olmayan standart bir model olur. Bu işlem geri alınamaz — öncesinde adaptörü ayrıca kaydet.

merge_and_save.py
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

base_model_id  = "meta-llama/Llama-3.2-3B-Instruct"
adapter_path   = "./llama3-sft-final"
merged_path    = "./llama3-sft-merged"

# ── 1. Base modeli yükle (fp16 — birleştirme için) ────────
base_model = AutoModelForCausalLM.from_pretrained(
    base_model_id,
    torch_dtype=torch.float16,
    device_map="auto",
)

# ── 2. Adaptörü yükle ─────────────────────────────────────
model = PeftModel.from_pretrained(base_model, adapter_path)

# ── 3. Birleştir ve PEFT sarmalını kaldır ─────────────────
model = model.merge_and_unload()
print("Birleştirme tamamlandı.")
print(type(model))  # → LlamaForCausalLM (PEFT yok)

# ── 4. Kaydet ─────────────────────────────────────────────
model.save_pretrained(merged_path, safe_serialization=True)

tokenizer = AutoTokenizer.from_pretrained(base_model_id)
tokenizer.save_pretrained(merged_path)
print(f"Model kaydedildi: {merged_path}")

# ── 5. HuggingFace Hub'a yükle (opsiyonel) ────────────────
from huggingface_hub import HfApi
api = HfApi()

# Önce login: huggingface-cli login
model.push_to_hub(
    "your-username/llama3-finetuned",
    safe_serialization=True,
    private=True,
)
tokenizer.push_to_hub("your-username/llama3-finetuned")

Unsloth ile Kaydetme

Unsloth, birleştirme ve kaydetmeyi GGUF formatı dahil birden fazla seçenekle destekler:

unsloth_save.py
# Standart HuggingFace formatı
model.save_pretrained_merged(
    "model_merged",
    tokenizer,
    save_method="merged_16bit",
)

# GGUF formatı — llama.cpp / Ollama için
model.save_pretrained_gguf(
    "model_gguf",
    tokenizer,
    quantization_method="q4_k_m",  # 4-bit GGUF
)

# Hub'a yükle
model.push_to_hub_merged(
    "your-username/llama3-merged",
    tokenizer,
    save_method="merged_16bit",
    token="hf_...",
)
NOT

Birleştirilmiş modeli Ollama ile çalıştırmak için GGUF formatına dönüştür. quantization_method="q4_k_m" kalite ve boyut dengesi açısından en yaygın tercih. q8_0 daha yüksek kalite ama daha büyük dosya boyutu verir.