一、前言
小王在畢設之餘瘋狂追劇,最近癡迷於《權利的遊戲》中龍母的美貌,太🉑了
當然,二丫 和 雪諾 的故事線也非常好看,我喜歡劇透,歡迎大家向我劇透。👀
當然了,小王也不能忘記畢設進度啦——好像是什麼手語識別來着?
哈哈哈哈,用最近了解的yolo跑個模型測試一下下吧,嘻嘻,效果還不錯!
咳咳,進入正題啦!
前面一篇文章算是打通了【yolo3識別】的任督二脈:
【Yolo3】一文掌握圖像標註、訓練、識別(Keras+TensorFlow-gpu)
梳理一下yolo3的知識點:
1.結構圖
參考CNN流程:
yolov3流程:
輸入圖片->darknet53(三個不同尺度特徵層)->yolo3解碼(卷積+採樣+結合)->(三個特徵結果)
圖片引用見logo
2.步驟
第一步:輸入圖片(調整爲416x416尺寸的圖片)
經過darknet53(5輪,23個殘差塊——對殘差網絡進行特徵提取)
分別得到✅3個不同尺度特徵層:13x13x1024
,26x26x512
,52x52x256
,
其中13x13表示網格數、3表示3個先驗框、後面表示類別數。
第二步:13x13的特徵層經過5層卷積
同
第三步:
-
再次進行3x3的卷積✅輸出特徵feat3 + 1x1卷積調整通道數
其中(75分爲4+1+20):- 4表示:偏移量x_offset、y_offset、height、width
- 1表示:置信度
- 25表示:對象類別數
-
13x13尺度: 卷積+上採樣(步長爲2,即把長寬變爲1/2),再與16x16的特徵層結合。
同
同理:16x16 五次卷積 -》3x3卷積✅輸出此層特徵feat2 + 1x1卷積調整通道數
16x16 卷積+上採樣 -》
同理:52x52 五次卷積 -》3x3卷積✅輸出此層特徵feat1 + 1x1卷積調整通道數
3.loss值
作用:判斷模型標準
特別說明:
-
先驗框的由來。先驗框數值越大,適合檢測大窗格13x13;對像素小,容易失真的圖片來說,先驗框數值越小檢測越精準,適合檢測小窗格52x52。
-
loss函數的定義:
存在的框:- 編碼後長寬與xy偏移量的差距
- 置信度與1的差值(loss =| 1- iou |)
- 種類預測結果與真實值的對比
不存在框: 最大iou與0的差值 (loss =| iou - 0|)
iou的概念補充:一般指代模型預測的 bbox 和 Groud Truth 之間的交併比。
左圖爲預測目標位置,右圖爲原始目標位置;交併比就是預測正確部分Area of overrap比上兩個位置所佔的全部面積Area of Union;iou越大,預測效果越好。 -
三個檢測結果進行堆疊:
- 左上和右下角進行標記
- 非極大抑制(去掉重疊的框,最多20個框)
相同目標最近的幾個框都滿足要求,只顯示最大的那個框。
- 左上和右下角進行標記
大概就是這些內容啦,接下來從源碼入手!
二、手識別
本文是對手語數據集訓練的一個記錄,算是 tf2 - keras-yolo3 復現。
下面操作中包含了源碼可訓練,以及loss查看tensorboard的使用。
0.圖片
(選做,用你自己的標註數據)
本次使用的數據集來自:牛津大學Arpit Mittal, Andrew Zisserman和 Phil Torr
綜合的手圖像數據集共有13050個手實例被註釋。大於邊界框固定區域(1500平方像素)的手部實例被認爲“足夠大”以進行檢測,並用於評估。這給出了大約4170個高品質手實例。在收集數據時,對人的姿勢或可見度沒有任何限制,對環境也沒有任何限制。在每幅圖像中,都標註了人類可以清晰感知的所有手。註釋由一個邊界矩形組成,該矩形不必相對於手腕進行軸對齊。
資料下載:
我們用到的數據集爲VOC格式:我們僅下載evaluation_code.tar.gz(13.8M)即可。
1.下載項目框架
參考:重磅!YOLOv3最全復現代碼合集(含TensorFlow/PyTorch和Keras等)
我僅根據做出源碼註釋和修改:keras-tensorflow(https://github.com/qqwweee/keras-yolo3)
-
單獨下載yolov3.weights 權重,放在項目根目錄下
-
將 DarkNet 的.weights文件轉換成 Keras 的.h5文件
python convert.py -w yolov3.cfg yolov3.weights model_data/yolo_weights.h5
2.標籤分類
- 將下載的數據集複製到項目路徑下:
事實是數據集有400+圖片,我訓練起來太累了,容易過擬合,這裏只用了009985-010028共40+張圖片進行訓練
開源數據集nb😁,不用手動找資源,再標註啦,嘻嘻嘻!支持開源~😁
- voc標籤格式:
voc_annotation.py
(後面我重構了一下項目結構,可能有出入)
會在ImageSets/Main目錄下生成對應文件
- yolo標籤格式:
yolo_annotation.py
- 修改classes爲你訓練的對象(我這裏是hand)
查看標籤:在VOCdevkit\VOC2007\Annotations\009985_hand.xml
- 這裏需要修改一下float格式
b = (int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)), int(float(xmlbox.find('xmax').text)), int(float(xmlbox.find('ymax').text)))
- 執行
yolo_annotation.py
,在model_data目錄下生成yolo標籤格式
現在我們就得到了model_data(標籤)
- 修改classes爲你訓練的對象(我這裏是hand)
3.訓練
Keras2.3.1 + TensorFlow-gpu2.1.0 + cuda 10.0
涉及到的文件和函數目錄:
原始目錄:tree_old目錄
我重新整合了一下目錄結構:tree目錄
根目錄
│
│ train.py --- 模型訓練
│
├─data --- 參數配置
│ │ yolo_weights.h5 --- 權重文件
│ │
│ ├─anchors
│ │ coco_anchors.txt --- 先驗參數
│ │
│ ├─classes
│ │ coco.name
│ │ voc_classes.txt --- 標籤樣本名稱
│ │
│ └─dataset
│ test.txt
│ train.txt
│ val.txt
│
└─core
│ darknet53.py --- 特徵提取網絡
│ loss.py --- 損失函數
│ yolo3.py --- yolo網絡
└─ utils.py --- 圖片加載工具類
運行train.py
50輪和100輪
(之前我更新了一次keras,導致之前的修改被抹除了,這裏修改一下:)
報錯:
參考:'Model’object has no attribute '_get_distribution_strategy’的一種解決方案
問題2:(運行到64輪時,VSCode崩掉了,這裏接着之前的模型運行)
註釋掉前50輪,直接model.load_weights('logs/ep064-loss16.422-val_loss20.496.h5')
你覺得合適的版本,
再把 initial_epoch 改爲當前的序號可以接着運行。
這是絕招了!
最終我運行到100輪時,loss值爲19.2
神經網絡可視化分析:
-
讀取運行時記錄:(這裏train和validation分別記錄)
-
在路徑下打開控制檯運行:
tensorboard --logdir=logs\
tensorboard 是 tensorflow安裝時就附帶安裝的可視化工具🍳,別說你還沒用過。
-
打開瀏覽器查看:http://localhost:6006/
其中GRAPHS可以打印出我們的神經網絡結構:(可以導出爲png圖片)
4.測試
修改yolo.py的模型路徑,socre和iou——是顯示檢測結果畫框框的重要因素:
"score": 0.45, # 框置信度閾值,小於閾值的框被刪除,需要的框較多,則調低閾值,需要的框較少,則調高閾值
"iou": 0.3, # 同類別框的IoU閾值,大於閾值的重疊框被刪除,重疊物體較多,則調高閾值,重疊物體較少,則調低閾值
直接檢測:predict.py
from keras.layers import Input
from yolo import YOLO,detect_video
from PIL import Image
def for_img(yolo):
path = 'D:/myworkspace/dataset/test.jpg'
try:
image = Image.open(path)
except:
print('Open Error! Try again!')
else:
r_image = yolo.detect_image(image)
r_image.show()
yolo.close_session()
def for_video(yolo):
detect_video(yolo, "D:/myworkspace/dataset/xuanya.mp4", "D:/myworkspace/dataset/xuanya_detect.mp4")
if __name__ == '__main__':
_yolo = YOLO()
for_img(_yolo)
# for_video(_yolo)
yolo.py測試部分報錯:
最終參考:tf2-keras-yolo3,可以直接對圖片和視頻進行檢測。
因爲模型是訓練一次就好了,測試部分我單獨提出封裝到代碼裏:(後面在這基礎上還要做手語識別,前途明朗~)
識別部分——代碼下載鏈接
yolo_video.py:
import sys
import argparse
from yolo import YOLO, detect_video
from PIL import Image
def detect_img(yolo):
while True:
print("Press 'q' quit !")
img = input('Input image filename:')
if img.lower() == 'q':
exit(0)
try:
image = Image.open(img)
except:
print('Open Error! Try again!')
continue
else:
r_image = yolo.detect_image(image)
r_image.show()
yolo.close_session()
FLAGS = None
if __name__ == '__main__':
# class YOLO defines the default value, so suppress any default here
parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
'''
Command line options
'''
parser.add_argument(
'--model_path', type=str,
help='path to model weight file, default ' + YOLO.get_defaults("model_path")
)
parser.add_argument(
'--anchors_path', type=str,
help='path to anchor definitions, default ' + YOLO.get_defaults("anchors_path")
)
parser.add_argument(
'--classes_path', type=str,
help='path to class definitions, default ' + YOLO.get_defaults("classes_path")
)
parser.add_argument(
'--gpu_num', type=int,
help='Number of GPU to use, default ' + str(YOLO.get_defaults("gpu_num"))
)
parser.add_argument(
'--image', default=False, action="store_true",
help='Image detection mode, will ignore all positional arguments'
)
'''
Command line positional arguments -- for video detection mode
'''
parser.add_argument(
"--input", nargs='?', type=str,required=False,default='./path2your_video',
help = "Video input path"
)
parser.add_argument(
"--output", nargs='?', type=str, default="",
help = "[Optional] Video output path"
)
FLAGS = parser.parse_args()
if FLAGS.image:
"""
Image detection mode, disregard any remaining command line arguments
"""
print("Image detection mode")
if "input" in FLAGS:
print(" Ignoring remaining command line arguments: " + FLAGS.input + "," + FLAGS.output)
detect_img(YOLO(**vars(FLAGS)))
elif "input" in FLAGS:
detect_video(YOLO(**vars(FLAGS)), FLAGS.input, FLAGS.output)
else:
print("Must specify at least video_input_path. See usage with --help.")
或者直接檢測
# 圖片檢測
python yolo_video.py --image
再輸入圖片路徑
# 視頻檢測
python yolo_video.py --input img\test.mp4
圖片識別率都不錯:
視頻檢測最高識別率爲57%
0.5秒檢測一幀,正確率在70%左右
後面會用來檢測我的手語:Python+Opencv2(三)保存視頻關鍵幀
手語手勢識別效果最高88%,非常nice!
yolo目標檢測,比過擬合的模型和openpose粗略估計好很多yo~~
三、總結
40+張圖片,跑的yolov3模型240M,檢測效果比較滿意啦。這裏檢測的是人手,如果把標註改爲權遊的龍,也是能檢測出來的哦,just try it!
環境:【GPU】win10 (1050Ti)+anaconda3+python3.6+CUDA10.0+tensorflow-gpu2.1.0
僅對於yolov3模型來說,模型較大,如果轉換成yolo-tiny甚至是yolo-nano會不會更方便移植。
生命不息,學習不止!😎
源碼:
補充,識別部分函數調用圖: