智慧交通day01-算法库03:cv.dnn
1.DNN模塊
1.1. 模塊簡介
OpenCV中的深度學習模塊(DNN)只提供了推理功能,不涉及模型的訓練,支持多種深度學習框架,比如TensorFlow,Caffe,Torch和Darknet。
?OpenCV那為什么要實現深度學習模塊?
-
輕量型。DNN模塊只實現了推理功能,代碼量及編譯運行開銷遠小于其他深度學習模型框架。
-
使用方便。DNN模塊提供了內建的CPU和GPU加速,無需依賴第三方庫,若項目中之前使用了OpenCV,那么通過DNN模塊可以很方便的為原項目添加深度學習的能力。
-
通用性。DNN模塊支持多種網絡模型格式,用戶無需額外的進行網絡模型的轉換就可以直接使用,支持的網絡結構涵蓋了常用的目標分類,目標檢測和圖像分割的類別,如下圖所示:
?DNN模塊支持多種類型網絡層,基本涵蓋常見的網絡運算需求。
?也支持多種運算設備(CPU,GPU等)和操作系統(Linux,windows,MacOS等)。
1.2.模塊架構
DNN模塊的架構如下圖所示:?
?從上往下依次是:
- 第一層:語言綁定層,主要支持Python和Java,還包括準確度測試、性能測試和部分示例程序。
- 第二層:C++的API層,是原生的API,功能主要包括加載網絡模型、推理運算以及獲取網絡的輸出等。
- 第三層:實現層,包括模型轉換器、DNN引擎以及層實現等。模型轉換器將各種網絡模型格式轉換為DNN模塊的內部表示,DNN引擎負責內部網絡的組織和優化,層實現指各種層運算的實現過程。
- 第四層:加速層,包括CPU加速、GPU加速、Halide加速和Intel推理引擎加速。CPU加速用到了SSE和AVX指令以及大量的多線程元語,而OpenCL加速是針對GPU進行并行運算的加速。Halide是一個實驗性的實現,并且性能一般。Intel推理引擎加速需要安裝OpenVINO庫,它可以實現在CPU、GPU和VPU上的加速,在GPU上內部會調用clDNN庫來做GPU上的加速,在CPU上內部會調用MKL-DNN來做CPU加速,而Movidius主要是在VPU上使用的專用庫來進行加速。
除了上述的加速方法外,DNN模塊還有網絡層面的優化。這種優化優化分兩類,一類是層融合,還有一類是內存復用。
-
層融合
層融合通過對網絡結構的分析,把多個層合并到一起,從而降低網絡復雜度和減少運算量。
如上圖所示,卷積層后面的BatchNorm層、Scale層和RelU層都被合并到了卷積層當中。這樣一來,四個層運算最終變成了一個層運算。
?如上圖所示,網絡結構將卷積層1和Eltwise Layer和RelU Layer合并成一個卷積層,將卷積層2作為第一個卷積層新增的一個輸入。這樣一來,原先的四個網絡層變成了兩個網絡層運算。
?如上圖所示,原始的網絡結構把三個層的輸出通過連接層連接之后輸入到后續層,這種情況可以把中間的連接層直接去掉,將三個網絡層輸出直接接到第四層的輸入上面,這種網絡結構多出現SSD類型的網絡架構當中。
-
內存復用
深度神經網絡運算過程當中會占用非常大量的內存資源,一部分是用來存儲權重值,另一部分是用來存儲中間層的運算結果。我們考慮到網絡運算是一層一層按順序進行的,因此后面的層可以復用前面的層分配的內存。
下圖是一個沒有經過優化的內存重用的運行時的存儲結構,紅色塊代表的是分配出來的內存,綠色塊代表的是一個引用內存,藍色箭頭代表的是引用方向。數據流是自下而上流動的,層的計算順序也是自下而上進行運算。每一層都會分配自己的輸出內存,這個輸出被后續層引用為輸入。
對內存復用也有兩種方法:
第一種內存復用的方法是輸入內存復用。
?如上圖所示,如果我們的層運算是一個in-place模式,那么我們無須為輸出分配內存,直接把輸出結果寫到輸入的內存當中即可。in-place模式指的是運算結果可以直接寫回到輸入而不影響其他位置的運算,如每個像素點做一次Scale的運算。類似于in-place模式的情況,就可以使用輸入內存復用的方式。
第二種內存復用的方法是后續層復用前面層的輸出。
?如上圖所示,在這個例子中,Layer3在運算時,Layer1和Layer2已經完成了運算。此時,Layer1的輸出內存已經空閑下來,因此,Layer3不需要再分配自己的內存,直接引用Layer1的輸出內存即可。由于深度神經網絡的層數可以非常多,這種復用情景會大量的出現,使用這種復用方式之后,網絡運算的內存占用量會下降30%~70%。
2.常用方法簡介
DNN模塊有很多可直接調用的Python API接口,現將其介紹如下:
2.1.dnn.blobFromImage
作用:根據輸入圖像,創建維度N(圖片的個數),通道數C,高H和寬W次序的blobs
原型:
blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None):參數:
-
image:cv2.imread 讀取的圖片數據
-
scalefactor: 縮放像素值,如 [0, 255] - [0, 1]
- size: 輸出blob(圖像)的尺寸,如 (netInWidth, netInHeight)
- mean: 從各通道減均值. 如果輸入 image 為 BGR 次序,且swapRB=True,則通道次序為 (mean-R, mean-G, mean-B).
- swapRB: 交換 3 通道圖片的第一個和最后一個通道,如 BGR - RGB
- crop: 圖像尺寸 resize 后是否裁剪. 如果crop=True,則,輸入圖片的尺寸調整resize后,一個邊對應與 size 的一個維度,而另一個邊的值大于等于 size 的另一個維度;然后從 resize 后的圖片中心進行 crop. 如果crop=False,則無需 crop,只需保持圖片的長寬比
- ddepth: 輸出 blob 的 Depth. 可選: CV_32F 或 CV_8U
示例:
import cv2 from cv2 import dnn import numpy as np import matplotlib.pyplot as pltimg_cv2 = cv2.imread("test.jpeg") print("原圖像大小: ", img_cv2.shape)inWidth = 256 inHeight = 256 outBlob1 = cv2.dnn.blobFromImage(img_cv2,scalefactor=1.0 / 255,size=(inWidth, inHeight),mean=(0, 0, 0),swapRB=False,crop=False) print("未裁剪輸出: ", outBlob1.shape) outimg1 = np.transpose(outBlob1[0], (1, 2, 0))outBlob2 = cv2.dnn.blobFromImage(img_cv2,scalefactor=1.0 / 255,size=(inWidth, inHeight),mean=(0, 0, 0),swapRB=False,crop=True) print("裁剪輸出: ", outBlob2.shape) outimg2 = np.transpose(outBlob2[0], (1, 2, 0))plt.figure(figsize=[10, 10]) plt.subplot(1, 3, 1) plt.title('輸入圖像', fontsize=16) plt.imshow(cv2.cvtColor(img_cv2, cv2.COLOR_BGR2RGB)) plt.axis("off") plt.subplot(1, 3, 2) plt.title('輸出圖像 - 未裁剪', fontsize=16) plt.imshow(cv2.cvtColor(outimg1, cv2.COLOR_BGR2RGB)) plt.axis("off") plt.subplot(1, 3, 3) plt.title('輸出圖像 - 裁剪', fontsize=16) plt.imshow(cv2.cvtColor(outimg2, cv2.COLOR_BGR2RGB)) plt.axis("off") plt.show()輸出結果為:
?另外一個API與上述API類似,是進行批量圖片處理的,其原型如下所示:
blobFromImages(images, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None):作用:批量處理圖片,創建4維的blob,其它參數類似于?dnn.blobFromImage。
2.2.dnn.NMSBoxes
作用:根據給定的檢測boxes和對應的scores進行NMS(非極大值抑制)處理
原型:
NMSBoxes(bboxes, scores, score_threshold, nms_threshold, eta=None, top_k=None)參數:
- boxes: 待處理的邊界框 bounding boxes
- scores: 對于于待處理邊界框的 scores
- score_threshold: 用于過濾 boxes 的 score 閾值
- nms_threshold: NMS 用到的閾值
- indices: NMS 處理后所保留的邊界框的索引值
- eta: 自適應閾值公式中的相關系數:?
- top_k: 如果 top_k>0,則保留最多 top_k 個邊界框索引值.
2.3. dnn.readNet
作用:加載深度學習網絡及其模型參數
原型:
readNet(model, config=None, framework=None)參數:
- model: 訓練的權重參數的模型二值文件,支持的格式有:*.caffemodel(Caffe)、*.pb(TensorFlow)、*.t7?或?*.net(Torch)、?*.weights(Darknet)、*.bin(DLDT).
- config: 包含網絡配置的文本文件,支持的格式有:*.prototxt?(Caffe)、*.pbtxt?(TensorFlow)、*.cfg?(Darknet)、*.xml?(DLDT).
- framework: 所支持格式的框架名
該函數自動檢測訓練模型所采用的深度框架,然后調用?readNetFromCaffe、readNetFromTensorflow、readNetFromTorch?或?readNetFromDarknet?中的某個函數完成深度學習網絡模型及模型參數的加載。
下面我們看下對應于特定框架的API:
Darknet
readNetFromDarknet(cfgFile, darknetModel=None)作用:加載采用Darknet的配置網絡和訓練的權重參數
Tensorflow
readNetFromTensorflow(model, config=None)作用:加載采用Tensorflow 的配置網絡和訓練的權重參數
參數:
- model: .pb 文件
- config: .pbtxt 文件
Torch
readNetFromTorch(model, isBinary=None)作用:加載采用 Torch 的配置網絡和訓練的權重參數
參數:
- model: 采用?torch.save()函數保存的文件
ONNX
readNetFromONNX(onnxFile)作用:加載 .onnx 模型網絡配置參數和權重參數
總結
DNN模塊是OPenCV中的深度學習模塊
優勢:輕量型,方便,通用性
架構:語言綁定層,API層,實現層,加速層
加速方法:層融合、內存復用
常用API
-
dnn.blobfromImage
利用圖片創建輸入到模型中的blobs
-
dnn.NMSBoxes
根據boxes和scores進行非極大值抑制
-
dnn.readNet
加載網絡模型和訓練好的權重參數
總結
以上是生活随笔為你收集整理的智慧交通day01-算法库03:cv.dnn的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像分类_04神经网络最优化过程:反向传
- 下一篇: 读取外部配置文件_SpringBoot外