ریاضی و AI / بهینهسازی
گرادیان نزولی چگونه مدل را آموزش میدهد؟ یک مثال با پایتون
تابع هزینه، مشتق، نرخ یادگیری و گرادیان را با محاسبهٔ دستی و کد ساده بفهم؛ سپس تفاوت کمینه کردن خطای آموزش با تعمیم را یاد بگیر.

تصویرسازی تحریریه با ابزار تولید تصویر؛ سند تاریخی یا مرجع تشریحی نیست.
عبارت «مدل از داده یاد میگیرد» تا وقتی وزن و خطا را نبینی مبهم میماند. در این درس یک پارامتر را از صفر حرکت میدهیم، هزینه را اندازه میگیریم و میبینیم چرا جهتِ منفیِ مشتق میتواند ما را به کمینه نزدیک کند. مثال عمداً کوچک است تا تمام مراحل با دست قابل بررسی باشد. بعد همین منطق را به یک مدلِ خطیِ ساده وصل میکنیم و محدودیتهای آن را میخوانیم.
این درس را با ساروی تمرین کن- مشتق جهتِ افزایشِ محلی را نشان میدهد
- قانونِ بهروزرسانی را با دست اجرا کن
- نرخ یادگیریِ بزرگ و کوچک چه میکنند؟
چه چیزی را میخواهیم کم کنیم؟
فرض کن تابعِ هزینه برابر مربعِ فاصلهٔ وزن از سه است: وزن منهای سه، همه به توان دو. کمینهٔ آن در وزنِ سه و مقدار صفر رخ میدهد. هنوز دادهٔ واقعی یا شبکهٔ عصبی نداریم؛ فقط یک مسئلهٔ بهینهسازی داریم. این سادگی اجازه میدهد الگوریتم را جدا از پیچیدگیِ مدل یاد بگیریم.
قبل از اجرای روش، سه چیز را مشخص کن: پارامترِ قابل تغییر چیست، هزینه چگونه تعریف میشود و دامنهٔ پارامتر چیست. اگر اینها معلوم نباشند، جملهٔ «بهینه شد» معنی روشنی ندارد. در مثال ما وزن یک عدد حقیقی است و هزینه نامنفی است. این دو ویژگی بعداً به ما امکان میدهند خروجیهای عجیبِ کد را با یک کنترلِ ساده تشخیص بدهیم.
منبع این بخش: Google؛ گرادیان نزولی ↗
مشتق جهتِ افزایشِ محلی را نشان میدهد
مشتقِ هزینهٔ مثال، دو برابر وزن منهای سه است. در وزنِ صفر، مشتق منفی شش است؛ با کمی افزایشِ وزن، هزینه کم میشود. در وزنِ پنج، مشتق چهار است؛ کاهشِ وزن میتواند هزینه را پایین بیاورد. گرادیان در چندبعد، برداری از مشتقهای جزئی است و جهتِ تندترین افزایشِ محلی را در هندسهٔ اقلیدسی نشان میدهد.
برای کم کردن هزینه، در جهتِ منفیِ گرادیان حرکت میکنیم. واژهٔ «محلی» مهم است؛ یک گامِ بسیار بزرگ ممکن است از ناحیهٔ مناسب عبور کند و نتیجهٔ بدتری بدهد. جهتِ درست بهتنهایی کافی نیست، اندازهٔ گام هم اهمیت دارد. تشبیه پایین رفتن از تپه مفید است، ولی تابعهای واقعیِ یادگیری لزوماً یک کاسهٔ صاف با یک نقطهٔ کمینه نیستند.
قانونِ بهروزرسانی را با دست اجرا کن
وزنِ جدید برابر وزنِ قبلی منهای نرخِ یادگیری ضربدر مشتقِ هزینه است. با وزنِ آغازین صفر و نرخِ یکدهم، گام اول صفر منهای یکدهم ضربدر منفی شش، یعنی ۰٫۶ است. هزینه از ۹ به ۵٫۷۶ میرسد. در گام بعد مشتق منفی ۴٫۸ و وزنِ تازه ۱٫۰۸ میشود.
برای سه گامِ بعد، همین حساب را روی کاغذ ادامه بده. هر سطر باید وزنِ قبلی، مشتق، وزنِ جدید و هزینهٔ جدید داشته باشد. اگر فقط فهرست وزنها را بنویسی، پیدا کردنِ خطای علامت سخت میشود. سپس جدول را با خروجی کد مقایسه کن. اختلافِ جزئیِ نمایش اعشاری طبیعی است؛ اختلافِ جهت یا رشدِ سریعِ هزینه نیاز به بررسی دارد.
L(w) = (w - 3)²
L'(w) = 2(w - 3)
w_next = w - learning_rate * L'(w)
w = 0, learning_rate = 0.1
w_next = 0 - 0.1 * (-6) = 0.6منبع این بخش: Google؛ تابع هزینه ↗
نرخ یادگیریِ بزرگ و کوچک چه میکنند؟
در همین تابعِ خاص، نرخِ ۰٫۵ از هر وزن در یک گام به سه میرسد. نرخِ یک از صفر به شش و دوباره به صفر میپرد و همگرا نمیشود. نرخِ بزرگتر میتواند فاصله را بیشتر کند. این رفتار را از رابطهٔ خطای تازه برابر یک منهای دو نرخ، ضربدر خطای قبلی میتوان فهمید؛ برای همگرایی، قدرمطلق این ضریب باید کمتر از یک باشد.
نتیجهٔ بازهٔ صفر تا یک برای نرخ، مخصوص همین تابع با همین مقیاس است. آن را نسخهٔ عمومی برای آموزش همهٔ مدلها ندان. اگر هزینه را در صد ضرب کنی، اندازهٔ مشتق و نرخِ مناسب هم تغییر میکند. در گزارش آزمایش، تابع، مقیاس داده و نرخ را کنار هم ثبت کن. یک عددِ خوب در یک مسئله ممکن است در مسئلهٔ دیگر باعث ناپایداری شود.
از یک کاسه به مدلِ خطی
حالا مدلِ پیشبینی را وزن ضربدر ایکس بگیر و دادههای فرضی را جفتهای یک و دو، دو و چهار، سه و شش قرار بده. در این مثال رابطهٔ دقیق ایگرگ برابر دو ایکس است. هزینه را میانگینِ مربعِ خطای پیشبینیها تعریف میکنیم. وزنِ مناسب دو است؛ عمداً عرض از مبدأ را صفر گرفتهایم تا تنها یک پارامتر داشته باشیم.
این انتخابِ مدل یک فرض است. اگر دادهٔ واقعی از خطی با عرض از مبدأ غیرصفر بیاید، مدلِ تکپارامتری ممکن است حتی با بهینهسازی خوب نتواند آن را دقیق نمایش دهد. خطای مدل و خطای الگوریتمِ بهینهسازی را جدا کن. کم کردنِ نرخ یا زیاد کردنِ تعداد گامها، کمبودِ شکلِ مدل را بهخودیخود جبران نمیکند.
منبع این بخش: Google؛ نرخ یادگیری و ابرپارامترها ↗
مشتقِ میانگین مربع خطا
برای هر نمونه، خطا برابر وزن ضربدر ورودی منهای خروجیِ واقعی است. مشتقِ مربع خطا نسبت به وزن، دو برابرِ ورودی ضربدر خطاست. سپس روی نمونهها میانگین میگیریم. در وزنِ صفر، خطاها منفی دو، منفی چهار و منفی ششاند و گرادیان میانگین منفی پنجاهوششسوم میشود. با نرخِ ۰٫۰۵، وزنِ گام اول حدود ۰٫۹۳۳۳ است.
نشانهٔ مثبتِ ورودیها در این مثال باعث میشود وزنِ صفر زیرپیشبینی کند و گام اول آن را بالا ببرد. برای کنترل، این توضیحِ کیفی را با علامتِ گرادیان تطبیق بده. اگر کد در گام نخست وزن را منفی کرد، احتمالاً علامتِ خطا یا قانونِ بهروزرسانی را وارونه نوشتهای. بررسیِ کیفی پیش از عدد، روش سادهای برای پیدا کردن خطاهای رایج است.
همهٔ داده یا یک دسته؟
در گرادیانِ کامل، هر گام از تمام دادههای آموزش استفاده میکند. در روش تصادفی یا دستههای کوچک، برآوردِ گرادیان از یک نمونه یا بخشی از داده به دست میآید. این کار میتواند هزینهٔ هر گام را کاهش دهد و مسیرِ پرنوسانتری بسازد. واژهٔ «تصادفی» به معنای تغییرِ بیقاعدهٔ پارامترها نیست؛ هنوز یک قانونِ بهروزرسانیِ مبتنی بر هزینه داریم.
برای شروع، نسخهٔ کاملِ مثالِ سهنمونهای را اجرا کن. بعد فقط یکی از نمونهها را در هر گام به کار ببر و تفاوت مسیر را ببین. مقایسهٔ منصفانه نیازمند توجه به تعدادِ عبور از داده و تعدادِ بهروزرسانیهاست. هزار گام روی یک نمونه با هزار گام روی تمام مجموعه، محاسبهٔ یکسانی مصرف نمیکند. معیارِ آزمایش را پیش از نتیجهگیری مشخص کن.
کاهش هزینهٔ آموزش، پایانِ یادگیری نیست
مدلی میتواند روی دادههای آموزش خوب عمل کند و روی نمونههای تازه ضعیف باشد. برای ارزیابی، دادهٔ جدا و روشِ تقسیمِ مناسب لازم است. اگر با نگاه کردنِ مکرر به آزمون، تنظیمات را عوض کنی، اطلاعاتِ آن مجموعه وارد تصمیمهای آموزش میشود و نقشِ آزمونِ نهایی تضعیف میشود. تفکیکِ آموزش، اعتبارسنجی و آزمون فقط یک نامگذاری ظاهری نیست.
در مثالِ کوچکِ ما، دادهها بینویز و دقیقاً خطیاند؛ پس موفقیتِ کد شواهدی دربارهٔ عملکرد روی مسئلهٔ واقعی نیست. این مرز را در یادداشتِ پروژه بنویس. برای یک مدلِ عملی، تعریفِ مسئله، کیفیتِ داده، نشتِ اطلاعات و معیارِ ارزیابی به اندازهٔ انتخابِ الگوریتم اهمیت دارند. «هزینه پایین آمد» یک مشاهده است، نه اثباتِ کیفیتِ محصول.
کدِ قابل اجرا و سه کنترل
کد همراه بدون کتابخانهٔ اضافی وزن را به سمت سه حرکت میدهد. هزینه و مشتق جدا تعریف شدهاند تا بتوانی هر کدام را مستقل بررسی کنی. در نرخِ یکدهم، هزینه باید کاهش یابد و پس از گامهای کافی وزن به سه نزدیک شود. سپس نرخِ یک را امتحان کن و نوسان را با تحلیلِ دستیِ بالا مقایسه کن.
برای مدلِ خطی، همان ساختار را با میانگینِ خطاها جایگزین کن. دادهٔ خالی، مقیاسِ بسیار بزرگِ ورودی و عددهای نامعتبر را در پروژهٔ واقعی مدیریت کن. در این درس کد فقط یک آزمایشِ آموزشیِ کوچک است. تعدادِ رقمهای اعشار را با دقتِ علمی اشتباه نگیر؛ نمایشِ ده رقم، ده رقم اطلاعاتِ قابل اعتماد تولید نمیکند.
def loss(w):
return (w - 3) ** 2
def train(rate, steps=100):
w = 0.0
costs = [loss(w)]
for _ in range(steps):
w -= rate * 2 * (w - 3)
costs.append(loss(w))
return w, costs
w, costs = train(.1)
assert abs(w - 3) < 1e-8
assert all(b <= a for a, b in zip(costs, costs[1:]))
print("weight:", w, "cost:", costs[-1])
print("rate=1:", train(1, 4))تمرینِ پایان و پرسشِ خوب از ساروی
با وزنِ اولیهٔ پنج و نرخِ ۰٫۱، مشتق چهار و وزنِ بعدی ۴٫۶ است. هزینه از چهار به ۲٫۵۶ میرسد. اکنون نرخ را ۱٫۲ بگیر؛ وزن از صفر به ۷٫۲ میرود و هزینه به ۱۷٫۶۴ افزایش مییابد. این دو مثال نشان میدهند جهتِ الگوریتم و اندازهٔ گام را باید با هم بررسی کرد.
در ساروی، بهجای «یادگیری ماشین را توضیح بده»، جدولِ گامهای خودت را بده و بخواه خطای علامت یا فرض را پیدا کند. بعد از مدل بخواه یک تابعِ هزینهٔ تازه با کمینهٔ معلوم پیشنهاد کند تا روش را امتحان کنی. اگر هنوز مشتق برایت مبهم است، به درسِ مشتق برگرد. فهمِ یک مثالِ کوچک و قابل بررسی، شروعِ بهتری از اجرای یک شبکهٔ بزرگ بدون دانستنِ معنای هزینه است.
این کار را خودت انجام بده.
- پنج گام نخست را با وزن، گرادیان و هزینه بنویس.
- نرخهای ۰٫۱ و ۱ را اجرا و علت تفاوت را توضیح بده.
- فرق خطای مدل، خطای بهینهسازی و خطای تعمیم را بنویس.
برای بررسی بیشتر
Google؛ گرادیان نزولیGoogle؛ تابع هزینهGoogle؛ نرخ یادگیری و ابرپارامترهادر انجام این کار به مشکل خوردی؟
از پشتیبانی کمک بگیر