عنوان
شبکهٔ عصبی ایدهایه که داره یک بستر ایجاد میکنه تا مدل بتونه چیزهای پیچیدهتر رو بفهمه. این کار رو هم با یکسری rule نسبتاً ساده انجام میده؛ ruleهایی که اجازه میدن مدل از اشتباههاش یاد بگیره.
یعنی مدل اول یک جواب میده، بعد میفهمه جوابش چقدر خوب یا بد بوده و سعی میکنه خودش رو طوری تغییر بده که دفعهٔ بعد جواب بهتری بده.
کل داستان شبکهٔ عصبی، gradient descent و backpropagation تهش برمیگرده به همین ایدهٔ ساده:
مدل اشتباه میکنه، میفهمه چقدر اشتباه کرده و یاد میگیره کمتر اشتباه کنه.
حالا سؤال اینه که این «یاد گرفتن» دقیقاً چطور اتفاق میافته؟
نورون مصنوعی قرار نیست واقعاً شبیه مغز انسان کار کنه؛ فقط یک ایدهٔ سادهست که از نورونهای مغزی الهام گرفته شده.
فرض کن مدل میخواد تصمیم بگیره یک عکس گربه هست یا نه. قبل از اینکه به جواب برسه، کلی عدد بهش میرسه؛ مثلاً رنگ بعضی پیکسلها، شکل گوشها، وجود داشتن یا نداشتن سبیل و هزار تا چیز دیگه.
یک نورون مصنوعی این ورودیها رو میگیره و برای هر کدوم مشخص میکنه که چقدر مهمه. این «مهم بودن» هر ورودی با یک عدد مشخص میشه که بهش میگیم weight یا وزن.
پس اگر خیلی ساده بخوایم بگیم، یک نورون ورودیها رو میگیره، به هر کدوم بر اساس اهمیتش وزن میده، همه رو با هم جمع میکنه و در نهایت مشخص میکنه خروجیاش چقدر فعال باشه.
محاسبهٔ اولیه در یک نورون
مدل قرار نیست خودش یک فرمول جدید اختراع کنه. ساختار کلیاش از قبل مشخصه؛ میدونیم قرار است ورودیها رو بگیره، در weightها ضرب کنه، با هم جمع کنه و یک خروجی بده.
چیزی که مدل نمیدونه، مقدار درست weightها و biasهاست. در واقع weight و bias همون چیزهایی هستن که مدل قراره یاد بگیره.
میشه اینطوری دیدش که مدل یکسری پیچ تنظیم داره. هر weight یک پیچه که مشخص میکنه یک ورودی چقدر مهمه و bias هم یک پیچ دیگهست که کمک میکنه مدل نقطهٔ شروع تصمیمش رو جابهجا کنه.
اول کار، مدل هیچ ایدهای نداره که کدوم ورودی مهمه. برای همین weightها معمولاً با عددهای کوچک و تقریباً رندوم شروع میشن. بعد مدل جواب درست رو با جواب خودش مقایسه میکنه و این پیچها را، نه کاملاً رندوم و نه به یک اندازه، تغییر میده.
اگر شبکه فقط ضرب و جمع انجام بده، حتی اگر دهها لایه داشته باشه، در نهایت معادل یک ضرب و جمع بزرگتره. یعنی اضافه کردن لایههای بیشتر به تنهایی به مدل کمک نمیکنه چیزهای پیچیدهتری یاد بگیره.
اینجاست که activation function وارد میشه. activation function یک تابع کوچیکه که بعد از محاسبهٔ هر نورون قرار میگیره و خروجی آن را تغییر میده. این تابع باعث میشه مدل فقط یک ماشین جمع و ضرب نباشه و بتواند رابطههای غیرخطی را هم یاد بگیره.
یک نورون کاملتر
خیلی از رابطههای واقعی خطی نیستن. مثلاً در قیمت خانه، ممکنه افزایش متراژ تا یک حدی روی قیمت خیلی اثر داشته باشه، ولی بعد از یک نقطه اثرش کمتر بشه. یا در تشخیص تصویر، وجود یک پیکسل خاص به تنهایی معنی خاصی نداره، ولی ترکیب چند شکل کنار هم میتونه معنی «گوش گربه» بده.
یکی از سادهترین activation functionها، ReLU است.
تابع ReLU
یعنی اگر مقدار ورودی مثبت باشه، همون مقدار را رد میکنه. اگر منفی باشه، خروجی را صفر میکنه.
دو نمونه از رفتار ReLU
یک activation function معروف دیگر، sigmoid است.
تابع Sigmoid
خروجی sigmoid همیشه بین صفر و یک است. برای همین وقتی میخواهیم خروجی را مثل احتمال ببینیم، خیلی کاربرد دارد.
تفسیر خروجی Sigmoid
وقتی داده از ورودی وارد شبکه میشه و لایهبهلایه جلو میره تا به prediction برسد، به این فرایند میگیم forward pass.
مسیر حرکت داده در شبکه
تا اینجا شبکه فقط دارد جواب تولید میکنه. برای یاد گرفتن، مدل باید بفهمه جوابش چقدر با جواب درست فاصله داشته.
فرض کن مدل میخواد قیمت یک خانه رو پیشبینی کنه. قیمت واقعی خانه مثلاً ۱۰ میلیارد بوده، ولی مدل گفته ۸ میلیارد.
مدل باید این اشتباه را به یک عدد تبدیل کنه تا بفهمه چقدر باید خودش رو تغییر بده. اینجاست که از چیزی به اسم loss function استفاده میکنیم.
محاسبهٔ loss
اینجا target جواب واقعی و prediction جواب مدل است.
محاسبهٔ خطای پیشبینی
اگر مدل بهجای ۸ میلیارد، ۹.۵ میلیارد را پیشبینی میکرد، loss کمتر میشد.
یک پیشبینی بهتر
پس مشخصه که جواب دوم بهتر بوده، چون loss کمتری داره.
حالا مدل میدونه جوابش چقدر بد بوده، ولی هنوز باید بفهمه هر weight را به کدام سمت و چقدر تغییر بده.
فرض کن فقط یک weight داریم. اگر این weight را یک مقدار خیلی کوچک تغییر بدیم، loss چه تغییری میکنه؟ اگر با بیشتر کردن weight، loss کمتر بشه، حرکت در همان جهت مفیده. اگر loss بیشتر بشه، باید به سمت دیگر حرکت کنیم.
مقداری که این تغییر را اندازه میگیره، همون چیزیه که بهش میگیم gradient.
> اگر این پارامتر را یک ذره تغییر بدی، loss تقریباً چقدر و در چه جهتی تغییر میکنه؟
Gradient یک Weight
اگر gradient یک weight بزرگ باشه، یعنی آن weight اثر زیادی روی اشتباه نهایی مدل داشته. اگر gradient نزدیک صفر باشه، یعنی تغییر کوچک آن weight فعلاً اثر خیلی خاصی روی loss نمیگذاره.
فرض کن روی یک کوه قرار گرفتی و هوا مهآلوده. هدفت اینه که خودت رو به پایینترین نقطهٔ دره برسونی، ولی فقط میتونی شیب اطراف پات رو ببینی.
gradient descent تقریباً همین کار رو برای مدل انجام میده. مدل روی سطحی حرکت میکنه که ارتفاعش مقدار loss است و سعی میکنه هر بار یک قدم به سمت پایین برداره.
قانون بهروزرسانی Weight
علامت منفی مهمه؛ gradient جهت بالا رفتن loss را نشان میده، ولی ما میخوایم به سمت پایین حرکت کنیم.
learning rate اندازهٔ قدم مدل را مشخص میکنه. اگر خیلی بزرگ باشه، مدل ممکنه از نقطهٔ خوب رد بشه. اگر خیلی کوچک باشه، یادگیری خیلی کند میشه.
قبل از اینکه سراغ چند لایه بریم، بهتره با یک نورون ساده خودِ gradient را حساب کنیم. اینجا قرار نیست چیزی را حفظ کنیم؛ فقط میخواهیم ببینیم مدل با عددها دقیقاً چه کار میکنه.
یک ورودی، یک weight، یک bias و یک sigmoid داریم. هدف مدل اینه که برای این ورودی، خروجی نزدیک به یک بده.
مقادیر اولیه
در forward pass، اول مقدار z و بعد prediction را حساب میکنیم.
Forward Pass
مدل باید خروجی یک میداده، ولی خروجیاش حدود ۰.۶۲۲ شده. حالا loss را حساب میکنیم.
Loss اولیه
حالا سؤال اصلی اینه: اگر weight را کمی تغییر بدیم، loss چقدر تغییر میکنه؟
برای جواب، مسیر اثر weight را قدمبهقدم دنبال میکنیم:
مسیر اثر Weight
قبل از اینکه اثر prediction روی loss را حساب کنیم، تعریف دقیق مشتق را داشته باشیم. مشتق میپرسد اگر prediction را به اندازهٔ خیلی کوچک h تغییر بدهیم، loss با چه سرعتی تغییر میکند.
رابطهٔ اصلی
اول اثر prediction روی loss را حساب میکنیم.
اثر Prediction روی Loss
بعد اثر z روی prediction را حساب میکنیم. چون activation ما sigmoid است، مشتق آن این شکلیه:
اثر z روی Prediction
حالا این دو اثر را ضرب میکنیم تا بفهمیم z چقدر در loss نقش داشته.
Gradient نسبت به z
و چون z از ضرب input در weight ساخته شده، gradient weight این شکلی میشه:
Gradient Weight
علامت منفی یعنی با بیشتر کردن weight، loss کمتر میشه. اگر learning rate را ۰.۱ در نظر بگیریم، update این شکلیه:
بهروزرسانی Weight
bias هم update میشه و بعد مدل دوباره forward pass را انجام میده. نتیجهٔ تازه کمی به جواب درست نزدیکتر و loss هم کمی کمتر میشه.
این فرایند ساده، پایهٔ تمام شبکههای بزرگتره. حالا مسئلهای که پیش میآد اینه که اگر بهجای یک نورون، چندین لایه داشته باشیم، اثر هر weight چطور محاسبه میشه؟
یک weight در لایهٔ اول مستقیماً روی loss اثر نمیذاره. اول خروجی یک نورون را تغییر میده، آن تغییر وارد لایهٔ بعدی میشه و در نهایت روی prediction و loss اثر میذاره.
اثر یک Weight در شبکهٔ چندلایه
سؤال اصلی backpropagation همین است:
هر weight، با عبور از این همه لایه، چقدر در loss نهایی نقش داشته؟
جواب با chain rule به دست میآد. chain rule میگه اگر یک اتفاق از چند مرحله رد شده، برای فهمیدن اثر مرحلهٔ اول روی نتیجهٔ آخر باید اثر همهٔ مرحلهها را پشت سر هم حساب کنیم.
Chain Rule
این فرمول فقط دارد یک سؤال را جواب میدهد: اگر weight را یک ذره تغییر بدیم، در نهایت loss چقدر تغییر میکنه؟
در forward pass، داده از لایهٔ اول وارد میشه، از لایههای بعدی رد میشه و در نهایت به prediction میرسه. بعد هم loss حساب میشه.
در backpropagation، مسیر برعکس میشه. مدل از loss شروع میکنه و به عقب برمیگرده. در هر مرحله بررسی میکنه خروجی آن لایه چقدر در اشتباه نهایی نقش داشته و سپس این سهم را به لایهٔ قبلی منتقل میکنه.
دو مسیر شبکه
هر لایه دو کار انجام میده: مشخص میکنه خروجی خودش چقدر در loss نقش داشته و مشخص میکنه هر weight داخل خودش چقدر مسئول آن خروجی بوده.
پس backpropagation خودش فرآیند یادگیری نیست. backpropagation روشی است که مدل با آن gradient همهٔ weightها و biasها را، حتی در یک شبکهٔ چندلایه، سریع و درست حساب میکنه. gradient descent هم از این gradientها استفاده میکنه تا مدل را یک قدم به سمت loss کمتر حرکت بده.
بیا یک شبکهٔ خیلی کوچک داشته باشیم: فقط یک ورودی، یک weight، یک bias و یک sigmoid. هدف مدل اینه که برای این ورودی، خروجی نزدیک به یک بده.
مقادیر اولیه
اول forward pass را انجام میدیم.
Forward Pass
مدل باید خروجی یک میداده، ولی خروجیاش حدود ۰.۶۲۲ شده. پس loss را حساب میکنیم.
Loss اولیه
حالا backpropagation شروع میشه. اول میپرسیم اگر prediction تغییر کنه، loss چقدر تغییر میکنه؟
اثر Prediction روی Loss
بعد باید اثر z را روی prediction حساب کنیم. چون از sigmoid استفاده کردیم، مشتق sigmoid این شکلیه:
مشتق Sigmoid
حالا این دو اثر را با هم ضرب میکنیم تا بفهمیم z چقدر در loss نقش داشته.
Gradient نسبت به z
و چون z از ضرب input در weight ساخته شده، gradient weight این شکلی میشه:
Gradient Weight
علامت منفی به ما میگه برای کم کردن loss باید weight را بیشتر کنیم.
بهروزرسانی Weight
bias هم gradient خودش را میگیرد و در این مثال به حدود ۰.۰۱۸ میرسد. اگر دوباره forward pass را انجام بدیم، prediction حدود ۰.۶۳۱ میشه. هنوز جواب کامل نیست، اما به جواب درست یعنی یک نزدیکتر شده و loss هم کمتر شده.
مدل همین چرخه را بارها و بارها تکرار میکنه:
چرخهٔ یادگیری
این دقیقاً همان چیزی است که بهش میگیم train کردن مدل.
یک ورودی، یک weight، یک bias و یک Sigmoid داریم. هدف اینه که خروجی نزدیک به یک بشه.
پارامترها و دادهٔ نمونه
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
برای طبقهبندی دودویی، معمولاً از binary cross-entropy استفاده میکنیم.
Binary Cross-Entropy
چون y برابر یک است:
رابطهٔ اصلی
جایگذاری مقادیر
مسیر اثر weight اینه:
مسیر اثر Weight
پس طبق chain rule:
رابطهٔ اصلی
برای ترکیب Sigmoid و Binary Cross-Entropy، بخش اول ساده میشه:
رابطهٔ اصلی
جایگذاری مقادیر
از طرف دیگر:
مشتقهای محلی
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
gradient منفی میگه بیشتر کردن weight و bias، loss را کمتر میکنه.
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
بعد از این update، prediction به حدود ۰.۶۱۸ میرسه و loss کمتر میشه.
در شبکهٔ چندلایه، weightهای لایهٔ اول مستقیم به loss وصل نیستن. ابتدا خروجی یک نورون را تغییر میدن، آن تغییر وارد لایهٔ بعدی میشه، بعد روی output layer اثر میگذاره و در نهایت loss را تغییر میده.
همینجا مسئلهٔ اصلی backpropagation به وجود میآد: هر weight، با عبور از این همه لایه، چقدر در loss نهایی نقش داشته؟
جواب با chain rule به دست میآد. chain rule میگه اگر یک اتفاق از چند مرحله رد شده، برای فهمیدن اثر مرحلهٔ اول روی نتیجهٔ آخر باید اثر همهٔ مرحلهها را پشت سر هم حساب کنیم.
ساختار شبکه
فرض کن hidden layer دو نورون ReLU دارد.
پارامترهای Hidden Layer
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
خروجی این دو نورون وارد output layer میشه.
پارامترهای Output Layer
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
از loss شروع میکنیم و به عقب برمیگردیم.
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
چون هر دو logit در hidden layer مثبتاند، مشتق ReLU برای هر دو یک است.
مشتق ReLU
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
رابطهٔ اصلی
جایگذاری مقادیر
این همان کاریه که backpropagation انجام میده: سهم هر weight در loss را از خروجی به سمت لایههای قبل برمیگردونه.
در forward pass، داده از لایهٔ اول وارد میشه، از لایههای بعدی رد میشه و در نهایت به prediction و loss میرسه. در backpropagation مسیر برعکس میشه؛ مدل از loss شروع میکنه و به عقب برمیگرده.
پس backpropagation خودش فرآیند یادگیری نیست. روشی است که مدل با آن gradient همهٔ weightها و biasها را، حتی در یک شبکهٔ چندلایه، سریع و درست حساب میکنه. gradient descent از این gradientها استفاده میکنه تا مدل را یک قدم به سمت loss کمتر حرکت بده.
Forward Pass در لایهٔ l
Backward Pass در لایهٔ l
Gradientهای لایهٔ l
علامت ⊙ یعنی ضرب عضوبهعضو. در یک batch، gradientها روی نمونهها جمع یا میانگین گرفته میشن.
نه. backpropagation ابزار خیلی قدرتمندیه، ولی تضمین نمیکنه مدل همیشه بهترین جواب ممکن را پیدا کنه.
مدل فقط اطراف نقطهای را میبینه که الان در آن قرار دارد؛ مثل کسی که در مه روی کوه حرکت میکنه و کل نقشهٔ کوه را نمیبینه. ممکنه داخل یک گودی محلی گیر کنه؛ یعنی جایی که اطرافش بهتر به نظر نمیرسه، ولی در یک بخش دیگر از سطح loss جواب خیلی بهتری وجود دارد. به این حالت local minimum میگیم.
اما مسئله فقط local minimum نیست. در شبکههای بزرگ، گاهی مدل به ناحیههای خیلی تخت میرسه که gradient در آنها نزدیک صفره. در این حالت، مدل تقریباً نمیفهمه به کدام سمت باید بره. به این وضعیت معمولاً plateau یا saddle point میگن.
یک مشکل مهم دیگر، vanishing gradient است. در شبکههای خیلی عمیق، چون gradient باید از لایههای زیادی رد بشه، ممکنه آنقدر کوچک بشه که لایههای ابتدایی تقریباً هیچ سیگنال یادگیری دریافت نکنن.
برعکسش هم وجود داره: exploding gradient. یعنی gradient آنقدر بزرگ میشه که weightها با هر قدم بیش از حد تغییر میکنن و آموزش ناپایدار میشه.
بعضی activation functionها هم مشکل مخصوص خودشان را دارن. مثلاً در ReLU، اگر ورودی یک نورون همیشه منفی بماند، خروجی آن نورون دائماً صفر میشود و ممکن است دیگر چیزی یاد نگیرد. به این حالت گاهی dead ReLU میگن.
در عمل برای کم کردن این مشکلات از روشهایی مثل initialization بهتر، normalization، activation functionهای مناسب، optimizerهایی مثل Adam، gradient clipping و معماریهایی مثل residual connection استفاده میشه.
شبکهٔ عصبی با چند rule ساده شروع میکنه، ولی از کنار هم قرار گرفتن تعداد زیادی از همین ruleها میتونه چیزهای پیچیدهای یاد بگیره.
مدل در forward pass یک prediction میده. loss function میگه این prediction چقدر بد بوده. backpropagation به مدل کمک میکنه سهم هر weight و bias را در آن اشتباه حساب کنه و gradient descent پارامترها را در جهتی تغییر میده که loss کمتر بشه.
شبکهٔ عصبی با پیشبینی کردن، اندازه گرفتن اشتباه، پخش کردن مسئولیت اشتباه بین پارامترها و اصلاح تدریجی آنها یاد میگیره.