Kısım III · Merak · Bölüm 51

Nöron, Katman, MLP

Motorla bir beyin taklidi kurmak (Neurons, layers, multi-layer perceptron)

Neden burada · Neye dayanıyor

Neden burada: Son iki bölümde küçük bir motor kurduk: sayıları Value nesnelerine sarıyor, hesabı bir grafik olarak kaydediyor ve sonuçtan geriye doğru "kim ne kadar sorumlu" diye soruyorduk. Ama motorun elinde henüz anlamlı bir şey yok: toplama, çarpma, birkaç matematik işlemi. Bu bölümde o motorun üstüne ilk gerçek yapıyı koyuyoruz: yapay nöron, nöronlardan katman, katmanlardan çok katmanlı ağ. Yani "öğrenebilen şey"in kendisi, henüz öğrenmeden, sadece iskeleti.

Neye dayanıyor: Bölüm 49'dan Value nesnesini ve hesap grafiğini (her sayı, onu üreten işlemi ve girdilerini bilir); Bölüm 50'den geri yayılımı (bir sonuçtaki gradyanı çarpma ve toplama düğümlerinden geriye taşımak). Ayrıca Bölüm 47'deki model ve parametre kavramlarını: parametre, modelin içindeki ayarlanabilir sayıdır. Bu bölümde parametrelerin tam olarak ne olduğunu göreceksin.

  1. Kat 10Uygulamalar: bizimki ve içinde yaşayan yapay zekâSinir ağı, başka her program gibi bir programdır; en üst katta, bir uygulama olarak yaşar.
  2. Kat 4–9Python, işletim sistemi, dosyalar, ağAğı yazdığımız dil ve çalıştığı yer. Bölüm 9–20, 21.
  3. Kat 3İşlemci ve GPUAğın gücünü aldığı yer: milyarlarca toplama ve çarpma. Bölüm 6, ayrıca Bölüm 55.4.
  4. Kat 0–2Bit, kapı, devreHer toplama ve çarpma sonunda bunlardır. Bölüm 2–5.

Bu bölümün sonunda şunları bileceksin: bir yapay nöronun yalnızca "ağırlıklı toplam artı sapma, sonra bir büküm" olduğunu; o bükümün (etkinleştirme fonksiyonunun) neden olmazsa olmaz olduğunu; nöronların katman, katmanların çok katmanlı ağ olduğunu; Karpathy'nin micrograd'ındaki 50 satırlık nn.py dosyasını satır satır okuyabildiğini; ve "bu modelin kaç parametresi var" sorusunun nasıl cevaplandığını, böylece "model büyüklüğü" lafının ne demek olduğunu.

51.1 Yapay nöron: ağırlık, sapma, toplam

Önce adı çözelim, çünkü ad yanıltıcı. Canlılardaki sinir hücresi (nöron) başka hücrelerden sinyal alır, bir eşiği aşarsa kendi sinyalini yollar. Yapay nöron bundan esinlenmiştir, ama bu esin kabaca bir fikirden öteye geçmez: birçok girdiyi alan, hepsini tek bir sayıya indiren küçük bir birim. Karpathy'nin deyişiyle (micrograd README'si) bizim "nöron" dediğimiz şey, motorun gözünden bakınca çok sayıda küçük toplama ve çarpmadan başka bir şey değildir; micrograd her nöronu bu ufak toplama ve çarpmalarına ayırır.1 Bu, Bölüm 49'daki grafiğin tam olarak istediği şeydir.

Gündelik bir benzetme: puan formülü

Nöronu tanımadan önce, aslında onu zaten bildiğini görelim. Uygulamamızda bir kullanıcının o günkü puanını şöyle hesapladığımızı düşün:

puan = 10 * dogru_sayisi + 2 * seri_gunu - 3 * kaybedilen_can

Üç girdi var (doğru sayısı, seri günü, kaybedilen can). Her girdinin yanında bir çarpan var (10, 2, −3): bu girdi sonuca ne kadar ve hangi yönde etki etsin. Sonuç çarpımların toplamı. Yapay nöronun ilk yarısı tam budur. Tek fark, çarpanları (10, 2, −3) bu örnekte biz elle seçtik; bir nöronda bu çarpanlar öğrenilir. Bu bölüm çarpanların ne olduğunu, sonraki bölüm (Bölüm 52) onların nasıl bulunduğunu anlatıyor.

Nöronun parçaları

Bir nöronun elindeki her şey şunlardır:

Formül olarak, her sembolü yukarıda tanıttığımıza göre:

toplam = w1*x1 + w2*x2 + ... + wn*xn + b

Hesaplı bir örnek. İki girdili bir nöron kuralım: x1 bir kullanıcının bugün çözdüğü soru sayısı, x2 bugün yaptığı hata sayısı olsun (örnek tamamen uydurma bir senaryo; amaç yalnızca aritmetiği görmek). Ağırlıklar w1 = 0,5 ve w2 = −1,0, sapma b = 0,25 olsun. Kullanıcı 2 soru çözdü ve 3 hata yaptıysa:

toplam = 0,5*2 + (-1,0)*3 + 0,25 = 1 - 3 + 0,25 = -1,75

Başka bir kullanıcı 2 soru çözdü ve (hata yerine) bu kez x2 = −3 girdisi aldıysa (yalnızca işaret farkını görmek için): 0,5·2 + (−1,0)·(−3) + 0,25 = 4,25. Ağırlığın işareti ve girdinin işareti birlikte belirler; bu aritmetiğin tamamı ilkokul düzeyindedir. (Bu iki sayıyı terminalde python ile yeniden hesapladım: −1,75 ve 4,25.)

Kodda nöron: nn.py'nin ilk sınıfı

Karpathy'nin micrograd deposundaki micrograd/nn.py dosyası, ağın tamamını yaklaşık 50 satırda yazar.2 Nöron sınıfını okuyalım (engine.py'daki Value'yu Bölüm 49'dan biliyorsun):

class Neuron(Module):

    def __init__(self, nin, nonlin=True):
        self.w = [Value(random.uniform(-1,1)) for _ in range(nin)]
        self.b = Value(0)
        self.nonlin = nonlin

    def __call__(self, x):
        act = sum((wi*xi for wi,xi in zip(self.w, x)), self.b)
        return act.relu() if self.nonlin else act

    def parameters(self):
        return self.w + [self.b]

Satır satır:

Dikkat edilecek bir şey: bu kodda hiç "geri yayılım" yok. Gerek yok. Nöron yalnızca + ve * kullanıyor; her + ve * sonucunu bir Value olarak üretiyor ve Bölüm 49–50'de kurduğumuz mekanizma, nöronun içinde ne olduğunu bilmeden gradyanları geri taşıyabiliyor. Bu bir soyutlama zaferidir (Bölüm 1.4): motor nöronu, nöron motoru bilmeden birlikte çalışıyor.

Tek nöronun gradyanı: Bölüm 50'ye geri dönüş

Karpathy'nin ders defterinde (micrograd dersi, ikinci yarı) tek bir nöron elle kurulur: x1 = 2, x2 = 0, w1 = −3, w2 = 1, b = 6,8813735870195432.3 Bu sapmanın tuhaf görünen uzun ondalığı bilerek seçilmiştir: toplamın tanh'ı güzel bir sayı çıksın diye. Aynı sayıları micrograd'ın engine.py'sine verip (tanh'ı ders defterindeki gibi ekleyerek) çalıştırdım:

DeğerSayıAnlamı
toplam n0,88142·(−3) + 0·1 + 6,8814
çıktı o = tanh(n)0,7071toplamın büküm sonrası hali
gradyan w11,0w1'i azıcık artırırsan çıktı yaklaşık o kadar artar (1 katı)
gradyan x1−1,5girdiyi artırmak çıktıyı azaltır
gradyan w20,0çünkü x2 = 0; çarpan sıfırsa ağırlığın etkisi yok
gradyan b0,5sapma toplamı doğrudan etkiler; tanh'ın o noktadaki eğimi 0,5

Hepsi Bölüm 50'deki kuralların doğrudan sonucu: çarpma düğümünde bir girdinin gradyanı diğer girdinin değeri çarpı gelen gradyan, toplama düğümünde gradyan olduğu gibi geçer. w2'nin gradyanının sıfır olması bu kuralın kendisidir: x2 = 0 olduğu için w2 ne olursa olsun çıktı değişmez. (Bu sayıları kendim çalıştırarak doğruladım; hatta ders defterinde aynı örnek PyTorch ile de çözülür ve aynı gradyanlar çıkar.)3

51.2 Etkinleştirme fonksiyonu: tanh, ReLU; neden doğrusal olmamak gerekir

Nöronun ikinci yarısı: toplamı, düz bir şekilde dışarı vermek yerine bir fonksiyondan geçirmek. Bu fonksiyona etkinleştirme fonksiyonu (activation function) denir. Neden gerek? Bunu anlamak için önce olmadığında ne olacağına bakalım.

Sorun: düz toplamları üst üste koymak hiçbir şey kazandırmaz

Diyelim iki nöron zinciri kurduk ve ikisi de yalnızca ağırlıklı toplam yapıyor, büküm yok. Birinci nöron h = 2x + 1 hesaplasın (ağırlık 2, sapma 1), ikinci nöron y = 3h − 4 (ağırlık 3, sapma −4). Birinciyi ikincinin içine yerleştirirsek:

y = 3*(2*x + 1) - 4 = 6*x + 3 - 4 = 6*x - 1

İki katman, tek bir y = 6x − 1'e çöktü. Bu bir kaza değil: düz çarpma ve toplamlarla yapılan her zincir, ne kadar uzun olursa olsun, sonunda tek bir "ağırlıklı toplam"a eşittir. Buna doğrusal (linear) hesap denir, çünkü girdi iki katına çıkınca çıktı da (sapma hariç) iki katına çıkar; grafiği düz bir çizgidir. Yani yüz katman koysak bile elimizde tek bir nöronun gücü kalır, ve tek nöron yalnızca "girdileri tart, topla" yapabilir. "Bu iki girdiden biri yüksek ama ikisi birden değilse evet de" gibi basit bir kuralı bile yazamaz.

Çözüm: nöronun toplamını, düz olmayan (doğrusal olmayan (nonlinear)) bir fonksiyondan geçirmek. O zaman katmanlar birbirine çökmez; her katman, bir öncekinin yaptığı bükülmüş sonuç üstüne yeni bir büküm ekler. Karpathy'nin ve 3Blue1Brown'ın anlatımında bu hep aynı şekilde geçer: ağırlıklı toplam artı sapma, sonra bir doğrusal olmayan fonksiyonun sarılması.4

tanh

Karpathy'nin derste kullandığı büküm tanh (hyperbolic tangent, hiperbolik tanjant)'tır. Formülünü ezberlemene gerek yok; davranışı yeter: küçük sayılara yaklaşık olduğu gibi davranır, büyük sayıları ise −1 ile +1 arasına sıkıştırır. Python ile hesapladığım birkaç değer:

Girdi (toplam)tanh(girdi)Yorum
00merkez; eğim 1,0
0,50,4621hâlâ yaklaşık doğru orantılı
10,7616sıkışma başladı
20,9640neredeyse +1
−3−0,9951neredeyse −1

tanh'ın eğimi (Bölüm 48'deki türev) 0'da 1,0, 3'te yaklaşık 0,0099, 5'te yaklaşık 0,00018'dir. Yani girdi büyüdükçe fonksiyon düzleşir ve eğim sıfıra yaklaşır. Bunun sonuçlarını Bölüm 52'de eğitim sırasında göreceksin: eğimi (gradyanı) sıfır olan bir yere sıkışan nöron öğrenemez.

ReLU

Daha yeni ve daha basit olan seçenek ReLU (rectified linear unit): negatifleri sıfırla, pozitifleri olduğu gibi bırak. Kod olarak tek satır, micrograd'ın engine.py'sinde:

def relu(self):
    out = Value(0 if self.data < 0 else self.data, (self,), 'ReLU')

    def _backward():
        self.grad += (out.data > 0) * out.grad
    out._backward = _backward

    return out

İlk satır: veri sıfırdan küçükse sıfır, değilse veri. _backward (Bölüm 50): gradyan, çıktı sıfırdan büyükse (out.data > 0, doğruysa 1, yanlışsa 0) olduğu gibi geçer; değilse kesilir. Önceki bölümdeki örneklerimizden: toplam −1,75 ise ReLU sonucu 0, toplam 4,25 ise 4,25. Sonuç: ReLU'nun eğimi pozitif tarafta her zaman 1, negatif tarafta her zaman 0'dır. (Buradan doğal bir gözlem çıkar: bir nöronun toplamı her örnekte negatif kalırsa gradyanı hep sıfır olur ve ağırlıkları hiç güncellenmez; ona "ölü ReLU" denir.)

Hangisi?

micrograd'ın deposu (nn.py) ReLU kullanır;2 Karpathy'nin ders defteri ise tanh. İkisi de aynı işi yapar: toplamı büker. 3Blue1Brown'ın yazılı dersi, bir ağırlıklı toplamın sigmoid ya da ReLU gibi doğrusal olmayan bir fonksiyona sarıldığını söyler;4 yani "etkinleştirme fonksiyonu" tek bir fonksiyonun adı değil, bir görevin adıdır. Bu kitapta bir seçeneğe sadık kalmak zorunda değiliz; önemli olan ilkeyi bilmek: bükmezsen katmanlar çöker.

51.3 Katman ve çok katmanlı algılayıcı (MLP)

Katman

Bir nöron tek bir sayı üretir. Ama çoğu zaman bir girdiye aynı anda birçok farklı bakış açısı isteriz. Çözüm: aynı girdileri, birbirinden bağımsız ağırlıkları olan birçok nörona birden vermek. Yan yana dizilmiş, aynı girdileri gören nöronlar kümesine katman (layer) denir. Kodu yine nn.py'den:

class Layer(Module):

    def __init__(self, nin, nout, **kwargs):
        self.neurons = [Neuron(nin, **kwargs) for _ in range(nout)]

    def __call__(self, x):
        out = [n(x) for n in self.neurons]
        return out[0] if len(out) == 1 else out

    def parameters(self):
        return [p for n in self.neurons for p in n.parameters()]

Bir katmanın girdisi bir sayı listesidir, çıktısı da bir sayı listesidir: bu listelerin uzunluğu farklı olabilir. 3 sayı girer, 4 sayı çıkar (Layer(3, 4)). Bu, bir sonraki katmana girdi olarak verilebilir. Zincirin mantığı bu.

Çok katmanlı ağ

Katmanları art arda dizersek elimizde çok katmanlı algılayıcı (MLP, multi-layer perceptron) olur. (Perceptron, "algılayıcı", bu fikrin tarihsel adıdır; bugün onu "bir nöron" gibi okuyabilirsin.) Girdi, birinci katmana girer; onun çıktıları ikinci katmana girdi olur; böyle gider; son katmanın çıktısı ağın cevabıdır. Kod:

class MLP(Module):

    def __init__(self, nin, nouts):
        sz = [nin] + nouts
        self.layers = [Layer(sz[i], sz[i+1], nonlin=i!=len(nouts)-1)
                       for i in range(len(nouts))]

    def __call__(self, x):
        for layer in self.layers:
            x = layer(x)
        return x

    def parameters(self):
        return [p for layer in self.layers for p in layer.parameters()]

Önce MLP(3, [4, 4, 1]) yazdığımızı düşün. Anlamı: "3 girdi var; birinci katmanda 4 nöron, ikinci katmanda 4 nöron, son katmanda 1 nöron." sz = [nin] + nouts bunu [3, 4, 4, 1] listesi yapar: her katman, listede yan yana duran iki sayıyla tanımlanır (sz[i] girdi, sz[i+1] çıktı sayısı): 3→4, 4→4, 4→1. nonlin=i!=len(nouts)-1 ince bir ayrıntı: son katman hariç her katman bükülür; son katman düz bırakılır, çünkü son çıktıyı (örneğin −1 ile 1 arasında bir hüküm ya da herhangi bir sayı) bükmeye gerek yok. __call__: x'i her katmandan sırayla geçir: x = layer(x).

Kerem için şöyle de okunabilir: bu, bir boru hattı (pipeline). Her katman bir önceki katmanın çıktısını girdi olarak alır; kimse atlamaz. Aradaki katmanlara gizli katman (hidden layer) denir: ne girdidirler ne çıktı, bir ağın "içinde" kalırlar. 3Blue1Brown'ın rakamları tanıyan ağı örneğinde 784 girdi (28×28 pikselin her biri), 16 nöronluk iki gizli katman ve 10 çıktı vardır; ilk katmanın kenarları, ikinci katmanın döngü ve çizgileri tanıyacağı umulur.5 Bu umut bir umuttur: ağa "kenar bul" demiyoruz, hepsini eğitim sırasında ağın kendisi buluyor (Bölüm 52).

Üç sınıf, tek ortak ata: Module

Neuron, Layer ve MLP üçü de Module'dan türer. Module iki iş yapar: parameters() (varsayılan olarak boş liste) ve zero_grad() (bütün parametrelerin gradyanını sıfırlamak). İkincisi Bölüm 52'nin kahramanı olacak. Yani ağın kendisi bir iç içe geçmiş kutu: MLP katmanları tutar, katman nöronları tutar, nöron Value'ları tutar. Bir parametre listesi istenince en dıştaki kutu içindekilere sorar, onlar da kendi içindekilere. Hukuk dilinde bir üst norm ile alt norm gibi bir hiyerarşi; ama burada hiyerarşi yalnızca bir yapıdır, otoriteyi Bölüm 52'deki kayıp fonksiyonu belirler.

İleri geçiş: bir MLP'nin gerçekten ne yaptığı

Bölüm 49'da öğrendiğin ileri geçiş (forward pass) burada hiçbir yeni şey değil. Karpathy'nin derste kurduğu MLP(3, [4, 4, 1]) ağına [2.0, 3.0, -1.0] girdisini verdiğinde sonuç tek bir sayıdır. Ben aynı ağı (tanh'lı ders sürümü) random.seed(42) ile kurdum ve ders defterinin dört örneğini verdim:

xs = [
  [2.0, 3.0, -1.0],
  [3.0, -1.0, 0.5],
  [0.5, 1.0, 1.0],
  [1.0, 1.0, -1.0],
]
ys = [1.0, -1.0, -1.0, 1.0]   # istenen çıktılar

Başlangıçta ağ rastgele olduğu için dört örnek için tahminleri 0,6994, 0,5026, 0,6932 ve 0,8755 çıktı. İstenen cevaplar +1, −1, −1, +1. Yani ağ, rastgele ağırlıklarla yaklaşık her örneğe "evet-ish" diyor: ikinci ve üçüncü örnekte tamamen yanlış. Ağı doğru yapacak sihir ağırlıklarda; bu sihri bir sonraki bölümde kuracağız. Şimdilik önemli olan bir ağın ileri geçişinin hesap grafiği olarak nasıl göründüğü: her nörondaki her çarpma ve toplama ayrı bir düğüm, ve bütün düğümlerin gradyanı Bölüm 50'deki geri yayılımla hesaplanabilir.

51.4 Parametre sayısı ve model büyüklüğü

Parametre (parameter), Bölüm 47'de tanıttığımız kavram: modelin içindeki ayarlanabilir sayı. Artık somut olarak biliyoruz: ağırlıklar ve sapmalar. Sayımı basit bir kural belirler: bir katmanda her nöronun (girdi sayısı + 1) parametresi var (her girdi için bir ağırlık, artı bir sapma); katmanın parametre sayısı bunun nöron sayısıyla çarpımı.

MLP(3, [4, 4, 1]) için sayalım:

KatmanHesapParametre
3 → 44 nöron × (3 ağırlık + 1 sapma)16
4 → 44 nöron × (4 ağırlık + 1 sapma)20
4 → 11 nöron × (4 ağırlık + 1 sapma)5
Toplam41

Python'da len(n.parameters()) ile sayınca da 41 çıktı (katmanlar için 16, 20, 5). Bu sayı küçük. Daha büyüğü 3Blue1Brown'ın rakam tanıyan ağı: 784 girdi, 16 + 16 gizli nöron, 10 çıktı. Ağırlıklar: 784·16 + 16·16 + 16·10 = 12.544 + 256 + 160 = 12.960; sapmalar: 16 + 16 + 10 = 42. Toplam 12.960 + 42 = 13.002; 3Blue1Brown'ın yazdığı sayı da tam bu.5 "13.002 düğme" ifadesi canlı bir imge: o ağın davranışını 13.002 sayı belirler, öğrenmek bu sayıları ayarlamaktır.

"Model büyüklüğü" tam olarak budur: parametre sayısı. Kısım III'ün ilerisinde bu sayı gözümüzde büyüyecek: bir sonraki bölümlerdeki makemore bigram modelinin 27 × 27 = 729 parametresi olacak (Bölüm 55); makemore deposunun varsayılan modeli README'ye göre "çok küçük, 200 bin parametreli bir transformer" (Bölüm 57);6 büyük dil modelleri çok daha büyük (Bölüm 58). Her biri aynı kavramın ölçeği.

Neden micrograd yavaş, neden tensör

micrograd'ın README'si bunu açıkça söyler: çizge yalnızca tek sayılar (scalar) üzerinde çalışır, bu yüzden her nöron tek tek küçük toplama ve çarpmalarına ayrılır.1 Bu, öğretmek için mükemmel (her şey görünür), ama 13.002 parametreli bir ağda bile her ileri geçişte on binlerce Value nesnesi yaratmak demek. Gerçek kütüphaneler aynı hesabı sayı listelerini (tensörleri) toplu işleyerek yapar. Bu fikre Bölüm 55.3'te geleceğiz; Bölüm 52.5'te de PyTorch'a bir pencere açacağız.

Uygulamamızda

Hukuk uygulamamızda "bir sonraki soruyu bu kullanıcı için ne kadar zor seçelim?" ya da "bu kullanıcı yarın seriyi bozar mı?" gibi bir tahmin istersek, girdiler şunlar olabilir: son 5 sorudaki doğru oranı, seri günü, bugün çalışılan dakika, kaç can kaldığı. Bir nöron bu dört sayıyı alır (4 ağırlık + 1 sapma = 5 parametre), tek bir "risk" sayısı üretir. İki gizli katmanlı küçük bir MLP bunu daha esnek yapabilir. Ama dürüst olalım: böyle bir şey yapmaya Kerem'in uygulamasında ihtiyaç var mı, bilmiyoruz; bu bir düşünce örneği, plan değil. Gerçekte bu tür bir tahmin için çoğu zaman basit bir kural ya da bir veritabanı sorgusu yeterlidir (Bölüm 38–39). Yine de bir şey öğretici: yukarıdaki puan formülü (10*doğru + 2*seri − 3*can) zaten bir nörondur, yalnızca ağırlıkları insan seçmiştir. Prototipinde ya da ileride Go'da yazılacak arka uçta büyük olasılıkla böyle bir ağırlıklı toplam olacak; bu "kuralı elle yazmak"tır. Sinir ağlarının farkı, ağırlıkları insanın değil verinin seçmesidir (Bölüm 47.2).

Bölüm 50 ve 49 ile bağlantı

Bu bölümde kurduğumuz her şeyin altında Bölüm 49'daki Value ve Bölüm 50'deki geri yayılım var. Bir Neuron çağrıldığında ortaya çıkan, bir hesap grafiğidir: her wi*xi bir çarpma düğümü, sum bir dizi toplama düğümü, relu bir düğüm. MLP çağrılınca onlarca ve yüzlerce düğümlük bir ağaç oluşur. Sonra tek bir çıktının üzerinde .backward() çağırırsan, Bölüm 50'de elle yaptığın gradyan taşımasının aynısı bu ağaçta otomatik olarak çalışır ve parameters()'in verdiği her ağırlığa bir gradyan yazar. Bu gradyanlar bir sonraki bölümde kullanılacak: "hangi ağırlığı hangi yöne, ne kadar çevirmeliyim?" sorusunun cevabı.

Bu bölümde neler kuruldu

Bir yapay nöron, girdilerin ağırlıklı toplamı artı bir sapmadır ve sonuç bir etkinleştirme fonksiyonundan (tanh ya da ReLU) geçer. Fonksiyonun doğrusal olmaması şarttır, yoksa üst üste konan katmanlar tek bir doğrusal hesaba çöker. Aynı girdileri gören nöronlar bir katman, art arda dizilmiş katmanlar bir çok katmanlı algılayıcı (MLP) olur; aradaki katmanlar gizli katmandır. micrograd'ın nn.py'si bunların hepsini Neuron, Layer, MLP sınıflarıyla yaklaşık 50 satırda yazar. Bir ağın parametre sayısı ağırlıklar artı sapmaların toplamıdır (MLP(3, [4, 4, 1]) için 41; 3Blue1Brown'ın rakam ağı için 13.002) ve "model büyüklüğü" bu sayıdır. Ağ henüz öğrenmedi; rastgele ağırlıklarla başlıyor. Öğrenme bir sonraki bölümün konusu.

Terimler sözlükte, Bölüm 51 başlığı altında.

Birincil okuma

Karpathy, micrograd, micrograd/nn.py: bütün dosya yaklaşık 50 satır; bu bölümü okuduktan sonra tamamını anlayabilmelisin. Derinleşmek için: 3Blue1Brown, "Gradient descent, how neural networks learn", Recap From Last Time başlığı (nöron, ağırlık, sapma, 13.002 parametre) ve micrograd README'si.

Takıldığın her yeri yapay zekâ öğretmenine sor. Bölüme özgü bir alıştırma: ondan sana "3 girdili, 2 nöronlu bir katmanın ağırlıklarını, girdilerini ve sapmalarını" sayı sayı versin; çıktıyı kâğıtta hesapla, sonra ReLU'dan geçir. Sonra aynı katmanı "ikinci bir katmana girdi" yaptır ve parametre sayısını birlikte sayın.

Bölüm sonu soruları

Kitaba bakmadan cevapla. Kâğıt kalem serbest.

1. Ağırlıkları 2 ve −1, sapması 3 olan bir nöron girdi olarak (4, 5) alıyor. Etkinleştirme uygulanmadan önceki toplam kaçtır?
Toplam = 2·4 + (−1)·5 + 3 = 8 − 5 + 3 = 6. On bir (8 + 3), ikinci girdiyi unutmaktan çıkar. Bkz. 51.1.
2. Etkinleştirme fonksiyonu olmasaydı, art arda yüz katmanlı bir ağ neye eşdeğer olurdu?
Doğrusal işlemlerin zinciri yine doğrusaldır: 3·(2x+1)−4 = 6x−1. Katmanlar birbirine çöker; büküm bu çöküşü engeller. Bkz. 51.2.
3. MLP(3, [4, 4, 1]) ağında kaç parametre vardır?
Her nöronun (girdi sayısı + 1) parametresi var: 4·(3+1) = 16, 4·(4+1) = 20, 1·(4+1) = 5; toplam 41. Bkz. 51.4.
4. ReLU'nun eğimi (türevi) negatif girdilerde nedir?
ReLU negatifleri sıfırlar; (out.data > 0) ifadesi bu durumda yanlıştır (0), gradyan kesilir. Bkz. 51.2.
5. Bir Layer(3, 4) nesnesi neyi temsil eder?
nin girdi sayısı, nout nöron sayısı. Katman, aynı girdileri gören nöronlar kümesidir. Bkz. 51.3.
6. Bir nöronun ağırlığı ile sapması arasındaki fark nedir?
Toplam = w₁x₁ + w₂x₂ + … + b: her ağırlık kendi girdisiyle çarpılır, sapma girdiden bağımsız bir başlangıç eğilimidir. İkisi de parametredir. Bkz. 51.1.
7. Kerem'in puan formülü 10*doğru + 2*seri − 3*can ile bir nöron arasındaki temel fark nedir?
Yapı aynı (ağırlıklı toplam); fark ağırlıkların kaynağı: formülde insan seçer, nöronda eğitim bulur (Bölüm 52). Bkz. 51.1.
8. micrograd neden nöronu tek tek toplama ve çarpmalarına ayırır?
README'ye göre çizge skalerler üzerinde çalışır: öğretmek için ideal, hız için kötü. Gerçek kütüphaneler tensörlerle toplu işler (Bölüm 55.3). Bkz. 51.4.
9. Kendi cümlelerinle: bir nöronun ne yaptığını (ağırlık, sapma, toplam, etkinleştirme) hukuk dışı, gündelik bir örnekle anlat. Sonra neden etkinleştirme fonksiyonuna ihtiyaç olduğunu söyle.
Örnek cevabı göster

Bir restoran seçerken puanı, fiyatı ve mesafeyi tartarsın: her biri için bir önem verirsin (ağırlık: puan çok önemli, fiyat eksi yönde önemli), genel bir eğilimin vardır (sapma: "genelde dışarıda yemek istiyorum"), hepsini tartıp tek bir "gideyim mi" sayısına dönüştürürsün (toplam); bunu "evet/hayır"a yakın bir eşik gibi büküp karar verirsin (etkinleştirme). Etkinleştirme olmazsa bütün katmanlar tek bir toplamaya çöker; büküm sayesinde katman katman daha karmaşık kurallar kurulabilir.

10. MLP(2, [3, 1]) ağının parametre sayısını göster. Her katman için hesabını yaz.
Cevabı göster

İlk katman 2 → 3: 3 nöron × (2 ağırlık + 1 sapma) = 9. İkinci katman 3 → 1: 1 nöron × (3 ağırlık + 1 sapma) = 4. Toplam 9 + 4 = 13 parametre.

Kaynaklar

  1. Karpathy, micrograd README'si: otomatik türev motoru ve üstündeki küçük sinir ağı kütüphanesi (yaklaşık 100 ve 50 satır); çizgenin yalnızca skalerler üzerinde çalışması, her nöronun tek tek toplama ve çarpmalara ayrılması.
  2. Karpathy, micrograd/nn.py ve micrograd/engine.py: Module, Neuron, Layer, MLP sınıfları ve relu. Bu bölümdeki kod alıntıları buradan; sayısal sonuçlar, bu dosyaları indirip kendi çalıştırmamla.
  3. Karpathy, nn-zero-to-hero deposu, micrograd ders defterleri (micrograd_lecture_first_half_roughly, micrograd_lecture_second_half_roughly): tek nöron örneği (x₁=2, x₂=0, w₁=−3, w₂=1, b=6,8813735870195432), tanh'lı Neuron, Layer, MLP sürümü, dört örnekli veri kümesi.
  4. 3Blue1Brown, "Gradient descent, how neural networks learn", Recap From Last Time: bir sonraki katmandaki her nöronun önceki katmanın ağırlıklı toplamı artı sapma olması ve ona sigmoid ya da ReLU gibi doğrusal olmayan bir fonksiyonun sarılması.
  5. Aynı ders, 3Blue1Brown: 784 girdi, 16 nöronluk iki gizli katman, 10 çıktı; toplam 13.002 ağırlık ve sapma. 12.960 ağırlık + 42 sapma hesabı bu bölümde bana ait (python ile doğrulandı).
  6. Karpathy, makemore README'si: varsayılan modelin "çok küçük, 200 bin parametreli bir transformer" olduğu.