چیت‌شیت

حسابان، گرادیان‌ها و بهینه‌سازی محدب

Calculus, Gradients and Convex Optimization

مشتق‌ها، مشتق‌گیری خودکار، GD، تکانه، Adam، نیوتن و آزمون‌های تحدب. پیاده‌سازی از صفر با Python و PyTorch.

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

گذر رو به جلو و گام رو به عقب در یک نورون

معماری
*w+bbackwardx1xورودیz1 = w*xضربz2 = w*x + bافزودن بایاسa = sigmoid(z2)فعال‌سازیdL/dwdL/dz2 * xdL/dbdL/dz2 * 1dL/dz2dL/da * a(1-a)Lتابع زیان (loss) آنتروپی متقاطع

مشتق‌گیری خودکار پس‌رو در Value.backward

گام‌به‌گام
  1. ثبتهر عملیات یک Value جدید با گره‌های فرزند و یک کلوژر _backward می‌سازد.
  2. مرتب‌سازیbuild_topo هر گره را پس از گره‌هایی که به آن‌ها وابسته است قرار می‌دهد.
  3. مقداردهی اولیه (Seed)تنظیم self.grad = 1.0 روی خروجی. این همان dy/dy = 1 است.
  4. پیمایش معکوسفراخوانی v._backward() برای هر گره بر اساس معکوس ترتیب توپولوژیک.
  5. انباشتهر کلوژر با += به مقدار .grad اضافه می‌کند. متغیری که دوبار استفاده شود جمع مقادیر را می‌گیرد.
  6. بازنشانیتنظیم p.grad = 0.0 برای تمام پارامترها قبل از فراخوانی بعدی loss.backward().
  7. به‌روزرسانیاعمال p.data -= lr * p.grad برای هر پارامتر.

وظایف در کد

کار و کد
وظیفهکد
تفاضل مرکزیnumerical_derivative(f, x, h=1e-7)
گرادیان با چندین ورودیnumerical_gradient(f, point, h=1e-7)
هسین f(x, y)hessian_2d(f, x, y, h=1e-5)
بررسی گرادیان مشتق‌گیری خودکارgradient_check(build_expr, x_val, h=1e-7)
شبکه XOR، با 4 گره پنهانmodel = MLP([2, 4, 1])
اجرای یک بهینه‌سازoptimize(optimizer, func, grad_func, start)
سنجش تحدب با نمونه‌برداریcheck_convexity(f, dim)
گام‌های نیوتن در فضای 2 بعدیnewtons_method(grad_f, hessian_f, x0)

بهینه‌سازها از صفر

کد
python
GradientDescent(lr=0.001)                                 # w = w - lr * gradient
SGDMomentum(lr=0.001, momentum=0.9)                       # v = beta * v + gradient
Adam(lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8)      # دو گشتاور به ازای هر وزن
m_hat = [m / (1 - self.beta1 ** self.t) for m in self.m]  # تصحیح سوگیری
p - self.lr * mh / (vh ** 0.5 + self.epsilon)             # اندازه‌ی گام اختصاصی برای هر وزن
adam_history = optimize(Adam(lr=0.01), rosenbrock, rosenbrock_gradient, start)

مشتق‌گیری خودکار و بهینه‌سازها در PyTorch

کد
python
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x + 1
y.backward()  # حالت پس‌رو از میان گراف ثبت‌شده
print(x.grad)  # 7.0 = 2*x + 3
sgd = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
adam = torch.optim.Adam(model.parameters(), lr=0.001)
adamw = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(adam, T_max=100)

فرمول‌های کلیدی

مفهوم‌ها
تفاضل مرکزی
$f'(x) \approx \frac{f(x + h) - f(x - h)}{2h}$.
قاعده‌ی زنجیره‌ای
$\frac{dy}{dx} = f'(g(x)) \cdot g'(x)$. جمع تمام مسیرها در نقاط انشعاب (branch) گراف.
گرادیان کاهشی
$w = w - \text{lr} \cdot \text{gradient}$.
تکانه
$v = \beta \cdot v + \text{gradient}$، سپس $w = w - \text{lr} \cdot v$.
Adam
$w = w - \text{lr} \cdot \hat{m} / (\sqrt{\hat{v}} + \epsilon)$ همراه با گشتاورهای تصحیح‌سوگیری‌شده.
نیوتن
$x_{\text{new}} = x - H^{-1} \cdot \text{gradient}$.
محدب
$f(tx + (1-t)y) \le t f(x) + (1-t) f(y)$ به ازای $t \in [0, 1]$.
لاگرانژی
$L(x, \lambda) = f(x) + \lambda g(x)$. گرادیان آن برابر صفر قرار داده می‌شود.

مشتق‌های مهم که باید بدانید

دستورها
دستورکاربرد
x^22x. تابع زیان (loss) مبتنی بر MSE
wx + bx برای w، 1 برای b، w برای x. لایه‌ی خطی
e^xe^x. سافت‌مکس، اتنشن
ln(x)1/x. تابع زیان (loss) آنتروپی متقاطع
sigmoidf(x)(1-f(x)). فعال‌ساز سیگموئید
tanh1 - tanh^2. تابع فعال‌ساز کلاسیک
x^nn x^(n-1). مورد استفاده در __pow__
sin(x^2)cos(x^2) * 2x. مثالی از قاعده‌ی زنجیره‌ای

انتخاب روش

دستورها
دستورکاربرد
Gradient descentمشتق‌های مرتبه اول. حافظه O(n). خط مبنا
SGD with momentumبهترین دقت نهایی با تیونینگ بیشتر
Adamانحنای قطری از روی گشتاورهای گرادیان. گزینه‌ی پیش‌فرض یادگیری عمیق
AdamWAdam با کاهش وزن مجزا. مدل‌های ترنسفورمر
Newton's methodهسین کامل. پیچیدگی O(n^3) به ازای هر گام. مسائل محدب کوچک
L-BFGSتفاضل‌های m گرادیان آخر. مسائل محدب متوسط
K-FACتقریب فیشر فاکتورگیری‌شده‌ی کرونکر. آموزش با دسته‌های بزرگ

اعداد و مقادیر پیش‌فرض

پیش‌فرض‌ها
تنظیمپیش‌فرضیادداشت
Adam `lr`0.001نقطه‌ی شروع برای اکثر مسائل
Adam `beta2`0.999beta1 برابر 0.9 است. نرخ‌های زوال گشتاور
Adam `epsilon`1e-8جلوگیری از تقسیم بر صفر
SGD momentum `lr`0.01با تکانه‌ی 0.9
AdamW `weight_decay`0.01مجزا از گام گرادیان
Mini-batch size32-256تخمین گرادیان مناسب با نویز متعادل
Finite difference `h`1e-7در numerical_derivative
Gradient check difference< 1e-5مقایسه‌ی مشتق‌گیری خودکار در برابر روش عددی

عیب‌یابی

عیب‌یابی
  • تابع زیان (loss) رشد می‌کند یا nan می‌شود

    علت
    نرخ یادگیری بسیار بزرگ است
    راه‌حل
    کاهش نرخ یادگیری
  • سرعت آموزش بسیار پایین است

    علت
    نرخ یادگیری بسیار کوچک است
    راه‌حل
    افزایش آن؛ افزودن برنامه‌ی زمان‌بندی نرخ یادگیری
  • حرکت زیگزاگی در دره‌های باریک

    علت
    عدد حالت بالای ماتریس هسین
    راه‌حل
    افزودن تکانه، یا استفاده از روش نیوتن
  • گرادیان نزدیک به 0 بدون پیشرفت

    علت
    نقطه‌ی زینی
    راه‌حل
    تکانه و نویز ناشی از دسته‌های کوچک
  • رشد تصاعدی گرادیان‌ها در هر گام

    علت
    انباشت در .grad با استفاده از +=
    راه‌حل
    تنظیم p.grad = 0.0 قبل از backward
  • اختلاف میان مشتق‌گیری خودکار و عددی

    علت
    باگ در قاعده‌ی _backward
    راه‌حل
    اجرای gradient_check
  • مشتق مرتبه‌ی دوم پر از نویز است

    علت
    اندازه‌ی گام h بسیار کوچک است
    راه‌حل
    استفاده از h=1e-4 برای هر دو فراخوانی
  • هزینه‌ی بالای نیوتن برای مدل‌های بزرگ

    علت
    حافظه O(n^2) و معکوس‌سازی O(n^3)
    راه‌حل
    استفاده از L-BFGS یا Adam

پرسش‌ها

پرسش و پاسخ
چرا حالت پس‌رو برای شبکه‌ها؟
ورودی‌های بسیار و یک تابع زیان (loss) واحد. یک گام رو به عقب تمام گرادیان‌ها را محاسبه می‌کند.
چگونه تحدب را بسنجیم؟
مشتق دوم >= 0 در فضای 1 بعدی؛ هسین مثبت نیمه‌معین در ابعاد بالاتر.
چرا SGD روی توابع زیان (loss) غیرمحدب کار می‌کند؟
اکثر نقاط بحرانی، نقاط زینی هستند و بیشتر کمینه‌ها عملکرد مناسبی دارند.
چرا L1 وزن‌های تنک تولید می‌کند؟
شکل لوزی در امتداد محورها دارای گوشه‌های نوک‌تیز است.
سستی مکمل چیست؟
$\lambda_i \, g_i(x) = 0$. در بردارهای پشتیبان مقدار $\lambda > 0$ است.

نکات

نکته‌ها
  • برای آموزش‌های طولانی‌تر از چند دوره (epoch)، از برنامه‌ی زمان‌بندی نرخ یادگیری استفاده کنید.
  • تبرید کسینوسی و گرم‌کردن مناسب مدل‌های ترنسفورمر و شبکه‌های بزرگ هستند.
  • روش نیوتن مسائل درجه دوم را تنها در یک گام حل می‌کند.
  • بررسی گرادیان نیازمند 2 گذر رو به جلو به ازای هر پارامتر است؛ آن را در محیط عملیاتی اجرا نکنید.
  • وجود مقادیر ویژه‌ با علامت‌های مختلف در ماتریس هسینِ یک نقطه‌ی بحرانی، نشان‌دهنده‌ی نقطه‌ی زینی است.
  • کمینه‌های تخت نسبت به کمینه‌های نوک‌تیز تعمیم‌پذیری بهتری دارند.