一、项目介绍
使用Yolov7做目标检测是常见的选择,目前YOLO系列已有yolov8,是一种即为流行的目标检测算法,相较于传统的目标检测算法,YOLO系列算法具有实时性,同时具有更快的检测速度和较高的精度。YOLOv7的主要创新如下:1. 单阶段检测:YOLOv7采用单个神经网络模型,直接在整个图像上进行目标检测,无需使用候选区域提取或多级分类器。2. 实时性能:YOLOv7能够以非常快的速度进行目标检测,适用于实时应用场景。3. 多尺度特征融合:YOLOv7通过使用不同尺度的特征图进行目标检测,能够更好地捕捉不同尺度的目标。4. Anchor Boxes:YOLOv7使用Anchor Boxes来预测目标的边界框,可以更好地适应不同形状和尺寸的目标。5. 高精度检测:YOLOv7在保持实时性能的同时,也具备较高的目标检测精度。
接下来是使用YOLOv7训练自己的数据集的全流程:1、下载源码 2、数据准备 3、修改配置文件参数 4、模型训练 5、模型预测。我会一步步为大家介绍。
二、具体步骤
1、下载源码:
官方源码github地址如下: https://github.com/WongKinYiu/yolov7 下载好压缩包后再用pycharm创建好工程,解压缩,这样就得到我们的源码。接下来,你需要仔细地根据requirements.txt配置好环境。我的做法是:用anaconda先创建一个虚拟环境,例如我想创建一个python3.6的虚拟环境,就可以在工程目录下打开cmd,然后输入conda create -n myenv python=3.6,这样就创建完成一个名为myenv的虚拟环境。我们每次需要激活它才能使用:conda activate myenv。
然后,输入conda install --file requirements.txt,这样就可以安装所有依赖项。当然,你可能会遇到安装超时问题,这时需要你把不能正常安装的依赖项用whl的方法安装,打开download.pytorch.org/whl/torch_stable.html网站,查找需要的依赖项下载到本地,在cmd中输入pip install 文件名.whl可以安装。需要注意的是,有些依赖项的不同版本可能会相互冲突,这样会产生一些常见的问题:
1、cuda,pytorch,torchvision版本之间相互不兼容,怎么办?:第一、你需要在pytorch官方或其他方法确认你的cuda所兼容的pytorch,torchvision版本,手动下载纠正。第二、pytorch,torchvision会存在cpu版本和gpu版本,我们一般需要下载的是前缀有cu+数字的版本。第三、你也可以通过换源的方法加速你的下载速度。
2、cuda需要提前安装,查看适合的cuda版本:cmd,然后nvidia-smi,这样可以查看兼容的CUDA版本,访问以下链接:https://developer.nvidia.com/cuda-gpus,在CUDA-GPUs部分的搜索框中,输入您的GPU型号,并从下拉列表中选择相应的型号。在结果页面中,找到与你的GPU型号兼容的CUDA版本,下载。
2、数据准备(打标签):
YOLOv7需要的数据集结构:
--Annotations
--00001.xml
--00002.xml
.....
--JPEGImages
--00001.jpg
--00002.jpg
需要准备一定数量的各类别的图片,还需要安装labelimg,你只需在终端输入pip install labelimg即可安装,之后输入labelimg打开,长下面这样的:
点击open dir是寻找要打标签的文件夹,即JPEGImages,然后选择生成xml的文件夹,即Annotations,再选择view ->Auto save mode开启自动保存。按w键拖动框柱要框柱的类别,这个相当于标签,即模型学习的答案,所以标签的质量会影响到模型的效果。全部标注好之后可以查看Annotations是否生成所有的xml。打标签环节结束。
3、修改配置文件参数
打开data文件夹,这里有官方的voc.yaml文件,你需要自己创建一个类似的.yaml文件,按情况修改以下参数:nc(类别数),names(类别名),然后根据JPEGImages和Annotations的信息进行voc_to_yolo的转换,创建一个python脚本,具体代码:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile
classes = ["one","two",]
TRAIN_RATIO = 50
def clear_hidden_files(path):
dir_list = os.listdir(path)
for i in dir_list:
abspath = os.path.join(os.path.abspath(path), i)
if os.path.isfile(abspath):
if i.startswith("._"):
os.remove(abspath)
else:
clear_hidden_files(abspath)
def convert(size, box):
dw = 1. / size[0]
dh = 1. / size[1]
x = (box[0] + box[1]) / 2.0
y = (box[2] + box[3]) / 2.0
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(image_id):
in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' % image_id)
out_file = open('VOCdevkit/VOC2007/YOLOLabels/%s.txt' % 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:
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')
in_file.close()
out_file.close()
wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_sapce_dir):
os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)
train_file = open(os.path.join(wd, "yolov7_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov7_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov7_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov7_val.txt"), 'a')
list_imgs = os.listdir(image_dir) # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0, len(list_imgs)):
path = os.path.join(image_dir, list_imgs[i])
if os.path.isfile(path):
image_path = image_dir + list_imgs[i]
voc_path = list_imgs[i]
(nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
(voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
annotation_name = nameWithoutExtention + '.xml'
annotation_path = os.path.join(annotation_dir, annotation_name)
label_name = nameWithoutExtention + '.txt'
label_path = os.path.join(yolo_labels_dir, label_name)
prob = random.randint(1, 100)
print("Probability: %d" % prob)
if (prob < TRAIN_RATIO): # train dataset
if os.path.exists(annotation_path):
train_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_train_dir + voc_path)
copyfile(label_path, yolov5_labels_train_dir + label_name)
else: # test dataset
if os.path.exists(annotation_path):
test_file.write(image_path + '\n')
convert_annotation(nameWithoutExtention) # convert label
copyfile(image_path, yolov5_images_test_dir + voc_path)
copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()
你只需要修改类别数即可。运行之后会在VOCdevkit里生成images和labels文件夹。这时你要找到之前创建的.yaml文件,修改train和val的路径,改成images里的train和val。此环节结束。
4、训练环节
接下来看看train,py,从522行(左右)起是主程序,修改weights为‘yolov7.pt’,如果你没有这个文件,可以到github去下载(上述),修改data为你的.yaml文件,修改epochs,batchsize,img-size,device,workers为你想要参数(不改也可以),然后运行。训练好的模型在runs/train
5、detect
打开detect.py,将训练好的.pth文件放到weights,souce选择预测模式(图片、视频、摄像头),其他的不用改。
这样,你就能用自己的数据集得到需要的目标检测模型!!!
以上为全部内容。