文章目錄
一、前言
yolo是一種簡易快捷的目標檢測算法,它可以對圖像做識別和目標檢測,因爲比一般算法快速,特別是到了v3版本, 也可以對視頻做實時識別。
在前一篇文章【Yolo3】入門目標檢測實驗–Python+Opencv2+dnn中,我們通過官方的模型檢測出來了“鳥”:
之前的模型支持檢測以下物體:
人 自行車 汽車 摩托車 飛機 巴士 火車 卡車 船 紅綠燈 消防栓 站牌 停車咪表 板凳 鳥 貓 狗
馬 羊 牛 象 熊 斑馬 長頸鹿 揹包 雨傘 手袋 領帶 手提箱 飛碟 滑雪 單板滑雪 運動的球
風箏 棒球棒 棒球手套 滑板 衝浪板 網球拍 瓶 酒杯 杯 叉 刀 勺 碗 香蕉 蘋果 三明治 橙
花椰菜 胡蘿蔔 熱狗 披薩 甜甜圈 蛋糕 椅子 沙發 盆栽植物 牀 餐桌 廁所 電視 筆記本
鼠標 遙控 鍵盤 手機 微波 烤箱 烤麪包 片 冰箱 本書 時鐘 花瓶 剪刀 泰迪熊 吹風機 牙刷
如果需要檢測更多的物體該怎麼辦呢?——本篇闡述如何製作自己的訓練集。
一個小故事來描述yolo圖像識別 的過程:
我們當老師,yolo當學生,學習過程分爲——備課、教學、考試:
1.老師需要備課、整理每個單元的知識點 (圖像標註)
2.老師上課教學(生成索引)
3.學生做課後作業(圖像訓練)
4.考試測評(圖像識別)
圖片就是課程內容、標註框就是知識點。
先說斷,後不亂
環境:windows10 + anaconda3(conda4.8.2)+ labelImg1.8.1 + VSCode
版本:python3.6.0 + opencv4.1.0 + yolo3 +keras 2.3.1 +tensorflow-gpu2.1.0
環境安裝記錄:
【GPU】win10 (1050Ti)+anaconda3+python3.6+CUDA10.0+tensorflow-gpu2.1.0
庫:numpy1.18.2、Pillow7.0.0、matplotlib 、python-opencv4.2.0
源碼源碼:
二、訓練集標註
老師備課階段——圖片是課程內容,標註框時知識點。
在yolo中,使用的是網格標註:
我們需要使用到圖片標註工具:labelImg
,需要安裝一下這個軟件(支持windows和Ubantu)
標註後的文件保存爲xml形式,是這樣的:
1. 圖像標註
老師備課,準備教學素材。 LabelImg就是老師的備課工具!
(1)下載LabelImg
LabelImg 是一個可視化的圖像標定工具。Faster R-CNN,YOLO,SSD等目標檢測網絡所需要的數據集,均需要藉此工具標定圖像中的目標。生成的 XML 文件是遵循 PASCAL VOC 的格式的。
下載地址1:https://github.com/tzutalin/labelImg/releases(可以源碼安裝、也可以直接下載exe免安裝版本)
我下載的是windows免安裝版本,下載如果很慢,可以使用以下鏈接:
下載地址2:鏈接: https://pan.baidu.com/s/1kwwO5VxLMpAuKFvckPpHyg 提取碼: 2557
好人一生平安!
(2)圖像標註
具體的備課內容——知識點就是標註方框信息。
-
準備
下載完成後是一個可執行exe文件,注意存放到一個非中文的路徑下。
同時,我創建了三個文件夾:- photos:存放原圖片
這裏我存放了5張小兔子的圖片,可參考Python爬取百度圖片並保存到本地。
- Annotations:存放xml標註信息文件
- JPEGImages:存放壓縮圖片
- photos:存放原圖片
-
標註
運行labelImage,調整到合適大小;熟記使用6步驟:
打開文件夾(photos)-》設置保存文件夾(annotations)
設置自動保存(view -》auto Saving)-》標註框(Create RectBox)並命名
快捷鍵A保存xml-》快捷鍵D下一張
附:(labelImg快捷鍵表)
標註示例(輪廓對齊原則):
(建議從左下角標註到右上角,因爲在圖片讀取中順序是(x1,y1)到(x2,y2))
標籤英文!!!因爲後面在python讀取不出錯
快捷鍵A,D之後:Annotations
文件夾保存了我們標記的文件,(之後我們訓練時會用到這個文件夾)
問:yolo需要標註多少張圖片呢?
答:取決於你的數據集,簡單的幾千張
就夠,複雜的就要比較大了。
說明:YOLOv3的樣本都不需要負樣本
,只需要你標出目標物體就行了。但是爲了提高準確率需要注意一下三點了:
- 對目標的大小也沒多大要求,但是不能太小(比如小到只有七八個像素點)
- 樣本足夠多(各種大小、角度最好都來點)
- 標註的時候一定要仔細,不要圖快,不然後面要返工(親身經歷),bounding box要剛好圈住目標物體(當然你想同時識別物體的局部的話那麼同一局部的圖片也要足夠多)
- 在複雜的場景下面,也可以添加負樣本,也就是說一張圖片裏面沒有目標物體,樣本對應的標籤只要給一個空的txt文件就行了。比例的話我覺佔總樣本的一半吧。
現在可以瘋狂標註了! 畢竟一個老師教會yolo學生識字,要不斷備課。老師不容易呀!
2.生成索引
老師開始上課啦,yolo同學要認真聽講。這是數據預處理階段
。
(1)VOC結構
本學期的課程目錄,由老師整理的備課而來。
VOC全稱Visual Object Classes,出自The PASCAL Visual Object Classes(VOC)Challenge,這個挑戰賽從2005年開始到2012年,每年主辦方都會提供一些圖片樣本供挑戰者識別分類。
文件目錄:
圖片源於 | チン昶
我們在工程目錄下按照層級新建VOC目錄,並把我們標註的內容複製到工程目錄下:
(2)生成voc索引
上課:老師把每個單元的知識板書在黑板上 (獲取xml內容到txt中)
將voc數據集生成索引txt保存在ImageSets/Main
目錄下:
在工程yolov3/VOCdevkit/VOC2007/目錄下生成:test.txt
, train.txt
, val.txt
。
"""
voc_annotation.py
# 生成voc索引
VOCdevkit/VOC2007/
Annotations/ ---xml文件
ImageSets/
Layout/
Main/
train.txt/ ---voc訓練索引
test.txt/ ---voc測試索引
trainval.txt/ ---voc訓練測試索引
val.txt/ ---voc驗證索引
Segmentation/
JPEGImages/ ---圖片
"""
import os
import random
trainval_percent = 0.1
train_percent = 0.9
VOC_path = 'D:/myworkspace/JupyterNotebook/yolov3/VOCdevkit/VOC2007/'
xmlfilepath = os.path.join(VOC_path, 'Annotations')
txtsavepath = os.path.join(VOC_path, 'ImageSets/Main')
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
ftrainval = open(VOC_path+'ImageSets/Main/trainval.txt', 'w')
ftest = open(VOC_path+'ImageSets/Main/test.txt', 'w')
ftrain = open(VOC_path+'ImageSets/Main/train.txt', 'w')
fval = open(VOC_path+'ImageSets/Main/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
我這裏示範有 蝴蝶、魚、兔子:
(3)生成yolo索引
上課:同學們記筆記——抄黑板上的板書、勾畫重點筆記 (txt補充標記框內容)
在工程目錄yolov3/下生成:test.txt
, train.txt
, val.txt
。注意:classes是要訓練的對象。
"""
# 生成yolo索引
# yolo_annotation.py(修改於官方的voc_annotation.py)
model_data/
voc_class.txt/ ---配置文件,保存所有對象信息
train.txt/ ---yolo訓練索引
test.txt/ ---yolo測試索引
trainval.txt/ ---yolo訓練測試索引
val.txt/ ---yolo驗證索引
"""
import xml.etree.ElementTree as ET
from os import getcwd
sets = [('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
classes = ["fish", "butterfly", "rabbit"] # 你要訓練的對象
# 1.保存所有對象信息
classes_file = open('model_data/voc_class.txt', 'w')
for idx in classes:
classes_file.write(str(idx))
classes_file.write('\n')
classes_file.close()
def convert_annotation(year, image_id, list_file):
"""Annotations中xml加上真實框信息
"""
in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml' % (year, image_id))
tree = ET.parse(in_file)
root = tree.getroot()
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text),
int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))
list_file.write(" " + ",".join([str(a)
for a in b]) + ',' + str(cls_id))
wd = getcwd() # 獲得當前的工作目錄
for year, image_set in sets:
image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt' %
(year, image_set)).read().strip().split() # 讀取VOC目錄下txt中圖片路徑信息
# 2.model_data目錄下yolo索引txt中加上真實框標註信息
list_file = open('model_data/%s.txt' % (image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg' %
(wd, year, image_id)) # 3.VOC目錄下voc索引txt中加上圖片路徑信息
# 4.Annotations中xml加上真實框信息
convert_annotation(year, image_id, list_file)
list_file.write('\n')
list_file.close()
查看文件可以發現:yolo索引是圖片地址+真實框位置 ,classes此處僅標記了fish
:
全部標記:根據你的需要修改
classes = ["fish","butterfly","rabbit"] # 你要訓練的對象
這裏存放在model_data目錄:
3.圖像訓練
下課了:現在是yolo學生開始做課後作業,對學習的內容加以鞏。 這個過程叫做遷移學習
。
(1)轉換權重文件
課後例題講解
將 DarkNet 的.weights文件轉換成 Keras 的.h5文件
準備三個文件:convert.py , yolov3.cfg , yolov3.weights
有教程是在這裏修改了yolov3.cfg,會造成nan現象,這裏沒有修改用原cfg
執行語句:
python convert.py -w yolov3.cfg yolov3.weights model_data/yolo_weights.h5
生成h5文件存放位置:model_data/yolo_weights.h5
,後面訓練時會用到。
先驗參數:yolo_anchors.txt
anchors是SPP(spatial pyramid pooling)思想的逆向,即將不同尺寸的輸入resize成爲相同尺寸的輸出。所以SPP的逆向就是,將相同尺寸的輸出,倒推得到不同尺寸的輸入。
參考:YOLO-v3模型參數anchor設置
我這裏也沒有修改,用的原始值
(2)訓練
課後作業
-
下載源碼
train.py (我也實在不明白,只好啃github源碼了)參考1:https://github.com/qqwweee/keras-yolo3
(Python 3.5.2 +Keras 2.1.5+ tensorflow 1.6.0)
參考2:https://github.com/bubbliiiing/yolo3-keras
(Keras2.1.15 + tensorflow1.13.1)
上面兩種參考都是tensorflow-gpu1.x版本,食用時有出入修改,後面講到。根據參考2我下載相應輔助函數:(nets爲 darknet53 網絡模型,utils爲圖像加載輔助函數)
下載的訓練函數:(全部源碼可以在我gitee上查看)
-
tf- gpu 2.1.0 版本遇到的問題及修改
-
修改1:128行左右(用到tf1的config函數和session函數)
#原版 config = tf.ConfigProto() config = tf.compat.v1.ConfigProto(allow_soft_placement=True) #原版 set_session(tf.Session(config=config)) tf.compat.v1.keras.backend.set_session(tf.compat.v1.Session(config=config)) #注意 ,這裏爲tensorflow2.0版本,與第1.0有差距。
-
修改2:(
module 'keras.backend' has no attribute 'control_flow_ops'
)D:\mydownload\Anaconda3\envs\tensorflow\Lib\site-packages\keras\
backend\ __ init__.py添加:from .load_backend import control_flow_ops
backend\tensorflow_backend.py添加:
from tensorflow.python.ops import control_flow_ops
-
修改3:(
'Model'object has no attribute '_get_distribution_strategy'
)
修改,記得備份:D:\mydownload\Anaconda3\envs\tensorflow\Lib\site-packages\
tensorflow_core\python\keras\ callbacks.py -
修改4:文件目錄不存在,手動新建—
項目根目錄\logs\train\plugins\profile
-
-
運行ok了,
之前因爲我生成.h5時,修改了yolov3.cfg,出現nan現象:
ctrl+c
中斷,別擔心,我們每輪h5都有保存,可以繼續學習:
參考Keras 搭建自己的yolo3目標檢測平臺,就是把train.py中:initial_epoch
改爲你預先訓練的輪數- 預訓練模型
model_data/yolo_weights.h5
改爲logs下已訓練保存的版本
防止中途斷掉前功盡棄。
成功運行效果:
最終loss降到了21.5,效果不是很理想;在5,6最大到10左右,纔是進行預測的最好模型!
擁有模型就等於完成了作業,驕傲!
(3)優化
學霸開始發言: (這裏,這裏和那裏都可以用更優的算法)
學渣的做法: (玩命標註和訓練)
- 步驟1 :調整圖像標註 (增加圖片的豐富性)
- 步驟3 :修改train.py 的訓練次數
epochs
三、圖像識別
老師需要檢查yolo同學的學習效果,接下來安排考試。 這是測試階段
。
yolo同學要加油啊!
參考https://github.com/qqwweee/keras-yolo3/blob/master/yolo.py
可直接運行yolo.py 和yolo_vedio.py
這裏yolo.py調用了nets和utils輔助函數、注意模型相關路徑、調整置信度是繪圖的關鍵(避免檢測不到框或者繪製很多框):
這裏單獨測試:yolo_video.py
(注意你的圖片路徑)
也可以直接檢測:
python yolo_video.py --input D:\myworkspace\dataset\test.mp4
最後,我自己的檢測效果:65%的準確率,最高檢測效果達到77%,哈哈哈還不錯!
(這裏用model_data/yolo_weights.h5
原始模型,效果是100%🤣)
python yolo_video.py --input D:\myworkspace\dataset\xuanya.mp4
視頻檢測結果:
相信我已經掌握 圖像標註、訓練、識別 全部流程!
繼續修改、訓練,直到得到滿意的分數!
總結:
一共19張圖片,3類;yolov3遷移訓練學習獲得h5模型
圖片檢測效果:
- 警告:
FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.
解決:參考鏈接