Kendi Verinle Model İnce Ayarı: Hugging Face Fine-tuning Rehberi
Makine öğrenmesi dünyasında hazır modelleri indirip kullanmak güzel bir başlangıç noktası, ama gerçek gücü ortaya çıkaran şey o modeli kendi verinle şekillendirmek. Hugging Face ekosistemi, bu süreci hem erişilebilir hem de oldukça esnek bir hale getiriyor. Bu yazıda sıfırdan bir fine-tuning pipeline’ı kurarak kendi veri setinle nasıl model eğiteceğini adım adım göstereceğim. Konuyu soyut bırakmamak için gerçek bir senaryo üzerinden ilerleyeceğiz: Türkçe müşteri şikayetlerini kategorize eden bir sınıflandırma modeli.
Fine-tuning Nedir ve Ne Zaman Gerekir?
Fine-tuning (ince ayar), önceden büyük verilerle eğitilmiş bir modeli, kendi spesifik görevin için yeniden eğitme sürecidir. Modelin mevcut ağırlıklarını koruyarak üzerine yeni bilgi katıyorsun. Bu sayede milyarlarca parametreyi sıfırdan eğitmek yerine, çok daha az veri ve işlem gücüyle hedefe odaklı bir model elde ediyorsun.
Peki ne zaman fine-tuning gerekir?
- Genel amaçlı model domain-specific terminolojini bilmiyor (tıp, hukuk, yazılım)
- Çıktı formatını veya tonunu kontrol etmek istiyorsun
- Gizlilik nedeniyle verini dışarıya gönderemiyorsun
- Mevcut modelin doğruluk oranı işin için yeterli değil
- Türkçe veya az kaynaklı dilde çalışıyorsun
Ortam Hazırlığı
Önce çalışma ortamını kuruyoruz. Bir CUDA destekli GPU varsa ideal, yoksa CPU ile de küçük modellerde çalışabilirsin, sadece daha yavaş olur.
# Python sanal ortamı oluştur
python3 -m venv finetuning-env
source finetuning-env/bin/activate
# Gerekli kütüphaneleri yükle
pip install transformers datasets evaluate accelerate
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install scikit-learn pandas numpy
pip install huggingface_hub peft # PEFT: Parameter-Efficient Fine-Tuning için
# Hugging Face CLI ile giriş yap (private model/dataset için)
huggingface-cli login
GPU durumunu kontrol edelim:
# NVIDIA GPU kontrolü
nvidia-smi
# Python içinden kontrol
python3 -c "import torch; print('CUDA:', torch.cuda.is_available()); print('GPU:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'Yok')"
Eğer bulut ortamında çalışıyorsan, Google Colab veya Kaggle Notebooks ücretsiz GPU erişimi sağlıyor. Üretim ortamı için ise AWS p3 instance’ları veya RunPod gibi servisleri değerlendirebilirsin.
Veri Setini Hazırlamak
Bu yazıdaki senaryomuz şu: Bir e-ticaret şirketinin destek ekibi, günde yüzlerce şikayet e-postası alıyor. Bu şikayetleri otomatik olarak kategorize etmek istiyorlar. Kategoriler şunlar: kargo_sorunu, urun_hatali, odeme_sorunu, iade_talebi, genel_sikayet.
Önce örnek veri setimizi oluşturalım:
# dataset_hazirla.py
import pandas as pd
import json
from datasets import Dataset, DatasetDict
from sklearn.model_selection import train_test_split
# Örnek veri (gerçek hayatta bu CSV veya DB'den gelir)
veriler = [
{"metin": "Siparişim 10 gündür gelmedi, kargoda kayboldu sanırım", "etiket": "kargo_sorunu"},
{"metin": "Aldığım ürün fotoğraftakinden tamamen farklı çıktı", "etiket": "urun_hatali"},
{"metin": "Kartımdan iki kez ödeme çekildi, birini geri istiyorum", "etiket": "odeme_sorunu"},
{"metin": "Ürünü iade etmek istiyorum nasıl yapabilirim", "etiket": "iade_talebi"},
{"metin": "Müşteri hizmetleri hiç dönmüyor, çok kötü deneyim", "etiket": "genel_sikayet"},
# ... gerçek hayatta burada yüzlerce/binlerce satır olur
]
df = pd.DataFrame(veriler)
# Etiketleri sayısal değerlere dönüştür
etiket_map = {
"kargo_sorunu": 0,
"urun_hatali": 1,
"odeme_sorunu": 2,
"iade_talebi": 3,
"genel_sikayet": 4
}
df["label"] = df["etiket"].map(etiket_map)
# Train/validation/test split
train_df, test_df = train_test_split(df, test_size=0.2, random_state=42, stratify=df["label"])
train_df, val_df = train_test_split(train_df, test_size=0.1, random_state=42, stratify=train_df["label"])
# Hugging Face Dataset formatına çevir
train_dataset = Dataset.from_pandas(train_df[["metin", "label"]].reset_index(drop=True))
val_dataset = Dataset.from_pandas(val_df[["metin", "label"]].reset_index(drop=True))
test_dataset = Dataset.from_pandas(test_df[["metin", "label"]].reset_index(drop=True))
dataset_dict = DatasetDict({
"train": train_dataset,
"validation": val_dataset,
"test": test_dataset
})
print(dataset_dict)
dataset_dict.save_to_disk("./sikayet_dataset")
Gerçek dünya notları: Verin ne kadar temizse model o kadar iyi öğrenir. Veri temizleme aşamasında HTML taglerini, fazladan boşlukları ve özel karakterleri temizle. Sınıf dengesizliği varsa (bir kategoride çok fazla, diğerinde az örnek) oversampling veya class weights kullanmayı düşün.
Tokenizer ve Model Seçimi
Türkçe metin için model seçimi kritik. Burada birkaç seçenek var:
- dbmdz/bert-base-turkish-cased: Türkçe BERT, sınıflandırma görevleri için solid seçenek
- xlm-roberta-base: Çok dilli RoBERTa, Türkçe dahil 100 dil destekliyor
- sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2: Daha hafif, hızlı
Biz xlm-roberta-base ile devam edeceğiz:
# model_hazirla.py
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from datasets import load_from_disk
import torch
MODEL_ADI = "xlm-roberta-base"
NUM_LABELS = 5
MAKS_UZUNLUK = 128
# Tokenizer yükle
tokenizer = AutoTokenizer.from_pretrained(MODEL_ADI)
# Dataset yükle
dataset = load_from_disk("./sikayet_dataset")
# Tokenization fonksiyonu
def tokenize_et(ornekler):
return tokenizer(
ornekler["metin"],
truncation=True,
padding="max_length",
max_length=MAKS_UZUNLUK,
return_tensors=None # Dataset map için None bırak
)
# Tüm split'lere uygula
tokenized_dataset = dataset.map(
tokenize_et,
batched=True,
remove_columns=["metin"] # Ham metni kaldır, sadece token'lar kalsın
)
tokenized_dataset.set_format("torch")
print("Tokenization tamamlandı:")
print(tokenized_dataset)
# Label isimleri için id2label ve label2id map'leri
id2label = {
0: "kargo_sorunu",
1: "urun_hatali",
2: "odeme_sorunu",
3: "iade_talebi",
4: "genel_sikayet"
}
label2id = {v: k for k, v in id2label.items()}
# Modeli yükle (classification head ile)
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_ADI,
num_labels=NUM_LABELS,
id2label=id2label,
label2id=label2id
)
print(f"nModel parametreleri: {model.num_parameters():,}")
Training Argümanları ve Trainer Kurulumu
Trainer API’si fine-tuning’in kalbinde yer alıyor. Training döngüsünü, evaluation’ı ve checkpointing’i otomatik hallediyor:
# egit.py
from transformers import TrainingArguments, Trainer, DataCollatorWithPadding
import evaluate
import numpy as np
# Metrics fonksiyonu
accuracy_metric = evaluate.load("accuracy")
f1_metric = evaluate.load("f1")
def metrikleri_hesapla(eval_pred):
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
accuracy = accuracy_metric.compute(predictions=predictions, references=labels)
f1 = f1_metric.compute(predictions=predictions, references=labels, average="weighted")
return {
"accuracy": accuracy["accuracy"],
"f1": f1["f1"]
}
# Training argümanları
training_args = TrainingArguments(
output_dir="./sikayet-model-checkpoints",
num_train_epochs=5,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
learning_rate=2e-5,
weight_decay=0.01,
warmup_ratio=0.1,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1",
greater_is_better=True,
logging_dir="./logs",
logging_steps=50,
fp16=torch.cuda.is_available(), # GPU varsa mixed precision
dataloader_num_workers=4,
report_to="none" # WandB veya TensorBoard kullanmak istersen değiştir
)
# Data collator
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
# Trainer oluştur
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["validation"],
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=metrikleri_hesapla
)
# Eğitimi başlat
print("Eğitim başlıyor...")
train_result = trainer.train()
# Sonuçları kaydet
trainer.save_model("./sikayet-model-final")
tokenizer.save_pretrained("./sikayet-model-final")
print("nEğitim tamamlandı!")
print(f"Train Loss: {train_result.training_loss:.4f}")
Önemli hyperparameter notları:
- learning_rate: 2e-5 ile 5e-5 arası genellikle BERT ailesi için işe yarar, çok büyük değerler catastrophic forgetting’e yol açar
- num_train_epochs: Küçük veri setlerinde 3-5 epoch yeterli, fazlası overfit’e götürür
- warmup_ratio: Öğrenme oranını yavaşça artırmak eğitim stabilitesini artırır
- fp16: CUDA varsa mixed precision training hem hızı artırır hem VRAM kullanımını düşürür
PEFT ile Verimli Fine-tuning: LoRA
Büyük modellerde tüm parametreleri eğitmek hem zaman hem bellek açısından pahalı. LoRA (Low-Rank Adaptation) yöntemi, orijinal ağırlıkları dondurup yanına küçük adaptör matrisler ekleyerek çok daha verimli eğitim yapmanı sağlıyor. Milyarlarca parametreli LLM’leri kısıtlı GPU ile fine-tune etmek istiyorsan bu yöntem şart:
# lora_finetuning.py
from peft import get_peft_model, LoraConfig, TaskType
from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer
# LoRA konfigürasyonu
lora_config = LoraConfig(
task_type=TaskType.SEQ_CLS,
r=16, # Rank: düşük = az parametre, yüksek = daha fazla kapasite
lora_alpha=32, # Scaling faktörü (genellikle r*2)
target_modules=["query", "value"], # Hangi katmanlar adapte edilsin
lora_dropout=0.1,
bias="none"
)
# Büyük model yükle (örneğin LLM için)
base_model = AutoModelForSequenceClassification.from_pretrained(
"xlm-roberta-large",
num_labels=5
)
# LoRA modelini hazırla
peft_model = get_peft_model(base_model, lora_config)
peft_model.print_trainable_parameters()
# Çıktı: trainable params: 887,040 || all params: 560,142,340 || trainable%: 0.16
# Bu model artık normal Trainer ile eğitilebilir
# Eğitim tamamlandıktan sonra LoRA ağırlıklarını kaydet
peft_model.save_pretrained("./lora-adaptors")
# İnference sırasında yükle
from peft import PeftModel
yuklu_model = PeftModel.from_pretrained(base_model, "./lora-adaptors")
LoRA ile eğitilebilir parametre sayısını yüzde 0.1-1 aralığına düşürebiliyorsun. Bu, 16GB VRAM’li bir GPU ile 7B parametreli modeli fine-tune etmeni mümkün kılıyor.
Model Değerlendirme ve Test
Eğitim bitti, şimdi gerçek hayat testine girelim:
# degerlendir.py
from transformers import pipeline
import torch
# Pipeline ile kolay inference
siniflandirici = pipeline(
"text-classification",
model="./sikayet-model-final",
tokenizer="./sikayet-model-final",
device=0 if torch.cuda.is_available() else -1
)
# Test cümleleri
test_cumleleri = [
"Kargom 2 haftadır yolda, nerede olduğunu bile söylemiyorlar",
"Ürün tamamen bozuk geldi, hiç çalışmıyor",
"Hesabımdan fazladan para çekilmiş, neden?",
"Ürünü beğenmedim, nasıl iade edebilirim acaba",
"Bu kadar kötü müşteri hizmeti görmedim hayatımda"
]
for cumle in test_cumleleri:
sonuc = siniflandirici(cumle)
print(f"Metin: {cumle}")
print(f"Kategori: {sonuc[0]['label']} (Skor: {sonuc[0]['score']:.3f})")
print("-" * 60)
# Test seti üzerinde detaylı değerlendirme
from sklearn.metrics import classification_report
import numpy as np
# Trainer ile test seti değerlendirmesi
test_sonuclari = trainer.predict(tokenized_dataset["test"])
tahminler = np.argmax(test_sonuclari.predictions, axis=1)
gercekler = test_sonuclari.label_ids
print(classification_report(
gercekler,
tahminler,
target_names=list(id2label.values())
))
Modeli Hugging Face Hub’a Göndermek
Modeli eğittikten sonra Hub’a push’layarak ekibinle paylaşabilir veya uygulamanda kullanabilirsin:
# Hugging Face CLI ile login
huggingface-cli login
# Model kartı (README) oluştur
cat > ./sikayet-model-final/README.md << 'EOF'
---
language: tr
tags:
- text-classification
- turkish
- customer-support
datasets:
- custom
metrics:
- accuracy
- f1
---
# Türkçe Müşteri Şikayet Sınıflandırıcı
xlm-roberta-base üzerinde fine-tune edilmiş Türkçe şikayet kategorilendirme modeli.
## Kategoriler
- kargo_sorunu
- urun_hatali
- odeme_sorunu
- iade_talebi
- genel_sikayet
## Kullanım
from transformers import pipeline clf = pipeline(“text-classification”, model=”kullanici-adi/sikayet-siniflandirici”) clf(“Kargom gelmedi”)
EOF
# hub_push.py
from huggingface_hub import HfApi
api = HfApi()
# Repository oluştur
api.create_repo(
repo_id="kullanici-adin/sikayet-siniflandirici",
private=True # Şimdilik private tut
)
# Modeli push'la
trainer.push_to_hub("kullanici-adin/sikayet-siniflandirici")
tokenizer.push_to_hub("kullanici-adin/sikayet-siniflandirici")
print("Model Hub'a yüklendi!")
Üretim Ortamında Dikkat Edilecekler
Fine-tuning’i production’a taşırken birkaç kritik nokta var:
Model boyutu ve hız dengesi:
- Büyük model her zaman daha iyi değil, küçük fine-tune edilmiş model büyük genel modeli yenebilir
- Inference hızı için ONNX export veya quantization düşün
torch.compile()ile inference’ı hızlandırabilirsin
Veri kalitesi ve güncelleme:
- Model zamanla data drift yaşar, yani gerçek dünya verisi eğitim verisinden uzaklaşır
- Düzenli aralıklarla yeni verilerle model güncelleme planı yap
- Eğitim ve inference arasındaki preprocessing pipeline’ının aynı olmasına dikkat et
Monitoring:
- Production’da model tahminlerini logla
- Düşük confidence skorlu tahminleri işaretle ve manüel review yap
- Sınıf dağılımı beklenenden farklılaşmaya başladıysa bu erken uyarı sinyali
Güvenlik:
- Fine-tuned modeller de adversarial girdi saldırılarına açık olabilir
- Private verilerle eğitilmiş modeller sızdırma saldırılarına karşı savunmasız olabilir, özellikle LLM’lerde dikkatli ol
# Model boyutunu optimize et - ONNX export
pip install optimum[onnxruntime]
python3 -c "
from optimum.onnxruntime import ORTModelForSequenceClassification
from transformers import AutoTokenizer
model = ORTModelForSequenceClassification.from_pretrained(
'./sikayet-model-final',
export=True
)
model.save_pretrained('./sikayet-model-onnx')
print('ONNX export tamamlandı')
"
Sonuç
Fine-tuning, genel amaçlı modelleri iş senaryona özgü, güçlü araçlara dönüştürmenin en pratik yolu. Hugging Face ekosistemi bu süreci hem yönetilebilir hem de tekrarlanabilir bir hale getiriyor. Birkaç yüz örnek veriyle bile anlamlı iyileştirmeler elde edebilirsin, yeter ki verin temiz ve dengeli olsun.
LoRA gibi parameter-efficient yöntemler sayesinde artık fine-tuning için dev bir GPU cluster’ına ihtiyacın yok. Tek bir consumer GPU ile bile ciddi işler çıkarabiliyor olmak, bu teknolojileri küçük ekiplerin de erişebileceği bir seviyeye taşıdı.
En önemli tavsiyem: küçük başla, hızlı iterate et. Önce 100-200 örnekle pipeline’ını kur, çalıştığını gör, sonra veriyi büyüt. Veri kalitesine odaklan, çünkü çöp girdi çöp çıktı prensibi burada da geçerli. İyi etiketlenmiş 500 örnek, kötü etiketlenmiş 5000 örnekten çok daha değerli.
