اگه تا الان سری به شبکههای عصبی زده باشید و باهاشون کار کرده باشید حتما اسم توابع فعال ساز(Activation Functions) یا توابع انتقال(Transform Functions) به گوشتون خورده. این توابع به کمک شبکههای عصبی میان تا بتونن انعطاف پذیری و کارایی بیشتری به اونها بدن. توی این مطلب میخوام کاربردیترین و پراستفادهترین تابعهای فعال ساز رو با جزئیات و کاربردشون رو براتون توضیح بدم. از اونجایی که من همه رو بلد نیستم و تعداد این توابع هم احتمالا در حال زیاد شدن هستش، این مطلب دائما به روز میشه و توابع بیشتری بهش اضافه خواهد شد. خوشحال میشم اگر تابعی رو میشناسید که من اینجا ذکر نکردم توی کامنتها بهم بگید تا اون رو هم اضافه کنم. خب بریم سراغ اصل مطلب.
فرض من برای نوشتن این مطلب اینه که شما با کلیّت شبکه عصبی یا حداقل یک نورون(یا پرسپترون) آشنا هستید و الان دنبال شناخت تابع فعال ساز هستید. اما برای این که جلوی چشممون باشه یه توضیح خیلی ریز درمورد نورون میدم. نورون کوچکترین واحد محاسباتی سازنده شبکههای عصبی هستش. هر نورون تعدادی کانال ورودی داره که ورودی رو از دادهها یا نورونهای دیگه دریافت میکنن. هر کانال برای خودش یک وزن داره و تمام مصیبت شبکههای عصبی پیدا کردن مقدار مناسب برای این وزنهاست.
بعد از اینکه دادهها از این کانالها وارد نورون شدن، هر ورودی در وزن کانال ضرب میشه و حاصل تمام این ضربها با هم جمع میشن و توی یک متغییری(مثلا z) قرار داده میشن.
برای اینکه خروجی نورون مشخص بشه باید این z اعتبار سنجی بشه که آیا این مقدار تولید شده به درد شبکه میخوره یا نه.
توی یک نورون، تابع فعال ساز تصمیم میگیره که با توجه به ورودیها آیا اون نورون باید خروجیش فعال شه یا نه؟ در واقع با مفاهیم ساده ریاضی تصمیم میگیره که آیا ورودیهای نورون در فرایند یادگیری و پیش بینی برای شبکه مهم هستن یا نه(اینکه همین عملیات ساده چجور منتهی به یادگیری و کارای خفن میشه رو حتی خود دانشمندا هم درست نمیدونن!). توابع فعال ساز زیادی وجود دارن که احتمالا به گوشتون خوردن، یکی از مواردی که توی معماری شبکههای عصبی تعیین کننده است انتخاب تابع فعال ساز درست هستش. ما میخوایم در ادامه ببینیم هر کدوم از این توابع چه مشخصههایی دارن و بهتره کجاها استفاده بشن. اینو یادتون باشه که اکثرا بهترین تابع فعال ساز، سادهترین اونها هستند و نیاز نیست الکی خودتونو زجرکش کنید بیخ همه رو دربیارید و فکر کنید هرچی بیشتر یاد بگیرید و پیچیدهتر فکر کنید خیلی خفنید! سادگی پادشاه است
ما سه دسته تابع فعال ساز داریم، که یک دستهش تقریبا تعطیله، یک دستش بود و نبودش فرقی نداره و یک دستش که کارِ ما رو راه میاندازه. این دسته بندی براساس خطی بودن توابع انجام شده:
این دسته فقط یک تابع داره که هم اسم خود دسته هم هستش. همون طور که از اسمش پیداست، این تابع شبیه به یک پله است. کار این تابع این هستش که بسته به یک مقدار آستانه تصمیم میگیره که خروجی تولید شده(z) فعال بشه یا نه(احتمالا با این تابع توی کتاب سیگنالها و سیستمها یا کتابهای ریاضیات مهندسی آشنا هستید). این مقدار آستانه(threshold) رو شما تعیین میکنید اما تابع اصلی براساس عدد 0 تصمیم میگیره. اگر z برابری یا کوچتر از صفر بود نورون غیرفعال(خروجی صفر) میشه در غیر این صورت z به خروجی ارسال میشه. شکلش رو هم براتون گذاشتم.
فرمول ریاضی(بدنه تابع) هم به شکل زیر هستش:
اما این تابع یه سری محدودیت داره که باعث میشه ما سراغ انواع دیگه بریم:
یک نکته بگم: با توجه به اینکه توی عملیات پس انتشار معمولا از مفهوم شیب(گرادیان) استفاده میشه، نباید تابع فعال سازی انتخاب کنید که مشتقش عدد ثابت بشه یا خیلی محدود باشه چون باعث "ناپدید شدن گرادیان" که یکی از مشکلات توی شبکههای عصبی هستش میشه.
این دسته از توابع خیلی آشنا هستن(از راهنمایی تقریبا همیشه باهاشون سر و کله زدیم). کلا هر تابعی که روی محور مختصات به شکل یک خط راست باشه ک تابع خطی یا تابع تطابق(Identity) به حساب میاد. شکل زیر معروفترین تابع خطی(y=x) هستش.
ضابطهی تمام توابع خطی هم به فرم زیر هستش(a و b اعداد ثابت هستن):
تابع خطی فعال ساز هم دقیقا همین ضابطه رو داره. این توابع خیلی ساده هستن که همین سادگی هم براشون سه مشکل عمده به وجود آورده که باعث شده استفاده چندانی نداشته باشن:
این دسته در حال حاضر پراستفادهترین و بهترین دسته برای شبکههای عصبی هستن. دلیلش هم اینه که اولا شکل خطی ندارن، پس میشه برای دادههای غیر خطی و پیچیده ازشون استفاده کرد؛ دوما مشتقشون هم عدد ثابت نمیشه، پس به درد استفاده توی عملیات پس انتشار میخورن. توابع غیر خطی زیادی داریم که در ادامه به اونها میپردازیم.
این تابع هر عدد حقیقیای رو به عنوان ورودی دریافت میکنه و خروجی اون عددی بین 0 تا 1 هست. هرچی عدد بزرگتر(مثبتتر) باشه خروجی بیشتر به ورودی نزدیک هستش و هرچی عدد کوچیکتر باشه خروجی بیشتر به صفر نزدیک میشه. شکل اون توی محور مختصات رو توی تصویر زیر میتونید ببینید.
ضابطهی تابع هم به شکل زیر هستش:
این تابع با اینکه شکل سادهای داره، اما یکی از پرکاربردترین توابع فعال ساز توی شبکههای عصبی هستش. چرا؟
مزایا
معایب
این تابع تقریبا عملکردی مثل تابع سیگموید داره اما با مقداری تفاوت که اون رو تبدیل به تابعی کارآمدتر و پر استفادهتر میکنه. گفتیم که تابع سیگموید چون خروجیای بین 0 تا 1 داره برای مواردی که بخوایم احتمال یک دسته رو به دست بیاریم مورد مناسبیه، اما یک مشکلی برای این کار وجود داره. فرض کنیم که ما توی لایه آخر شبکه عصبی 5 خروجی داریم که به این صورت هستن 0.8، 0.9، 0.7، 0.8، و 0.6 آیا میتونید بگید این خروجی چه چیزی رو بهتون نشون میده؟ نه! چون مشخص نیست که ما باید کدوم خروجی رو به عنوان جواب مسئله مون بپذیریم. ما میدونیم که مجموعه احتمالات فضای خروجی یک مسئله باید برابر با 1 بشه. اما توی مثال بالا اینطور نیست! تابع softmax رو میشه به شکل ترکیبی از چندین تابع سیگموید در نظر گرفت که در نهایت احتمال مرتبط با هر خروجی رو محاسبه میکنه و خروجی این تابع قابل فهمتره نسبت به تابع سیگموید. این تابع اکثرا در لایه آخر شبکه استفاده میشه و وظیفش هم این هستش که احتمال هر خروجی رو بهتون میده طوری که مجموع احتمالات برابر با 1 باشه و شما بتونید از اون استفاده کنید. ضابطه تابع به شکل زیر هستش:
این تابع هم از لحاظ شکل مختصاتی بسیار شبیه به تابع سیگموید هستش با این تفاوت که خروجی تابع(بُرد تابع) توی بازهی -1 تا 1 هستش. در تانژانت هایپربولیک یا تانژانت هذلولوی(Hyperbolic Tangent) هرچی ورودی بزرگتر(مثبتتر) باشه، خروجی خروجی بیشتر به 1 نزدیک میشه و برعکس هرچی خروجی کوچیکتر(منفیتر) باشه خروجی به -1 نزدیک میشه. توی شکل زیر گراف این تابع رو میتونید ببینید:
ضابطهی تابع هم به شکل زیر درمیاد:
مزایا
معایب
توی توابعی که تا الان بررسی کردیم به مشتق اونها هم توجه ویژهای داشتیم، بگذارید برای tanh هم این کار رو انجام بدیم. شکل زیر نمودار مشتق این تابع رو توی دستگاه مختصات نشون میده:
همونطور که میبینید اینجا هم، مثل تابع سیگموید، مشکل ناپدید شدن گرادیان رو داریم. به علاوه شیب اون هم نسبت به شیب مشتق تابع سیگموید تندتره.
اگر چه هر دو تابعِ سیگموید و tanh مشکل ناپدید شدن گرادیان رو دارن، اما چون tanh نسبت به صفر متقارن هستش و این باعث میشه که گرادیان اون به طور مشخص به سمت خاصی حرکت نکنه، به همین خاطر اکثرا در عمل از tanh استفاده میکنن.
این تابع فعال ساز خیلی مهمه و براساس اون هم توابع فعال ساز زیادی به وجود اومدن. به همین خاطر پیشنهاد میکنم حواستون رو توی این یک مورد بیشتر جمع کنید. ReLU از سرواژهی Rectified Linear Unit (واحد خطی تصحیح شده) تشکیل شده. اگر به شکل گرافش که توی تصویر زیر اومده دقت کنید حسِ یک تابع خطی رو به شما میده. مشکل توابع خطی این بود که مشتقشون اعداد ثابت بودن به همین خاطر ما نمیتونستیم از اونها استفاده کنیم. اما تابع ReLU مشتق پذیره و میتونیم از اون برای پس انتشار استفاده کنیم و هزینه محاسباتی کمی هم برای ما داره، برای همین از خوبای توابع فعال ساز به حساب میاد. نکته اصلی توی تابع ReLU این هستش که این تابع فعال ساز تمام نورونها رو فعال نمیکنه و فقط نورونهایی رو فعال میکنه که خروجی اونها بزرگتر از یک هستش(توی شکل زیر میتونید ببینید)
رابطه ریاضی اون به شکل زیر هستش:
مزایا
معایب
ایراد اصلی این تابع مشکلی هست به نام "مرگ ReLU". منظور از مرگ ReLU اینه که برخی از نورونهای ReLU میمیرن و غیرفعال میشن و برای تمامی ورودیها، خروجی 0 میشه. در این حالت، هیچ گرادیانی جریان پیدا نمیکنه و در صورتیکه تعداد نورونهای غیرفعال در شبکه عصبی زیاد بشه، عملکرد مدل تحت تأثیر قرار میگیره.
برای رفع ایراد مرگ ReLU تابعی به اسم Leaky ReLU وجود داره که از مرگ نورونهای با مقادیر منفی جلوگیری میکنه. شکل زیر رو ببینید.
ضابطه تابع هم به شکل زیر هستش:
این تابع تمام مزایای ReLU رو داره و مشکل مرگ نورونها رو هم حل کرده. با این تغییر توی تابع ReLU دیگه برای مقادیر منفی گرادیان صفر نمیشه و میتونیم از اون برای مواردی که خروجی نورون منفی هست هم استفاده کنیم. شکل زیر مشتق تابع Leaky ReLU رو نشون میده.
معایب
این تابع هم یکی از انواع تابع ReLU هستش که برای حل مشکل مرگ نورونها برای مقادیر منفی به وجود اومده(کلا این ReLU اینقدر خوبه که همه میخوان یه جوری کمکش کنن). این تابع برای قسمت منفیها یک ضریب(شیب) در نظر گرفته به نام a. توی عملیات پس انتشار سعی میشه بهترین مقدار a یادگرفته بشه.
ضابطه تابع هم به شکل زیر هستش:
توی تابع بالا a همون ضریب یا شیب برای مقادیر منفی هستش.
اگر توی حل مسئله با استفاده از leaky ReLU موفق نبودیم، میتونیم از این تابع استفاده کنیم. عیب این تابع هم این هستش که به خاطر پارامتر a ممکنه برای مسائل مختلف، به شکل متفاوتی عمل کنه.
این تابع هم برای حل مشکل مرگ نورون توی تابع ReLU به وجود اومده. این تابع هم مثل تابع قبلی تلاش میکنه تا یک شیب رو به قسمت منفی نسبت بده و با این کار از حذف نورونهای منفی جلوگیری کنه. این تابع از یک خم لگاریتمی برای مشخص کردن قسمت منفی استفاده میکنه، برخلاف دو تابع قبلی که این کار رو با یک خط راست انجام داده بودن.
ضابطه تابع:
به دلایل زیر ELU یک جایگزین خیلی خوب برای ReLU هستش:
معایب
این تابع توسط محققین شرکت گوگل توسعه داده شده. این تابع عملکردی مشابه با ReLU رو توی شبکههای عمیق داره. swish کران پایین داره ولی از بالا نامحدوده. یعنی با نزدیک شدن X(مقادیر ورودی) به منفی بینهایت، Yها یا خروجیهای ما به یک مقدار نزدیک میشن. اما با نزدیک شدن X به مثبت بینهایت، Y ها هم به مثبت بینهایت نزدیک میشن. این قضیه توی گراف تابع قابل مشاهده است.
ضابطه تابع هم به شکل زیر هستش:
اندر مزایای این تابع باید براتون بگم که:
خب اینم از این، همونطور که اول مطلب هم گفتم تعداد توابع فعال ساز زیاده و به مرور این مطلب تکمیلتر میشه. خیلی خوشحال میشم توی نظرات توابع دیگه رو هم معرفی کنید که به سراغ بررسی اونها هم برم یا اینکه اگر ویژگیای جا مونده و ما بررسی نکردیم بگید که برای توابع بررسی کنیم. از تجربیات خودتون درمورد استفاده از انواع مختلف توابع فعال ساز توی کاربردها و معماریها متفاوت بگید تا این تجربیات به دوستان دیگه هم منتقل بشه.
مطالب مرتبط با این نوشته در وبلاگ من:
منابع: