Video van Cloud Object Detector op Raspberry Pi

proloog

Er circuleert inmiddels een video op internet waarin te zien is hoe de automatische piloot van Tesla de weg ziet.

Ik heb er lang naar uitgekeken om video verrijkt met een detector uit te zenden, en wel in realtime.

Video van Cloud Object Detector op Raspberry Pi

Het probleem is dat ik video van Raspberry wil uitzenden, en de prestaties van de neurale netwerkdetector erop laten veel te wensen over.

Intel neurale computerstick

Ik heb verschillende oplossingen overwogen.

В laatste artikel geëxperimenteerd met Intel Neural Computer Stick. De hardware is krachtig, maar vereist een eigen netwerkformaat.

Hoewel Intel converters levert voor grote raamwerken, zijn er een aantal valkuilen.

Het formaat van het vereiste netwerk kan bijvoorbeeld incompatibel zijn, en als het compatibel is, worden sommige lagen mogelijk niet ondersteund op het apparaat. Als ze wel worden ondersteund, kunnen er tijdens het conversieproces fouten optreden, waardoor we krijgen een aantal vreemde dingen aan de uitgang.

Als je een willekeurig neuraal netwerk wilt, werkt het over het algemeen mogelijk niet met NCS. Daarom besloot ik te proberen het probleem op te lossen met behulp van de meest voorkomende en toegankelijke hulpmiddelen.

wolk

Het voor de hand liggende alternatief voor een lokale hardwareoplossing is om naar de cloud te gaan.

Kant-en-klare opties - mijn ogen worden wild.

Alle leiders:

... En tientallen minder bekende.

Kiezen tussen deze variëteit is helemaal niet eenvoudig.

En ik besloot niet te kiezen, maar het goede oude werkschema op OpenCV in Docker te verpakken en in de cloud uit te voeren.

Het voordeel van deze aanpak is flexibiliteit en controle - u kunt het neurale netwerk, de hosting en de server wijzigen - in het algemeen, elke gril.

Server

Laten we beginnen met een lokaal prototype.

Traditioneel gebruik ik Flask voor REST API, OpenCV en MobileSSD-netwerk.

Nadat ik de huidige versies op Docker had geïnstalleerd, ontdekte ik dat OpenCV 4.1.2 niet werkt met Mobile SSD v1_coco_2018_01_28, en moest ik teruggaan naar het beproefde 11/06_2017.

Aan het begin van de service laden we de klassennamen en het netwerk:

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

Op een lokale docker (op een niet erg jonge laptop) duurt het 0.3 seconden, op Raspberry - 3.5.

Laten we beginnen met de berekening:

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 sec, framboos - 1.7.

Tensor-uitlaat omzetten in leesbare 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

verder exporteer deze bewerking via Flask(invoer is een afbeelding, uitvoer is de resultaten van de detector in json).

Een alternatieve optie, waarbij meer werk naar de server wordt verschoven: deze omcirkelt zelf de gevonden objecten en retourneert de voltooide afbeelding.

Deze optie is goed als we opencv niet naar de server willen slepen.

Dokwerker

Wij verzamelen het beeld.

De code wordt uitgekamd en erop gepost Github, zal Docker het rechtstreeks vanaf daar overnemen.

Als platform nemen we dezelfde Debian Stretch als op Raspberry - we wijken niet af van de bewezen tech-stack.

Je moet flask, protobuf, verzoeken, opencv_python installeren, Mobile SSD, servercode van Github downloaden en de server starten.

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

eenvoudig detector-client op basis van verzoeken.

Publiceren naar Docker Hub

Docker-registers vermenigvuldigen zich met een snelheid die niet minder is dan die van clouddetectoren.

Om ons niet druk te maken, gaan we conservatief door DockerHub.

  1. Register
  2. Log in:
    docker inloggen
  3. Laten we een betekenisvolle naam bedenken:
    docker-tag opencv-detect tprlab/opencv-detect-ssd
  4. Upload de afbeelding naar de server:
    docker push tprlab/opencv-detect-ssd

Wij lanceren in de cloud

De keuze waar de container moet worden geplaatst, is ook vrij breed.

Alle grote spelers (Google, Microsoft, Amazon) bieden het eerste jaar gratis een micro-instantie aan.
Na te hebben geëxperimenteerd met Microsoft Azure en Google Cloud, heb ik voor het laatste gekozen omdat het sneller van de grond kwam.

Ik heb hier geen instructies geschreven, omdat dit deel zeer specifiek is voor de geselecteerde aanbieder.

Ik heb verschillende hardwareopties geprobeerd,
Lage niveaus (gedeeld en speciaal) - 0.4 - 0.5 seconden.
Krachtigere auto's - 0.25 - 0.3.
Nou ja, zelfs in het ergste geval zijn de winsten drie keer, je kunt het proberen.

Video

We lanceren een eenvoudige OpenCV-videostreamer op Raspberry, die detecteert via Google Cloud.
Voor het experiment is gebruik gemaakt van een videobestand dat ooit op een willekeurig kruispunt is gefilmd.


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

Met de detector halen we niet meer dan drie beelden per seconde, alles gaat heel langzaam.
Als je een krachtige machine in GCloud neemt, kun je 4-5 frames per seconde detecteren, maar het verschil is bijna onzichtbaar voor het oog, het is nog steeds traag.

Video van Cloud Object Detector op Raspberry Pi

De cloud- en transportkosten hebben er niets mee te maken; de detector draait op gewone hardware en werkt zo snel.

Neurale computerstick

Ik kon het niet laten en voerde de benchmark uit op NCS.

De snelheid van de detector was iets langzamer dan 0.1 seconde, in ieder geval 2-3 keer sneller dan de cloud op een zwakke machine, namelijk 8-9 frames per seconde.

Video van Cloud Object Detector op Raspberry Pi

Het verschil in resultaten wordt verklaard door het feit dat NCS Mobile SSD versie 2018_01_28 draaide.

PS Daarnaast is uit experimenten gebleken dat een redelijk krachtige desktopmachine met een I7-processor iets betere resultaten laat zien en bleek het mogelijk om er 10 frames per seconde op te persen.

TROS

Het experiment ging verder en ik installeerde de detector op vijf knooppunten in Google Kubernetes.
De pods zelf waren zwak en elk van hen kon niet meer dan 2 frames per seconde verwerken.
Maar als u een cluster met N knooppunten uitvoert en frames in N threads ontleedt, kunt u met een voldoende aantal knooppunten (5) de gewenste 10 frames per seconde bereiken.

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

Dit is wat er gebeurde:

Video van Cloud Object Detector op Raspberry Pi

Iets minder snel dan bij NCS, maar krachtiger dan in één stroom.

De winst is uiteraard niet lineair: er zijn overlays voor synchronisatie en diep kopiëren van opencv-afbeeldingen.

Conclusie

Over het geheel genomen kunnen we uit het experiment concluderen dat als je het probeert, je weg kunt komen met een eenvoudige cloud.

Maar met een krachtige desktop of lokale hardware kunt u betere resultaten behalen, en zonder enige trucjes.

referenties

Bron: www.habr.com

Voeg een reactie