Sıradaki

ReLU ve türevi

Zorluk: Kolay

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:

  • zz: ağırlıklı toplam, yani aktivasyon öncesi değer (pre-activation).
  • aa: 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 zz‘ye göre türevini (derivative) eleman bazında (element-wise) hesapla:

a=max⁡(0,z),dadz={1z>00z≤0a = \max(0, z), \qquad \frac{da}{dz} = \begin{cases} 1 & z > 0 \\ 0 & z \le 0 \end{cases}

ReLU, z=0z = 0 noktasında kırılır ve türevi orada tanımsızdır. Bu problemde z=0z = 0 için türev 00 alınır. Formüldeki z≤0z \le 0 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 z=0z = 0 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. a ReLU’nun çıktısı, da_dz türevidir. İkisi de z ile aynı shape’te birer NumPy array’idir.
  • z = 0 için türev 0 olmalı, 1 değil. z > 0 ise türev 1, aksi hâlde 0’dır.
  • İki array de float olmalı. Türev True ve False ya da tam sayılar değil, 0.0 ve 1.0 iç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 zz‘nin işaretine bağlıdır.

  • z>0z > 0: çıktı zz‘nin kendisi, türev 11.
  • z≤0z \le 0: çıktı 00, türev 00.

z=(−2,0,3)z = (-2, 0, 3) için çıktı a=(0,0,3)a = (0, 0, 3), türev (0,0,1)(0, 0, 1) olur.

Türev, geri geçişte (backward pass) gradyanın (gradient) nörondan geçip geçmeyeceğini belirler. z>0z > 0 ise gradyan olduğu gibi geçer. z≤0z \le 0 ise gradyan orada durur.

ReLU’nun sigmoid’e (değerleri 00 ile 11 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.

AktivasyonTürevGradyana etkisi
sigmoiden çok 0,250{,}25Gradyan her layer’da küçülür ve sonunda kaybolur.
ReLUpozitif tarafta tam 11Pozitif tarafta gradyan küçülmez.

ReLU’nun bir bedeli var. zz‘si hep negatif kalan bir nöronun türevi her örnekte 00‘dır. O nöron hiç öğrenmez.

zz‘nin tam 00 olduğu durumlar genellikle nadirdir. Bu yüzden z=0z = 0‘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.

  1. Çıktı için np.maximum(0.0, z) yaz. Negatifleri sıfırlar.
  2. Türev için (z > 0).astype(float) yaz. Karşılaştırma türevi verir, .astype(float) onu 1.0 ve 0.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 >= 0 ile yazmak: bu, z=0z = 0 için 1 verir.
  • np.sign(z) kullanmak: negatif girdilerde -1 verir, oysa türev oralarda 0’dır.
  • Python’un yerleşik max(0, z) ifadesini kullanmak: array üzerinde ValueError verir. Eleman bazında büyüğünü almak için np.maximum gerekir.

Bu problemde bir sorun mu var?

solution.py
import numpy as npdef relu_and_grad(z: np.ndarray) -> tuple[np.ndarray, np.ndarray]:    """ReLU'nun çıktısını ve z'ye göre türevini döndürür; ikisinin de şekli z ile aynıdır."""    # Kodunu buraya yaz.    return np.zeros_like(z), np.zeros_like(z)

İçindekiler

Geri bildirim

Tür