Prologu
Un video hè in circulazione in Internet chì mostra cumu l'autopilotu di Tesla vede a strada.
Aghju prucedimentu per un bellu pezzu per trasmette video arricchitu cù un detector, è in tempu reale.
U prublema hè chì vogliu trasmette u video da Raspberry, è a prestazione di u detector di a rete neurale lascia assai per esse desideratu.
Intel Neural Computer Stick
Aghju cunsideratu diverse suluzioni.
В
Ancu s'è Intel furnisce cunvertitori per i frameworki maiò, ci sò una quantità di trappule.
Per esempiu, u formatu di a reta dumandata pò esse incompatibile, è s'ellu hè cumpatibile, allura certi strati ùn ponu esse supportati in u dispusitivu, è s'ellu sò supportati, allura l'errore pò accade durante u prucessu di cunversione, per via di quale. avemu alcune cose strane à l'output.
In generale, sè vo vulete un tipu di rete neurale arbitraria, allora ùn pò micca travaglià cù NCS. Dunque, aghju decisu di pruvà à risolve u prublema cù l'arnesi più diffusi è accessibili.
Cloud
L'alternativa ovvia à una suluzione hardware locale hè di andà in u nuvulu.
Opzioni prontu - i vostri ochji sò salvatichi.
Tutti i capi:
... È decine di menu cunnisciuti.
Sceglie trà sta varietà ùn hè micca faciule.
E aghju decisu di ùn sceglie micca, ma di imballà u bonu schema di travagliu anticu in OpenCV in Docker è eseguisce in u nuvulu.
U vantaghju di questu approcciu hè a flessibilità è u cuntrollu - pudete cambià a rete neurale, hosting, servitore - in generale, ogni capriccio.
Servidor
Cuminciamu cù un prototipu lucale.
Tradizionalmente, aghju utilizatu Flask per a rete REST API, OpenCV è MobileSSD.
Dopu avè installatu e versioni attuali nantu à Docker, aghju scupertu chì OpenCV 4.1.2 ùn funziona micca cù Mobile SSD v1_coco_2018_01_28, è aghju avutu à rinvià à a pruvata 11/06_2017.
À u principiu di u serviziu, carchemu i nomi di classi è a rete:
def init():
tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)
In un docker locale (in un laptop micca assai ghjovanu) ci vole 0.3 seconde, in Raspberry - 3.5.
Cuminciamu u calculu:
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, Raspberry - 1.7.
Trasfurmà l'exhaust tensor in json leggibile:
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
Poi
Una opzione alternativa, in quale più travagliu hè spustatu à u servitore: ellu stessu circunda l'uggetti truvati è torna l'imagine finita.
Questa opzione hè bona induve ùn vulemu micca arrastà opencv à u servitore.
Docker
Cullemu l'imaghjini.
U codice hè pettinatu è publicatu
Cum'è una piattaforma, piglieremu u listessu Debian Stretch cum'è in Raspberry - ùn deviaremu micca da a pila di tecnulugia pruvata.
Avete bisognu di stallà flask, protobuf, richieste, opencv_python, scaricate Mobile SSD, codice di u servitore da Github è inizià u servitore.
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"]
Простой
Publicazione à Docker Hub
I registri Docker si multiplicanu à una velocità micca menu di i detectori di nuvola.
Per ùn disturbà, andemu cunservatoriamente
- Registrate
- Entra in:
login docker - Venitemu cun un nome significativu:
tag docker opencv-detect tprlab/opencv-detect-ssd - Caricate l'imaghjini à u servitore:
docker push tprlab/opencv-detect-ssd
Lanciamu in u nuvulu
L'scelta di induve corre u cuntinuu hè ancu abbastanza larga.
Tutti i grandi attori (Google, Microsoft, Amazon) offrenu una microistanza gratuitamente per u primu annu.
Dopu avè spirimintatu cù Microsoft Azure è Google Cloud, aghju stabilitu nantu à l'ultime perchè s'hè alluntanatu più veloce.
Ùn aghju micca scrittu struzzioni quì, postu chì sta parte hè assai specifica per u fornitore sceltu.
Aghju pruvatu diverse opzioni di hardware,
Livelli bassi (spartitu è dedicatu) - 0.4 - 0.5 seconde.
Cars più putenti - 0.25 - 0.3.
Ebbè, ancu in u peghju scenariu, i vincitori sò trè volte, pudete pruvà.
Видео
Lancemu un streamer di video OpenCV simplice nantu à Raspberry, detectendu attraversu Google Cloud.
Per l'esperimentu, hè stata utilizata un schedariu di video chì una volta era filmatu in una intersezzione aleatoria.
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")
Cù u detector ùn avemu micca più di trè frames per seconda, tuttu passa assai pianu.
Se pigliate una macchina putente in GCloud, pudete detectà 4-5 frames per seconda, ma a diferenza hè quasi invisibule à l'ochju, hè sempre lenta.
U nuvulu è i costi di trasportu ùn anu nunda di fà cù questu; u detector funziona nantu à hardware regulare è travaglia à quella velocità.
Stick Neural Computer
Ùn pudia micca resiste è curria u benchmark in NCS.
A vitezza di u detector era ligeramente più lenta di 0.1 seconde, in ogni casu 2-3 volte più veloce di u nuvulu nantu à una macchina debule, vale à dì 8-9 frames per seconda.
A sfarenza di i risultati hè spiegata da u fattu chì NCS eseguiva Mobile SSD versione 2018_01_28.
P.S. Inoltre, l'esperimenti anu dimustratu chì una macchina di scrivania abbastanza putente cù un processore I7 mostra risultati ligeramente megliu è hè statu pussibule di strincà 10 frames per seconda.
Cluster
L'esperimentu andò più in là è aghju installatu u detector in cinque nodi in Google Kubernetes.
I baccelli stessi eranu debuli è ognunu ùn pudia micca processà più di 2 frames per seconda.
Ma se eseguite un cluster cù N nodes è parse frames in N threads, allora cun un numeru suffirenziu di nodi (5) pudete ottene i 10 frames per seconda.
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
Eccu ciò chì succideva:
Un pocu menu veloce chì cù NCS, ma più vigoru chì in un flussu.
U guadagnu, sicuru, ùn hè micca lineare - ci sò overlays per a sincronizazione è a copia profonda di l'imagine opencv.
cunchiusioni
In generale, l'esperimentu ci permette di cuncludi chì, se pruvate, pudete scappà cù un nuvulu simplice.
Ma un putente desktop o hardware locale permette di ottene risultati megliu, è senza trucchi.
referenze
Source: www.habr.com