دسته‌بندی دیتاست CIFAR-10 با استفاده از شبکه‌های کانولوشن و PyTorch

در این پست می‌خواهیم دیتاست CIFAR10 را با استفاده از شبکه‌های کانولوشن ( CNN – Convolutional Neural Network) و با استفاده از فریم‌ورک یادگیری عمیق پای تورج (PyTorch) دسته‌بندی (Classification) کنیم.

دیتاست سیفار-۱۰ یا همان CIFAR-10 یک دیتاست است که از ۱۰ کلاس زیر تشکیل شده است:

  • هواپیما
  • اتومبیل
  • پرنده
  • گربه
  • گوزن
  • سگ
  • قورباغه
  • اسب
  • کشتی
  • کامیون

 

هر کلاس شامل ۵۰۰۰ داده آموزش و ۱۰۰۰ داده تست هست و کل دیتاست شامل ۶۰۰۰۰ تصویر است. حجم دیتاست چیزی در حدود ۱۶۰ مگابایت است. هر تصویر در این دیتاست ۳۲*۳۲ پیکسل است. در تصویر زیر نمونه‌ای از تصویرهای موجود در این دیتاست را مشاهده می‌کنید.

 

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

از آنجایی که هدف به دست آوردن یک دقت معقول و کار با شبکه‌های عصبی کانولوشن و فریم‌ورک پایتورچ است، از یک شبکه سبک و ساده کانولوشن استفاده می‌کنیم که هم دقت نسبتا خوبی به دست بیاوریم و هم آن را به آسانی آموزش دهیم.

شبکه کانولوشنی که استفاده می‌کنیم به شکل زیر است:

  • یک لایه کانولوشنی که یک ورودی با ۳ کانال را می‌گیرد و یک خروجی با ۹ کانال می‌دهد و اندازه کرنل آن ۵*۵ است و از تابع غیر خطی ‌ReLu استفاده می‌کند.
  • یک لایه ‌Max Pooling که اندازه کرنل آن ۲*۲ است.
  • یک لایه کانولوشنی که یک ورودی با ۹ کانال را می‌گیرد و یک خروجی با ۱۸ کانال می‌دهد و اندازه کرنل آن ۳*۳ است و از تابع غیر خطی ‌ReLu استفاده می‌کند.
  • یک لایه ‌Max Pooling که اندازه کرنل آن ۲*۲ است.
  • یک لایه Fully Connected که ۱۰۰ نورون دارد و از تابع غیر خطی ReLu استفاده می‌کند.
  • یک لایه Fully Connected که ۴۰ نورون دارد و از تابع غیر خطی ReLu استفاده می‌کند.
  • یک لایه Fully Connected که ۱۰ نورون دارد که با تعداد کلاس‌ها برابر است.

 

ابتدا پکیج‌های مورد استفاده را ایمپورت می‌کنیم:

torch و torchvision دو پکیج برای کار کردن با شبکه‌های عصبی و انجام کارهای مربوط به بینایی کامپیوتر (ویژن) هستند.

سپس اقدام به خواندن دیتاست می‌کنیم:

در کد بالا transforms.ToTensor تابعی هست که یک آرایه عادی یا از جنس numpy را به یک Tensorتبدیل می‌کند. پایتورچ از تنسور استفاده می‌کند و از آرایه‌های عادی و numpy استفاده نمی‌کند. تفاوتشان این است که تنسور قابلیت استفاده از جی.پی.یو را دارند. تابع transforms.Normaalize با توجه ورودی‌هایی که به آن داده شده است، مقدار پیکسل‌ها را به بازه‌ی -۱ تا ۱ منتقل می‌کند و این نرمال سازی کار آموزش شبکه را آسان‌تر می‌کند. تابع compose دو تابع بالا را در کنارهم قرار می‌دهد. ‌پایتورچ تابع‌ها و امکاناتی برای خواندن بعضی از دیتاست‌های معروف دارند و یکی از این دیتاست‌ها دیتاست CIFAR10 است که در بالا از آن استفاده کرده‌ایم. در صورتی که دیتاست در مسیر مشخص شده موجود نباشد آن را اتوماتیک دانلود می‌کند. DataLoader اجازه دسترسی به دیتاهای دیتاست را به صورت mini-batch می‌دهد و کار شافل کردن را نیز انجام می‌دهد.

تابع بالا کار نمایش یک تصویر که به صورت Tensor است را انجام می‌دهد. در ابتدا مشخص شده است که تنسور قرار است با سی.پی.یو پردازش شود. سپس مقدارهای -۱ تا ۱ به بازه‌ی ۰ تا ۱ منتقل می‌شوند و بعد تنسور به یک آرایه از نوع numpy تبدیل می‌شود و در ادامه تصویر از شکل ۳HW به صورت HW3 در آورده می‌شود. دلیل این امر تفاوت تصویر در پایتورچ با سایر کتابخانه‌ها و استانداردها است و در آخر تصویر رسم می‌شود.

در ادامه چند مورد از‌ تصویر‌های موجود در مجموعه داده‌ی سیفار را رسم می‌کنیم:

خروجی کد بالا تصاویر زیر است:

gt در بالا معنی Ground Truth را می‌دهد.

 

در کد بالا یک شبکه عصبی کانولوشنی که در بالا آن را شرح دادیم را ایجاد می‌کنیم. کلاسی که می‌نویسیم کلاس پدرش، حتما باید to_nn.Module باشد. در constructor ابتدا کانستراکتور کلاس پدر را فرا می‌خوانیم سپس لایه‌هایی از شبکه که پارامترهایی قابل یادگیری دارند را تعریف می‌کنیم.

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

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

در کد بالا از کلاس‌ شبکه‌ای که ایجاد کرده‌ایم یک شی می‌سازیم و مشخص می‌کنیم از جی.پی.یو و یا سی.پی.یو استفاده کند.

شبکه‌ی عصبی مان نیاز به یک Loss Function دارد، از تابع هزینه Cross Entropy استفاده می‌کنیم که معمولا برای دسته‌بندی نتایج خوبی می‌دهد. همین طور به الگوریتم بهینه‌سازی نیازی داریم و برای این کار الگوریتم Stochastic Gradient Descent را انتخاب کرده‌ایم.

در کد بالا آموزش شبکه انجام می‌پذیرد. برای ۱۰ ایپاک شبکه را آموزش می‌دهیم. zero_grad گرادیان‌های شبکه را صفر می‌کند اگر این کار را انجام ندهیم گرادیان‌ها جمع می‌شوند و اشتباه رخ می‌دهد. تابع backward هم کار backpropagation را انجام می‌دهد و گرادیان‌ها را محاسبه می‌کند. step نیز با توجه با گرادیان‌های محاسبه شده و ضریب یادگیری و … وزن‌ها را به‌روزرسانی می‌کند. در زیر بخشی از خروجی در حین آموزش را مشاهده می‌کنید:

 

 

در کد بالا بعد از آموزش شبکه، پیش‌بینی شبکه برای چند ورودی که از مجموعه تست انتخاب شده‌اند نمایش داده می‌شود و سپس دقت بر روی مجموعه تست نمایش داده می‌شود.

در تصویر بالا پیشبینی شبکه آموزش دیده شده را برای چند تصویر مشاهده می‌کنید و در زیر دقت شبکه بر روی مجموعه تست را می‌بینید:

 

این شبکه را برای کلسیفیکیشن دیتاست CIFAR10 را خیلی سریع ایجاد کردیم و نتایج خوبی گرفتیم با ایجاد تغییر در ساختار و پارامترهای شبکه می‌توان دقت را بهبود بخشید.

 

در زیر کد کلی برنامه را مشاهده می‌کنید:

 

 

 

 

 

 

نظرتان را برای ما بنویسید

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