İki ay veri setinde MLP eğit
Zorluk: Zor Çözüldüsinir ağları
Bu problemde küçük bir çok katmanlı algılayıcıyı (multilayer perceptron, MLP) sıfırdan eğitir ve iki sınıflı bir veri kümesini ayırırsın. train(X_train, y_train, X_test) fonksiyonunu yaz. Fonksiyon MLP’yi eğitim kümesinde (training set) eğitir. Sonra test kümesindeki (test set) her örnek (sample) için tahmin ettiği sınıfı döndürür.
Veri kümesi (dataset) iki ay (two moons) biçimindedir: iki yarım çember birbirinin içine geçer, her noktaya rastgele gürültü eklenir. Üstteki ay sınıf 0, alttaki ay sınıf 1’dir. Fonksiyona üç array gelir:
X_train: eğitim noktaları, shape’i(300, 2)olan birfloatarray’i. Sütunlar noktanın iki koordinatıdır.y_train: eğitim etiketleri (label), shape’i(300,). Her değer 0 ya da 1’dir.X_test: test noktaları, shape’i(200, 2). Etiketleri sana verilmez.
Fonksiyon, X_test’teki her nokta için bir sınıf döndürür: 0 ve 1’lerden oluşan, (200,) shape’inde bir tam sayı (int) array’i.
Tahminlerin en az %95’i doğru olmalı. Doğruluk (accuracy), doğru tahminlerin oranıdır:
Köşeli parantezin içindeki koşul doğruysa değeri 1, değilse 0 olur. Formül doğru tahminlerin oranını verir.
Doğrusal bir model bu veride yetmez. İki ay bir doğruyla ayrılamaz. Lojistik regresyon yaklaşık %86’da kalır. En az bir gizli katman (hidden layer) ve doğrusal olmayan bir aktivasyon fonksiyonu (activation function) gerekir.
Örnekler
Girdi: n_per_corner = 30, seed = 0
Çıktı: array([1, 1, 1, ..., 0, 0, 1], shape=(100,))
Girdi: n_per_corner = 10, seed = 3
Çıktı: array([0, 0, 0, ..., 1, 0, 1], shape=(100,))
İpucu 1
İki girdi, 16 ReLU’lu bir gizli katman ve sigmoid’li tek çıktı yeterlidir. Kayıp (loss) olarak ikili çapraz entropi (binary cross-entropy) kullan. Sigmoid ve çapraz entropi birlikte düşünülünce çıktı katmanının gradyanı olur.
İpucu 2
Her epoch’ta sırasıyla ileri geçiş (forward pass), kayıp, geri geçiş (backward pass) ve güncelleme yap. Veri küçük olduğu için tüm eğitim kümesini her adımda kullanabilirsin. Gradyanları ile ortalamaya al.
İpucu 3
He ilklendirmesi, lr için 0.5 civarı ve 1000 epoch iyi bir başlangıçtır. Bu değerlerle eğitim bir saniyenin çok altında biter. Tahmin için çıktının sigmoid’ini hesaplamana gerek yok: ham skor (logit) 0’dan büyükse sınıf 1’dir. Sonucu astype(int) ile tam sayıya çevir.
Gereksinimler
- Dönüş değeri
inttüründe,(len(X_test),)shape’inde bir NumPy array’idir. Her değer 0 ya da 1’dir. Olasılık ya dafloatdöndürme. - Test set’te accuracy en az %95 olmalı. Testler ikinci bir iki ay verisinde de aynı sınırı arar.
- Model doğrusal olmayan bir problemi çözmeli. Testler ayrıca XOR benzeri bir veri dener: dört nokta öbeği, çaprazlardaki öbekler aynı sınıftan. Lojistik regresyon orada %50 civarında kalır; en iyi doğru bile %75’i geçemez.
- Modeli sen eğit. İlklendirme (initialization) rastgele olmalı: ağırlıkları sıfırla başlatırsan gizli nöronlar birbirinden ayrılmaz ve model öğrenemez.
- Eğitim kısa sürmeli. Testlerin tamamı 20 saniye içinde bitmeli. 300 örnek ve 1000 epoch (dataset’in tamamı üzerinden bir tur) bir saniyenin altında biter.
X_train,y_trainveX_test’i yerinde değiştirme.
Bir MLP, doğrusal bir ayırıcının yetmediği yerde karar sınırını (decision boundary) büker. Gizli katman girdiyi öyle bir uzaya taşır ki sınıflar orada doğruyla ayrılabilir. ReLU gibi bir aktivasyon olmasa iki katman tek bir doğrusal katmana indirgenirdi.
Eğitim döngüsü dört adımdır: ileri geçiş, kayıp, geri geçiş, güncelleme. İkili sınıflandırmada sigmoid ve ikili çapraz entropinin birleşik gradyanı olur. Bu, doğrusal modelle aynı sadelikte bir ifadedir.
Kararlı bir eğitim için ağırlıkları sıfırdan farklı, uygun ölçekte başlatmak gerekir. Bunu Xavier ve He ilklendirmesi probleminde yazarsın.
Daha fazlası için Bir MLP eğitmek dersine bak.
İki katmanlı bir ağ kur ve tüm eğitim kümesiyle gradyan inişi yap. Ağırlıkları He ile, sapmaları sıfırla başlat. Her epoch’ta ileri geçiş, geri geçiş ve güncelleme sırasıyla çalışır. Sonunda test noktalarında logit’e bak.
import numpy as npdef train(X_train: np.ndarray, y_train: np.ndarray, X_test: np.ndarray) -> np.ndarray: rng = np.random.default_rng(0) n = len(X_train) hidden, lr, epochs = 16, 0.5, 1000 # He ilklendirmesi; bias'lar sıfır W1 = rng.normal(0.0, np.sqrt(2.0 / 2), (2, hidden)) b1 = np.zeros(hidden) W2 = rng.normal(0.0, np.sqrt(2.0 / hidden), (hidden, 1)) b2 = np.zeros(1) for _ in range(epochs): # ileri geçiş Z1 = X_train @ W1 + b1 A1 = np.maximum(Z1, 0.0) p = 1.0 / (1.0 + np.exp(-(A1 @ W2 + b2)[:, 0])) # geri geçiş: sigmoid ve ikili çapraz entropi için dZ2 = (p - y) / n dZ2 = ((p - y_train) / n)[:, None] dW2 = A1.T @ dZ2 db2 = dZ2.sum(axis=0) dZ1 = (dZ2 @ W2.T) * (Z1 > 0) dW1 = X_train.T @ dZ1 db1 = dZ1.sum(axis=0) # güncelleme W1 -= lr * dW1 b1 -= lr * db1 W2 -= lr * dW2 b2 -= lr * db2 logits = np.maximum(X_test @ W1 + b1, 0.0) @ W2 + b2 return (logits[:, 0] > 0).astype(int)
Sık yapılan hata, gradyanı ile ortalamamaktır. lr sabitken adım örnek sayısıyla büyür ve eğitim ıraksar ya da nan üretir.
Bir başka hata, (p - y)’yi (n, 1) yerine (n,) shape’iyle bırakıp A1.T @ dZ2 işlemini yanlış shape’lerle yapmaktır. Gradyanlar da ağırlıklarla aynı shape’te olmalıdır.
Bu problemde bir sorun mu var?