Video cu detector de obiecte în cloud pe Raspberry Pi

prolog

Un videoclip circulă acum pe internet care arată cum vede pilotul automat Tesla drumul.

Am mâncărime de mult timp să difuzez videoclipuri îmbogățite cu un detector și în timp real.

Video cu detector de obiecte în cloud pe Raspberry Pi

Problema este că vreau să difuzez video de la Raspberry, iar performanța detectorului de rețea neuronală de pe el lasă de dorit.

Stick de computer Intel Neural

Am luat în calcul soluții diferite.

В ultimul articol a experimentat cu Intel Neural Computer Stick. Hardware-ul este puternic, dar necesită propriul format de rețea.

Chiar dacă Intel oferă convertoare pentru cadrele majore, există o serie de capcane.

De exemplu, formatul rețelei necesare poate fi incompatibil și, dacă este compatibil, este posibil ca unele straturi să nu fie acceptate pe dispozitiv și, dacă sunt acceptate, pot apărea erori în timpul procesului de conversie, drept urmare primim niște lucruri ciudate la ieșire.

În general, dacă doriți un fel de rețea neuronală arbitrară, atunci este posibil să nu funcționeze cu NCS. Prin urmare, am decis să încerc să rezolv problema folosind cele mai răspândite și accesibile instrumente.

nor

Alternativa evidentă la o soluție hardware locală este să mergi în cloud.

Opțiuni gata făcute - ochii îmi fug.

Toți liderii:

... Și zeci de altele mai puțin cunoscute.

Alegerea dintre această varietate nu este deloc ușoară.

Și am decis să nu aleg, ci să împachetez vechea schemă de lucru bună pe OpenCV în Docker și să o rulez în cloud.

Avantajul acestei abordări este flexibilitatea și controlul - puteți schimba rețeaua neuronală, găzduire, server - în general, orice capriciu.

Server

Să începem cu un prototip local.

În mod tradițional, folosesc Flask pentru REST API, OpenCV și rețeaua MobileSSD.

După ce am instalat versiunile actuale pe Docker, am descoperit că OpenCV 4.1.2 nu funcționează cu Mobile SSD v1_coco_2018_01_28 și a trebuit să revin la data dovedită 11/06_2017.

La începutul serviciului, încărcăm numele claselor și rețeaua:

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

Pe un docker local (pe un laptop nu foarte tânăr) durează 0.3 secunde, pe Raspberry - 3.5.

Să începem calculul:

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 secunde, Zmeura - 1.7.

Transformarea eșapamentului tensorului în json lizibil:

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

mai departe exportați această operațiune prin Flask(intrarea este o imagine, ieșirea este rezultatele detectorului în json).

O opțiune alternativă, în care mai multă muncă este transferată către server: el însuși încercuiește obiectele găsite și returnează imaginea finală.

Această opțiune este bună acolo unde nu vrem să tragem opencv pe server.

Docher

Colectăm imaginea.

Codul este pieptănat și postat pe Github, docker îl va lua direct de acolo.

Ca platformă, vom lua același Debian Stretch ca și pe Raspberry - nu ne vom abate de la stiva tehnologică dovedită.

Trebuie să instalați flask, protobuf, requests, opencv_python, să descărcați Mobile SSD, codul de server din Github și să porniți serverul.

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

simplu client detector pe baza cererilor.

Publicarea în Docker Hub

Registrele Docker se înmulțesc cu o viteză nu mai mică decât detectoarele de nor.

Pentru a nu ne deranja, vom trece conservator DockerHub.

  1. Inregistreaza-te
  2. Log in:
    conectare la docker
  3. Să găsim un nume semnificativ:
    etichetă docker opencv-detect tprlab/opencv-detect-ssd
  4. Încărcați imaginea pe server:
    docker push tprlab/opencv-detect-ssd

Lansăm în cloud

Alegerea unde să ruleze containerul este, de asemenea, destul de largă.

Toți jucătorii mari (Google, Microsoft, Amazon) oferă o microinstanță gratuită pentru primul an.
După ce am experimentat cu Microsoft Azure și Google Cloud, m-am hotărât pe acesta din urmă pentru că a decolat mai repede.

Nu am scris instrucțiuni aici, deoarece această parte este foarte specifică furnizorului selectat.

Am încercat diferite opțiuni hardware,
Niveluri scăzute (partajat și dedicat) - 0.4 - 0.5 secunde.
Mașini mai puternice - 0.25 - 0.3.
Ei bine, chiar și în cel mai rău caz, câștigurile sunt de trei ori, poți încerca.

video

Lansăm un simplu streamer video OpenCV pe Raspberry, detectând prin Google Cloud.
Pentru experiment, a fost folosit un fișier video care a fost filmat cândva la o intersecție aleatorie.


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

Cu detectorul nu obținem mai mult de trei cadre pe secundă, totul merge foarte încet.
Dacă introduceți o mașină puternică în GCloud, puteți detecta 4-5 cadre pe secundă, dar diferența este aproape invizibilă pentru ochi, este încă lentă.

Video cu detector de obiecte în cloud pe Raspberry Pi

Cloudul și costurile de transport nu au nimic de-a face cu asta; detectorul funcționează pe hardware obișnuit și funcționează cu o astfel de viteză.

Stick de computer neuronal

Nu am putut rezista și am rulat benchmark-ul pe NCS.

Viteza detectorului a fost puțin mai mică de 0.1 secunde, în orice caz de 2-3 ori mai rapidă decât cea a norului pe o mașină slabă, adică 8-9 cadre pe secundă.

Video cu detector de obiecte în cloud pe Raspberry Pi

Diferența de rezultate se explică prin faptul că NCS rula SSD mobil versiunea 2018_01_28.

PS În plus, experimentele au arătat că o mașină desktop destul de puternică cu un procesor I7 arată rezultate puțin mai bune și s-a dovedit a fi posibil să stoarce 10 cadre pe secundă pe ea.

Cluster

Experimentul a mers mai departe și am instalat detectorul pe cinci noduri din Google Kubernetes.
Păstăile în sine erau slabe și fiecare dintre ele nu putea procesa mai mult de 2 cadre pe secundă.
Dar dacă rulați un cluster cu N noduri și analizați cadre în N fire, atunci cu un număr suficient de noduri (5) puteți obține cele 10 cadre pe secundă dorite.

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

Iată ce s-a întâmplat:

Video cu detector de obiecte în cloud pe Raspberry Pi

Puțin mai puțin rapid decât cu NCS, dar mai viguros decât într-un singur flux.

Câștigul, desigur, nu este liniar - există suprapuneri pentru sincronizare și copiere profundă a imaginilor opencv.

Concluzie

În general, experimentul ne permite să concluzionam că, dacă încerci, poți scăpa cu un simplu nor.

Dar un desktop puternic sau un hardware local vă permite să obțineți rezultate mai bune și fără trucuri.

referințe

Sursa: www.habr.com

Adauga un comentariu