قم بتشغيل كاشف الشبكة العصبية الخاص بك على Raspberry Pi باستخدام Neural Compute Stick و OpenVINO

مع انتشار الشبكات العصبية وتطويرها ، هناك حاجة متزايدة لاستخدامها على الأجهزة المدمجة والطاقة المنخفضة والروبوتات والطائرات بدون طيار. يسمح لنا الجهاز العصبي للحساب العصبي بالتزامن مع إطار عمل Intel OpenVINO بحل هذه المشكلة عن طريق أخذ الحسابات الثقيلة للشبكات العصبية. بفضل هذا ، يمكنك بسهولة تشغيل مصنف الشبكة العصبية أو كاشف على جهاز منخفض الطاقة مثل Raspberry Pi في الوقت الفعلي تقريبًا ، مع عدم زيادة استهلاك الطاقة بشكل كبير. في هذا المنشور ، سأوضح لك كيفية استخدام إطار عمل OpenVINO (في C ++) و Neural Compute Stick لإطلاق نظام بسيط للكشف عن الوجه على Raspberry Pi.

كالعادة ، كل رمز متاح على جيثب .



قليلا عن العصبية حساب العصا و OpenVINO


في صيف عام 2017 ، أصدرت Intel جهاز Neural Compute Stick (NCS) ، المصمم لتشغيل الشبكات العصبية على الأجهزة منخفضة الطاقة ، وبعد بضعة أشهر يمكن شراؤه واختباره ، وهو ما قمت به. NCS هي وحدة حوسبة صغيرة بها غلاف من اللون الأزرق السماوي (يعمل أيضًا كمبرد) ، ومتصل بالجهاز الرئيسي عبر USB. من الداخل ، من بين أشياء أخرى ، وحدة المعالجة المركزية Intel Myriad VPU ، والتي هي في الأساس معالج متوازي من 12 نواة ، تم شحذها للعمليات التي تحدث في كثير من الأحيان في الشبكات العصبية. NCS غير مناسب لتدريب الشبكات العصبية ، لكن الاستدلال في الشبكات العصبية المدربة بالفعل مماثل للسرعة على GPU. يتم إجراء جميع الحسابات في NCS على أرقام تعويم 16 بت ، مما يسمح لك بزيادة السرعة. لا يتطلب NCS سوى 1 واط من الطاقة للتشغيل ، أي عند 5 فولت ، يتم استهلاك تيار يصل إلى 200 مللي أمبير على موصل USB - وهذا أقل من كاميرا Raspberry Pi (250 مللي أمبير).



للعمل مع أول NCS ، تم استخدام Neural Compute SDK (NCSDK): وهو يتضمن أدوات لتجميع الشبكات العصبية بتنسيقات Caffe و TensorFlow لتنسيق NCS ، وأدوات لقياس أدائها ، وكذلك Python و C ++ API للاستدلال.

ثم تم إصدار نسخة جديدة من إطار عمل NCS: NCSDK2 . لقد تغيرت واجهة برمجة التطبيقات بشكل كبير ، وعلى الرغم من أن بعض التغييرات بدت غريبة بالنسبة لي ، إلا أن هناك بعض الابتكارات المفيدة. على وجه الخصوص ، تمت إضافة التحويل التلقائي من تعويم 32 بت إلى تعويم 16 بت إلى C ++ (في وقت سابق ، كان لا بد من إدراج العكازات في شكل رمز من Numpy). كما ظهرت طوابير الصور ونتائج معالجتها.

في مايو 2018 ، أصدرت Intel OpenVINO (المعروف سابقًا باسم Intel Computer Vision SDK). تم تصميم هذا الإطار لإطلاق الشبكات العصبية بكفاءة على مختلف الأجهزة: معالجات Intel وبطاقات الرسومات ، FPGA ، بالإضافة إلى Neural Compute Stick.

في نوفمبر 2018 ، تم إصدار نسخة جديدة من المعجل: Neural Compute Stick 2 . تمت زيادة القدرة الحاسوبية للجهاز: في الوصف الموجود على الموقع ، يعدون بتسارع يصل إلى 8x ، ومع ذلك ، لا يمكنني اختبار الإصدار الجديد من الجهاز. يتحقق التسارع بزيادة عدد النوى من 12 إلى 16 ، بالإضافة إلى إضافة أجهزة حوسبة جديدة محسنة للشبكات العصبية. صحيح ، لم أجد معلومات حول استهلاك الطاقة للمعلومات.

الإصدار الثاني من NCS غير متوافق بالفعل مع NCSDK أو NCSDK2: OpenVINO ، القادر على العمل مع العديد من الأجهزة الأخرى إلى جانب كلا نسختين من NCS ، اجتاز سلطتهما. يتمتع OpenVINO نفسه بوظيفة رائعة ويتضمن المكونات التالية:

  1. Optimizer Model: Python script الذي يسمح لك بتحويل الشبكات العصبية من أطر التعلم العميقة الشائعة إلى تنسيق OpenVINO العالمي. قائمة الأطر المدعومة: Caffe ، TensorFlow ، MXNET ، Kaldi (إطار التعرف على الكلام) ، ONNX (تنسيق مفتوح لتمثيل الشبكات العصبية).
  2. محرك الاستدلال: C ++ و Python API لاستدلال الشبكة العصبية ، المستخلص من جهاز استدلال محدد. سيبدو رمز API متطابقًا تقريبًا لوحدة المعالجة المركزية (CPU) و GPU و FPGA و NCS.
  3. مجموعة من المكونات الإضافية للأجهزة المختلفة. الإضافات عبارة عن مكتبات ديناميكية يتم تحميلها بشكل صريح في رمز البرنامج الرئيسي. نحن مهتمون أكثر بالبرنامج المساعد ل NCS.
  4. مجموعة من النماذج المدربة مسبقًا بتنسيق OpenVINO العالمي (القائمة الكاملة هنا ). مجموعة رائعة من الشبكات العصبية عالية الجودة: أجهزة الكشف عن الوجوه ، المشاة ، الأشياء ؛ الاعتراف بتوجه الوجوه ونقاط الوجوه الخاصة والمواقف الإنسانية ؛ قرار السوبر. وغيرها. تجدر الإشارة إلى أنه ليس كلهم ​​مدعومين من قبل NCS / FPGA / GPU.
  5. تنزيل النموذج: برنامج نصي آخر يبسط تنزيل نماذج OpenVINO عبر الشبكة (رغم أنه يمكنك الاستغناء عنها بسهولة).
  6. OpenCV مكتبة رؤية الكمبيوتر الأمثل لأجهزة إنتل.
  7. مكتبة رؤية الكمبيوتر OpenVX .
  8. مكتبة إنتل لحساب الشبكات العصبية العميقة .
  9. مكتبة Intel Math Kernel للشبكات العصبية العميقة .
  10. أداة لتحسين الشبكات العصبية لـ FPGA (اختياري).
  11. التوثيق وعينة البرامج.

في مقالاتي السابقة ، تحدثت عن كيفية تشغيل كاشف وجه YOLO على NCS (المقالة الأولى) ، وكذلك كيفية تدريب جهاز كشف وجه SSD وتشغيله على Raspberry Pi و NCS (المقالة الثانية) . في هذه المقالات ، استخدمت NCSDK و NCSDK2. في هذه المقالة ، سوف أخبرك بكيفية القيام بشيء مماثل ، لكن باستخدام OpenVINO ، سأجري مقارنة بسيطة لكلا من أجهزة كشف الوجه المختلفة وإطارين لإطلاقهما ، وسأشير إلى بعض المزالق. أكتب في C ++ ، لأنني أعتقد أنه بهذه الطريقة يمكنك تحقيق أداء أكبر ، وهو أمر مهم في حالة Raspberry Pi.

تثبيت OpenVINO


ليست المهمة الأكثر صعوبة ، على الرغم من وجود التفاصيل الدقيقة. في وقت كتابة هذا التقرير ، يدعم OpenVINO فقط Ubuntu 16.04 LTS و CentOS 7.4 و Windows 10. لدي Ubuntu 18 مثبت وأحتاج إلى عكازات صغيرة لتثبيته. أردت أيضًا أن أقارن OpenVINO بـ NCSDK2 ، الذي يواجه تثبيته أيضًا مشكلات: على وجه الخصوص ، يشدد إصداراته من Caffe و TensorFlow ويمكنه كسر إعدادات البيئة قليلاً. في النهاية ، قررت اتباع مسار بسيط وتثبيت كلا الإطارين في جهاز افتراضي باستخدام Ubuntu 16 (أستخدم VirtualBox ).

تجدر الإشارة إلى أنه من أجل توصيل NCS بنجاح بجهاز ظاهري ، تحتاج إلى تثبيت إضافات ضيف VirtualBox وتمكين دعم USB 3.0. أضفت أيضًا عامل تصفية عالميًا لأجهزة USB ، ونتيجة لذلك ، تم توصيل NCS دون مشاكل (على الرغم من أن كاميرا الويب لا تزال بحاجة إلى الاتصال في إعدادات الجهاز الظاهري). لتثبيت OpenVINO وتجميعها ، يجب أن يكون لديك حساب Intel ، واختر خيار إطار (مع أو بدون دعم FPGA) واتبع التعليمات . NCSDK أبسط من ذلك: يتم تشغيله من GitHub (لا تنس تحديد فرع ncsdk2 للإصدار الجديد من الإطار) ، وبعد ذلك تحتاج إلى make install .

المشكلة الوحيدة التي واجهتها أثناء تشغيل NCSDK2 في جهاز ظاهري هي خطأ في النموذج التالي:

 E: [ 0] dispatcherEventReceive:236 dispatcherEventReceive() Read failed -1 E: [ 0] eventReader:254 Failed to receive event, the device may have reset 

يحدث في نهاية التنفيذ الصحيح للبرنامج و (يبدو) لا يؤثر على أي شيء. على ما يبدو ، هذا خطأ صغير يتعلق بـ VM (يجب ألا يكون هذا في التوت).

التثبيت على Raspberry Pi مختلف بشكل كبير. أولاً ، تأكد من تثبيت Raspbian Stretch: يعمل كلا الإطارين رسميًا فقط على نظام التشغيل هذا. يجب تجميع NCSDK2 في وضع واجهة برمجة التطبيقات فقط ، وإلا فإنه سيحاول تثبيت Caffe و TensorFlow ، وهو أمر غير مرجح لإرضاء توت العليق. في حالة OpenVINO ، هناك إصدار تم تجميعه بالفعل لـ Raspberry ، والذي تحتاج فقط إلى فك تكوين متغيرات البيئة وتكوينها. في هذا الإصدار يوجد فقط C ++ و Python API ، وكذلك مكتبة OpenCV ، وجميع الأدوات الأخرى غير متوفرة. هذا يعني أنه في كلا الإطارين ، يجب تحويل الطرز مقدمًا على جهاز باستخدام Ubuntu. يعمل عرض الكشف عن الوجه الخاص بي على كل من Raspberry وعلى سطح المكتب ، لذلك أضفت للتو ملفات الشبكة العصبية المحولة إلى مستودع GitHub الخاص بي لتسهيل المزامنة مع Raspberry. لديّ طراز Raspberry Pi 2 B ، لكن يجب أن تقلع مع طرز أخرى.

هناك دقة أخرى فيما يتعلق بتفاعل Raspberry Pi وعصا Neural Compute Stick: إذا كان يكفي في حالة الكمبيوتر المحمول فقط إدخال NCS في أقرب منفذ USB 3.0 ، فسيتعين عليك في Raspberry إيجاد كبل USB ، وإلا فإن NSC ستحظر موصلات USB الثلاثة المتبقية بجسمها. تجدر الإشارة أيضًا إلى أن Raspberry يحتوي على جميع إصدارات USB 2.0 ، وبالتالي فإن معدل الاستدلال سيكون أقل بسبب تأخير الاتصالات (ستكون المقارنة التفصيلية لاحقًا). ولكن إذا كنت ترغب في توصيل اثنين أو أكثر من NCS بـ Raspberry ، فمن الأرجح أنك ستحتاج إلى العثور على لوحة وصل USB مع طاقة إضافية.

كيف يبدو رمز OpenVINO


ضخم جدا. هناك العديد من الإجراءات المختلفة التي يجب القيام بها ، بدءًا من تحميل المكون الإضافي وتنتهي بالاستدلال نفسه - لهذا السبب كتبت فئة مجمّع للكاشف. يمكن الاطلاع على الرمز الكامل على GitHub ، لكن هنا أذكر النقاط الرئيسية فقط. لنبدأ بالترتيب:

توجد تعريفات جميع الوظائف التي نحتاجها في ملف inference_engine.hpp في مساحة الاسم InferenceEngine .

 #include <inference_engine.hpp> using namespace InferenceEngine; 

سوف تكون هناك حاجة للمتغيرات التالية في كل وقت. نحن بحاجة إلى اسم الإدخال و اسم الإخراج من أجل معالجة مدخلات ومخرجات الشبكة العصبية. بشكل عام ، يمكن أن يكون للشبكة العصبية العديد من المدخلات والمخرجات ، ولكن في كاشفاتنا سيكون هناك واحد في كل مرة. net المتغيرة هي الشبكة نفسها ، request هو مؤشر إلى آخر طلب للاستدلال ، و inputBlob هو مؤشر إلى مجموعة بيانات الإدخال للشبكة العصبية. المتغيرات المتبقية تتحدث عن نفسها.

 string inputName; string outputName; ExecutableNetwork net; InferRequest::Ptr request; Blob::Ptr inputBlob; //input shape int netInputWidth; int netInputHeight; int netInputChannels; //output shape int maxNumDetectedFaces; //return code StatusCode ncsCode; 

الآن قم بتنزيل المكون الإضافي الضروري - نحتاج إلى المكون المسؤول عن NCS و NCS2 ، ويمكن الحصول عليه بالاسم "MYRIAD". دعني أذكرك أنه في سياق OpenVINO ، يعد البرنامج المساعد مجرد مكتبة ديناميكية تتصل بطلب واضح. معلمة وظيفة PluginDispatcher هي قائمة PluginDispatcher التي تبحث فيها عن المكونات الإضافية. إذا قمت بإعداد متغيرات البيئة وفقًا للتعليمات ، فسيكون الخط الفارغ كافيًا. كمرجع ، توجد إضافات في [OpenVINO_install_dir]/deployment_tools/inference_engine/lib/ubuntu_16.04/intel64/

 InferencePlugin plugin = PluginDispatcher({""}).getPluginByDevice("MYRIAD"); 

قم الآن بإنشاء كائن لتحميل الشبكة العصبية ، والنظر في وصفه وتعيين حجم الدفعة (عدد الصور التي تتم معالجتها في وقت واحد). يتم تعريف الشبكة العصبية بتنسيق OpenVINO بملفين: ملف .xml مع وصف للبنية و .bin بأوزان. على الرغم من أننا سنستخدم أجهزة الكشف الجاهزة من OpenVINO ، فإننا سننشئ فيما بعد أجهزة خاصة بنا. هنا std::string filename هو اسم الملف بدون الملحق. يجب أيضًا أن تضع في اعتبارك أن NCS يدعم فقط حجم الدُفعة 1.

 CNNNetReader netReader; netReader.ReadNetwork(filename+".xml"); netReader.ReadWeights(filename+".bin"); netReader.getNetwork().setBatchSize(1); 

ثم يحدث ما يلي:

  1. لدخول الشبكة العصبية ، اضبط نوع البيانات على char 8 بت غير موقَّع. هذا يعني أنه يمكننا إدخال الصورة بالتنسيق الذي تأتي به من الكاميرا ، وسيتولى InferenceEngine التحويل (يقوم NCS بإجراء حسابات بتنسيق تعويم 16 بت). سيؤدي ذلك إلى زيادة سرعة استخدام Raspberry Pi - كما أفهمها ، يتم التحويل على NCS ، لذلك هناك تأخير أقل في نقل البيانات عبر USB.
  2. نحصل على أسماء المدخلات والمخرجات ، حتى نتمكن لاحقًا من الوصول إليها.
  3. نحصل على وصف المخرجات (هذه خريطة من اسم الإخراج إلى مؤشر إلى كتلة بيانات). نحصل على مؤشر إلى كتلة البيانات من الإخراج الأول (واحد).
  4. نحصل على حجمها: 1 × 1 × أقصى عدد من الاكتشافات × طول وصف الكشف (7). حول تنسيق وصف الاكتشافات - في وقت لاحق.
  5. تعيين تنسيق الإخراج لتعويم 32 بت. مرة أخرى ، التحويل من تعويم 16 بت يعتني InferenceEngine.

 //we can set input type to unsigned char: conversion will be performed on device netReader.getNetwork().getInputsInfo().begin()->second->setPrecision(Precision::U8); //get input and output names and their info structures inputName = netReader.getNetwork().getInputsInfo().begin()->first; outputName = netReader.getNetwork().getOutputsInfo().begin()->first; OutputsDataMap outputInfo(netReader.getNetwork().getOutputsInfo()); InputsDataMap inputInfo(netReader.getNetwork().getInputsInfo()); DataPtr &outputData = (outputInfo.begin()->second); //get output shape: (1 x 1 x maxNumDetectedFaces x faceDescriptionLength(7)) const SizeVector outputDims = outputData->getTensorDesc().getDims(); maxNumDetectedFaces = outputDims[2]; //set input type to float32: calculations are all in float16, conversion is performed on device outputData->setPrecision(Precision::FP32); 

الآن النقطة الأكثر أهمية: نحن تحميل الشبكة العصبية في البرنامج المساعد (وهذا هو ، في NCS). على ما يبدو ، ترجمة إلى التنسيق المطلوب على الطاير. إذا تعطل البرنامج عن هذه الوظيفة ، فربما لا تكون الشبكة العصبية مناسبة لهذا الجهاز.

 net = plugin.LoadNetwork(netReader.getNetwork(), {}); 

وأخيرًا - سوف نجعل الاستدلال التجريبي والحصول على أحجام المدخلات (ربما يمكن القيام بذلك بشكل أكثر أناقة). أولاً ، نفتح طلبًا للاستدلال ، ثم نحصل منه على رابط إلى كتلة بيانات الإدخال ، ونطلب بالفعل الحجم منه.

 //perform single inference to get input shape (a hack) request = net.CreateInferRequestPtr(); //open inference request //we need the blob size: (batch(1) x channels(3) x H x W) inputBlob = request->GetBlob(inputName); SizeVector blobSize = inputBlob->getTensorDesc().getDims(); netInputWidth = blobSize[3]; netInputHeight = blobSize[2]; netInputChannels = blobSize[1]; request->Infer(); //close request 

دعنا نحاول تحميل صورة إلى NCS. بنفس الطريقة ، نقوم بإنشاء طلب للاستدلال ، والحصول على مؤشر إلى كتلة بيانات منه ، ومن هناك نحصل على مؤشر إلى المصفوفة نفسها. بعد ذلك ، ما عليك سوى نسخ البيانات من صورتنا (هنا يتم تقليلها بالفعل إلى الحجم المطلوب). تجدر الإشارة إلى أنه في cv::Mat و inputBlob يتم تخزين القياسات بترتيب مختلف (في OpenCV ، يتغير مؤشر القناة بشكل أسرع من الكل ، في OpenVINO يكون أبطأ من الكل) ، لذلك memcpy أمر لا غنى عنه. ثم نبدأ الاستدلال غير المتزامن.

لماذا غير متزامن؟ سيؤدي هذا إلى تحسين تخصيص الموارد. بينما تعتبر NCS الشبكة العصبية ، يمكنك معالجة الإطار التالي - سيؤدي ذلك إلى تسارع ملحوظ في Raspberry Pi.

 cv::Mat data; ... //get image somehow //create request, get data blob request = net.CreateInferRequestPtr(); inputBlob = request->GetBlob(inputName); unsigned char* blobData = inputBlob->buffer().as<unsigned char*>(); //copy from resized frame to network input int wh = netInputHeight*netInputWidth; for (int c = 0; c < netInputChannels; c++) for (int h = 0; h < wh; h++) blobData[c * wh + h] = data.data[netInputChannels*h + c]; //start asynchronous inference request->StartAsync(); 

إذا كنت على دراية جيدة بالشبكات العصبية ، فقد يكون لديك سؤال حول متى نقيس قيم بكسلات إدخال الشبكة العصبية (على سبيل المثال ، نأتي إلى النطاق [0،1]) والحقيقة هي أن هذا التحول في نماذج OpenVINO مدرج بالفعل في وصف الشبكة العصبية ، وعند استخدام كاشفنا ، سنفعل شيئًا مماثلاً. ونظرًا لأن كلا من التحويل إلى تعويم وتوسيع المدخلات يتم إجراؤه بواسطة OpenVINO ، فإننا نحتاج فقط إلى تغيير حجم الصورة.

الآن (بعد القيام ببعض الأعمال المفيدة) سنكمل طلب الاستدلال. يتم حظر البرنامج حتى تأتي نتائج التنفيذ. نحصل على مؤشر إلى النتيجة.

 float * output; ncsCode = request->Wait(IInferRequest::WaitMode::RESULT_READY); output = request->GetBlob(outputName)->buffer().as<float*>(); 

حان الوقت الآن للتفكير في التنسيق الذي يُرجع به NCS نتيجة الكاشف. تجدر الإشارة إلى أن التنسيق يختلف قليلاً عما كان عليه عند استخدام NCSDK. بشكل عام ، يكون خرج الكاشف ثلاثي الأبعاد وله بعد (1 × 1 × أقصى عدد من الاكتشافات × 7) ، يمكننا أن نفترض أن هذا هو مجموعة من الحجم ( maxNumDetectedFaces x 7).

يتم تعيين المعلمة maxNumDetectedFaces في وصف الشبكة العصبية ، ومن السهل تغييرها ، على سبيل المثال ، في وصف .prototxt للشبكة بتنسيق Caffe. في وقت سابق حصلنا عليه من الكائن الذي يمثل كاشف. تتعلق هذه المعلمة بخصائص فئة أجهزة الكشف عن الأقراص الصلبة (SSD Detector) ، والتي تشمل جميع أجهزة كشف NCS المدعومة. يأخذ SSD دائمًا نفس العدد (والكبير جدًا) من الصناديق المحيطية لكل صورة ، وبعد تصفية الاكتشافات بمعدل ثقة منخفض وإزالة الإطارات المتداخلة باستخدام قمع غير أقصى ، عادة ما يتركون أفضل 100- 200. هذا هو بالضبط ما المعلمة هي المسؤولة عن.

القيم السبع في وصف اكتشاف واحد كالتالي:

  1. رقم الصورة في المجموعة التي تم اكتشاف الكائن عليها (في حالتنا ، يجب أن تكون صفرية) ؛
  2. فئة الكائن (0 - خلفية ، تبدأ من 1 - فئات أخرى ، يتم إرجاع الاكتشافات فقط مع فئة موجبة) ؛
  3. الثقة في وجود الكشف (في النطاق [0،1]) ؛
  4. إحداثي س-تطبيع من الزاوية اليسرى العليا من المربع المحيط (في النطاق [0،1]) ؛
  5. بالمثل - ص الإحداثي.
  6. تطبيع عرض مربع المحيط (في النطاق [0،1]) ؛
  7. بالمثل - الارتفاع ؛

رمز لاستخراج مربعات المحيطة من إخراج كاشف
 void get_detection_boxes(const float* predictions, int numPred, int w, int h, float thresh, std::vector<float>& probs, std::vector<cv::Rect>& boxes) { float score = 0; float cls = 0; float id = 0; //predictions holds numPred*7 values //data format: image_id, detection_class, detection_confidence, //box_normed_x, box_normed_y, box_normed_w, box_normed_h for (int i=0; i<numPred; i++) { score = predictions[i*7+2]; cls = predictions[i*7+1]; id = predictions[i*7 ]; if (id>=0 && score>thresh && cls<=1) { probs.push_back(score); boxes.push_back(Rect(predictions[i*7+3]*w, predictions[i*7+4]*h, (predictions[i*7+5]-predictions[i*7+3])*w, (predictions[i*7+6]-predictions[i*7+4])*h)); } } } 

نتعلم numPred من الكاشف نفسه ، و w,h أحجام الصور للتصور.

الآن حول كيف يبدو المخطط العام للاستدلال في الوقت الحقيقي. أولاً ، نقوم بتهيئة الشبكة العصبية والكاميرا ، وبدء تشغيل cv::Mat للإطارات الأولية وواحدة أخرى للإطارات التي تم تصغيرها إلى الحجم المطلوب. نحن نملأ الإطارات الخاصة بنا بالأصفار - وهذا سيضيف الثقة إلى أن الشبكة العصبية لن تجد شيئًا في بداية واحدة. ثم نبدأ دورة الاستدلال:

  • نقوم بتحميل الإطار الحالي في الشبكة العصبية باستخدام طلب غير متزامن - لقد بدأت NCS في العمل بالفعل ، وفي الوقت الحالي لدينا الفرصة لجعل العمل المفيد هو المعالج الرئيسي.
  • نعرض جميع الاكتشافات السابقة على الإطار السابق ، ونرسم إطارًا (إذا لزم الأمر).
  • نحصل على إطار جديد من الكاميرا ، وضغطه على الحجم المطلوب. بالنسبة لـ Raspberry ، أوصي باستخدام أبسط خوارزمية تغيير الحجم - في OpenCV ، هذا هو أقرب استيفاء من الجيران. لن يؤثر هذا على جودة أداء الكاشف ، لكن يمكن أن يضيف بعض السرعة. أنا أيضا مرآة الإطار لسهولة التصور (اختياري).
  • الآن هو الوقت المناسب للحصول على النتيجة مع NCS عن طريق إكمال طلب الاستدلال. سيتم حظر البرنامج حتى يتم استلام النتيجة.
  • نعالج اكتشافات جديدة ، حدد الإطارات.
  • الباقي: ممارسة ضغطات المفاتيح ، عد الإطارات ، إلخ.

كيفية تجميعها


في أمثلة InferenceEngine ، لم يعجبني ملفات CMake الضخمة ، وقررت إعادة كتابة كل شيء بشكل مضغوط إلى Makefile:

 g++ $(RPI_ARCH) \ -I/usr/include -I. \ -I$(OPENVINO_PATH)/deployment_tools/inference_engine/include \ -I$(OPENVINO_PATH_RPI)/deployment_tools/inference_engine/include \ -L/usr/lib/x86_64-linux-gnu \ -L/usr/local/lib \ -L$(OPENVINO_PATH)/deployment_tools/inference_engine/lib/ubuntu_16.04/intel64 \ -L$(OPENVINO_PATH_RPI)/deployment_tools/inference_engine/lib/raspbian_9/armv7l \ vino.cpp wrapper/vino_wrapper.cpp \ -o demo -std=c++11 \ `pkg-config opencv --cflags --libs` \ -ldl -linference_engine $(RPI_LIBS) 

سيعمل هذا الفريق على كل من Ubuntu و Raspbian ، وذلك بفضل بعض الحيل. مسارات البحث عن الرؤوس والمكتبات الديناميكية التي أشرت إليها لكل من Raspberry وآلة Ubuntu. بالنسبة إلى المكتبات ، بالإضافة إلى OpenCV ، يجب عليك أيضًا توصيل libinference_engine و libdl - مكتبة للربط الديناميكي بالمكتبات الأخرى ، وهي ضرورية لكي يعمل المكون الإضافي. في الوقت نفسه ، libmyriadPlugin نفسه libmyriadPlugin يحتاج إلى تحديد. من بين أشياء أخرى ، بالنسبة لـ Raspberry أقوم أيضًا بتوصيل مكتبة Raspicam للعمل مع الكاميرا (هذا هو $(RPI_LIBS) ). كان علي أيضًا استخدام معيار C ++ 11.

بشكل منفصل ، تجدر الإشارة إلى أنه عند التحويل البرمجي لـ Raspberry ، فإن -march=armv7-a flag ضرورية (هذا هو $(RPI_ARCH) ). إذا لم تحدده ، فسيتم ترجمة البرنامج ، ولكن سيتعطل مع segfault صامت. يمكنك أيضا إضافة تحسينات باستخدام -O3 ، وهذا سيضيف السرعة.

ما هي أجهزة الكشف


لا يدعم NCS سوى كاشفات SSD من المربع ، على الرغم من وجود بعض الحيل القذرة تمكنت من تشغيل YOLO من تنسيق Darknet عليه. يعد Single Shot Detector (SSD) بنية شائعة بين الشبكات العصبية خفيفة الوزن ، وبمساعدة من أجهزة التشفير المختلفة (أو شبكات العمود الفقري) ، يمكنك تغيير نسبة السرعة والجودة بمرونة.

سأقوم بتجربة أجهزة كشف الوجه المختلفة:

  • YOLO ، مأخوذة من هنا ، يتم تحويلها أولاً إلى تنسيق Caffe ، ثم إلى تنسيق NCS (فقط مع NCSDK). الصورة 448 × 448.
  • كاشف Mobilenet + SSD الخاص بي ، الذي تحدثت عنه حول التدريب في منشور سابق . لا يزال لدي نسخة مقصوصة من هذا الكاشف ، الذي لا يرى سوى الوجوه الصغيرة ، وفي نفس الوقت أسرع قليلاً. سوف أتحقق من النسخة الكاملة لجهاز الكشف الخاص بي على كل من NCSDK و OpenVINO. الصورة 300 × 300.
  • كشف الوجه adas-0001 من OpenVINO: MobileNet + SSD. صورة 384 × 672.
  • OpenVINO-face-retail-0004 detector: خفيفة الوزن SqueezeNet + SSD. الصورة 300 × 300.

بالنسبة للكاشفات من OpenVINO ، لا توجد موازين في تنسيق Caffe أو تنسيق NCSDK ، لذلك لا يمكنني تشغيلها إلا في OpenVINO.

تحويل كاشف الخاص بك إلى تنسيق OpenVINO


لدي ملفان بتنسيق Caffe: .prototxt مع وصف للشبكة و .caffemodel مع الأوزان. أحتاج إلى الحصول على ملفين منهم بتنسيق OpenVINO: .xml و .bin مع الوصف والأوزان ، على التوالي. للقيام بذلك ، استخدم البرنامج النصي mo.py من OpenVINO (المعروف أيضًا باسم Optimizer):

 mo.py \ --framework caffe \ --input_proto models/face/ssd-face.prototxt \ --input_model models/face/ssd-face.caffemodel \ --output_dir models/face \ --model_name ssd-vino-custom \ --mean_values [127.5,127.5,127.5] \ --scale_values [127.5,127.5,127.5] \ --data_type FP16 

يحدد output_dir الدليل الذي سيتم فيه إنشاء ملفات جديدة ، model_name هو اسم الملفات الجديدة بدون امتداد ، data_type (FP16/FP32) هو نوع التوازن في الشبكة العصبية (NCS يدعم FP16 فقط). تقوم mean_values, scale_values بتعيين المتوسط ​​والحجم للمعالجة المسبقة للصور قبل إطلاقها في الشبكة العصبية. يبدو التحويل المحدد كما يلي:

(بكسل قيممتوسط قيم)/مقياس قيم



في هذه الحالة ، يتم تحويل القيم من النطاق [0.255]في النطاق [0،1]. بشكل عام ، يحتوي هذا البرنامج النصي على الكثير من المعلمات ، بعضها خاص بالأُطر الفردية ، نوصي بالبحث في دليل البرنامج النصي.

لا يحتوي توزيع OpenVINO لـ Raspberry على نماذج جاهزة ، ولكن من السهل جدًا تنزيلها.

على سبيل المثال ، مثل هذا.
  wget --no-check-certificate \ https://download.01.org/openvinotoolkit/2018_R4/open_model_zoo/face-detection-retail-0004/FP16/face-detection-retail-0004.xml \ -O ./models/face/vino.xml; \ wget --no-check-certificate \ https://download.01.org/openvinotoolkit/2018_R4/open_model_zoo/face-detection-retail-0004/FP16/face-detection-retail-0004.bin \ -O ./models/face/vino.bin 


مقارنة بين أجهزة الكشف والأطر


لقد استخدمت ثلاثة خيارات للمقارنة: 1) الجهاز الظاهري NCS + مع Ubuntu 16.04 ، معالج Core i7 ، موصل USB 3.0 ؛ 2) NCS + نفس الجهاز ، موصل USB 3.0 + كابل USB 2.0 (سيكون هناك المزيد من التأخير في التبادل مع الجهاز) ؛ 3) NCS + Raspberry Pi 2 طراز B ، امتداد Raspbian ، موصل USB 2.0 + كابل USB 2.0.

بدأت تشغيل الكاشف الخاص بي مع كل من OpenVINO و NCSDK2 ، وكاشفات من OpenVINO فقط مع إطار عملهما الأصلي ، YOLO فقط مع NCSDK2 (على الأرجح ، يمكن تشغيله أيضًا على OpenVINO).

يشبه جدول FPS للكشف عن مختلف (الأرقام تقريبية):

نموذجUSB 3.0USB 2.0التوت بي
SSD مخصص مع NCSDK210.89.37.2
SSD longrange مخصصة مع NCSDK211.810.07.3
YOLO v2 مع NCSDK25.34.63.6
SSD مخصص مع OpenVINO10.69.97.9
OpenVINO - كشف الوجه - التجزئة - 000415.614.29.3
OpenVINO-face-detect-adas-00015.85.53.9


ملاحظة: تم قياس الأداء للبرنامج التجريبي بأكمله ، بما في ذلك معالجة وتصور الإطارات.

كان YOLO الأبطأ والأكثر عدم استقرارًا على الإطلاق. في كثير من الأحيان يتخطى الكشف ولا يمكن أن يعمل مع إطارات مضيئة.

يعمل الكاشف الذي قمت بتدريبه بسرعة مرتين ، وهو أكثر مقاومة للتشوه في الإطارات ، وحتى يكتشف الوجوه الصغيرة. ومع ذلك ، فإنه لا يزال يتخطى الكشف في بعض الأحيان ويكتشف أحيانًا أخطاء مزيفة. إذا قمت بقطع الطبقات القليلة الأخيرة منه ، فستصبح أسرع قليلاً ، ولكنها ستتوقف عن رؤية الوجوه الكبيرة. يصبح الكاشف نفسه الذي يتم إطلاقه من خلال OpenVINO أسرع قليلاً عند استخدام USB 2.0 ، لا تتغير الجودة بصريًا.

بطبيعة الحال ، فإن أجهزة الكشف عن OpenVINO تفوق بكثير كل من YOLO وكاشفتي. (لن أبدأ في تدريب مكشافي إذا كان OpenVINO موجودًا في شكله الحالي في ذلك الوقت). طراز البيع بالتجزئة -4000 أسرع بكثير وفي الوقت نفسه لا يفوتك الوجه عمليًا ، لكنني تمكنت من خداعه قليلاً (على الرغم من أن الثقة في هذه الاكتشافات منخفضة):


هجوم تنافسي للذكاء الطبيعي على اصطناعي

كاشف adas-0001 أبطأ بكثير ، لكنه يعمل مع الصور الكبيرة ويجب أن يكون أكثر دقة. لم ألاحظ الفرق ، لكنني راجعت إطارات بسيطة إلى حد ما.

الخاتمة


بشكل عام ، من الجيد جدًا أنه على جهاز منخفض الطاقة مثل Raspberry Pi ، يمكنك استخدام الشبكات العصبية ، وحتى في الوقت الفعلي تقريبًا. يوفر OpenVINO وظائف شاملة للغاية لاستدلال الشبكات العصبية على العديد من الأجهزة المختلفة - أوسع بكثير مما وصفته في المقالة. أعتقد أن Neural Compute Stick و OpenVINO سيكونان مفيدان للغاية في بحثي الآلي.

Source: https://habr.com/ru/post/ar436744/


All Articles