Video ng Cloud Object Detector sa Raspberry Pi

Prologue

Kumakalat na ngayon ang isang video sa Internet na nagpapakita kung paano nakikita ng autopilot ni Tesla ang kalsada.

Matagal na akong nangangati na mag-broadcast ng video na pinayaman ng isang detector, at sa real time.

Video ng Cloud Object Detector sa Raspberry Pi

Ang problema ay gusto kong mag-broadcast ng video mula sa Raspberry, at ang pagganap ng neural network detector dito ay nag-iiwan ng maraming nais.

Intel Neural Computer Stick

Nag-isip ako ng iba't ibang solusyon.

Π’ huling artikulo nag-eksperimento sa Intel Neural Computer Stick. Malakas ang hardware, ngunit nangangailangan ng sarili nitong format ng network.

Kahit na nagbibigay ang Intel ng mga converter para sa mga pangunahing framework, mayroong ilang mga pitfalls.

Halimbawa, ang format ng kinakailangang network ay maaaring hindi tugma, at kung ito ay magkatugma, kung gayon ang ilang mga layer ay maaaring hindi suportado sa device, at kung sila ay suportado, kung gayon ang mga error ay maaaring mangyari sa panahon ng proseso ng conversion, bilang isang resulta kung saan nakakakuha tayo ng ilang kakaibang bagay sa output.

Sa pangkalahatan, kung gusto mo ng ilang uri ng arbitrary na neural network, maaaring hindi ito gumana sa NCS. Samakatuwid, nagpasya akong subukang lutasin ang problema gamit ang pinakalaganap at naa-access na mga tool.

Cloud

Ang halatang alternatibo sa isang lokal na solusyon sa hardware ay pumunta sa cloud.

Mga handa na pagpipilian - ang aking mga mata ay tumatakbo nang ligaw.

Lahat ng mga pinuno:

... At dose-dosenang mga hindi gaanong kilala.

Ang pagpili sa iba't ibang ito ay hindi madali.

At nagpasya akong huwag pumili, ngunit i-wrap ang magandang lumang working scheme sa OpenCV sa Docker at patakbuhin ito sa cloud.

Ang bentahe ng diskarteng ito ay flexibility at kontrol - maaari mong baguhin ang neural network, hosting, server - sa pangkalahatan, anumang kapritso.

Server

Magsimula tayo sa isang lokal na prototype.

Karaniwang ginagamit ko ang Flask para sa REST API, OpenCV at MobileSSD network.

Sa pag-install ng mga kasalukuyang bersyon sa Docker, natuklasan ko na ang OpenCV 4.1.2 ay hindi gumagana sa Mobile SSD v1_coco_2018_01_28, at kailangan kong bumalik sa napatunayang 11/06_2017.

Sa simula ng serbisyo, nilo-load namin ang mga pangalan ng klase at network:

def init():
    tf_labels.initLabels(dnn_conf.DNN_LABELS_PATH)
    return cv.dnn.readNetFromTensorflow(dnn_conf.DNN_PATH, dnn_conf.DNN_TXT_PATH)

Sa isang lokal na docker (sa isang hindi masyadong batang laptop) ay tumatagal ng 0.3 segundo, sa Raspberry - 3.5.

Simulan natin ang pagkalkula:

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 seg, Raspberry - 1.7.

Ginagawang nababasang json ang tensor exhaust:

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

Dagdag pa i-export ang operasyong ito sa pamamagitan ng Flask(ang input ay isang larawan, ang output ay ang mga resulta ng detektor sa json).

Isang alternatibong opsyon, kung saan mas maraming trabaho ang inililipat sa server: ito mismo ang umiikot sa mga nahanap na bagay at nagbabalik ng natapos na imahe.

Ang pagpipiliang ito ay mabuti kung saan hindi namin nais na i-drag ang opencv sa server.

Docker

Kinokolekta namin ang imahe.

Ang code ay sinusuklay at naka-post sa Github, kukunin ito ng docker nang direkta mula doon.

Bilang isang platform, kukuha kami ng parehong Debian Stretch tulad ng sa Raspberry - hindi kami lilihis mula sa napatunayang tech stack.

Kailangan mong mag-install ng flask, protobuf, mga kahilingan, opencv_python, i-download ang Mobile SSD, server code mula sa Github at simulan ang server.

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 kliyente ng detector batay sa mga kahilingan.

Pag-publish sa Docker Hub

Ang mga rehistro ng Docker ay dumarami sa bilis na hindi bababa sa mga cloud detector.

Para hindi mag-abala, konserbatibo tayong dadaan DockerHub.

  1. Magrehistro
  2. Mag log in:
    pag-login sa docker
  3. Bumuo tayo ng isang makabuluhang pangalan:
    docker tag opencv-detect tprlab/opencv-detect-ssd
  4. I-upload ang larawan sa server:
    docker push tprlab/opencv-detect-ssd

Naglulunsad kami sa cloud

Medyo malawak din ang pagpili kung saan patakbuhin ang lalagyan.

Ang lahat ng malalaking manlalaro (Google, Microsoft, Amazon) ay nag-aalok ng libreng micro-instance para sa unang taon.
Pagkatapos mag-eksperimento sa Microsoft Azure at Google Cloud, inayos ko ang huli dahil mas mabilis itong umalis.

Hindi ako nagsulat ng mga tagubilin dito, dahil ang bahaging ito ay napaka-espesipiko sa napiling provider.

Sinubukan ko ang iba't ibang mga pagpipilian sa hardware,
Mababang antas (nakabahagi at nakatuon) - 0.4 - 0.5 segundo.
Mas makapangyarihang mga kotse - 0.25 - 0.3.
Well, even in the worst case scenario, tatlong beses ang panalo, pwede mong subukan.

video

Naglulunsad kami ng simpleng OpenCV video streamer sa Raspberry, na nagde-detect sa pamamagitan ng Google Cloud.
Para sa eksperimento, ginamit ang isang video file na dating kinunan sa isang random na intersection.


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")

Sa pamamagitan ng detektor nakakakuha kami ng hindi hihigit sa tatlong mga frame sa bawat segundo, ang lahat ay napakabagal.
Kung magdadala ka ng malakas na makina sa GCloud, makaka-detect ka ng 4-5 frame sa bawat segundo, ngunit halos hindi nakikita ng mata ang pagkakaiba, mabagal pa rin ito.

Video ng Cloud Object Detector sa Raspberry Pi

Ang mga gastos sa ulap at transportasyon ay walang kinalaman dito; ang detector ay tumatakbo sa ordinaryong hardware at gumagana sa ganoong bilis.

Neural Computer Stick

Hindi ko napigilan at pinatakbo ang benchmark sa NCS.

Ang bilis ng detector ay bahagyang mas mabagal kaysa sa 0.1 segundo, sa anumang kaso 2-3 beses na mas mabilis kaysa sa ulap sa isang mahinang makina, i.e. 8-9 na mga frame bawat segundo.

Video ng Cloud Object Detector sa Raspberry Pi

Ang pagkakaiba sa mga resulta ay ipinaliwanag sa pamamagitan ng katotohanan na ang bersyon ng Mobile SSD na 2018_01_28 ay inilunsad sa NCS.

P.S. Bilang karagdagan, ipinakita ng mga eksperimento na ang isang medyo malakas na desktop machine na may processor ng I7 ay nagpapakita ng bahagyang mas mahusay na mga resulta at naging posible na mag-squeeze ng 10 mga frame bawat segundo.

Kumpol

Ang eksperimento ay nagpatuloy at na-install ko ang detector sa limang node sa Google Kubernetes.
Ang mga pod mismo ay mahina at ang bawat isa sa kanila ay hindi makapagproseso ng higit sa 2 mga frame bawat segundo.
Ngunit kung nagpapatakbo ka ng isang kumpol na may mga N node at nag-parse ng mga frame sa N mga thread, pagkatapos ay may sapat na bilang ng mga node (5) maaari mong makamit ang nais na 10 mga frame sa bawat segundo.

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

Narito ang nangyari:

Video ng Cloud Object Detector sa Raspberry Pi

Medyo mas mabilis kaysa sa NCS, ngunit mas masigla kaysa sa isang stream.

Ang pakinabang, siyempre, ay hindi linear - may mga overlay para sa pag-synchronize at malalim na pagkopya ng mga imahe ng opencv.

Konklusyon

Sa pangkalahatan, binibigyang-daan kami ng eksperimento na tapusin na kung susubukan mo, maaari kang makatakas gamit ang isang simpleng ulap.

Ngunit ang isang malakas na desktop o lokal na hardware ay nagbibigay-daan sa iyo upang makamit ang mas mahusay na mga resulta, at nang walang anumang mga trick.

sanggunian

Pinagmulan: www.habr.com

Magdagdag ng komento