使用labelImg訓練模型並用yolo3進行識別的工作流程


1.參考上一篇博客

https://www.cnblogs.com/StarZhai/p/11926610.html

2.下載yolov3項目工程。

https://github.com/pjreddie/darknet

3.修改Makefile文件(文件就在下載的darknet文件夾內)

GPU=1    #使用GPU訓練,其他的沒有用,所以沒有置為1,可根據自己的需要調整
CUDNN=1
OPENCV=1
OPENMP=0
DEBUG=0

4.在目錄下新建VOC2007,並在VOC2007下新建Annotations,ImageSets和JPEGImages三個文件夾。在ImageSets下新建Main文件夾。文件目錄如下所示:

然后可以按照labelImg使用方法開始標注圖片,生成xml文件或txt文件

 

 

 5.划分訓練集測試集按照上一篇文檔

6.將labels中的txt全部復制到JPEGImages文件夾中,做到圖片和txt一一對應

  一開始是要吧JPEGImages文件中的圖片放到darknet-master/data/images目錄下,現在直接把yolo的標簽文件txt即labels中的內容復制到JPEGImages文件夾中就可以了。

7.局部修改

 

①根據自己的路徑修改cfg/voc.data

 

②修改data/voc.names和coco.names

 

③修改參數文件cfg/yolov3-voc.cfg

ctrl+f搜 yolo, 總共會搜出3個含有yolo的地方。
每個地方都必須要改2處, filters:3*(5+len(classes));
其中:classes: len(classes) = 1,這里以單個類dog為例
filters = 18
classes = 1
可修改:random = 1:原來是1,顯存小改為0。(是否要多尺度輸出。)

8.開始訓練

①在darknet-master終端運行如下代碼進行訓練

wget https://pjreddie.com/media/files/darknet53.conv.74

#不保留訓練日志的訓練執行命令 ./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

 #保存訓練日志的訓練執行命令

 ./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74 | tee train_yolov3-voc.log

#日志位於項目的根目錄下

 
        

②訓練默認的是前1000輪每100輪保存一次模型,1000輪后每10000輪保存一次模型。可以修改examples/detector.c文件的138行。修改完重新編譯一下,在darknet目錄下執行make。

make

 

 

 

9.訓練日志參數說明

Region xx:cfg文件中yolo-layer的索引;
Avg IOU: 當前迭代中,預測的box與標注的box的平均交並比,越大越好,期望數值為1;
Class:標注物體的分類准確率,越大越好,期望數值為1;
obj:越大越好,期望數值為1;
No obj:越小越好;
.5R:以IOU=0.5為閾值時候的recall; recall = 檢出的正樣本/實際的正樣本
0.75R:以IOU=0.75為閾值時候的recall;
count:正樣本數目

 

 

20277: 指示當前訓練的迭代次數
0.38915: 是總體的Loss(損失)
0.42692 avg: 是平均Loss,這個數值應該越低越好,一般來說,一旦這個數值低於0.060730 avg就可以終止訓練了。
0.000100 rate: 代表當前的學習率,是在.cfg文件中定義的。
0.302128 seconds: 表示當前批次訓練花費的總時間。
162216 images: 這一行最后的這個數值表示到目前為止,參與訓練的圖片的總量。

10.調參中遇到的問題

在Region 82 Avg IOU、Region 94 Avg IOU、Region 106 Avg IOU中出現很多nan
前提說明:在訓練過程中,nan的屏幕占比30%是正常的,如果太大,全是nan,則就是訓練出了問題

解決方法一:在顯存允許的情況下,可以適當增加batch(darknet-master/yolov3-voc.cfg中的batch)的大小(要視自己數據集 的大小情況來調整batch和subdivisions batch指的是單詞識別圖片個數,subdivisions是將batch划分的組數:例如batch=64 subdivisions=16  64/16=4所以單次訓練變成16次循環,每次循環同事訓練4張圖片。我的電腦GTX1050 8G做深度學習略低,只允許同時訓練一張圖片。因此通過同時擴大二者可以增大循環訓練次數。我用1000張滅火器圖片另bath和subdivisions都為8最終效果還不錯),這樣能夠一定程度減少nan的出現。

解決方法二:增加數據集的規模。若是對於10類以內的圖片,500張以內的訓練集未必是太少了,因此可以增加數據集,實在不                         行的話就進行數據增強,把數據集擴展到原來的幾倍到幾十倍不等。

 CUDA Error: out of memory darknet: ./src/cuda.c:36: check_error: Assertio `0' failed.

 解決方法:顯存不夠,調小batch,關閉多尺度訓練:random=0.(*************親測有用**************)

 random所在(darknet-master/cfg/yolov3-voc.cfg):

11.訓練結果

  在訓練20000步以后可以看到在backup生成如下訓練過程中的權重文件

 

保存的訓練日志文件

 

 

12.在avg低於0.06以后,如何停止訓練

ubuntu系統下,在訓練終端處,使用ctrl+c終止訓練

13.如何接着上一步停止處的訓練狀態繼續訓練

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.backup

 14.將訓練好的權重放到yolov3項目中convert.py的同級目錄下邊(yolov項目項目的根目錄)執行訓練語句

python convert.py yolov3_voc.cfg yolov3.weights model_data/yolo.h5

 TypeError: buffer is too small for requested array

解決方法:把cfg文件對應好,用上文改好的yolov3-voc.cfg(與其他的cfg類個數不同)

 

15.訓練日志的可視化

visualization_train_yolov3-voc_log.py

# -*- coding: utf-8 -*-
# @Func    :yolov3 訓練日志可視化,把該腳本和日志文件放在同一目錄下運行。
 
import pandas as pd
import matplotlib.pyplot as plt
import os
 
# ==================可能需要修改的地方=====================================#
g_log_path = "train_yolov3-voc.log"  # 此處修改為你的訓練日志文件名
# ==========================================================================#
 
def extract_log(log_file, new_log_file, key_word):
    '''
    :param log_file:日志文件
    :param new_log_file:挑選出可用信息的日志文件
    :param key_word:根據關鍵詞提取日志信息
    :return:
    '''
    with open(log_file, "r") as f:
        with open(new_log_file, "w") as train_log:
            for line in f:
                # 去除多gpu的同步log
                if "Syncing" in line:
                    continue
                # 去除nan log
                if "nan" in line:
                    continue
                if key_word in line:
                    train_log.write(line)
    f.close()
    train_log.close()
 
 
def drawAvgLoss(loss_log_path):
    '''
    :param loss_log_path: 提取到的loss日志信息文件
    :return: 畫loss曲線圖
    '''
    line_cnt = 0
    for count, line in enumerate(open(loss_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(loss_log_path, skiprows=[iter_num for iter_num in range(line_cnt) if ((iter_num < 500))],
                         error_bad_lines=False,
                         names=["loss", "avg", "rate", "seconds", "images"])
    result["avg"] = result["avg"].str.split(" ").str.get(1)
    result["avg"] = pd.to_numeric(result["avg"])
 
    fig = plt.figure(1, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result["avg"].values, label="Avg Loss", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg Loss Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg Loss")
 
 
def drawIOU(iou_log_path):
    '''
    :param iou_log_path: 提取到的iou日志信息文件
    :return: 畫iou曲線圖
    '''
    line_cnt = 0
    for count, line in enumerate(open(iou_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(iou_log_path, skiprows=[x for x in range(line_cnt) if (x % 39 != 0 | (x < 5000))],
                         error_bad_lines=False,
                         names=["Region Avg IOU", "Class", "Obj", "No Obj", "Avg Recall", "count"])
    result["Region Avg IOU"] = result["Region Avg IOU"].str.split(": ").str.get(1)
 
    result["Region Avg IOU"] = pd.to_numeric(result["Region Avg IOU"])
 
    result_iou = result["Region Avg IOU"].values
    # 平滑iou曲線
    for i in range(len(result_iou) - 1):
        iou = result_iou[i]
        iou_next = result_iou[i + 1]
        if abs(iou - iou_next) > 0.2:
            result_iou[i] = (iou + iou_next) / 2
 
    fig = plt.figure(2, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result_iou, label="Region Avg IOU", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg IOU Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg IOU")
 
 
if __name__ == "__main__":
    loss_log_path = "train_log_loss.txt"
    iou_log_path = "train_log_iou.txt"
    if os.path.exists(g_log_path) is False:
        exit(-1)
    if os.path.exists(loss_log_path) is False:
        extract_log(g_log_path, loss_log_path, "images")
    if os.path.exists(iou_log_path) is False:
        extract_log(g_log_path, iou_log_path, "IOU")
    drawAvgLoss(loss_log_path)
    drawIOU(iou_log_path)
    plt.show()
 

(2) 將上述python腳本文件和訓練日志放在同一目錄下,打開此目錄下的終端,運行上述.py文件可以得到loss變化曲線和Avg IOU變化曲線。同時,在當前目錄下生成了train_log_iou.txt和train_log_loss.txt文件。

loss變化曲線和Avg IOU變化曲線(僅供參考)

 

 

 

 

 

.測試結果

 

 

 

誤判的0.1那個通過設置yolo.py中的閾值解決

 

 

 

 參考文檔:

①超詳細教程:YOLO_V3(yolov3)訓練自己的數據

  https://blog.csdn.net/qq_21578849/article/details/84980298
②字兒超級多的ubuntu訓練自定義目標識別
  https://blog.csdn.net/gaoyu1253401563/article/details/89642932
③小白手冊
  https://blog.csdn.net/weixin_42731241/article/details/81352013


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM