经过YOLOv5训练一个简单的识别鱼的模型(超详细的入门级教程)(一)的学习后,明白了训练模型的全套流程,现在我们的问题是如何提升模型的性能?
非常重要的一个环节便是数据集,一个好的数据集对于模型性能是至关重要的。
我们首先利用VOC2007数据集来对模型进行复现
解压到当前文件夹
,两个压缩包的内容会合并在VOCdevkit
中000005.jpg
时云里雾里。这时我们对于VOC2007数据集有了进一步的理解,有以下文件:
我们做的时目标检测任务,而且不是人的动作识别(具有人体部位的数据)(layout是做这个任务的)所以上述的SegmentationClass
,SegmentationObject
,Layout
,Segmentation
文件夹我们都不需要。
在data
目录下,放入VOCdevkit
(包括了一整个VOC2007数据集),在相同的文件夹内创建voc2yolo.py
,内容如下,并运行
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
# 这里就体现出来了咱们在1.2步骤的时候我说的尽量按照那个目录名进行操作的优势,
# 在这可以剩下很多去修改名称的精力
# sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
sets=[ ('2007', 'train'), ('2007', 'val'), ('2007', 'test')] # 我只用了VOC2007
classes = ["aeroplane", "bicycle", "bird", "boat", "bottle",
"bus", "car", "cat", "chair", "cow",
"diningtable", "dog", "horse", "motorbike", "person",
"pottedplant", "sheep", "sofa", "train", "tvmonitor"]
#classes = ["face"] # 修改为自己的label
def convert(size, box):
dw = 1./(size[0]) # 有的人运行这个脚本可能报错,说不能除以0什么的,你可以变成dw = 1./((size[0])+0.1)
dh = 1./(size[1]) # 有的人运行这个脚本可能报错,说不能除以0什么的,你可以变成dh = 1./((size[0])+0.1)
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
w = box[1] - box[0]
h = box[3] - box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def convert_annotation(year, image_id):
in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
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 = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
bb = convert((w,h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
for year, image_set in sets:
if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
# 这块是路径拼接,暂时用不上,先都注释了
# os.system("cat 2007_train.txt 2007_val.txt 2012_train.txt 2012_val.txt > train.txt")
# os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt > train.all.txt")
可以看到生成了三个数据集的路径txt文件,和label文件夹。
还是原来的步骤,我们继续巩固以下~
这里我们直接修改voc.yaml
的文件,可以看到还有coco.yaml
文件,其实就是你的数据集的配置文件罢了!!
# PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC/
# Download command: bash ./data/get_voc.sh
# Train command: python train.py --data voc.yaml
# Default dataset location is next to /yolov5:
# /parent_folder
# /VOC
# /yolov5
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
train: F:\AI\datasets\VOC2007\VOCdevkit\VOC2007\2007_train.txt
val: F:\AI\datasets\VOC2007\VOCdevkit\VOC2007\2007_val.txt
# number of classes
nc: 20
# class names
names: ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
可以看到博主把常用数据集都放在了一个路径里,整理在一起!!值得学习
该文件需要修改的地方是第2行nc的个数,需要改成自己数据集类别的个数,对于VOC数据集改成20。
/
,但是在win下用的是\
,所以找不到label(可能是这个原因)voc2yolo.py
中最后的代码修改为 list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
换成
list_file.write('%s\VOCdevkit\VOC%s\JPEGImages\%s.jpg\n'%(wd, year, image_id))
但是发现还是找不到label,我们把将里面所有txt文件复制到 [ VOCdevkit\VOC2007\JPEGImages ]中即可。
这时,常规错误出现了
这类报错原因是显卡内存太小了,一次装不下太多的图片,因此可以通过–batch-size调整每个批次样本的个数,默认值是16。报错后可以调整为8试试,如果还是报错,再调整为4试试,如果还是报错,那请找一把锤子,瞄准电脑主机箱用力地砸下去…
我的batch-size已经改成1了伙计们。。
那下一个教程咱们就利用远程服务器来进行模型训练吧!~
在Main
文件夹下可以看到很多的txt文件,作用是什么呢?就是分出test集、train集和val集。还有一个trainval集(train+val和合集嘛)
刚打开的时候发现有84个txt文件,其中有四个不带前缀,剩下的80个呢分别对应了VOC中的20个类别的四个数据集txt文件。
train
、test
、trainval
、val
里面的内容如下,就是很常规的划分数据集:
这个1
和-1
所代表的正负样本究竟是什么呢?
所以在进行数据采样时,如何解决数据不平衡的问题呢?
这是一种较为直接的办法,即通过随机复制少数类来增加其中的实例数量,从而可增加样本中少数类的代表性。
这种方法也比较直接,即通过随机消除占多数类的样本来平衡类分布,直到多数类和少数类实现平衡。
上面的两种方法比较直接方便,但也存在弊端,比如过采样可能会导致过拟合,欠采样可能无法很好地利用有限的数据(这也可能会造成过拟合)。因此最好还是获取更多的样本来补充,我认为主要有下面两种方法: