ReLU ve türevi
Zorluk: Kolay Çözüldüaktivasyon fonksiyonları
ReLU (rectified linear unit), en yaygın aktivasyon fonksiyonlarından (activation function) biridir. Negatif girdileri sıfıra çeker, pozitif girdileri olduğu gibi bırakır.
Bir nöron (neuron) ağırlıklı toplamını hesaplar. ReLU bu toplamdan nöronun çıktısını üretir:
- : ağırlıklı toplam, yani aktivasyon öncesi değer (pre-activation).
- : nöronun çıktısı, yani aktivasyon sonrası değer (activation).
relu_and_grad(z) fonksiyonunu yaz. z, herhangi bir şekle (shape) sahip bir float dizisidir (array). ReLU’yu ve ‘ye göre türevini (derivative) eleman bazında (element-wise) hesapla:
ReLU, noktasında kırılır ve türevi orada tanımsızdır. Bu problemde için türev alınır. Formüldeki koşulu bunu söyler.
Fonksiyon (a, da_dz) biçiminde, iki array içeren bir demet (tuple) döndürmeli. İlk array ReLU’nun çıktısı, ikincisi türevi. İkisinin de shape’i z ile aynıdır.
Örnekler
Girdi: z = [-2.0, -0.5, 0.5, 3.0]
Çıktı: (array([0. , 0. , 0.5, 3. ]), array([0., 0., 1., 1.]))
Girdi: z = [[-1.5, 0.0, 2.0], [3.0, -0.5, 0.0]]
Çıktı: (array([[0., 0., 2.],
[3., 0., 0.]]), array([[0., 0., 1.],
[1., 0., 0.]]))
Girdi: z = [-30.0, -1e-09, 1e-09, 40.0]
Çıktı: (array([0.e+00, 0.e+00, 1.e-09, 4.e+01]), array([0., 0., 1., 1.]))
İpucu 1
np.maximum iki değeri eleman bazında karşılaştırır ve büyüğünü verir. ReLU her eleman için z ile 0’dan büyük olanı alır. Python’un yerleşik max’ı array’lerde çalışmaz.
İpucu 2
Türev, z > 0 karşılaştırmasının kendisidir. z > 0 ise 1, değilse 0 çıkar.
z >= 0 ile z > 0 yalnızca noktasında ayrılır. Hangisinin orada 0 verdiğine bak.
İpucu 3
.astype(float), bool array’ini 1.0 ve 0.0 değerli bir float array’ine çevirir. z > 0, True ve False içeren bir array verir. İki sonucu return a, da_dz ile bir tuple olarak döndür.
Gereksinimler
z, herhangi bir shape’te bir float array’idir. Tek boyutlu da olabilir, iki boyutlu da. Fonksiyon her elemanı ayrı hesaplar.- Dönüş değeri
(a, da_dz)tuple’ıdır.aReLU’nun çıktısı,da_dztürevidir. İkisi dezile aynı shape’te birer NumPy array’idir. z = 0için türev0olmalı,1değil.z > 0ise türev1, aksi hâlde0’dır.- İki array de float olmalı. Türev
TrueveFalseya da tam sayılar değil,0.0ve1.0içermeli. z’yi değiştirme. Fonksiyon bittiğinde çağıran kodun array’i aynı kalmalı.- Elemanlar üzerinde döngü kullanma: iki NumPy ifadesi yeter.
ReLU’nun çıktısı da türevi de ‘nin işaretine bağlıdır.
- : çıktı ‘nin kendisi, türev .
- : çıktı , türev .
için çıktı , türev olur.
Türev, geri geçişte (backward pass) gradyanın (gradient) nörondan geçip geçmeyeceğini belirler. ise gradyan olduğu gibi geçer. ise gradyan orada durur.
ReLU’nun sigmoid’e (değerleri ile arasına sıkıştıran fonksiyon) üstünlüğü de bu türevden gelir. Gradyan geriye doğru her layer’dan geçerken layer’ın türeviyle çarpılır. Çarpanlar küçükse gradyan sonunda kaybolur; buna kaybolan gradyan (vanishing gradient) denir.
| Aktivasyon | Türev | Gradyana etkisi |
|---|---|---|
| sigmoid | en çok | Gradyan her layer’da küçülür ve sonunda kaybolur. |
| ReLU | pozitif tarafta tam | Pozitif tarafta gradyan küçülmez. |
ReLU’nun bir bedeli var. ‘si hep negatif kalan bir nöronun türevi her örnekte ‘dır. O nöron hiç öğrenmez.
‘nin tam olduğu durumlar genellikle nadirdir. Bu yüzden ‘daki kabul pratikte çoğu zaman az fark yaratır.
Yine de kod her yerde aynı kabulü kullanmalı. Testler de 0’ı bekler.
Daha fazlası için Nöronlar ve aktivasyonlar dersine bak.
İki NumPy ifadesi yeter.
- Çıktı için
np.maximum(0.0, z)yaz. Negatifleri sıfırlar. - Türev için
(z > 0).astype(float)yaz. Karşılaştırma türevi verir,.astype(float)onu1.0ve0.0’a çevirir.
import numpy as npdef relu_and_grad(z: np.ndarray) -> tuple[np.ndarray, np.ndarray]: a = np.maximum(0.0, z) da_dz = (z > 0).astype(float) return a, da_dz
Sık yapılan üç hata var:
- Türevi
z >= 0ile yazmak: bu, için1verir. np.sign(z)kullanmak: negatif girdilerde-1verir, oysa türev oralarda0’dır.- Python’un yerleşik
max(0, z)ifadesini kullanmak: array üzerindeValueErrorverir. Eleman bazında büyüğünü almak içinnp.maximumgerekir.
Bu problemde bir sorun mu var?