YOLOv5作为常用的目标检测框架,在如今还有很多地方可以使用到。今天不讲yolov5的模型架构,更注重实际怎么使用这个框架,该文章将从数据集制作和yolov5训练的数据集格式开始讲起,使用两个目标【行人】【非机动车】作为案例制作数据集,再到训练网络,最后使用训练得到的网络来进行推理。

1 利用labelimg制作YOLOv5目标检测数据集

参考链接:http://t.csdnimg.cn/uJVVr

1.1 labelimg介绍

Labelimg是一款开源的数据标注工具,可以标注三种格式。分为是:
1 VOC标签文件,保存为xml文件。
2 yolo标签格式,保存为txt文件。
3 createML标签格式,保存为json格式。

1.2 labelimg安装

1.window系统命令安装
首先打开cmd命令行(快捷键:win+R)。进入cmd命令行控制台。输入如下的命令:

pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple

-i https://pypi.tuna.tsinghua.edu.cn/simple是指使用清华镜像源来安装,直接安装可能使用的国外网站源,没有挂梯子下载很慢。![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1952dde4dd594ef99fca846d39eda4cf.jpeg#pic_center在这里插入打打撒
的=
我这里已经安装,你只需要安装上述指令安装最后出现successfully install提示行就表明安装成功了!

2.anaconda命令安装
你也可以通过anaconda创建一个新的环境来安装。
可参考:http://t.csdnimg.cn/qRyXZ
本篇文章就按第一种方法安装。

1.3 labelimg使用

安装好labelimg后我们就可以对我们的数据进行标注啦!

1.3.1 yolov5数据集格式

yolov5训练的数据集格式为图片和图片对应的标签txt文件。其中txt文件包含了你所标注的框的位置信息和框的长宽信息以及类别。
这边先整理出数据里,首先了解文件夹目录结构:
├── data(一级文件夹)
│├── Image 存放需要打标签的图片文件
│├── Labels 存放标注的标签文件
注意对应好文件夹的目录级别
在这里插入图片描述
如图Image文件夹下存放这我要标注的图片。

1.3.2 使用labelimg进行标注

打开cmd命令终端(快捷键:win+R),输入以下指令即可打开标注截面,指令如下:

labelimg 

在这里插入图片描述

点击< Open Dir >选择Image文件夹后进入带操作界面,如下图所示:
在这里插入图片描述
点击View,会出现如图红色框框中的选项。最好和我一样把勾勾勾上。如下图所示:

    Auto Save mode:切换到下一张图的时候,会自动保存标签。

    Display Labels:会显示标注框和标签

    Advanced Mode:标注的十字架会一直悬浮在窗口。

在这里插入图片描述
一些快捷键
A:切换到上一张图片

D:切换到下一张图片

W:调出标注十字架

del :删除标注框框

Ctrl+u:选择标注的图片文件夹

Ctrl+r:选择标注好的label标签存在的文件夹
开始标注
我们先点击 < Change Save Dir >按键选择同级目录下的Labels文件夹来保存我们输出的标签文件,由于我们使用yolo模型来进行训练,故格式输出调整为yolo即可。

如下图所示,点击< Create RectBox >按键创建标注框,输入你的类别。
在这里插入图片描述
输出的txt文件如下图所示,第一列数字0,1代表的是类别名,后面四个数字代表的是标注框的X,Y,W,H 位置信息和框的宽高信息。
在这里插入图片描述
当然voc格式和yolo格式可以相互转化,通过我提供的xml2txt进行xml转换为yolo格式,通过txt2xml将yolo格式转为xml格式,代码如下:
—txt2xml.py

import os
import xml.etree.ElementTree as ET
from PIL import Image
import numpy as np

# 图片文件夹,后面的/不能省
img_path = 'C:/Users/KD35lrp/Downloads/DATASET/dataset/detectiondataset/Image/'

# txt文件夹,后面的/不能省
labels_path = 'C:/Users/KD35lrp/Downloads/DATASET/dataset/detectiondataset/label/'

# xml存放的文件夹,后面的/不能省
annotations_path = 'C:/Users/KD35lrp/Downloads/DATASET/dataset/detectiondataset/xml/'

labels = os.listdir(labels_path)

# 类别
classes = ["Non_motorized_Vehicle", "Pedestrian"]  #类别名

# 图片的高度、宽度、深度
sh = sw = sd = 0

def write_xml(imgname, sw, sh, sd, filepath, labeldicts):
    '''
    imgname: 没有扩展名的图片名称
    '''

    # 创建Annotation根节点
    root = ET.Element('Annotation')

    # 创建filename子节点,无扩展名
    ET.SubElement(root, 'filename').text = str(imgname)

    # 创建size子节点
    sizes = ET.SubElement(root,'size')
    ET.SubElement(sizes, 'width').text = str(sw)
    ET.SubElement(sizes, 'height').text = str(sh)
    ET.SubElement(sizes, 'depth').text = str(sd)

    for labeldict in labeldicts:
        objects = ET.SubElement(root, 'object')
        ET.SubElement(objects, 'name').text = labeldict['name']
        ET.SubElement(objects, 'pose').text = 'Unspecified'
        ET.SubElement(objects, 'truncated').text = '0'
        ET.SubElement(objects, 'difficult').text = '0'
        bndbox = ET.SubElement(objects,'bndbox')
        ET.SubElement(bndbox, 'xmin').text = str(int(labeldict['xmin']))
        ET.SubElement(bndbox, 'ymin').text = str(int(labeldict['ymin']))
        ET.SubElement(bndbox, 'xmax').text = str(int(labeldict['xmax']))
        ET.SubElement(bndbox, 'ymax').text = str(int(labeldict['ymax']))
    tree = ET.ElementTree(root)
    tree.write(filepath, encoding='utf-8')


for label in labels:
    with open(labels_path + label, 'r') as f:
        img_id = os.path.splitext(label)[0]
        contents = f.readlines()
        labeldicts = []
        for content in contents:
            # !!!这里要看你的图片格式了,我这里是png,注意修改
            img = np.array(Image.open(img_path + label.strip('.txt') + '.jpg'))

            # 图片的高度和宽度
            sh, sw, sd = img.shape[0], img.shape[1], img.shape[2]
            content = content.strip('\n').split()
            x = float(content[1])*sw
            y = float(content[2])*sh
            w = float(content[3])*sw
            h = float(content[4])*sh

            # 坐标的转换,x_center y_center width height -> xmin ymin xmax ymax
            new_dict = {'name': classes[int(content[0])],
                        'difficult': '0',
                        'xmin': x+1-w/2,
                        'ymin': y+1-h/2,
                        'xmax': x+1+w/2,
                        'ymax': y+1+h/2
                        }
            labeldicts.append(new_dict)
        write_xml(img_id, sw, sh, sd, annotations_path + label.strip('.txt') + '.xml', labeldicts)

—xml2txt.py

import xml.etree.ElementTree as ET
import os

classes = ['Non_motorized_Vehicle', 'Pedestrian']  # 写自己的分类名
pre_dir = r'C:/Users/KD35lrp/Downloads/DATASET/dataset/detectiondataset/enhancexml'  # xml文件所在文件夹
target_dir = r'C:/Users/KD35lrp/Downloads/DATASET/dataset/detectiondataset/enhancetxt'  # 想要存储txt文件的文件夹
path = os.listdir(pre_dir)

for path1 in path:
    tree = ET.parse(os.path.join(pre_dir, path1))
    root = tree.getroot()
    oo = []
    for child in root:
        if child.tag == 'filename':
            oo.append(child.text)  # 获得xml文件的名
            # print(child.text)
        for i in child:

            if i.tag == 'width':  # 获得图片的w
                oo.append(i.text)
                # print(i.text)
            if i.tag == 'height':  # 获得图片的h
                oo.append(i.text)
                # print(i.text)
            if i.tag == 'name':  # 获得当前框的class
                oo.append(i.text)
                # print(i.text)

            for j in i:
                if j.tag == 'xmin':  # 获得当前框的两个对角线上的点的两组坐标
                    oo.append(j.text)
                    # print(j.text)
                if j.tag == 'ymin':
                    oo.append(j.text)
                    # print(j.text)
                if j.tag == 'xmax':
                    oo.append(j.text)
                    # print(j.text)
                if j.tag == 'ymax':
                    oo.append(j.text)
                    # print(j.text)
    print(oo)
    filename = oo[0]  # 读取图片的名和宽高
    filename = os.path.split(filename)
    # print(filename)
    name, extension = os.path.splitext(filename[1])  # 获取xml名和后缀
    width = oo[1]
    dw = 1 / int(width)
    height = oo[2]
    dh = 1 / int(height)
    oo.pop(0)
    oo.pop(0)
    oo.pop(0)  # 删除三次oolist的0号元素

    back = []
    # print((len(oo))%5)
    for i in range(len(oo) // 5):
        for p in range(len(classes)):  # 划定class的序号
            if classes[p] == oo[5 * i]:  # str == str
                cl = p
                back.append(cl)
        x = (int(oo[5 * i + 1]) + int(oo[5 * i + 3])) / 2  # oo里的所有元素都是str,数字也是
        y = (int(oo[5 * i + 2]) + int(oo[5 * i + 4])) / 2  # 计算标注框的中心点的xy坐标
        w = int(oo[5 * i + 3]) - int(oo[5 * i + 1])
        h = int(oo[5 * i + 4]) - int(oo[5 * i + 2])  # 计算标注框的宽高
        back.append('{:.4f}'.format(x * dw))
        back.append('{:.4f}'.format(y * dh))
        back.append('{:.4f}'.format(w * dw))
        back.append('{:.4f}'.format(h * dh))
        # back.append(y*dh)
        # back.append(w*dw)
        # back.append(h*dh)#转换到0-1区间
    print(back)
    # dir=r'C:\Users\loadlicb\Desktop'#label文件夹名
    file = open(os.path.join(target_dir, name + '.txt'), 'w')
    for i in range(len(back)):
        l = ' '
        if (i + 1) % 5 == 0:
            l = '\n'
        file.writelines(str(back[i]) + l)  # over

至此,数据集的准备工作讲解已经做完!接下来就是训练网络了。

2 YOLOv5训练行人和非机动车的目标检测网络

2.1 YOLOv5项目的下载和配置环境

YOLOv5的代码是开源的,因此我们可以从github上克隆其源码。这里使用的是yolov5-5.0下载链接为:https://github.com/ultralytics/yolov5/tree/v5.0。安装图示操作即可下载代码。注意GitHub属于国外网站,如果没开东西可能打开的很慢,看运气了。
在这里插入图片描述

2.2 文件目录简要介绍

将我们下载好的yolov5的代码解压,然后用一款IDE打开(我用的是pycharm,你也可以使用vscode等IDE打开,具体下载和配置可以搜索相关的安装教程,这里默认你已经安装好pycharm),打开之后整个代码目录如下图:

在这里插入图片描述
现在来对代码的整体目录做一个介绍:
├── data:主要是存放一些超参数的配置文件(这些文件(yaml文件)是用来配置训练集和测试集还有验证集的路径的,其中还包括目标检测的种类数和种类的名称);还有一些官方提供测试的图片。如果是训练自己的数据集的话,那么就需要修改其中的yaml文件。但是自己的数据集不建议放在这个路径下面,而是建议把数据集放到yolov5项目的同级目录下面。

├── models:里面主要是一些网络构建的配置文件和函数,其中包含了该项目的四个不同的版本,分别为是s、m、l、x。从名字就可以看出,这几个版本的大小。他们的检测测度分别都是从快到慢,但是精确度分别是从低到高。这就是所谓的鱼和熊掌不可兼得。如果训练自己的数据集的话,就需要修改这里面相对应的yaml文件来训练自己模型

├── utils:存放的是工具类的函数,里面有loss函数,metrics函数,plots函数等等。

├── weights:可以运行bash指令从网上下载预训练权重(预训练权重就是已经训练好的模型参数,可以拿来直接做目标检测,yolo官方提供的预训练权重是从coco数据集中训练出来的,包含八十个类别)。

├── detect.py:利用训练好的权重参数进行目标检测,可以进行图像、视频和摄像头的检测。

├── train.py:训练自己的数据集的函数。

├── test.py:测试训练的结果的函数。

├──requirements.txt:这是一个文本文件,里面写着使用yolov5项目的环境依赖包的一些版本,可以利用该文本导入相应版本的包。

以上就是yolov5项目代码的整体介绍。我们训练和测试自己的数据集基本就是利用到如上的代码。
如果你只是把yolov5当做工具来训练一个自己的目标检测网络,只需要修改data文件夹下的yaml和model文件夹下的yaml配置文件,以及知道train,py和detect.py中的各个参数具有什么作用以及如何修改,接下来会讲到。

2.3 项目环境配置

一个项目的代码想要运行,必须配置好相关的运行环境,这些环境能提供相关的库文件和工具,就像你去炒股,你也需要一个好的环境才能赚钱一样,程序也是如此要有一个配置好的环境才能运行,我们首先在终端运行如下指令:
pip install -r requirements.txt
如图所示:
在这里插入图片描述

2.4 数据集准备以及预训练权重下载

使用我们之前标注好的行人和非机动车数据集,数据最好放在最外一级目录中,然后数据集的目录格式如下图所示。大家一定要严格按我的格式来,否则非常容易出问题。
在这里插入图片描述
yolo训练需要将图片和标签数据集划分为训练集和验证集(还有一个测试集,但我们一般可以不用),你可以通过我提供的以下代码直接将我们以及标注好并且分好目录的数据集划分为训练集和验证集,你只需要修改最下面的parser相关地址,注释已经写的很清楚了,代码如下:

# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os
import argparse
 
 
# 检查文件夹是否存在
def mkdir(path):
    if not os.path.exists(path):
        os.makedirs(path)
 
def main(image_dir, txt_dir, save_dir):
    # 创建文件夹
    mkdir(save_dir)
    images_dir = os.path.join(save_dir, 'images')
    labels_dir = os.path.join(save_dir, 'labels')
 
    img_train_path = os.path.join(images_dir, 'train')
    img_test_path = os.path.join(images_dir, 'test')
    img_val_path = os.path.join(images_dir, 'val')
 
    label_train_path = os.path.join(labels_dir, 'train')
    label_test_path = os.path.join(labels_dir, 'test')
    label_val_path = os.path.join(labels_dir, 'val')
 
    mkdir(images_dir);
    mkdir(labels_dir);
    mkdir(img_train_path);
    mkdir(img_test_path);
    mkdir(img_val_path);
    mkdir(label_train_path);
    mkdir(label_test_path);
    mkdir(label_val_path);
 
    # 数据集划分比例,训练集75%,验证集15%,测试集15%,按需修改
    train_percent = 0.85
    val_percent = 0.15
    test_percent = 0
 
    total_txt = os.listdir(txt_dir)
    num_txt = len(total_txt)
    list_all_txt = range(num_txt)  # 范围 range(0, num)
 
    num_train = int(num_txt * train_percent)
    num_val = int(num_txt * val_percent)
    num_test = num_txt - num_train - num_val
 
    train = random.sample(list_all_txt, num_train)
    # 在全部数据集中取出train
    val_test = [i for i in list_all_txt if not i in train]
    # 再从val_test取出num_val个元素,val_test剩下的元素就是test
    val = random.sample(val_test, num_val)
 
    print("训练集数目:{}, 验证集数目:{},测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
    for i in list_all_txt:
        name = total_txt[i][:-4]
 
        srcImage = os.path.join(image_dir, name + '.jpg')
        srcLabel = os.path.join(txt_dir, name + '.txt')
 
        if i in train:
            dst_train_Image = os.path.join(img_train_path, name + '.jpg')
            dst_train_Label = os.path.join(label_train_path, name + '.txt')
            shutil.copyfile(srcImage, dst_train_Image)
            shutil.copyfile(srcLabel, dst_train_Label)
        elif i in val:
            dst_val_Image = os.path.join(img_val_path, name + '.jpg')
            dst_val_Label = os.path.join(label_val_path, name + '.txt')
            shutil.copyfile(srcImage, dst_val_Image)
            shutil.copyfile(srcLabel, dst_val_Label)
        else:
            dst_test_Image = os.path.join(img_test_path, name + '.jpg')
            dst_test_Label = os.path.join(label_test_path, name + '.txt')
            shutil.copyfile(srcImage, dst_test_Image)
            shutil.copyfile(srcLabel, dst_test_Label)
 
 
if __name__ == '__main__':
    """
    python split_datasets.py --image-dir my_datasets/color_rings/imgs --txt-dir my_datasets/color_rings/txts --save-dir my_datasets/color_rings/train_data
    """
    parser = argparse.ArgumentParser(description='split datasets to train,val,test params')
    parser.add_argument('--image-dir', type=str,default='F:/DL/Pytorch/yolov8/ultralytics-seg/data/skinning/images', help='image path dir') # 将地址改为你标注数据的图片地址
    parser.add_argument('--txt-dir', type=str,default='F:/DL/Pytorch/yolov8/ultralytics-seg/data/skinning/txt' , help='txt path dir') # 将地址改为你标注数据的txt标签地址
    parser.add_argument('--save-dir', default='F:/DL/Pytorch/yolov8/ultralytics-seg/data/skinning/split', type=str, help='save dir') # 将地址改为你想要存取分好的数据集目录地址
    args = parser.parse_args()
    image_dir = args.image_dir
    txt_dir = args.txt_dir
    save_dir = args.save_dir
 
    main(image_dir, txt_dir, save_dir)

–预训练权重–
一般为了缩短网络的训练时间,并达到更好的精度,我们一般加载预训练权重进行网络的训练而不是从头开始训练。而yolov5的5.0版本给我们提供了几个预训练权重,我们可以对应我们不同的需求选择不同的版本的预训练权重。通过如下的图可以获得权重的名字和大小信息,可以预料的到,预训练权重越大,训练出来的精度就会相对来说越高,但是其检测的速度就会越慢。
从链接:https://github.com/ultralytics/yolov5/releases找到yolov5s.pt,yolov5s.pt即可满足本次行人和非机动车检测。
在这里插入图片描述
在这里插入图片描述

3 训练自己的数据集

到这里,我们终于要开始修改项目的一些文件来支持我们特定目标的训练啦!训练目标检测模型需要修改两个yaml文件中的参数。一个是data目录下的相应的yaml文件,一个是model目录文件下的相应的yaml文件。

3.1 修改data目录下的yaml配置文件

修改data目录下的相应的yaml文件。找到目录下的voc.yaml文件,将该文件复制一份,将复制的文件重命名,最好和项目相关,这样方便后面操作。我这里修改为myproject.yaml。该项目是对行人和非机动车的识别。打开这个文件夹修改其中的参数,首先将download: bash data/scripts/get_voc.sh的那一行代码注释掉(我已经注释掉了),如果不注释这行代码训练的时候会自动下载voc数据集,我们修改的路径必须是英文地址不能用反斜杠 ‘\’ 而用 ‘/’.
–coco.yaml在这里插入图片描述
–myproject.yaml修改如下图所示,类别顺序对应好你标注时候给的顺序。
在这里插入图片描述

3.2 修改model目录下的yaml配置文件

本次训练使用的是yolov5s.pt,故修改对应的yaml配置文件。操作同上,先对yolov5s.yaml复制再创建以备份,我创建的新配置文件名为yolov5s_myproject.yaml,修改.–yolov5s.yaml只需要修改如下一个地方。
–yolov5s.yaml
在这里插入图片描述
–yolov5s_myproject.yaml
在这里插入图片描述
到这里我们就把相关的配置文件给修改好了。

3.3 训练自己的网络train.py

对于train,py文件我们只需要了解里面的参数的作用以及如何修改他即可开始我们的训练,所有参数如下:

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path')
    parser.add_argument('--cfg', type=str, default='models/yolov5s_myproject.yaml', help='model.yaml path')
    parser.add_argument('--data', type=str, default='data/myproject.yaml', help='data.yaml path')  # 数据yaml路径
    parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path')  # 超参数yaml路径
    parser.add_argument('--epochs', type=int, default=151)
    parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs')
    parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')
    parser.add_argument('--rect', action='store_true', help='rectangular training')
    parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training')
    parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
    parser.add_argument('--notest', action='store_true', help='only test final epoch')
    parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')
    parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
    parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
    parser.add_argument('--cache-images', action='store_true', help='cache images for faster training')
    parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')
    parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%%')
    parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class')
    parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer')
    parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode')
    parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')
    parser.add_argument('--workers', type=int, default=12, help='maximum number of dataloader workers')
    parser.add_argument('--project', default='runs/train', help='save to project/name')
    parser.add_argument('--entity', default=None, help='W&B entity')
    parser.add_argument('--name', default='exp', help='save to project/name')
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    parser.add_argument('--quad', action='store_true', help='quad dataloader')
    parser.add_argument('--linear-lr', action='store_true', help='linear LR')
    parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
    parser.add_argument('--upload_dataset', action='store_true', help='Upload dataset as W&B artifact table')
    parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B')
    parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch')
    parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used')
    opt = parser.parse_args()

训练自己的模型需要修改如下几个参数就可以训练了。首先将weights权重的路径填写到对应的参数里面,然后将修好好的models模型的yolov5s.yaml文件路径填写到相应的参数里面,最后将data数据的hat.yaml文件路径填写到相对于的参数里面。这几个参数就必须要修改的参数。

parser = argparse.ArgumentParser()
    parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path') #预训练权重的地址
    parser.add_argument('--cfg', type=str, default='models/yolov5s_myproject.yaml', help='model.yaml path') # 模型配置的地址
    parser.add_argument('--data', type=str, default='data/myproject.yaml', help='data.yaml path')  # 数据yaml路径

其中还有几个需要关注的参数如下代码,分别是epochs训练的轮数,batch-size单批次图片输入张数和workers工作核心数,如果训练报错显存不够,则需要修改后面两个参数,将其改小。训练过程可能会遇到很多其他错误,改正错误是一个进步的过程,能让你对代码更深入的了解,你可以通过复制错误信息去搜索以及询问ChatGPT工具帮助你!

parser.add_argument('--epochs', type=int, default=151)
parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs')
parser.add_argument('--workers', type=int, default=12, help='maximum number of dataloader workers')

至此我们可以在IDE直接运行代码也可以在当前目录终端输入python train.py来开始我们的训练。训练结果默认保存在 run/train 文件目录下。

3.4 tensorbord以及使用训练好的模型进行推理

yolov5里面有写好的tensorbord函数,可以运行命令就可以调用tensorbord,然后查看tensorbord了。首先打开pycharm的命令控制终端,输入如下命令,就会出现一个网址地址,将那行网址复制下来到浏览器打开就可以看到训练的过程了

tensorboard --logdir=runs/train

在这里插入图片描述
如果模型已经训练好了,但是我们还想用tensorbord查看此模型的训练过程,就需要输入如下的命令。就可以看到模型的训练结果了。

tensorboard --logdir=runs

推理部分
等到数据训练好了以后,就会在主目录下产生一个run文件夹,在run/train/exp/weights目录下会产生两个权重文件,一个是最后一轮的权重文件,一个是最好的权重文件,一会我们就要利用这个最好的权重文件来做推理测试。除此以外还会产生一些验证文件的图片等一些文件。
在这里插入图片描述
我们找到主目录下的detect.py文件,找到代码参数部分:

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', nargs='+', type=str, default='/private/LRP/yolov5-5/runs/train/exp14/weights/best.pt', help='model.pt path(s)')
    parser.add_argument('--source', type=str, default='/private/LRP/yolov5-5/demo.avi', help='source')  # file/folder, 0 for webcam
    parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
    parser.add_argument('--conf-thres', type=float, default=0.4, help='object confidence threshold')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--view-img', action='store_true', help='display results')
    parser.add_argument('--save-txt', action='store_true', default=True, help='save results to *.txt')
    parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
    parser.add_argument('--save-crop', action='store_false', help='save cropped prediction boxes')
    parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
    parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
    parser.add_argument('--augment', action='store_true', help='augmented inference')
    parser.add_argument('--update', action='store_true', help='update all models')
    parser.add_argument('--project', default='runs/detect', help='save results to project/name')
    parser.add_argument('--name', default='exp', help='save results to project/name')
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    opt = parser.parse_args()
    print(opt)

其中我们只需要修改weights和source参数,修改weights地址为刚刚训练好的最好的模型best.pt地址,已经修改source地址为你想要推理的文件地址,它可以是图片也可以是视频,我这里使用了视频推理。

parser.add_argument('--weights', nargs='+', type=str, default='/private/LRP/yolov5-5/runs/train/exp14/weights/best.pt', help='model.pt path(s)') # 将训练得到的最好模型地址修改
parser.add_argument('--source', type=str, default='/private/LRP/yolov5-5/demo.avi', help='source')  # file/folder, 0 for webcam

当然还有一些其他参数可以关注,conf-thres为置信度阈值,也就是超过这个阈值的框才会显示出来,而iou-thres为交并比阈值。

parser.add_argument('--conf-thres', type=float, default=0.4, help='object confidence threshold')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')

运行推理代码可以在IDE直接运行detect.py也可以在终端输入python detect.py来运行,运行结果保存在 runs/detect 目录下。
在这里插入图片描述
查看推理结果可见效果还是挺好的!
在这里插入图片描述

至此,YOLOv5项目从制作数据集到修改配置文件,修改训练代码,使用训练得到的模型进行推理整个pipline已经讲完了,希望这篇文章对你有所帮助,我将继续更新使用YOLOv8来实现图像分割的任务。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐