Prolog
Derzeit kursiert ein Video – wie der Autopilot von Tesla die Straße sieht.
Ich wollte schon lange ein Video mit einer Objektkennung in Echtzeit übertragen.

Das Problem ist, dass ich das Video mit einem Raspberry übertragen möchte, aber die Leistung des neuronalen Erkennungsmoduls lässt zu wünschen übrig.
Intel Neural Computer Stick
Ich habe verschiedene Lösungsmöglichkeiten in Betracht gezogen.
In habe ich mit dem Intel Neural Computer Stick experimentiert. Das Gerät ist leistungsstark, benötigt jedoch ein spezifisches Netzwerkformat.
Obwohl Intel Konverter für gängige Frameworks bereitstellt, gibt es hier einige Fallstricke.
Das Netzwerkformat könnte inkompatibel sein, und selbst wenn es kompatibel ist, können einige Layer auf dem Gerät nicht unterstützt werden. Falls die Unterstützung vorhanden ist, können während der Konvertierung Fehler auftreten, sodass am Ende seltsame Ergebnisse herauskommen.
Im Grunde genommen, wenn man eine beliebige neuronale Netzstruktur möchte, könnte es mit dem NCS problematisch werden. Deshalb habe ich beschlossen, das Problem mit den am weitesten verbreiteten und zugänglichen Tools zu lösen.
Cloud
Eine offensichtliche Alternative zur lokalen Hardwarelösung ist der Wechsel in die Cloud.
Die Auswahl an verfügbaren Optionen ist überwältigend.
Alle führenden Anbieter:
… und Dutzende weniger bekannter Anbieter.
Es ist gar nicht so einfach, aus dieser Vielzahl das Passende auszuwählen.
Ich habe mich entschieden, nichts zu wählen, sondern mein bewährtes Arbeitsmodell mit OpenCV in Docker zu packen und in der Cloud zu betreiben.
Der Vorteil dieses Ansatzes liegt in der Flexibilität und Kontrolle – man kann das neuronale Netzwerk, das Hosting oder den Server wechseln – praktisch alles ist möglich.
Server
Lassen Sie uns mit einem lokalen Prototyp beginnen.
Traditionell verwende ich Flask für das REST API, OpenCV und das MobileSSD-Netzwerk.
Als ich die aktuellen Versionen in Docker installierte, stellte ich fest, dass OpenCV 4.1.2 nicht mit Mobile SSD v1_coco_2018_01_28 funktioniert, deshalb musste ich auf die bewährte Version 11_06_2017 zurückgreifen.
Zu Beginn des Services laden wir die Klassennamen und das Netzwerk:
def init():
tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)
Auf meinem lokalen Docker (auf einem etwas älteren Laptop) dauert dies 0,3 Sekunden, auf dem Raspberry 3,5 Sekunden.
Wir starten die Berechnung:
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 Sekunden, Raspberry – 1,7 Sekunden.
Wir verwandeln den Tensor-Ausgang in ein lesbares 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
Weiter (Bild als Eingabe, Ergebnisse des Detektors im JSON-Format als Ausgabe).
Eine alternative Variante, bei der mehr Arbeit auf den Server verlagert wird: Er umrandet die gefundenen Objekte und gibt das fertige Bild zurück.
Diese Variante ist gut, wenn wir opencv nicht auf dem Server installieren wollen.
Docker
Wir erstellen ein Image.
Der Code wurde aufbereitet und auf , Docker wird es direkt von dort abrufen.
Als Plattform verwenden wir das gleiche Debian Stretch wie auf dem Raspberry – lassen wir den bewährten Tech-Stack unverändert.
Wir müssen flask, protobuf, requests, opencv_python installieren, das Mobile SSD herunterladen, den Servercode von GitHub holen und den 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"]
Einfacher basierend auf requests.
Veröffentlichung auf Docker Hub
Docker-Register entstehen ebenso schnell wie Cloud-Detektoren.
Um es einfach zu halten, werden wir konservativ über .
- Registrieren
- Einloggen:
docker login - Wir überlegen uns einen aussagekräftigen Namen:
docker tag opencv-detect tprlab/opencv-detect-ssd - Das Image auf den Server hochladen:
docker push tprlab/opencv-detect-ssd
In der Cloud starten
Die Auswahl, wo man den Container starten möchte, ist ebenfalls sehr groß.
Alle großen Anbieter (Google, Microsoft, Amazon) bieten im ersten Jahr kostenlos einen Micro-Instance an.
Nach Experimenten mit Microsoft Azure und Google Cloud habe ich mich für Letzteres entschieden – weil es schneller gestartet ist.
Ich habe hier keine Anleitung geschrieben, da dieser Teil sehr spezifisch für den gewählten Anbieter ist.
Ich habe verschiedene Hardware-Optionen ausprobiert,
Niedrige Ebenen (Shared und Dedicated) – 0,4 – 0,5 Sekunden.
Stärkere Maschinen – 0,25 – 0,3.
Nun, selbst im schlimmsten Fall kann der Gewinn dreimal höher sein, das sollten wir versuchen.
Video
Wir starten einen einfachen OpenCV-Videostream auf dem Raspberry, der über Google Cloud erkennt.
Für das Experiment wurde eine Videoaufnahme verwendet, die einst an einer zufälligen Kreuzung gemacht wurde.
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")
Mit dem Detektor werden nicht mehr als drei Bilder pro Sekunde erzeugt, alles läuft sehr langsam.
Wenn man in GCloud eine leistungsstarke Maschine mietet, kann man 4-5 Bilder pro Sekunde erkennen, aber der Unterschied ist mit bloßem Auge praktisch nicht erkennbar, es bleibt alles langsam.

Die Cloud und Transportkosten spielen hier keine Rolle, auf normaler Hardware arbeitet der Detektor mit dieser Geschwindigkeit.
Neural Computer Stick
Ich konnte nicht widerstehen und habe einen Benchmark auf dem NCS durchgeführt.
Die Geschwindigkeit des Detektors lag bei etwas weniger als 0,1 Sekunden, auf jeden Fall 2-3 Mal schneller als die Cloud auf einem schwachen Rechner, also 8-9 Bilder pro Sekunde.

Der Unterschied in den Ergebnissen erklärt sich dadurch, dass auf dem NCS die Mobile SSD Version 2018_01_28 verwendet wurde.
P.S. Darüber hinaus haben Tests gezeigt, dass ein leistungsstarker Desktop-Computer mit einem I7-Prozessor geringfügig bessere Ergebnisse erzielt und es möglich ist, bis zu 10 Frames pro Sekunde zu erreichen.
Cluster
Das Experiment ging weiter und ich habe den Detector auf fünf Knoten in Google Kubernetes eingerichtet.
Die Pods an sich waren schwach und jeder von ihnen konnte nicht mehr als 2 Frames pro Sekunde verarbeiten.
Wenn man jedoch einen Cluster mit N Knoten startet und die Frames in N Threads verarbeitet, kann man bei ausreichender Knotenanzahl (5) die gewünschten 10 Frames pro Sekunde erreichen.
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/jpeg
' + bytearray(outFrame) + b'
')
keep_polling = len(Q) > 0
else:
keep_polling = len(Q) >= M
Das ist das Ergebnis:

Nicht ganz so flink wie mit NCS, aber flotter als in einem Stream.
Der Gewinn ist natürlich nicht linear – es gibt Verzögerungen durch die Synchronisation und das tiefe Kopieren von Bildern in OpenCV.
Fazit
Insgesamt erlaubt das Experiment die Schlussfolgerung, dass man mit ein wenig Aufwand aus einer einfachen Cloud das Beste herausholen kann.
Ein leistungsstarker Desktop oder eine lokale Hardware ermöglichen jedoch bessere Ergebnisse, und das ganz ohne Tricks.
Links
Quelle: habr.com
