MLP، پسانتشار و معماریهای رگرسیون و طبقهبندی شبکه عصبی
در رابطهٔ خروجی لایهٔ کاملاً متصل، ماتریس X شامل ویژگیهای ورودی است؛ هر سطر یک نمونه و هر ستون یک ویژگی را نمایش میدهد. ماتریس وزن W همهٔ وزنهای اتصال را در خود دارد؛ هر سطر آن متناظر با یک ورودی و هر ستون متناظر با یک نورون است. بردار b شامل جملههای بایاس است، یعنی برای هر نورون یک بایاس. تابع ϕ نیز تابع فعالسازی نام دارد؛ وقتی نورونهای مصنوعی از نوع TLU باشند، این تابع همان تابع پلهای است.
آموزش پرسپترون و قانون هب
الگوریتم آموزشی پرسپترون که روزنبلات پیشنهاد کرد، تا حد زیادی از قانون هب الهام گرفته بود. دونالد هب در کتاب The Organization of Behavior در سال ۱۹۴۹ پیشنهاد کرد وقتی یک نورون زیستی بارها نورون دیگری را تحریک میکند، اتصال بین آن دو قویتر میشود. این ایده بعدها با عبارت معروف «سلولهایی که با هم شلیک میکنند، با هم سیمکشی میشوند» خلاصه شد و به «قانون هب» یا «یادگیری هبی» معروف شد.
پرسپترون از گونهای از این قانون استفاده میکند که خطای پیشبینی شبکه را نیز در نظر میگیرد. نمونههای آموزشی یکییکی به شبکه داده میشوند. شبکه برای هر نمونه پیشبینی میکند و هر نورون خروجی که پاسخ نادرست داده باشد، وزن اتصالهایی تقویت میشود که میتوانستند آن نورون را به پاسخ صحیح نزدیک کنند. قانون بهروزرسانی وزن چنین است:
wi,j(next) = wi,j + η (yj − ŷj) xi
- wi,j وزن اتصال بین ورودی i و نورون j است.
- xi مقدار ورودی i برای نمونهٔ آموزشی جاری است.
- ŷj خروجی فعلی نورون j و yj خروجی هدف آن است.
- η نرخ یادگیری است.
مرز تصمیم هر نورون خروجی خطی است؛ بنابراین پرسپترونها مانند رگرسیون لجستیک قادر به یادگیری الگوهای پیچیده نیستند. با این حال، اگر دادهها جداییپذیر خطی باشند، الگوریتم پرسپترون به یک راهحل همگرا میشود؛ نتیجهای که به «قضیهٔ همگرایی پرسپترون» معروف است. این راهحل یکتا نیست، زیرا برای دادههای جداییپذیر خطی بینهایت ابرصفحهٔ جداکننده وجود دارد.
Scikit-Learn کلاس Perceptron را ارائه میکند. نمونهٔ زیر پرسپترون را برای تشخیص گونهٔ Iris setosa بر اساس طول و عرض گلبرگ آموزش میدهد:
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
iris = load_iris(as_frame=True)
X = iris.data[["petal length (cm)", "petal width (cm)"]].values
y = (iris.target == 0) # Iris setosa
per_clf = Perceptron(random_state=42)
per_clf.fit(X, y)
X_new = [[2, 0.5], [3, 1]]
y_pred = per_clf.predict(X_new) # predicts True and False for these 2 flowers
الگوریتم یادگیری پرسپترون شباهت زیادی به گرادیان کاهشی تصادفی دارد. در Scikit-Learn، کلاس Perceptron عملاً با SGDClassifier و تنظیمات loss="perceptron"، learning_rate="constant"، eta0=1 و penalty=None معادل است.
ماروین مینسکی و سیمور پاپرت در کتاب Perceptrons در سال ۱۹۶۹ چند ضعف مهم این مدل را برجسته کردند؛ از جمله ناتوانی آن در حل مسئلهٔ سادهٔ XOR. البته همهٔ طبقهبندهای خطی چنین محدودیتی دارند، اما انتظارات از پرسپترونها بسیار بیشتر بود و همین موضوع بخشی از جامعهٔ پژوهشی را از شبکههای عصبی دور کرد.
بعضی محدودیتهای پرسپترون را میتوان با رویهمگذاشتن چند پرسپترون برطرف کرد. شبکهٔ حاصل «پرسپترون چندلایه» یا MLP نام دارد. یک MLP میتواند مسئلهٔ XOR را حل کند: برای ورودیهای (0,0) و (1,1) خروجی صفر و برای (0,1) و (1,0) خروجی یک میشود.
شکل ۱۰-۶. مسئلهٔ طبقهبندی XOR و یک MLP که آن را حل میکند
پرسپترون چندلایه و پسانتشار
یک MLP از یک لایهٔ ورودی، یک یا چند لایهٔ TLU به نام «لایههای پنهان» و یک لایهٔ نهایی TLU به نام «لایهٔ خروجی» تشکیل میشود. لایههای نزدیک ورودی معمولاً لایههای پایین و لایههای نزدیک خروجی لایههای بالا نامیده میشوند.
شکل ۱۰-۷. معماری یک MLP با دو ورودی، یک لایهٔ پنهان چهارنورونی و سه نورون خروجی
اگر شبکهٔ عصبی دارای پشتهای عمیق از لایههای پنهان باشد، به آن «شبکهٔ عصبی عمیق» یا DNN گفته میشود. یادگیری عمیق عمدتاً DNNها و بهطور کلی مدلهایی با پشتهٔ عمیق از محاسبات را مطالعه میکند. مرز دقیقی برای واژهٔ «عمیق» وجود ندارد؛ چیزی که در دههٔ ۱۹۹۰ شبکهای عمیق محسوب میشد، امروز ممکن است بسیار کمعمق تلقی شود.
برای سالهای طولانی، پژوهشگران روش مؤثری برای آموزش MLPها در اختیار نداشتند. استفاده از گرادیان کاهشی مطرح شده بود، اما محاسبهٔ گرادیان خطای شبکه نسبت به تعداد بسیار زیادی پارامتر، با توان پردازشی آن دوران کار سادهای نبود. در سال ۱۹۷۰، سپو لیناینما در پایاننامهٔ کارشناسیارشد خود روشی برای محاسبهٔ خودکار و کارآمد همهٔ گرادیانها معرفی کرد که امروزه «مشتقگیری خودکار حالت معکوس» یا Reverse-Mode Autodiff نامیده میشود.
این الگوریتم تنها با دو گذر از شبکه، یکی رو به جلو و دیگری رو به عقب، میتواند گرادیان خطای شبکه را نسبت به تکتک پارامترها محاسبه کند. به بیان دیگر مشخص میکند هر وزن اتصال و هر بایاس باید در چه جهتی تغییر کند تا خطا کم شود. سپس از این گرادیانها یک گام گرادیان کاهشی ساخته میشود. تکرار این فرایند، خطا را بهتدریج تا رسیدن به یک کمینه کاهش میدهد. ترکیب مشتقگیری خودکار معکوس با گرادیان کاهشی همان چیزی است که امروز «پسانتشار» یا Backpropagation نامیده میشود.
پسانتشار فقط مخصوص شبکههای عصبی نیست و روی انواع گرافهای محاسباتی قابل استفاده است. پایاننامهٔ لیناینما نیز موضوعی عمومیتر از شبکهٔ عصبی داشت. چند سال بعد استفاده از آن برای آموزش شبکههای عصبی جدی شد و در سال ۱۹۸۵ مقالهٔ مهم دیوید راملهارت، جفری هینتون و رونالد ویلیامز نشان داد چگونه پسانتشار به شبکه اجازه میدهد بازنماییهای داخلی مفید را یاد بگیرد. نتایج آن پژوهش باعث فراگیرشدن سریع این روش شد و امروز پسانتشار رایجترین روش آموزش شبکههای عصبی است.
پسانتشار چگونه کار میکند؟
- الگوریتم هر بار یک Mini-batch، مثلاً شامل ۳۲ نمونه، را پردازش میکند و مجموعهٔ آموزشی را چندین بار میپیماید. هر پیمایش کامل یک Epoch نام دارد.
- Mini-batch از لایهٔ ورودی وارد شبکه میشود. خروجی تمام نورونهای نخستین لایهٔ پنهان برای همهٔ نمونهها محاسبه میشود، سپس نتیجه به لایهٔ بعد میرود و این روند تا لایهٔ خروجی ادامه پیدا میکند. این مرحله «گذر رو به جلو» است. همهٔ نتایج میانی نگه داشته میشوند، زیرا در گذر معکوس لازم خواهند بود.
- سپس الگوریتم خطای خروجی را با یک تابع Loss که خروجی واقعی شبکه را با خروجی مطلوب مقایسه میکند اندازه میگیرد.
- با استفاده از قاعدهٔ زنجیرهای، مشخص میشود هر بایاس خروجی و هر اتصال به لایهٔ خروجی چه سهمی در خطا داشته است.
- همین محاسبه لایهبهلایه در جهت معکوس ادامه مییابد تا سهم خطا و گرادیان مربوط به همهٔ وزنها و بایاسها محاسبه شود. به همین دلیل نام الگوریتم «پسانتشار» است.
- در پایان، یک گام گرادیان کاهشی با استفاده از گرادیانهای محاسبهشده اجرا و همهٔ وزنها و بایاسها اصلاح میشوند.
خلاصه اینکه پسانتشار برای یک Mini-batch پیشبینی میکند، خطا را میسنجد، در جهت معکوس سهم هر پارامتر را در خطا محاسبه میکند و سپس با گرادیان کاهشی وزنها و بایاسها را برای کاهش خطا تنظیم میکند.
تابعهای فعالسازی غیرخطی
برای اینکه پسانتشار بهدرستی کار کند، راملهارت و همکارانش یک تغییر مهم در MLP ایجاد کردند: تابع پلهای را با تابع لجستیک یا Sigmoid جایگزین کردند:
σ(z) = 1 / (1 + exp(−z))
تابع پلهای تقریباً همهجا بخشهای تخت دارد و بنابراین گرادیان مفیدی در اختیار گرادیان کاهشی نمیگذارد. در مقابل، Sigmoid مشتقی مشخص و غیرصفر دارد و به الگوریتم اجازه میدهد در هر گام پیشرفت کند. پسانتشار البته با فعالسازیهای دیگری هم خوب کار میکند. دو انتخاب مهم عبارتاند از:
- تانژانت هذلولوی
- tanh(z) = 2σ(2z) − 1. این تابع نیز Sشکل، پیوسته و مشتقپذیر است، اما خروجی آن در بازهٔ منفی یک تا یک قرار دارد. این بازه در ابتدای آموزش خروجی هر لایه را تقریباً حول صفر متمرکز میکند و اغلب همگرایی را سریعتر میسازد.
- واحد خطی یکسوشده یا ReLU
- ReLU(z) = max(0, z). این تابع پیوسته است اما در صفر مشتقپذیر نیست و برای مقادیر منفی مشتق صفر دارد. با این وجود در عمل بسیار خوب عمل میکند و محاسبهٔ آن سریع است، بنابراین به انتخاب پیشفرض رایجی تبدیل شده است. نامحدودبودن خروجی مثبت آن نیز بعضی مشکلات گرادیان کاهشی را کاهش میدهد.
شکل ۱۰-۸. تابعهای فعالسازی پرکاربرد در سمت چپ و مشتقهای آنها در سمت راست
وجود غیرخطیبودن بین لایهها ضروری است. اگر چند تبدیل خطی را پشت سر هم قرار دهید، نتیجه همچنان یک تبدیل خطی خواهد بود. برای نمونه اگر f(x)=2x+3 و g(x)=5x−1 باشند، ترکیب آنها f(g(x))=10x+1 است. بنابراین بدون فعالسازی غیرخطی، حتی یک پشتهٔ عمیق از لایهها معادل یک لایه خواهد بود و قدرت حل مسائل پیچیده را ندارد. در مقابل، یک DNN بهاندازهٔ کافی بزرگ با فعالسازیهای غیرخطی از نظر نظری میتواند هر تابع پیوستهای را با دقت دلخواه تقریب بزند.
MLP برای رگرسیون
MLPها را میتوان برای مسائل رگرسیون نیز بهکار برد. اگر هدف پیشبینی یک مقدار باشد، مثلاً قیمت خانه از روی مجموعهای از ویژگیها، یک نورون خروجی کافی است. در رگرسیون چندمتغیره، برای هر بُعد خروجی یک نورون نیاز دارید. برای مثال، تعیین مرکز یک شیء در تصویر به دو مختصه و در نتیجه دو نورون خروجی نیاز دارد؛ و اگر بخواهیم جعبهٔ مرزی شیء را نیز پیشبینی کنیم، عرض و ارتفاع هم لازم میشود و تعداد خروجیها به چهار میرسد.
Scikit-Learn کلاس MLPRegressor را فراهم میکند. مثال زیر شبکهای با سه لایهٔ پنهان و ۵۰ نورون در هر لایه را روی دادهٔ مسکن کالیفرنیا آموزش میدهد. ویژگیها پیش از ورود به شبکه استاندارد میشوند، زیرا گرادیان کاهشی در حضور مقیاسهای بسیار متفاوت ویژگیها بهخوبی همگرا نمیشود.
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
housing = fetch_california_housing()
X_train_full, X_test, y_train_full, y_test = train_test_split(
housing.data, housing.target, random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(
X_train_full, y_train_full, random_state=42)
mlp_reg = MLPRegressor(hidden_layer_sizes=[50, 50, 50], random_state=42)
pipeline = make_pipeline(StandardScaler(), mlp_reg)
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_valid)
rmse = mean_squared_error(y_valid, y_pred, squared=False) # about 0.505
RMSE اعتبارسنجی در این مثال حدود 0.505 است. لایهٔ خروجی این MLP تابع فعالسازی ندارد و بنابراین میتواند هر مقدار حقیقی را تولید کند. برای تضمین خروجی مثبت میتوان از ReLU یا Softplus استفاده کرد. تابع Softplus یعنی log(1 + exp(z)) برای مقادیر منفی به صفر نزدیک است و برای مقادیر مثبت به خود z نزدیک میشود. برای محدودکردن خروجی به یک بازهٔ مشخص نیز میتوان از Sigmoid یا tanh و مقیاسدهی مناسب هدف استفاده کرد. کلاس MLPRegressor Scikit-Learn امکان انتخاب فعالسازی لایهٔ خروجی را نمیدهد.
MLPRegressor از میانگین مربع خطا استفاده میکند. در دادههای دارای Outlier زیاد، میانگین قدرمطلق خطا میتواند مناسبتر باشد. Loss هوبر نیز ترکیبی از این دو است: برای خطاهای کوچک رفتار درجهدوم و برای خطاهای بزرگ رفتار خطی دارد و در نتیجه نسبت به Outlierها مقاومتر است. با این حال، MLPRegressor از MSE استفاده میکند.
جدول ۱۰-۱. معماری معمول یک MLP برای رگرسیون| ابرپارامتر | مقدار معمول |
| تعداد لایههای پنهان | بسته به مسئله، معمولاً ۱ تا ۵ |
| نورونهای هر لایهٔ پنهان | بسته به مسئله، معمولاً ۱۰ تا ۱۰۰ |
| نورونهای خروجی | برای هر بُعد پیشبینی یک نورون |
| فعالسازی پنهان | ReLU |
| فعالسازی خروجی | بدون فعالسازی؛ یا ReLU/Softplus برای خروجی مثبت؛ یا Sigmoid/tanh برای خروجی کراندار |
| تابع Loss | MSE؛ یا Huber در حضور Outlier |
MLP برای طبقهبندی
MLPها برای طبقهبندی نیز مناسباند. در طبقهبندی دودویی فقط یک نورون خروجی با فعالسازی Sigmoid لازم است. خروجی عددی بین صفر و یک است و میتوان آن را احتمال تخمینی کلاس مثبت در نظر گرفت؛ احتمال کلاس منفی برابر یک منهای این مقدار است.
برای طبقهبندی چندبرچسبی دودویی، به ازای هر برچسب مثبت یک نورون خروجی Sigmoid در نظر میگیریم. مثلاً سامانهای که برای هر ایمیل هم Spam بودن و هم فوریبودن را پیشبینی میکند، دو نورون خروجی دارد. مجموع این احتمالها لازم نیست یک باشد، زیرا برچسبها مستقلاند.
اگر هر نمونه دقیقاً متعلق به یکی از سه کلاس یا بیشتر باشد، برای هر کلاس یک نورون خروجی لازم است و کل لایهٔ خروجی باید از تابع Softmax استفاده کند. Softmax تمام احتمالها را بین صفر و یک نگه میدارد و مجموع آنها را برابر یک میکند. برای چنین مسائل احتمالاتی، Loss آنتروپی متقاطع معمولاً انتخاب مناسبی است.
شکل ۱۰-۹. یک MLP مدرن برای طبقهبندی با فعالسازی ReLU در لایههای پنهان و Softmax در خروجی
Scikit-Learn در بستهٔ sklearn.neural_network کلاس MLPClassifier را نیز دارد. رفتار آن بسیار شبیه MLPRegressor است، با این تفاوت که بهجای MSE آنتروپی متقاطع را کمینه میکند.
جدول ۱۰-۲. معماری معمول MLP برای طبقهبندی| ابرپارامتر | طبقهبندی دودویی | چندبرچسبی دودویی | چندکلاسه |
| لایههای پنهان | معمولاً ۱ تا ۵ لایه، بسته به مسئله |
| نورونهای خروجی | ۱ | برای هر برچسب دودویی یک نورون | برای هر کلاس یک نورون |
| فعالسازی خروجی | Sigmoid | Sigmoid | Softmax |
| تابع Loss | Cross-Entropy | Cross-Entropy | Cross-Entropy |
این ترجمه برای استفادهٔ آموزشی تهیه شده است. انتشار عمومی، فروش یا بازنشر آن باید با رعایت حقوق مؤلف و ناشر و اخذ مجوزهای لازم انجام شود.