Видео с облачен детектор на обекти на Raspberry Pi

Пролог

В мрежата се разпространява видео — как автопилотът на Тесла вижда пътя.

Отдавна ми се искаше да предавам видео, обвързано с детектор, и то в реално време.

Видео с облачен детектор на обекти на Raspberry Pi

Проблемът е, че искам да предавам видео с Raspberry, а производителността на невронния детектор на него оставя много да се желае.

Intel Neural Computer Stick

Разглеждах различни варианти за решение.

В прошлата статия експериментирах с Intel Neural Computer Stick. Устройството е мощно, но изисква свой формат на мрежата.

Въпреки че Интел предоставя конвертори за основните фреймворкове, тук има редица подводни камъни.

Например, формата на необходимата мрежа може да не е съвместим, а ако е съвместим, някои слоеве може да не се поддържат от устройството, а ако се поддържат, по време на конверсията може да възникнат грешки, в резултат на което на изхода получаваме някакви странни неща.

Ако искате произволна невронна мрежа, с NCS може да не успеете. Затова реших да опитам да реша проблема чрез най-масовите и достъпни инструменти.

Облако

Очевидна алтернатива на локално-хардварното решение е да се премине в облака.

Готовите варианти са наистина много.

Всички лидери:

… и десетки по-малко известни.

Изборът сред това многообразие не е лесен.

Реших да не избирам, а да върна старата добра работна схема в OpenCV в докер и да я стартирам в облака.

Предимството на този подход е в гъвкавостта и контрола — можете да сменяте невронната мрежа, хостинга, сървъра — изобщо, каквото пожелаете.

Сървър

Нека започнем с локален прототип.

Традиционно използвам Flask за REST API, OpenCV и MobileSSD мрежа.

Поставяйки текущите версии в докер, открих, че 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 сек, Raspberry — 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 на сървъра.

Докер

Събираме образа.

Кодът е обработен и публикуван на Линукс версии, Docker ще го вземе директно от там.

Като платформа ще вземем същия Debian Stretch, както и на Raspberry — да не се отклоняваме от проверената технологична стека.

Трябва да инсталираме flask, protobuf, requests, 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"]

Прост клиент за детектора на базата на requests.

Публикация в Docker Hub

Docker регистрите се появяват с скорост не по-малка от облачните детектори.

За да не се задълбочавам, ние консервативно ще преминем през Docker Hub.

  1. Регистрираме се
  2. Авторизираме се:
    docker login
  3. Предлагам съдържателно име:
    docker tag opencv-detect tprlab/opencv-detect-ssd
  4. Качване на образа на сървъра:
    docker push 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 кадъра в секунда, но разликата с окото почти не се забелязва, пак е бавно.

Видео с облачен детектор на обекти на Raspberry Pi

Облакът и транспортните разходи не влизат в сметката, на обикновен хардуер детекторът работи с такава скорост.

Neural Computer Stick

Не се сдържах и направих бенчмарк на NCS.

Скоростта на детектора беше малко под 0.1 секунда, така или иначе 2-3 пъти по-бързо от облака на слаба машина, т.е. 8-9 кадъра в секунда.

Видео с облачен детектор на обекти на Raspberry Pi

Разликата в резултатите се обяснява с това, че на NCS беше стартиран Mobile SSD версия 2018_01_28.

P.S. Освен това експериментите показаха, че достатъчно мощен настолен компютър с процесор I7 показва малко по-добри резултати и на него стана възможно да се постигнат 10 кадъра в секунда.

Кластер

Експериментът продължи и поставих детектора на пет възела в Google Kubernetes.
Сами по себе си подите бяха слаби и всеки от тях не можеше да обработи повече от 2 кадъра в секунда.
Но ако стартирам кластер на N възела и разбивам кадрите на N потока — при достатъчен брой възли (5) може да се постигнат желаните 10 кадъра в секунда.

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

Вижте какво стана:

Видео с облачен детектор на обекти на Raspberry Pi

Не толкова бързо, колкото с NCS, но по-добре отколкото в един поток.

Печалбата, разбира се, не е линейна — има забавяния при синхронизацията и дълбокото копиране на изображенията в OpenCV.

Заключение

Общо, експериментът позволява извода, че ако се постараеш, можеш да се справиш и с прост облак.

Но мощен настолен компютър или локален хардуер позволяват постигането на по-добри резултати, и то без всякакви хитринки.

Връзки

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster