درک سازوکار داخلی شبکههای عصبی بدون تسلط بر مفاهیم پایهای حسابان دشوار است. در عمل، مدلهای یادگیری عمیق چیزی جز توابع ریاضی بزرگ نیستند و برای کاهش خطای پیشبینی، باید بدانیم تنظیم هر وزن چه اثری روی خروجی نهایی میگذارد؛ این همان نقشی است که مشتقها ایفا میکنند.
این درس به شما نشان میدهد چطور از مفاهیمی چون مشتق جزئی، بردار گرادیان، ماتریس هسیان و تقریبهای سری تیلور برای ساخت الگوریتم گرادیان کاهشی استفاده کنید. با فهم این مبانی، چرخهی آموزش شبکهها و رفتار بهینهسازهایی مثل Adam و روش نیوتن دیگر برایتان مثل جعبه سیاه نخواهد بود.
تمام کدهای این درس با تکیه بر فرمولهای پایه و کتابخانهی NumPy روی پردازندهی معمولی سیستم شخصی شما اجرا میشوند و نیازی به کارتهای گرافیکی گرانقیمت یا دسترسی به سرویسهای ابری خارجی ندارید.
مشتقها مشخص میکنند کدام مسیر به سمت سرازیری است. برای یادگیری یک شبکه عصبی، دانستن همین نکته کافی است.
اهداف یادگیری
- محاسبهی مشتق عددی و تحلیلی برای توابع رایج در یادگیری ماشین (، سیگموئید و انتروپی متقاطع)
- پیادهسازی گرادیان کاهشی (gradient descent) از صفر برای کمینهسازی تابع زیان در حالتهای 1بعدی و 2بعدی
- بهدست آوردن گرادیان مدل رگرسیون خطی و آموزش آن با بهروزرسانی دستی وزنها
- تشریح ماتریس هسیان، تقریبهای سری تیلور و ارتباط آنها با روشهای بهینهسازی
صورت مسئله
یک شبکه عصبی با میلیونها وزن دارید. هر وزن مثل یک پیچ تنظیم است. باید بفهمید هرکدام از این پیچها را به کدام سمت بچرخانید تا خطای مدل اندکی کمتر شود. حسابان (calculus) این جهت را مشخص میکند.
بدون حسابان، آموزش یک شبکه عصبی یعنی دستکاری تصادفی وزنها و امید به اینکه نتیجه بهتر شود. اما با مشتق، دقیقاً میدانید هر وزن چه تأثیری روی خطا دارد. اینگونه، همهی پیچها را هربار در جهت درست میچرخانید.
مفهوم اصلی
مشتق چیست؟
مشتق، نرخ تغییرات را اندازه میگیرد. برای تابع ، مشتق میگوید: اگر را به اندازهای بسیار ناچیز تغییر دهید، مقدار چقدر تغییر میکند؟
از نظر هندسی، مشتق همان شیب خط مماس بر منحنی در یک نقطه است.
:
| (شیب) | ||
|---|---|---|
| 0 | 0 | 0 (تخت، در پایینترین نقطه) |
| 1 | 1 | 2 |
| 2 | 4 | 4 (شیب خط مماس در این نقطه) |
| 3 | 9 | 6 |
در نقطهی ، شیب برابر با 4 است. اگر را اندکی به سمت راست ببرید، مقدار تقریباً 4 برابرِ آن افزایش مییابد. در نقطهی ، شیب 0 است؛ یعنی درست در کف کاسه قرار دارید.
تعریف صوری مشتق:
در کدنویسی، حد را کنار میگذاریم و صرفاً از مقداری بسیار کوچک برای استفاده میکنیم؛ به این کار مشتق عددی (numerical derivative) میگویند.
مشتقهای جزئی: یک متغیر در هر لحظه
توابع واقعی چندین ورودی دارند. زیان یک شبکه عصبی به هزاران وزن وابسته است. مشتق جزئی (partial derivative) همهی متغیرها جز یکی را ثابت نگه میدارد و بعد نسبت به همان یک متغیر مشتق میگیرد.
هر مشتق جزئی به این پرسش پاسخ میدهد: اگر فقط همین یک وزن را کمی تغییر دهم، تابع زیان چقدر تغییر میکند؟
گرادیان: بردار تمام مشتقهای جزئی
گرادیان (gradient)، تمام مشتقهای جزئی را در یک بردار جمع میکند. برای تابع ، گرادیان عبارت است از:
گرادیان در جهتی قرار دارد که بیشترین شیب صعودی را میسازد. بنابراین برای کمینهسازی تابع، باید در جهت عکس آن حرکت کنید.
نمودار کانتور (خطوط تراز) تابع :
این تابع شکل کاسهای با خطوط تراز دایرهای هممرکز است. نقطهی کمینه در (0, 0) قرار دارد.
| نقطه | (جهت کاهش) | |
|---|---|---|
| (1, 1) | [2, 2] (رو به بالا، دور از کمینه) | [-2, -2] (رو به پایین، به سمت کمینه) |
| (0, 0) | [0, 0] (تخت، در نقطهی کمینه) | [0, 0] |
این تصویر کل ایدهی گرادیان کاهشی است: گرادیان را حساب کنید، علامتش را منفی کنید و یک گام بردارید.
ارتباط با بهینهسازی
آموزش شبکه عصبی همان بهینهسازی است. یک تابع زیان دارید که میزان خطای مدل را اندازه میگیرد و هدف شما کمینهکردن آن است.
Gradient descent update rule:
w_new = w_old - learning_rate * dL/dw
For every weight:
1. Compute the partial derivative of loss with respect to that weight
2. Subtract a small multiple of it from the weight
3. Repeat
نرخ یادگیری (learning rate) طول گامها را کنترل میکند. اگر زیادی بزرگ باشد، از کمینه رد میشوید؛ اگر خیلی کوچک باشد، فوقالعاده کند پیش میروید.
چشمانداز زیان (برش 1بعدی):
تابع زیان با تغییر وزن ، منحنیای پر از قلهها و درهها میسازد.
| ویژگی | توضیحات |
|---|---|
| کمینهی سراسری (Global minimum) | پایینترین نقطه در کل منحنی؛ بهترین جواب ممکن |
| کمینهی محلی (Local minimum) | درهای که از همسایههایش پایینتر است اما پایینترین نقطهی کل نمودار نیست |
| شیب | گرادیان کاهشی از هر نقطهی شروعی، شیب را به سمت پایین دنبال میکند |
گرادیان کاهشی شیب را رو به پایین دنبال میکند. این روش ممکن است در کمینههای محلی گیر بیفتد، اما در فضاهای چندبعدی بزرگ (با میلیونها وزن)، این موضوع در عمل بهندرت دردسرساز میشود.
مشتق عددی در مقایسه با مشتق تحلیلی
برای محاسبهی مشتق دو راه وجود دارد:
تحلیلی: با استفادهی دستی از قواعد حسابان. برای ، مشتق برابر با است؛ دقیق و سریع.
عددی: تقریب زدن با تعریف مشتق. مقادیر و را برای مقداری ناچیز از حساب کنید و بعد از تفاضل آنها کمک بگیرید.
Numerical (central difference):
f'(x) ~= f(x + h) - f(x - h)
-----------------------
2h
h = 0.0001 works well in practice
مشتقهای عددی کندترند اما برای هر تابعی جواب میدهند. مشتقهای تحلیلی سریعاند اما باید فرمول آنها را خودتان به دست آورید. فریمورکهای شبکه عصبی سراغ روش سومی میروند: مشتقگیری خودکار (automatic differentiation) که مشتقهای دقیق را بهصورت مکانیکی حساب میکند. این روش را در فاز 3 خواهید دید.
مشتق دستی توابع ساده
اینها همان مشتقهایی هستند که در یادگیری ماشین مدام با آنها سروکار دارید:
Function Derivative Used in
-------- ---------- -------
f(x) = x^2 f'(x) = 2x Loss functions (MSE)
f(x) = wx + b f'(w) = x Linear layer (gradient w.r.t. weight)
f'(b) = 1 Linear layer (gradient w.r.t. bias)
f'(x) = w Linear layer (gradient w.r.t. input)
f(x) = e^x f'(x) = e^x Softmax, attention
f(x) = ln(x) f'(x) = 1/x Cross-entropy loss
f(x) = 1/(1+e^-x) f'(x) = f(x)(1-f(x)) Sigmoid activation
برای :
f(x) = x^2 f'(x) = 2x
x f(x) f'(x) meaning
-2 4 -4 slope tilts left (decreasing)
-1 1 -2 slope tilts left (decreasing)
0 0 0 flat (minimum!)
1 1 2 slope tilts right (increasing)
2 4 4 slope tilts right (increasing)
برای با فرضیات و :
f(w) = 3w + 1 f'(w) = 3
The derivative with respect to w is just x.
If x is big, a small change in w causes a big change in output.
قاعدهی زنجیرهای
وقتی توابع با یکدیگر ترکیب میشوند، قاعدهی زنجیرهای (chain rule) مشخص میکند چطور باید مشتق بگیرید.
If y = f(g(x)), then dy/dx = f'(g(x)) * g'(x)
Example: y = (3x + 1)^2
outer: f(u) = u^2 f'(u) = 2u
inner: g(x) = 3x + 1 g'(x) = 3
dy/dx = 2(3x + 1) * 3 = 6(3x + 1)
شبکههای عصبی زنجیرهای از توابع هستند: ورودی -> لایهی خطی -> تابع فعالسازی -> لایهی خطی -> تابع فعالسازی -> تابع زیان. پسانتشار (backpropagation) چیزی نیست جز اجرای پیدرپیِ همین قاعدهی زنجیرهای از خروجی به سمت ورودی. کل الگوریتم به همین خلاصه میشود.
ماتریس هسیان
گرادیان شیب را نشان میدهد، اما ماتریس هسیان (Hessian) انحنا را مشخص میکند.
ماتریس هسیان از مشتقهای جزئی مرتبهی دوم ساخته شده است. برای تابع ، درایهی هسیان به شکل زیر تعریف میشود:
برای تابعی با 2 متغیر :
اطلاعاتی که ماتریس هسیان در یک نقطهی بحرانی (جایی که گرادیان = 0 است) به ما میدهد:
| ویژگی هسیان | معنا | نمونهی سطح |
|---|---|---|
| معین مثبت (تمامی مقادیر ویژه > 0) | کمینهی محلی | کاسهای رو به بالا |
| معین منفی (تمامی مقادیر ویژه < 0) | بیشینهی محلی | کاسهای رو به پایین |
| نامعین (مقادیر ویژه با علامتهای مختلف) | نقطهی زینی (Saddle point) | شبیه به زین اسب |
مثال: (یک تابع زینی)
df/dx = 2x df/dy = -2y
d^2f/dx^2 = 2 d^2f/dy^2 = -2 d^2f/dxdy = 0
H = | 2 0 |
| 0 -2 |
Eigenvalues: 2 and -2 (one positive, one negative)
--> Saddle point at (0, 0)
مقایسه کنید با (یک کاسه):
H = | 2 0 |
| 0 2 |
Eigenvalues: 2 and 2 (both positive)
--> Local minimum at (0, 0)
چرا هسیان در یادگیری ماشین مهم است؟
روش نیوتن (Newton's method) با کمک ماتریس هسیان، گامهای بهینهسازی بهتری نسبت به گرادیان کاهشی برمیدارد. به جای اینکه فقط شیب را دنبال کند، انحنا را هم در نظر میگیرد:
روش نیوتن سریعتر همگرا میشود؛ چون ماتریس هسیان مقیاس گرادیان را دوباره تنظیم میکند؛ یعنی در مسیرهای تند گامهای کوچکتر و در مسیرهای هموار گامهای بزرگتری برمیدارد.
اما یک مشکل اساسی وجود دارد: برای شبکهای با پارامتر، ابعاد ماتریس هسیان خواهد بود. مدلی با 1 میلیون پارامتر به ماتریسی با 1 تریلیون درایه نیاز دارد! به همین دلیل به سراغ روشهای تقریبی میرویم.
| روش | مواردی که استفاده میکند | هزینه | همگرایی |
|---|---|---|---|
| گرادیان کاهشی | فقط مشتقهای مرتبه اول | در هر گام | کند (خطی) |
| روش نیوتن | ماتریس کامل هسیان | در هر گام | سریع (درجه دو) |
| L-BFGS | تقریب هسیان با تاریخچهی گرادیانها | در هر گام | متوسط (فرارفتگی خطی یا superlinear) |
| Adam | نرخهای یادگیری تطبیقی برای هر پارامتر (تقریب قطری هسیان) | در هر گام | متوسط |
| گرادیان طبیعی (Natural gradient) | ماتریس اطلاعات فیشر (هسیان آماری) | در هر گام | سریع |
در عمل، Adam بهینهساز پیشفرض یادگیری عمیق (deep learning) است. این الگوریتم با ثبت میانگین متحرک و واریانس گرادیانها برای هر پارامتر، اطلاعات مرتبهی دوم را با هزینهای ناچیز تقریب میزند.
تقریب سری تیلور
هر تابع همواری را میتوان بهصورت موضعی با یک چندجملهای تقریب زد:
هرچه جملات بیشتری اضافه کنید تقریب بهتر میشود؛ البته فقط در نزدیکی نقطهی .
چرا سری تیلور در یادگیری ماشین اهمیت دارد؟
-
تیلور مرتبهی اول = گرادیان کاهشی. وقتی از رابطهی استفاده میکنید، در واقع تقریب خطی میزنید. گرادیان کاهشی همین مدل خطی را کمینه میکند تا را انتخاب کند.
-
تیلور مرتبهی دوم = روش نیوتن. با به یک مدل درجه دو میرسید. کمینهکردن آن خروجی را به شما میدهد؛ یعنی همان گام نیوتن.
-
طراحی تابع زیان. توابع زیان MSE و انتروپی متقاطع هموار هستند؛ یعنی بسط تیلور آنها رفتار پایداری دارد. این موضوع اتفاقی نیست؛ زیانهای هموار بهینهسازی را پیشبینیپذیر میکنند.
Approximation order What it captures Optimization method
------------------- ----------------- -------------------
0th order (constant) Just the value Random search
1st order (linear) Slope Gradient descent
2nd order (quadratic) Curvature Newton's method
Higher orders Finer structure Rarely used in ML
نکتهی کلیدی: در کل بهینهسازیهای مبتنی بر گرادیان، تنها کاری که میکنیم تقریب موضعی تابع زیان و برداشتن گام به سمت نقطهی کمینهی همان تقریب است.
انتگرال در یادگیری ماشین
مشتقها نرخ تغییرات را نشان میدهند و انتگرالها انباشت را حساب میکنند؛ یعنی همان مساحت زیر منحنی.
در یادگیری ماشین بهندرت پیش میآید که انتگرال را دستی حساب کنید، اما ردپای این مفهوم همهجا دیده میشود:
احتمال. برای یک متغیر تصادفی پیوسته با چگالی :
مساحت زیر منحنی چگالی احتمال در بازهی تا ، برابر با احتمال قرار گرفتن در همان بازه است.
امید ریاضی (Expected value). میانگین وزنی خروجیها با استفاده از احتمال:
زیان مورد انتظار روی توزیع دادهها یک انتگرال است و فرایند آموزش، تقریب تجربی همین انتگرال را کمینه میکند.
واگرایی کولبک-لایبلر (KL divergence). میزان تفاوت میان دو توزیع را میسنجد:
این مفهوم در VAEها، تقطیر دانش (knowledge distillation) و استنتاج بیزی کاربرد دارد.
ثابتهای نرمالسازی. در استنتاج بیزی:
مخرج کسر، یک انتگرال روی تمام مقادیر ممکن پارامترهاست. این انتگرال اغلب محاسبهناپذیر است؛ به همین دلیل به سراغ تقریبهایی مثل MCMC و استنتاج متغیری (variational inference) میرویم.
| مفهوم انتگرال | کاربرد در یادگیری ماشین |
|---|---|
| مساحت زیر منحنی | محاسبهی احتمال از روی توابع چگالی |
| امید ریاضی | توابع زیان، کمینهسازی ریسک |
| واگرایی KL | مدلهای VAE، بهینهسازی خطمشی، تقطیر دانش |
| نرمالسازی | توزیعهای پسین بیزی، مخرج تابع softmax |
| درستنمایی حاشیهای (Marginal likelihood) | مقایسهی مدلها، کران پایین شواهد (ELBO) |
قاعدهی زنجیرهای چندمتغیره در گراف محاسباتی
قاعدهی زنجیرهای صرفاً برای توابع اسکالر خطی نیست. در یک شبکه عصبی، متغیرها branch میشوند و دوباره با هم merge میگردند. در تصویر زیر جریان حرکت مشتقها را در یک رفت مستقیم (forward pass) ساده میبینید:
مرحلهی بازگشت (backward pass) گرادیانها را از راست به چپ محاسبه میکند:
در راستای هر پیکان، ضرب در مشتق محلی انجام میشود. گرادیان هر پارامتر برابر است با حاصلضرب تمام مشتقهای محلی در مسیر میان تابع زیان تا آن پارامتر. وقتی مسیرها branch و سپس merge شوند، سهم هرکدام را با هم جمع میکنید (قاعدهی زنجیرهای چندمتغیره).
کل پسانتشار همین است: پیادهسازی سیستماتیک قاعدهی زنجیرهای در یک گراف محاسباتی، از خروجی به سمت ورودیها.
ماتریس ژاکوبی
وقتی تابعی یک بردار را به بردار دیگر مینگارد (مانند یک لایهی شبکه عصبی)، مشتق آن یک ماتریس خواهد بود. ماتریس ژاکوبی (Jacobian) شامل تمام مشتقهای جزئی تکتک خروجیها نسبت به تکتک ورودیهاست.
برای تابع ، ماتریس ژاکوبی یک ماتریس است:
| ... | ||||
|---|---|---|---|---|
| ... | ||||
| ... | ||||
| ... | ... | ... | ... | ... |
| ... |
برای شبکههای عصبی نیازی نیست ژاکوبی را دستی حساب کنید؛ PyTorch خودش این کار را انجام میدهد. اما شناخت آن به درک ابعاد ماتریسها در پسانتشار کمک میکند: اگر لایهای را به تصویر کند، ژاکوبی آن دارای ابعاد خواهد بود. گرادیان در مسیر بازگشت از ترانهادهی این ماتریس عبور میکند.
چرا این موضوع در شبکههای عصبی اهمیت دارد؟
تکتک وزنهای شبکه عصبی صاحب یک گرادیان میشوند. گرادیان میگوید هر وزن را چطور دستکاری کنید تا زیان کاهش یابد.
بهروزرسانی هر وزن به این صورت است:
W1 = W1 - lr * dL/dW1W2 = W2 - lr * dL/dW2
در گذر پیشرو (forward pass) پیشبینی و زیان حساب میشوند. در گذر پسرو (backward pass) گرادیان زیان نسبت به تکتک وزنها به دست میآید. سپس هر وزن گام کوچکی رو به پایین برمیدارد. تکرار این کار برای میلیونها مرحله، کل داستان یادگیری عمیق است.
پیادهسازی عملی
گام 1: مشتق عددی از صفر
def numerical_derivative(f, x, h=1e-7):
return (f(x + h) - f(x - h)) / (2 * h)
def f(x):
return x ** 2
for x in [-2, -1, 0, 1, 2]:
numerical = numerical_derivative(f, x)
analytical = 2 * x
print(f"x={x:2d} f'(x) numerical={numerical:.6f} analytical={analytical:.1f}")
مشتق عددی تا چندین رقم اعشار کاملاً با مشتق تحلیلی همخوانی دارد.
گام 2: مشتقهای جزئی و گرادیانها
def numerical_gradient(f, point, h=1e-7):
gradient = []
for i in range(len(point)):
point_plus = list(point)
point_minus = list(point)
point_plus[i] += h
point_minus[i] -= h
partial = (f(point_plus) - f(point_minus)) / (2 * h)
gradient.append(partial)
return gradient
def f_multi(point):
x, y = point
return x**2 + 3*x*y + y**2
grad = numerical_gradient(f_multi, [1.0, 2.0])
print(f"Numerical gradient at (1,2): {[f'{g:.4f}' for g in grad]}")
print(f"Analytical gradient at (1,2): [2*1+3*2, 3*1+2*2] = [{2*1+3*2}, {3*1+2*2}]")
گام 3: گرادیان کاهشی برای یافتن کمینهی f(x) = x^2
x = 5.0
lr = 0.1
for step in range(20):
grad = 2 * x
x = x - lr * grad
print(f"step {step:2d} x={x:8.4f} f(x)={x**2:10.6f}")
با شروع از ، در هر گام به کمینه یعنی نزدیکتر میشویم.
گام 4: گرادیان کاهشی روی یک تابع 2بعدی
def f_2d(point):
x, y = point
return x**2 + y**2
point = [4.0, 3.0]
lr = 0.1
for step in range(30):
grad = numerical_gradient(f_2d, point)
point = [p - lr * g for p, g in zip(point, grad)]
loss = f_2d(point)
if step % 5 == 0 or step == 29:
print(f"step {step:2d} point=({point[0]:7.4f}, {point[1]:7.4f}) f={loss:.6f}")
گام 5: مقایسهی مشتقهای عددی و تحلیلی
import math
test_functions = [
("x^2", lambda x: x**2, lambda x: 2*x),
("x^3", lambda x: x**3, lambda x: 3*x**2),
("sin(x)", lambda x: math.sin(x), lambda x: math.cos(x)),
("e^x", lambda x: math.exp(x), lambda x: math.exp(x)),
("1/x", lambda x: 1/x, lambda x: -1/x**2),
]
x = 2.0
print(f"{'Function':<12} {'Numerical':>12} {'Analytical':>12} {'Error':>12}")
print("-" * 50)
for name, f, df in test_functions:
num = numerical_derivative(f, x)
ana = df(x)
err = abs(num - ana)
print(f"{name:<12} {num:12.6f} {ana:12.6f} {err:12.2e}")
گام 6: محاسبهی عددی ماتریس هسیان
def hessian_2d(f, x, y, h=1e-5):
fxx = (f(x + h, y) - 2 * f(x, y) + f(x - h, y)) / (h ** 2)
fyy = (f(x, y + h) - 2 * f(x, y) + f(x, y - h)) / (h ** 2)
fxy = (f(x + h, y + h) - f(x + h, y - h) - f(x - h, y + h) + f(x - h, y - h)) / (4 * h ** 2)
return [[fxx, fxy], [fxy, fyy]]
def saddle(x, y):
return x ** 2 - y ** 2
def bowl(x, y):
return x ** 2 + y ** 2
H_saddle = hessian_2d(saddle, 0.0, 0.0)
H_bowl = hessian_2d(bowl, 0.0, 0.0)
print(f"Saddle Hessian: {H_saddle}") # [[2, 0], [0, -2]] -- mixed signs
print(f"Bowl Hessian: {H_bowl}") # [[2, 0], [0, 2]] -- both positive
مقادیر ویژهی هسیان برای تابع زینی برابر با 2 و -2 هستند (علامتهای مختلف که نشاندهندهی نقطهی زینی است). برای تابع کاسهای، مقادیر ویژه 2 و 2 هستند (هر دو مثبت که کمینه بودن نقطه را تأیید میکنند).
گام 7: بررسی تقریب تیلور در عمل
import math
def taylor_approx(f, f_prime, f_double_prime, x0, h, order=2):
result = f(x0)
if order >= 1:
result += f_prime(x0) * h
if order >= 2:
result += 0.5 * f_double_prime(x0) * h ** 2
return result
x0 = 0.0
for h in [0.1, 0.5, 1.0, 2.0]:
true_val = math.sin(h)
t1 = taylor_approx(math.sin, math.cos, lambda x: -math.sin(x), x0, h, order=1)
t2 = taylor_approx(math.sin, math.cos, lambda x: -math.sin(x), x0, h, order=2)
print(f"h={h:.1f} sin(h)={true_val:.4f} order1={t1:.4f} order2={t2:.4f}")
نزدیک به نقطهی ، تقریب مرتبهی اول تیلور به شکل درمیآید. این تقریب برای مقادیر کوچک عالی است اما برای مقادیر بزرگ به هم میریزد. به همین دلیل گرادیان کاهشی با نرخهای یادگیری کوچک بهتر کار میکند؛ چون در هر گام فرض بر این است که تقریب خطی اعتبار دارد.
گام 8: چرا این موضوع برای شبکه عصبی اهمیت دارد؟
import random
random.seed(42)
w = random.gauss(0, 1)
b = random.gauss(0, 1)
lr = 0.01
xs = [1.0, 2.0, 3.0, 4.0, 5.0]
ys = [3.0, 5.0, 7.0, 9.0, 11.0]
for epoch in range(200):
total_loss = 0
dw = 0
db = 0
for x, y in zip(xs, ys):
pred = w * x + b
error = pred - y
total_loss += error ** 2
dw += 2 * error * x
db += 2 * error
dw /= len(xs)
db /= len(xs)
total_loss /= len(xs)
w -= lr * dw
b -= lr * db
if epoch % 40 == 0 or epoch == 199:
print(f"epoch {epoch:3d} w={w:.4f} b={b:.4f} loss={total_loss:.6f}")
print(f"\nLearned: y = {w:.2f}x + {b:.2f}")
print(f"Actual: y = 2x + 1")
تمام حلقههای آموزشی مبتنی بر گرادیان همین الگو را دنبال میکنند: پیشبینی، محاسبهی زیان، محاسبهی گرادیانها و بهروزرسانی وزنها.
استفادهی عملی
با NumPy، همین کارها بسیار سریعتر و خلاصهتر انجام میشوند:
import numpy as np
x = np.array([1, 2, 3, 4, 5], dtype=float)
y = np.array([3, 5, 7, 9, 11], dtype=float)
w, b = np.random.randn(), np.random.randn()
lr = 0.01
for epoch in range(200):
pred = w * x + b
error = pred - y
loss = np.mean(error ** 2)
dw = np.mean(2 * error * x)
db = np.mean(2 * error)
w -= lr * dw
b -= lr * db
print(f"Learned: y = {w:.2f}x + {b:.2f}")
همین حالا گرادیان کاهشی را از صفر پیادهسازی کردید. در PyTorch محاسبهی گرادیان خودکار انجام میشود، اما چرخهی بهروزرسانی دقیقاً شبیه به همین کد است.
تمرینها
- تابع
numerical_second_derivative(f, x)را با دو بار صدا زدنnumerical_derivativeپیادهسازی کنید. بررسی کنید که مشتق دوم در نقطهی برابر با 12 شود. - با گرادیان کاهشی کمینهی تابع را پیدا کنید. کار را از شروع کنید. پاسخ نهایی باید به همگرا شود.
- تکانه (momentum) را به حلقهی گرادیان کاهشی اضافه کنید: یک بردار سرعت (velocity) بسازید که گرادیانهای قبلی را در خود ذخیره کند. سرعت همگرایی را با و بدون momentum روی تابع مقایسه کنید.
راهنماییها
تمرین 1. تابع کمکی سادهای بنویسید که خروجی numerical_derivative(f, x) را برگرداند و بعد همان را دوباره به numerical_derivative بدهید. اگر خروجی نویز داشت، در هر دو فراخوانی گام بزرگتری مثل h=1e-4 بردارید؛ مقدار تابع در باید به 12 بسیار نزدیک باشد.
تمرین 2. فرمول گرادیان را بنویسید یا از numerical_gradient استفاده کنید و سپس gradient_descent_nd را از نقطهی اجرا کنید. مقدار نقطه را هر 10 گام یک بار چاپ کنید؛ این مقدار باید به سمت برود و زیان به حدود 0 برسد.
تمرین 3. یک متغیر سرعت به نام v نگه دارید، آن را به شکل v = momentum * v - lr * grad بهروزرسانی کنید و بعد v را با x جمع بزنید. تعداد گامهایی را بشمارید که هر روش برای رساندن گرادیان به حدود 0 نیاز دارد؛ نقطهی کمینه روی است.
اصطلاحات کلیدی
| اصطلاح | در گفتار عامیانه | معنای دقیق علمی |
|---|---|---|
| مشتق (Derivative) | «شیب خط» | نرخ تغییرات تابع در یک نقطه؛ نشان میدهد خروجی به ازای هر واحد تغییر در ورودی، چقدر تغییر میکند. |
| مشتق جزئی (Partial derivative) | «مشتق یک متغیر» | مشتق نسبت به یک متغیر در حالی که سایر متغیرها ثابت فرض شدهاند. |
| گرادیان (Gradient) | «جهت بیشترین شیب صعودی» | برداری از تمام مشتقهای جزئی؛ به سمتی اشاره میکند که مقدار تابع بیشترین سرعت رشد را دارد. |
| گرادیان کاهشی (Gradient descent) | «حرکت به سمت سرازیری» | کم کردن مضربی از گرادیان (با ضریب نرخ یادگیری) از پارامترها برای کاهش زیان؛ هستهی اصلی آموزش شبکههای عصبی. |
| نرخ یادگیری (Learning rate) | «طول گام» | عددی اسکالر که اندازهی هر گام گرادیان کاهشی را تعیین میکند. زیادی بزرگ: واگرایی؛ زیادی کوچک: سرعت حلزونی. |
| قاعدهی زنجیرهای (Chain rule) | «ضرب زنجیرهای مشتقها» | قانون مشتقگیری از توابع مرکب: . پایهی ریاضی پسانتشار. |
| ماتریس ژاکوبی (Jacobian) | «ماتریس مشتقها» | وقتی تابع بردار را به بردار مینگارد، ژاکوبی ماتریسِ تمام مشتقهای جزئیِ خروجیها نسبت به ورودیها است. |
| مشتق عددی (Numerical derivative) | «تفاضل متناهی» | تقریب مشتق با ارزیابی تابع در دو نقطهی بسیار نزدیک و بهدست آوردن شیب خط بین آنها. |
| پسانتشار (Backpropagation) | «مشتقگیری خودکار حالت معکوس» | محاسبهی لایهبهلایهی گرادیانها از خروجی به ورودی بر اساس قاعدهی زنجیرهای؛ موتور اصلی یادگیری در شبکههای عصبی. |
| هسیان (Hessian) | «ماتریس مشتقهای مرتبه دوم» | ماتریس تمام مشتقهای جزئی مرتبهی دوم؛ انحنای تابع را مشخص میکند. معین مثبت بودن هسیان در نقطهی بحرانی، نشانهی کمینهی محلی است. |
| سری تیلور (Taylor series) | «تقریب با چندجملهای» | تقریب زدن تابع در نزدیکی یک نقطه با مشتقهای آن: . پایهای برای درک سازوکار گرادیان کاهشی و روش نیوتن. |
| انتگرال (Integral) | «مساحت زیر منحنی» | انباشت یک کمیت در یک بازه؛ در یادگیری ماشین برای تعریف احتمالات، امید ریاضی و واگرایی KL به کار میرود. |
برای مطالعهی بیشتر
- 3Blue1Brown: Essence of Calculus - درک شهودی و بصری از مشتقها، انتگرالها و قاعدهی زنجیرهای
- Stanford CS231n: Backpropagation - نحوهی جریان گرادیانها در لایههای شبکه عصبی
