هادی عبدی خجسته | Hadi Abdi Khojasteh
هادی عبدی خجسته | Hadi Abdi Khojasteh
خواندن ۲۲ دقیقه·۴ سال پیش

چطوری با بینایی کامپیوتر هواپیماها رو در تصویر هوایی پیدا کنیم؟

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

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

تنها با جستجوی یک کلمه یا ایموجی می‌توان در بین تمام تصاویری که قبلا برچسب‌گذاری نشده‌اند، جستجو کرد. مثلا با نوشتن کلمه 'سگ' میشه تمام تصاویر شامل این شی رو پیدا کرد. این کار واقعا چطور انجام می‌شود؟
تنها با جستجوی یک کلمه یا ایموجی می‌توان در بین تمام تصاویری که قبلا برچسب‌گذاری نشده‌اند، جستجو کرد. مثلا با نوشتن کلمه 'سگ' میشه تمام تصاویر شامل این شی رو پیدا کرد. این کار واقعا چطور انجام می‌شود؟

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


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

شروع ساده

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

واقعیت این است که یادگیری ماشین تنها زمانی کار می‌کند که داده‌های کافی و مناسب داشته باشیم. پس برای شروع نیاز به تعداد زیادی تصویر از اعداد دست‌نویس داریم. به لطف مجموعه ارقام هدی، در حال حاضر تعداد زیادی تصویر از اعداد برای استفاده تحقیقاتی موجود است. این مجموعه بزرگ ارقام دستنویس فارسی، شامل ۱۰۲۳۵۳ نمونه دست‌نوشته سیاه و سفید است. داده های این مجموعه از حدود ۱۲۰۰۰ فرم ثبت نام آزمون سراسری کارشناسی ارشد و آزمون کاردانی در سال ۱۳۸۳ استخراج شده است. در واقع هر عدد یک تصویر ۲۸ در ۲۸ پیکسل است. در ادامه نمونه هایی از اعداد این مجموعه آمده است.

نمونه‌هایی از اعداد نوشته‌شده با دست‌خط‌های مختلف در مجموعه ارقام دست‌نویس
نمونه‌هایی از اعداد نوشته‌شده با دست‌خط‌های مختلف در مجموعه ارقام دست‌نویس

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

ورودی تصویر یا عدد؟ مسئله این است!

می‌دونیم که شبکه‌های عصبی فقط تعدادی عدد به عنوان ورودی می‌پذیرد. ولی ما در اینجا می‌خواهیم تصاویر را به عنوان ورودی در‌نظر بگیریم. خب سوال این است که تصاویر چگونه در شبکه پردازش می‌شوند؟ پاسخ ساده است. برای کامپیوتر هر تصویر یک ماتریس از اعداد بین ۰ تا ۲۵۵ است که این عدد نشان می‌دهد هر پیکسل چقدر تیره است.

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

ما می‌تونیم یک ماتریس ۲۸ در ۲۸ رو به صورت یک آرایه ۷۸۴ تایی از اعداد به عنوان ورودی شبکه عصبی در نظر بگیریم. بنابراین مدل ما باید ۷۸۴ عدد ورودی بگیرد و ما به ازای هر گروه از ورودی یک خروجی تولید کند. با داشتن خروجی جداگانه برای هر نوع شی که می‌خواهیم تشخیص دهیم، می‌تونیم از شبکه برای طبقه‌بندی اشیا به گروه‌ها استفاده کنیم. منظور از گروه حالت‌های خروجی برای مدل است. مثلا مدل می تواند ۱۰ حالت خروجی برای اعداد داشته باشد یا تنها یک حالت داشته باشد که با یک عدد اعشاری بین صفر و یک احتمال سه بودن عدد داخل تصویر را مشخص می‌کند. برای سادگی فعلا فرض کنید شبکه ما یک خروجی دارد.

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

یافتن عدد دست‌نویس در تصاویر

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

شبکه عصبی مصنوعی تصویر ورودی سه که در مرکز تصویر است را به درستی تشخیص می‌دهد.
شبکه عصبی مصنوعی تصویر ورودی سه که در مرکز تصویر است را به درستی تشخیص می‌دهد.

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

مدل آموزش داده‌شده، به علت تغییر عدد ورودی با جابجایی تصویر، نمی‌تواند عدد را تشخیص دهد.
مدل آموزش داده‌شده، به علت تغییر عدد ورودی با جابجایی تصویر، نمی‌تواند عدد را تشخیص دهد.

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

ایده اول؛ جستجو در تصویر

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

جستجو اعداد در پنجره‌های کوچک‌تر در تصویر
جستجو اعداد در پنجره‌های کوچک‌تر در تصویر

این رویکرد به پنجره کشویی (روان) یا Sliding Window معروف است که کاملا غیرهوشمندانه یا Brute-force است. این روش در موارد محدودی کار می‌کند ولی در موارد زیادی واقعا ناکارآمد است. چون باید این کار را برای تمام بخش‌های یک تصویر در اندازه‌های مختلف چند بار امتحان کنیم؛ یعنی باید از قبل بدانیم چه اندازه پنجره‌ای برای پیدا‌کردن عدد مناسب است یا اندازه‌های زیادی را امتحان کنیم. بنابراین بهتر است ایده‌های دیگری رو هم درنظر بگیریم.

ایده دوم؛ داده‌های بیشتر برای آموزش

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

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

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

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

کانوُلوشِن

به طور شهودی می‌دونیم که تصاویر دارای یک سلسله‌مراتب یا ساختار مفهومی هستند. این تصویر را ببینید:

ماچِکول؛ تصویر مارمولک زیبایی که در یکی از سفرهایم ملاقات کردم.
ماچِکول؛ تصویر مارمولک زیبایی که در یکی از سفرهایم ملاقات کردم.

به عنوان یک انسان، شما فورا مفاهیم سلسله‌مراتبی را در این تصویر تشخیص می‌دهید: زمینی پوشیده از خاک و گیاهان، مارمولک زیبای سبز رنگ، مارمولک روی یک سنگ لَم داده است و سنگی که روی خاک و علف‌زار است. ما از کودکی یادگرفتیم که مفهوم مارمولک فارغ از آنچه که روی آن نشسته است تعریف می‌شود و به ازای هر سطح متفاوت یکبار این مفهوم را مجددا بازنگری نمی‌کنیم. کاری که در حال حاضر، شبکه عصبی ما نمی‌تواند انجام دهد. مدل فکر می‌کند عدد در هر بخش از تصویر یک مفهوم متفاوت است و نمی‌داند که مکان عدد تاثیری در ماهیت آن ندارد و این یعنی هربار باید دوباره مفهوم را در یک مکان جدید در تصویر یاد بگیرد. همچنین شبکه‌ای که تا به اینجا آموزش داده شده است اعداد را در یک پس‌زمینه سفید یاد می‌گیرد که همیشه اینطور نیست. پس بهتر است مدل نیز یک مفهوم از اشیا را یاد بگیرد. برای این‌کار باید از مفهومی به اسم کانوُلوشِن کمک بگیریم. ایده استفاده از کانولوشن برای جل این مسئله، تا حدی از علوم کامپیوتر و زیست‌شناسی (دانشمندان دیوانه‌ای که پروب‌های الکتریکی را برای این‌که بفهمند مغز چگونه تصاویر را پردازش میکند، در مغز گربه قرار دادند!) الهام گرفته شده است.

کانولوشن چگونه کار میکند؟

کانوُلوشِن یا هم‌گشت (Convolution) در ریاضیات یا به طور دقیق‌تر آنالیز تابعی، یک عملگر ریاضی است که بر روی دو تابع f و g به صورت f*g نوشته می‌شود. عمل می‌کند. کانولوشن مشابه تابع هم‌بستگی است. بنابراین این تعریف به صورت انتگرال حاصل‌ضرب دو تابع که یکی از آن‌ها نسبت به محور عمودی مختصات برعکس شده و روی آن یکی می‌لغزد تعریف می‌شود. با این تعریف، کانولوشن یک نوع خاص از تبدیل انتگرالی است. این عملگر از آمار گرفته تا بینایی رایانه‌ای، پردازش تصویر، پردازش سیگنال، مهندسی برق و معادلات دیفرانسیل کاربرد دارد. به جای این‌که کل تصویر را به شکل ماتریسی از اعداد ورودی در نظر بگیریم، با کمک این عملگر و تکنیک‌های دیگر، مفهوم اینکه شی فارغ از مکانش در تصویر همیشه یک مفهوم را می‌رساند، مرحله‌به‌مرحله پیاده‌سازی خواهیم کرد. هدف ساخت مدلی است که احتمال حضور مارمولک در تصویر را تخمین بزند.

مرحله اول؛ تفکیک تصویر به تعدادی تصویر کوچکتر با هم‌پوشانی

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

تصویر شکسته شده به تصاویر کوچک‌تر هم اندازه که باهم هم‌پوشانی دارند.
تصویر شکسته شده به تصاویر کوچک‌تر هم اندازه که باهم هم‌پوشانی دارند.

در این مثال بخشی مربعی از تصویر اصلی با اندازه ۵۷۶ در ۵۷۶ پیکسل را به ۶۴ کاشی تصویری کوچک‌تر با اندازه برابر که با هم هم‌پوشانی دارند، تقسیم کرده‌ایم.

مرحله دوم؛ پردازش هر کاشی با یک شبکه عصبی کوچک‌تر

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

مرحله پردازش هر کاشی کوچک‌تر ایجاد شده از تصویر بزرگتر اصلی، به ازای هر کاشی یعنی ۶۴ بار تکرار می‌شود.
مرحله پردازش هر کاشی کوچک‌تر ایجاد شده از تصویر بزرگتر اصلی، به ازای هر کاشی یعنی ۶۴ بار تکرار می‌شود.

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

مرحله سوم؛ ذخیره نتایج حاصل از هر کاشی در یک آرایه جدید

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

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

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

مرحله چهارم؛ کاهش نمونه

نتیجه مرحله قبل، آرایه‌ای است که نمایندگان خوبی برای بخش‌هایی از تصویر اصلی هستند که برای یادگیری جالب هستند. اما این آرایه ها هنوز هم خیلی بزرگ هستند. برای کاهش اندازه آرایه و کاهش نمونه‌ها، از روش بیشینه تجمع (Max Pooling) استفاده می‌کنم. فقط کافی است در هر ناحیه محلی ۲ در ۲ از آرایه‌ها فقط آرایه‌ای را نگه‌داریم که بیشترین مقدار (یا جالب‌ترین ناحیه برای یادگیری) را دارد.

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

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

مرحله آخر؛ پیش بینی تصویر ورودی

مدل تا به اینجا، یک تصویر غول پیکر را به آرایه نسبت کوچکی تقلیل داده است. حدس بزنید به چی رسیدیم؟ بله، یک آرایه که فقط دسته‌ای از اعداد است، بنابراین ما می‌توانیم از آن آرایه کوچک به عنوان ورودی یک شبکه عصبی دیگر استفاده کنیم. این شبکه عصبی نهایی تصمیم می‌گیرد که تصویر ورودی چه خواهد بود. برای متمایز‌کردن این شبکه از شبکه کانولوشن (پیچشی)، به اون شبکه عصبی تماما متصل (Fully Connected) می‌گوییم. تصویر زیر تمام پنج مرحله شناسایی تصویر را از ابتدا تا به انتها نشان می‌دهد.

مدل شبکه عصبی مصنوعی برای تشخیص اشیا از روی تصویر ورودی
مدل شبکه عصبی مصنوعی برای تشخیص اشیا از روی تصویر ورودی

گام‌های بیشتر

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

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

مدل YOLO برای تشخیص بلادرنگ اشیا در تصویر با دقت بالا
مدل YOLO برای تشخیص بلادرنگ اشیا در تصویر با دقت بالا

در این نمونه، مدل یک تصویر ۴۴۸ در ۴۴۸ پیکسل را دریافت می‌کند. سپس چهار بار کانولوشن و تجمیع انجام میدهد. اعداد یافته شده نهایی به یک شبکه عصبی تماما‌متصل با دو لایه ورودی داده می شود. در آخر شبکه می تواند کلاس تصویر را از بین ۱۰۰۰ کلاس انتخاب کند. حتی این مدل می‌تواند چند شی را در تصویر شناسایی کرده و محل دقیق آنها رو هم علامت‌گذاری کند.

معماری مناسب برای یک شبکه

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

تشخیص هواپیما در تصاویر هوایی با یادگیری عمیق

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

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

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

تصاویر دیگر موجود در مجموعه شامل اشیا دیگر در تصاویر هوایی هستند که جمعا ۲۴۰۰۰ تصویر هستند. یک سوم از نمونه ها پوشش‌های طبیعی مختلف روی زمین مثل آب، درختان، زمین‌خالی، ساختمان و غیره هستند که هیچ هواپیمایی را شامل نمی‌شوند. یک سوم دیگر تنها جزئی از هواپیما را نشان میدهند که برای یادگیری تمام مفهوم هواپیما کافی نیستند. یک سوم نهایی اما اشیا جالبی هستند که براق و شبیه هواپیما هستند و ممکن است مدل را دچار اشتباه کند. این تصاویر توسط مدل‌های هوش مصنوعی قبلا علامت‌گذاری شدند اما هواپیما نیستند.

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

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

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

pip install kaggle mkdir -p ~/.kaggle cp kaggle.json ~/.kaggle/ chmod 600 ~/.kaggle/kaggle.json kaggle datasets download -d rhammell/planesnet unzip planesnet.zip

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

def LoadDir(dirname): imgs = [np.zeros([20,20,3])] labels = [0] for imgname in os.listdir(dirname): if(imgname[0] == '1'): labels.append(1) else: labels.append(0) if os.path.isfile(os.path.join(dirname, imgname)): img = Image.open(os.path.join(dirname, imgname)) img = np.array(img) imgs.append(img) return np.array(imgs),np.array(labels) imgs, labels = LoadDir(r'planesnet/planesnet/')

حال باید داده‌های آموزشی و آزمایشی را از هم تفکیک کنیم. در همین مرحله نیز می‌توانیم داده‌های مشابه برای یادگیری بهتر ایجاد کنیم:

x_train, x_temp, y_train, y_temp = train_test_split(imgs, labels, test_size = 0.20, random_state = 42, shuffle = True) x_valid, x_test, y_valid, y_test = train_test_split(x_temp, y_temp, test_size = 0.50, random_state = 42, shuffle = True) x_train1 = np.rot90(x_train, k = 1, axes = (1, 2)) #Generate new samples x_train2 = np.rot90(x_train, k = 2, axes = (1, 2)) x_train3 = np.rot90(x_train, k = 3, axes = (1, 2)) x_train = np.append(x_train, x_train1, axis = 0) x_train = np.append(x_train, x_train2, axis = 0) x_train = np.append(x_train, x_train3, axis = 0) y_train = np.append(y_train, y_train) y_train = np.append(y_train, y_train)

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

model = Sequential() def swish(x): return (K.sigmoid(x) * x) get_custom_objects().update({'swish': Activation(swish)}) model.add(Conv2D(16, 2, padding = 'valid', input_shape = (20,20,3))) model.add(BatchNormalization()) model.add(Activation('tanh')) model.add(MaxPooling2D((2,2))) model.add(Conv2D(32, 3, padding = 'valid')) model.add(BatchNormalization()) model.add(Activation('swish')) model.add(Dropout(0.2)) model.add(MaxPooling2D((2,2))) model.add(Conv2D(64, 2, kernel_initializer = 'random_uniform', padding = 'valid')) #64 2 model.add(BatchNormalization()) model.add(Activation('swish')) model.add(Dropout(0.2)) model.add(Flatten()) model.add(Dense(1, activation = 'sigmoid')) opt = keras.optimizers.SGD(lr = 0.01, momentum = 0.1, decay = 0.00005, nesterov = True) model.compile(optimizer = opt, loss = 'binary_crossentropy', metrics = ['binary_accuracy']) log = model.fit(x_train, y_train, shuffle = True, validation_data = (x_valid, y_valid), epochs = 200)

اگر برای اجرای این کد از یک کارت گرافیک خوب و حافظه کافی استفاده می‌کنید، به زمانی کمتر از یک ساعت برای آموزش و تنظیم وزن های شبکه نیاز دارید. اگر از یک پردازنده معمولی استفاده می‌کنید، ممکن است این فرآیند چند ساعت زمان نیاز داشته باشد. با آموزش هرچه بیشتر مدل دقت آن نیز افزایش می‌یابد. در پیاده‌سازی که انجام دادم، بعد از اولین تکرار (Epoch) دقت مدل ۸۵.۲۸ درصد بود. تنها بعد از ۱۰ تکرار این دقت به ۹۷ درصد رسید. بعد از گذشت ۵۰ تکرار، دقت مدل آموزش داده شده به ۹۸.۵۶ درصد رسید و تغییری نکرد. شما می تونید از روش‌های مختلف مثل چرخش تصاویر، تغییر اندازه، تغییر رنگ یا غیره داده‌های بیشتری مشابه داده‌های ورودی تولید کنید یا معماری مدل را تغییر دهید تا به دقت بیشتری برسید. همچنین اگر علاقمندید می تونید با روش پنجره روان با اندازه های مختلف که در بخش اول توضیح دادیم، از یک تصویر هوایی، تصاویر کوچکتری را انتخاب کنید تا بتونید محل دقیق هواپیما در یک عکس بزرگ تشخیص دهید. تبریک میگم، حالا ما یک مدل هوش مصنوعی داریم که در تصاویر هوایی هواپیما را تشخیص می‌دهد!

آزمایش شبکه با یک تصویر ورودی

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

y_pred = model.predict(x_test) y_pred[y_pred > 0.5] = 1 y_pred[y_pred < 0.5] = 0 y_pred = np.asarray(y_pred, dtype=bool)

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

دقت ۹۹ درصد چقدر دقیق است؟

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

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

اول، هواپیماهایی که شبکه به درستی به عنوان هواپیما شناخته است که آن را مثبت صحیح (True Positive) می‌نامیم. دوم، همان تصاویری که هواپیما نبودند و به درستی شناسایی شدند که به آن ها منفی صحیح (True Negative) می‌گوییم. سوم، تصاویری که مدل فکر میکرد هواپیما هستند ولی این‌طور نبودند که مثبت کاذب (False Positive) می‌گوییم. و چهارم، تصاویری از هواپیما که شبکه نتوانسته است آن‌ها را هواپیما شناسایی کند که منفی کاذب (False Negative) گوییم.

در جدول زیر با اعتبارسنجی مدل بر اساس داده‌های آزمایشی دقت با جزئیات بیشتری بر اساس معیارهای مختلف که این چهار دسته را در نظر میگیرند، آمده است:

نمودارهای زیر نیز تغییرات خطای مدل در هر بار تکرار در آموزش شبکه و دقت نمونه های آموزشی و آزمایشی را نشان میدهد.

دقت شبکه عصبی عمیق برای شناسایی تصاویر هواپیما در فرآیند آموزش بر اساس نمونه‌های آموزشی و آزمایشی به همراه خطا در هر تکرار
دقت شبکه عصبی عمیق برای شناسایی تصاویر هواپیما در فرآیند آموزش بر اساس نمونه‌های آموزشی و آزمایشی به همراه خطا در هر تکرار

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


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

ویدیو نمایشی پروژه خودروی خودران برای نظارت بر رفتار راننده برای جلوگیری از تصادفات ناشی از اشتباهات راننده
ویدیو نمایشی پروژه خودروی خودران برای نظارت بر رفتار راننده برای جلوگیری از تصادفات ناشی از اشتباهات راننده

در نوشتن این متن از ترجمه کلمات تخصصی علوم کامپیوتر و هوش مصنوعی در فارسی استفاده شده است که از دیکشنری متن‌باز تخصصی انگلیسی‌-‌فارسی علوم کامپیوتر انتخاب شده‌اند. شما هم می‌تونید از اینجا با مشارکت در تکمیل یا اصلاح فهرست واژگان رشته تخصصی خود سهمی در گسترش علم داشته باشید.
این ماجراجویی تموم شد. حالا نوبت شماست که شبکه عصبی خودتون رو برای شناخت اشیا در تصاویر طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما ایجاد یک برنامه برای شناخت همزمان چندین موجودیت در تصویر چه چالش هایی به همراه داره؟

https://virgool.io/@hadiakhojasteh/how-to-build-an-intelligent-car-with-image-processing-rkgz4q8v37xg
یادگیری عمیقشبکه عصبی مصنوعیهوش مصنوعیبینایی کامپیوتریادگیری ماشین
معمار نرم افزار، پژوهشگر یادگیری ماشین، زبان و بینایی کامپیوتر، عاشق سفر و خلق تجربیات جدید
شاید از این پست‌ها خوشتان بیاید