0. 前言
如果只是想體驗(yàn)項(xiàng)目,請(qǐng)直接跳轉(zhuǎn)到本文第2節(jié),或者跳轉(zhuǎn)到我的facemask_detect。
剪枝的代碼可以查看我的github:yolov5-6.2-pruning
第1章是講述如何得到第2章用到的onnx格式的模型文件(我的項(xiàng)目里直接提供了這個(gè)文件)。
第2章開始講述如何使用cv2.dnn加載onnx文件并推理yolov5n模型。
1. 訓(xùn)練
本節(jié)內(nèi)容:下載mask_yolo數(shù)據(jù)集
1.1 獲取口罩佩戴檢測(cè)數(shù)據(jù)集
原數(shù)據(jù)集在FaceMaskDetection中有獲取的方法。但是其是voc格式的數(shù)據(jù)集,用在yolov5中需要轉(zhuǎn)成yolo格式的;而且有多處標(biāo)注存在內(nèi)容遺漏。
建議直接下載我生成的yolo格式的數(shù)據(jù)集,獲取鏈接
:mask_yolo。
1.2 訓(xùn)練環(huán)境配置
yolov5項(xiàng)目對(duì)pytorch的版本較為敏感,可能有些問題在某個(gè)特定版本會(huì)出現(xiàn),有些問題則不會(huì)。
舉例來說,pytorch 1.12版本調(diào)用yolov5中export.py文件生成onnx文件或者detect.py調(diào)用onnx文件,會(huì)出現(xiàn)問題,詳見issue.
pytorch需要用1.11
及更低的版本。
其余庫(kù)參考yolov5的requirements.txt
即可。
1.3 修改模型文件和數(shù)據(jù)集文件
本節(jié)內(nèi)容:clone yolov5項(xiàng)目
;下載yaml文件并修改
。
1.3.1 使用的模型
本項(xiàng)目使用的是yolov5系列中最小的一個(gè)模型yolov5n
,因?yàn)槭褂米畛S玫膟olov5s會(huì)使得推理變慢,造成延時(shí)現(xiàn)象。并且只是檢測(cè)是否佩戴口罩,可能并不需要太大的模型。
請(qǐng)前往github中clone最新的yolov5(當(dāng)前為6.2版本)代碼,地址:yolov5。
關(guān)于yolov5網(wǎng)絡(luò)結(jié)構(gòu)圖可以參考我的另一篇博文:yolov5s 6.0結(jié)構(gòu)圖。
1.3.2 下載yaml文件并修改
-
下載數(shù)據(jù)集的yaml文件:mask.yaml,放入
yolov5/data
文件夾,并修改path路徑為你下載的數(shù)據(jù)集存放的位置。 -
下載模型的yaml文件:yolov5n_mask.yaml,放入
yolov5/models
文件夾。
關(guān)鍵參數(shù)nc=2
對(duì)應(yīng):不佩戴口罩(face)和佩戴口罩(face_mask)。
1.4 訓(xùn)練
本節(jié)內(nèi)容:修改訓(xùn)練參數(shù)并訓(xùn)練
1.4.1 修改訓(xùn)練參數(shù)
以下三個(gè)參數(shù)分別對(duì)應(yīng)預(yù)訓(xùn)練權(quán)重文件、模型文件、數(shù)據(jù)集文件,填上對(duì)應(yīng)的路徑即可。
默認(rèn)yolov5n.pt
程序會(huì)自動(dòng)下載,如果下載失敗,請(qǐng)使用該鏈接手動(dòng)下載:yolov5n.pt, 然后放置在yolov5主目錄下。
parser.add_argument('--weights', type=str, default=ROOT / 'yolov5n.pt', help='initial weights path')
# 模型yaml
parser.add_argument('--cfg', type=str, default=ROOT / 'models/yolov5n_mask.yaml', help='model.yaml path')
# 修改數(shù)據(jù)集yaml
parser.add_argument('--data', type=str, default=ROOT / 'data/mask.yaml', help='dataset.yaml path')
修改imgsz
參數(shù),這個(gè)參數(shù)表示訓(xùn)練時(shí)圖片縮放到什么尺寸,默認(rèn)為640,建議改小一些,以加快訓(xùn)練速度,本項(xiàng)目這里設(shè)置為320
.
parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=320, help='train, val image size (pixels)')
windows端則需要修改workers
參數(shù)設(shè)置為0,否則加載數(shù)據(jù)集可能會(huì)報(bào)錯(cuò)。
parser.add_argument('--workers', type=int, default=0, help='max dataloader workers (per RANK in DDP mode)')
epochs可以調(diào)小一些,比如100或者200.
parser.add_argument('--epochs', type=int, default=200, help='total training epochs')
其余參數(shù)可以參考我的train.py.
修改完畢后,運(yùn)行train.py文件即可。
1.4.2 訓(xùn)練結(jié)果
訓(xùn)練結(jié)果可以在runs/train
中查看,exp
后面的數(shù)字最大的,就是當(dāng)前訓(xùn)練對(duì)應(yīng)的文件夾。
查看一下驗(yàn)證的結(jié)果,貌似還不錯(cuò),用衣服遮住口鼻的也沒有被誤檢為face_mask。
訓(xùn)練文件夾中的weights
文件夾存放著權(quán)重文件,我們需要best.pt
。
1.5 轉(zhuǎn)換為onnx格式
使用yolov5中的export.py
將pytorch模型轉(zhuǎn)換為onnx
格式(再次提示不要使用pytorch 1.12版本,使用1.11版本及更低版本)。
該py文件中用到了onnx,請(qǐng)使用pip install onnx
安裝。
使用如下命令轉(zhuǎn)換,其中runs/train/exp3/weights/best.pt
修改為你自己的訓(xùn)練權(quán)重路徑。
python export.py --weights runs/train/exp3/weights/best.pt --include onnx
然后我們就在best.pt
所在的文件夾得到了best.onnx
文件
export會(huì)把三個(gè)檢測(cè)頭的輸出合并到一起(以輸入為640×640
為例)
(80,80,255)->(3,80,80,85)->(19200,85)
(40,40,255)->(3,40,40,85)->(4800,85)
(20,20,255)->(3,20,20,85)->(1200,85)
(19200+4800+1200,85)=(25200,85)
因此export后的模型detect只會(huì)輸出一個(gè)(25200,85)的矩陣。
2. 使用口罩佩戴實(shí)時(shí)檢測(cè)項(xiàng)目
本節(jié)內(nèi)容:項(xiàng)目介紹和使用
。
我的項(xiàng)目地址:facemask_detect
從github中clone下來,并根據(jù)對(duì)應(yīng)的requirements.txt安裝項(xiàng)目的虛擬環(huán)境。
該項(xiàng)目中的模型使用opencv-python進(jìn)行onnx格式的模型推理,擺脫了對(duì)pytorch庫(kù)的依賴,同時(shí)使用onnx格式會(huì)比pytorch格式進(jìn)行推理速度要更加快。
項(xiàng)目的具體使用步驟參照項(xiàng)目中的README.md。
項(xiàng)目界面如下所示:
項(xiàng)目中的yolov5n_mask.onnx就是在1.4小節(jié)得到的best.onnx
文件。
2.1 cv2.dnn推理yolov5n
如果只是想體驗(yàn)項(xiàng)目,本文到上面就結(jié)束了。
下面講解如何使用cv2.dnn模塊使用得到的onnx格式的模型文件。
這部分代碼在項(xiàng)目中的controller/utils/yolo_inference.py
中,
該部分可以大致分為
- 加載模型:cv2.dnn.readNetFromONNX
- 數(shù)據(jù)預(yù)處理:包括letterbox、BGR2RGB、歸一化等
- 推理:net.forwad()
- 后處理操作:NMS、scale_boxes
- 繪制標(biāo)注信息:cv2.rectangle
下面講解其中的一些內(nèi)容。
2.1.1 讀取模型
opencv-python讀取onnx格式的模型,需要使用cv2.dnn.readNetFromONNX
函數(shù)。
net = cv2.dnn.readNetFromONNX('models/yolov5s_mask.onnx')
第三次提示之前pytorch的版本不要使用1.12版本,因?yàn)槭褂眠@個(gè)版本得到的onnx模型,上邊的代碼加載時(shí)會(huì)報(bào)錯(cuò),請(qǐng)換成1.11或者更低的版本。
2.1.2 letterbox函數(shù)
yolov5在將圖像數(shù)據(jù)輸入到模型之前需要進(jìn)行縮放操作
,同時(shí)cv2.dnn中進(jìn)行forward時(shí)輸入的尺寸也要和訓(xùn)練時(shí)用到的尺寸保持一致,因?yàn)樯线呌?xùn)練用到的是320×320的,所以模型的輸入也得是320×320的,否則會(huì)報(bào)錯(cuò):
cv2.error: OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv\modules\dnn\src\layers\reshape_layer.cpp:107: error: (-215:Assertion failed) total(srcShape, srcRange.start, srcRange.end) == maskTotal in function 'cv::dnn::computeShapeByReshapeMask'
然而直接進(jìn)行縮小,可能會(huì)導(dǎo)致圖標(biāo)中的目標(biāo)變形,影響目標(biāo)檢測(cè)效果。
所以yolov5采用如下圖的縮放技巧,以(750,500)
縮放到(640,640)
為例。
- 計(jì)算高度和寬度縮放比
- 使用最小的縮放比,保持縮放后高度和寬度仍是等比的
- 對(duì)于不足640的邊,以灰色填充兩邊使得其達(dá)到640
通過這樣的技巧既能夠保持高寬比,又能達(dá)到正方形縮放的效果。
2.1.3 推理
img_trans = cv2.dnn.blobFromImage(image=img_data, scalefactor=1 / 255., swapRB=True)
net = cv2.dnn.readNetFromONNX('models/yolov5n_mask.onnx')
net.setInput(img_trans)
# 輸入數(shù)據(jù),并獲得輸出,yolov5中將三個(gè)檢測(cè)頭的輸出合并到了一起
outputs = net.forward()
使用opencv讀取的圖片數(shù)據(jù)需要進(jìn)行預(yù)處理操作:
img_trans = cv2.dnn.blobFromImage(image=img_data, scalefactor=1 / 255., swapRB=True)
- 歸一化,將數(shù)據(jù)從0-255縮放至0-1:
scalefactor=1 / 255.
- 將RGB轉(zhuǎn)換為BGR:
swapRB=True
在推理之前需要設(shè)置輸入數(shù)據(jù):net.setInput(img_trans)
然后直接使用net.forward()
得到最后一層(即Detect
層)的輸出。文章來源:http://www.zghlxwxcb.cn/news/detail-404186.html
2.1.3 NMS
2.1.4 待續(xù)
后續(xù)還有些內(nèi)容需要更新,待續(xù)。當(dāng)前日期:2022年10月18日文章來源地址http://www.zghlxwxcb.cn/news/detail-404186.html
到了這里,關(guān)于Yolov5口罩佩戴實(shí)時(shí)檢測(cè)項(xiàng)目(模型剪枝+opencv+python推理)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!