使用自己数据集训练yolov5-6.0_yolov5-6.0训练教程-程序员宅基地

技术标签: 计算机视觉  深度学习  目标检测  

目录

1.生成数据集

 2.运行train.py脚本

3.运行val.py脚本

4. 运行detect.py脚本

最后,附杂草预测结果图


简要说明:

  • 默认yolov5-6.0已下载到本地,并相关依赖包已经安装完毕
  • yolov5-6.0代码下载地址:yolov5-6.0代码下载地址
  • 需要下载的相关依赖包在requirems.txt中,在终端输入命令:pip install -r requirements.txt,即可自动安全相关依赖包
  • python版本>=3.8,PyTorch>=1.6

1.生成数据集

概述:使用labelimg标注图片数据(pascal voc格式),如想使用离线目标检测数据增强,可参照这篇博文(模型本身就有在线数据增强),然后将pascal voc数据格式转换为coco数据格式,并划分为训练集和测试集,生成train2017.txt和val2017.txt(训练集和测试集的图片路径)

1)官网下载:labelimg官网下载

2)进入cmd命令框,输入labelimg,点击回车,就会弹出labelimg图像标注工具

3)标注图片,Open Dir选择D/data/image(改成你自己的图片所在路径),Change Save Dir选择D/data/annotations(改成所要保存的xml文件路径),因为还要将其转换为coco数据格式,因此只需要这两个文件夹

 标注完所有类别后直接点击Save,然后点击Next Image即可

4)在生成pascal voc数据集后,将数据集转为coco数据集,并生成训练集、测试集、train2017.txt和val2017.txt。 注意:

  • 该脚本还需要一个含所有类别标签的json文件
  • 为了避免出错,文件夹格式尽量于coco数据集文件格式一致

生成json文件代码和内容如下:(目标检测的类别都是从1开始,0默认表示背景图)

import json

dict_class={'weed':1,
'crop':2,
}
def json_file(dict_class):
    json_str = json.dumps(dict_class, indent=1)
    with open('./classes.json', 'w') as json_file:
        json_file.write(json_str)
json_file(dict_class)

将数据集转为coco数据集,并生成训练集、测试集、train2017.txt和val2017.txt代码如下

"""
本脚本有三个功能:
1.将voc数据集标注信息(.xml)转为yolo标注格式(.txt),包含标签和相应的box坐标
2.划分为训练集(80%)和验证集(20%)
3.生成train2017.txt和val2017.txt
"""
import os
from tqdm import tqdm
from lxml import etree
import json
import cv2


def parse_xml_to_dict(xml):
    """
    将xml文件解析成字典形式,参考tensorflow的recursive_parse_xml_to_dict
    Args:
        xml: xml tree obtained by parsing XML file contents using lxml.etree

    Returns:
        Python dictionary holding XML contents.
    """

    if len(xml) == 0:  # 遍历到底层,直接返回tag对应的信息
        return {xml.tag: xml.text}

    result = {}
    for child in xml:
        child_result = parse_xml_to_dict(child)  # 递归遍历标签信息
        if child.tag != 'object':
            result[child.tag] = child_result[child.tag]
        else:
            if child.tag not in result:  # 因为object可能有多个,所以需要放入列表里
                result[child.tag] = []
            result[child.tag].append(child_result[child.tag])

    return {xml.tag: result}


def translate_info(file_names: list,resouce_imgPath,resouce_xmlPath,save_txt_path, class_dict: dict):
    """
    将对应xml文件信息转为yolo中使用的txt文件信息
    :param file_names:
    :param save_root:
    :param class_dict:
    :param train_val:
    :return:
    """
    if os.path.exists(save_txt_path) is False:
        os.makedirs(save_txt_path)
    if os.path.exists(resouce_imgPath) is False:
        os.makedirs(resouce_imgPath)


     # 检查下图像文件是否存在
    img_path =resouce_imgPath+'/'+file_names+'jpg'
    assert os.path.exists(img_path), "file:{} not exist...".format(img_path)

    # 检查xml文件是否存在
    xml_path = resouce_xmlPath+'/'+file_names+'xml'
    assert os.path.exists(xml_path), "file:{} not exist...".format(xml_path)

    # read xml
    with open(xml_path) as fid:
        xml_str = fid.read()
    xml = etree.fromstring(xml_str)
    data = parse_xml_to_dict(xml)["annotation"]
    img_height = int(data["size"]["height"])
    img_width = int(data["size"]["width"])

    # write object info into txt
    assert "object" in data.keys(), "file: '{}' lack of object key.".format(xml_path)
    if len(data["object"]) == 0:
        # 如果xml文件中没有目标就直接忽略该样本
        print("Warning: in '{}' xml, there are no objects.".format(xml_path))

    save_txt=save_txt_path+'\\'+file_names+'txt'
    with open(save_txt, "w+") as f:
        for index, obj in enumerate(data["object"]):
            label=obj
            # 获取每个object的box信息
            xmin = float(obj["bndbox"]["xmin"])
            xmax = float(obj["bndbox"]["xmax"])
            ymin = float(obj["bndbox"]["ymin"])
            ymax = float(obj["bndbox"]["ymax"])
            class_name = obj["name"]
            class_index = class_dict[class_name] - 1  # 目标id从0开始

            # 进一步检查数据,有的标注信息中可能有w或h为0的情况,这样的数据会导致计算回归loss为nan
            if xmax <= xmin or ymax <= ymin:
                print("Warning: in '{}' xml, there are some bbox w/h <=0".format(xml_path))
                continue

            # 将box信息转换到yolo格式
            xcenter = xmin + (xmax - xmin) / 2
            ycenter = ymin + (ymax - ymin) / 2
            w = xmax - xmin
            h = ymax - ymin

            # 绝对坐标转相对坐标,保存6位小数
            xcenter = round(xcenter / img_width, 6)
            ycenter = round(ycenter / img_height, 6)
            w = round(w / img_width, 6)
            h = round(h / img_height, 6)

            info = [str(i) for i in [class_index, xcenter, ycenter, w, h]]

            if index == 0:
                f.write(" ".join(info))
            else:
                f.write("\n" + " ".join(info))


def trainval(resouce_imgPath,resouce_xmlPath,train_rate,save_imgPath,save_txtPath):
    l=len(os.listdir(resouce_imgPath))
    print("总的长度len{}".format(l))
    vl=int(l*(1-train_rate)+1)
    k=int(l/vl)
    print("总的长度val_len{}".format(vl))
    i=0
    count=0
    # read class_indict
    json_file = open(label_json_path, 'r')
    class_dict = json.load(json_file)
    for img in os.listdir(resouce_imgPath):
        xmlName=img[:-3]
        i+=1
        s = 'train2017'
        if i%int(l/vl)==0:
            count+=1
            print("valLen{}".format(count))
            s='val2017'
            # save_xml_path=save_imgPath+'/'+s
        save_txt_path=save_txtPath+'/'+s
        # 调用保存img文件和txt文件函数
        saveImgPath=save_imgPath+'/'+s+img
        im=cv2.imread(resouce_imgPath+'/'+img)
        cv2.imwrite(save_imgPath+'/'+s+'/'+img,im)
        translate_info(xmlName, resouce_imgPath,resouce_xmlPath,save_txt_path, class_dict)

def trainval_txt(save_img_path,image_path,train_or_val):
    # image_path = './yolo_data/coco128/images/train2017/'  # 修改为自己的路径
    file_path = save_img_path + train_or_val + '.txt'
    file = open(file_path, 'w')  # 修改为自己的路径
    for filename in os.listdir(image_path):
        # print(filename)
        file.write(image_path + filename)
        file.write('\n')
    file.close()


if __name__ == "__main__":
    #先将相应pascal数据集下生成labels(coco),并划分tain和val
    label_json_path = './classes.json'
    #可以换成自己想要的划分比例
    train_rate=0.8
    label = ['train2017', 'val2017']
    #改成自己原来的img路径和xml文件路径
    resouce_imgPath='./new/new_xmls'
    resouce_xmlPath= './new/new_imgs'
    #改成所要保存的img路径和xml文件路径
    save_imgPath='./yolo_data/from_0_start/images'
    save_txtPath='./yolo_data/from_0_start/labels'
    trainval(resouce_imgPath, resouce_xmlPath, train_rate, save_imgPath, save_txtPath)
    for i in range(len(label)):
        save_img_path = './yolo_data/from_0_start/'
        image_path = './yolo_data/{}/images/{}/'.format(label[i])
        trainval_txt(save_img_path, image_path, label[i])

    #将不同数据集进行划分(没有多个数据集,就不需要用该部分)
    # file_name=['250imgs','500imgs','1000imgs']
    # for k in range(len(file_name)):
    #     resouce_imgPath='./pascal_data/{}/VOCdevkit/VOC2007/JPEGImages'.format(file_name[k])
    #     resouce_xmlPath='./pascal_data/{}/VOCdevkit/VOC2007/Annotations'.format(file_name[k])
    #     save_imgPath='./yolo_data/{}/images'.format(file_name[k])
    #     save_txtPath='./yolo_data/{}/labels'.format(file_name[k])
    #     trainval(resouce_imgPath, resouce_xmlPath, train_rate, save_imgPath, save_txtPath)
    #     for i in range(len(label)):
    #         save_img_path = './yolo_data/{}/'.format(file_name[k])
    #         image_path='./yolo_data/{}/images/{}/'.format(file_name[k],label[i])
    #         trainval_txt(save_img_path, image_path, label[i])





 2.运行train.py脚本

概述:该部分主要修改两个配置文件,模型配置文件和读取数据配置文件

1)模型配置文件,位于源码的models模块下,主要 这里以yolov5s.yaml为模板,将nc对应的种类改为自己的类别总类(我实验的类别种类是两种weed和crop,因此改为2),其他地方不变,生成yolov5s_my.yaml

2)读取数据配置文件,位于data文件目录下,生成自己的读取数据集的配置文件,这里保存为my1000imgsData.yaml

 3)修改train脚本的相关参数(主要是修改为上述生成的配置文件),如下,同时下载预训练权重yolov5s.pt放到weights文件夹下(手动下载更快)。预训练权重下载地址(选择yolov5s.pt)

4)上述准备完毕,就可以运行train.py脚本了,结果存在runs/train/exp(i)中

3.运行val.py脚本

1)修改val.py的读取数据配置文件和权重文件,如下:

 2)这里还需要修改模型文件,因为yolov5使用coco数据集训练模型,其种类有80种,而我的只有2种,因此需要找到相应的模型文件进行修改。(如果疑惑为什么train.py不用修改,而val.py需要修改:主要原因是在train.py中就修改了模型的配置文件,不信你往上翻,会找到yolov5s_my.yaml。而val.py脚本内没有导入模型配置文件,因此需要在原模型上修改)

3)上述步骤完成后,就可以运行val.py脚本了。如果运行不了,就是上述步骤修改出错了,多检查一下。上述工作完成后,即可运行val.py文件,生成的结果保存在runs/val/exp(i)中

4. 运行detect.py脚本

1)将需要预测的图片放入data/images文件夹中,并修改detect.py内的权重文件,如下

 

 2)上述工作完成后,即可运行detect.py文件,生成的结果保存在runs/detect/exp(i)中

最后,附杂草预测结果图

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_46777224/article/details/125132577

智能推荐

服务器知识和维护,服务器维护知识-程序员宅基地

文章浏览阅读244次。服务器维护知识 内容精选换一换旨在推动鲲鹏计算人才的培养,面向鲲鹏计算工程师提供芯片技术基础知识、计算系统架构、操作系统、鲲鹏产品、应用移植相关内容培训,内容包含芯片介绍,欧拉操作系统介绍,鲲鹏服务器产品培训、服务器管理、配置与部署,日常维护、典型问题处理等,使学员具备产品的规划设计、安装部署、运维和故障处理等能力,了解欧拉操作系统、应用移植基本知识,具备胜任鲲鹏计算为加强对系统数据的容灾管理,云..._服务器维护工程师学习资料

MySQL死锁解决_mysql trx_rows_locked: 1774-程序员宅基地

文章浏览阅读195次。查看mysql存储引擎模式:SHOW ENGINES;查看事务提交模式:SHOW SESSION VARIABLES LIKE ‘autocommit’;SHOW GLOBAL VARIABLES LIKE ‘autocommit’;Value的值为ON,表示autocommit开启。OFF表示autocommit关闭。查看锁记录等待时间:SHOW VARIABLES LIKE ‘innodb_lock_wait_timeout’;把超时等待时间修改为5秒:SET innodb_lock__mysql trx_rows_locked: 1774

由国家土地流转政策想到的-程序员宅基地

文章浏览阅读2.6k次。最近国家出了一个土地自由流转的正常,我发现这个想法跟我在05年写了博客《构建高效率的农业构架》(http://blog.csdn.net/sunlen/archive/2005/08/28/466916.aspx)想法基本上是一样了,并且听说政府前一两年就开始在做试点了,可见政府早就知道这个问题了,不过现在政府提出来的也只不过我提出想法的初步实现而已,等农业搞到高级阶段,有3亿农民就已经绰绰有余了

通过.netCore运行vue项目的解决方案-程序员宅基地

文章浏览阅读730次。背景最近有个特殊的需求需要通过.netCore来启动vue项目,而不是通过npm run dev 来启动。这里不写dotnetCore的壳子是怎么写的,我们只需要可以利用.netCore把项目启动起来就可以。用起来就跟用vue-cli一样。(废话,我就是用vue-cli 2创建的项目)用vue-cli3的朋友们需要稍加修改。事前准备.netCore 2.1vue-cli 2.9.6..._vue.netcore-master怎么使用viewgrid.vue页面

Velocity模板引擎-收集整理-程序员宅基地

文章浏览阅读216次。前述:基于Java的网站开发,很多人都采用JSP作为前端网页制作的技术,尤其是在国。这种技术通常会存在一些问题,可以通过简单地分析网站开发过程来看看这些问题。通常网站开发采用以下两种方式:◆ 网站功能确定后,由美工设计网页的UI(界面)部分,然后由程序员在其上加入代码显示逻辑(比如循环、判断显示数据结果)。这就是通常的JSP页面制作,当然这部分可以由美工完成模板,然后由JSP工程师以它为原型创建..._velocity模板引擎

linux下nodejs安装步骤简化版-程序员宅基地

文章浏览阅读1.2k次。安装依赖nodejs下载地址 https://nodejs.org/en/本文安装版本 node-v10.16.0-linux-x64.tar.xz解压:# xz -d node-v10.16.0-linux-x64.tar.xz# tar -xvf node-v10.16.0-linux-x64.tar建立软链:# ln -s /nodejs/node-v10.16.0-l...

随便推点

Mac下Android studio 运行真机-程序员宅基地

文章浏览阅读582次。一·配置adb打开Android studio的终端窗口,输入adb。如果显示command not found..._android studio flamingo mac真机运行

opporeno5可以用鸿蒙系统,OPPO Reno5 Pro+超大杯曝光 首发旗舰IMX766-程序员宅基地

文章浏览阅读2.6k次。中关村在线消息:12月21日,OPPO官方发布了这款机型的预热海报,并且表示,OPPOReno5 Pro+将采用与索尼联合研发的旗舰传感器——IMX766,这将开启全能影像新体验。据了解,OPPO Reno5 Pro+首发的索尼IMX766为5000万像素,CMOS尺寸约为 1/1.5英寸。回想上一代Reno4 Pro,采用了索尼定制版IMX708传感器,拥有16:9定制视频画幅、120度超广角..._reno5pro可以刷别的系统吗?

C-问题-程序员宅基地

文章浏览阅读64次。2019独角兽企业重金招聘Python工程师标准>>> ..._asyncvect=getvect(0x0c)

随心篇第三期:它们始终激励着我-程序员宅基地

文章浏览阅读56次。有时候,我在想一个问题:为什么要写博客,在里面写文章、写技术,为了什么现在想一想:也许只是单纯的为了实现自己下一个目标罢了不知道什么时候又让我想起了几句话:生活来之不易,工作需要努力;花有重开时,人无再少年;一步一个脚印,踏踏实实,奋勇向前,接受挑战,和自己的团队一起进步,多做一些靠谱的事情还记得在学生时代,遇到了困难,大家都会说:加油,你一定可以工作以后呢,更多的是:You...

POSIX线程(三)-程序员宅基地

文章浏览阅读51次。并发执行下面我们将要编写一个检测两个线程是否并发执行的程序。因为我们还没有了解要有效完成这一任务所需要的线程同步的知识,所以这并不是一个高效完成在线程之间称之为池操作的程序。再一起说明,我们要利用这一事实,在一个进程内部的不同线程之间共享除了局部函数变量之外的所有变量。试验--两个线程的同步执行在这一部分,我们所创建的程序thread2.c,是对thread1.c进行了..._posix线程多线程的字符统计程序,输入字符完成后按下回车,程序能统计所输入字符串

vue js监听浏览器tab页切换-程序员宅基地

文章浏览阅读2.1k次。vue js 浏览器tab监听