序幕
現在網路上流傳著一段視頻,展示了特斯拉的自動駕駛儀如何看待道路。
很長一段時間以來,我一直渴望即時播放用探測器豐富的影片。
問題是我想從 Raspberry 播放視頻,而其上的神經網絡檢測器的性能還有很多不足之處。
英特爾神經電腦棒
我考慮了不同的解決方案。
В
儘管英特爾為主要框架提供了轉換器,但仍存在許多缺陷。
例如,所需網路的格式可能不相容,如果相容,則裝置上可能不支援某些層,如果支持,則在轉換過程中可能會出現錯誤,從而導致我們在輸出中得到一些奇怪的東西。
一般來說,如果你想要某種任意的神經網絡,那麼它可能不適用於 NCS。 因此,我決定嘗試使用最廣泛且易於使用的工具來解決該問題。
雲
本地硬體解決方案的明顯替代方案是遷移到雲端。
現成的選擇-我的眼睛變得瘋狂。
各位領導:
……還有幾十個鮮為人知的。
在這個品種中進行選擇並不容易。
我決定不選擇,而是將 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)
在本機 docker 上(在一台不太年輕的筆記型電腦上)需要 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 拖曳到伺服器時,此選項非常有用。
碼頭工人
我們收集圖像。
程式碼梳理了一下,貼在
作為一個平台,我們將採用與 Raspberry 相同的 Debian Stretch - 我們不會偏離經過驗證的技術堆疊。
您需要安裝flask、protobuf、requests、opencv_python、從Github下載Mobile SSD、伺服器程式碼並啟動伺服器。
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 標籤 opencv-偵測 tprlab/opencv-偵測-ssd - 將圖片上傳到伺服器:
docker Push tprlab/opencv-檢測-ssd
我們在雲端啟動
在哪裡運行容器的選擇也相當廣泛。
所有大型企業(Google、微軟、亞馬遜)第一年都免費提供微型實例。
在嘗試了 Microsoft Azure 和 Google Cloud 後,我選擇了後者,因為它發展得更快。
我沒有在這裡寫說明,因為這部分是針對所選提供者的。
我嘗試了不同的硬體選項,
低等級(共享和專用)- 0.4 - 0.5 秒。
更強大的汽車 - 0.25 - 0.3。
好吧,即使在最壞的情況下,獎金也是三倍,你可以嘗試。
視頻
我們在 Raspberry 上啟動了一個簡單的 OpenCV 視訊串流傳輸器,透過 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幀,但肉眼幾乎看不到差別,它仍然很慢。
雲端和運輸成本與此無關;探測器在普通硬體上運行並以這樣的速度工作。
神經電腦棒
我無法抗拒並在 NCS 上運行了基準測試。
偵測器的速度略慢於 0.1 秒,無論如何都比在弱機器上的雲快 2-3 倍,即每秒 8-9 幀。
結果差異的原因是行動 SSD 版本 2018_01_28 是在 NCS 上推出的。
PS 另外,實驗表明,配備 I7 處理器的功能相當強大的桌上型電腦顯示出稍微好一些的結果,並且事實證明可以在其上壓縮每秒 10 幀的速度。
簇
實驗更進一步,我在 Google Kubernetes 的五個節點上安裝了偵測器。
Pod 本身很弱,每個 Pod 每秒處理的幀數不能超過 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 影像的覆蓋範圍。
結論
總的來說,這個實驗讓我們得出這樣的結論:如果你嘗試,你就可以使用簡單的雲。
但是強大的桌面或本機硬體可以讓您獲得更好的結果,並且無需任何技巧。
引用
來源: www.habr.com