返回顶部
首页 > 资讯 > 后端开发 > Python >Yolov7训练自己的数据集(超详细教程)
  • 332
分享到

Yolov7训练自己的数据集(超详细教程)

python深度学习视觉检测目标检测 2023-09-02 05:09:26 332人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录 一,准备数据集 1.1 挑选照片 1.2 做标注 二,下载YoloV7 三,划分数据集 四,模型训练 4.1 创建yaml文件 4.2 修改默认参数 4.3 开始训练 五,训练模型遇到的问题 5.1 UnicodeDecodeErro

目录

一,准备数据集

1.1 挑选照片

1.2 做标注

二,下载YoloV7

三,划分数据集

四,模型训练

4.1 创建yaml文件

4.2 修改默认参数

4.3 开始训练

五,训练模型遇到的问题

5.1 UnicodeDecodeError: 'gbk' codec can't decode type 0xaf in position 525: illegal multibyte sequence

5.2  subprocess.Called processError: Command 'git tag' returned non-zero exit status 128

六,测试

七,解决标签中文显示问题


一,准备数据集

1.1 挑选照片

  公主做的是缺陷检测方向,没有好办法,只能靠人眼,公主试过用阈值分割法来挑选,但是!如果阈值分割法能准确分离缺陷,就不用用yolo了不是?特别是灰度相近,而且每张照片灰度都不同,背景与缺陷灰度对比度很接近,比如上图中的硌伤~特别是背景有噪声的时候如下图,阈值分割法就直接躺平了~                                      

       没办法,从4T的数据里挑出来,挑的公主眼睛都要瞎了~~~

1.2 做标注

  公主用的labelImg,大部分做yolo标注都用这个,也是很主流的标注工具,安装方法见公主另一篇博客。那篇博客标注方法没写全,在这里详细介绍一下:

  (1)修改默认标签。公主先只做了一种缺陷,缺陷名称为“硌伤”,因此只写了一种class。在labelImg的安装文件夹中的data/predefined_classes里面修改class:

  (2)创建images文件夹和labels文件夹,可以放在任意的文件夹下。将挑选出的照片放到images的文件夹中。

  (3)在cmd中cd到labelImg文件夹下,运行python labelImg命令打开labelImg主页面。或者直接在PyCharm的Terminal中打开也行,公主是直接用pycharm的Terminal来运行的。

      (4)在主页面上打开待标注文件,进行标注

  labelImg如上图所示。

    • 第一步先将标注类型改为YOLO,这一步非常关键!
    • 第二部修改Save Dir到之前创建的labels的文件夹
    • 第三步Open Dir,打开之前创建的images文件夹,此时会出现4框中的所有文件
    • 双击想要标注的图像,通过Create RectBox在需要标注的位置画出框,选好标注类型就可以啦~
    • 可以选中View->Auto Save Mode,这样标注完就不用手动点Save了,直接点Next Image跳到下一张即可自动保存。
    • 此时可以看到labels文件夹中多了一个与图像同名的.txt文件,即为标注文件啦!注意,标注与图片是一一对应的!

  labels的格式如下:

二,下载YoloV7

  下载地址

  下载之后的目录结构是这样的:

三,划分数据集

  由于公主是一股脑将所有图像放到一起了,由于工业生产的特殊性,临近时间产生的缺陷相似,因此需要随机将图像拆分为训练集,验证集及测试集。

  在yolov7-main主文件夹下创建data.py, 并在datasets文件夹下创建defect文件夹,目录结构如下:红框画出的文件是下面代码运行完后自动生成的。  

  公主在这篇博客的代码基础上修改了一下,同时生成了yolov7需要的目录文件,代码如下:

# 将图片和标注数据按比例切分为 训练集和测试集import shutilimport randomimport os# 原始路径image_original_path = "./mydata/images/"label_original_path = "./mydata/label/"cur_path = os.getcwd()# 训练集路径train_image_path = os.path.join(cur_path, "datasets/defect/images/train/")train_label_path = os.path.join(cur_path, "datasets/defect/labels/train/")# 验证集路径val_image_path = os.path.join(cur_path, "datasets/defect/images/val/")val_label_path = os.path.join(cur_path, "datasets/defect/labels/val/")# 测试集路径test_image_path = os.path.join(cur_path, "datasets/defect/images/test/")test_label_path = os.path.join(cur_path, "datasets/defect/labels/test/")# 训练集目录list_train = os.path.join(cur_path, "datasets/defect/train.txt")list_val = os.path.join(cur_path, "datasets/defect/val.txt")list_test = os.path.join(cur_path, "datasets/defect/test.txt")train_percent = 0.6val_percent = 0.2test_percent = 0.2def del_file(path):    for i in os.listdir(path):        file_data = path + "\\" + i        os.remove(file_data)def mkdir():    if not os.path.exists(train_image_path):        os.makedirs(train_image_path)    else:        del_file(train_image_path)    if not os.path.exists(train_label_path):        os.makedirs(train_label_path)    else:        del_file(train_label_path)    if not os.path.exists(val_image_path):        os.makedirs(val_image_path)    else:        del_file(val_image_path)    if not os.path.exists(val_label_path):        os.makedirs(val_label_path)    else:        del_file(val_label_path)    if not os.path.exists(test_image_path):        os.makedirs(test_image_path)    else:        del_file(test_image_path)    if not os.path.exists(test_label_path):        os.makedirs(test_label_path)    else:        del_file(test_label_path)def clearfile():    if os.path.exists(list_train):        os.remove(list_train)    if os.path.exists(list_val):        os.remove(list_val)    if os.path.exists(list_test):        os.remove(list_test)def main():    mkdir()    clearfile()    file_train = open(list_train, 'w')    file_val = open(list_val, 'w')    file_test = open(list_test, 'w')    total_txt = os.listdir(label_original_path)    num_txt = len(total_txt)    list_all_txt = range(num_txt)    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从list_all_txt取出num_train个元素    # 所以list_all_txt列表只剩下了这些元素    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 = image_original_path + name + '.bmp'        srcLabel = label_original_path + name + ".txt"        if i in train:            dst_train_Image = train_image_path + name + '.bmp'            dst_train_Label = train_label_path + name + '.txt'            shutil.copyfile(srcImage, dst_train_Image)            shutil.copyfile(srcLabel, dst_train_Label)            file_train.write(dst_train_Image + '\n')        elif i in val:            dst_val_Image = val_image_path + name + '.bmp'            dst_val_Label = val_label_path + name + '.txt'            shutil.copyfile(srcImage, dst_val_Image)            shutil.copyfile(srcLabel, dst_val_Label)            file_val.write(dst_val_Image + '\n')        else:            dst_test_Image = test_image_path + name + '.bmp'            dst_test_Label = test_label_path + name + '.txt'            shutil.copyfile(srcImage, dst_test_Image)            shutil.copyfile(srcLabel, dst_test_Label)            file_test.write(dst_test_Image + '\n')    file_train.close()    file_val.close()    file_test.close()if __name__ == "__main__":    main()

至此,数据集彻底准备完毕!

  CUDA的安装我是参考这篇博客

四,模型训练

4.1 创建yaml文件

   在data文件夹中创建新的yaml文件,本例中缺陷为硌痕(公主不知道硌痕怎么翻译,长得像气泡,就翻译成了bubble >_<)。把coco.yaml文件复制过来,根据自己的要求修改。

4.2 修改默认参数

  修改train.py中的默认参数,根据自己的情况修改,参数代表的意思可以参考这篇博客,讲的非常详细。

   公主只改了这三个,

    • --data:是必改的。
    • --epochs:公主的缺陷类型比较简单,好识别,因此只设了200个epochs,实际上150个左右的时候就差不多收敛了。
    • --batch-size:公主的显卡显存不太行,只设了8个。但照片数量少,只有一千张左右,因此速度也不算慢。
    • --img-size:本例训练集照片是512*512的,因此公主使用了默认的[640 640]

4.3 开始训练

  由于默认参数已经修改了,训练时直接运行命令

        即可。

      训练时:

 训练完毕会提示:

   最后一轮迭代的权重文件放在runs\train\exp6\weights\last.pt中,最好的权重文件放在runs\train\exp6\weights\bext.pt中。

五,训练模型遇到的问题

5.1 UnicodeDecodeError: 'gbk' codec can't decode type 0xaf in position 525: illegal multibyte sequence

        查了下原因是Python和win10系统,打开文件时默认的编码方式冲突导致:python默认的是gbk,而win10默认的是utf-8,所以只要改一下python打开文件时,默认的编码就行。(PS:开始公主用的官网默认的 --batch-size 32,然后GPU out of memory了,改成16,还是out of memory,最后含泪改成8.截上图的时候还没到out of memory那一步,因此--batch-size还是32)

5.2  subprocess.Called processError: Command 'git tag' returned non-zero exit status 128

  主要原因是因为request请求访问GitHub被墙,解决方案就是手动下载所需的yolov7.pt权重文件,地址为https://github.com/WongKinYiu/yolov7。下载之后放在主目录下,然后还要把train.py中的权重从yolo7.pt改为yolov7.pt,

六,测试

   在datasets\defect中新建一个文件夹testImages。运行detect.py   

 在runs\defect\exp2中打开文件查看

  哎呦,标的很准,可是,由于标签是中文,显示乱码“?????”怎么办呢?

七,解决标签中文显示问题

  为啥显示乱码呢?查了下资料,原来是OpenCV的cv2.putText()不支持中文。只能重写plots.py里的plot_one_box()函数,根据这篇博客的介绍。将plot_one_box重写如下:

def plot_one_box(x, img, color=None, label=None, line_thickness=3):    # Plots one bounding box on image img    tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1  # line/font thickness    color = color or [random.randint(0, 255) for _ in range(3)]    c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))    cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)    if label:        tf = max(tl - 1, 1)  # font thickness        t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]        font_size = t_size[1]        font = ImageFont.truetype(r"D:\YOLOV7\yolov7-main\Font\simsun.ttc", font_size, encoding="utf-8")        t_size = font.getsize(label)        c2 = c1[0] + t_size[0], c1[1] - t_size[1]        cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA)  # filled        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))        draw = ImageDraw.Draw(img)        draw.text((c1[0], c2[1]), label, (0, 0, 0), font=font)        # cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)                return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)

 为了保证多个标签时能都保存下来

  detect.py文件,plot_one_box(xyxy, im0, ....) 修改为 im0 = plot_one_box(xyxy, im0, ...)

        plots.py文件,plot_one_box(box, mosaic,...) 修改为 mosaic = plot_one_box(box, mosaic,...)

最后得到结果: 

完美!!!!!

小插曲:在修改中文标签的时候,想用matplotlib.pyplot.imshow()来打印图片,无奈老是不显示。查了很久才发现是matplotlib.get_backend是agg,而agg不支持GUI画图。但在terminal里运行print(matplotlib.get_backend())明明是QtAgg.后来又在程序里打印,仍然是agg。抓狂了很久后才发现,在plots.py中作者写了这句:

 太坑了!!!手动改成matplotlib.use('Qt5Agg'),原码是matplotlib.use('Agg')。

PS:本文与Yolov7训练自己的数据集(超详细) - 玻璃公主 - 博客园一摸一样,都是公主的博客>_<

来源地址:https://blog.csdn.net/qing2019/article/details/127054577

--结束END--

本文标题: Yolov7训练自己的数据集(超详细教程)

本文链接: https://lsjlt.com/news/389818.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作