Film przedstawiający detektor obiektów w chmurze na Raspberry Pi

Prolog

W Internecie krąży teraz wideo pokazujące, jak autopilot Tesli widzi drogę.

Już od dawna nosiłem się z zamiarem transmisji wideo wzbogaconego o detektor i to w czasie rzeczywistym.

Film przedstawiający detektor obiektów w chmurze na Raspberry Pi

Problem w tym, że chcę transmitować wideo z Raspberry, a działanie detektora sieci neuronowych na nim pozostawia wiele do życzenia.

Kij komputerowy Intel Neural Computer

Rozważałem różne rozwiązania.

В ostatni artykuł eksperymentowano z Intel Neural Computer Stick. Sprzęt jest potężny, ale wymaga własnego formatu sieciowego.

Mimo że Intel zapewnia konwertery dla głównych platform, istnieje wiele pułapek.

Na przykład format wymaganej sieci może być niekompatybilny, a jeśli jest kompatybilny, niektóre warstwy mogą nie być obsługiwane na urządzeniu, a jeśli są obsługiwane, mogą wystąpić błędy podczas procesu konwersji, w wyniku czego na wyjściu otrzymujemy dziwne rzeczy.

Ogólnie rzecz biorąc, jeśli potrzebujesz dowolnej sieci neuronowej, może ona nie działać z NCS. Dlatego postanowiłem spróbować rozwiązać problem za pomocą najbardziej powszechnych i dostępnych narzędzi.

Chmura

Oczywistą alternatywą dla lokalnego rozwiązania sprzętowego jest przejście do chmury.

Gotowe opcje - moje oczy szaleją.

Wszyscy liderzy:

...I dziesiątki mniej znanych.

Wybór spośród tej odmiany wcale nie jest łatwy.

I zdecydowałem się nie wybierać, ale owinąć stary dobry działający schemat na OpenCV w Dockerze i uruchomić go w chmurze.

Zaletą takiego podejścia jest elastyczność i kontrola - możesz zmieniać sieć neuronową, hosting, serwer - w sumie dowolnie.

Server

Zacznijmy od lokalnego prototypu.

Tradycyjnie korzystam z Flaska dla REST API, OpenCV i sieci MobileSSD.

Po zainstalowaniu aktualnych wersji na Dockerze odkryłem, że OpenCV 4.1.2 nie działa z Mobile SSD v1_coco_2018_01_28 i musiałem wrócić do sprawdzonej wersji 11/06_2017.

Na starcie usługi ładujemy nazwy klas i sieć:

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

Na lokalnym oknie dokowanym (na niezbyt młodym laptopie) zajmuje to 0.3 sekundy, na Raspberry - 3.5.

Zacznijmy obliczenia:

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()

Docker – 0.2 sek., Malinowy – 1.7.

Zamiana wydechu tensora w czytelny 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

Dalej wyeksportuj tę operację przez Flask(wejście to obraz, wyjście to wyniki detektora w jsonie).

Alternatywna opcja, w której więcej pracy zostaje przerzuconych na serwer: on sam okrąża znalezione obiekty i zwraca gotowy obraz.

Ta opcja jest dobra, gdy nie chcemy przeciągać opencv na serwer.

Doker

Zbieramy obraz.

Kod jest przeczesywany i publikowany dalej Github, doker pobierze go bezpośrednio stamtąd.

Jako platformę przyjmiemy ten sam Debian Stretch, co na Raspberry – nie odejdziemy od sprawdzonego stosu technologicznego.

Musisz zainstalować flask, protobuf, żądania, opencv_python, pobrać Mobile SSD, kod serwera z Github i uruchomić serwer.

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"]

Prosty klient detektora w oparciu o prośby.

Publikowanie w Docker Hub

Rejestry Dockerów mnożą się z prędkością nie mniejszą niż detektory chmur.

Aby nie zawracać sobie głowy, przejdziemy konserwatywnie DockerHub.

  1. Zarejestrować
  2. Zaloguj sie:
    login dokera
  3. Wymyślmy sensowną nazwę:
    tag dokera opencv-detect tprlab/opencv-detect-ssd
  4. Prześlij obraz na serwer:
    docker push tprlab/opencv-detect-ssd

Uruchamiamy w chmurze

Wybór miejsca umieszczenia kontenera również jest dość szeroki.

Wszyscy duzi gracze (Google, Microsoft, Amazon) oferują mikroinstancję za darmo przez pierwszy rok.
Po eksperymentach z Microsoft Azure i Google Cloud zdecydowałem się na tę drugą opcję, ponieważ działała szybciej.

Nie pisałem tutaj instrukcji, ponieważ ta część jest bardzo specyficzna dla wybranego dostawcy.

Próbowałem różnych opcji sprzętowych,
Niskie poziomy (współdzielone i dedykowane) - 0.4 - 0.5 sekundy.
Mocniejsze samochody - 0.25 - 0.3.
Cóż, nawet w najgorszym przypadku wygrana jest trzykrotna, możesz spróbować.

Wideo

Uruchamiamy prosty streamer wideo OpenCV na Raspberry, wykrywający poprzez Google Cloud.
Do eksperymentu wykorzystano plik wideo, który został kiedyś nakręcony w przypadkowym skrzyżowaniu.


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")

Z detektorem uzyskujemy nie więcej niż trzy klatki na sekundę, wszystko idzie bardzo wolno.
Jeśli weźmiesz potężną maszynę do GCloud, możesz wykryć 4-5 klatek na sekundę, ale różnica jest prawie niewidoczna dla oka, nadal jest powolna.

Film przedstawiający detektor obiektów w chmurze na Raspberry Pi

Chmura i koszty transportu nie mają z tym nic wspólnego; wykrywacz działa na zwykłym sprzęcie i działa z taką prędkością.

Neuronowy kij komputerowy

Nie mogłem się oprzeć i przeprowadziłem test porównawczy na NCS.

Szybkość detektora była nieco mniejsza niż 0.1 sekundy, w każdym razie 2-3 razy większa niż chmura na słabej maszynie, czyli 8-9 klatek na sekundę.

Film przedstawiający detektor obiektów w chmurze na Raspberry Pi

Różnicę w wynikach tłumaczy fakt, że NCS korzystał z Mobile SSD w wersji 2018_01_28.

PS Poza tym eksperymenty wykazały, że nieco lepszy komputer stacjonarny z procesorem I7 radzi sobie z nieco lepszymi wynikami i okazało się, że da się na nim wycisnąć 10 klatek na sekundę.

Klaster

Eksperyment poszedł dalej i zainstalowałem detektor na pięciu węzłach w Google Kubernetes.
Same strąki były słabe i każdy z nich nie potrafił przetworzyć więcej niż 2 klatki na sekundę.
Ale jeśli uruchomisz klaster z N węzłami i przeanalizujesz ramki w N wątkach, to przy wystarczającej liczbie węzłów (5) możesz osiągnąć pożądane 10 klatek na sekundę.

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

Oto co się stało:

Film przedstawiający detektor obiektów w chmurze na Raspberry Pi

Trochę wolniej niż z NCS, ale za to bardziej energicznie niż w jednym strumieniu.

Wzmocnienie oczywiście nie jest liniowe - istnieją nakładki do synchronizacji i głębokiego kopiowania obrazów opencv.

wniosek

Ogólnie rzecz biorąc, eksperyment pozwala nam stwierdzić, że jeśli spróbujesz, możesz obejść się bez prostej chmury.

Ale potężny komputer stacjonarny lub sprzęt lokalny pozwala osiągnąć lepsze wyniki i to bez żadnych sztuczek.

referencje

Źródło: www.habr.com

Dodaj komentarz