当前位置:   article > 正文

yolov5训练自己的数据_out, train_out = model(im) if training else model(

out, train_out = model(im) if training else model(im, augment=augment, val=t

组件知识笔记:

yolov5组件笔记_jacke121的专栏-CSDN博客_yolov5深度可分离卷积

参考:使用YOLOv5训练自己的数据集_laovife的博客-CSDN博客_使用yolov5训练自己的数据集

最新精度:

Modelsize
(pixels)
mAPval
0.5:0.95
mAPtest
0.5:0.95
mAPval
0.5
Speed
V100 (ms)
params
(M)
FLOPS
640 (B)
YOLOv5s64036.736.755.42.07.317.0
YOLOv5m64044.544.563.12.721.451.3
YOLOv5l64048.248.266.93.847.0115.4
YOLOv5x64050.450.468.86.187.7218.8
YOLOv5s6128043.343.361.94.312.717.4
YOLOv5m6128050.550.568.78.435.952.4
YOLOv5l6128053.453.471.112.377.2117.7
YOLOv5x6128054.454.472.022.4141.8222.9

开源地址:https://github.com/ultralytics/YOLOv5

保存路径修改:

opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve)  # increment run

yolov5保存模型:

  1. if save:
  2. with open(results_file, 'r') as f: # create checkpoint
  3. ckpt = {'epoch': epoch,
  4. 'best_fitness': best_fitness,
  5. 'training_results': f.read(),
  6. 'model': ema.ema.module if hasattr(ema, 'module') else ema.ema,
  7. 'optimizer': None if final_epoch else optimizer.state_dict()}
  8. # Save last, best and delete
  9. if best_fitness == fi:
  10. best=wdir+f'_{best_fitness[0]:.4f}_{epoch}.pth'
  11. torch.save(ckpt, best)

加载模型:

类的方式加载:

  1. config_file='models/yolov5s.yaml'
  2. with open(config_file) as f:
  3. myaml = yaml.load(f, Loader=yaml.FullLoader) # model dict
  4. model = YOLOv5_s(num_cls=1, anchors=myaml['anchors'], strides=myaml['strides']).to(device)
  5. # Load model
  6. model.eval()
  7. model.load_state_dict(torch.load(weights, map_location=device)['model'].state_dict())

不需要声明类的自动加载,但是类的代码项目中需要有:

  1. def attempt_load(weights, map_location=None):
  2. # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
  3. model = Ensemble()
  4. for w in weights if isinstance(weights, list) else [weights]:
  5. attempt_download(w)
  6. # model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model
  7. model.append(torch.load(w, map_location=map_location)['model'].float().eval()) # load FP32 model
  8. if len(model) == 1:
  9. return model[-1] # return model
  10. else:
  11. print('Ensemble created with %s\n' % weights)
  12. for k in ['names', 'stride']:
  13. setattr(model, k, getattr(model[-1], k))
  14. return model # return ensemble

x:

return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t

fit计算:相当于map50*0.1+0.9*mAP@0.5:0.95

  1. def fitness(x):
  2. # Returns fitness (for use with results.txt or evolve.txt)
  3. w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95]
  4. return (x[:, :4] * w).sum(1)

关于多分类:好像有个标签单独标注是否是物体,再有one-hot分类是哪类物体

有一个文件.shapes,里面放的每个文件的宽高

数据集准备

图片大小:自己准备的图片大小不需要统一尺寸,预处理中会自动数据增强,统一尺寸进行训练。

coco数据集格式:xc yc w h,不是百分比

  1. {
  2. "segmentation": [[510.66,423.01,511.72,420.03,510.45......]],
  3. "area": 702.1057499999998,
  4. "iscrowd": 0,
  5. "image_id": 289343,
  6. "bbox": [473.07,395.93,38.65,28.67],
  7. "category_id": 18,
  8. "id": 1768
  9. },

yolov5使用的是yolo格式的标注文件,内容长这样,第一个数是标签的序号,后面四个是坐标。

坐标格式:class_index xc yc w h,都是百分比

标签处理代码:

标签长度为5的时候,

直接返回l和shape,segments 是空list []

  1. if os.path.isfile(lb_file):
  2. nf += 1 # label found
  3. with open(lb_file, 'r') as f:
  4. l = [x.split() for x in f.read().strip().splitlines()]
  5. if any([len(x) > 8 for x in l]): # is segment
  6. classes = np.array([x[0] for x in l], dtype=np.float32)
  7. segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2) for x in l] # (cls, xy1...)
  8. l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh)
  9. l = np.array(l, dtype=np.float32)
  10. if len(l):
  11. assert l.shape[1] == 5, 'labels require 5 columns each'
  12. assert (l >= 0).all(), 'negative labels'
  13. assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels'
  14. assert np.unique(l, axis=0).shape[0] == l.shape[0], 'duplicate labels'
  15. else:
  16. ne += 1 # label empty
  17. l = np.zeros((0, 5), dtype=np.float32)

x[im_file] = [l, shape, segments]

load_image:

最大边放大到640,同比例缩放

坐标框处理:

  1. if x.size > 0:
  2. # Normalized xywh to pixel xyxy format
  3. labels = x.copy()
  4. labels[:, 1] = ratio[0] * w * (x[:, 1] - x[:, 3] / 2) + pad[0] # pad width
  5. labels[:, 2] = ratio[1] * h * (x[:, 2] - x[:, 4] / 2) + pad[1] # pad height
  6. labels[:, 3] = ratio[0] * w * (x[:, 1] + x[:, 3] / 2) + pad[0]
  7. labels[:, 4] = ratio[1] * h * (x[:, 2] + x[:, 4] / 2) + pad[1]

在下面两个函数中都有处理,送入算法转xc yc w h形式。

getitem
load_mosaic

标注软件依然是labelimg,在使用前将VOC格式转换为YOLO即可

如果有之前标注好的xml文件,可以通过脚本直接转成yolo所需的txt格式: link.
不过在转换完成后记得添加labels文件,标注文件根据序号从labels里面对应标签。

到此数据集准备完毕,在data/coco128.yaml文件里,修改为自己的参数,到这一步就可以尝试train。

coco128.yaml:

  1. train: ./data/coco128/images/train2017/
  2. val: ./data/coco128/images/train2017/
  3. # number of classes
  4. nc: 80
  5. # class names
  6. ...

三.参数调整
yolov5提供了几种权重供选择,其中5l的性价比最高,适合CV爱好者日常研究;5x效果最好,如果硬件配置低,还可以选用只有27M的5s

在train.py修改你选用的权重,并前往权重文件中将nc改为和你样本库匹配的值。
根据要求修改epoch和batchsize,就可以开始初步的训练了。

ap计算:

def test(data,...)中
  1. seen = 0
  2. names = model.names if hasattr(model, 'names') else model.module.names
  3. coco91class = coco80_to_coco91_class()
  4. s = ('%20s' + '%12s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@.5', 'mAP@.5:.95')
  5. p, r, f1, mp, mr, map50, map, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0.
  6. loss = torch.zeros(3, device=device)
  7. jdict, stats, ap, ap_class = [], [], [], []
  8. for batch_i, (img, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)):
  9. img = img.to(device, non_blocking=True)
  10. img = img.half() if half else img.float() # uint8 to fp16/32
  11. img /= 255.0 # 0 - 255 to 0.0 - 1.0
  12. targets = targets.to(device)
  13. nb, _, height, width = img.shape # batch size, channels, height, width
  14. whwh = torch.Tensor([width, height, width, height]).to(device)
  15. # Disable gradients
  16. with torch.no_grad():
  17. # Run model
  18. t = torch_utils.time_synchronized()
  19. inf_out, train_out = model(img, augment=augment) # inference and training outputs
  20. t0 += torch_utils.time_synchronized() - t
  21. # Compute loss
  22. if training: # if model has loss hyperparameters
  23. loss += compute_loss([x.float() for x in train_out], targets, model)[1][:3] # GIoU, obj, cls
  24. # Run NMS
  25. t = torch_utils.time_synchronized()
  26. output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, merge=merge)
  27. t1 += torch_utils.time_synchronized() - t
  28. # Statistics per image
  29. for si, pred in enumerate(output):
  30. labels = targets[targets[:, 0] == si, 1:]
  31. nl = len(labels)
  32. tcls = labels[:, 0].tolist() if nl else [] # target class
  33. seen += 1
  34. if pred is None:
  35. if nl:
  36. stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls))
  37. continue
  38. # Append to text file
  39. if save_txt:
  40. gn = torch.tensor(shapes[si][0])[[1, 0, 1, 0]] # normalization gain whwh
  41. txt_path = str(out / Path(paths[si]).stem)
  42. pred[:, :4] = scale_coords(img[si].shape[1:], pred[:, :4], shapes[si][0], shapes[si][1]) # to original
  43. for *xyxy, conf, cls in pred:
  44. xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh
  45. with open(txt_path + '.txt', 'a') as f:
  46. f.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format
  47. # Clip boxes to image bounds
  48. clip_coords(pred, (height, width))
  49. # Append to pycocotools JSON dictionary
  50. if save_json:
  51. # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ...
  52. image_id = Path(paths[si]).stem
  53. box = pred[:, :4].clone() # xyxy
  54. scale_coords(img[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape
  55. box = xyxy2xywh(box) # xywh
  56. box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner
  57. for p, b in zip(pred.tolist(), box.tolist()):
  58. jdict.append({'image_id': int(image_id) if image_id.isnumeric() else image_id,
  59. 'category_id': coco91class[int(p[5])],
  60. 'bbox': [round(x, 3) for x in b],
  61. 'score': round(p[4], 5)})
  62. # Assign all predictions as incorrect
  63. correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device)
  64. if nl:
  65. detected = [] # target indices
  66. tcls_tensor = labels[:, 0]
  67. # target boxes
  68. tbox = xywh2xyxy(labels[:, 1:5]) * whwh
  69. # Per target class
  70. for cls in torch.unique(tcls_tensor):
  71. ti = (cls == tcls_tensor).nonzero().view(-1) # prediction indices
  72. pi = (cls == pred[:, 5]).nonzero().view(-1) # target indices
  73. # Search for detections
  74. if pi.shape[0]:
  75. # Prediction to target ious
  76. ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices
  77. # Append detections
  78. for j in (ious > iouv[0]).nonzero():
  79. d = ti[i[j]] # detected target
  80. if d not in detected:
  81. detected.append(d)
  82. correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn
  83. if len(detected) == nl: # all targets already located in image
  84. break
  85. # Append statistics (correct, conf, pcls, tcls)
  86. stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls))
  87. # Plot images
  88. if batch_i < 1:
  89. f = Path(save_dir) / ('test_batch%g_gt.jpg' % batch_i) # filename
  90. plot_images(img, targets, paths, str(f), names) # ground truth
  91. f = Path(save_dir) / ('test_batch%g_pred.jpg' % batch_i)
  92. plot_images(img, output_to_target(output, width, height), paths, str(f), names) # predictions
  93. # Compute statistics
  94. stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy
  95. if len(stats) and stats[0].any():
  96. p, r, ap, f1, ap_class = ap_per_class(*stats)
  97. p, r, ap50, ap = p[:, 0], r[:, 0], ap[:, 0], ap.mean(1) # [P, R, AP@0.5, AP@0.5:0.95]
  98. mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean()
  99. nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class
  100. else:
  101. nt = torch.zeros(1)
  102. # Print results
  103. pf = '%20s' + '%12.3g' * 6 # print format
  104. print(pf % ('all', seen, nt.sum(), mp, mr, map50, map))
  105. # Print results per class
  106. if verbose and nc > 1 and len(stats):
  107. for i, c in enumerate(ap_class):
  108. print(pf % (names[c], seen, nt[c], p[i], r[i], ap50[i], ap[i]))
  109. # Print speeds
  110. t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple
  111. if not training:
  112. print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t)
  113. # Save JSON
  114. if save_json and len(jdict):
  115. f = 'detections_val2017_%s_results.json' % \
  116. (weights.split(os.sep)[-1].replace('.pt', '') if isinstance(weights, str) else '') # filename
  117. print('\nCOCO mAP with pycocotools... saving %s...' % f)
  118. with open(f, 'w') as file:
  119. json.dump(jdict, file)
  120. try: # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb
  121. from pycocotools.coco import COCO
  122. from pycocotools.cocoeval import COCOeval
  123. imgIds = [int(Path(x).stem) for x in dataloader.dataset.img_files]
  124. cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api
  125. cocoDt = cocoGt.loadRes(f) # initialize COCO pred api
  126. cocoEval = COCOeval(cocoGt, cocoDt, 'bbox')
  127. cocoEval.params.imgIds = imgIds # image IDs to evaluate
  128. cocoEval.evaluate()
  129. cocoEval.accumulate()
  130. cocoEval.summarize()
  131. map, map50 = cocoEval.stats[:2] # update results (mAP@0.5:0.95, mAP@0.5)
  132. except Exception as e:
  133. print('ERROR: pycocotools unable to run: %s' % e)
  134. # Return results
  135. model.float() # for training
  136. maps = np.zeros(nc) + map
  137. for i, c in enumerate(ap_class):
  138. maps[c] = ap[i]
  139. return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist()), maps, t

计算 p r 

ap50就来自:compute_ap
  1. def ap_per_class(tp, conf, pred_cls, target_cls):
  2. """ Compute the average precision, given the recall and precision curves.
  3. Source: https://github.com/rafaelpadilla/Object-Detection-Metrics.
  4. # Arguments
  5. tp: True positives (nparray, nx1 or nx10).
  6. conf: Objectness value from 0-1 (nparray).
  7. pred_cls: Predicted object classes (nparray).
  8. target_cls: True object classes (nparray).
  9. # Returns
  10. The average precision as computed in py-faster-rcnn.
  11. """
  12. # Sort by objectness
  13. i = np.argsort(-conf)
  14. tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
  15. # Find unique classes
  16. unique_classes = np.unique(target_cls)
  17. # Create Precision-Recall curve and compute AP for each class
  18. pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898
  19. s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95)
  20. ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s)
  21. for ci, c in enumerate(unique_classes):
  22. i = pred_cls == c
  23. n_gt = (target_cls == c).sum() # Number of ground truth objects
  24. n_p = i.sum() # Number of predicted objects
  25. if n_p == 0 or n_gt == 0:
  26. continue
  27. else:
  28. # Accumulate FPs and TPs
  29. fpc = (1 - tp[i]).cumsum(0)
  30. tpc = tp[i].cumsum(0)
  31. # Recall
  32. recall = tpc / (n_gt + 1e-16) # recall curve
  33. r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases
  34. # Precision
  35. precision = tpc / (tpc + fpc) # precision curve
  36. p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score
  37. # AP from recall-precision curve
  38. for j in range(tp.shape[1]):
  39. ap[ci, j] = compute_ap(recall[:, j], precision[:, j])
  40. # Plot
  41. # fig, ax = plt.subplots(1, 1, figsize=(5, 5))
  42. # ax.plot(recall, precision)
  43. # ax.set_xlabel('Recall')
  44. # ax.set_ylabel('Precision')
  45. # ax.set_xlim(0, 1.01)
  46. # ax.set_ylim(0, 1.01)
  47. # fig.tight_layout()
  48. # fig.savefig('PR_curve.png', dpi=300)
  49. # Compute F1 score (harmonic mean of precision and recall)
  50. f1 = 2 * p * r / (p + r + 1e-16)
  51. return p, r, ap, f1, unique_classes.astype('int32')

常见报错:

BrokenPipeError: [Errno 32] Broken pipe

  1. File "G:/project/detect/v5/yolov5_annotations/train.py", line 890, in <module>
  2. main(opt)
  3. File "G:/project/detect/v5/yolov5_annotations/train.py", line 755, in main
  4. train(opt.hyp, opt, device)
  5. File "G:/project/detect/v5/yolov5_annotations/train.py", line 320, in train
  6. prefix=colorstr('val: '))[0]
  7. File "G:\project\detect\v5\yolov5_annotations\utils\datasets.py", line 136, in create_dataloader
  8. collate_fn=LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn)
  9. File "G:\project\detect\v5\yolov5_annotations\utils\datasets.py", line 149, in __init__
  10. self.iterator = super().__iter__()
  11. File "D:\Users\Administrator\miniconda3\lib\site-packages\torch\utils\data\dataloader.py", line 352, in __iter__
  12. return self._get_iterator()
  13. File "D:\Users\Administrator\miniconda3\lib\site-packages\torch\utils\data\dataloader.py", line 294, in _get_iterator
  14. return _MultiProcessingDataLoaderIter(self)
  15. File "D:\Users\Administrator\miniconda3\lib\site-packages\torch\utils\data\dataloader.py", line 801, in __init__
  16. w.start()
  17. File "D:\Users\Administrator\miniconda3\lib\multiprocessing\process.py", line 112, in start
  18. self._popen = self._Popen(self)
  19. File "D:\Users\Administrator\miniconda3\lib\multiprocessing\context.py", line 223, in _Popen
  20. return _default_context.get_context().Process._Popen(process_obj)
  21. File "D:\Users\Administrator\miniconda3\lib\multiprocessing\context.py", line 322, in _Popen
  22. return Popen(process_obj)
  23. File "D:\Users\Administrator\miniconda3\lib\multiprocessing\popen_spawn_win32.py", line 89, in __init__
  24. reduction.dump(process_obj, to_child)
  25. File "D:\Users\Administrator\miniconda3\lib\multiprocessing\reduction.py", line 60, in dump
  26. ForkingPickler(file, protocol).dump(obj)
  27. BrokenPipeError: [Errno 32] Broken pipe

解决方法:

workers 默认为8,改小一点,不能超过电脑cpu核数。

parser.add_argument('--workers', type=int, default=1, help='maximum number of dataloader workers')
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/308688
推荐阅读
相关标签
  

闽ICP备14008679号