YOLO算法之车型识别
理論知識
干貨
論文鏈接
論文解讀
darknet安裝
? 在darknet安裝之前,需要預先裝好cuda、cudnn和opencv環境。也可以不用裝GPU版本直接編譯運行使用cpu版本,但是,為了體現更好的處理效率,推薦使用GPU。
? 安裝方法直接按照官網教程就可以,鏈接如下:
? darknet安裝
車型識別
車型識別目標: 要精確識別給定車輛圖片的車型信息
零碎知識點
標注軟件Colabeler
參考鏈接1
參考鏈接2
yolo可視化
darknet命令總結
召回率和準確率<https://www.zhihu.com/question/19645541/answer/91694636>
mAp、P、IOU
數據集準備與處理
車型數據集共有1500張車輛照片,主要為汽車、公共汽車、卡車三種類型,拍攝時盡可能從不同角度、不同場景、不同環境下采集圖片,初次之外,每種類型車型的圖片量盡可能相差不大。
注意:標注圖片時,要時常查看標注的數據是否已經保存,并且要非常注意要勾選標注圖片的類型
xml文件
[外鏈圖片轉存失敗(img-FuNiXWdz-1568511457921)(/home/gavin/NoteBook/學習匯報/DeepinScreenshot_select-area_20190516185547.png)]
注意:一定要生成指定的XML格式文件,此次主要是根據pascal xml數據制作數據標簽。
生成標簽
VOCdevkit
└── VOC2018
├── Annotations #存放標記生成的XML文件
├── ImageSets #存放訓練集和驗證集的照片信息(照片的名稱)
├── JPEGImages #存放車型數據集
└── labels # 每張樣本的標簽
labels文件格式:
0 0.5467489919354839 0.4299395161290323 0.8933971774193548 0.5191532258064516
- object-class:是指對象的索引,從0開始,具體代表哪個對象去obj.names配置文件中按索引查,初次之外,每個txt文件可以有多個boundbox的信息,表示圈定的圖片不是一個單一類。
- x,y:是一個坐標,需要注意的是它可不是對象左上角的坐標,而對象中心的坐標
- width,height:是指對象的寬高
voc_label.py 解析
import xml.etree.ElementTree as ET import pickle import os from os import listdir, getcwd from os.path import joinsets=[('2018', 'train'), ('2018', 'val')]classes = ["car", "bus", "truck"] #設置分類車型def convert(size, box): #此函數主要生成labels文件中歸一化的值dw = 1./(size[0]) #用于歸一化dh = 1./(size[1])x = (box[0] + box[1])/2.0 #找出對象的中心點坐標y = (box[2] + box[3])/2.0w = box[1] - box[0] # 得到真是的boundbox的長寬信息h = box[3] - box[2]x = x*dw #歸一化w = w*dwy = y*dhh = h*dhreturn (x,y,w,h)def convert_annotation(year, image_id):#解析XMl文件in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')tree=ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):difficult = obj.find('difficult').textcls = obj.find('name').text #查找是不是我們自己的類if cls not in classes or int(difficult)==1:#跳過continuecls_id = classes.index(cls)#得到類別標簽xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))bb = convert((w,h), b)out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')wd = getcwd()#獲取當前路徑#1.創建labels文件夾 for year, image_set in sets: #此處第一個循環訓練集 第二個循環驗證集if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):os.makedirs('VOCdevkit/VOC%s/labels/'%(year))#2.得到圖片的id image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() #3.創建訓練集和驗證集文件夾 list_file = open('%s_%s.txt'%(year, image_set), 'w') #4.創建絕對路徑下的圖片文件路徑 for image_id in image_ids:list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id)) #5.xml 轉 labelconvert_annotation(year, image_id)list_file.close()os.system("cat 2018_train.txt 2018_val.txt > train.txt")#擴充訓練集數據量數據預處理
voc.data
classes= 3 #分類類型 train = /home/gavin/Machine/darknet/scripts/train.txt #訓練集 valid = /home/gavin/Machine/darknet/scripts/2018_val.txt #驗證集 names = data/voc.names #類別信息 backup = backup #存放訓練權重yolov3-tiny.cfg
考慮的筆記本硬件的不足,選擇了yolov3-tiny版網絡模型,缺點:會喪失一定的準確度
[net] # Testing #batch=1 #subdivisions=1 Training batch=2 subdivisions=1 width=416 height=416 channels=3 momentum=0.9 decay=0.0005 angle=0 saturation = 1.5 exposure = 1.5 hue=.1learning_rate=0.001 burn_in=1000 max_batches = 500200 policy=steps steps=400000,450000 scales=.1,.1......[convolutional] size=1 stride=1 pad=1 filters=24 #classes*8 activation=linear[yolo] mask = 3,4,5 anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 classes=3#classes num=6 jitter=.3 ignore_thresh = .7 truth_thresh = 1 random=1[route] layers = -4[convolutional] batch_normalize=1 filters=128 size=1 stride=1 pad=1 activation=leaky[upsample] stride=2[route] layers = -1, 8[convolutional] batch_normalize=1 filters=256 size=3 stride=1 pad=1 activation=leaky[convolutional] size=1 stride=1 pad=1 filters=24 activation=linear[yolo] mask = 0,1,2 anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 classes=3 num=6 jitter=.3 ignore_thresh = .7 truth_thresh = 1 random=1網絡模型
訓練模型
開始訓練
darknet : sudo ./darknet detector train cfg/voc.data cfg/yolov3-tiny.cfg
本次訓練總共7萬次,已經達到了不錯的效果
日志文件解析
Region 16 Avg IOU: 0.100322, Class: 0.425682, Obj: 0.461557, No Obj: 0.488897, .5R: 0.000000, .75R: 0.000000, count: 4 Region 23 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.534580, .5R: -nan, .75R: -nan, count: 0 2: 675.922241, 673.001831 avg, 0.000000 rate, 0.177072 seconds, 8 images Loaded: 0.315449 seconds Region 16 Avg IOU: 0.142092, Class: 0.463787, Obj: 0.288284, No Obj: 0.489365, .5R: 0.000000, .75R: 0.000000, count: 4 Region 23 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.534735, .5R: -nan, .75R: -nan, count: 0 3: 673.221313, 673.023804 avg, 0.000000 rate, 0.173940 seconds, 12 images Loaded: 0.325054 seconds Region 16 Avg IOU: 0.293639, Class: 0.411060, Obj: 0.413394, No Obj: 0.489323, .5R: 0.000000, .75R: 0.000000, count: 4其中每行的參數意義如下:
Avg IOU:當前迭代中,預測的box與標注的box的平均交并比,越大越好,期望數值為1;
Class: 標注物體的分類準確率,越大越好,期望數值為1;
obj: 越大越好,期望數值為1;
No obj: 越小越好;
.5R: 以IOU=0.5為閾值時候的recall; recall = 檢出的正樣本/實際的正樣本
0.75R: 以IOU=0.75為閾值時候的recall;
count:正樣本數目。
注:存在nan值說明該子批次沒有預測到正樣本,在訓練開始時候有出現是正常現象
特別的每一個批次結束之后會輸出一下結果:
3: 673.221313, 673.023804 avg, 0.000000 rate, 0.173940 seconds, 12 images
第幾批次,總損失,平均損失,當前學習率,當前批次訓練時間,目前為止參與訓練的圖片總數
檢測圖片
3.1 批量化測試效果
darknet: ./darknet detector valid cfg/voc.data cfg/yolov3-tiny.cfg backup/yolov3-tiny_70000.weights
注意 : 此時應該修改yolov3-tiny.cfg文件中的batch和subminibatch為1
測試結果會存放在results文件夾下:如下
comp4_det_test_bus.txt
comp4_det_test_car.txt
comp4_det_test_truck.txt
yolo_valid.txtbus.txt
yolo_valid.txtcar.txt
yolo_valid.txttruck.txt
當打開其中comp4_det_test_bus.txt:
1039 0.008945 1075.546509 642.225098 1427.953003 852.698364
0822 0.005433 578.461548 576.750000 2930.228027 1478.208252
0860 0.987352 133.620972 325.751465 3403.745117 2544.819336
圖片名稱 該類置信度 坐標信息
3.2 單張測試效果
darknet: sudo ./darknet detector test cfg/voc.data cfg/yolov3-tiny.cfg backup/yolov3-tiny_70000.weights
汽車檢測效果:
準確率:
卡車檢測效果:
準確率:
公交車檢測效果:
準確率:
對于一些復雜場景下的檢測效果
覆蓋車輛下的檢測效果
檢測結果:未識別
只有部分車身檢測效果
檢測結果:未識別
多車輛下的檢測效果
檢測結果:此時的car 的準確率只有57%,并且對其它車輛不能夠進行檢測
黑夜下的檢測效果
檢測結果:未識別
結論:由于本次采集的數據未能夠采集到特殊條件下的車輛照片,尤其是黑夜和不同角度下的車輛數據,而只是簡單的采集了大多數正面和光線條件比較好的情況下的車輛照片,造成了對于復雜環境下未能檢測的效果。后期需要如果能夠加大數據集的囊括性,便能夠達到很好的檢測效果。
數據分析
提取數據
import inspect import os import random import sys def extract_log(log_file,new_log_file,key_word):with open(log_file, 'r') as f:with open(new_log_file, 'w') as train_log:#f = open(log_file)#train_log = open(new_log_file, 'w')for line in f:# 去除多gpu的同步logif 'Syncing' in line:continue# 去除除零錯誤的logif 'nan' in line:continueif key_word in line:train_log.write(line)f.close()train_log.close()extract_log('yolov3.log','train_log_loss.txt','images') extract_log('yolov3.log','train_log_iou.txt','IOU')繪制數據圖
import pandas as pd import numpy as np import matplotlib.pyplot as plt #%matplotlib inlinelines =79755 #改為自己生成的train_log_loss.txt中的行數 result = pd.read_csv('train_log_loss.txt', skiprows=[x for x in range(lines) if ((x%10!=9) |(x<1000))] ,error_bad_lines=False, names=['loss', 'avg', 'rate', 'seconds', 'images']) result.head()result['loss']=result['loss'].str.split(' ').str.get(1) result['avg']=result['avg'].str.split(' ').str.get(1) result['rate']=result['rate'].str.split(' ').str.get(1) result['seconds']=result['seconds'].str.split(' ').str.get(1) result['images']=result['images'].str.split(' ').str.get(1) result.head() result.tail()# print(result.head()) # print(result.tail()) # print(result.dtypes)print(result['loss']) print(result['avg']) print(result['rate']) print(result['seconds']) print(result['images'])result['loss']=pd.to_numeric(result['loss']) result['avg']=pd.to_numeric(result['avg']) result['rate']=pd.to_numeric(result['rate']) result['seconds']=pd.to_numeric(result['seconds']) result['images']=pd.to_numeric(result['images']) result.dtypesfig = plt.figure() ax = fig.add_subplot(1, 1, 1) ax.plot(result['avg'].values,label='avg_loss') # ax.plot(result['loss'].values,label='loss') ax.legend(loc='best') #圖列自適應位置 ax.set_title('The loss curves') ax.set_xlabel('batches') fig.savefig('avg_loss') # fig.savefig('loss')2.1 loss 圖:
2.2 IOU圖:
2.3 Ap:
| Ap | 0.33 | 0.29 | 0.32 |
mAP = 0.313
Recall:
2.3.1 預備工作
修改darknet根文件下的detector.c
list *plist = get_paths("data/voc.2007.test"); char **paths = (char **)list_to_array(plist);//修改為如下 list *plist = get_paths("scripts/train.txt"); char **paths = (char **)list_to_array(plist);./darknet detector recall <data_cfg> <test_cfg> <weights>
2.3.2 顯示結果
數據:
Number Correct Total Rps/Img IOU Recall 2940 2933 2940 RPs/Img: 1.42 IOU: 85.75% Recall:99.76%2941 2934 2941 RPs/Img: 1.42 IOU: 85.75% Recall:99.76%2942 2935 2942 RPs/Img: 1.42 IOU: 85.75% Recall:99.76%2943 2936 2943 RPs/Img: 1.42 IOU: 85.75% Recall:99.76%2944 2937 2944 RPs/Img: 1.42 IOU: 85.76% Recall:99.76%2945 2938 2945 RPs/Img: 1.42 IOU: 85.76% Recall:99.76%2946 2939 2946 RPs/Img: 1.42 IOU: 85.76% Recall:99.76%2947 2940 2947 RPs/Img: 1.42 IOU: 85.76% Recall:99.76%分析:
Number表示處理到第幾張圖片。
Correct表示正確的識別除了多少bbox。這個值算出來的步驟是這樣的,丟進網絡一張圖片,網絡會預測出很多bbox,每個bbox都有其置信概率,概率大于threshold的bbox與實際的bbox,也就是labels中txt的內容計算IOU,找出IOU最大的bbox,如果這個最大值大于預設的IOU的threshold,那么correct加一。
Total表示實際有多少個bbox。
Rps/img表示平均每個圖片會預測出來多少個bbox。
IOU: 這個是預測出的bbox和實際標注的bbox的交集 除以 他們的并集。顯然,這個數值越大,說明預測的結果越好。
Recall召回率, 意思是檢測出物體的個數 除以 標注的所有物體個數。通過代碼我們也能看出來就是Correct除以Total的值。
總結
? 本次,從darknet的安裝到yolo模型的實戰,成功的實現了從理論到實戰的轉換,雖然此次檢測結果未能對一些復雜環境下的車型進行識別,但是,還是能夠實現對大多數條件比較好的車型進行識別,并且準確率比較高。這次實際操作也能更加對yolov3的論文中的一些知識點進行深刻理解。初次之外,通過這次的練習,也學會了一些其他知識技能,比如圖片數據的標記與處理、opencv的使用等等。或許這一次的項目實戰在整體性完整性上有許多未能考慮點,有許多知識點暫時還未能觸及到或尚未真正理解明白,這就需要我接下來認真的重新看有關方面的知識來進行加強。
? 總之,這次理論與實踐相的融合,讓我學習到了很多知識。
總結
以上是生活随笔為你收集整理的YOLO算法之车型识别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国建筑抗震设计规范反应谱v2.0(20
- 下一篇: 线性同余法的伪随机数