• YOLOv5从训练到移植


    一、图像采集和标注

    • 图像采集

    覆盖所有的数据目标,不同场景(视角、光照、可能的干扰)、距离、运动、背景等,用深度和广度摄像头都行。

    若兼顾效率和准确率,可以用迁移学习思路训练,则不同场景下采集的图像数据量可以适当降低,但避免场景单一问题。

    • 图像标注

    可以看LabelImg安装与使用

    二、YOLOv5模型训练

    1、YOLOv5深度网络下载

    下载地址:YOLOv5模型

    2、安装环境依赖库

    安装命令语句 

    pip install -r requirements.txt

     或者

    按照requirements.txt文件里依赖库的顺序,分别用pip install安装对应的包

    3、准备数据集

    把图像数据集和标定数据复制到yolov5/InsectImg/RawInsect文件夹下, 创建一个YOLOLabels文件夹,主要将Pascal VOC标注模式生成的.xml文件转换为.txt格式。

    完整代码

    1. import xml.etree.ElementTree as ET
    2. import pickle
    3. import os
    4. from os import listdir, getcwd
    5. from os.path import join
    6. import random
    7. from shutil import copyfile
    8. classes = ['aedes', 'aegypti','albiceps','albopictus','americana','australasiae','bazini','cheopis','coquillett', 'culex','cuprina',
    9. 'fabricius','fuliginosa','gblattella','melanura', 'musca','pattoni','rhombifolia','sericata','sorbens','wiedemann']
    10. TRAIN_RATIO = 80
    11. def clear_hidden_files(path):
    12. dir_list = os.listdir(path)
    13. for i in dir_list:
    14. abspath = os.path.join(os.path.abspath(path), i)
    15. if os.path.isfile(abspath):
    16. if i.startswith("._"):
    17. os.remove(abspath)
    18. else:
    19. clear_hidden_files(abspath)
    20. def convert(size, box):
    21. dw = 1. / size[0]
    22. dh = 1. / size[1]
    23. x = (box[0] + box[1]) / 2.0
    24. y = (box[2] + box[3]) / 2.0
    25. w = box[1] - box[0]
    26. h = box[3] - box[2]
    27. x = x * dw
    28. w = w * dw
    29. y = y * dh
    30. h = h * dh
    31. return (x, y, w, h)
    32. def convert_annotation(image_id):
    33. in_file = open('InsectImg/RawInsect/Annotations/%s.xml' % image_id)
    34. out_file = open('InsectImg/RawInsect/YOLOLabels/%s.txt' % image_id, 'w')
    35. tree = ET.parse(in_file)
    36. root = tree.getroot()
    37. size = root.find('size')
    38. w = int(size.find('width').text)
    39. h = int(size.find('height').text)
    40. for obj in root.iter('object'):
    41. difficult = obj.find('difficult').text
    42. cls = obj.find('name').text
    43. if cls not in classes or int(difficult) == 1:
    44. continue
    45. cls_id = classes.index(cls)
    46. xmlbox = obj.find('bndbox')
    47. b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
    48. float(xmlbox.find('ymax').text))
    49. bb = convert((w, h), b)
    50. out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
    51. in_file.close()
    52. out_file.close()
    53. wd = os.getcwd()
    54. wd = os.getcwd()
    55. data_base_dir = os.path.join(wd, "InsectImg/")
    56. if not os.path.isdir(data_base_dir):
    57. os.mkdir(data_base_dir)
    58. work_sapce_dir = os.path.join(data_base_dir, "RawInsect/")
    59. if not os.path.isdir(work_sapce_dir):
    60. os.mkdir(work_sapce_dir)
    61. annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
    62. if not os.path.isdir(annotation_dir):
    63. os.mkdir(annotation_dir)
    64. clear_hidden_files(annotation_dir)
    65. image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
    66. if not os.path.isdir(image_dir):
    67. os.mkdir(image_dir)
    68. clear_hidden_files(image_dir)
    69. yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
    70. if not os.path.isdir(yolo_labels_dir):
    71. os.mkdir(yolo_labels_dir)
    72. clear_hidden_files(yolo_labels_dir)
    73. yolov5_images_dir = os.path.join(data_base_dir, "images/")
    74. if not os.path.isdir(yolov5_images_dir):
    75. os.mkdir(yolov5_images_dir)
    76. clear_hidden_files(yolov5_images_dir)
    77. yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
    78. if not os.path.isdir(yolov5_labels_dir):
    79. os.mkdir(yolov5_labels_dir)
    80. clear_hidden_files(yolov5_labels_dir)
    81. yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
    82. if not os.path.isdir(yolov5_images_train_dir):
    83. os.mkdir(yolov5_images_train_dir)
    84. clear_hidden_files(yolov5_images_train_dir)
    85. yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
    86. if not os.path.isdir(yolov5_images_test_dir):
    87. os.mkdir(yolov5_images_test_dir)
    88. clear_hidden_files(yolov5_images_test_dir)
    89. yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
    90. if not os.path.isdir(yolov5_labels_train_dir):
    91. os.mkdir(yolov5_labels_train_dir)
    92. clear_hidden_files(yolov5_labels_train_dir)
    93. yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
    94. if not os.path.isdir(yolov5_labels_test_dir):
    95. os.mkdir(yolov5_labels_test_dir)
    96. clear_hidden_files(yolov5_labels_test_dir)
    97. train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
    98. test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
    99. train_file.close()
    100. test_file.close()
    101. train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
    102. test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
    103. list_imgs = os.listdir(image_dir) # list image files
    104. prob = random.randint(1, 100)
    105. print("Probability: %d" % prob)
    106. for i in range(0, len(list_imgs)):
    107. path = os.path.join(image_dir, list_imgs[i])
    108. if os.path.isfile(path):
    109. image_path = image_dir + list_imgs[i]
    110. voc_path = list_imgs[i]
    111. (nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
    112. (voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
    113. annotation_name = nameWithoutExtention + '.xml'
    114. annotation_path = os.path.join(annotation_dir, annotation_name)
    115. label_name = nameWithoutExtention + '.txt'
    116. label_path = os.path.join(yolo_labels_dir, label_name)
    117. prob = random.randint(1, 100)
    118. print("Probability: %d" % prob)
    119. if (prob < TRAIN_RATIO): # train dataset
    120. if os.path.exists(annotation_path):
    121. train_file.write(image_path + '\n')
    122. convert_annotation(nameWithoutExtention) # convert label
    123. copyfile(image_path, yolov5_images_train_dir + voc_path)
    124. copyfile(label_path, yolov5_labels_train_dir + label_name)
    125. else: # test dataset
    126. if os.path.exists(annotation_path):
    127. test_file.write(image_path + '\n')
    128. convert_annotation(nameWithoutExtention) # convert label
    129. copyfile(image_path, yolov5_images_test_dir + voc_path)
    130. copyfile(label_path, yolov5_labels_test_dir + label_name)
    131. train_file.close()
    132. test_file.close()
    • 修改class类别标签名
    • 修改TRAIN_RATIO,划分训练数据集和验证数据集比例8:2
    • 修改文件路径

    第一处:

    1. in_file = open('InsectImg/RawInsect/Annotations/%s.xml' % image_id)
    2. out_file = open('InsectImg/RawInsect/YOLOLabels/%s.txt' % image_id, 'w')

    第二处:

    1. data_base_dir = os.path.join(wd, "InsectImg/")
    2. if not os.path.isdir(data_base_dir):
    3. os.mkdir(data_base_dir)
    4. work_sapce_dir = os.path.join(data_base_dir, "RawInsect/")

     4、配置YOLOv5数据环境

    data文件夹下,仿照coco.yaml,创建insect.yaml文件

    • 修改train训练数据集路径
    • 修改val验证数据集路径
    • 修改nc类别数
    • 修改names列表标签名

     在models文件夹下,仿照yolov5l.yaml,创建yolov5l_insect.yaml文件

    • 修改nc类别数

    weights文件夹下,存放从GitHub上下载的yolov5l6.pt

    注意:如果YOLOv5系列有n、s、m、l、x,models文件夹下创建什么类型的模型,weights文件夹下要存放相应的训练好的模型pt文件。

    5、修改train.py参数

    一般情况下,需要修改参数: 

    • 修改 --weights路径
    • 修改--cfg配置模型路径
    • 修改--data图像数据路径
    • 根据电脑GPU核,设置--batch-size
    • 根据n、s、m、l、x,设置--imgsz,YOLOv5l输入图像大小设置为640
    • 一般--resume设置为False,如果因电脑重启导致训练中断,可以设置为True,接着上一次的结果继续训练
    • epochs一般300,也可以根据训练情况调整

    其他参数可以根据情况自动设置

    6、运行train.py 进行模型训练

    训练模型结果保存在路径

    E:\Code\Python\yolov5\runs\train\exp

    该路径下的weights文件夹生成了last.pt和best.pt两个文件,选择best.pt作为移植模型。

    三、YOLOv5模型移植

    1、修改export.py文件

    • 修改--data,为自己数据的.yaml文件
    • 修改--weights,为上一步YOLOv5l训练得到best.pt最佳路径
    • 修改--imgsz,一般设置为320
    • 修改--include,根据实际案例,可以选择tflite/onnx/pb等。

    运行export.py导出量化后的模型

    2、量化后模型移植终端

    配置终端环境,调用量化后的模型。

  • 相关阅读:
    判断素数/质数的快速算法
    【技术实战】Vue功能样式实战【三】
    STM32进阶:使用STM32驱动ST7735S(内附核心源码)
    ubuntu1804系统安装Realsense SDK驱动和ROS Wrapper
    Prometheus:优秀和强大的监控报警工具
    动态生成表格完整版(内含解析)
    76.【图】
    vue相关面试题:Vuex是什么?
    顾往前行,我的前端之路系列(二)
    什么是跨域以及为什么会出现跨域以及跨域的解决方案
  • 原文地址:https://blog.csdn.net/miao0967020148/article/details/130859792