Yoğun katman ileri geçişi
Zorluk: Orta Çözüldüsinir ağları
Yoğun katman (dense layer), sinir ağlarının temel yapı taşıdır. Layer’daki her nöron (neuron) bir örnek (sample) için şunları yapar:
- Örneğin bütün özniteliklerini (feature) kendi ağırlıklarıyla (weight) çarpar ve toplar.
- Bir sapma (bias) ekler.
- Sonucu bir aktivasyon fonksiyonundan (activation function) geçirir.
Bütün nöronları ve bütün örnekleri tek bir matris çarpımıyla (matrix product) hesaplayabilirsin.
dense_forward(X, W, b, activation) fonksiyonunu yaz. Fonksiyon, layer’ın ileri geçişini (forward pass) hesaplar. Girdiler şunlardır:
X: şekli (shape)(n, d_in)olan bir dizi (array). Her satır bir örnektir.W:(d_in, d_out)shape’inde weight matrisi. . sütunu . nöronun weight’leridir.b:(d_out,)shape’inde bir vektör. Her nöron için bir bias içerir.activation: aktivasyon fonksiyonunun adı, birstr.
aktivasyon öncesi değerlerdir (pre-activation). , ‘nin her satırına eklenir. Aktivasyon, bias eklendikten sonra uygulanır.
, activation adıyla seçilen fonksiyondur. ‘nin her elemanına ayrı uygulanır. Seçenekler şunlardır:
-
"linear": , yani aktivasyon yok. -
"relu": . ReLU (rectified linear unit) negatifleri sıfıra çeker. -
"sigmoid": sigmoid her değeri ile arasına sıkıştırır. -
"tanh": . Tanh (hiperbolik tanjant) her değeri ile arasına sıkıştırır.
Fonksiyon (n, d_out) shape’inde A’yı döndürmeli. Tanınmayan bir isim verilirse ValueError fırlat.
Örnekler
Girdi: X = [[1.0, -2.0], [0.5, 3.0], [-1.0, 0.0]], W = [[0.5, -1.0, 2.0], [1.5, 0.25, -0.5]], b = [0.1, -0.2, 0.3], activation = 'relu'
Çıktı: array([[0. , 0. , 3.3 ],
[4.85, 0.05, 0. ],
[0. , 0.8 , 0. ]])
Girdi: X = [[1.0, 2.0, 3.0]], W = [[0.5], [-1.0], [2.0]], b = [-6.0], activation = 'linear'
Çıktı: array([[-1.5]])
Girdi: X = [[-1.0, 2.0, 0.5], [0.0, -3.0, 1.0]], W = [[1.0, -0.5], [0.25, 1.0], [-2.0, 0.5]], b = [0.5, -1.0], activation = 'sigmoid'
Çıktı: array([[0.26894142, 0.8519528 ],
[0.09534946, 0.02931223]])
İpucu 1
Z = X @ W + b ile başla. Shape’lere bak: (n, d_in) @ (d_in, d_out), (n, d_out) verir.
NumPy, (d_out,) shape’indeki b’yi her satıra yayınlar (broadcasting).
İpucu 2
activation’a göre bir if / elif zinciri ya da bir sözlük kullanabilirsin. Hiçbirine uymayan bir isimde raise ValueError(...) yaz.
Aktivasyonlar eleman bazında (element-wise) çalışır. ReLU için np.maximum(0.0, Z), tanh için np.tanh(Z) yeter.
İpucu 3
Sigmoid’i Kararlı sigmoid probleminde yazdığın gibi hesapla: np.exp’e hiç büyük pozitif bir sayı verme. İki ifade de sorunludur:
1 / (1 + np.exp(-Z)), büyük negatifZ’denp.exp’i taşırır. Sonuç yine0çıkar.np.exp(Z) / (1 + np.exp(Z)), büyük pozitifZ’deinf / inf, yaninanverir.
Gereksinimler
X(n, d_in),W(d_in, d_out),b(d_out,)shape’indedir.X @ Wdoğrudan çalışır.W’nin devriğini (transpose) almana gerek yok.- Dönüş değeri
(n, d_out)shape’inde bir NumPy array’idir.n = 1ya dad_out = 1olsa bile iki boyutlu kalmalı. - Bias, aktivasyondan önce eklenir. hesapla, değil.
- Tanınmayan bir
activationadı içinValueErrorfırlat. SessizceZ’yi döndürme. - Sigmoid ve tanh, büyük girdilerde de (
1000ya da-1000gibi)nanya dainfüretmemeli. X’i,W’yi veb’yi değiştirme. Fonksiyon bittiğinde çağıran kodun array’leri aynı kalmalı.- Örnekler üzerinde döngü kullanma: tek bir matris çarpımı yeter.
Layer her nöron için ağırlıklı toplamı hesaplar, bias ekler ve aktivasyonu uygular. İki özniteliği olan tek bir örnek, , ve iki nöronlu bir layer alalım:
Hesap üç adımdır:
- Ağırlıklı toplamları bul: .
- Bias ekle: .
- ReLU uygula: . Birinci nöron kapanır, ikincisi geçirir.
Birçok örnek olduğunda her satır için aynı işlem yapılır. Matris çarpımı hepsini tek seferde hesaplar.
Aktivasyon gereklidir. Aktivasyonsuz iki layer’ı üst üste koyarsan sonuç yine tek bir doğrusal layer olur:
Layer’lar arasındaki doğrusal olmayan aktivasyon, ağın doğrusal bir modelin yapamadığı şeyleri öğrenmesini sağlar. "linear" seçeneği, çıktı layer’ı gibi aktivasyonun gerekmediği yerlere uygundur.
Bu kursta layer X @ W + b olarak yazılır. Başka bir kaynak okurken ‘nin shape’ine bak:
| Kaynak | shape’i |
|---|---|
| Bu kurs | (d_in, d_out) |
PyTorch nn.Linear | (d_out, d_in), yani devriği |
Daha fazlası için Nöronlar ve aktivasyonlar dersine bak.
Layer X @ W + b ile başlar ve aktivasyonu bias’tan sonra uygular.
X @ W + bile ‘yi hesapla.- Aktivasyonu
activationadına göre seç. - Tanınmayan bir ad için
ValueErrorfırlat.
Sigmoid için kararlı biçimi kullan. e = np.exp(-np.abs(Z)) her Z’de güvenlidir, çünkü argümanı hiçbir zaman pozitif olmaz. Sigmoid iki durumda şöyle olur:
Z >= 0için .Z < 0için .
import numpy as npdef dense_forward(X: np.ndarray, W: np.ndarray, b: np.ndarray, activation: str) -> np.ndarray: Z = X @ W + b if activation == "linear": return Z if activation == "relu": return np.maximum(0.0, Z) if activation == "sigmoid": e = np.exp(-np.abs(Z)) return np.where(Z >= 0, 1 / (1 + e), e / (1 + e)) if activation == "tanh": return np.tanh(Z) raise ValueError(f"Tanınmayan aktivasyon adı: {activation}")
Sık yapılan üç hata var:
- Bias’ı aktivasyondan sonra eklemek:
np.maximum(0.0, X @ W) + b. Bias negatifse ReLU’dan sonra negatif bir değer kalır. Oysa ReLU’nun çıktısı hiçbir zaman negatif olmaz. W’nin devriğini almak:Wzaten(d_in, d_out)shape’indedir.- Sigmoid’i
1 / (1 + np.exp(-Z))olarak yazmak: büyük negatifZ’denp.exp’i taşırır. Sonuç yine doğru çıksa da Kararlı sigmoid probleminde öğrendiğin kuralı bozar.
Bu problemde bir sorun mu var?