تشخیص اشیا در پایتون — راهنمای کاربردی

۲۷۸۸ بازدید
آخرین به‌روزرسانی: ۰۷ اسفند ۱۴۰۲
زمان مطالعه: ۲۲ دقیقه
تشخیص اشیا در پایتون — راهنمای کاربردی

در چند سال اخیر، فناوری‌های مبتنی بر «تشخیص اشیا» (Object Detection) به سرعت در حال یکپارچه شدن با دستگاه‌های الکترونیکی نظیر تلفن‌های همراه، دوربین‌های دیجیتال و فرایندهای صنعتی هستند. همچنین، الگوریتم‌های تشخیص اشیا به بخش جداناپذیری از فناوری‌های پیشرفته‌ای نظیر «اتومبیل‌های خوران» (Self-Driving Automobiles | Autonomous Vehicle)، «احراز هویت بیومتریک» (Biometric Authentication) و سایر موارد تبدیل شده‌اند.

فناوری‌های مبتنی بر تشخیص اشیا، در حال محکم کردن جای پای خود در دنیای فناوری و «گجت‌های» (Gadgets) دیجیتال هستند. اگر شما جزء آن دسته از کاربرانی هستید که برای باز کردن گوشی تلفن همراه خود از دوربین تلفن و امکاناتی نظیر Face Unlock استفاده می‌کنید، در واقع در حال استفاده از فناوری‌های مبتنی بر تشخیص اشیا هستید. در صورتی که کاربران شبکه‌های اجتماعی برای گرفتن «سلفی» (Selfie) یا تماس تصویری، از «جلوه‌های» (Effect) خاصی نظیر قرار دادن عینک آفتابی روی صورت استفاده کنند، فناوری‌های مبتنی بر تشخیص اشیا را در تعاملات روزمره خود مورد استفاده قرار داده‌‌اند.

فناوری‌های پیشرفته دیگری نظیر «واقعیت افزوده» (Augmented Reality) نیز به طور مستقیم از تشخیص اشیا، جهت فراهم آوردن «تجربه همه جانبه» (Immersive Experience) از «واقعیت مجازی» (Virtual Reality)، برای کاربران خود استفاده می‌کنند. شاید بسیاری از کاربران با این واقعیت آشنا نباشند که ویژگی‌های جالبی که توسط فناوری تشخیص اشیا امکان‌پذیر می‌شوند، در اصل، توسط دسته خاصی از الگوریتم‌های «شبکه‌های عصبی مصنوعی» (Artificial Neural Networks) امکان‌پذیر شده‌اند که نه تنها قادر به تشخیص چهره در تصویر یا ویدئو هستند، بلکه این توانایی را دارند که اجزای مختلف چهره و جایگاه هر کدام از آن‌ها در چهره را نیز تشخیص دهند.

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

در این مطلب، ابتدا با مفاهیمی نظیر «تشخیص اشیا» (Object Detection) و «بینایی کامپیوتر» (Computer Vision) آشنا خواهید شد. سپس، مراحل لازم برای پیاده‌سازی یک سیستم تشخیص اشیا ارائه خواهد شد. برای پیاده‌سازی سیستم تشخیص اشیا در «زبان برنامه‌نویسی پایتون» (Python Programming Language)، از چالش Google AI Open Image که به میزبانی Kaggle برگزار می‌شود استفاده شده است. هدف این چالش، توسعه یک سیستم تشخیص اشیا است که بتواند اشیاء مختلف را در تصاویر مختلف و بعضا پیچیده تشخیص دهد.

تشخیص اشیا

اگر قرار باشد یک تعریف مشخصی از فناوری تشخیص اشیا ارائه شود، این دسته از فناوری‌ها را می‌توان در قالب فناوری‌ها و سیستم‌های کامپیوتری تعریف کرد که مجموعه‌ای از وظایف مرتبط با حوزه‌های بینایی کامپیوتر (پردازش کامپیوتری تصاویر و ویدئو و درک محتوای آ‌ن‌ها) و «پردازش تصویر» (Image Processing) را «خودکارسازی» (Automate) می‌کنند. به این دسته از فناوری‌ها که کامپیوتر‌ها را قادر به «دیدن» می‌سازند، «بینایی کامپیوتر» (Computer Vision) گفته می‌شود. به عبارت دیگر، تشخیص اشیا زیر مجموعه فناوری‌ها و سیستم‌های کامپیوتری هستند که در حوزه بینایی کامپیوتر و پردازش تصویر فعالیت دارند.

در روش‌های تشخیص اشیا، هدف تشخیص نمونه‌ها یا اشیاء مرتبط با یک کلاس خاص (به عنوان نمونه، انسان، ساختمان، اتومبیل‌ها و سایر موارد) در تصاویر و ویدئوهای دیجیتالی است. تشخیص اشیا حوزه تحقیقاتی بسیار بزرگی است و تحقیقات بسیار زیادی در این زمینه انجام شده است؛ دامنه‌هایی نظیر «تشخیص چهره» (Face Detection) و «تشخیص عابر پیاده» (Pedestrian Detection) از جمله دامنه‌های تحقیقاتی پرطرفدار در حوزه تشخیص اشیا محسوب می‌شوند. سیستم‌های تشخیص اشیا کاربردهای فراوانی در حوزه‌های مختلف بینایی کامپیوتر نظیر «بازیابی تصویر» (Image Retrieval) و «نظارت ویدئویی» (Video Surveillance) دارند.

تشخیص اشیاء

مفاهیم مهم در سیستم‌های تشخیص اشیا

در سیستم‌های تشخیص اشیا، هدف «دسته‌بندی» (Classify) اشیاء موجود در تصویر، در مجموعه‌ای از «کلاس‌های» (Classes) از پیش تعیین شده است. هر کدام از کلاس‌های تعریف شده، مجموعه‌ای از «ویژگی‌های» (Features) مختص به خود دارند که به سیستم در دسته‌بندی اشیاء متعلق به این کلاس‌ها کمک می‌کنند. به عنوان، شکل هندسی دایره‌ها گرد است. بنابراین، هنگامی که سیستم به دنبال تشخیص دایره در ویدئو است، اشیائی که در فاصله خاصی از یک نقطه (مثلا مرکز) قرار دارند، جستجو می‌شوند. به طور مشابه، زمانی که سیستم به دنبال تشخیص مربع در تصویر است، اشیائی را جستجو می‌کند که در گوشه‌ها عمود هستند و اندازه اضلاع آن‌ها با یکدیگر برابر هستند.

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

روش‌های مهم تشخیص اشیا در تصاویر و ویدئوهای دیجیتال

مهم‌ترین روش‌های تشخیص اشیا، معمولا از رویکردهای مبتنی بر «یادگیری ماشین» (Machine Learning) و یا مدل‌های مبتنی بر «یادگیری عمیق» (Deep Learning) استفاده می‌کنند.

در رویکردهای مبتنی بر یادگیری ماشین، بسیار حیاتی است که ابتدا ویژگی‌های مرتبط با اشیاء موجود در تصویر، با استفاده از روش‌های خاصی نظیر روش‌های زیر استخراج شوند:

سپس در مرحله بعد، از یکی روش‌های شناخته شده یادگیری ماشین، نظیر «ماشین بردار پشتیبان» (Support Vector Machine)، استفاده می‌شود تا اشیاء در کلاس‌های از پیش تعیین شده دسته‌بندی شوند. در سمت مقابل، مدل‌های یادگیری عمیق امکان «تشخیص اشیا نقطه به نقطه» (ٍEnd-to-End Object Detection) را برای محققان یادگیری ماشین فراهم می‌کنند. چنین روش‌هایی از این جهت حائز اهمیت هستند که قابلیت تشخیص اشیا، بدون تعریف صریح ویژگی‌های مرتبط با هر کدام از کلاس‌های تعریف شده از اشیاء، برای سیستم پدید می‌آید. این دسته از مدل‌های تشخیص اشیا، معمولا مبتنی بر «شبکه‌های عصبی پیچشی» (Convolutional Neural Network) هستند. مهم‌ترین سیستم‌های تشخیص اشیا مبتنی بر یادگیری عمیق عبارتند از:

  • روش‌های Region Proposals (که نواحی دربرگیرنده اشیاء در تصویر را شناسی می‌کنند) نظیر R-CNN ،Fast R-CNN و Faster R-CNN.
  • روش Single Shot MultiBox Detector یا SSD.
  • روش‌‎های شناخته شده You Only Look Once یا YOLO.

تشخیص اشیاء

بینایی کامپیوتر

بینایی کامپیوتر، یک حوزه «بین رشته‌ای» (Interdisciplinary) در علوم کامپیوتر و «هوش مصنوعی» (Artificial Intelligence) محسوب می‌شود. این حوزه با چگونگی ایجاد درک سطح بالا از تصاویر و ویدئوهای دیجیتال، توسط سیستم‌های کامپیوتری سر و کار دارد. از دیدگاه مهندسی، هدف نهایی سیستم‌های بینایی کامپیوتر، «خودکارسازی» (Automation) وظایف قابل انجام توسط سیستم بینایی انسان است.

به عنوان یکی از شاخه‌های علمی حوزه علوم کامپیوتر و هوش مصنوعی،  وظیفه سیستم‌های بینایی کامپیوتر استخراج، تحلیل و درک خودکار اطلاعات مفید از یک تصویر ایستا یا دنباله‌ای از تصاویر است. حوزه بینایی کامپیوتر با توسعه پایه‌های نظری و الگوریتم-محور لازم، جهت دستیابی به «درک بصری خودکار» (Automatic Visual Understanding) از تصاویر و ویدئوهای دیجیتال سر و کار دارد.

به عبارت دیگر، از دیدگاه علمی، بینایی کامپیوتر با نظریه‌ها، الگوریتم‌ها و رویکردهای قابل استفاده در سیستم‌های هوش مصنوعی جهت استخراج، تحلیل و درک تصاویر دیجیتالی سر و کار دارد. تصاویر دیجیتالی می‌توانند فرم‌های مختلفی به خود بگیرند؛ دنباله‌های ویدئویی، چشم‌انداز از دید دوربین‌های مختلف یا داده‌های «چندبُعدی» (Multi-Dimensional) به دست آمده از اسکنرهای پزشکی. با این حال از دیدگاه فناوری، هدف بینایی کامپیوتر به کارگیری نظریه‌ها، الگوریتم‌های و مدل‌های مطرح شده در حوزه بینایی کامپیوتر (و به طور گسترده‌تر، حوزه هوش مصنوعی) جهت ساختن سیستم‌های بینایی کامپیوتر است.

تشخیص اشیاء

وظایف سیستم‌های بینایی کامپیوتر

از جمله مهم‌ترین وظایف قابل تعریف در سیستم‌های بینایی کامپیوتر، می‌توان به توسعه روش‌هایی برای «اکتساب» (Acquire)، «پردازش» (Process)، «تحلیل» (Analyze) و «درک» (Understand) تصاویر دیجیتالی اشاره کرد. همچنین، استخراج داده‌های با ابعاد بالا از جهان واقعی جهت تولید اطلاعات عددی یا «نمادین» (Symbolic)، به عنوان نمونه در قالب تصمیم قابل اتخاذ توسط سیستم، از جمله دیگر وظایف قابل تعریف در سیتم‌های بینایی کامپیوتر محسوب می‌شوند.

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

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

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

  • سیستم‌های «بازسازی صحنه» (Scene Reconstruction)
  • سیستم‌های «دسته‌بندی تصاویر» (Image Classification)
  • سیستم‌های «تشخیص رویداد» (Event Detection)
  • سیستم‌های «ردیابی ویدئویی» (Video Tracking)
  • سیستم‌های «تخمین حالت سه‌بُعدی» (3D Pose Estimation)
  • سیستم‌های «تخمین حرکت» (Motion Estimation)
  • سیستم‌های «ترمیم تصاویر دیجیتالی»
  • سیستم‌های «بازشناسی و تشخیص اشیا» (Object Detection and Recognition)
  • سیستم‌های «نظارت بصری» (Visual Surveillance)
  • سیستم‌های «ناوبری» (Navigation) در اتومبیل‌های خودران یا «روبات‌های متحرک» (Mobile Robot)
  • سیستم‌های «شاخص‌گذاری تصاویر و ویدئوهای دیجیتالی» (Digital Image and Video Indexing)

در سال‌های اخیر، به دلیل جهش بی‌سابقه در قدرت محاسباتی سیستم‌های کامپیوتری (به ویژه سیستم‌های محاسبات مبتنی بر «واحدهای پردازش گرافیکی» (Graphical Processing Units | GPUs)) و امکان‌پذیر کردن توسعه مدل‌های یادگیری عمیق جهت پیاد‌ه‌‎سازی سیستم‌های بینایی کامپیوتر، استفاده از مدل‌های بینایی کامپیوتر به امری معمولی تبدیل شده است. بسیاری از شرکت‌های معروف حوزه فناوری نظیر آمازون، گوگل، تسلا، فیسبوک و مایکروسافت، سرمایه‌گذاری‌های هنگفتی در این فناوری و کاربردهای آن انجام داده‌اند.

در این مطلب، روی دو وظیفه (دامنه کاربردی) عمده در سیستم‌های بینایی کامپیوتر تمرکز خواهد شد؛ دسته‌بندی تصاویر و تشخیص اشیا در تصاویر.

سیستم‌های دسته‌بندی تصاویر روی دسته‌بندی (گروه‌بندی) تصاویر در طبقه‌ها یا کلاس‌های از پیش تعیین شده تمرکز دارند. برای پیاده‌سازی چنین سیستم‌هایی، ابتدا باید تصاویری که در کلاس‌های مورد نظر دسته‌بندی می‌شوند، در اختیار سیستم قرار داده شود. سپس، سیستم با استفاده از این تصاویر «آموزش» (Train) داده می‌شود. مدل آموزش داده شده قادر خواهد بود تا با تحلیل «ویژگی‌های» (Features) تصویر، کلاس یا طبقه تصاویر را مشخص کند. به عنوان نمونه، در صورتی که تصویر حاوی گربه وارد سیستم شود، آن را در کلاس گربه دسته‌بندی می‌کند.

تشخیص اشیاء

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

تشخیص اشیاء

در این مطلب و برای پیاده‌سازی سیستم تشخیص اشیا، از چالش Google AI Open Image که به میزبانی Kaggle برگزار می‌شود استفاده شده است. هدف این چالش، تشخیص اشیا گوناگون، در تصاویر مختلف و بعضا پیچیده است. در این چالش، از یک مجموعه داده متشکل از 1٫۷ میلیون تصویر استفاده شده است. اشیاء موجود در تصاویر این مجموعه داده، به وسیله 12 میلیون «کادر محصور کننده» (Bounding Box) در 500 کلاس مختلف دسته‌بندی شده‌اند ( به هر کدام از تصاویر موجود در مجموعه داده، چندین کادر محصور کننده برای تشخیص اشیا مشخص شده است).

از جمله مهم‌ترین ویژگی‌های این مجموعه داده، می‌توان به موارد زیر اشاره کرد:

  • 12 میلیون «کادر محصور کننده» (Bounding Box) برای دسته‌بندی 1٫۷ میلیون تصویر در 500 کلاس مختلف.
  • تصاویر با صحنه‌های پیچیده که در برگیرنده چندین شیء مختلف هستند؛ به طور متوسط 7 کادر محصور کننده به ازاء هر تصویر.
  • تصاویر بسیار متنوع که حاوی اشیاء مختلف و متمایز هستند.
  • سلسله مراتبی مناسب برای کلاس‌ها، که منعکس کننده روابط میان کلاس‌های این مجموعه داده است.

تشخیص اشیاء

تشخیص اشیاء

این مجموعه داده، از طریق لینک [+] قابل دانلود است.

تحلیل اکتشافی داده‌ها

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

تشخیص اشیاء

با بررسی اجمالی تصاویر آموزشی مشخص می‌شود که تناوب برخی از کلاس‌های موجود در مجموعه داده، به مراتب بالاتر از سایر کلاس‌ها است. نمودار بالا، توزیع 43 کلاس متناوب در مجموعه داده Open Image را نشان می‌دهد. همانطور که مشاهده می‌شود، توزیع نمونه‌های موجود در کلاس‌های مختلف نابرابر است؛ مشکلی که برای آموزش بهینه سیستم تشخیص اشیا، به نحوی باید برطرف شود. برای متعادل کردن تناوب داده‌های آموزشی هر کلاس، رویه زیر اتخاذ شده است:

  • برای آموزش سیستم تشخیص اشیا، تنها از داده‌های موجود در 43 کلاس متناوب در مجموعه داده Open Image استفاده می‌شود (در مجموع، 300 هزار تصویر در این 43 کلاس وجود دارند).
  • برای متعادل کردن تناوب داده‌های آموزشی هر کلاس، از هر کلاس تنها 400 تصویر به طور تصادفی انتخاب و در مجموعه آموزشی قرار داده می‌شود (در مجموع، 17200 تصویر برای پیاده‌سازی سیستم تشخیص اشیا استفاده شده است).

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

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

به دلیل محدودیت‌های محاسباتی و زمانی، تصمیمات زیر جهت طراحی و پیاده شبکه عصبی (برای کاربرد تشخیص اشیا) اتخاذ شد:

  1. از یک مدل YOLO V2 که پیش از این برای شناسایی اشیاء خاصی آموزش دیده شده است، استفاده می‌شود (یک مدل یادگیری عمیق از پیش آموزش داده شده).
  2. از قدرت مفهوم «یادگیری انتقال» (Transfer Learning) استفاده می‌شود و لایه کانولوشن (پیچشی) آخر مدل YOLO دوباره آموزش داده می‌شود تا سیستم تشخیص اشیا بتواند اشیائی را که پیش از با آن‌ها برخورد نداشته است (Unseen Objects)، نظیر گیتار، خانه، مرد، زن، پرنده و سایر موارد، تشخیص دهد.

مشخصات ورودی‌های مدل YOLO برای تشخیص اشیا

الگوریتم YOLO برای اینکه بتواند اشیاء موجود در تصویر را تشخیص دهد، ورودی‌های خاصی را می‌پذیرد:

  1. ابعاد تصاویر ورودی: شبکه YOLO به گونه‌ای طراحی شده است تا با تصاویری که ابعاد مشخصی دارند آموزش ببیند. ابعاد تصویر استفاده شده برای آموزش شبکه YOLO، برابر با 608x608 است.
  2. تعداد کلاس‌ها: برابر 43 کلاس است. تعداد کلاس‌ها، پارامتری است که برای تعریف ابعاد خروجی‌های شبکه YOLO مورد نیاز است.
  3. پارامترهای Anchor Box: تعداد کادرهای محصور کننده یا Bounding Box و همچنین ابعاد بیشینه و کمینه آن‌ها؛ به مجموعه این اطلاعات، پارامترهای Anchor Box گفته می‌شود.
  4. حد آستانه برای معیارهای IoU (معیار Intersection over Union) و ضریب اطمینان (Confidence): این حد آستانه به این دلیل تعریف شده است تا مشخص شود کدام یک از کادرهای محصور کننده، باید به عنوان کادرهای در بر گیرنده اشیاء موجود در تصویر انتخاب شوند (انتخاب میان کادرهای محصور کننده).
  5. اسامی تصاویر به همراه اطلاعات پارامترهای Anchor Box: به ازاء هر تصویر، نیاز است تا اطلاعاتی همانند اطلاعات تعبیه شده در شکل زیر در اختیار شبکه YOLO قرار گرفته شود.

تشخیص اشیاء

قطعه کد لازم برای تولید ورودی‌های شبکه YOLO در ادامه نمایش داده شده است:

1LABELS = ['Shirt', 'Trousers', 'Swimwear', 'Tie', 'Bus', 'Truck', 'Train', 'Motorcycle', 'Helmet', 'Shorts', 'Airplane', 
2         'Sunglasses', 'Jacket', 'Dress', 'Human eye', 'Suit', 'Footwear', 'Woman', 'Human face', 'Man', 'Human arm', 
3          'Human head','Human hand', 'Human leg', 'Human nose', 'Human mouth', 'Human ear', 'Human beard', 'Human foot', 'Car',
4          'Wheel', 'Boat', 'House', 'Bird', 'Guitar', 'Fast food', 'Hat', 'Dog', 'Laptop', 'Beer', 'Cat', 'Lantern', 'Fountain']
5
6# Setting the input image size to 608 X 608
7IMAGE_H, IMAGE_W = 608, 608
8
9# We wil use 19X19 grids for our images. This will lead us to a total of 608/19 = 32 grids for an image
10GRID_H,  GRID_W  = 19 , 19
11BOX              = 5
12# Getting the total number of classes/labels we will be predicting.
13CLASS            = len(LABELS)
14
15# Assigning 1's to all class labels
16CLASS_WEIGHTS    = np.ones(CLASS, dtype='float32')
17
18# Pr (object in class) * Pr (class of the object) < Obj_threshold, then it disregards this anchor box
19OBJ_THRESHOLD    = 0.3#0.5
20
21# If there are many overlapping boxes and IOU is > NMS_thereshold, then we will drop the one with a lower probability. 
22NMS_THRESHOLD    = 0.3#0.45
23
24# Anchor Boxes Dimensions
25ANCHORS          = [0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828]
26
27NO_OBJECT_SCALE  = 1.0
28OBJECT_SCALE     = 5.0
29COORD_SCALE      = 1.0
30CLASS_SCALE      = 1.0
31
32BATCH_SIZE       = 16
33WARM_UP_BATCHES  = 0
34TRUE_BOX_BUFFER  = 50

معماری شبکه YOLO V2

معماری شبکه YOLO V2 در شکل زیر نمایش داده شده است. این شبکه، از 23 لایه کانولوشن (پیچشی) تشکیل شده است؛ هر کدام از این لایه‌ها، واحد «نرمال‌سازی دسته‌ای» (Batch Normalization)، تابع فعال‌سازی Leaky RELU و واحد Max Pooling مختص به خود را دارد.

تشخیص اشیاء

هدف لایه‌های تعریف شده، استخراج چندین ویژگی مهم از تصاویر دیجیتالی است تا از این طریق، سیستم تشخیص اشیا قادر باشد اشیاء مختلف موجود در تصویر را تشخیص دهد و آن‌ها در کلاس‌های متناظر دسته‌بندی کند. با هدف تشخیص اشیا موجود در تصویر، الگوریتم YOLO تصویر را به یک گرید (Grid) متشکل از سلول‌های 19x19 تقسیم‌بندی می‌کند؛ به ازاء هر سلول تشکیل شده در گرید، پنج کادر محصور کننده با ابعاد متفاوت تعریف می‌شود. سپس شبکه YOLO تلاش می‌کند تا کلاس اشیاء موجود در سلول‌های گریدی را تشخیص دهد؛ به عبارت دیگر، احتمال تعلق هر کدام از اشیاء شناسایی شده (درون کادرهای محصور کننده هر سلول) به کلاس‌های موجود در مجموعه داده محاسبه می‌شود.

هر کدام از کادرهای محصور کننده، ابعاد و اشکال متفاوتی نسبت به یکدیگر دارند و در اصل ، برای تشخیص دادن اشیاء گوناگون (با شکل‌ها و ابعاد مختلف) در هر یک از سلول‌های گریدی طراحی شده‌اند. خروجی الگوریتم YOLO ماتریسی به شکل زیر است؛ به ازاء هر کدام از کادرهای محصور کننده تعریف شده (در هر کدام از سلول‌های گریدی)، ماتریسی مشابه شکل زیر تولید خواهد شد.

تشخیص اشیاء

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

تشخیص اشیاء

این ماتریس اطلاعات بسیار مهمی نظیر «احتمال مشاهده شدن یک شیء در هر یک از کادرهای محصور کننده» (Probabilities of Observing an Object for Each Anchor Box) و احتمال تعلق شیء شناسایی شده در کارد محصور کننده، به هر کدام از کلاس‌های از پیش تعریف شده را، در اختیار قرار می‌دهد. برای اینکه کادرهای بدون شیء (کادرهایی که هیچ شیء خاصی در آن‌ها وجود ندارد)، کادرهایی که شیء شناسایی شده در آن‌ها در هیچ کلاسی دسته‌بندی نمی‌شود یا کادرهایی که شیء شناسایی شده در آن‌ها با کادرهای دیگر هم‌پوشانی دارند، فیلتر شوند ار دو حد آستانه زیر استفاده می‌شود:

  • حد آستانه IoU: برای فیلتر کردن کادرهایی به کار می‌رود که یک شیء واحد و یکسان در آن‌ها شناسایی شده است.
  • حد آستانه ضریب اطمینان (Confidence): برای فیلتر کردن کادرهایی به کار می‌روند، احتمال تعلق آن‌ها به کلاس‌های مختلف  بسیار پایین است.

قطعه کد زیر، نحوه تعریف لایه‌های مختلف شبکه YOLO جهت تشخیص اشیا را نشان می‌دهد:

1input_image = Input(shape=(IMAGE_H, IMAGE_W, 3))
2true_boxes  = Input(shape=(1, 1, 1, TRUE_BOX_BUFFER , 4))
3
4# Layer 1
5x = Conv2D(32, (3,3), strides=(1,1), padding='same', name='conv_1', use_bias=False)(input_image)
6x = BatchNormalization(name='norm_1')(x)
7x = LeakyReLU(alpha=0.1)(x)
8x = MaxPooling2D(pool_size=(2, 2))(x)
9
10# Layer 2
11x = Conv2D(64, (3,3), strides=(1,1), padding='same', name='conv_2', use_bias=False)(x)
12x = BatchNormalization(name='norm_2')(x)
13x = LeakyReLU(alpha=0.1)(x)
14x = MaxPooling2D(pool_size=(2, 2))(x)
15
16# Layer 3
17x = Conv2D(128, (3,3), strides=(1,1), padding='same', name='conv_3', use_bias=False)(x)
18x = BatchNormalization(name='norm_3')(x)
19x = LeakyReLU(alpha=0.1)(x)
20
21# Layer 4
22x = Conv2D(64, (1,1), strides=(1,1), padding='same', name='conv_4', use_bias=False)(x)
23x = BatchNormalization(name='norm_4')(x)
24x = LeakyReLU(alpha=0.1)(x)
25
26# Layer 5
27x = Conv2D(128, (3,3), strides=(1,1), padding='same', name='conv_5', use_bias=False)(x)
28x = BatchNormalization(name='norm_5')(x)
29x = LeakyReLU(alpha=0.1)(x)
30x = MaxPooling2D(pool_size=(2, 2))(x)
31
32# Layer 6
33x = Conv2D(256, (3,3), strides=(1,1), padding='same', name='conv_6', use_bias=False)(x)
34x = BatchNormalization(name='norm_6')(x)
35x = LeakyReLU(alpha=0.1)(x)
36
37# Layer 7
38x = Conv2D(128, (1,1), strides=(1,1), padding='same', name='conv_7', use_bias=False)(x)
39x = BatchNormalization(name='norm_7')(x)
40x = LeakyReLU(alpha=0.1)(x)
41
42# Layer 8
43x = Conv2D(256, (3,3), strides=(1,1), padding='same', name='conv_8', use_bias=False)(x)
44x = BatchNormalization(name='norm_8')(x)
45x = LeakyReLU(alpha=0.1)(x)
46x = MaxPooling2D(pool_size=(2, 2))(x)
47
48# Layer 9
49x = Conv2D(512, (3,3), strides=(1,1), padding='same', name='conv_9', use_bias=False)(x)
50x = BatchNormalization(name='norm_9')(x)
51x = LeakyReLU(alpha=0.1)(x)
52
53# Layer 10
54x = Conv2D(256, (1,1), strides=(1,1), padding='same', name='conv_10', use_bias=False)(x)
55x = BatchNormalization(name='norm_10')(x)
56x = LeakyReLU(alpha=0.1)(x)
57
58# Layer 11
59x = Conv2D(512, (3,3), strides=(1,1), padding='same', name='conv_11', use_bias=False)(x)
60x = BatchNormalization(name='norm_11')(x)
61x = LeakyReLU(alpha=0.1)(x)
62
63# Layer 12
64x = Conv2D(256, (1,1), strides=(1,1), padding='same', name='conv_12', use_bias=False)(x)
65x = BatchNormalization(name='norm_12')(x)
66x = LeakyReLU(alpha=0.1)(x)
67
68# Layer 13
69x = Conv2D(512, (3,3), strides=(1,1), padding='same', name='conv_13', use_bias=False)(x)
70x = BatchNormalization(name='norm_13')(x)
71x = LeakyReLU(alpha=0.1)(x)
72
73skip_connection = x
74
75x = MaxPooling2D(pool_size=(2, 2))(x)
76
77# Layer 14
78x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_14', use_bias=False)(x)
79x = BatchNormalization(name='norm_14')(x)
80x = LeakyReLU(alpha=0.1)(x)
81
82# Layer 15
83x = Conv2D(512, (1,1), strides=(1,1), padding='same', name='conv_15', use_bias=False)(x)
84x = BatchNormalization(name='norm_15')(x)
85x = LeakyReLU(alpha=0.1)(x)
86
87# Layer 16
88x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_16', use_bias=False)(x)
89x = BatchNormalization(name='norm_16')(x)
90x = LeakyReLU(alpha=0.1)(x)
91
92# Layer 17
93x = Conv2D(512, (1,1), strides=(1,1), padding='same', name='conv_17', use_bias=False)(x)
94x = BatchNormalization(name='norm_17')(x)
95x = LeakyReLU(alpha=0.1)(x)
96
97# Layer 18
98x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_18', use_bias=False)(x)
99x = BatchNormalization(name='norm_18')(x)
100x = LeakyReLU(alpha=0.1)(x)
101
102# Layer 19
103x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_19', use_bias=False)(x)
104x = BatchNormalization(name='norm_19')(x)
105x = LeakyReLU(alpha=0.1)(x)
106
107# Layer 20
108x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_20', use_bias=False)(x)
109x = BatchNormalization(name='norm_20')(x)
110x = LeakyReLU(alpha=0.1)(x)
111
112# Layer 21
113skip_connection = Conv2D(64, (1,1), strides=(1,1), padding='same', name='conv_21', use_bias=False)(skip_connection)
114skip_connection = BatchNormalization(name='norm_21')(skip_connection)
115skip_connection = LeakyReLU(alpha=0.1)(skip_connection)
116skip_connection = Lambda(space_to_depth_x2)(skip_connection)
117
118x = concatenate([skip_connection, x])
119
120# Layer 22
121x = Conv2D(1024, (3,3), strides=(1,1), padding='same', name='conv_22', use_bias=False)(x)
122x = BatchNormalization(name='norm_22')(x)
123x = LeakyReLU(alpha=0.1)(x)
124
125# Layer 23
126x = Conv2D(BOX * (4 + 1 + CLASS), (1,1), strides=(1,1), padding='same', name='conv_23')(x)
127output = Reshape((GRID_H, GRID_W, BOX, 4 + 1 + CLASS))(x)
128
129# small hack to allow true_boxes to be registered when Keras build the model 
130# for more information: https://github.com/fchollet/keras/issues/2790
131output = Lambda(lambda args: args[0])([output, true_boxes])
132
133model = Model([input_image, true_boxes], output)

یادگیری انتقال

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

به عنوان نمونه، شبکه عصبی از پیش آموزش داده شده که در این مطلب استفاده شده است، چیزی حدود 50 میلیون پارامتر وزن دارد. یادگیری چنین مدلی در پلتفرم‌های قدرتمند محاسبات ابری نظیر Google Cloud، حداقل به 4 الی 5 روز زمان نیاز دارد. برای اینکه از مفهوم یادگیری انتقال، با موفقیت، برای آموزش دوباره شبکه عصبی (روی داده‌های جدید) استفاده شود، لازم است که برخی از پارامترها و تنظیمات مدل به‌روز رسانی شوند تا مدل آموزش از پیش داده شده بتواند خود را با داده‌های جدید وفق دهد:

  • ابعاد تصاویر ورودی: ابعاد تصاویر ورودی در مدل YOLO از پیش آموزش داده شده، برابر با 416x416 است. از آن جایی که تصاویر استفاده شده در این مطلب، ابعاد بزرگتری نسبت به تصاویر استفاده شده در مدل YOLO از پیش آموزش داده شده دارند و همچنین، ابعاد برخی از اشیائی که قرار است شناسایی شوند بسیار کوچک است (نظیر کفش، پرنده و سایر موارد)، منطقی نیست که ابعاد تصاویر جدید تا ابعاد 416x416 کاهش پیدا کنند. به همین خاطر، ابعاد تصاویر جدید برای آموزش دوباره مدل YOLO، برابر با 608x608 در نظر گرفته شده است.
  •  اندازه گرید (Grid): در مدل YOLO از پیش آموزش داده شده، ابعاد سلول‌های گرید برابر با 13x13 است. در این مطلب، ابعاد سلول‌های گرید، جهت آموزش دوباره مدل YOYO، به 19x19 تغییر پیدا کرده است.
  • لایه خروجی: تعدادکلاس‌ها در مدل YOLO از پیش آموزش داده شده، برابر با 80 است. در حالی که برای آموزش دوباره مدل، از داده‌های 43 کلاس استفاده شده است. بنابراین، لازم است تغییراتی در ابعاد لایه خروجی ایجاد شود تا سیستم بتواند خود را با کلاس‌های جدید، داده‌های آن‌ها و الگوهای موجود در آن‌ها وفق دهد.

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

1#from utils.utils import WeightReader
2weight_reader = WeightReader(wt_path)
3
4weight_reader.reset()
5nb_conv = 23
6
7for i in range(1, nb_conv+1):
8    conv_layer = model.get_layer('conv_' + str(i))
9    
10    if i < nb_conv:
11        norm_layer = model.get_layer('norm_' + str(i))
12        
13        size = np.prod(norm_layer.get_weights()[0].shape)
14        
15        beta  = weight_reader.read_bytes(size)
16        gamma = weight_reader.read_bytes(size)
17        mean  = weight_reader.read_bytes(size)
18        var   = weight_reader.read_bytes(size)
19
20        weights = norm_layer.set_weights([gamma, beta, mean, var])       
21        
22    if len(conv_layer.get_weights()) > 1:
23        bias   = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[1].shape))
24        kernel = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[0].shape))
25        kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))
26        kernel = kernel.transpose([2,3,1,0])
27        
28        conv_layer.set_weights([kernel, bias])
29        
30    else:
31        kernel = weight_reader.read_bytes(np.prod(conv_layer.get_weights()[0].shape))
32        kernel = kernel.reshape(list(reversed(conv_layer.get_weights()[0].shape)))
33        kernel = kernel.transpose([2,3,1,0])
34        conv_layer.set_weights([kernel])
35
36# Transfer Learning - Re-initialize the Weights of the Last Convolutional Layer of YOLO
37layer   = model.layers[-4] # the last convolutional layer
38weights = layer.get_weights()
39
40new_kernel = np.random.normal(size=weights[0].shape)/(GRID_H*GRID_W)
41new_bias   = np.random.normal(size=weights[1].shape)/(GRID_H*GRID_W)
42
43layer.set_weights([new_kernel, new_
44

تابع «هزینه» (Cost) یا «زیان» (Loss)

در مسائل مرتبط با تشخیص اشیا در تصویر، هدف شناسایی درست کلاس اشیاء، با بیشترین احتمال یا ضریب اطمینان (Confidence) ممکن است.

تابع هزینه برای یک سیستم تشخیص اشیا از سه مؤلفه تشکیل شده است:

  • زیان دسته‌بندی (Classification Loss): در صورتی که یک شیء در تصویر تشخیص داده شده باشد، این مؤلفه، «مربع خطای» (Squared Error) احتمال شرطی کلاس را محاسبه می‌کند. بنابراین، تابع زیان تنها در صورتی که یک شیء در یک سلول گریدی وجود داشته باشد، برای خطای انجام شده در دسته‌بندی، جریمه در نظر می‌گیرد.
  • زیان محلی‌سازی (Localization Loss): این مؤلفه، در صورتی که کاردهای محصور کننده مسئول تشخیص شیء در تصویر باشند، مربع خطای مرتبط با «اندازه و مکان کادر محصورسازی مسئول تشخیص شیء» را نسبت به «اندازه و مکان کادر محصور کننده در «پاسخ‌های صحیح مبنا» (Ground Truth)» محاسبه می‌کند. جهت مشخص کردن جریمه خطاهای حاصل از مختصات مکانی کاردهای محصور کننده، از یک پارامتر regularization استفاده می‌شود.
  • زیان ضریب اطمینان (Confidence Loss):  این مؤلفه، مربع خطای ضریب اطمینان کادر محصور کننده را محاسبه می‌کند. از آنجایی که تمامی کادرهای محصور کننده تعریف شده، در تشخیص یک شیء در تصویر دخالت ندارند، معادله محاسبه زیان در این مؤلفه به دو بخش تقسیم می‌شود؛ بخش اول، برای کادرهای محصور کننده‌ای که مسئول تشخیص اشیا موجود در تصویر هستند و بخش دوم، برای بقیه کادرهای محصور کننده.

مزیت عمده مدل YOLO نسبت به مدل‌های مشابه تشخیص اشیا این است که خطاهایی توسط این مدل محاسبه می‌شوند که به راحتی توسط «توابع بهینه‌سازی» (Optimization Functions) معروف نظیر «گرادیان کاهشی تصادفی» (Stochastic Gradient Descent | SGD)، گرادیان کاهشی تصادفی با پارامتر Momentum و بهینه‌ساز Adam قابل بهینه‌سازی هستند.

قطعه کد زیر برای محاسبه تابع هزینه یا زیان استفاده می‌شود:

1def custom_loss(y_true, y_pred):
2    mask_shape = tf.shape(y_true)[:4]
3    
4    cell_x = tf.to_float(tf.reshape(tf.tile(tf.range(GRID_W), [GRID_H]), (1, GRID_H, GRID_W, 1, 1)))
5    cell_y = tf.transpose(cell_x, (0,2,1,3,4))
6
7    cell_grid = tf.tile(tf.concat([cell_x,cell_y], -1), [BATCH_SIZE, 1, 1, 5, 1])
8    
9    coord_mask = tf.zeros(mask_shape)
10    conf_mask  = tf.zeros(mask_shape)
11    class_mask = tf.zeros(mask_shape)
12    
13    seen = tf.Variable(0.)
14    total_recall = tf.Variable(0.)
15    
16    """
17    Adjust prediction
18    """
19    ### adjust x and y      
20    pred_box_xy = tf.sigmoid(y_pred[..., :2]) + cell_grid
21    
22    ### adjust w and h
23    pred_box_wh = tf.exp(y_pred[..., 2:4]) * np.reshape(ANCHORS, [1,1,1,BOX,2])
24    
25    ### adjust confidence
26    pred_box_conf = tf.sigmoid(y_pred[..., 4])
27    
28    ### adjust class probabilities
29    pred_box_class = y_pred[..., 5:]
30    
31    """
32    Adjust ground truth
33    """
34    ### adjust x and y
35    true_box_xy = y_true[..., 0:2] # relative position to the containing cell
36    
37    ### adjust w and h
38    true_box_wh = y_true[..., 2:4] # number of cells accross, horizontally and vertically
39    
40    ### adjust confidence
41    true_wh_half = true_box_wh / 2.
42    true_mins    = true_box_xy - true_wh_half
43    true_maxes   = true_box_xy + true_wh_half
44    
45    pred_wh_half = pred_box_wh / 2.
46    pred_mins    = pred_box_xy - pred_wh_half
47    pred_maxes   = pred_box_xy + pred_wh_half       
48    
49    intersect_mins  = tf.maximum(pred_mins,  true_mins)
50    intersect_maxes = tf.minimum(pred_maxes, true_maxes)
51    intersect_wh    = tf.maximum(intersect_maxes - intersect_mins, 0.)
52    intersect_areas = intersect_wh[..., 0] * intersect_wh[..., 1]
53    
54    true_areas = true_box_wh[..., 0] * true_box_wh[..., 1]
55    pred_areas = pred_box_wh[..., 0] * pred_box_wh[..., 1]
56
57    union_areas = pred_areas + true_areas - intersect_areas
58    iou_scores  = tf.truediv(intersect_areas, union_areas)
59    
60    true_box_conf = iou_scores * y_true[..., 4]
61    
62    ### adjust class probabilities
63    true_box_class = tf.argmax(y_true[..., 5:], -1)
64    
65    """
66    Determine the masks
67    """
68    ### coordinate mask: simply the position of the ground truth boxes (the predictors)
69    coord_mask = tf.expand_dims(y_true[..., 4], axis=-1) * COORD_SCALE
70    
71    ### confidence mask: penelize predictors + penalize boxes with low IOU
72    # penalize the confidence of the boxes, which have IOU with some ground truth box < 0.6
73    true_xy = true_boxes[..., 0:2]
74    true_wh = true_boxes[..., 2:4]
75    
76    true_wh_half = true_wh / 2.
77    true_mins    = true_xy - true_wh_half
78    true_maxes   = true_xy + true_wh_half
79    
80    pred_xy = tf.expand_dims(pred_box_xy, 4)
81    pred_wh = tf.expand_dims(pred_box_wh, 4)
82    
83    pred_wh_half = pred_wh / 2.
84    pred_mins    = pred_xy - pred_wh_half
85    pred_maxes   = pred_xy + pred_wh_half    
86    
87    intersect_mins  = tf.maximum(pred_mins,  true_mins)
88    intersect_maxes = tf.minimum(pred_maxes, true_maxes)
89    intersect_wh    = tf.maximum(intersect_maxes - intersect_mins, 0.)
90    intersect_areas = intersect_wh[..., 0] * intersect_wh[..., 1]
91    
92    true_areas = true_wh[..., 0] * true_wh[..., 1]
93    pred_areas = pred_wh[..., 0] * pred_wh[..., 1]
94
95    union_areas = pred_areas + true_areas - intersect_areas
96    iou_scores  = tf.truediv(intersect_areas, union_areas)
97
98    best_ious = tf.reduce_max(iou_scores, axis=4)
99    conf_mask = conf_mask + tf.to_float(best_ious < 0.6) * (1 - y_true[..., 4]) * NO_OBJECT_SCALE
100    
101    # penalize the confidence of the boxes, which are reponsible for corresponding ground truth box
102    conf_mask = conf_mask + y_true[..., 4] * OBJECT_SCALE
103    
104    ### class mask: simply the position of the ground truth boxes (the predictors)
105    class_mask = y_true[..., 4] * tf.gather(CLASS_WEIGHTS, true_box_class) * CLASS_SCALE       
106    
107    """
108    Warm-up training
109    """
110    no_boxes_mask = tf.to_float(coord_mask < COORD_SCALE/2.)
111    seen = tf.assign_add(seen, 1.)
112    
113    true_box_xy, true_box_wh, coord_mask = tf.cond(tf.less(seen, WARM_UP_BATCHES), 
114                          lambda: [true_box_xy + (0.5 + cell_grid) * no_boxes_mask, 
115                                   true_box_wh + tf.ones_like(true_box_wh) * np.reshape(ANCHORS, [1,1,1,BOX,2]) * no_boxes_mask, 
116                                   tf.ones_like(coord_mask)],
117                          lambda: [true_box_xy, 
118                                   true_box_wh,
119                                   coord_mask])
120    
121    """
122    Finalize the loss
123    """
124    nb_coord_box = tf.reduce_sum(tf.to_float(coord_mask > 0.0))
125    nb_conf_box  = tf.reduce_sum(tf.to_float(conf_mask  > 0.0))
126    nb_class_box = tf.reduce_sum(tf.to_float(class_mask > 0.0))
127    
128    loss_xy    = tf.reduce_sum(tf.square(true_box_xy-pred_box_xy)     * coord_mask) / (nb_coord_box + 1e-6) / 2.
129    loss_wh    = tf.reduce_sum(tf.square(true_box_wh-pred_box_wh)     * coord_mask) / (nb_coord_box + 1e-6) / 2.
130    loss_conf  = tf.reduce_sum(tf.square(true_box_conf-pred_box_conf) * conf_mask)  / (nb_conf_box  + 1e-6) / 2.
131    loss_class = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=true_box_class, logits=pred_box_class)
132    loss_class = tf.reduce_sum(loss_class * class_mask) / (nb_class_box + 1e-6)
133    
134    loss = loss_xy + loss_wh + loss_conf + loss_class
135    
136    nb_true_box = tf.reduce_sum(y_true[..., 4])
137    nb_pred_box = tf.reduce_sum(tf.to_float(true_box_conf > 0.5) * tf.to_float(pred_box_conf > 0.3))
138
139    """
140    Debugging code
141    """    
142    current_recall = nb_pred_box/(nb_true_box + 1e-6)
143    total_recall = tf.assign_add(total_recall, current_recall) 
144
145    loss = tf.Print(loss, [tf.zeros((1))], message='Dummy Line \t', summarize=1000)
146    loss = tf.Print(loss, [loss_xy], message='Loss XY \t', summarize=1000)
147    loss = tf.Print(loss, [loss_wh], message='Loss WH \t', summarize=1000)
148    loss = tf.Print(loss, [loss_conf], message='Loss Conf \t', summarize=1000)
149    loss = tf.Print(loss, [loss_class], message='Loss Class \t', summarize=1000)
150    loss = tf.Print(loss, [loss], message='Total Loss \t', summarize=1000)
151    loss = tf.Print(loss, [current_recall], message='Current Recall \t', summarize=1000)
152    loss = tf.Print(loss, [total_recall/seen], message='Average Recall \t', summarize=1000)
153    
154    return loss

قطعه کد زیر نیز، پارامترهای استفاده شده برای بهینه‌سازی تابع هدف را نشان می‌دهد.

1# Optimization Functions               
2optimizer = Adam(lr=0.5e-4, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
3#optimizer = SGD(lr=1e-4, decay=0.0005, momentum=0.9)
4#optimizer = RMSprop(lr=1e-4, rho=0.9, epsilon=1e-08, decay=0.0)
5
6model.compile(loss=custom_loss, optimizer=optimizer)
7
8model.fit_generator(generator        = train_batch, 
9                    steps_per_epoch  = int(len(train_batch)/16), 
10                    epochs           = 100, 
11                    verbose          = 1,
12                    validation_data  = valid_batch,
13                    validation_steps = int(len(valid_batch)/16),
14                    callbacks        = [early_stop, checkpoint,learning_rate_reduction],#, tensorboard], 
15                    max_queue_size   = 3)

دقت خروجی: mean Average Precision (امتیاز mAP)

معیارهای زیادی برای ارزیابی مدل‌های تشخیص اشیا ارائه شده است. در این مطلب، جهت ارزیابی سیستم تشخیص اشیا پیاده‌سازی شده از معیار «میانگین دقت متوسط» (mean Average Precision | mAP) استفاده شده است؛ این معیار، متوسط بیشینه مقادیر صحت (Precision) به ازاء مقادیر حساسیت (Recall) متفاوت را اندازه‌گیری می‌کند (برای تمامی مقادیر حد آستانه IoU). برای درک بهتر معیار mAP، ابتدا معیارهای صحت (Precision)، حساسیت (Recall) و IoU (معیار Intersection over Union) مورد بررسی قرار گرفته می‌شود.

معیارهای صحت (Precision) و حساسیت (Recall)

معیار صحت، درصد پیش‌بینی‌های مثبتی که به درستی به عنوان مثبت پیش‌بینی شده‌اند را محاسبه می‌کند. معیار حساسیت نیز نسبت «مثبت‌های صحیح» (True Positives) به تمامی خروجی‌های ممکن را محاسبه می‌کند. این دو معیار، ارتباط معکوسی با یکدیگر دارند.

تشخیص اشیاء

$$Recall = \frac { TP } { TP + FN }$$

$$Precision = \frac { TP } { TP + FP }$$

$$F1 = 2 \cdot \frac { Precision \cdot Recall } { Precision + Recall }$$

$$AP = \frac { 1 } { 1 1 } \Large \sum_ { r \in \left \{ 0 , 0.1 , . . . . . , 1 \right \} } AP_ { r } = \frac { 1 } { 1 1 } \Large \sum_ {r \in \left \{0 , 0.1 , . . . . . , 1 \right \} } P_ { Interp } ( r )$$

$$P_ { Interp } ( r ) = max_ { \widetilde { r } \; \geq \; r } \;p ( \widetilde { r } )$$

معیار Intersection over Union یا IOU

این معیار، میزان هم‌پوشانی میان دو «ناحیه» (Region) را اندازه‌گیری می‌کند؛ این مقدار برابر با، ناحیه حاصل از هم‌پوشانی این دو ناحیه، تقسیم بر، ناحیه حاصل از اجتماع این دو ناحیه است. این معیار در اصل، کیفیت پیش‌بینی‌های تولید شده توسط سیستم تشخیص اشیا را نسبت به پاسخ‌های صحیح مبنا (Ground Truth) نشان می‌دهد و آن‌ها را با یکدیگر مقایسه می‌کند.

$$I o U = \frac { Area \; of \; overlap } { Area \; of \; Union }$$

نتایج حاصل از تست سیستم تشخیص اشیا

در ادامه، نتایج حاصل از تست سیستم تشخیص اشیا روی تصاویر نمونه نمایش داده شده است.

تشخیص اشیاء

تشخیص اشیاء

تشخیص اشیا

تشخیص اشیاء

کدهای کامل پیاده‌سازی روش پیاده‌سازی سیستم تشخیص اشیا، با استفاده از مجموعه داده Open Images، از طریق لینک [+] قابل دسترسی است.

جمع‌بندی

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

در هنگام پیاده‌سازی چنین سیستم‌هایی، ابتدا از تمامی داده‌های موجود در 500 کلاس مجموعه داده Open Images استفاده شد. با این حال، پس از پایان مرحله آموزش مدل و در جریان تست مدل تشخیص اشیا مشخص شد که مدل آموزش داده شده قادر به پیش‌بینی کلاس صحیح بسیاری از تصاویر تست نبود. دلیل این امر این بود که فراوانی نمونه‌های موجود در کلاس‌های مختلف نابرابر بود؛ به عبارت دیگر مجموعه داده استفاده شده «نامتعادل» (Imbalance) بود.

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

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

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

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

  1. آموزش دادن مدل روی کلاس‌های بیشتر جهت تشخیص اشیا بیشتر و متنو‌ع‌تر در تصویر. برای رسیدن به این هدف نیاز است تا ابتدا مشکل نامتعادل بودن داده‌های آموزشی حل شود. یک راه حل محتمل برای رفع چنین نقیصه‌ای، جمع‌آوری یا تهیه تصاویر بیشتر از کلاس‌های نادر است (کلاس‌هایی که تعداد نمونه‌های موجود در آن‌ها کم است).
    • «افزودن داده» (Data Augmentation): در این روش، تصاویر موجود اندکی تغییر پیدا می‌کنند تا تصاویر جدیدی شکل بگیرد.
    • «نسخه‌برداری از تصاویر» (Image duplication): می‌توان از یک تصویر، چندین بار برای آموزش یک مدل استفاده کرد. چنین کاری، به سیستم کمک می‌کند تا بتواند رفتار داده‌های یک کلاس خاص را به شکل بهتری مدل کند.
    • روش‌های ترکیبی (Ensemble): یک روش دیگر این است که یک مدل تشخیص اشیا روی کلاس‌های متناوب در مجموعه داده آموزش داده شود و یک مدل دیگر، برای تشخیص اشیا خاص موجود در تصاویر (اشیائی که تشخیص آن‌ها سخت است و یا داده‌های کمی برای یادگیری تشخیص آن‌ها وجود دارد) مورد استفاده قرار بگیرد.
  2. علاوه بر این، این امکان وجود دارد تا مدل‌های مختلفی نظیر MobileNet ،VGG و سایر موارد (مدل‌های شبکه عصبی پیچشی که برای تشخیص اشیا مورد استفاده قرار می‌گیرند) را آموزش داد و سپس، آن‌ها را با یکدیگر ترکیب کرد (مدل‌های Ensemble).

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

لوگو ساناست
این مطلب با حمایت «ساناست» نوشته شده است.

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

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

کالا، خدمات و برند خود را در کادر «حامی مطالب» مجله فرادرس معرفی کنید.
کلیک کنید

^^

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
Towards Data ScienceKaggle
۵ دیدگاه برای «تشخیص اشیا در پایتون — راهنمای کاربردی»

بسیار عالی و مفهومی توضیح داده شد. تیتر مربوط به معیار دقت و صحت را از نظر انگلیسی اشتباه نوشته شده. در واقع recall یعنی نرخ یادگیری و precision هم نرخ صحت است و دقت هم می شود accuracy


با سلام و احترام؛

این مورد اصلاح شد.

از همراهی شما با مجله فرادرس سپاسگزاریم

عالی بود

وزن ها رو برای این کد خاص باید از کجا دانلود کرد و کدوم ورژن???

این دوتا احتمالا کمک کنه:

https://colab.research.google.com/drive/1e4zvS6LyhOAayEDh3bz8MXFTJcVFSvZX?usp=sharing#scrollTo=zog_lDxCd0dg

https://colab.research.google.com/drive/1e4zvS6LyhOAayEDh3bz8MXFTJcVFSvZX?usp=sharing#scrollTo=zog_lDxCd0dg

نظر شما چیست؟

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