当前位置:   article > 正文

YOLOv8-Detect训练CoCo数据集+自己的数据集

YOLOv8-Detect训练CoCo数据集+自己的数据集

目录

0、引言

1、环境准备

2、数据集准备

2.1、创建数据集存放的文件夹

2.2、准备用于YOLOv8-Detect训练的txt

2.2.1 将CoCo数据集Json格式转为Xml

2.2.2 将CoCo数据集Xml整合到一个大的txt文件

2.2.3 将自己标注的xml整合到一个大的txt文件

2.2.4 将生成的txt合并分成训练集和训练集

2.2.5 将大的txt分解成多个小txt,txt以图片名字命名

2.2.6 将大的txt中对应的路径的图片复制到images/train

2.2.7 验证生成的txt是否准确

3、创建配置文件

3.1、设置官方配置文件:default.yaml,可自行修改。

3.2、设置data.yaml

3.3、设置yolov8s.yaml

4、进行训练

5、验证模型

6、总结


0、引言

本文是使用YOLOv8-Detect训练自己的数据集+CoCo数据集,数据集包含COCO数据集的人猫狗数据以及自己制作的人猫狗数据集,类别为0:person、1:cat、2:dog三类,大家可根据自己的数据集类别进行调整。

1、环境准备

可以参考这篇博客:深度学习环境搭建-CSDN博客

本文环境:

  • Windows10
  • python:3.10
  • cuda:11.6
  • pytorch:1.12.0
  • torchvision:0.13.0

2、数据集准备

2.1、创建数据集存放的文件夹

  1. mydata
  2. ______images
  3. ____________train
  4. _________________001.jpg
  5. ____________val
  6. _________________002.jpg
  7. ______labels
  8. ____________train
  9. _________________001.txt
  10. ____________val
  11. _________________002.txt

本人的数据都存放在mydata文件夹中(自定义命名)

目录结构如下:images存放训练集和验证集图片,labels存放训练集和验证集txt

2.2、准备用于YOLOv8-Detect训练的txt

2.2.1 将CoCo数据集Json格式转为Xml

从官网下载CoCo数据集的json文件

  1. import argparse, json
  2. import cytoolz
  3. from lxml import etree, objectify
  4. import os, re
  5. def instance2xml_base(anno):
  6. E = objectify.ElementMaker(annotate=False)
  7. anno_tree = E.annotation(
  8. E.folder('VOC2014_instance/{}'.format(anno['category_id'])),
  9. E.filename(anno['file_name']),
  10. E.source(
  11. E.database('MS COCO 2014'),
  12. E.annotation('MS COCO 2014'),
  13. E.image('Flickr'),
  14. E.url(anno['coco_url'])
  15. ),
  16. E.size(
  17. E.width(anno['width']),
  18. E.height(anno['height']),
  19. E.depth(3)
  20. ),
  21. E.segmented(0),
  22. )
  23. return anno_tree
  24. def instance2xml_bbox(anno, bbox_type='xyxy'):
  25. """bbox_type: xyxy (xmin, ymin, xmax, ymax); xywh (xmin, ymin, width, height)"""
  26. assert bbox_type in ['xyxy', 'xywh']
  27. if bbox_type == 'xyxy':
  28. xmin, ymin, w, h = anno['bbox']
  29. xmax = xmin+w
  30. ymax = ymin+h
  31. else:
  32. xmin, ymin, xmax, ymax = anno['bbox']
  33. E = objectify.ElementMaker(annotate=False)
  34. anno_tree = E.object(
  35. E.name(anno['category_id']),
  36. E.bndbox(
  37. E.xmin(xmin),
  38. E.ymin(ymin),
  39. E.xmax(xmax),
  40. E.ymax(ymax)
  41. ),
  42. E.difficult(anno['iscrowd'])
  43. )
  44. return anno_tree
  45. def parse_instance(content, outdir):
  46. # print('11111',content)
  47. categories = {d['id']: d['name'] for d in content['categories']}
  48. # merge images and annotations: id in images vs image_id in annotations
  49. merged_info_list = list(map(cytoolz.merge, cytoolz.join('id', content['images'], 'image_id', content['annotations'])))
  50. # print('111111111111',merged_info_list)
  51. # convert category id to name
  52. for instance in merged_info_list:
  53. instance['category_id'] = categories[instance['category_id']]
  54. # group by filename to pool all bbox in same file
  55. for name, groups in cytoolz.groupby('file_name', merged_info_list).items():
  56. anno_tree = instance2xml_base(groups[0])
  57. # if one file have multiple different objects, save it in each category sub-directory
  58. filenames = []
  59. # print(groups)
  60. for group in groups:
  61. filenames.append(os.path.join(outdir, re.sub(" ", "_", group['category_id']), os.path.splitext(name)[0] + ".xml"))
  62. anno_tree.append(instance2xml_bbox(group, bbox_type='xyxy'))
  63. for filename in filenames:
  64. etree.ElementTree(anno_tree).write(filename, pretty_print=True)
  65. print("Formating instance xml file {} done!".format(name))
  66. def main(args):
  67. if not os.path.exists(args.output_dir):
  68. os.makedirs(args.output_dir)
  69. content = json.load(open(args.anno_file, 'r'))
  70. if args.type == 'instance':
  71. # make subdirectories
  72. sub_dirs = [re.sub(" ", "_", cate['name']) for cate in content['categories']]
  73. for sub_dir in sub_dirs:
  74. sub_dir = os.path.join(args.output_dir, str(sub_dir))
  75. if not os.path.exists(sub_dir):
  76. os.makedirs(sub_dir)
  77. parse_instance(content, args.output_dir)
  78. if __name__ == "__main__":
  79. parser = argparse.ArgumentParser()
  80. parser.add_argument("--anno_file", help="annotation file for object instance/keypoint", default=r'D:\CoCoData\annotations_14_17\instances_train2017.json')
  81. parser.add_argument("--type", type=str, default='instance', help="object instance or keypoint", choices=['instance', 'keypoint'])
  82. parser.add_argument("--output_dir", help="output directory for voc annotation xml file", default=r'D:\CoCoData\CoCoXml')
  83. args = parser.parse_args()
  84. main(args)

修改文件存放的路径和保存xml文件的路径。

运行后得到80个文件夹,分别为80类的xml文件:

再将需要类别的xml文件整合,得到训练集和验证集xml

2.2.2 将CoCo数据集Xml整合到一个大的txt文件
  1. import os
  2. import random
  3. import xml.etree.ElementTree as ET
  4. import glob
  5. classes = ['person', 'cat', 'dog']
  6. def convert(size, box):
  7. # print('size--',size)
  8. dw = 1. / size[0]
  9. dh = 1. / size[1]
  10. x = (box[0] + box[2]) / 2.0
  11. y = (box[1] + box[3]) / 2.0
  12. w = min(size[0],box[2] - box[0])
  13. h = min(size[1],box[3] - box[1])
  14. # print(x,y,w,h)
  15. x = x * dw
  16. w = w * dw
  17. y = y * dh
  18. h = h * dh
  19. return (x, y, w, h)
  20. def convert_annotation(xml, list_file):
  21. in_file = open(os.path.join(xml), encoding='utf-8')
  22. tree = ET.parse(in_file)
  23. root = tree.getroot()
  24. xmlsize = root.find('size')
  25. w = int(xmlsize.find('width').text)
  26. h = int(xmlsize.find('height').text)
  27. # print(w,h)
  28. for obj in root.iter('object'):
  29. difficult = 0
  30. if obj.find('difficult') != None:
  31. difficult = obj.find('difficult').text
  32. cls = obj.find('name').text
  33. if cls not in classes or int(difficult) == 1:
  34. # print(cls, "------------------------------------\n")
  35. continue
  36. cls_id = classes.index(cls)
  37. # print(cls, cls_id)
  38. xmlbox = obj.find('bndbox')
  39. x0 = float(xmlbox.find('xmin').text)
  40. y0 = float(xmlbox.find('ymin').text)
  41. x1 = float(xmlbox.find('xmax').text)
  42. y1 = float(xmlbox.find('ymax').text)
  43. xmin = min(x0, x1)
  44. ymin = min(y0, y1)
  45. xmax = max(x0, x1)
  46. ymax = max(y0, y1)
  47. # b = (int(xmin), int(ymin), int(xmax), int(ymax))
  48. b = (float(xmin), float(ymin), float(xmax), float(ymax))
  49. # print((w, h))
  50. # if w==0 or h == 0 :
  51. # print('11111111111')
  52. bb = convert((w, h), b)
  53. # print(bb)
  54. list_file.write(" "+str(cls_id) +"," + ",".join([str(a) for a in bb]))
  55. if __name__ == "__main__":
  56. random.seed(0)
  57. # 图片路径
  58. cocoImgPath = r'I:\allShare\CoCoData\train2017'
  59. # Xml路径
  60. cocoXmlPath = r'G:\CoCopcd_xml\cocotrain_pcd'
  61. #txt保存路径
  62. txtsavepath = r'G:\Yolov8\ultralytics-main\datasets\mydata\coco_v8txt'
  63. fileWriteTxt = txtsavepath + '\\'+ cocoImgPath.split('\\')[-1] + '_v8.txt'
  64. xmls = glob.glob(os.path.join(cocoXmlPath, '*.xml'))
  65. list_file = open(fileWriteTxt, 'w', encoding='utf-8')
  66. for xml in xmls:
  67. img = xml.replace(cocoXmlPath, cocoImgPath).replace('.xml', '.jpg')
  68. if not os.path.exists(img):
  69. print(img, ' is not exit')
  70. continue
  71. # print(img)
  72. list_file.write(img)
  73. convert_annotation(xml, list_file)
  74. list_file.write('\n')
  75. list_file.close()

分别运行train2017和val2017后得到:

2.2.3 将自己标注的xml整合到一个大的txt文件

批量处理多个文件夹:

  1. import os
  2. import random
  3. import xml.etree.ElementTree as ET
  4. import glob
  5. classes = ['person', 'cat', 'dog']
  6. def convert(size, box):
  7. # print('size--',size)
  8. dw = 1. / size[0]
  9. dh = 1. / size[1]
  10. x = (box[0] + box[2]) / 2.0
  11. y = (box[1] + box[3]) / 2.0
  12. w = min(size[0],box[2] - box[0])
  13. h = min(size[1],box[3] - box[1])
  14. # print(x,y,w,h)
  15. x = x * dw
  16. w = w * dw
  17. y = y * dh
  18. h = h * dh
  19. return (x, y, w, h)
  20. def convert_annotation(xml, list_file):
  21. in_file = open(os.path.join(xml), encoding='utf-8')
  22. tree = ET.parse(in_file)
  23. root = tree.getroot()
  24. xmlsize = root.find('size')
  25. w = int(xmlsize.find('width').text)
  26. h = int(xmlsize.find('height').text)
  27. # print(w,h)
  28. for obj in root.iter('object'):
  29. difficult = 0
  30. if obj.find('difficult') != None:
  31. difficult = obj.find('difficult').text
  32. cls = obj.find('name').text
  33. if cls not in classes or int(difficult) == 1:
  34. # print(cls, "------------------------------------\n")
  35. continue
  36. cls_id = classes.index(cls)
  37. # print(cls, cls_id)
  38. xmlbox = obj.find('bndbox')
  39. x0 = float(xmlbox.find('xmin').text)
  40. y0 = float(xmlbox.find('ymin').text)
  41. x1 = float(xmlbox.find('xmax').text)
  42. y1 = float(xmlbox.find('ymax').text)
  43. xmin = min(x0, x1)
  44. ymin = min(y0, y1)
  45. xmax = max(x0, x1)
  46. ymax = max(y0, y1)
  47. # b = (int(xmin), int(ymin), int(xmax), int(ymax))
  48. b = (float(xmin), float(ymin), float(xmax), float(ymax))
  49. # print((w, h))
  50. # if w==0 or h == 0 :
  51. # print('11111111111')
  52. bb = convert((w, h), b)
  53. # print(bb)
  54. list_file.write(" "+str(cls_id) +"," + ",".join([str(a) for a in bb]))
  55. if __name__ == "__main__":
  56. random.seed(0)
  57. pathdir = r'G:\dataset\selfXml'
  58. for path, dddddd, file_name in os.walk(pathdir):
  59. print(path)
  60. # 图片路径
  61. cocoImgPath = path
  62. # Xml路径
  63. cocoXmlPath = path
  64. #txt保存路径
  65. txtsavepath = r'G:\ultralytics-main\datasets\mydata\self_v8txt'
  66. fileWriteTxt = txtsavepath + '\\'+ cocoImgPath.split('\\')[-1] + '_v8.txt'
  67. xmls = glob.glob(os.path.join(cocoXmlPath, '*.xml'))
  68. list_file = open(fileWriteTxt, 'w', encoding='utf-8')
  69. for xml in xmls:
  70. img = xml.replace(cocoXmlPath, cocoImgPath).replace('.xml', '.jpg')
  71. if not os.path.exists(img):
  72. print(img, ' is not exit')
  73. continue
  74. # print(img)
  75. list_file.write(img)
  76. convert_annotation(xml, list_file)
  77. list_file.write('\n')
  78. list_file.close()

此代码运行后会得到一个空的txt,删除即可

运行以上代码可得到txt,内容如下:图片路径,classID,xmin,ymin,xmax,ymax  (归一化)

2.2.4 将生成的txt合并分成训练集和训练集

将以上步骤得到的txt放在同一文件夹下

运行以下代码合并分割训练集和验证集,自行调整 ratio

  1. import random
  2. import os
  3. import glob
  4. # 转化数据
  5. record_jpg_fold_root = r'G:\Yolov8\ultralytics-main\datasets\mydata\self_v8txt'
  6. ratio = 0.05
  7. # ratio = 1
  8. record_jpg_files = os.listdir(record_jpg_fold_root)
  9. record_jpg_files = glob.glob(os.path.join(record_jpg_fold_root, '*.txt'))
  10. train_files = []
  11. valid_files = []
  12. datas = []
  13. for record_file in record_jpg_files:
  14. record_file_path = os.path.join(record_jpg_fold_root, record_file)
  15. f = open(record_file_path, 'r')
  16. datas_temp = f.readlines()
  17. total_num = len(datas_temp)
  18. valid_datas_num = int(total_num * ratio)
  19. valid_datas = random.sample(datas_temp, valid_datas_num)
  20. datas += datas_temp # all datas
  21. valid_files += valid_datas # valid datas
  22. # print(datas)
  23. # datas = datas.split('\n')
  24. # print(datas)
  25. random.shuffle(datas)
  26. # print(files)
  27. # total_num = len(datas)
  28. # valid_datas_num = int(total_num * 0.1)
  29. # valid_datas = random.sample(datas, valid_datas_num)
  30. traintxtdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\merge_v8txt\merge_CoCo_pcdtrain_01.txt'
  31. valtxtdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\merge_v8txt\merge_CoCo_pcdval_01.txt'
  32. with open(traintxtdir, 'w') as ft, \
  33. open(valtxtdir, 'w') as fv:
  34. for file in datas:
  35. if file in valid_files:
  36. fv.write(file)
  37. else:
  38. ft.write(file)

2.2.5 将大的txt分解成多个小txt,txt以图片名字命名

注意检查保存路径

  1. import glob
  2. import os
  3. txtpathdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\merge_v8txt\merge_CoCo_pcdtrain_01.txt'
  4. #保存txt路径
  5. savetxtpath = r'G:\Yolov8\ultralytics-main\datasets\mydata\labels\train'
  6. file = open(txtpathdir,'r',encoding='utf-8')
  7. lines = file.readlines()
  8. for line in lines:
  9. line = line.split('\n')[0]
  10. # print(line)
  11. imgdir = line.split(' ')[0]
  12. bboxinfo = line.split(' ')[1:]
  13. # print('imgdir',imgdir)
  14. savetxtdir = os.path.join(savetxtpath,imgdir.split('\\')[-1].replace('.jpg','.txt'))
  15. file = open(savetxtdir, 'w', encoding='utf-8')
  16. # print(savetxtdir)
  17. for i in range(len(bboxinfo)):
  18. # print(bboxinfo[i])
  19. info = bboxinfo[i].split(',')
  20. # print(info)
  21. info1 = ' '.join(info)
  22. print(info1)
  23. file.write(info1+'\n')

运行后得到多个训练和验证txt:

txt的内容要与官方格式一致:

分别代表:类别、框的中心点xy坐标以及框的宽高(进行了归一化处理)

2.2.6 将大的txt中对应的路径的图片复制到images/train
  1. import glob
  2. import os
  3. import shutil
  4. txtpathdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\merge_v8txt\merge_CoCo_pcdtrain_01.txt'
  5. saveimgpath = r'G:\Yolov8\ultralytics-main\datasets\mydata\images\train'
  6. file = open(txtpathdir,'r',encoding='utf-8')
  7. lines = file.readlines()
  8. for line in lines:
  9. line = line.split('\n')[0]
  10. imgdir = line.split(' ')[0]
  11. # print('imgdir',imgdir)
  12. saveimgdir = os.path.join(saveimgpath,imgdir.split('\\')[-1])
  13. # print(saveimgdir)
  14. shutil.copy(imgdir,saveimgdir)
  15. print('end.....')

2.2.7 验证生成的txt是否准确
  1. import os
  2. import glob
  3. import cv2
  4. imgdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\images\val'
  5. txtdir = r'G:\Yolov8\ultralytics-main\datasets\mydata\labels\val'
  6. list1 = glob.glob(os.path.join(imgdir,'*.jpg'))
  7. list2 = glob.glob(os.path.join(txtdir,'*.txt'))
  8. idx = 0
  9. # print(len(list1))
  10. # print(len(list2))
  11. while (idx < len(list1)):
  12. imgpath = list1[idx]
  13. txtpath = list2[idx]
  14. print(imgpath)
  15. print(txtpath)
  16. f = open(txtpath,'r')
  17. lines = f.readlines()
  18. img = cv2.imread(imgpath)
  19. h, w, c = img.shape
  20. colors = [[0, 0, 255],[0, 255, 0], [0, 255, 255]]
  21. # print(lines)
  22. for line in lines:
  23. # print(line)
  24. l = line.split(' ')
  25. # print(len(l))
  26. label = l[0]
  27. cx = float(l[1]) * w
  28. cy = float(l[2]) * h
  29. weight = float(l[3]) * w
  30. height = float(l[4]) * h
  31. xmin = cx - weight/2
  32. ymin = cy - height/2
  33. xmax = cx + weight/2
  34. ymax = cy + height/2
  35. print(label,(xmin,ymin),(xmax,ymax))
  36. color = colors[int(label)]
  37. cv2.putText(img,label,(int(xmin),int(ymin)),cv2.FONT_HERSHEY_SIMPLEX,0.8,color,1,cv2.LINE_AA)
  38. cv2.rectangle(img,(int(xmin),int(ymin)),(int(xmax),int(ymax)),color,2)
  39. kpts = []
  40. img = cv2.resize(img, None, fx=1, fy=1)
  41. cv2.imshow('1',img)
  42. key = cv2.waitKey(0)
  43. if key == ord('q'):
  44. break
  45. if key == ord('z'):
  46. idx -=1
  47. else:
  48. idx += 1

将txt信息可视化:

完成以上步骤即将训练和验证的数据集准备完成。

3、创建配置文件

3.1、设置官方配置文件:default.yaml,可自行修改。

所有参数参见:Configuration - Ultralytics YOLOv8 Docs

3.2、设置data.yaml

根据自己的数据集位置进行修改和配置。

  1. path: D:\Yolov8\ultralytics-main\datasets\mydata # dataset root dir
  2. train: images/train # train images (relative to 'path') 118287 images
  3. val: images/val # val images (relative to 'path') 5000 images
  4. #test: test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
  5. # Classes
  6. names:
  7. 0: person
  8. 1: cat
  9. 2: dog
  10. nc: 3

3.3、设置yolov8s.yaml

根据自己想使用的权重进行选择,我这里采用的是yolov8s.pt进行训练,类别为3。

  1. # Ultralytics YOLO
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/85048
    推荐阅读
    相关标签