در این مطلب، یک پروژه یادگیری عمیق با پایتون انجام و توضیحات مربوط به آن، همراه با کدهای مورد استفاده، به طور کامل ارائه شده است. «کِرَس» (Keras) یک کتابخانه قدرتمند و با کاربری آسان در «زبان برنامه‌نویسی پایتون» (Python Programming Language) برای توسعه و ارزیابی «مدل‌های یادگیری عمیق» (Deep Learning Models) است. کرس، کتابخانه‌های یادگیری ماشین عددی «ثینو» (Theano) و «تنسورفلو» (TensorFlow) را پوشش می‌دهد و به کاربر این امکان را می‌دهد تا مدل‌های «شبکه عصبی مصنوعی» (Artificial Neural Network) را تنها با چند خط کد تعریف کند و آموزش دهد. در این مطلب، روش ساخت یک مدل شبکه عصبی یادگیری عمیق در پایتون با استفاده از کتابخانه کرس (Keras) آموزش داده شده است.

پروژه یادگیری عمیق با پایتون

کدهای زیادی برای پیاده‌سازی یک پروژه یادگیری عمیق با پایتون نیاز نیست. مراحل لازم برای این کار در ادامه به صورت مرحله به مرحله پیاده‌سازی و انجام شده‌اند و هر بخش از کار به طور کامل شرح داده شده است. مخاطبان می‌توانند همراه با این مطلب، مدل خودشان را بسازند. مراحلی که در این مطلب انجام و پوشش داده می‌شوند، در ادامه بیان شده‌اند.

مراحلی که در این مطلب انجام می‌شوند، نیاز به پیش‌نیازهایی دارند که در زیر آورده شده است.

  • پایتون ۲ یا ۳ روی سیستم کاربر نصب و پیکربندی شده باشد.
  • کتابخانه «سای‌پای» (SciPy) شامل «نام‌پای» (NumPy) نصب و پیکربندی شده باشد.
  • کرس و بک‌اند آن یعنی ثینو یا «تنسورفلو» (TensorFlow) نصب و پیکربندی شده باشد.

اکنون، فایل جدیدی با عنوان keras_first_network.py ساخته می‌شود. سپس، کدها در ادامه کار نوشته و با کپی-پیست کردن به این فایل اضافه می‌شوند.

بارگذاری داده‌ها

اولین گام برای انجام پروژه یادگیری عمیق در پایتون، تعریف توابع و کلاس‌هایی است که در این راهنما مورد استفاده قرار خواهند گرفت. از کتابخانه نام‌پای برای بارگذاری مجموعه داده استفاده می‌شود. همچنین، از دو کلاس کتابخانه کرس برای تعریف مدل استفاده خواهد شد. «ایمپورت‌های» (Imports) مورد نیاز در ادامه لیست شده‌اند.

اکنون می‌توان کتابخانه را بارگذاری کرد. در این راهنمای کرس، از مجموعه داده بیماران مبتلا به دیابت «پیما ایندینز» (Pima Indians) استفاده خواهد شد.  Pima Indians یک مجموعه داده استاندارد یادگیری ماشین از مخزن یادگیری ماشین UCI است. این مجموعه داده، حاوی داده‌های سوابق پزشکی بیماران برای Pima Indians طی مدت پنج سال است. مساله‌ای که در اینجا حل خواهد شد، یک مسئله «دسته‌بندی دودویی» (Binary Classification) است. در این مجموعه داده، برای افراد مبتلا «۱» و برای افراد سالم «۰» ثبت شده است. این صفر و یک‌ها در واقع «برچسب‌های» (Labels) مجموعه داده هستند. همه متغیرهای ورودی که وضعیت بیماران (نمونه‌ها) را توصیف می‌کنند عددی هستند.

این امر موجب می‌شود تا استفاده مستقیم از مجموعه داده همراه با شبکه عصبی، آسان باشد. زیرا شبکه عصبی مقادیر عددی را به عنوان ورودی دریافت و در خروجی ارائه می‌کند و گزینه‌ای ایده‌آل برای انجام یک پروژه یادگیری عمیق در پایتون محسوب می‌شود. مجموعه داده مورد استفاده در این مطلب را می‌توان از اینجا [+] دانلود و جزئیات مربوط به آن را در اینجا [+] مطالعه کرد. پس از دانلود مجموعه داده، باید آن را در پوشه کاری جاری (موقعیتی مشابه با فایل پایتون) قرار داد. می‌توان این مجموعه داده پایتون را با نام فایل ذخیره کرد.

با استفاده از قطعه کد زیر، می‌توان نگاهی به داده‌های موجود در مجموعه داده داشت. در ادامه، داده‌ها به صورت زیر قابل مشاهده هستند.

اکنون می‌توان فایل را با استفاده از تابع نام‌پای loadtxt()‎، به صورت ماتریسی از اعداد بارگذاری کرد. هشت متغیر ورودی و یک متغیر خروجی (ستون آخر) در این مجموعه داده وجود دارد. در ادامه، یک مدل برای نگاشت سطرهای متغیر ورودی (X) به متغیر خروجی (y) آموزش داده می‌شود که معمولا به صورت y = f(X)‎ خلاصه می‌شود. متغیرها را می‌توان به صورت زیر خلاصه کرد.

متغیرهای ورودی (X):

  • تعداد دفعات بارداری
  • تست سطح قند خون در دو ساعت در یک تست توازن قند دهانی
  • فشار خون دیاستول (mm Hg)
  • ضخامت ماهیچه سه سر (mm)
  • سرم انسولین ۲ ساعتی (mu U/ml)
  • شاخص توده بدنی (وزن به کیلوگرم/(ارتفاع به متر)^۲)
  • سابقه بیماری دیابت
  • سن (سال)

متغیر خروجی (y): متغیر دسته (۰ یا ۱)

هنگامی که فایل CSV در حافظه بارگذاری شد، می‌توان ستون‌های داده را در متغیرهای ورودی و خروجی دسته‌بندی کرد. داده‌ها در یک آرایه دوبُعدی ذخیره می‌شوند که در آن اولین بُعد سطرها و دومین بُعد ستون‌ها هستند (برای مثال [rows, columns]). می‌توان آرایه را با انتخاب زیرمجموعه‌ای از ستون‌ها با استفاده از «عملگر» (Operator) برش زنی استاندارد موجود در نام‌پای یعنی «:» به دو بخش تقسیم کرد. می‌توان اولین ۸ ستون را از اندیس ۰ تا ۷ با استفاده از 0:8 انتخاب کرد. سپس، می‌توان ستون خروجی با اندیس هشت (متغیر نهم) را انتخاب کرد.

اکنون، می‌توان مدل شبکه عصبی را تعریف کرد. شایان توجه است که مجموعه داده دارای ۹ ستون است و رنج ۰:۸ ستون‌ها را از ۰ تا ۷ انتخاب می‌کند و پیش از اندیس ۸ متوقف می‌شود.

تعریف مدل کرس

مدل‌های کرس به صورت توالی از لایه‌ها تعریف شده‌اند. می‌توان یک مدل ترتیبی ساخت و هر بار یک لایه را اضافه کرد، تا وقتی که معماری شبکه نهایی شود. اولین چیزی که در این راستا باید به آن پرداخت حصول اطمینان از این موضوع است که لایه ورودی دارای تعداد صحیحی ویژگی ورودی است. این مورد را می‌توان با ساخت اولین لایه با استفاده از آرگومان input_dim و تنظیم آن روی ۸ برای ۸ متغیر ورودی تعیین کرد.

پرسشی که در این وهله ممکن است برای بسیاری از افراد مطرح شود این است که چطور می‌توان تعداد لایه‌ها و نوع آن‌ها را دانست؟ این پرسشی سخت است. هیوریستک‌هایی وجود دارند که می‌توان از آن‌ها استفاده کرد و اغلب بهترین ساختار شبکه را می‌توان طی یک فرایند آزمون و خطا پیدا کرد. عموما، کاربر نیاز به آن دارد که شبکه به اندازه کافی بزرگ باشد تا بتواند ساختار مسأله را ثبت کند. برای کسب اطلاعات بیشتر در این راستا، مطالعه دو مطلب زیر پیشنهاد می‌شود:

لایه‌های کاملا متصل با استفاده از کلاس Dense تعریف می‌شوند. می‌توان تعداد نورون‌ها یا گره‌ها را در لایه به عنوان اولین آرگومان تعیین کرد و تابع فعال‌سازی را با استفاده از آرگومان activation مشخص کرد. در اینجا از تابع ReLU (تابع فعال‌سازی واحد خطی اصلاح شده | Rectified Linear Unit Activation Function) در دو لایه اول و تابع سیگموئید در لایه خروجی استفاده می‌شود.

از این تابع فعال‌سازی به این دلیل استفاده می‌شود که توابع فعال‌سازی سیگموئید و Tanh برای همه لایه‌ها ترجیح داده می‌شوند. این روزها، کارایی بهتری با استفاده از تابع فعال‌سازی ReLU حاصل می‌شود. از تابع سیگموئید در خروجی برای حصول اطمینان از این مورد استفاده می‌شود که خروجی شبکه بین ۰ و ۱ است و همچنین، نگاشت آن به احتمال کلاس ۱ یا اسنپ به دسته‌بندی سخت (Hard Classification) و یا کلاس با آستانه پیش‌فرض ۰.۵ آسان است. می‌توان همه این موارد را با هر لایه کنار هم قرار داد.

  • مدل نیازمند سطرهای داده با ۸ متغیر است (آرگومان input_dim=8)
  • اولین لایه پنهان دارای ۱۲ گره است و از تابع فعال‌سازی relu‌ استفاده می‌کند
  • دومین لایه پنهان دارای ۸ گره است و از تابع فعال‌سازی relu استفاده می‌کند
  • لایه خروجی دارای یک گره است و از تابع فعال‌سازی سیگموئید استفاده می‌کند
توجه: سردرگم کننده‌ترین چیزی که در اینجا وجود دارد شکل ورودی به مدل به عنوان آرگومانی روی اولین لایه پنهان تعریف شده است. این یعنی که خط کد که اولین لایه Dense را اضافه می‌کند، دو کار انجام می‌دهد. این دو کار عبارتند از تعریف کردن ورودی یا لایه پیدا و اولین لایه پنهان.

کامپایل کردن مدل کرس

اکنون که مدل تعریف شد، می‌توان آن را کامپایل کرد. در کامپایل کردن مدل از کتابخانه‌های موثر عددی برای تحت پوشش مانند ثینو یا تنسورفلو استفاده می‌شود. بک‌اند به طور خودکار بهترین راه را برای نمایش شبکه برای آموزش دادن و انجام پیش‌بینی برای اجرا روی سخت‌افزار مانند CPU یا GPU استفاده می‌کند. هنگام کامپایل کردن، باید برخی از خصوصیات افزوده مورد نیاز هنگام آموزش شبکه را تعیین کرد. باید به خاطر داشت که آموزش دادن یک شبکه به معنای پیدا کردن بهترین مجموعه ا زوزن‌ها برای نگاشت ورودی‌ها به خروجی‌ها در مجموعه داده است.

کاربر باید «تابع زیان» (Loss Function) را برای استفاده به منظور ارزیابی یک مجموعه از وزن‌ها تعیین کند؛ بهینه‌ساز برای جستجو از میان وزن‌های مختلف برای شبکه و هر سنجه انتخابی (اختیاری) دیگری که نیاز به گردآوری و گزارش دادن آن‌ها در هنگام آموزش دادن دارد مورد استفاده قرار می‌گیرد.

در این مورد، از «آنتروپی متقاطع» (Cross Entropy) به عنوان آرگومان زیان استفاده می‌شود. این زیان برای مسائل دسته‌بندی دودویی است و در کرس به عنوان «binary_crossentropy» تعریف شده است. در ادامه، بهینه‌ساز به عنوان «الگوریتم گرادیان کاهشی تصادفی» (Stochastic Gradient Descent Algorithm) «آدام» (Adam) مورد استفاده قرار می‌گیرد. این یک نسخه مشهور از الگوریتم گرادیان کاهشی است؛ زیرا به طور خودکار خودش را تنظیم و نتایج خوبی را در طیف وسیعی از مسائل، ارائه می‌کند. در نهایت، به دلیل اینکه مسئله موجود در اینجا یک مسئله دسته‌بندی است، صحت دسته‌بندی که با آرگومان metrics تعریف شده است، گردآوری و گزارش می‌شود.

برازش مدل کرس

  • طی مراحل انجام شده در بخش‌های پیشین، مدل تعریف و کامپایل شد و اکنون برای پردازش به شیوه موثر، آماده است. در حال حاضر زمان ان رسیده است که مدل روی بخشی از داده‌ها اجرا شود. می‌توان مدل را روی داده‌های بارگذاری شده با فراخوانی تابع fit()‎ روی مدل برازش کرد. آموزش دادن طی «دوره‌ها» (Epoches) اتفاق می‌افتد و هر دوره، به دسته‌هایی تقسیم می‌شود.
  • دوره (Epoch): یک عبور از همه سطرها در مجموعه داده آموزش
  • دسته (Batch): یک یا تعداد بیشتری نمونه در نظر گرفته شده توسط مدل در درون یک دوره پیش از آنکه وزن‌ها به روز رسانی شوند.

یک دوره، شامل یک یا تعداد بیشتری از دسته‌ها، بر اساس سایز دسته انتخاب شده است و مدل، برای تعداد دوره‌های زیادی برازش داده می‌شود. فرایند آموزش دادن برای تعداد ثابتی از تکرارها از طریق دوره‌های فراخوانی شده مجموعه داده انجام می‌شود؛ این مورد باید با استفاده از آرگومان epochs تعریف شود. همچنین، باید تعداد سطرهای مجموعه داده را که پیش از وزن‌های مدل نظر گرفته شده‌اند درون هر دوره به روز رسانی کرد؛ فراخوانی سایز و مجموعه دسته با استفاده از آرگومان batch_size انجام می‌شود.

برای حل این مسئله، اجرا با تعداد دوره‌های کمی (۱۵۰ دوره) انجام می‌شود و همچنین، از یک سایز دسته نسبتا کوچک (۱۰) استفاده خواهد شد. این پیکربندی‌ها را می‌توان به طور تجربی با روش آزمون و خطا انتخاب کرد. در این راستا، نیاز به آن است که مدل به اندازه کافی آموزش ببیند تا نگاشت خوب (یا یک نگاشت به اندازه کافی خوب) از سطرهای مجموعه داده ورودی به سطرهای خروجی را بیاموزد. مدل همیشه دارای میزانی خطا خواهد بود، اما میزان خطا پس از انجام اقداماتی برای پیکربندی خروجی، یکنواخت می‌شود.

این همان جایی است که کارها روی CPU یا GPU انجام می‌شود. در این مثال، نیاز به GPU نیست، اما در بسیاری از موارد نیاز به استفاده از GPU برای انجام پردازش‌های زیاد نیاز است.

ارزیابی مدل کرس

در بخش‌های پیشین، شبکه عصبی روی کل مجموعه داده آموزش داده شد و بنابراین، در این مرحله می‌توان کارایی شبکه را روی همان مجموعه داده ارزیابی کرد. این مورد فقط ایده‌ای از اینکه مجموعه داده چقدر خوب مدل شده است (برای مثال صحت مدل) به دست می‌دهد؛ اما هیچ ایده‌ای از اینکه الگوریتم چقدر خوب روی داده‌های جدید عمل خواهد کرد، ارائه نمی‌کند. این کار به منظور سادگی انجام شده است، اما به طور ایده‌آل کاربر می‌تواند داده‌های خود را به داده‌های تست (Test) و آموزش (Train) برای آموزش دادن و ارزیابی مدل تقسیم کند. این کار یک پیش‌بینی برای هر جفت ورودی خروجی ارائه و امتیازها را شامل میانگین هزینه و هر سنجه‌ای که پیکربندی شده مانند صحبت، تولید می‌کند. تابع evaluate()‎ لیستی با دو مقدار را باز می‌گرداند. اولین مقدار زیان مدل روی مجموعه داده و دومین مورد، صحت مدل روی مجموعه داده است. در این مورد، صحت دارای جذابیت است و بنابراین، از مقدار زیان چشم‌پوشی می‌شود.

یکپارچه‌سازی کلیه موارد

همانطور که در بخش‌هاش پیشین مشاهده شد، می‌توان یک مدل شبکه عصبی را به سادگی در کرس ساخت. اکنون، کلیه بخش‌های مربوط به مدل کنار هم قرار می‌گیرند تا مدل کامل ساخته شود.

مخاطبان گرامی می‌توانند همه کد ارائه شده در بالا را رد یک فایل پایتون کپی و آن را با عنوان «keras_first_network.py» در پوشه‌ای مشابه با پوشه‌ای که مجموعه داده بیماران دیابتی یا همان «pima-indians-diabetes.csv» قرار دارد، ذخیره کنند. سپس، می‌توان فایل پایتون را به عنوان یک اسکریپت از خط فرمان (Command Prompt) به صورت زیر اجرا کرد.

با اجرای مثال ارائه شده در این مطلب، باید پیامی برای هر یک از ۱۵۰ دوره چاپ شود که زیان و صحت را نشان می‌دهد و در نهایت، ارزیابی نهایی مدل روی مجموعه داده را به تصویر می‌کشد. در سیستم نویسنده این مطلب، اجرای این مثال ۱۰ ثانیه به طول انجامیده است. به طور ایده‌آل، انتظار می‌رود که زیان به سمت صفر و صحت به سمت ۱ میل کند (یعنی صحت ۱۰۰ درصد). البته، آنچه بیان شد برای همه مسئله‌ای ممکن نیست، اما در بدیهی‌ترین مسائل یادگیری ماشین امکان به دست آوردن صحت ۱۰۰ درصد وجود دارد. اما رد مثال جهان واقعی، همیشه میزانی هر چند ناچیز، خطا وجود دارد. هدف انتخاب یک پیکربندی مدل و پیکربندی آموزش مدل است که پایین‌ترین زیان و بالاترین صحت ممکن را برای یک مجموعه داده، به دست می‌آورد.

 ...
768/768 [==============================] - 0s 63us/step - loss: 0.4817 - acc: 0.7708
Epoch 147/150
768/768 [==============================] - 0s 63us/step - loss: 0.4764 - acc: 0.7747
Epoch 148/150
768/768 [==============================] - 0s 63us/step - loss: 0.4737 - acc: 0.7682
Epoch 149/150
768/768 [==============================] - 0s 64us/step - loss: 0.4730 - acc: 0.7747
Epoch 150/150
768/768 [==============================] - 0s 63us/step - loss: 0.4754 - acc: 0.7799
768/768 [==============================] - 0s 38us/step
Accuracy: 76.56

نکته: در صورت اجرای این مثال در «‌ژوپیتر نوت‌بوک» (Jupyter Notebook) یا «آی‌پایتون» (IPython)، ممکن است اجرای برنامه با خطا مواجه شود. دلیل این امر نوارهای پیشرفت خروجی در طول آموزش است. این خصوصیت را می‌توان به سادگی با تنظیم verbose=0 در فراخوانی روی  توابع fit()‎ و evaluate()‎ خاموش کرد؛ برای مثال:

نکته: شایان توجه است که صحبت مدل متغیر است. دلیل این امر آن است که شبکه‌های عصبی مصنوعی الگوریتم‌های تصادفی هستند؛ این بدین معنا است که یک الگوریتم روی داده‌های مشابه، می‌تواند مدل‌های متفاوتی را در هر بار از اجرای مدل آموزش دهد. این یک ویژگی، و نه باگ، است. واریانس در کارایی این مدل به معنای آن است که باید یک تخمین منطقی از اینکه مدل چقدر عملکرد خوبی دارد به دست بیاید؛ در این راستا کاربر ممکن است نیاز به براز این مدل به دفعات بالا و محاسبه میانگین صحت داشته باشد. برای مثال، امتیازهای صحبت برای این مثال طی اجراهایی مختلف نمایش داده شده است.

Accuracy: 75.00
Accuracy: 77.73
Accuracy: 77.60
Accuracy: 78.12
Accuracy: 76.17

انجام پیش‌بینی

پرسشی که ممکن است برای بسیاری از افراد در این وهله مطرح شود این است که «پس از آموزش دادن مدل، چگونه می‌توان از آن برای انجام پیش‌بینی روی داده‌های جدید استفاده کرد؟». در پاسخ به این پرسش باید گفت که می‌توان مثال بالا را سازگار و از آن برای تولید پیش‌بینی روی مجموعه داده آموزش استفاده کرد و در واقع، وانمود کرد که این یک مجموعه داده جدید است که پیش از این مشاهده نشده است.

انجام پیش‌بینی با فراخوانی  تابع predict()‎ روی مدل کار ساده‌ای است. در اینجا از تابع فعال‌سازی سیگموئید روی لایه خروجی استفاده شده است، بنابراین پیش‌بینی‌ها احتمالا در طیف بین ۰ و ۱ خواهند بود. می‌توان به سادگی این موارد را با گردن کردن آن‌ها، به پیش‌بینی‌های دودویی برای این مسئله دسته‌بندی تبدیل کرد. برای مثال:

به طور جایگزین، می‌توان تابع predict_classes()‎ را روی مدل برای پیش‌بینی کلاس‌ها به طور مستقیم، استفاده کرد؛ برای مثال:

مثال کامل زیر، برای هر نمونه در مجموعه داده پیش‌بینی انجام می‌دهد و سپس، داده‌های ورودی، کلاس پیش‌بینی شده و کلاس مورد انتظار را برای ۵ مثال اول در مجموعه داده، چاپ می‌کند.

اجرای مثال بالا، نوار پیشرفت را مانند آنچه پیش از این وجود داشت، نمایش نمی‌دهد؛ زیرا در اینجا آرگومان verbose برابر با صفر تنظیم شده است. پس از آنکه مدل برازش شد، پیش‌بینی برای همه مثال‌ها در مجموعه داده انجام می‌شود و سطرهای ورودی و مقدار کلاس پیش‌بینی شده برای ۵ نمونه چاپ و با مقدار کلاس مورد انتظار مقایسه شده‌اند. می‌توان مشاهده کرد که سطرها به طور درستی پیش‌بینی می‌شوند. در حقیقت، انتظار می‌رود که در حدود ۷۶/۹ درصد از سطرها به طور درست و بر مبنای کارایی تخمین زده شده مدل در بخش پیشین، پیش‌بینی شوند.

[6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0] => 0 (expected 1)
[1.0, 85.0, 66.0, 29.0, 0.0, 26.6, 0.351, 31.0] => 0 (expected 0)
[8.0, 183.0, 64.0, 0.0, 0.0, 23.3, 0.672, 32.0] => 1 (expected 1)
[1.0, 89.0, 66.0, 23.0, 94.0, 28.1, 0.167, 21.0] => 0 (expected 0)
[0.0, 137.0, 40.0, 35.0, 168.0, 43.1, 2.288, 33.0] => 1 (expected 1)

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

^^

الهام حصارکی (+)

«الهام حصارکی»، فارغ‌التحصیل مقطع کارشناسی ارشد مهندسی فناوری اطلاعات، گرایش سیستم‌های اطلاعات مدیریت است. او در زمینه هوش مصنوعی و داده‌کاوی، به ویژه تحلیل شبکه‌های اجتماعی، فعالیت می‌کند.

بر اساس رای 5 نفر

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *