فيديو لـ Cloud Object Detector على Raspberry Pi

فاتحة

يتم الآن تداول مقطع فيديو على الإنترنت يوضح كيف يرى الطيار الآلي في سيارة تسلا الطريق.

لقد كنت متشوقًا منذ فترة طويلة لبث فيديو معزز بالكاشف، وفي الوقت الفعلي.

فيديو لـ Cloud Object Detector على Raspberry Pi

المشكلة هي أنني أرغب في بث فيديو من Raspberry، وأداء كاشف الشبكة العصبية عليه يترك الكثير مما هو مرغوب فيه.

عصا كمبيوتر إنتل العصبية

فكرت في حلول مختلفة.

В المادة الاخيرة جربت عصا الكمبيوتر العصبية Intel. الجهاز قوي، ولكنه يتطلب تنسيق الشبكة الخاص به.

على الرغم من أن Intel توفر محولات لأطر العمل الرئيسية، إلا أن هناك عددًا من المخاطر.

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

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

سحابة

البديل الواضح لحل الأجهزة المحلية هو الانتقال إلى السحابة.

خيارات جاهزة - عيني تشتعل.

جميع القادة:

... والعشرات من الأقل شهرة.

الاختيار من بين هذا التنوع ليس بالأمر السهل على الإطلاق.

وقررت عدم الاختيار، ولكن تغليف مخطط العمل القديم الجيد على OpenCV في Docker وتشغيله في السحابة.

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

الخادم

لنبدأ بنموذج أولي محلي.

تقليديًا، أستخدم Flask لشبكة REST API وOpenCV وMobileSSD.

بعد تثبيت الإصدارات الحالية على Docker، اكتشفت أن OpenCV 4.1.2 لا يعمل مع Mobile SSD v1_coco_2018_01_28، واضطررت إلى العودة إلى الإصدار 11/06_2017 المثبت.

في بداية الخدمة، نقوم بتحميل أسماء الفئات والشبكة:

def init():
    tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
    return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)

على عامل الإرساء المحلي (على جهاز كمبيوتر محمول غير صغير جدًا) يستغرق الأمر 0.3 ثانية، على Raspberry - 3.5.

لنبدأ الحساب:

def inference(img):
    net.setInput(cv.dnn.blobFromImage(img, 1.0/127.5, (300, 300), (127.5, 127.5, 127.5), swapRB=True, crop=False))
    return net.forward()

عامل الميناء - 0.2 ثانية، التوت - 1.7.

تحويل عادم الموتر إلى json قابل للقراءة:

def build_detection(data, thr, rows, cols):
    ret = []
    for detection in data[0,0,:,:]:
        score = float(detection[2])
        if score > thr:
            cls = int(detection[1])
            a = {"class" : cls, "name" : tf_labels.getLabel(cls),  "score" : score}
            a["x"] = int(detection[3] * cols)
            a["y"] = int(detection[4] * rows)
            a["w"] = int(detection[5] * cols ) - a["x"]
            a["h"] = int(detection[6] * rows) - a["y"]
            ret.append(a)
    return ret

إضافي تصدير هذه العملية عبر Flask(الإدخال عبارة عن صورة، والإخراج هو نتائج الكاشف في json).

خيار بديل يتم من خلاله نقل المزيد من العمل إلى الخادم: فهو نفسه يدور حول الكائنات التي تم العثور عليها ويعيد الصورة النهائية.

يعد هذا الخيار جيدًا حيث لا نريد سحب opencv إلى الخادم.

عامل ميناء

نحن نجمع الصورة.

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

كمنصة، سنتخذ نفس Debian Stretch كما هو الحال في Raspberry - ولن نحيد عن مجموعة التكنولوجيا التي أثبتت جدواها.

تحتاج إلى تثبيت flask وprotobuf والطلبات وopencv_python وتنزيل Mobile SSD ورمز الخادم من Github وبدء تشغيل الخادم.

FROM python:3.7-stretch

RUN pip3 install flask
RUN pip3 install protobuf
RUN pip3 install requests
RUN pip3 install opencv_python

ADD http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_11_06_2017.tar.gz /
RUN tar -xvf /ssd_mobilenet_v1_coco_11_06_2017.tar.gz

ADD https://github.com/tprlab/docker-detect/archive/master.zip /
RUN unzip /master.zip

EXPOSE 80

CMD ["python3", "/docker-detect-master/detect-app/app.py"]

بسيط عميل الكاشف بناء على الطلبات.

النشر إلى Docker Hub

تتكاثر سجلات Docker بسرعة لا تقل عن سرعة أجهزة الكشف عن السحابة.

من أجل عدم الإزعاج، سنذهب بشكل متحفظ DockerHub.

  1. يسجل
  2. تسجيل الدخول:
    تسجيل دخول عامل ميناء
  3. دعونا نتوصل إلى اسم ذو معنى:
    علامة عامل ميناء opencv-detect tprlab/opencv-detect-ssd
  4. تحميل الصورة إلى الخادم:
    دفع عامل الإرساء tprlab/opencv-detect-ssd

نطلق في السحابة

إن اختيار مكان تشغيل الحاوية واسع جدًا أيضًا.

يقدم جميع اللاعبين الكبار (Google، وMicrosoft، وAmazon) مثيلًا صغيرًا مجانًا للسنة الأولى.
بعد تجربة استخدام Microsoft Azure وGoogle Cloud، استقررت على الخيار الأخير لأنه انطلق بشكل أسرع.

لم أكتب تعليمات هنا، لأن هذا الجزء خاص جدًا بالمزود المحدد.

لقد جربت خيارات الأجهزة المختلفة،
المستويات المنخفضة (المشتركة والمخصصة) - 0.4 - 0.5 ثانية.
سيارات أكثر قوة - 0.25 - 0.3.
حسنًا، حتى في أسوأ السيناريوهات، تكون المكاسب ثلاث مرات، يمكنك المحاولة.

فيديو

أطلقنا أداة بث فيديو OpenCV بسيطة على Raspberry، ونكتشفها من خلال Google Cloud.
بالنسبة للتجربة، تم استخدام ملف فيديو تم تصويره في تقاطع عشوائي.


def handle_frame(frame):
    return detect.detect_draw_img(frame)
       
def generate():
    while True:
        rc, frame = vs.read()
        outFrame = handle_frame(frame)
        if outFrame is None:
            (rc, outFrame) = cv.imencode(".jpg", frame)
        yield(b'--framern' b'Content-Type: image/jpegrnrn' + bytearray(outFrame) + b'rn')

@app.route("/stream")
def video_feed():
    return Response(generate(), mimetype = "multipart/x-mixed-replace; boundary=frame")

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

فيديو لـ Cloud Object Detector على Raspberry Pi

لا علاقة للسحابة وتكاليف النقل بالأمر، فالكاشف يعمل على أجهزة عادية ويعمل بهذه السرعة.

عصا الكمبيوتر العصبية

لم أستطع المقاومة وقمت بتشغيل المعيار على NCS.

كانت سرعة الكاشف أبطأ قليلاً من 0.1 ثانية، وعلى أي حال أسرع 2-3 مرات من السحابة على جهاز ضعيف، أي 8-9 إطارات في الثانية.

فيديو لـ Cloud Object Detector على Raspberry Pi

يُفسر الاختلاف في النتائج بحقيقة أن NCS كانت تقوم بتشغيل إصدار Mobile SSD رقم 2018_01_28.

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

كتلة

ذهبت التجربة إلى أبعد من ذلك وقمت بتثبيت الكاشف على خمس عقد في Google Kubernetes.
كانت القرون نفسها ضعيفة ولم تتمكن كل واحدة منها من معالجة أكثر من إطارين في الثانية.
ولكن إذا قمت بتشغيل مجموعة تحتوي على عقد N وإطارات تحليلية في سلاسل N، فمن خلال عدد كافٍ من العقد (5) يمكنك تحقيق الإطارات العشرة المرغوبة في الثانية.

def generate():
    while True:
        rc, frame = vs.read()
        if frame is not None:
            future = executor.submit(handle_frame, (frame.copy()))
            Q.append(future)

        keep_polling = len(Q) > 0
        while(keep_polling):            
            top = Q[0]
            if top.done():
                outFrame = top.result()
                Q.popleft()
                if outFrame:
                    yield(b'--framern' b'Content-Type: image/jpegrnrn' + bytearray(outFrame) + b'rn')
                keep_polling = len(Q) > 0
            else:
                keep_polling = len(Q) >= M

هنا ما حدث:

فيديو لـ Cloud Object Detector على Raspberry Pi

أقل سرعة قليلاً من NCS، ولكنه أكثر قوة من تيار واحد.

المكسب، بالطبع، ليس خطيًا - فهناك تراكبات للمزامنة والنسخ العميق لصور opencv.

اختتام

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

لكن سطح المكتب أو الأجهزة المحلية القوية تسمح لك بتحقيق نتائج أفضل، ودون أي حيل.

مراجع

المصدر: www.habr.com

إضافة تعليق