متعدد المعالجات إنتل العصبية العصا الكمبيوتر الوصول عن طريق REST

مشكلة مهمة واحدة


في السلسلة الأخيرة ، وضعت Intel Neural Computer Stick 2 على الخزان وألقيت عليه جميع حسابات الشبكة العصبية ، متخليًا عن Tensorflow و OpenCV-DNN.

كانت هناك مشكلة واجهتها بالفعل - عدم القدرة على العمل مع NCS من عدة عمليات في وقت واحد. ثم لم يكن الأمر بالغ الأهمية ، ولكن حان الوقت الآن لمعرفة ذلك.

عند محاولة تحميل نموذج من العملية الثانية ، بدأ OpenVino في أداء اليمين:

E: [ncAPI] [ 926029] resetAll:348 Failed to connect to stalled device, rc: X_LINK_ERROR E: [ncAPI] [ 933282] ncDeviceOpen:672 Failed to find suitable device, rc: X_LINK_DEVICE_NOT_FOUND 

من خلال البحث في منتدى دعم Intel ، تم العثور على مشكلة مماثلة.

من هناك تم نقلنا إلى الوثائق حيث تم النص بوضوح:

لا يمكن مشاركة جهاز واحد عبر عمليات متعددة.

في هذه التجربة ، يمكنك تقليل الوصول إلى المعالجة المتعددة والبدء في ذلك.

خدمة NCS


من المنطقي تمامًا وضع العمل المباشر مع NCS في خدمة منفصلة ، وتوزيع API على جميع العملاء الذين سيعملون من خلالهم.

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

NCS API


على مستوى منخفض ، واجهة برمجة تطبيقات NCS بسيطة للغاية:
- نموذج الحمل
- ابدأ الحساب
- الحصول على قائمة النماذج
- الحصول على خصائص النموذج

إذا كان كل شيء لا لبس فيه عند تحميل النموذج ، فإن العادم الحسابي هو موتر حساس للسياق قد لا يحتاجه العميل.

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

بالإضافة إلى ذلك ، المستوى المنخفض جيد ، ولكن إذا كنت تدعم العمليات المتخصصة ، فإنه يبسط المنطق والبيانات.

وبالتالي ، بالإضافة إلى القاعدة ، هناك مهمة لدعم واجهة برمجة التطبيقات للتصنيف والكشف والتجزئة.

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

تستخدم أي من هذه العمليات الحساب الأساسي للنموذج ، ولكنها تختلف في تفسير موتر الإخراج.

الواجهة الرئيسية


لذلك ، تتضمن الواجهة الرئيسية الأساليب:

  • وظيفة: / تحميل - تحميل النموذج
  • POST: / unload / model $ - حذف النموذج (من الخدمة ، من المستحيل إزالته من الجهاز)
  • الحصول على: / قائمة - الحصول على قائمة النماذج
  • الحصول على: / الإدخال / الشكل / $ النموذج - معرفة البعد من موتر الإدخال
  • POST: / inference / file / $ model - قم بإجراء عملية حسابية باستخدام بيانات من الذاكرة
  • POST: / inference / path / $ model - قم بإجراء عملية حسابية باستخدام البيانات الموجودة في نظام الملفات

فيما يلي كلمتين حول البيانات من الذاكرة ونظام الملفات:

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

توضح الاختبارات أن نقل البايتات من الذاكرة أبطأ بشكل ملحوظ (تم إجراء القياس لـ 1000 محاولة):

من الذاكرة: 87.5 ثانية
مسار الملف: 63.3150 ثانية

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

بشكل عام ، تأخذ طريقة الاستدلال صورة في شكل صفيف numpy كمدخل وتنتج موترًا بنفس التنسيق.
كيفية تفسير العادم هو بالفعل مشكلة العملاء.
لتسهيل هذه المهمة ، تدعم الخدمة الطرق المتخصصة التي تستخرج معلومات مهمة في شكل بشري من موتر الإخراج.

تصنيف


للتصنيف ، نقوم بإنشاء طريقة REST منفصلة ، والتي تحول موتر الإخراج إلى مجموعة من الأزواج (فئة ، درجة).

 def get_class_tensor(data): ret = [] thr = 0.01 while(True): cls = np.argmax(data) if data[cls] < thr: break; logging.debug(("Class", cls, "score", data[cls])) c = {"class" : int(cls), "score" : int(100 * data[cls])} data[cls] = 0 ret.append(c) return ret def classify(model_id, img): rc, out = run_inference(model_id, img) if not rc: return rc, out return True, get_class_tensor(out) 

كما في حالة الإخراج العادي ، يتم دعم طريقتين - من خلال ملف في الذاكرة ومسار على القرص.

  • وظيفة: / تصنيف / ملف / نموذج $
  • ما بعد: / تصنيف / مسار / نموذج $

كشف


يحتوي الموتر الناتج عن كاشف مجموعة (فئة ، احتمال ، إحداثيات طبيعية) ويبدو مرهقا إلى حد ما.

نحولها إلى شكل مفهوم ، مع قطع الخيارات غير المحتملة:

 def get_detect_from_tensor(t, rows, cols): score = int(100 * t[2]) cls = int(t[1]) left = int(t[3] * cols) top = int(t[4] * rows) right = int(t[5] * cols) bottom = int(t[6] * rows) return {"class" : cls, "score" : score, "x" : left, "y" : top, "w" : (right - left), "h" : (bottom - top)} def build_detection(data, thr, rows, cols): T = {} for t in data: score = t[2] if score > thr: cls = int(t[1]) if cls not in T: T[cls] = get_detect_from_tensor(t, rows, cols) else: a = T[cls] if a["score"] < score: T[cls] = get_detect_from_tensor(t, rows, cols) return list(T.values()) def detect(model_id, img): rc, out = run_inference(model_id, img) if not rc: return rc, out rows, cols = img.shape[:2] return True, build_detection(out[0], 0.01, rows, cols) 

كالعادة ، يتم دعم كلتا الطريقتين:

  • وظيفة: / كشف / ملف / نموذج $
  • وظيفة: / كشف / المسار / نموذج دولار

تقسيم


يحتوي مجزئ التجزئة على احتمالات حسب الفئة وحتى في بعد الشبكة العصبية.
تحويل هذا ببساطة إلى قناع فئة:

 def segment(model_id, img): rc, out = run_inference(model_id, img) if not rc: return rc, out out = np.argmax(out, axis=0) out = cv.resize(out, (img.shape[1], img.shape[0]),interpolation=cv.INTER_NEAREST) return True, out 

  • وظيفة: / قطعة / ملف / نموذج دولار
  • ما بعد: / قطعة / المسار / نموذج دولار

استنتاج


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

مرة أخرى ، أستخدم الخدمة على Raspberry Pi ، لكن يمكن تشغيلها على أي نظام أساسي يوجد به python و OpenVino مع NCS.

مراجع


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


All Articles