توابع فعال ساز در شبکه‌های عصبی

اگه تا الان سری به شبکه‌های عصبی زده باشید و باهاشون کار کرده باشید حتما اسم توابع فعال ساز(Activation Functions) یا توابع انتقال(Transform Functions) به گوشتون خورده. این توابع به کمک شبکه‌های عصبی میان تا بتونن انعطاف پذیری و کارایی بیشتری به اونها بدن. توی این مطلب می‌خوام کاربردی‌ترین و پراستفاده‌ترین تابع‌های فعال ساز رو با جزئیات و کاربردشون رو براتون توضیح بدم. از اونجایی که من همه رو بلد نیستم و تعداد این توابع هم احتمالا در حال زیاد شدن هستش، این مطلب دائما به روز می‌شه و توابع بیشتری بهش اضافه خواهد شد. خوشحال می‌شم اگر تابعی رو می‌شناسید که من اینجا ذکر نکردم توی کامنت‌ها بهم بگید تا اون رو هم اضافه کنم. خب بریم سراغ اصل مطلب.توابع فعال سازفرض من برای نوشتن این مطلب اینه که شما با کلیّت شبکه عصبی یا حداقل یک نورون(یا پرسپترون) آشنا هستید و الان دنبال شناخت تابع فعال ساز هستید. اما برای این که جلوی چشممون باشه یه توضیح خیلی ریز درمورد نورون می‌دم. نورون کوچکترین واحد محاسباتی سازنده شبکه‌های عصبی هستش. هر نورون تعدادی کانال ورودی داره که ورودی رو از داده‌ها یا نورون‌های دیگه دریافت می‌کنن. هر کانال برای خودش یک وزن داره و تمام مصیبت شبکه‌های عصبی پیدا کردن مقدار مناسب برای این وزن‌هاست. شماتیک کلی یک نورون(پرسپترون)بعد از اینکه داده‌ها از این کانال‌ها وارد نورون شدن، هر ورودی در وزن کانال ضرب می‌شه و حاصل تمام این ضرب‌ها با هم جمع می‌شن و توی یک متغییری(مثلا z) قرار داده می‌شن.شماتیک محاسباتی نورون با تابع فعال سازمعادله خروجی نهایی نورون برای اینکه خروجی نورون مشخص بشه باید این z اعتبار سنجی بشه که آیا این مقدار تولید شده به درد شبکه می‌خوره یا نه.توی یک نورون، تابع فعال ساز تصمیم می‌گیره که با توجه به ورودی‌ها آیا اون نورون باید خروجیش فعال شه یا نه؟ در واقع با مفاهیم ساده ریاضی تصمیم می‌گیره که آیا ورودی‌های نورون در فرایند یادگیری و پیش بینی برای شبکه مهم هستن یا نه(اینکه همین عملیات ساده چجور منتهی به یادگیری و کارای خفن می‌شه رو حتی خود دانشمندا هم درست نمی‌دونن!). توابع فعال ساز زیادی وجود دارن که احتمالا به گوشتون خوردن، یکی از مواردی که توی معماری شبکه‌های عصبی تعیین کننده است انتخاب تابع فعال ساز درست هستش. ما می‌خوایم در ادامه ببینیم هر کدوم از این توابع چه مشخصه‌هایی دارن و بهتره کجاها استفاده بشن. اینو یادتون باشه که اکثرا بهترین تابع فعال ساز، ساده‌ترین اونها هستند و نیاز نیست الکی خودتونو زجرکش کنید بیخ همه رو دربیارید و فکر کنید هرچی بیشتر یاد بگیرید و پیچیده‌تر فکر کنید خیلی خفنید! سادگی پادشاه‌ استانواع توابع فعال سازما سه دسته تابع فعال ساز داریم، که یک دسته‌ش تقریبا تعطیله، یک دستش بود و نبودش فرقی نداره و یک دستش که کارِ ما رو راه می‌اندازه. این دسته بندی براساس خطی بودن توابع انجام شده:تابع پله دودویی(تعطیل)تابع خطی(باشه نباشه مهم نیست)تابع غیرخطی(کار راه بنداز)دسته اول: تابع پله‌ی دودویی(Binary Step Function)این دسته فقط یک تابع داره که هم اسم خود دسته هم هستش. همون طور که از اسمش پیداست، این تابع شبیه به یک پله است. کار این تابع این هستش که بسته به یک مقدار آستانه تصمیم می‌گیره که خروجی تولید شده(z) فعال بشه یا نه(احتمالا با این تابع توی کتاب سیگنال‌ها و سیستم‌ها یا کتاب‌های ریاضیات مهندسی آشنا هستید). این مقدار آستانه(threshold) رو شما تعیین می‌کنید اما تابع اصلی براساس عدد 0 تصمیم میگیره. اگر z برابری یا کوچتر از صفر بود نورون غیرفعال(خروجی صفر) می‌شه در غیر این صورت z به خروجی ارسال می‌شه. شکلش رو هم براتون گذاشتم.تابع پله دودویی فرمول ریاضی(بدنه تابع) هم به شکل زیر هستش:تابع پله دودوییاما این تابع یه سری محدودیت داره که باعث می‌شه ما سراغ انواع دیگه بریم:توانایی تولید چند مقدار رو نداره، یعنی همیشه یا صفرِ یا یک. مثلا نمی‌شه ازش برای کلاسبندی چندتایی استفاده کردمشتق( شیب، به انگلیسی: Gradient) این تابع صفر هستش، که یک مانع برای عملیات پس انتشار(backpropagation) حساب می‌شه. پس اگر جایی عملیات پس انتشار داشتید نمی‎‌تونید از این تابع استفاده کنید.یک نکته بگم: با توجه به اینکه توی عملیات پس انتشار معمولا از مفهوم شیب(گرادیان) استفاده می‌شه، نباید تابع فعال سازی انتخاب کنید که مشتقش عدد ثابت بشه یا خیلی محدود باشه چون باعث "ناپدید شدن گرادیان" که یکی از مشکلات توی شبکه‌های عصبی هستش می‌شه. دسته دوم: توابع فعال ساز خطی(Linear Activation Function)این دسته از توابع خیلی آشنا هستن(از راهنمایی تقریبا همیشه باهاشون سر و کله زدیم). کلا هر تابعی که روی محور مختصات به شکل یک خط راست باشه ک تابع خطی یا تابع تطابق(Identity) به حساب میاد. شکل زیر معروف‌ترین تابع خطی(y=x) هستش.ضابطه‌ی تمام توابع خطی هم به فرم زیر هستش(a و b اعداد ثابت هستن):تابع خطیتابع خطی فعال ساز هم دقیقا همین ضابطه رو داره. این توابع خیلی ساده هستن که همین سادگی هم براشون سه مشکل عمده به وجود آورده که باعث شده استفاده چندانی نداشته باشن:چون مشتق این تابع یک عدد ثابت می‌شه نمی‌شه از اون برای مواقعی که پس انتشار داریم استفاده کنیم.چون خط راست هستش نمی‌شه ازش برای دسته‌بندی داده‌های پیچیده استفاده کرد. اکثر داده‌های امروزی اَشکال چند بعدی و پیچیده دارن که با خط راست قابل جداسازی نیستن.توی شبکه‌های عصبی چند لایه، استفاده از این تابع فعال ساز باعث می‌شه تمام لایه‌ها روی یک لایه بریزن(collapse). مهم نیست که شما چند لایه دارید، لایه آخر یک تابع خطی از لایه اول هستش.دسته سوم: توابع فعال ساز غیر خطیاین دسته در حال حاضر پراستفاده‌ترین و بهترین دسته برای شبکه‌های عصبی هستن. دلیلش هم اینه که اولا شکل خطی ندارن، پس می‌شه برای داده‌های غیر خطی و پیچیده ازشون استفاده کرد؛ دوما مشتقشون هم عدد ثابت نمی‌شه، پس به درد استفاده توی عملیات پس انتشار می‌خورن. توابع غیر خطی زیادی داریم که در ادامه به اونها می‌پردازیم.1.تابع فعال ساز سیگموید یا لجستیک(Sigmoid / Logistic Activation Function)این تابع هر عدد حقیقی‌ای رو به عنوان ورودی دریافت می‌کنه و خروجی اون عددی بین 0 تا 1 هست. هرچی عدد بزرگتر(مثبت‌تر) باشه خروجی بیشتر به ورودی نزدیک هستش و هرچی عدد کوچیک‌تر باشه خروجی بیشتر به صفر نزدیک می‌شه. شکل اون توی محور مختصات رو توی تصویر زیر می‌تونید ببینید.تابع فعال ساز سیگمویدضابطه‌ی تابع هم به شکل زیر هستش:تابع سیگمویداین تابع با اینکه شکل ساده‌ای داره، اما یکی از پرکاربردترین توابع فعال ساز توی شبکه‌های عصبی هستش. چرا؟مزایاتوی اکثر مسائلی که توی شبکه‌های عصبی و یادگیری عمیق بررسی می‌‍شن، ما سعی داریم که احتمال خروجی رو بررسی کنیم. از اونجایی که این تابع خروجیش(بُرد تابع) همیشه بین 0 تا 1 هست مورد بسیار مناسبی برای این کاره.تابع مشتق پذیر هستش و مشتق اون یک تابع نرم(smooth) هستش که باعث می‌شه موقع پس انتشار جهشی بین خروجی مقادیر نداشته باشیم(شکل مشتق تابع سیگموید رو می‌تونید این زیر ببینید)نمودار مشتق تابع سیگمویدمعایبمشتق تابع سیگموید می‌شه f'(x) = sigmoid(x)*(1-sigmoid(x)) که توی شکل بالا هم نشون داده شده. همون طور که مشخصه مشتق تابع بین -3 تا 3 مقدار قابل توجهی داره و توی نواحی دیگه این مقدار خیلی کم می‌شه. این یعنی برای مقادیری خارج از بازه ی -3 تا 3 مقدار مشتق تابع خیلی کم و نزدیک به صفر هستش که این می‌تونه منجر به مشکل ناپدید شدن گرادیان بشه که یادگیری شبکه رو به صفر می‌رسونه.مشکل بعدی هم اینه که خروجی تابع در نزدیکی صفر متقارن نیست. بنابراین خروجی نورون‌ها هم علامت می‌شه که این قضیه آموزش شبکه رو مشکل و ناپایدار می‌کنه.2. تابع فعال ساز سافت مکس(softmax)این تابع تقریبا عملکردی مثل تابع سیگموید داره اما با مقداری تفاوت که اون رو تبدیل به تابعی کارآمدتر و پر استفاده‌تر می‌کنه. گفتیم که تابع سیگموید چون خروجی‌ای بین 0 تا 1 داره برای مواردی که بخوایم احتمال یک دسته رو به دست بیاریم مورد مناسبیه، اما یک مشکلی برای این کار وجود داره. فرض کنیم که ما توی لایه آخر شبکه عصبی 5 خروجی داریم که به این صورت هستن 0.8، 0.9، 0.7، 0.8، و 0.6 آیا می‌تونید بگید این خروجی چه چیزی رو بهتون نشون می‌ده؟ نه! چون مشخص نیست که ما باید کدوم خروجی رو به عنوان جواب مسئله مون بپذیریم. ما می‌دونیم که مجموعه احتمالات فضای خروجی یک مسئله باید برابر با 1 بشه. اما توی مثال بالا اینطور نیست! تابع softmax رو می‌شه به شکل ترکیبی از چندین تابع سیگموید در نظر گرفت که در نهایت احتمال مرتبط با هر خروجی رو محاسبه می‌کنه و خروجی این تابع قابل فهم‌تره نسبت به تابع سیگموید. این تابع اکثرا در لایه آخر شبکه استفاده می‌شه و وظیفش هم این هستش که احتمال هر خروجی رو بهتون می‌ده طوری که مجموع احتمالات برابر با 1 باشه و شما بتونید از اون استفاده کنید. ضابطه تابع به شکل زیر هستش:تابع Softmax3. تابع فعال ساز Tanhاین تابع هم از لحاظ شکل مختصاتی بسیار شبیه به تابع سیگموید هستش با این تفاوت که خروجی تابع(بُرد تابع) توی بازه‌ی -1 تا 1 هستش. در تانژانت هایپربولیک یا تانژانت هذلولوی(Hyperbolic Tangent) هرچی ورودی بزرگتر(مثبت‌تر) باشه، خروجی خروجی بیشتر به 1 نزدیک می‎شه و برعکس هرچی خروجی کوچیکتر(منفی‌تر) باشه خروجی به -1 نزدیک می‌شه. توی شکل زیر گراف این تابع رو می‌تونید ببینید:تابع tanhضابطه‌ی تابع هم به شکل زیر درمیاد:تابع tanhمزایاخروجی تابع فعال ساز tanh نسبت به صفر مرکزیت داره، یعنی صفر در مرکز خروجی این تابع قرار داره. این ویژگی یک خاصیت به این تابع می‌ده که به کمک اون می‌تونیم مقادیر خروجی رو به خیلی منفی، صفر و خیلی مثبت تقسیم کنیم.بیشتر برای لایه‎‌های میانی و مخفی شبکه استفاده می‌شه. از اونجایی که خروجی اون بین -1 تا 1 هستش و معمولا میانه(mean) خروجی لایه مخفی نزدیک به 0 در میاد، کمک می‌کنه تا داده‌ها رو متمرکز و یادگیری رو برای لایه بعدی آسون‌تر کنهمعایبتوی توابعی که تا الان بررسی کردیم به مشتق اونها هم توجه ویژه‌ای داشتیم، بگذارید برای tanh هم این کار رو انجام بدیم. شکل زیر نمودار مشتق این تابع رو توی دستگاه مختصات نشون می‌ده:مشتق تابع tanhهمونطور که می‌بینید اینجا هم، مثل تابع سیگموید، مشکل ناپدید شدن گرادیان رو داریم. به علاوه شیب اون هم نسبت به شیب مشتق تابع سیگموید تندتره.اگر چه هر دو تابعِ سیگموید و tanh مشکل ناپدید شدن گرادیان رو دارن، اما چون tanh نسبت به صفر متقارن هستش و این باعث می‌شه که گرادیان اون به طور مشخص به سمت خاصی حرکت نکنه، به همین خاطر اکثرا در عمل از tanh استفاده می‎‌کنن.4. تابع فعال ساز ReLUاین تابع فعال ساز خیلی مهمه و براساس اون هم توابع فعال ساز زیادی به وجود اومدن. به همین خاطر پیشنهاد می‌کنم حواستون رو توی این یک مورد بیشتر جمع کنید. ReLU از سرواژه‌ی Rectified Linear Unit (واحد خطی تصحیح شده) تشکیل شده. اگر به شکل گرافش که توی تصویر زیر اومده دقت کنید حسِ یک تابع خطی رو به شما می‌ده. مشکل توابع خطی این بود که مشتقشون اعداد ثابت بودن به همین خاطر ما نمی‌تونستیم از اونها استفاده کنیم. اما تابع ReLU مشتق پذیره و می‌تونیم از اون برای پس انتشار استفاده کنیم و هزینه محاسباتی کمی هم برای ما داره، برای همین از خوبای توابع فعال ساز به حساب میاد. نکته اصلی توی تابع ReLU این هستش که این تابع فعال ساز تمام نورون‌ها رو فعال نمی‌کنه و فقط نورون‌هایی رو فعال می‌کنه که خروجی اونها بزرگتر از یک هستش(توی شکل زیر می‌تونید ببینید)تابع فعال ساز ReLUرابطه ریاضی اون به شکل زیر هستش:تابع فعال ساز ReLUمزایاچون فقط تعدادی از نورون‌ها فعال می‌شن، هزینه محاسباتی این تابع نسبت به توابع قبلی کمتر هستش. به همین خاطر توی خیلی از موارد مثل پردازش متن، پردازش تصویر و پردازش صوت از این تابع استفاده می‌شه.این تابع به خاطر ویژگی خطی که داره باعث تسریع عملیات کاهش گرادیان(gradient descent) برای پیدا کردن مقدار کمینه سراسری(global minimum) می‌شه.معایبایراد اصلی این تابع مشکلی هست به نام "مرگ ReLU". منظور از مرگ ReLU اینه که برخی از نورون‌های ReLU می‌میرن و غیرفعال می‌شن و برای تمامی ورودی‌ها، خروجی 0 می‌شه. در این حالت، هیچ گرادیانی جریان پیدا نمی‌کنه و در صورتی‌که تعداد نورون‌های غیرفعال در شبکه عصبی زیاد بشه، عملکرد مدل تحت تأثیر قرار می‌گیره.مشتق تابع ReLU5. تابع فعال ساز Leaky ReLUبرای رفع ایراد مرگ ReLU تابعی به اسم Leaky ReLU وجود داره که از مرگ نورون‌های با مقادیر منفی جلوگیری می‌کنه. شکل زیر رو ببینید.تابع فعال ساز Leaky ReLUضابطه تابع هم به شکل زیر هستش:تابع فعال ساز Leaky ReLUاین تابع تمام مزایای ReLU رو داره و مشکل مرگ نورون‌ها رو هم حل کرده. با این تغییر توی تابع ReLU دیگه برای مقادیر منفی گرادیان صفر نمی‌شه و می‌تونیم از اون برای مواردی که خروجی نورون منفی هست هم استفاده کنیم. شکل زیر مشتق تابع Leaky ReLU رو نشون میده.مشتق تابع فعال ساز Leaky ReLUمعایبممکنه پیش بینی‌ها با ورودی‌های منفی سازگار نباشن.گرادیان برای اعداد منفی مقدار کوچکی هستش که این می‌تونه هزینه یادگیری رو برای ما افزایش بده.6. تابع فعال ساز Parametric ReLUاین تابع هم یکی از انواع تابع ReLU هستش که برای حل مشکل مرگ نورون‌ها برای مقادیر منفی به وجود اومده(کلا این ReLU اینقدر خوبه که همه می‌خوان یه جوری کمکش کنن). این تابع برای قسمت منفی‌ها یک ضریب(شیب) در نظر گرفته به نام a. توی عملیات پس انتشار سعی می‌شه بهترین مقدار a یادگرفته بشه.نمودار تابع Parametric ReLUضابطه تابع هم به شکل زیر هستش:ضابطه تابع Parametric ReLUتوی تابع بالا a همون ضریب یا شیب برای مقادیر منفی هستش.اگر توی حل مسئله با استفاده از leaky ReLU موفق نبودیم، می‌تونیم از این تابع استفاده کنیم. عیب این تابع هم این هستش که به خاطر پارامتر a ممکنه برای مسائل مختلف، به شکل متفاوتی عمل کنه.7. تابع فعال ساز Exponential Linear Units (ELUs)این تابع هم برای حل مشکل مرگ نورون توی تابع ReLU به وجود اومده. این تابع هم مثل تابع قبلی تلاش می‌کنه تا یک شیب رو به قسمت منفی نسبت بده و با این کار از حذف نورون‌های منفی جلوگیری کنه. این تابع از یک خم لگاریتمی برای مشخص کردن قسمت منفی استفاده می‌کنه، برخلاف دو تابع قبلی که این کار رو با یک خط راست انجام داده بودن.تابع فعال ساز ELUضابطه تابع:ضابطه تابع فعال ساز ELU به دلایل زیر ELU یک جایگزین خیلی خوب برای ReLU هستش:این تابع به صورت خیلی آرام نرم می‌شه(خمی که توی نمودار هست) درصورتی که توی ReLU یک جهش یا یک زاویه داشتیم. با یک خم نرم و لگاریتمی از مرگ نورون‌ها هم جلوگیری می‌کنه. این به وزن‌ها و بایاس‌ها کمک می‌کنه تا در مسیر درست و با شیب درست حرکت کنن.نمودار مشتق تابع ELUضابطه مشتق تابع ELUمعایببه خاطر این که محاسبات نمایی توی خودش داره، هزینه محاسباتی بالایی دارهمشکل انفجار گرادیان رو داریم!8. تابع فعال ساز Swishاین تابع توسط محققین شرکت گوگل توسعه داده شده. این تابع عملکردی مشابه با ReLU رو توی شبکه‌های عمیق داره. swish کران پایین داره ولی از بالا نامحدوده. یعنی با نزدیک شدن X(مقادیر ورودی) به منفی بی‌نهایت، Yها یا خروجی‌های ما به یک مقدار نزدیک می‌شن. اما با نزدیک شدن X به مثبت بی‌نهایت، Y ها هم به مثبت بی‌نهایت نزدیک می‌شن. این قضیه توی گراف تابع قابل مشاهده است.نمودار تابع Swishضابطه تابع هم به شکل زیر هستش:ضابطه‌ی تابع Swish اندر مزایای این تابع باید براتون بگم که:مثل تابع ELU این تابع هم تغیرات نرمی رو حول صفر داره و برخلاف ReLU رفتار تندی توی اون ناحیه نداره.مقادیر منفی کوچک در ReLU صفر می‌شدند. در حالی که ممکن بود این مقادیر در استخراج و ثبت الگوها موثر باشند. از طرفی در Swish مقادیر منفی بزرگ به دلیل پخش شدگی صفر می‌شوند و این تابع یک عملکرد برد برد در قبال اعداد منفی دارد.خب اینم از این، همونطور که اول مطلب هم گفتم تعداد توابع فعال ساز زیاده و به مرور این مطلب تکمیل‌تر می‌شه. خیلی خوشحال می‌شم توی نظرات توابع دیگه رو هم معرفی کنید که به سراغ بررسی اونها هم برم یا اینکه اگر ویژگی‌ای جا مونده و ما بررسی نکردیم بگید که برای توابع بررسی کنیم. از تجربیات خودتون درمورد استفاده از انواع مختلف توابع فعال ساز توی کاربردها و معماری‌ها متفاوت بگید تا این تجربیات به دوستان دیگه هم منتقل بشه.مطالب مرتبط با این نوشته در وبلاگ من:آموزش نوشتن خودرمزنگار(Auto Encoder) برای بازسازی تصاویر به همراه سورس کدمنابع:لینک