Նախաբան
Այժմ համացանցում շրջանառվում է մի տեսանյութ, որը ցույց է տալիս, թե ինչպես է Tesla-ի ավտոպիլոտը տեսնում ճանապարհը:
Ես երկար ժամանակ քոր էի զգում դետեկտորով հարստացված տեսանյութ հեռարձակելու համար և իրական ժամանակում։
Խնդիրն այն է, որ ես ուզում եմ հեռարձակել տեսանյութ Raspberry-ից, և դրա վրա նեյրոնային ցանցի դետեկտորի աշխատանքը շատ ցանկալի է թողնում:
Intel Neural Computer Stick
Տարբեր լուծումներ եմ դիտարկել։
В
Թեև Intel-ը փոխակերպիչներ է տրամադրում հիմնական շրջանակների համար, կան մի շարք որոգայթներ:
Օրինակ՝ պահանջվող ցանցի ձևաչափը կարող է անհամատեղելի լինել, և եթե այն համատեղելի է, ապա որոշ շերտեր կարող են չաջակցվել սարքի վրա, իսկ եթե դրանք ապահովված են, ապա փոխակերպման գործընթացում կարող են առաջանալ սխալներ, ինչի հետևանքով. մենք ստանում ենք մի քանի տարօրինակ բաներ ելքի ժամանակ:
Ընդհանրապես, եթե ցանկանում եք ինչ-որ կամայական նեյրոնային ցանց, ապա այն կարող է չաշխատել NCS-ի հետ: Ուստի որոշեցի փորձել լուծել խնդիրը՝ օգտագործելով ամենատարածված և հասանելի գործիքները։
Cloud
Տեղական ապարատային լուծման ակնհայտ այլընտրանքը ամպին գնալն է:
Պատրաստի տարբերակներ - աչքերս վազում են:
Բոլոր առաջնորդները.
... Եվ տասնյակ քիչ հայտնիներ:
Այս բազմազանության մեջ ընտրելն ամենևին էլ հեշտ չէ։
Եվ ես որոշեցի չընտրել, այլ փաթաթել OpenCV-ի հին լավ սխեման Docker-ում և գործարկել այն ամպի մեջ:
Այս մոտեցման առավելությունը ճկունությունն ու վերահսկումն է. դուք կարող եք փոխել նեյրոնային ցանցը, հոսթինգը, սերվերը, ընդհանրապես ցանկացած քմահաճույք:
Սերվեր
Սկսենք տեղական նախատիպից:
Ավանդաբար ես օգտագործում եմ Flask REST API-ի, OpenCV-ի և MobileSSD ցանցի համար:
Տեղադրելով ընթացիկ տարբերակները Docker-ում, ես հայտնաբերեցի, որ OpenCV 4.1.2-ը չի աշխատում Mobile SSD-ի հետ v1_coco_2018_01_28, և ես ստիպված էի վերադառնալ ապացուցված 11/06_2017:
Ծառայության սկզբում մենք բեռնում ենք դասերի անունները և ցանցը.
def init():
tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)
Տեղական դոկերի վրա (ոչ շատ երիտասարդ նոութբուքի վրա) դա տևում է 0.3 վայրկյան, Raspberry-ի վրա՝ 3.5:
Սկսենք հաշվարկը.
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 վրկ, Raspberry - 1.7:
Տենսորի արտանետումը ընթեռնելի 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
Հետագա
Այլընտրանքային տարբերակ, որտեղ ավելի շատ աշխատանք տեղափոխվում է սերվեր. նա ինքն է պտտվում հայտնաբերված օբյեկտների վրա և վերադարձնում պատրաստի պատկերը:
Այս տարբերակը լավ է այնտեղ, որտեղ մենք չենք ցանկանում opencv-ին քաշել սերվեր:
Դոկեր
Մենք հավաքում ենք պատկերը:
Կոդը սանրված և փակցված է
Որպես հարթակ, մենք կվերցնենք նույն Debian Stretch-ը, ինչ Raspberry-ում. մենք չենք շեղվի ապացուցված տեխնոլոգիական փաթեթից:
Դուք պետք է տեղադրեք flask, protobuf, հարցումներ, opencv_python, ներբեռնեք Mobile SSD, սերվերի կոդը Github-ից և գործարկեք սերվերը:
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"]
Պարզ
Հրապարակում Docker Hub-ում
Docker ռեգիստրները բազմապատկվում են ոչ պակաս արագությամբ, քան ամպային դետեկտորները:
Որպեսզի չանհանգստանանք, պահպանողական կերպով կանցնենք
- Գրանցվել
- Մուտք գործեք՝
docker մուտք - Եկեք մի իմաստալից անուն գտնենք.
docker պիտակ opencv-detect tprlab/opencv-detect-ssd - Վերբեռնեք պատկերը սերվեր.
docker push tprlab/opencv-detect-ssd
Մենք գործարկում ենք ամպի մեջ
Բավական լայն է նաև կոնտեյների տեղադրման վայրի ընտրությունը:
Բոլոր խոշոր խաղացողները (Google, Microsoft, Amazon) առաջին տարին անվճար միկրոօրգանիզմ են առաջարկում:
Microsoft Azure-ի և Google Cloud-ի հետ փորձարկումներից հետո ես որոշեցի վերջինիս վրա, քանի որ այն ավելի արագ հեռացավ:
Ես այստեղ հրահանգներ չեմ գրել, քանի որ այս մասը շատ հատուկ է ընտրված մատակարարին:
Ես փորձեցի տարբեր ապարատային տարբերակներ,
Ցածր մակարդակներ (համօգտագործվող և նվիրված) - 0.4 - 0.5 վայրկյան:
Ավելի հզոր մեքենաներ՝ 0.25 - 0.3:
Դե, նույնիսկ ամենավատ սցենարի դեպքում, շահումները երեք անգամ են, կարող եք փորձել:
Video
Մենք գործարկում ենք մի պարզ OpenCV վիդեո հեռարձակում Raspberry-ում, որը հայտնաբերվում է Google Cloud-ի միջոցով:
Փորձի համար օգտագործվել է վիդեո ֆայլ, որը ժամանակին նկարահանվել է պատահական խաչմերուկում:
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")
Դետեկտորով մենք ստանում ենք ոչ ավելի, քան երեք կադր վայրկյանում, ամեն ինչ շատ դանդաղ է ընթանում:
Եթե դուք հզոր մեքենա եք վերցնում GCloud-ում, կարող եք հայտնաբերել վայրկյանում 4-5 կադր, բայց տարբերությունը գրեթե անտեսանելի է աչքի համար, այն դեռ դանդաղ է:
Ամպը և տրանսպորտային ծախսերը դրա հետ կապ չունեն, դետեկտորն աշխատում է սովորական սարքաշարով և աշխատում է այդ արագությամբ:
Neural Computer Stick
Ես չկարողացա դիմադրել և գործարկեցի NCS-ի չափանիշը:
Դետեկտորի արագությունը մի փոքր ավելի դանդաղ էր, քան 0.1 վայրկյան, ամեն դեպքում 2-3 անգամ ավելի արագ, քան թույլ մեքենայի ամպը, այսինքն՝ 8-9 կադր վայրկյանում:
Արդյունքների տարբերությունը բացատրվում է նրանով, որ NCS-ն աշխատում էր Mobile SSD 2018_01_28 տարբերակով:
P.S. Բացի այդ, փորձերը ցույց են տվել, որ I7 պրոցեսորով բավականին հզոր աշխատասեղանի մեքենան մի փոքր ավելի լավ արդյունքներ է ցույց տալիս, և պարզվել է, որ հնարավոր է սեղմել վայրկյանում 10 կադր:
Կլաստեր
Փորձն ավելի հեռուն գնաց, և ես դետեկտորը տեղադրեցի Google Kubernetes-ի հինգ հանգույցների վրա:
Ինքնին պատիճները թույլ էին և նրանցից յուրաքանչյուրը չէր կարողանում վայրկյանում 2 կադրից ավելի մշակել։
Բայց եթե դուք գործարկում եք կլաստեր N հանգույցներով և վերլուծում շրջանակները N թելերով, ապա բավարար թվով հանգույցներով (5) կարող եք հասնել ցանկալի 10 կադր վայրկյանում:
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
Ահա թե ինչ է տեղի ունեցել.
Մի փոքր ավելի քիչ արագ, քան NCS-ով, բայց ավելի եռանդուն, քան մեկ հոսքում:
Շահույթը, իհարկե, գծային չէ. կան ծածկույթներ opencv պատկերների համաժամացման և խորը պատճենման համար:
Ամփոփում
Ընդհանուր առմամբ, փորձը թույլ է տալիս եզրակացնել, որ եթե փորձեք, կարող եք ազատվել պարզ ամպից:
Բայց հզոր աշխատասեղան կամ տեղական սարքավորումը թույլ է տալիս ավելի լավ արդյունքների հասնել և առանց որևէ հնարքների:
Սայլակ
Source: www.habr.com