چیت‌شیت

مبانی شبکه عصبی

Neural Network Basics

پرسپترون، گذر رو به جلو، پس‌انتشار، انتخاب تابع زیان و یک مینی‌فریم‌ورک. فرمول‌ها، ابعاد، مقادیر پیش‌فرض و راه‌حل‌ها.

  • ۱۱ بخش
  • ۵ درس مرتبط
  • کد و دستورها عیناً از دوره‌ی اصلی
فهرست مطالب
  1. گذر رو به جلو و عقب در یک شبکه 2 لایه
  2. یک گام آموزش
  3. فرمول‌ها
  4. وظایف در کد
  5. گره Value با backward
  6. حلقه‌ی آموزش مینی‌فریم‌ورک
  7. کدام تابع زیان
  8. پیش‌فرض‌ها در کد درس
  9. اعدادی که باید به خاطر سپرد
  10. عیب‌یابی
  11. پرسش‌ها

گذر رو به جلو و عقب در یک شبکه 2 لایه

معماری
رو به جلوa1a2رو به عقبورودی xبدون محاسباتلایه‌ی پنهانa1 = sigmoid(W1 x + b1)لایه‌ی خروجیa2 = sigmoid(W2 a1 + b2)تابع زیان (loss)L = (a2 - y)^2dL/dz22(a2 - y) a2 (1 - a2)dL/dW2 = dL/dz2 a1dL/da1 = dL/dz2 W2dL/dz1dL/da1 a1 (1 - a1)dL/dW1 = dL/dz1 xdL/db1 = dL/dz1

یک گام آموزش

گام‌به‌گام
  1. DataLoaderدسته‌ای از ورودی‌ها و اهداف را تحویل می‌دهد. در هر دور (epoch) بر می‌زند.
  2. Modelگذر رو به جلو را لایه به لایه اجرا می‌کند. هر لایه ورودی و خروجی خود را ذخیره می‌کند.
  3. Lossپیش‌بینی‌ها را با اهداف مقایسه کرده و یک عدد اسکالر می‌دهد.
  4. Optimizerمتد optimizer.zero_grad() همه‌ی گرادیان‌ها را صفر می‌کند.
  5. Lossمتد loss.backward() گرادیان‌ها را از راست به چپ در گراف ارسال می‌کند.
  6. Optimizerمتد optimizer.step() هر پارامتر را به‌روزرسانی می‌کند؛ برای SGD به شکل param -= lr * grad.
  7. Modelفراخوانی model.eval() پیش از آزمون. استنتاج فقط گذر رو به جلو را اجرا می‌کند.

فرمول‌ها

مفهوم‌ها
پله (Step)
اگر $z \ge 0$ باشد $\text{step}(z) = 1$، وگرنه 0.
قاعده پرسپترون
w_i = w_i + learning_rate * error * x_i، با error = y_true منهای y_pred.
سیگموئید
$\sigma(z) = \frac{1}{1 + e^{-z}}$، بازه (0, 1). مشتق آن $a(1 - a)$ است.
لایه
$z = W x + b$، سپس $a = \text{sigmoid}(z)$.
MSE
برابر با $\frac{1}{n} \sum (y_{\text{pred}} - y_{\text{true}})^2$، گرادیان $\frac{2}{n}(y_{\text{pred}} - y_{\text{true}})$.
BCE
برابر با $-\left(y \log(p) + (1 - y) \log(1 - p)\right)$
CCE
برابر با $-\sum_i y_i \log(p_i)$. فقط کلاس واقعی سهم دارد.
گرادیان سافت‌مکس به همراه CE
احتمال منهای 1 برای کلاس واقعی، و خود احتمال برای سایر کلاس‌ها.

وظایف در کد

کار و کد
وظیفهکد
آموزش پرسپترون روی AND`p_and = Perceptron(2)` then `p_and.train(and_data)`
زنجیره‌سازی لایه‌هاNetwork([hidden, output])
شبکه مشتق‌گیری خودکار، 2-4-1net = Network([2, 4, 1])
پس‌انتشار از تابع زیانtotal_loss.backward()
تابع زیان پایدار چندکلاسهF.cross_entropy(logits, labels)
اهداف هموارشدهlabel_smoothing=0.1
انتخاب بهینه‌سازAdam(model.parameters(), lr=0.01)
دسته‌بندی داده‌هاDataLoader(train_data, batch_size=16, shuffle=True)

گره Value با backward

کد
python
out = Value(self.data + other.data, (self, other), '+')
self.grad += out.grad               # عملگر add گرادیان را عبور می‌دهد
other.grad += out.grad
out = Value(self.data * other.data, (self, other), '*')
self.grad += other.data * out.grad  # عملگر mul ورودی‌ها را جابه‌جا می‌کند
other.grad += self.data * out.grad
self.grad += (s * (1 - s)) * out.grad # sigmoid reuses s
build_topo(self)                    # مرتب‌سازی توپولوژیک گراف
self.grad = 1.0                     # dL/dL = 1
for v in reversed(topo):
    v._backward()                   # ارسال (push) گرادیان‌ها به فرزندان

حلقه‌ی آموزش مینی‌فریم‌ورک

کد
python
model = Sequential(Linear(2, 16), ReLU(), Linear(16, 16), ReLU(),
                   Linear(16, 8), ReLU(), Linear(8, 1), Sigmoid())
criterion = BCELoss()
optimizer = Adam(model.parameters(), lr=0.01)
model.train()                        # روشن بودن دراپ‌اوت و آمارهای دسته
for batch_inputs, batch_targets in loader:
    for x, t in zip(batch_inputs, batch_targets):
        pred = model.forward(x)
        loss = criterion(pred, t)
        optimizer.zero_grad()
        grad = criterion.backward()  # dL/dpred
        model.backward(grad)         # ماژول‌ها به ترتیب معکوس
        optimizer.step()
model.eval()                         # آمارهای جاری، بدون دراپ‌اوت

کدام تابع زیان

دستورها
دستورکارکرد
F.mse_lossرگرسیون. جریمه‌ی مربعی داده‌های پرت
MAE / Huberرگرسیون مقاوم در برابر داده‌های پرت
F.binary_cross_entropyدسته‌بندی دوکلاسه روی احتمالات
F.cross_entropyچندکلاسه. Log-softmax و NLL در یک گام
Label smoothingافزودن در زمان بیش‌اطمینانی CE چندکلاسه
Focal Lossکلاس‌های نامتوازن. وزن‌دهی کمتر به نمونه‌های ساده
Triplet Lossلنگر، مثبت، منفی با حاشیه (margin)
InfoNCEامبدینگ‌های خودنظارتی دسته‌بزرگ

پیش‌فرض‌ها در کد درس

پیش‌فرض‌ها
تنظیمپیش‌فرضنکته
Perceptron `learning_rate`0.1epochs=100
Adam `lr`0.001beta1=0.9، beta2=0.999، eps=1e-8
SGD `lr`0.01param -= lr * grad
Dropout `p`0.5مقیاس‌بندی باقی‌مانده‌ها با 1/(1-p)
BatchNormmomentum=0.1eps=1e-5، آمارهای جاری برای eval
BCE clip `eps`1e-15BCELoss در فریم‌ورک از 1e-7 استفاده می‌کند
alpha0.1هموارسازی برچسب‌ها، هدف 0.91 برای 10 کلاس
temperature0.07تابع زیان تقابلی، پیش‌فرض SimCLR

اعدادی که باید به خاطر سپرد

نکته‌ها
  • مشتق سیگموئید در $a = 0.5$ به اوج 0.25 می‌رسد.
  • ده لایه سیگموئید گرادیان را حداکثر با ضریب $0.25^{10} = 0.000001$ تضعیف می‌کنند.
  • تابع MSE که در وظیفه‌ی دوکلاسه 50/50 عدد 0.5 را پیش‌بینی کند، زیان 0.25 داده و چیزی یاد نمی‌گیرد.
  • آنتروپی متقاطع مقادیر $-\log(0.5) = 0.693$ و $-\log(0.99) = 0.01$ را می‌دهد.
  • حدس اشتباهِ بااطمینان $p = 0.01$ هزینه‌ای معادل $-\log(0.01) = 4.6$ دارد.
  • حدس تصادفی روی 10 کلاس هزینه‌ای معادل $-\log(0.1) = 2.3$ دارد.
  • تابع زیان کانونی با $\gamma = 2$ به نمونه‌ی ساده وزن 0.01 و به نمونه‌ی سخت وزن 0.81 می‌دهد.
  • یک گام رو به عقب همه‌ی گرادیان‌ها را می‌دهد. تغییر جزئی هر وزن نیازمند یک گذر رو به جلو به ازای هر وزن است.

عیب‌یابی

عیب‌یابی
  • پرسپترون روی XOR هرگز همگرا نمی‌شود

    علت
    مسئله XOR تفکیک‌پذیر خطی نیست
    راه‌حل
    افزودن یک لایه‌ی پنهان
  • خروجی طبقه‌بند برای همه 0.5 است

    علت
    تابع زیان MSE برای طبقه‌بندی
    راه‌حل
    استفاده از آنتروپی متقاطع
  • لایه‌های اولیه یاد نمی‌گیرند

    علت
    سیگموئید گرادیان‌ها را در هر لایه کوچک می‌کند
    راه‌حل
    استفاده از ReLU (درس 04)، مقداردهی اولیه‌ی مقیاس‌شده
  • تابع زیان inf یا NaN است

    علت
    $\log(0) = -\infty$
    راه‌حل
    محدود کردن (clip) مقدار p در بازه [eps, 1 - eps]
  • سرریز math.exp(1000)

    علت
    ورودی بزرگ به سیگموئید
    راه‌حل
    محدود کردن (clamp) در بازه [-500, 500]
  • گرادیان نادرست برای مقدار بازاستفاده‌شده

    علت
    = روی مسیرهای دیگر بازنویسی می‌کند
    راه‌حل
    تجمع گرادیان با +=
  • رشد گرادیان‌ها در هر گام

    علت
    باقی ماندن گرادیان‌های قبلی
    راه‌حل
    ابتدا فراخوانی zero_grad()
  • تغییر نتایج آزمون در هر بار اجرا

    علت
    دراپ‌اوت همچنان روشن است
    راه‌حل
    فراخوانی model.eval()

پرسش‌ها

پرسش و پاسخ
ابعاد W چیست؟
سطرها مطابق با لایه فعلی؛ ستون‌ها مطابق با لایه قبلی.
چرا برای آموزش از سیگموئید استفاده می‌شود نه پله؟
سیگموئید هموار است، بنابراین گرادیان وجود دارد.
چرا اکتیویشن‌ها ذخیره می‌شوند؟
گام رو به عقب به آن‌ها نیاز دارد. حافظه هزینه می‌شود تا تنها یک گام نیاز باشد.
چرا مرتب‌سازی توپولوژیک؟
هر گره قبل از انتقال گرادیان به بعدی، کل گرادیان خود را دریافت می‌کند.
چرا F.cross_entropy، و نه سافت‌مکس و سپس لگاریتم؟
یک عملیات واحد از نظر محاسباتی پایدار است.
چرا train() و eval()؟
دراپ‌اوت و BatchNorm در هر حالت رفتار متفاوتی دارند.
چرا zero_grad یک فراخوانی جداگانه است؟
گرادیان‌ها با += انباشته می‌شوند مگر اینکه آن‌ها را بازنشانی کنید.