Proloog
Praegu levib internetis video, kuidas Tesla autopiloot nÀeb teed.
Olen juba ammu tahtnud edastada videot, mida tÀiustatakse detektoriga, ja seda reaalses ajas.

Probleem on selles, et tahan videot edastada Raspberry-lt, kuid nÀrvivÔrgu detektori jÔudlus on kehv.
Intel Neural Computer Stick
Olen kaalunud erinevaid lahendusi.
V Eksperimenteerin Intel Neural Computer Stickiga. Seade on vÔimas, kuid vajab oma vÔrgu formaati.
Kuigi Intel pakub konvertereid peamiste raamistike jaoks, on siin mitmeid peidetud probleeme.
NĂ€iteks vajalik vĂ”rgu formaat vĂ”ib olla ĂŒhilduv, ja isegi kui see on ĂŒhilduv, vĂ”ivad mĂ”ned kihid seadmes ei ole toetatud, aga kui need on toetatud, vĂ”ivad konversiooni kĂ€igus tekkida vead, mille tulemuseks on mĂ”ned kummalised asjad.
ĂhesĂ”naga, kui soovite mĂ”nda suvalist nĂ€rvivĂ”rku, siis ei pruugi see NCS-iga Ă”nnestuda. SeetĂ”ttu otsustasin proovida probleemi lahendada kĂ”ige massilisemate ja kergesti juurdepÀÀsetavate tööriistade kaudu.
Pilv
Ilmselt on kohalikule riistvaralahendusele alternatiiviks ĂŒleminek pilve.
ValikuvÔimalusi on tohutult.
KÔik liidrid:
⊠ja kĂŒmneid vĂ€hem tuntud.
Selle mitmekesisuse seast valimine pole just lihtne.
Otsustasin mitte valida, vaid tÔsta vana hea tööprotsessi OpenCV Dockerisse ja kÀivitada see pilves.
Selle lĂ€henemise eeliseks on paindlikkus ja kontroll â saab vahetada nĂ€rvivĂ”rku, hostimist, serverit â ĂŒldiselt kĂ”ike, mida soovid.
Server
Alustame kohalikust prototĂŒĂŒbist.
Tavaliselt kasutan REST API jaoks Flaski, OpenCV-d ja MobileSSD vÔrku.
Paigaldades Dockerisse uusimad versioonid, avastasin, et OpenCV 4.1.2 ei tööta koos Mobile SSD v1_coco_2018_01_28-ga ning pidin tagasi minema tÔestatud 11_06_2017 versiooni.
Teenuse kÀivitamisel laadime klasside nimed ja vÔrgu:
def init():
tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)
Kohalikus Dockeris (mitte kĂ”ige uuemas sĂŒlearvutis) vĂ”tab see 0,3 sekundit, Raspberry-l aga 3,5.
KĂ€ivitame arvutuse:
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.
Muutame tensori vÀljundi loetavaks json-iks:
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
Edasi (sisendiks on pilt, vĂ€ljundiks â detektori tulemused json-formaadis).
Alternatiivne variant, kus rohkem tööd kantakse serveri Ă”lule: see joonistab leitud objektid ise ĂŒmber ja tagastab valmis pildi.
See variant sobib hÀsti, kui me ei soovi opencv-d serverisse tuua.
Docker
Kogume pildi.
Kood on korrastatud ja postitatud , docker vÔtab selle otse sealt.
Platvormiks vĂ”tame sama Debian Stretchi, mis on Raspberry peal â ei lĂ€he usaldusvÀÀrsest tehnoloogiapakist kaugemale.
Peame installima flaski, protobufi, requests'i, opencv_python'i, alla laadima Mobile SSD, serverikoodi GitHubist ja serveri kÀivitama.
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"]
Lihtne pÔhinev requestsil.
Avaldamine Docker Hubis
Docker registrid tÔukuvad sama kiiresti, kui pilvedetektorid.
Et mitte keeruliseks minna, vÔtame konservatiivse lÀhenemise lÀbi .
- Registreerume
- Logime sisse:
docker login - MÔtleme vÀlja sisuka nime:
docker tag opencv-detect tprlab/opencv-detect-ssd - Laeme pildi serverisse:
docker push tprlab/opencv-detect-ssd
KĂ€ivitame pilves
Valik, kus konteinerit kĂ€ivitada, on samuti ĂŒsna lai.
KÔik suured tegijad (Google, Microsoft, Amazon) pakuvad esimese aasta jooksul tasuta mikroinstantsi.
Katsusin Microsoft Azureâi ja Google Cloudi, kuid peatusin viimase juures â sest see tĂ”usis kiiremini.
Ei hakanud siia juhendit kirjutama, kuna see osa on vÀga spetsiifiline valitud teenusepakkuja jaoks.
Proovisin erinevaid rauavariante,
Madala taseme (jagatud ja pĂŒhendatud) â 0,4 â 0,5 sekundit.
Tugevamad masinad â 0,25 â 0,3.
Noh, isegi halvemal juhul on vÔit kolme korda, proovi Àra.
Video
KÀivitame lihtsa OpenCV videostreami Raspberryl, tuvastades lÀbi Google Cloud.
Eksperimendi jaoks kasutati videofaili, mis on kunagi filmitud juhuslikul ristmikul.
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")
Detektoriga ei saa rohkem kui kolm kaadrit sekundis, kÔik toimub vÀga aeglaselt.
Kui GCloudis vÔtta vÔimas masin, vÔib tuvastada 4-5 kaadrit sekundis, kuid silmaga on erinevus praktiliselt mÀrkamatud, ikkagi aeglane.

Pilv ja transpordikulud siin ei mÀngi rolli, tavalisel riistvaral töötab detektor sellise kiirus.
Neural Computer Stick
Ei suutnud end tagasi hoida ja jooksin NCS-il benchmark'i.
Detektori kiirus oli natuke aeglasem kui 0.1 sekundit, igal juhul 2-3 korda kiiremini kui pilves nÔrkal masinal, s.t 8-9 kaadrit sekundis.

Tulemustes on erinevus seletatav sellega, et NCS-il kÀivitati Mobile SSD versioon 2018_01_28.
P.S. Lisaks on katsetused nÀidanud, et piisavalt vÔimas lauaarvuti, millel on I7 protsessor, nÀitab veidi paremaid tulemusi ja sellel Ônnestub saavutada 10 kaadrit sekundis.
Klaster
Eksperiment lÀks kaugemale ja paigaldasin detektori viiele sÔlmele Google Kuberneteses.
Isegi konteinerid olid nĂ”rgad ja igaĂŒhel neist ei Ă”nnestunud töödelda rohkem kui 2 kaadrit sekundis.
Kuid kui kĂ€ivitada klaster N sĂ”lmel ja jagada kaadreid N voogu â siis piisava arvu sĂ”lmade (5) korral on vĂ”imalik saavutada soovitud 10 kaadrit sekundis.
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
Siin on tulemused:

Veidi mitte nii kiiresti nagu NCS-iga, kuid kiiremini kui ĂŒhes voos.
Kasum ei ole loomulikult lineaarne â tekivad sĂŒnkroniseerimise ja sĂŒgava kopeerimise probleemid opencv piltide puhul.
KokkuvÔte
Ăldiselt vĂ”imaldab eksperiment jĂ€reldada, et kui pingutada, on lihtsa pilve toestamine vĂ”imalik.
Kuid vÔimas töölaua arvuti vÔi kohalik server annab paremaid tulemusi, ilma igasuguste trikkideta.
Lingid
Allikas: habr.com
