【Keras+TensorFlow+Yolo3】一文掌握圖像標註、訓練、識別(tf2填坑)

一、前言

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

源碼源碼:

https://gitee.com/cungudafa/keras-yolo3

二、訓練集標註

老師備課階段——圖片是課程內容,標註框時知識點。

在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)圖像標註

具體的備課內容——知識點就是標註方框信息。

  1. 準備
    下載完成後是一個可執行exe文件,注意存放到一個非中文的路徑下。
    在這裏插入圖片描述
    同時,我創建了三個文件夾:

  2. 標註
    運行labelImage,調整到合適大小;熟記使用6步驟:
    打開文件夾(photos)-》設置保存文件夾(annotations)
    設置自動保存(view -》auto Saving)-》標註框(Create RectBox)並命名
    快捷鍵A保存xml-》快捷鍵D下一張
    在這裏插入圖片描述
    在這裏插入圖片描述
    附:(labelImg快捷鍵表)
    在這裏插入圖片描述
    標註示例(輪廓對齊原則):
    在這裏插入圖片描述
    (建議從左下角標註到右上角,因爲在圖片讀取中順序是(x1,y1)到(x2,y2))
    標籤英文!!!因爲後面在python讀取不出錯
    在這裏插入圖片描述
    快捷鍵A,D之後:Annotations文件夾保存了我們標記的文件,(之後我們訓練時會用到這個文件夾)
    在這裏插入圖片描述

問:yolo需要標註多少張圖片呢?

答:取決於你的數據集,簡單的幾千張就夠,複雜的就要比較大了。

在這裏插入圖片描述
說明:YOLOv3的樣本都不需要負樣本,只需要你標出目標物體就行了。但是爲了提高準確率需要注意一下三點了:

  1. 對目標的大小也沒多大要求,但是不能太小(比如小到只有七八個像素點)
  2. 樣本足夠多(各種大小、角度最好都來點)
  3. 標註的時候一定要仔細,不要圖快,不然後面要返工(親身經歷),bounding box要剛好圈住目標物體(當然你想同時識別物體的局部的話那麼同一局部的圖片也要足夠多)
  4. 複雜的場景下面,也可以添加負樣本,也就是說一張圖片裏面沒有目標物體,樣本對應的標籤只要給一個空的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)訓練

課後作業
在這裏插入圖片描述

  1. 下載源碼
    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上查看)
    在這裏插入圖片描述

  2. 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
      在這裏插入圖片描述
      在這裏插入圖片描述

  3. 運行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】使用VOC數據集訓練自己的YOLOv3模型(Keras/TensorFlow)

三、圖像識別

老師需要檢查yolo同學的學習效果,接下來安排考試。 這是測試階段
yolo同學要加油啊!
在這裏插入圖片描述

參考https://github.com/qqwweee/keras-yolo3/blob/master/yolo.py
可直接運行yolo.py 和yolo_vedio.py

這裏yolo.py調用了nets和utils輔助函數、注意模型相關路徑、調整置信度是繪圖的關鍵(避免檢測不到框或者繪製很多框):
在這裏插入圖片描述

這裏單獨測試:yolo_video.py
(注意你的圖片路徑)
在這裏插入圖片描述
也可以直接檢測:

參考:tf2-keras-yolo3

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模型
在這裏插入圖片描述
圖片檢測效果:
在這裏插入圖片描述


  1. 警告: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'.
    解決:參考鏈接
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章