prolog
En video cirkulerer nu på internettet, der viser, hvordan Teslas autopilot ser vejen.
Jeg har længe kløet efter at udsende video beriget med en detektor og i realtid.
Problemet er, at jeg vil udsende video fra Raspberry, og ydeevnen af den neurale netværksdetektor på den lader meget tilbage at ønske.
Intel Neural Computer Stick
Jeg overvejede forskellige løsninger.
В
Selvom Intel leverer konvertere til større frameworks, er der en række faldgruber.
For eksempel kan formatet på det påkrævede netværk være inkompatibelt, og hvis det er kompatibelt, understøttes nogle lag muligvis ikke på enheden, og hvis de understøttes, kan der opstå fejl under konverteringsprocessen, som et resultat af vi får nogle mærkelige ting ved udgangen.
Generelt, hvis du ønsker en form for vilkårligt neuralt netværk, så virker det muligvis ikke med NCS. Derfor besluttede jeg at forsøge at løse problemet ved hjælp af de mest udbredte og tilgængelige værktøjer.
sky
Det oplagte alternativ til en lokal hardwareløsning er at gå til skyen.
Færdiglavede muligheder - mine øjne løber løbsk.
Alle ledere:
... Og snesevis af mindre kendte.
At vælge blandt denne sort er slet ikke let.
Og jeg besluttede ikke at vælge, men at pakke det gode gamle arbejdsskema på OpenCV i Docker og køre det i skyen.
Fordelen ved denne tilgang er fleksibilitet og kontrol - du kan ændre det neurale netværk, hosting, server - generelt ethvert indfald.
Server
Lad os starte med en lokal prototype.
Traditionelt bruger jeg Flask til REST API, OpenCV og MobileSSD netværk.
Efter at have installeret de nuværende versioner på Docker, opdagede jeg, at OpenCV 4.1.2 ikke virker med Mobile SSD v1_coco_2018_01_28, og jeg var nødt til at rulle tilbage til den gennemprøvede 11/06_2017.
Ved starten af tjenesten indlæser vi klassenavne og netværk:
def init():
tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)
På en lokal docker (på en ikke særlig ung bærbar computer) tager det 0.3 sekunder, på Raspberry - 3.5.
Lad os starte udregningen:
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., Raspberry - 1.7.
Forvandler tensorudstødning til læsbar 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
yderligere
En alternativ mulighed, hvor mere arbejde flyttes til serveren: den selv cirkler de fundne objekter og returnerer det færdige billede.
Denne mulighed er god, hvor vi ikke ønsker at trække opencv til serveren.
Docker
Vi samler billedet.
Koden kæmmes og lægges på
Som platform tager vi den samme Debian Stretch som på Raspberry - vi vil ikke afvige fra den gennemprøvede teknologistak.
Du skal installere flask, protobuf, requests, opencv_python, downloade Mobile SSD, serverkode fra Github og starte serveren.
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"]
Simple
Udgivelse til Docker Hub
Docker-registre formerer sig med en hastighed, der ikke er mindre end skydetektorer.
For ikke at genere, vil vi konservativt gå igennem
- Tilmeld
- Log på:
docker-login - Lad os finde på et meningsfuldt navn:
docker tag opencv-detect tprlab/opencv-detect-ssd - Upload billedet til serveren:
docker push tprlab/opencv-detect-ssd
Vi starter i skyen
Valget af, hvor containeren skal køres, er også ret bredt.
Alle de store spillere (Google, Microsoft, Amazon) tilbyder en mikroinstans gratis det første år.
Efter at have eksperimenteret med Microsoft Azure og Google Cloud valgte jeg sidstnævnte, fordi det tog fart hurtigere.
Jeg har ikke skrevet instruktioner her, da denne del er meget specifik for den valgte udbyder.
Jeg prøvede forskellige hardwareindstillinger,
Lave niveauer (delt og dedikeret) - 0.4 - 0.5 sekunder.
Kraftigere biler - 0.25 - 0.3.
Nå, selv i det værste tilfælde er gevinsten tre gange, du kan prøve.
Video
Vi lancerer en simpel OpenCV-videostreamer på Raspberry, der registrerer via Google Cloud.
Til forsøget blev der brugt en videofil, der engang blev filmet i et tilfældigt kryds.
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")
Med detektoren får vi ikke mere end tre billeder i sekundet, alt går meget langsomt.
Hvis du tager en kraftfuld maskine ind i GCloud, kan du registrere 4-5 billeder i sekundet, men forskellen er næsten usynlig for øjet, den er stadig langsom.
Sky- og transportomkostningerne har intet med det at gøre; detektoren kører på almindelig hardware og arbejder med sådan en hastighed.
Neural Computer Stick
Jeg kunne ikke modstå og kørte benchmark på NCS.
Detektorens hastighed var lidt langsommere end 0.1 sekunder, i hvert fald 2-3 gange hurtigere end skyen på en svag maskine, altså 8-9 billeder i sekundet.
Forskellen i resultater forklares af, at NCS kørte Mobile SSD version 2018_01_28.
P.S. Derudover har eksperimenter vist, at en ret kraftig desktop-maskine med en I7-processor viser lidt bedre resultater og det viste sig at være muligt at presse 10 billeder ud i sekundet.
klynge
Eksperimentet gik videre, og jeg installerede detektoren på fem noder i Google Kubernetes.
Selve bælgerne var svage, og hver af dem kunne ikke behandle mere end 2 billeder i sekundet.
Men hvis du kører en klynge med N noder og parser frames i N tråde, så kan du med et tilstrækkeligt antal noder (5) opnå de ønskede 10 frames i sekundet.
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
Her er hvad der skete:
Lidt mindre hurtigt end med NCS, men kraftigere end i én vandløb.
Forstærkningen er selvfølgelig ikke lineær - der er overlays til synkronisering og dyb kopiering af opencv-billeder.
Konklusion
Samlet set giver eksperimentet os mulighed for at konkludere, at hvis du prøver, kan du slippe afsted med en simpel sky.
Men en kraftfuld desktop eller lokal hardware giver dig mulighed for at opnå bedre resultater og uden nogen tricks.
RЎSЃS <P "RєRё
Kilde: www.habr.com