YOLOv5訓練過程
1. 數據格式轉為YOLOv5需要的格式
YOLOv5
需要圖像標注的數據格式
大家都知道,用於訓練的圖片都是有對應的標注信息的,主要來標注圖片中的待識別物體(用邊界框和類別表示)
在yolov5
中每一個圖片對應的標注信息(邊界框和類別)是存放在txt
文件中的,內容如下所示:
每一行5個值,含義依次是類別,真實邊界框中心點x坐標,y坐標,寬,高
如果你的數據沒有對應的標注文件,那么可以用標注工具進行標注:(可以用labelme
或者labelimg
,或者yolov5
提供的一個網址數據集制作)
如果你有標注文件,但是格式不對的畫,比如你是json
格式,就需要自己手動編寫腳本去轉換,或者去網上找別人寫好的腳本
這里以一個我的json
文件為例,如果有和這個json格式相同的,可能大多數都與這個不同,可以用下面代碼進行轉換:
{"info":
{"image_name": "5191_1642654681678.jpg"},
"annotations": [{"bbox": [99, 517, 8, 18], "color": "other"}, {"bbox": [113, 519, 9, 17], "color": "other"},
{"bbox": [223, 531, 9, 29], "color": "other"}, {"bbox": [237, 555, 7, 14], "color": "other"}, {"bbox": [382, 564, 6, 12],
"color": "red"}, {"bbox": [325, 484, 10, 28], "color": "other"}, {"bbox": [388, 480, 12, 22], "color": "other"},
{"bbox": [453, 481, 13, 29], "color": "other"}, {"bbox": [721, 555, 7, 17], "color": "other"}, {"bbox": [710, 555, 7, 15],
"color": "other"}, {"bbox": [944, 533, 7, 18], "color": "red"}, {"bbox": [992, 533, 6, 18], "color": "red"},
{"bbox": [1261, 566, 6, 15], "color": "red"}, {"bbox": [801, 565, 6, 15], "color": "other"}, {"bbox": [792, 565, 7, 15],
"color": "other"}, {"bbox": [772, 575, 8, 18], "color": "red"}, {"bbox": [389, 564, 6, 14], "color": "other"}]}
import os
from PIL import Image
import json
import numpy as np
import pandas as pd
# 讀取原始的json數據
ant_root_dir = "./traffic_light_data/annotations" # 存放json文件的文件夾
img_root_dir = "./traffic_light_data/images" # 存放圖像的文件夾
output_root = "./traffic_light_data/ant_txt" # 存放輸出結果的文件夾
json_list = os.listdir(ant_root_dir)
json_dir_list = [os.path.join(ant_root_dir, json_dir) for json_dir in json_list]
def cls_merger_bbox(cls, bbox, size):
"""
這個函數需要你修改一下下面的類別映射,如果類別多的話,用下面的代碼則很不好,可以自己改一下
"""
# 轉換顏色字符串為類別數字
if cls == 'red':
cls = 0
elif cls == 'green':
cls = 1
elif cls == 'yellow':
cls = 2
else:
cls = 3
# 轉換bbox到0-1之間(除以圖像寬和高)
# 傳入的bbox格式為(邊界框中心x,中心y,寬,高)
bbox [0], bbox[2] = bbox[0] / size[0], bbox[2] / size[0]
bbox[1], bbox[3] = bbox[1] / size[1], bbox[3] / size[1]
bbox.insert(0, cls)
bbox = np.around(bbox, decimals=4)
return bbox
for i, json_dir in enumerate(json_dir_list):
# 將json數據轉為python字典格式,並讀取標注信息
data = json.load(open(json_dir))
ant_list = data['annotations']
image_name = data['info']['image_name']
# 讀取json文件對應的圖像寬高
image_dir = os.path.join(img_root_dir, image_name)
img = Image.open(image_dir)
size = img.size
# 用數組存取我們的標注信息
ant_yolo_np = np.zeros((len(ant_list), 5))
for i, ant in enumerate(ant_list):
bbox = ant['bbox'] # list
cls = ant['color'] # str
# 將bbox縮放到0-1之間,並把cls轉成對應的數字,將兩者放在一個列表中
cls_bbox = cls_merger_bbox(cls, bbox, size)
# 放入數組中
ant_yolo_np[i, :] = cls_bbox
output = pd.DataFrame(ant_yolo_np)
output.iloc[:, 0] = output.iloc[:, 0].astype(int)
output_name = os.path.join(output_root, os.path.splitext(image_name)[0]+'.txt')
# np.savetxt(output_name, ant_yolo_np, delimiter=' ', fmt='%.04f')
output.to_csv(output_name, sep=' ', index=False, header=False)
print("轉換完畢")
import random
import shutil
"""
下面代碼用於划分訓練集和驗證集
"""
image_list = os.listdir(img_root_dir)
output_list = os.listdir(output_root)
index_list = random.sample(range(len(image_list)), 80)
for i in index_list:
image_name = os.path.join(img_root_dir, image_list[i])
txt_name = os.path.join(output_root, output_list[i])
shutil.move(image_name, './valid_image')
shutil.move(txt_name, './valid_txt')
yolov5需要的數據在文件夾中的位置
你的圖像和標注數據應該按照下面的形式放在文件夾中:
datasets
- traffic_light
- images
- train 存放訓練圖像
- val 存放驗證集圖像
- labels
- train 存放訓練圖像對應的標注txt文件
- val 同上
- images
然后將datasets
文件夾放到與你下載到的yolov5
項目的同級目錄下
2.訓練時必須修改的文件
創建自己的.yaml
文件,里面主要用來配置你的數據的信息,創建位置如下圖所示:
里面的內容如下所示:
主要是把我們剛才放到datasets
下的數據集的路徑還有訓練集合驗證集的路徑填一下
修改models
文件夾下的yolov5*.yaml
文件,這個是你后面用於訓練的模型配置文件(下圖改的是yolov5x.yaml
),修改一下類別就行,其他的有能力也可以改:
將數據集配置好,並修改以上兩個文件后就可以訓練啦!
進入yolov5
項目文件夾,打開終端,輸入下面命令:
python train.py --img 640 --batch 4 --epochs 30 --data ./data/traffic_light.yaml --weights ./weights/yolov5x.pt --cfg ./models/yolov5x.yaml
--img
:指的是輸入網絡的圖像尺寸,有兩個選擇,640
和1280
--batch
:是1
個epoch
內,一次性喂入網絡的數據中包含的圖像個數,也就是卷積網絡輸入數據的第一個緯度(比如[4,3, 640,640]
);可以根據你的顯存大小進行調整,顯存越大可以設置更大,我的就6G,且網絡模型很大,所以就設置小一些,不然會報顯存不足或者其他錯誤--epochs
:訓練網絡的次數,一個epoch
有圖像總數/batch
次更新模型的機會,一個epoch
進行完之后,說明你的訓練數據集已將全部被網路訓練一遍了,接下來網絡會在驗證集上驗證目前的網絡參數效果如何--data
:你的數據集對應的.yaml
文件--weights
:官方提供的預訓練權重,weights
文件夾是我自己建的;下載地址:權重下載,進去之后找到Assets字樣,如果你的網絡比較卡,可以在百度網盤中下載:鏈接:https://pan.baidu.com/s/1CCmJmx4wCIJcmDahIye2Hw ,權重后面的6
表示的是輸入圖像尺寸為1280分辨率的圖像,--cfg
也要改成相應的帶6
的
提取碼:iltr--cfg
:網絡模型對應的文件
正常來說就可以訓練了,如果有什么問題可以留言,看到了會回復
訓練好之后,會提示你本次訓練結果存放在run/train/exp*
文件夾下,在該文件夾下的weights
文件夾中可以看到本次訓練的最好參數和最后一個epoch
訓練完之后的權重
用你訓練好的權重進行測試
執行下面代碼:
python detect.py --weights ./runs/train/exp6/weights/best.pt --source ./test.jpg
執行完之后會提示你結果保存在***
中
- 下面是
--source
參數的值
--weights
:是你訓練好的權重
3.其他
可視化時,更改邊界框的粗細
修改學習率等超參數
data
文件夾下的hyps
文件夾中可以修改各種超參數,-low
好像是圖像尺寸為640
時生效
4.訓練結果記錄
第一次: 本次用的圖像尺寸是640,也就是說會把你輸入的圖像,進行縮放與隨機裁剪等變化,最終用於訓練的大小是640;直接用的最大的模型yolov5x,批次剛開始小一些30個,發現mAP一直在上升,因此可以加大批次數,增大一些學習率python train.py --img 640 --batch 4 --epochs 30 --data ./data/traffic_light.yaml --weights ./weights/yolov5x.pt --cfg ./models/yolov5x.yaml |
---|
![]() |
測試結果:python detect.py --weights ./runs/train/exp6/weights/best.pt --source ./test.jpg |
第二次: 與第一次相比,只是把初始學習率改為了0.03 ,然后訓練次數增大到100 ;感覺mAP 還有上升空間,下面繼續增加訓練次數和學習率python train.py --img 640 --batch 4 --epochs 100 --data ./data/traffic_light.yaml --weights ./weights/yolov5x.pt --cfg ./models/yolov5x.yaml |
![]() |
python detect.py --weights ./runs/train/exp6/weights/best.pt --source ./detect # 將detect 文件夾下的圖片都進行測試 |
下面是跑了300個epochs 的情況,感覺兩次結果很接近 |
![]() |