Cost-Sensitive Learning ve Focal Loss: Loss Function'ı Imbalanced'a Eğitmek
Sampling alternatifi: loss function'ı değiştirme. Cost matrix, class weight, sample weight, asymmetric loss, focal loss (Lin et al., 2017), Tversky loss, ve imbalanced AD'de pratik uygulamalar.
Şükrü Yusuf KAYA
26 dakikalık okuma
Orta💸 Hatalar eşit değildir
Bir fraud transaction'ı kaçırmak (FN) ile bir normal transaction'a yanlış alarm üretmek (FP) aynı maliyette değildir. FN ortalama 2.500 TL fraud kaybı; FP ortalama 5 TL analist saati maliyet. Yani FN ≈ 500 × FP. Standart loss bunları eşit cezalandırır — yanlış. Bu derste loss function'ı maliyet bilinciyle eğitmenin tekniklerini göreceğiz.
Cost Matrix: Hatalar Para Birimine Çevrilir#
Klasik confusion matrix (2 sınıf):
| Tahmin: 0 | Tahmin: 1 | |
|---|---|---|
| Gerçek: 0 | TN | FP |
| Gerçek: 1 | FN | TP |
Cost matrix bu kutulara para birimi koyar:
| Tahmin: 0 | Tahmin: 1 | |
|---|---|---|
| Gerçek: 0 | 0 TL | C(FP) |
| Gerçek: 1 | C(FN) | 0 TL |
Sektörel Cost Matrix Örnekleri#
Banking Kart Fraud
- C(FN) = ortalama fraud tutarı ≈ 2.500 TL
- C(FP) = analist 3 dakika × 2.000 TL/saat = 100 TL
- Cost oranı: FN / FP ≈ 25
Network IDS
- C(FN) = bir attack kaçma → 50.000 TL ortalama hasar
- C(FP) = SOC analist 4 dakika → 130 TL
- Cost oranı: ~385
Predictive Maintenance
- C(FN) = bir bearing fail → 60.000 TL üretim kaybı
- C(FP) = gereksiz bakım 2 saat = 8.000 TL
- Cost oranı: ~7.5
Healthcare ECG
- C(FN) = kalp krizi kaçırma — sınırsız (hayat değeri)
- C(FP) = gereksiz inceleme 500 TL
- Cost oranı: çok yüksek, asimetrik
Asıl Optimizasyon#
Cost matrix bilinince, optimal model toplam beklenen maliyeti minimize eder:
Bu aynı zamanda optimal eşik hesaplamayı sağlar. Bir model p(anomali|x) verirse:
Örn: C(FP)=100, C(FN)=2500. Eşik = 100/2600 ≈ 0.04 — yani p(anomali) > 0.04 olunca alarm. Eğer modelin default eşiği 0.5 ise, bu eşiği değiştirmemek ekonomik olarak yanlış.
python
import numpy as npfrom sklearn.metrics import confusion_matrix def expected_cost(y_true, y_pred, c_fn, c_fp): """Toplam beklenen maliyet.""" tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel() return fn * c_fn + fp * c_fp def optimal_threshold(probs, y_true, c_fn=2500, c_fp=100): """Maliyeti minimize eden eşiği bul.""" thresholds = np.linspace(0.01, 0.99, 99) costs = [] for t in thresholds: y_pred = (probs >= t).astype(int) costs.append(expected_cost(y_true, y_pred, c_fn, c_fp)) best_idx = np.argmin(costs) return thresholds[best_idx], costs[best_idx] # Örnek (bir modelin probability output'u varsayalım)# best_t, best_c = optimal_threshold(model.predict_proba(X_val)[:,1], y_val)Cost-aware threshold seçimi
Class Weight: En Basit Yaklaşım#
scikit-learn ve XGBoost class_weight parametresi sunar. Loss'u sınıf
ağırlığıyla çarp:
Pratik formül: (w_1 = N/(2 \cdot N_1)), (w_0 = N/(2 \cdot N_0)).
from sklearn.utils.class_weight import compute_class_weight import numpy as np # Otomatik hesaplama weights = compute_class_weight('balanced', classes=np.unique(y), y=y) class_weight_dict = dict(zip(np.unique(y), weights)) print(class_weight_dict) # {0: 0.5, 1: 100} gibi # scikit-learn'de from sklearn.ensemble import RandomForestClassifier clf = RandomForestClassifier(class_weight='balanced', random_state=42) # Veya custom oran clf = RandomForestClassifier(class_weight={0: 1, 1: 100}, random_state=42) # XGBoost'ta import xgboost as xgb # scale_pos_weight = N_neg / N_pos n_pos, n_neg = (y==1).sum(), (y==0).sum() clf = xgb.XGBClassifier(scale_pos_weight=n_neg/n_pos, random_state=42)
Avantaj: Tek parametre, tüm sklearn modellerinde destekli.
Dezavantaj: Tüm pozitif örneklere eşit ağırlık — "kolay" pozitiflere
gereksiz ağırlık verir.
Burada (p_t = p) eğer y=1, (p_t = 1-p) eğer y=0.
Focal Loss:#
İki ek terim:
- (\alpha_t) — class weight (genelde (\alpha) pozitif için, (1-\alpha) negatif için)
- ((1-p_t)^\gamma) — focusing parameter
Sezgi: model bir örneği zaten iyi sınıflandırıyorsa ((p_t) yüksek),
loss'un katkısı azaltılır. Tersine, zor örnekler ((p_t) düşük)
loss'a daha çok katkı yapar.
| γ değeri | Etki |
|---|---|
| 0 | Standard CE (class weight ile) |
| 1 | Hafif focusing |
| 2 | Tipik standart (RetinaNet papers) |
| 5 | Çok agresif focusing |
Sezgisel Örnek#
Bir pozitif örnek için p=0.9 → focal loss = standart CE'nin 0.01 katı (γ=2)
Bir pozitif örnek için p=0.1 → focal loss = standart CE'nin 0.81 katı (γ=2)
Yani modelin "kolay yaktığı" örnekler artık eğitime az katkı verir; "yanlış
yaptıkları" daha çok katkı verir. Hard example mining otomatik.
python
import torchimport torch.nn as nnimport torch.nn.functional as F class FocalLoss(nn.Module): """ Binary focal loss. Lin et al., 2017 — RetinaNet. """ def __init__(self, alpha=0.25, gamma=2.0, reduction='mean'): super().__init__() self.alpha = alpha self.gamma = gamma self.reduction = reduction def forward(self, logits, targets): # logits: [N], targets: [N] (0 veya 1) bce = F.binary_cross_entropy_with_logits(logits, targets.float(), reduction='none') p = torch.sigmoid(logits) p_t = p * targets + (1 - p) * (1 - targets) alpha_t = self.alpha * targets + (1 - self.alpha) * (1 - targets) focal_factor = (1 - p_t) ** self.gamma loss = alpha_t * focal_factor * bce if self.reduction == 'mean': return loss.mean() elif self.reduction == 'sum': return loss.sum() return loss # Kullanımfocal = FocalLoss(alpha=0.25, gamma=2.0)# logits = model(X)# loss = focal(logits, y)PyTorch'ta Focal Loss
Focal Loss Hyperparameter Tuning#
| Veri imbalance | α (positive weight) | γ (focusing) |
|---|---|---|
| 1:10 | 0.5-0.7 | 1-2 |
| 1:100 | 0.25 | 2 |
| 1:1.000 | 0.1 | 2-3 |
| 1:10.000+ | 0.05 | 3-5 |
Pratik: γ=2 standart başlangıç. α'yı veri imbalance'a göre ayarla. Çok agresif γ (>5) yakınsama problemi yapabilir.
Asymmetric Loss (Ben-Baruch et al., 2020)#
Focal loss'un yeni nesli. Pozitif ve negatif örnekler için farklı γ:
Burada (p_m = \max(p - m, 0)) — negatif örneklerde "margin" uygula.
Tipik tuning: (\gamma_+ = 0), (\gamma_- = 4), (m = 0.05).
Sezgi: Pozitif örneklere standart loss (her birine değer ver), ama negatif
örneklere daha agresif focusing (kolay negatifleri loss'tan dışla).
Multi-label classification'da en çok kullanılan; binary AD'de de işe yarar.
Tversky Loss, Dice Loss (Vision AD için)#
Görsel anomaly detection'da (Modül 24) piksel seviyesi imbalance baskındır
— defektsiz piksel ezici çoğunluk. Tversky loss bu duruma adapte:
α, β = FP/FN ağırlıkları. α=β=0.5 → Dice coefficient. α<β → Recall öncelikli.
Vision AD'de yaygın: defekt segmentation'da Tversky veya Focal Tversky loss
standart. Modül 24'te detaylı.
Hangi Loss Ne Zaman?#
| Senaryo | Önerilen Loss |
|---|---|
| 1:10 imbalance, tabular | Class weight + CE |
| 1:100 imbalance, tabular | Focal loss (γ=2) |
| 1:1000+ imbalance, tabular | Focal loss (γ=3) + class weight |
| Vision segmentation | Tversky veya Focal Tversky |
| Multi-label, tail-heavy | Asymmetric loss |
| Compliance gerekli (yorumlanabilir) | Class weight (basit, açıklanabilir) |
| Hızlı deney baseline | XGBoost + scale_pos_weight |
Karşılaştırma#
| Yöntem | Hyperparameter | Açıklanabilir | DL desteği | Klasik ML |
|---|---|---|---|---|
| Class weight | 1 | Çok | Var | Var |
| Cost matrix + threshold | 2 (cost) | Çok | Manuel | Manuel |
| Focal loss | 2 (α, γ) | Orta | Var | Yok |
| Asymmetric loss | 4 (α, γ±, m) | Az | Var | Yok |
| Tversky | 2 (α, β) | Orta | Var (vision) | Yok |
Sampling vs Cost-Sensitive: Ne Zaman Hangisi?#
Bu iki yaklaşım rakip değil, tamamlayıcı:
Sampling İyidir#
- Klasik ML modellerinde (RF, XGBoost, kNN)
- Categorical feature ağırlıklı veride (SMOTE-NC)
- Outlier'lar nadir ve "iyi tanımlı"
Cost-Sensitive İyidir#
- Deep learning modellerinde
- Maliyet açıkça hesaplanabiliyorsa
- Eğitim seti çok büyük (oversampling pratik değil)
- Adversarial fraud (sentetik veri attacker'ı yardımcı)
Hibrit Yaygın#
- Hafif SMOTE (örn. 1:10'a çıkar) + class weight
- DL'de: hafif oversampling + focal loss
- Production'da bu hibrit en stabil sonuç verir
🎯 Üretim için en sağlam yaklaşım
(1) Sampling'i abartma — pozitif örnekleri 1:1'e değil 1:10'a getir; (2) Focal loss veya class_weight ekle; (3) Cost-aware threshold optimization yap; (4) PR-AUC ve cost metric'i ile değerlendir. Bu dörtlü Türkiye'deki en olgun fraud takımlarının default pipeline'ı.
Gerçek Vaka: Türk Bankası Fraud Pipeline 2024#
Bir büyük Türk bankası 2024'te yaptığı pipeline güncellemesi:
Önce: XGBoost + SMOTE 1:1
- Train accuracy: %99.8
- Test PR-AUC: 0.42
- Üretim alarm rate: %0.4 (false positive %85)
Güncelleme adımları:
- SMOTE'u 1:1 → 1:5'e düşür (daha gerçekçi)
- XGBoost ekle (cost-aware)
scale_pos_weight=200 - Threshold'u cost-aware optimize et (FN/FP = 30:1 oranı)
- Validation PR-AUC ve cost metric ile model seç
Sonra: Aynı XGBoost, sadece loss & threshold ayarı
- Test PR-AUC: 0.57 (+%36)
- Üretim alarm rate: %0.18 (false positive %62)
- Aylık fraud kaybı: -1.4M TL
- Aylık analist saat: -180K TL (alarm azaldı)
Modeli değiştirmeden, sadece loss function & threshold mühendisliği bu kadar fark yarattı. Bu ders bunun sırrı.
👉 Bir sonraki ders
Ders 3.4 — Weak Supervision & Snorkel. Etiket azlığında 'programmatic labeling': domain expert kuralları → otomatik etiket. Snorkel framework, label model, Cleanlab ile etiket düzeltme. Healthcare ve insurance fraud'da kritik.
Sık Sorulan Sorular
γ=2 standart başlangıç. Validation set'inde PR-AUC'a göre 1, 2, 3 dene. γ çok büyük (>5) model yakınsamasını yavaşlatır. Veri 1:10.000+ imbalanced ise γ=3-4 deneyebilirsin.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Modül 0: Kurs Çerçevesi ve Atölye Kurulumu
Anomaly Detection Engineer Kimdir? Fraud, SRE, Quality Engineer ile Farklar ve Türkiye Maaş Manzarası
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu
Kurs Felsefesi: Neden Bu Yol, Neden Bu Sıra — Anomaly Detection Öğrenme Nehri
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu