پروژه تشخیص اشیاء
آموزش‌های پیشرفته هوش مصنوعیبینایی ماشینپایتون و ابزارهای یادگیری عمیقچالش‌های عملیاتی

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

    2
    مدت زمان مطالعه: ۱۱ دقیقه
    اخیراً مشغول کار در پروژه‌ای مربوطه به نرم‌افزار پردازش آنی بوده‌ایم. این نرم‌افزار ویدئوها را از سیستم‌های نظارتی دریافت کرده و کادرهای محصورکننده Bounding boxes را در موارد شناسایی‌شده به نمایش در می‌آورد. سپس اطلاعات مربوط به آن موارد در فایل‌های json به صورت رکورد log ذخیره می‌شود. به نظر می‌آید این پروژه تشخیص اشیاء ساده برای شروع کار، خوب باشد. در همین راستا، از رویکرد Test-Driven-Development برای نوشتن کد نرم‌افزار استفاده می‌کنیم. امیدواریم افراد تازه‌کاری که مایل‌اند با ابزارهای unittest در پایتون آشنا شوند، نهایت استفاده را از این پست ببرند. شما می‌توانید برای دریافت کد منبع به این لینک مراجعه کنید. در این لینک، یک مورد پیاده‌سازی همین کد بر روی سرویس تشخیص اشیاء  Object detection service نیز اضافه شده است. منبع کد پروژه تشخیص اشیاء متعلق به آدریان رزبراک است که در این پست فوق‌العاده به اشتراک گذاشته شده است.

    توصیف سیستم

    برای اینکه دقیقاً متوجه هدف این پست شوید، یک نگاه به نمونه عکس زیر بیندازید:

    پروژه تشخیص اشیاء

    در این عکس، فریمی با دو کادر محصورکننده نشان داده شده و هر کادر حاوی برچسبی با سطح اطمینان مشخص است. پس فهرستی از فریم‌ها در اختیار داریم و هر فریم می‌تواند دربردارنده‌ی چندین کادر می‌باشد. معمولاً در اکثر پروژه‌های تشخیص اشیاء در خروجی شبکه‌های پروژه تشخیص اشیاء، برای هر کادر محصور کننده چندین برچسب‌ با درجه اطمینان وجود دارد که شی شناسایی شده با اولویت درجه اطمینان انتخاب می‌شود. پس در این پروژه شرایطی فراهم می‌آوریم که کادرها فهرستی از برچسب‌ها با درصد اطمینان خروجی شبکه مصنوعی داشته باشند. این کار با انتخاب پارامتری تحت عنوان top_k_label به انجام می‌رسد. انتظار داریم همه کادرها تعداد برچسب یکسانی داشته باشند. حال، به مثالی از فایل json که به شکل ۱ مربوط است، توجه نمائید:

     

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

    شروع کار

    من کد اولیه را با سه class شروع کردم. این class حاوی اطلاعاتی درباره فریم‌ها، کادرها و برچسب‌ها است.

    دسته‌های پایه

    class دیگری برای مدیریت خروجی ایجاد و آن را JsonParser نامگذاری کردم:

    این class مخصوصِ مدیریت logger است.

    مرحله ۱: افزودن فریم
    حال که class های اولیه را در اختیار داریم، بیایید از رویکرد TDD software development استفاده کنیم. من فایل دیگری به نام test_json_parser ایجاد کردم و آن را در پوشه tests قرار دادم. حالا به کدی نیاز داریم که افزودنِ فریم به JsonParser.frames را تحت آزمایش unittest قرار دهد. اکنون زمان اجرای TestCase با کد زیر فرا رسیده است:

     

    مقداردهی اولیه برای jsonparser tests

    من از ابزارهای نرم افزار pycharm برای آزمایش کد استفاده کردم. دلیل افزودنِ sys.path.append(../..) این بود که اگر قادر به استفاده از pycharm نبودید، بتوانید از فرمان‌های terminal برای انجام unittest ها استفاده کنیم. کد زیر، فرایند افزودن فریم را تحت unittest قرار می‌دهد.

     

     

    در این آزمایش:
    ۱. اطمینان حاصل می‌کنیم که تعداد فریمی که در json قرار دارد همان مقداری است که در ورودی تخصیص یافته است.
    ۲. اگر بر اساس شماره فریم، فریمی تکراری جایگذاری شود، انتظار می‌رود روند کار با خطا همراه باشد.
    توجه داشته باشید که تابع assertRaisesRegex از عبارات معمولی برای بررسی پیام خطا استفاده می‌کند. عبارت (.*?) یک عبارت معمولی است، اما در این مورد، برای چشم‌پوشی از جملات میان (Frame id:) و already exists استفاده شد. حال بیایید کد را برای پشت سر گذاشتن این آزمایش به کار ببندیم. باید کار را با ماژول JsonParser آغاز کنیم. در همین راستا، سه تابع زیر به کد اضافه می شود:

     

    توابع لازم برای پشت سر گذاشتن آزمایش «اضافه کردنِ فریم»

    من معمولاً از دستورالعمل __dict__() برای دسترسی به خصوصیات کلاس‌ها در پایتون استفاده می‌کنم. اما به منظور دسترسی به خصوصیاتی که شامل یک لیست از اشیاء می‌شوند، مثل labels در دسته Bbox یا bboxes در دسته Frame، باید از یک ترفند برای به دست آوردن این پارامترها استفاده کنیم. به لطف این لینک ، یک کلاس والد Parent class ایجاد کردم که خصوصیت دیگری به کلاس‌های Frame، Bbox و Label اضافه می‌کند. نام این کلاس BaseJsonParser است. به فرایند زیر توجه نمائید.

     

    تعریف BaseJsonParser

    با انتخاب BaseJsonParser به عنوان کلاس والد، خصیصه ای به نام dic برای کلاس ها تخصیص داده می‌شود. این خصوصیت  Attribute به ما اجازه خواهد داد تا خصوصیات را در کلاس های جایگذاری شده بازگردانیم. اکنون زمان افزودنِ دستورالعمل output به JsonParser و اجرای آزمایش فرا رسیده است:

     

    این تابع را به کلاس JsonParser اضافه کنید.

    حالا به اجرای test_add_frame.pyمی پردازیم.

    پروژه تشخیص اشیاء

    آزمایش اول با موفقیت به پایان رسید!

    مرحله ۲: اضافه کردن کادر محصورکننده به هر فریم
    بسیار عالی! اکنون می‌خواهیم آزمایش دوم را بنویسیم که مخصوصِ اضافه کردنِ کادر به فریم‌ها است:

    این کار برای اضافه کردن کادر ضروری است.

    باید موارد زیر را برای پاس کردن تست‌ها پیاده‌سازی کنیم:
    ۱. ایجاد تابع برای JsonParser تا بررسی کند آیا bbox وجود دارد یا خیر.
    ۲. ایجا تابع برای اضافه کردنِ bbox به فریم

     

    این موارد را به JsonParser اضافه کنید.

     

    این مورد را به دستۀ Frame اضافه کنید.

     

    حالا نوبت انجام مجدد هر دو آزمایش فرا رسیده است:

    پروژه تشخیص اشیاء

    مرحله ۳: اضافه کردنِ برچسب به کادرها
    در گام بعدی، باید برچسب‌ها را به bboxes افزوده و فرایند کار را آزمایش کنیم. باید موارد زیر آزمایش شوند:
    ۱. با بکارگیری top_k_labels و افزودن برچسب‌های یکسان به bboxes، انتظار داریم کار بدون هیچ مشکلی پیش برود.
    ۲. با اضافه شدن برچسب‌های بیشتر از top_k_labels به خطای ValueError خواهیم خورد.
    ۳. در حین خروجی گرفتن از json، انتظار داریم برنامه از این موضوع را اطمینان حاصل کند که تعداد برچسبهای هر کادر یکسان باشد.
    اکنون به روند آزمایش دقت کنید:

     

    آزمایشِ روند افزودن برچسب به bbox

    حال با پیاده سازی موارد زیر این تست را پشت سر می گذاریم:
    ۱. تابعی نیاز داریم تا bbox را در لیست bboxes با در اختیار داشتن frame_id و bbox_id از لیست frames پیدا کند.
    ۲. ایجاد تابعی که برچسبی به bbox پیدا شده اضافه کند.
    ۳. باید تعداد برچسب‌های اضافه شده به bbox برابر با تعداد top_k_labels باشد. در غیر این صورت، انتظار داریم خطا رخ بدهد. هنگام خروجی گرفتن از فریم‌ها نیز باید این مسئله بررسی شود.

    حال، تابع find_bbox را در JsonParser اضافه می‌کنیم:

     

     

    اینجا باید add_label_to_bbox را به JsonParser اضافه کنیم:

     

     

    همان طور که ملاحظه می‌کنید، باید add_label در bbox وجود داشته باشد. البته من علاوه بر آن تابع دیگری تحت عنوان labels_full نیز اضافه کردم:

     

    با افزودن add_label و labels_full، به‌روزرِرسانیِ کلاس Bbox در دستور کار قرار گرفت.
    مقداری که در ورودی برای labels_full تخصیص داده شد، top_k خواهد بود. این مورد در JsonParser مد نظر قرار گرفته بود. اکنون مجبوریم کد مربوط به تابع خروجی را در JsonParser اصلاح کنیم:

    اصلاح خروجی در JsonParser

    بیایید یکبار دیگر همه تست‌ها را یکجا اجرا کنیم:

    پروژه تشخیص اشیاء

    اجرای همه تست‌ها

     

    مرحله ۱: خودکارسازی خروجی‌های Json
    بسیار خب. JsonParser را در اختیار داریم. زمینه برای ساخت تابعی که بتواند کل فرایندِ ذخیرۀ فایل‌های json را خودکار کند، فراهم شده است. سازوکارِ من برای پیاده‌سازی این طرح به صورت زیر است:
    ۱. یک پارامتر interval در اختیار داریم که می‌تواند بین ۱ ثانیه تا ۵ ساعت باشد. این پارامتر نشان می‌دهد که فایل‌های json چند وقت به چند وقت ذخیره می‌شوند.
    ۲. پیش از اینکه فرایند فریم اول آغاز شود، باید زمان آغاز را تعیین کنیم.
    ۳. تابع زمان‌بندی در حلقه به کار گرفته می‌شود و این فرایند در هر فریم به اجرا درمی‌آید. در وهله بعد، می‌توان تفاوت میان زمان آغازین و زمان فعلی را اندازه گرفت. هر وقت این تفاوت بیشتر از پارامتر time_to_save باشد، می‌توانیم فایل json را ذخیره کنیم.
    اکنون زمان ایجاد تست در فایلی دیگر به نام test_scheduled_output.py و انجام فرایند تست به صورت زیر فرا رسیده است:

     

    انجام آزمایش خروجی
    چرا mkdtemp ؟
    تابع mkdtemp از کتابخانه tempfile از یک منبع موقتی در سیستم استفاده کرده و یک پوشه موقت هم ایجاد می‌کند. این پوشه برای ذخیره کردنِ json به منظور آزمایش موقت در آنجا ذخیره می‌شود.
    باید این فرایند بیش از یک ثانیه طول بکشد تا ببینیم json به صورت خودکار ذخیره می‌شود یا خیر. برای اینکه تاخیر زیادی در فرایند اتفاق نیفتد، از ویدئو در آزمایش استفاده نمی‌شود.
    اکنون باید کد زیر را به اجرا درآوریم:

    اضافه کردن json_output و schedule_output

    JsonMeta به چه دردی می‌خورد؟ دلیل استفاده از JsonMeta این است که می‌خواهیم بعضی از مقادیر مانند ثانیه، دقیقه و ساعت را به صورت پیش فرض قرار دهیم تا مقادیر مورد استفاده در در تابع schedule_output را کنترل کنیم. به کلاس JsonMeta توجه کنید:

    پروژه تشخیص اشیاء

    کلاس JsonMeta
    بگذارید ببینیم آیا آزمایش با موفقیت انجام شده است یا خیر:

    پروژه تشخیص اشیاء

    بسیار عالی! همه آزمایش‌ها پاس شده است.
    در نهایت از تابع زیر می‌توان برای افزودن جزئیات ویدئو به json استفاده کرد:

    پروژه تشخیص اشیاء

    پیشنهاد برای کارهای آتی
    اکنون ابزاری در اختیار داریم که برای ذخیره json در سیستم نظارت لحظه‌ای مفید است. توصیه می‌کنم ویژگی‌های زیر را برای تمرین هم که شده، اضافه کنید:
    ۱. دسته دیگری ایجاد کنید که قادر به تجزیه و تحلیل داده‌های json باشد.
    ۲. تابعی ایجاد کنید بتواند با بازسازی bboxها در فریم ویدئو، موارد شناسایی را ذکر کرده و نتایج را نشان دهد.
    ۳. سعی کنید کد را در کد پروژه تشخیص اشیاء مورد استفاده قرار دهید.
    کل کد پروژه تشخیص اشیاء در این لینک بارگذاری شده است.

    این مطلب چه میزان برای شما مفید بوده است؟
    [کل: ۰ میانگین: ۰]

    استفاده از یادگیری ماشین در موبایل

    مقاله قبلی

    سرعت دادن به شبکه های عصبی عمیق

    مقاله بعدی

    شما همچنین ممکن است دوست داشته باشید

    2 نظرات

    1. جامع و مفید
      دستتون درد نکنه

      1. خواهش میکنم
        موفق باشید

    پاسخ دهید

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