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