• YOLO V8训练自己的数据集并测试


    目录

    1 YOLOV8部署

    2 标注软件labelme安装

    3 将labelme转化为YOLOV8支持的数据格式

    4 开始训练

    5 利用训练结果进行测试


    1 YOLOV8部署

            我的一篇博客已经提到,这里不再赘述:

    YOLO V8语义分割模型部署-CSDN博客YOLO V8语义分割模型部署https://blog.csdn.net/qq_41694024/article/details/133983334

    2 标注软件labelme安装

            我们采用一键安装的方式:

     pip install labelme

            这个对python版本有要求,python版本最好是3.8。如果不是那就再茶ungjiange虚拟环境吧。

            直接命令行输入labelme启动,可能会出现这个问题:

    1. (yo) liuhongwei@liuhongwei-Legion-Y9000P-IRX8H:~/Desktop/ultralytics/examples/YOLOv8-CPP-Inference/build$ labelme
    2. [INFO ] __init__:get_config:70 - Loading config file from: /home/liuhongwei/.labelmerc
    3. QObject::moveToThread: Current thread (0x564cffaed340) is not the object's thread (0x564d01248510).
    4. Cannot move to target thread (0x564cffaed340)
    5. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/home/liuhongwei/anaconda3/envs/yo/lib/python3.8/site-packages/cv2/qt/plugins" even though it was found.
    6. This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
    7. Available platform plugins are: xcb, eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl.

            这是QT版本太高了.....,降低QT版本:

    pip install pyqt5==5.14.0

            再次启动labelme:

            可以用了。

            label使用就是打开一个含有图像的文件夹就可以,使用很简单,上过本科的一看界面就会,给大家展示一张标注结果:

    3 将labelme转化为YOLOV8支持的数据格式

            先装依赖:

    pip install pycocotools

            用我的脚本将labelme形式的标注文件转化为yolo格式的文件:

    1. '''
    2. Created on Oct 23, 2023
    3. @author: Liuhongwei
    4. '''
    5. import os
    6. import sys
    7. import argparse
    8. import shutil
    9. import math
    10. from collections import OrderedDict
    11. import json
    12. import cv2
    13. import PIL.Image
    14. from sklearn.model_selection import train_test_split
    15. from labelme import utils
    16. class Labelme2YOLO(object):
    17. def __init__(self, json_dir):
    18. self._json_dir = json_dir
    19. self._label_id_map = self._get_label_id_map(self._json_dir)
    20. def _make_train_val_dir(self):
    21. self._label_dir_path = os.path.join(self._json_dir,
    22. 'YOLODataset/labels/')
    23. self._image_dir_path = os.path.join(self._json_dir,
    24. 'YOLODataset/images/')
    25. for yolo_path in (os.path.join(self._label_dir_path + 'train/'),
    26. os.path.join(self._label_dir_path + 'val/'),
    27. os.path.join(self._image_dir_path + 'train/'),
    28. os.path.join(self._image_dir_path + 'val/')):
    29. if os.path.exists(yolo_path):
    30. shutil.rmtree(yolo_path)
    31. os.makedirs(yolo_path)
    32. def _get_label_id_map(self, json_dir):
    33. label_set = set()
    34. for file_name in os.listdir(json_dir):
    35. if file_name.endswith('json'):
    36. json_path = os.path.join(json_dir, file_name)
    37. data = json.load(open(json_path))
    38. for shape in data['shapes']:
    39. label_set.add(shape['label'])
    40. return OrderedDict([(label, label_id) \
    41. for label_id, label in enumerate(label_set)])
    42. def _train_test_split(self, folders, json_names, val_size):
    43. if len(folders) > 0 and 'train' in folders and 'val' in folders:
    44. train_folder = os.path.join(self._json_dir, 'train/')
    45. train_json_names = [train_sample_name + '.json' \
    46. for train_sample_name in os.listdir(train_folder) \
    47. if os.path.isdir(os.path.join(train_folder, train_sample_name))]
    48. val_folder = os.path.join(self._json_dir, 'val/')
    49. val_json_names = [val_sample_name + '.json' \
    50. for val_sample_name in os.listdir(val_folder) \
    51. if os.path.isdir(os.path.join(val_folder, val_sample_name))]
    52. return train_json_names, val_json_names
    53. train_idxs, val_idxs = train_test_split(range(len(json_names)),
    54. test_size=val_size)
    55. train_json_names = [json_names[train_idx] for train_idx in train_idxs]
    56. val_json_names = [json_names[val_idx] for val_idx in val_idxs]
    57. return train_json_names, val_json_names
    58. def convert(self, val_size):
    59. json_names = [file_name for file_name in os.listdir(self._json_dir) \
    60. if os.path.isfile(os.path.join(self._json_dir, file_name)) and \
    61. file_name.endswith('.json')]
    62. folders = [file_name for file_name in os.listdir(self._json_dir) \
    63. if os.path.isdir(os.path.join(self._json_dir, file_name))]
    64. train_json_names, val_json_names = self._train_test_split(folders, json_names, val_size)
    65. self._make_train_val_dir()
    66. # convert labelme object to yolo format object, and save them to files
    67. # also get image from labelme json file and save them under images folder
    68. for target_dir, json_names in zip(('train/', 'val/'),
    69. (train_json_names, val_json_names)):
    70. for json_name in json_names:
    71. json_path = os.path.join(self._json_dir, json_name)
    72. json_data = json.load(open(json_path))
    73. print('Converting %s for %s ...' % (json_name, target_dir.replace('/', '')))
    74. img_path = self._save_yolo_image(json_data,
    75. json_name,
    76. self._image_dir_path,
    77. target_dir)
    78. yolo_obj_list = self._get_yolo_object_list(json_data, img_path)
    79. self._save_yolo_label(json_name,
    80. self._label_dir_path,
    81. target_dir,
    82. yolo_obj_list)
    83. print('Generating dataset.yaml file ...')
    84. self._save_dataset_yaml()
    85. def convert_one(self, json_name):
    86. json_path = os.path.join(self._json_dir, json_name)
    87. json_data = json.load(open(json_path))
    88. print('Converting %s ...' % json_name)
    89. img_path = self._save_yolo_image(json_data, json_name,
    90. self._json_dir, '')
    91. yolo_obj_list = self._get_yolo_object_list(json_data, img_path)
    92. self._save_yolo_label(json_name, self._json_dir,
    93. '', yolo_obj_list)
    94. def _get_yolo_object_list(self, json_data, img_path):
    95. yolo_obj_list = []
    96. img_h, img_w, _ = cv2.imread(img_path).shape
    97. for shape in json_data['shapes']:
    98. # labelme circle shape is different from others
    99. # it only has 2 points, 1st is circle center, 2nd is drag end point
    100. if shape['shape_type'] == 'circle':
    101. yolo_obj = self._get_circle_shape_yolo_object(shape, img_h, img_w)
    102. else:
    103. yolo_obj = self._get_other_shape_yolo_object(shape, img_h, img_w)
    104. yolo_obj_list.append(yolo_obj)
    105. return yolo_obj_list
    106. def _get_circle_shape_yolo_object(self, shape, img_h, img_w):
    107. obj_center_x, obj_center_y = shape['points'][0]
    108. radius = math.sqrt((obj_center_x - shape['points'][1][0]) ** 2 +
    109. (obj_center_y - shape['points'][1][1]) ** 2)
    110. obj_w = 2 * radius
    111. obj_h = 2 * radius
    112. yolo_center_x= round(float(obj_center_x / img_w), 6)
    113. yolo_center_y = round(float(obj_center_y / img_h), 6)
    114. yolo_w = round(float(obj_w / img_w), 6)
    115. yolo_h = round(float(obj_h / img_h), 6)
    116. label_id = self._label_id_map[shape['label']]
    117. return label_id, yolo_center_x, yolo_center_y, yolo_w, yolo_h
    118. def _get_other_shape_yolo_object(self, shape, img_h, img_w):
    119. def __get_object_desc(obj_port_list):
    120. __get_dist = lambda int_list: max(int_list) - min(int_list)
    121. x_lists = [port[0] for port in obj_port_list]
    122. y_lists = [port[1] for port in obj_port_list]
    123. return min(x_lists), __get_dist(x_lists), min(y_lists), __get_dist(y_lists)
    124. obj_x_min, obj_w, obj_y_min, obj_h = __get_object_desc(shape['points'])
    125. yolo_center_x= round(float((obj_x_min + obj_w / 2.0) / img_w), 6)
    126. yolo_center_y = round(float((obj_y_min + obj_h / 2.0) / img_h), 6)
    127. yolo_w = round(float(obj_w / img_w), 6)
    128. yolo_h = round(float(obj_h / img_h), 6)
    129. label_id = self._label_id_map[shape['label']]
    130. return label_id, yolo_center_x, yolo_center_y, yolo_w, yolo_h
    131. def _save_yolo_label(self, json_name, label_dir_path, target_dir, yolo_obj_list):
    132. txt_path = os.path.join(label_dir_path,
    133. target_dir,
    134. json_name.replace('.json', '.txt'))
    135. with open(txt_path, 'w+') as f:
    136. for yolo_obj_idx, yolo_obj in enumerate(yolo_obj_list):
    137. yolo_obj_line = '%s %s %s %s %s\n' % yolo_obj \
    138. if yolo_obj_idx + 1 != len(yolo_obj_list) else \
    139. '%s %s %s %s %s' % yolo_obj
    140. f.write(yolo_obj_line)
    141. def _save_yolo_image(self, json_data, json_name, image_dir_path, target_dir):
    142. img_name = json_name.replace('.json', '.png')
    143. img_path = os.path.join(image_dir_path, target_dir,img_name)
    144. if not os.path.exists(img_path):
    145. img = utils.img_b64_to_arr(json_data['imageData'])
    146. PIL.Image.fromarray(img).save(img_path)
    147. return img_path
    148. def _save_dataset_yaml(self):
    149. yaml_path = os.path.join(self._json_dir, 'YOLODataset/', 'dataset.yaml')
    150. with open(yaml_path, 'w+') as yaml_file:
    151. yaml_file.write('train: %s\n' % \
    152. os.path.join(self._image_dir_path, 'train/'))
    153. yaml_file.write('val: %s\n\n' % \
    154. os.path.join(self._image_dir_path, 'val/'))
    155. yaml_file.write('nc: %i\n\n' % len(self._label_id_map))
    156. names_str = ''
    157. for label, _ in self._label_id_map.items():
    158. names_str += "'%s', " % label
    159. names_str = names_str.rstrip(', ')
    160. yaml_file.write('names: [%s]' % names_str)
    161. if __name__ == '__main__':
    162. parser = argparse.ArgumentParser()
    163. parser.add_argument('--json_dir',type=str,
    164. help='Please input the path of the labelme json files.')
    165. parser.add_argument('--val_size',type=float, nargs='?', default=None,
    166. help='Please input the validation dataset size, for example 0.1 ')
    167. parser.add_argument('--json_name',type=str, nargs='?', default=None,
    168. help='If you put json name, it would convert only one json file to YOLO.')
    169. args = parser.parse_args(sys.argv[1:])
    170. convertor = Labelme2YOLO(args.json_dir)
    171. if args.json_name is None:
    172. convertor.convert(val_size=args.val_size)
    173. else:
    174. convertor.convert_one(args.json_name)

            将标注文件全部放在labelmeannotation文件夹内:

            启动脚本,参数1为这个文件夹,参数2为val占数据集的比例,比如是0.1。命令如下:

     python 222.py --json_dir labelmeannotation/ --val_size 0.1

            开始转换ing:

            转化完毕:

            转化好的文件在labelmeannotation文件夹内。

            我们把这个文件拷贝到yolo的主目录下:

            新建一个文件default_copy.yaml,里面有几个部分注意修改。

    1. # Ultralytics YOLO 🚀, AGPL-3.0 license
    2. # Default training settings and hyperparameters for medium-augmentation COCO training
    3. task: detect # (str) YOLO task, i.e. detect, segment, classify, pose
    4. mode: train # (str) YOLO mode, i.e. train, val, predict, export, track, benchmark
    5. # Train settings -------------------------------------------------------------------------------------------------------
    6. model: # (str, optional) path to model file, i.e. yolov8n.pt, yolov8n.yaml
    7. data: /home/liuhongwei/Desktop/ultralytics/YOLODataset/dataset.yaml # (str, optional) path to data file, i.e. coco128.yaml
    8. epochs: 300 # (int) number of epochs to train for
    9. patience: 50 # (int) epochs to wait for no observable improvement for early stopping of training
    10. batch: -1 # (int) number of images per batch (-1 for AutoBatch)
    11. imgsz: 640 # (int | list) input images size as int for train and val modes, or list[w,h] for predict and export modes
    12. save: True # (bool) save train checkpoints and predict results
    13. save_period: -1 # (int) Save checkpoint every x epochs (disabled if < 1)
    14. cache: False # (bool) True/ram, disk or False. Use cache for data loading
    15. device: 0 # (int | str | list, optional) device to run on, i.e. cuda device=0 or device=0,1,2,3 or device=cpu
    16. workers: 16 # (int) number of worker threads for data loading (per RANK if DDP)
    17. project: # (str, optional) project name
    18. name: /home/liuhongwei/Desktop/ultralytics/666/ # (str, optional) experiment name, results saved to 'project/name' directory
    19. exist_ok: False # (bool) whether to overwrite existing experiment
    20. pretrained: True # (bool | str) whether to use a pretrained model (bool) or a model to load weights from (str)
    21. optimizer: auto # (str) optimizer to use, choices=[SGD, Adam, Adamax, AdamW, NAdam, RAdam, RMSProp, auto]
    22. verbose: True # (bool) whether to print verbose output
    23. seed: 0 # (int) random seed for reproducibility
    24. deterministic: True # (bool) whether to enable deterministic mode
    25. single_cls: False # (bool) train multi-class data as single-class
    26. rect: False # (bool) rectangular training if mode='train' or rectangular validation if mode='val'
    27. cos_lr: False # (bool) use cosine learning rate scheduler
    28. close_mosaic: 10 # (int) disable mosaic augmentation for final epochs (0 to disable)
    29. resume: False # (bool) resume training from last checkpoint
    30. amp: True # (bool) Automatic Mixed Precision (AMP) training, choices=[True, False], True runs AMP check
    31. fraction: 1.0 # (float) dataset fraction to train on (default is 1.0, all images in train set)
    32. profile: False # (bool) profile ONNX and TensorRT speeds during training for loggers
    33. freeze: None # (int | list, optional) freeze first n layers, or freeze list of layer indices during training
    34. # Segmentation
    35. overlap_mask: True # (bool) masks should overlap during training (segment train only)
    36. mask_ratio: 4 # (int) mask downsample ratio (segment train only)
    37. # Classification
    38. dropout: 0.0 # (float) use dropout regularization (classify train only)
    39. # Val/Test settings ----------------------------------------------------------------------------------------------------
    40. val: True # (bool) validate/test during training
    41. split: val # (str) dataset split to use for validation, i.e. 'val', 'test' or 'train'
    42. save_json: False # (bool) save results to JSON file
    43. save_hybrid: False # (bool) save hybrid version of labels (labels + additional predictions)
    44. conf: # (float, optional) object confidence threshold for detection (default 0.25 predict, 0.001 val)
    45. iou: 0.7 # (float) intersection over union (IoU) threshold for NMS
    46. max_det: 300 # (int) maximum number of detections per image
    47. half: False # (bool) use half precision (FP16)
    48. dnn: False # (bool) use OpenCV DNN for ONNX inference
    49. plots: True # (bool) save plots during train/val
    50. # Prediction settings --------------------------------------------------------------------------------------------------
    51. source: # (str, optional) source directory for images or videos
    52. show: False # (bool) show results if possible
    53. save_txt: False # (bool) save results as .txt file
    54. save_conf: False # (bool) save results with confidence scores
    55. save_crop: False # (bool) save cropped images with results
    56. show_labels: True # (bool) show object labels in plots
    57. show_conf: True # (bool) show object confidence scores in plots
    58. vid_stride: 1 # (int) video frame-rate stride
    59. stream_buffer: False # (bool) buffer all streaming frames (True) or return the most recent frame (False)
    60. line_width: # (int, optional) line width of the bounding boxes, auto if missing
    61. visualize: False # (bool) visualize model features
    62. augment: False # (bool) apply image augmentation to prediction sources
    63. agnostic_nms: False # (bool) class-agnostic NMS
    64. classes: # (int | list[int], optional) filter results by class, i.e. classes=0, or classes=[0,2,3]
    65. retina_masks: False # (bool) use high-resolution segmentation masks
    66. boxes: True # (bool) Show boxes in segmentation predictions
    67. # Export settings ------------------------------------------------------------------------------------------------------
    68. format: torchscript # (str) format to export to, choices at https://docs.ultralytics.com/modes/export/#export-formats
    69. keras: False # (bool) use Kera=s
    70. optimize: False # (bool) TorchScript: optimize for mobile
    71. int8: False # (bool) CoreML/TF INT8 quantization
    72. dynamic: False # (bool) ONNX/TF/TensorRT: dynamic axes
    73. simplify: False # (bool) ONNX: simplify model
    74. opset: # (int, optional) ONNX: opset version
    75. workspace: 4 # (int) TensorRT: workspace size (GB)
    76. nms: False # (bool) CoreML: add NMS
    77. # Hyperparameters ------------------------------------------------------------------------------------------------------
    78. lr0: 0.01 # (float) initial learning rate (i.e. SGD=1E-2, Adam=1E-3)
    79. lrf: 0.01 # (float) final learning rate (lr0 * lrf)
    80. momentum: 0.937 # (float) SGD momentum/Adam beta1
    81. weight_decay: 0.0005 # (float) optimizer weight decay 5e-4
    82. warmup_epochs: 3.0 # (float) warmup epochs (fractions ok)
    83. warmup_momentum: 0.8 # (float) warmup initial momentum
    84. warmup_bias_lr: 0.1 # (float) warmup initial bias lr
    85. box: 7.5 # (float) box loss gain
    86. cls: 0.5 # (float) cls loss gain (scale with pixels)
    87. dfl: 1.5 # (float) dfl loss gain
    88. pose: 12.0 # (float) pose loss gain
    89. kobj: 1.0 # (float) keypoint obj loss gain
    90. label_smoothing: 0.0 # (float) label smoothing (fraction)
    91. nbs: 64 # (int) nominal batch size
    92. hsv_h: 0.015 # (float) image HSV-Hue augmentation (fraction)
    93. hsv_s: 0.7 # (float) image HSV-Saturation augmentation (fraction)
    94. hsv_v: 0.4 # (float) image HSV-Value augmentation (fraction)
    95. degrees: 0.0 # (float) image rotation (+/- deg)
    96. translate: 0.1 # (float) image translation (+/- fraction)
    97. scale: 0.5 # (float) image scale (+/- gain)
    98. shear: 0.0 # (float) image shear (+/- deg)
    99. perspective: 0.0 # (float) image perspective (+/- fraction), range 0-0.001
    100. flipud: 0.0 # (float) image flip up-down (probability)
    101. fliplr: 0.5 # (float) image flip left-right (probability)
    102. mosaic: 1.0 # (float) image mosaic (probability)
    103. mixup: 0.0 # (float) image mixup (probability)
    104. copy_paste: 0.0 # (float) segment copy-paste (probability)
    105. # Custom config.yaml ---------------------------------------------------------------------------------------------------
    106. cfg: # (str, optional) for overriding defaults.yaml
    107. # Tracker settings ------------------------------------------------------------------------------------------------------
    108. tracker: botsort.yaml # (str) tracker type, choices=[botsort.yaml, bytetrack.yaml]

            1.data:改成我们生成文件的dataset.yaml文件路径 其他就用我的就行了

    4 开始训练

            将YOLODataset文件夹移动到ultralytics文件夹(YOLO主目录),修改/home/liuhongwei/Desktop/ultralytics/YOLODataset/datasetsyaml文件,改成绝对路径。

    1. train: /home/liuhongwei/Desktop/ultralytics/YOLODataset/images/train/
    2. val: /home/liuhongwei/Desktop/ultralytics/YOLODataset/images/val/
    3. nc: 6
    4. names: ['ZD', 'XALYS', 'ZZS', 'BH', 'SQL', 'HPYS']

           打开我们的yolo环境输入开始训练

    yolo cfg=/home/liuhongwei/Desktop/ultralytics/default_copy.yaml

            开始训练!这里训练300个epoch!GPU一定显存一定要大!!!mAP一直提高,yolo内部损失函数计算做的很好。

            训练完毕!

            得到我们的训练结果:

    5 利用训练结果进行测试

            YOLOV8为我们封装好了测试的功能包:

            直接调用我的代码即可:

    1. from ultralytics import YOLO
    2. # 预测
    3. model = YOLO("/home/liuhongwei/Desktop/ultralytics/YOLODataset/runs/detect/train2/weights/best.pt")
    4. source = "/home/liuhongwei/Desktop/ultralytics/test_images"
    5. results = model.predict(source,save=True,show_conf=True) # predict on an image
    6. print('ok')

  • 相关阅读:
    模拟电路设计(34)---脉宽调制型开关电路
    矿井水深度除总氮有什么好工艺?硝酸根离子交换柱
    JsonPath 数据快速查找和提取工具
    大数据相关积累
    C#压缩图片
    Golang context 原理分析
    目标检测算法——YOLOv5/YOLOv7改进之结合​PP-LCNet(轻量级CPU网络)
    配置elasticsearch用windows account(AD)登录
    react中jest配置,解决node_modules报错esm无法解析的问题
    HTML(23)——垂直对齐方式
  • 原文地址:https://blog.csdn.net/qq_41694024/article/details/133985854