پرسپترون چند لایه در پایتون — راهنمای کاربردی
حوزه «یادگیری ماشین» (Machine Learning)، در حال تبدیل شدن به یکی از حوزههای انقلابی و حیاتی در «علم داده» (Data Science) است. حوزه یادگیری ماشین و تکنیکهای موجود در آن، به محققان این حوزه اجازه میدهند تا بتوانند «روابط غیرخطی» (Non-Linear Relationships) میان «ویژگیها» (Features) را بیابند و از آنها، برای انجام پیشبینی در مورد «نمونههای» (Samples) جدید استفاده کنند. یکی از روشهای ساده یادگیری ماشین، «پرسپترون چند لایه» (Multi-Layer Perceptron) نام دارد.
در این مطلب، مفهوم «شبکههای عصبی مصنوعی» (Artificial Neural Networks) و به طور ویژه، شبکههای عصبی پرسپترون چند لایه مورد بررسی قرار میگیرد. همچنین، نحوه پیادهسازی شبکه عصبی پرسپترون چند لایه در «زبان برنامهنویسی پایتون» (Python Programming Language)، بدون استفاده از کتابخانه نرمافزاری محبوب SciKit-Learn نمایش داده میشود.
ساختن یک شبکه عصبی چند لایه از «پایه» (Scratch)، به کاربران و مخاطبان این مطلب اجازه میدهد که درک عمیقتری از نحوه عملکرد شبکههای عصبی در دستهبندی نمونهها پیدا کنند. همچنین، مخاطبان با ایدههایی نظیر «پس انتشار» (Backpropagation) و «پیشخور» (Feedforward)، که نقشی حیاتی در عملکرد شبکههای عصبی پرسپترون چند لایه دارند، آشنا خواهند شد.
شبکه پرسپترون تک لایه
پیش از اینکه شبکههای عصبی پرسپترون چند لایه مورد بررسی قرار گرفته شود، نوع سادهای از شبکههای عصبی بررسی خواهد شد؛ «شبکه عصبی پرسپترون تک لایه» (Single Layer Neural Network Perceptron). شبکه عصبی پرسپترون تک لایه، تعداد مشخصی داده ورودی یا (هر داده ورودی، تعداد ویژگی مشخص دارد) را به عنوان ورودی دریافت میکند.
در هر مرحله یکی از دادههای ورودی وارد شبکه عصبی میشود. با داشتن مجموعهای از وزنها () و مقدار «بایاس» (Bias)، شبکه عصبی پرسپترون تک لایه، خروجی متناسب با داده ورودی و وزنها تولید میکند. به دادههای ورودی به شبکه عصبی پرسپترون تک لایه، در مرحله آموزش شبکه، دادههای آموزشی گفته میشود.
خروجی تولید شده وارد یک تابع خاص میشود. به این تابع، «تابع انتقال» (Transfer Function) یا «تابع فعالسازی» (Activation Function) گفته میشود. این تابع، در صورتی که مقدار خروجی تولید شده بیشتر از صفر باشد، مقدار 1 تولید میکند و در صورتی که خروجی تولید شده کمتر از صفر باشد، مقدار 1- توسط تابع تولید خواهد شد. در این دسته از مدلهای شبکه عصبی، یادگیری زمانی اتفاق میافتد که مقدار «باینری» (Binary) تولید شده توسط تابع، با «خروجی مورد انتظار» (Expected Output) دادههای آموزشی مقایسه میشود.
در مرحله بعد، اختلاف میان مقادیر تولید شده توسط تابع و خروجی مورد انتظار دادههای آموزشی، در مقدار داده ورودی و یک «نرخ یادگیری» (Learning Rate) ضرب میشود. مقدار حاصل با مقدار وزن جمع میشود؛ در این رابطه، وزن، نقش تصحیح کننده را در مدل شبکه عصبی بر عهده دارد. به بیان سادهتر، شبکه عصبی پرسپترون تک لایه، یک دستهبند خطی است؛ یعنی، دستهبندی که دادههای ورودی را با استفاده از یک «خط جداکننده» (Seperating Line)، به دو گروه دستهبندی میکند.
در این رابطه، مقدار نرخ یادگیری (عددی مثبت)، مقدار خروجی مورد انتظار برای ورودی و خروجی تولید شده برای ورودی مسأله است. نکته مهم در مورد این رابطه این است که در صورتی که مقدار خروجی مورد انتظار با خروجی تولید شده شبکه برابر باشد، تغییری در وزنها صورت نمیگیرد. ایده توضیح داده شده در این بخش، «پس انتشار خطا» (Error Backpropagation) نام دارد و الگوریتم اصلی یادگیری در شبکه عصبی پرسپترون تک لایه محسوب میشود. البته، ایده انتشار خطا در شبکه عصبی پرسپترون تک لایه، بسیار ابتدایی است.
در ادامه و در هنگام معرفی شبکههای عصبی پرسپترون چند لایه، نسخه پیشرفتهتری از الگوریتم یادگیری پس انتشار خطا، برای آموزش این شبکه معرفی خواهد شد. شبکه عصبی پرسپترون تک لایه، به راحتی و با استفاده از عملیات ماتریسی بسیار بهینه بسته نرمافزاری numpy در پایتون، قابل پیادهسازی خواهد بود. کد زیر، برای پیادهسازی شبکه عصبی پرسپترون تک لایه مورد استفاده قرار میگیرد.
1import numpy as np
2class Perceptron(object):
3def __init__(self, learn, itr):
4 """
5 :param learn: learning rate
6 :type learn: float
7 :param itr: number of iterations
8 :type itr: integer
9 """
10 self.learn = learn
11 self.itr = itr
12def train(self, x, y):
13 """
14 Train the weights with data set x for outputs y
15 :param x: training data features
16 :type x: array (matrix) of n-samples, n-features
17 :param y: training data outputs
18 :type y: array of n-samples
19 :return: weights (w) and errors for each iteration
20 """
21 self.w = np.zeros(1 + x.shape[1])
22 self.error = []
23 for _ in range(self.itr):
24 errors = 0
25 for xi, target in zip(x, y):
26 update = self.learn*(target - self.predict(xi))
27 self.w[1:] += update*xi
28 self.w[0] += update
29 errors += int(update != 0)
30 self.error.append(errors)
31 return self
32def predict(self, x):
33 """
34 :param x: input vector of features
35 :type x: ndarray
36 :return: int 1 or -1
37 """
38 self.output = np.dot(x, self.w[1:]) + self.w[0]
39 return np.where(self.output >= 0, 1, -1)
تا اینجا، نحوه عملکرد شبکههای عصبی پرسپترون تک لایه شرح و پیادهسازی آن در پایتون ارائه شده است. در ادامه، معماری شبکههای عصبی پرسپترون چند لایه و نحوه یادگیری در این شبکه مورد بررسی قرار میگیرد.
شبکههای عصبی پرسپترون چند لایه
شبکه عصبی پرسپترون چند لایه، دستهای از شبکههای عصبی مصنوعی پیشخور محسوب میشوند. در بخش بعد، با مفهوم پیشخور در این شبکه عصبی آشنا خواهید شد.
در یک شبکه عصبی پرسپترون چند لایه، حداقل سه «لایه» (Layer) از «نودها» (Nodes) وجود خواهند داشت:
- یک «لایه ورودی» (Input Layer)
- یک «لایه نهان» (Hidden Layer)
- یک «لایه خروجی» (Output layer)
نودهای شبکه عصبی که به آنها «نرون» (Neuron) نیز گفته میشود، واحدهای محاسباتی در یک شبکه عصبی محسوب میشوند. در این شبکه عصبی، از خروجیهای لایه اول (ورودی)، به عنوان ورودیهای لایه بعدی (نهان) استفاده میشود؛ این کار به همین شکل ادامه پیدا میکند، تا زمانی که، پس از تعداد خاصی از لایهها، خروجیهای آخرین لایه نهان به عنوان ورودیهای لایه خروجی مورد استفاده قرار میگیرد. به لایههایی که بین لایه ورودی و لایه خروجی قرار میگیرند، «لایههای نهان» (Hidden Layers) گفته میشود. شبکههای پرسپترون چند لایه، مانند شبکههای عصبی پرسپترون تک لایه، حاوی مجموعهای از وزنها نیز هستند که باید برای آموزش و یادگیری شبکه عصبی تنظیم شوند.
الگوریتم پیشخور
اولین بخش در پیادهسازی یک شبکه عصبی پرسپترون چند لایه، توسعه الگوریتم پیشخور است. الگوریتم پیشخور، فرآیندی را کنترل میکند که در نتیجه آن، ورودیهای مسأله به یک خروجی تبدیل میشوند. با این حال، فرآیند پیشخور در شبکه پرسپترون چند لایه، به سادگی شبکههای پرسپترون تک لایه نیست.
در فرآیند پیشخور در شبکه پرسپترون چند لایه، عملیات تعریف شده در الگوریتم، در تمامی لایههای تعریف شده در شبکه انجام میشود. در این فرایند، خروجی هر لایه به عنوان ورودی لایه بعدی تعریف میشود. برای مشخص کردن خروجی هر لایه، از رابطهای شبیه به رابطه زیر استفاده میشود. این فرایند، تا زمانی ادامه پیدا میکند که خروجی لایه آخر شبکه (لایه خروجی) تولید شود. خروجی هر کدام از نودهای موجود در هر یک از لایههای شبکه عصبی پرسپترون چند لایه، از طریق روابط زیر تولید میشود.
با استفاده از عملیات ماتریسی بسته نرمافزاری numpy در پایتون، میتوان مرحله پیشخور در یک شبکه عصبی پرسپترون چند لایه را پیادهسازی کرد.
1def feedforward(self, x):
2 """
3 Predict the output given the inputs
4 :param x: input vector of features
5 :type x: ndarray
6 :return: All activation values and x values.
7 """
8 self.z0 = np.dot(self.w0, x)
9 self.output1 = self.sigmoid(self.z0)
10 self.z1 = np.matmul(self.w1, self.output1)
11 self.output2 = self.sigmoid(self.z1)
12 self.z2 = np.matmul(self.w2, self.output2)
13 self.output3 = self.sigmoid(self.z2)
14return self.z0, self.output1, self.z1, self.output2, self.z2, self.output3
محاسبه خطای شبکه با استفاده از تابع زیان
وقتی که یک نمونه آموزشی، به عنوان ورودی وارد سیستم میشود، در لایه آخر، یک خروجی به ازاء ورودی و وزنها تولید میشود. به عبارت دیگر، ورودی مسأله به یک خروجی تبدیل میشود. همان طور که پیش از این اشاره شد، خروجی هر لایه به عنوان ورودی لایه بعد تعریف میشود. این فرایند، تا زمانی که خروجی در لایه آخر تولید شود، ادامه پیدا میکند. به خروجی در لایه آخر، «خروجی پیشبینی شده» (Predicted Output) گفته میشود. در تمامی «الگوریتمهای یادگیری نظارت شده» (Supervised Learning)، خروجی واقعی دادههای آموزشی از پیش مشخص شده است. به این خروجیها، «خروجی مورد انتظار» (Expected Output) نیز گفته میشود.
از خروجیهای مورد انتظار برای سنجش عملکرد سیستم شبکه عصبی استفاده میشود. بر اساس مقادیر خروجی مورد انتظار و خروجی پیشبینی شده، مقدار «زیان» (Loss) شبکه عصبی پرسپترون چند لایه محاسبه میشود. از مقدار زیان محاسبه شده، برای پس انتشار خطا در شبکه پرسپترون و به روز رسانی وزنها استفاده میشود.
الگوریتم پس انتشار خطا
پس از معرفی مراحل پیشخور و محاسبه خطا در شبکه عصبی پرسپترون چند لایه، وقت آن فرا رسیده است تا مهمترین الگوریتم موجود در این شبکه عصبی را مورد بررسی قرار دهیم. پس از محاسبه مقدار زیان در مرحله قبل، این مقدار به صورت معکوس (از لایه خروجی به سمت لایه اول) در شبکه انتشار مییابد و با استفاده از مفهوم «گرادیان» (Gradient) یا شیب، وزنهای شبکه عصبی پرسپترون چند لایه به روز رسانی میشوند.
این بخش، مهمترین بخش الگوریتم پس انتشار در آموزش شبکه عصبی پرسپترون چند لایه محسوب میشود. مراحل یادگیری با استفاده از الگوریتم پس انتشار خطا در شبکه عصبی پرسپترون چند لایه به شرح زیر است:
- با فرض داشتن تعداد نود لایه نهان و یک نمونه ورودی با تعداد ویژگی در یک شبکه عصبی پرسپترون چند لایه، خروجی نودهای لایه آخر (لایه خروجی)، از طریق رابطه زیر مشخص میشوند.در این رابطه، ، خروجی نود اُم هر کدام از لایههای نهان را نشان میدهد.
- در مرحله بعد، با توجه به مقادیر خروجی مورد انتظار و خروجی پیشبینی شده برای هر کدام از نودهای لایه خروجی ()، مقدار «دلتا» (Delta) برای هر کدام از نودها، توسط رابطه زیر محاسبه میشود. در این رابطه، خروجی مورد انتظار نود در لایه خروجی و ، خروجی پیشبینی شده توسط نود در لایه خروجی است.
- برای هر کدام از نودهای لایه نهان ()، مقدار دلتا از طریق رابطه زیر محاسبه میشود.
- برای تنظیم کردن وزنهای تمامی نودها در شبکه عصبی پرسپترون چند لایه، از روش «گرادیان کاهشی» (Gradient Descent) استفاده میشود. در این روش، وزنهای تمامی نودها از طریق رابطه عمومی زیر تنظیم میشوند.
- به طور خاص، برای تنظیم وزن نود از لایه نهان (از نود لایه ورودی به سمت نود لایه نهان)، از رابطه زیر استفاده میشود. در این رابطه، مقدار نود لایه ورودی را نشان میدهد.
- همچنین، برای تنظیم وزن نود از لایه خروجی (از نود لایه نهان به سمت نود لایه خروجی)، از رابطه زیر استفاده میشود. در این رابطه، مقدار خروجی نود لایه نهان را نشان میدهد.
در روابط نمایش داده شده، نرخ یادگیری شبکه عصبی پرسپترون چند لایه است؛ اَبَرپارامتری که برای تنظیمِ نرخ تغییراتِ وزنهای شبکه عصبی مورد استفاده قرار میگیرد. معمولا در ابتدای کار شبکه عصبی پرسپترون چند لایه، مقدار کوچکی برای این اَبَرپارامتر در نظر گرفته میشود. با این حال، توصیه میشود که در طی فرایند یادگیری و با افزایش تعداد تکرارهای این شبکه، به تدریج مقدار این اَبَرپارامتر افزایش پیدا کند. از کدهای زیر، برای پیادهسازی الگوریتم پس انتشار خطا در شبکه عصبی پرسپترون چند لایه استفاده میشود.
1for _ in range(self.itr):
2 for xi, target in zip(self.x, self.y):
3 self.feedforward(xi)
4 cost = target.T - self.output3
5for i in range(self.w2.shape[0]):
6 self.w2[i] += -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * \ self.output2[i]
7for i in range(self.w1.shape[0]):
8 for j in range(self.w1.shape[1]):
9 self.w1[i, j] += -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * self.w2[i] * \
10self.sigmoid(self.z1[i]) * (1 - self.sigmoid(self.z1[i])) * \ self.output1[j]
11for i in range(self.w0.shape[0]):
12 for j in range(self.w0.shape[1]):
13 self.w0[i, j] += -self.learn * cost.sum() * \ self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2)) * self.w2[i] * \
14self.sigmoid(self.z1[i]) * (1 - self.sigmoid(self.z1[i])) * \ self.w1[i, j] * self.sigmoid(self.z0[i]) * (1 - \ self.sigmoid(self.z0[i])) * xi[j]
جمعبندی
اگرچه شبکه عصبی پرسپترون چند لایه جزء پیشرفتهترین و پیچیدهترین شبکههای عصبی مصنوعی به حساب نمیآید، با این حال، روشی بسیار مفید برای درک بهتر نحوه یادگیری در شبکههای عصبی مصنوعی محسوب میشود. کدهای ارائه شده در این مطلب، بدون استفاده از کتابخانههای نرمافزاری قدرتمند در پایتون نظیر Keras و Scikit-Learn پیادهسازی شدهاند.
در نتیجه، نسبت به شبکههای عصبی پیادهسازی شده در این دسته از کتابخانههای پایتون، بهینه نیستند. نوشتن کدهای یک مدل یادگیری از پایه و بدون استفاده از کتابخانههای نرمافزاری از پیش تعریف شده، درک برنامهنویسان مبتدی را از نحوه یادگیری در آن افزایش میدهد.
اگر نوشته بالا برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای دادهکاوی و یادگیری ماشین
- آموزش اصول و روشهای دادهکاوی (Data Mining)
- مجموعه آموزشهای هوش مصنوعی
- برترین الگوریتمهای پیشبینی در یادگیری ماشین (Machine Learning)
- پیشبینی قیمت بیت کوین با شبکه عصبی — راهنمای کاربردی
- نقشه دانش فناوریهای هوش مصنوعی و دسته بندی آنها — راهنمای جامع
^^
روش ارتباط با شمارو میخواستم ..
با سلام؛
در با مراجعه به بالای صفحه مجله میتوانید به لینک «تماس با ما» دسترسی داشته باشید.
با تشکر از همراهی شما با مجله فرادرس