当前位置:   article > 正文

【YOLOV5】使用YOLOV5训练自己的数据集并预测_valueerror: box has no area

valueerror: box has no area

目录

一 数据准备

二 配置文件

三 开始训练

四 预测

yolov5 github的地址:https://github.com/ultralytics/yolov5

一 数据准备

使用的labelImg标注工具,对数据进行标注。标注工具具体使用方法,可以自己去查一下。

yolov5-master/data文件下新建下列文件夹

images文件夹放置图像文件,Annotations文件夹放置标注好的xml文件,ImageSets文件夹放置生成的训练txt文件,labels放置生成的标签文件。

在yolov5-master文件夹下新建dataprocess_split.py文件并运行,代码如下:

  1. import os
  2. import random
  3. trainval_percent = 0.1
  4. train_percent = 0.9
  5. xmlfilepath = 'data/Annotations'
  6. txtsavepath = 'data/ImageSets'
  7. total_xml = os.listdir(xmlfilepath)
  8. num = len(total_xml)
  9. list = range(num)
  10. tv = int(num * trainval_percent)
  11. tr = int(tv * train_percent)
  12. trainval = random.sample(list, tv)
  13. train = random.sample(trainval, tr)
  14. ftrainval = open('data/ImageSets/trainval.txt', 'w')
  15. ftest = open('data/ImageSets/test.txt', 'w')
  16. ftrain = open('data/ImageSets/train.txt', 'w')
  17. fval = open('data/ImageSets/val.txt', 'w')
  18. for i in list:
  19. name = total_xml[i][:-4] + '\n'
  20. if i in trainval:
  21. ftrainval.write(name)
  22. if i in train:
  23. ftest.write(name)
  24. else:
  25. fval.write(name)
  26. else:
  27. ftrain.write(name)
  28. ftrainval.close()
  29. ftrain.close()
  30. fval.close()
  31. ftest.close()

在yolov5-master文件夹下新建dataprocess_voc_label.py文件并运行,代码如下:

  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. sets = ['train', 'test','val']
  7. classes = ['face']
  8. def convert(size, box):
  9. dw = 1. / size[0]
  10. dh = 1. / size[1]
  11. x = (box[0] + box[1]) / 2.0
  12. y = (box[2] + box[3]) / 2.0
  13. w = box[1] - box[0]
  14. h = box[3] - box[2]
  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(image_id):
  21. in_file = open('data/Annotations/%s.xml' % (image_id))
  22. out_file = open('data/labels/%s.txt' % (image_id), 'w')
  23. tree = ET.parse(in_file)
  24. root = tree.getroot()
  25. size = root.find('size')
  26. w = int(size.find('width').text)
  27. h = int(size.find('height').text)
  28. for obj in root.iter('object'):
  29. difficult = obj.find('difficult').text
  30. cls = obj.find('name').text
  31. if cls not in classes or int(difficult) == 1:
  32. continue
  33. cls_id = classes.index(cls)
  34. xmlbox = obj.find('bndbox')
  35. b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
  36. float(xmlbox.find('ymax').text))
  37. bb = convert((w, h), b)
  38. out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
  39. wd = getcwd()
  40. print(wd)
  41. for image_set in sets:
  42. if not os.path.exists('data/labels/'):
  43. os.makedirs('data/labels/')
  44. image_ids = open('data/ImageSets/%s.txt' % (image_set)).read().strip().split()
  45. list_file = open('data/%s.txt' % (image_set), 'w')
  46. for image_id in image_ids:
  47. list_file.write('data/images/%s.jpg\n' % (image_id))
  48. convert_annotation(image_id)
  49. list_file.close()

配置文件

1 数据集的配置

数据准备后,训练之前,修改配置文件。在data文件夹下,找到coco.yaml文件。复制一份,重命名为me.yaml(自己随意命名)。修改文件内容如下:

2 模型的配置文件

聚类得出先验框(可选)(聚类重新生成anchors运行时间较长)
最新版的yolov5,它会自动kmeans算出anchors。

dataprocess_kmeans.py代码如下:

  1. import numpy as np
  2. def iou(box, clusters):
  3. """
  4. Calculates the Intersection over Union (IoU) between a box and k clusters.
  5. :param box: tuple or array, shifted to the origin (i. e. width and height)
  6. :param clusters: numpy array of shape (k, 2) where k is the number of clusters
  7. :return: numpy array of shape (k, 0) where k is the number of clusters
  8. """
  9. x = np.minimum(clusters[:, 0], box[0])
  10. y = np.minimum(clusters[:, 1], box[1])
  11. if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:
  12. raise ValueError("Box has no area") # 如果报这个错,可以把这行改成pass即可
  13. intersection = x * y
  14. box_area = box[0] * box[1]
  15. cluster_area = clusters[:, 0] * clusters[:, 1]
  16. iou_ = intersection / (box_area + cluster_area - intersection)
  17. return iou_
  18. def avg_iou(boxes, clusters):
  19. """
  20. Calculates the average Intersection over Union (IoU) between a numpy array of boxes and k clusters.
  21. :param boxes: numpy array of shape (r, 2), where r is the number of rows
  22. :param clusters: numpy array of shape (k, 2) where k is the number of clusters
  23. :return: average IoU as a single float
  24. """
  25. return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])
  26. def translate_boxes(boxes):
  27. """
  28. Translates all the boxes to the origin.
  29. :param boxes: numpy array of shape (r, 4)
  30. :return: numpy array of shape (r, 2)
  31. """
  32. new_boxes = boxes.copy()
  33. for row in range(new_boxes.shape[0]):
  34. new_boxes[row][2] = np.abs(new_boxes[row][2] - new_boxes[row][0])
  35. new_boxes[row][3] = np.abs(new_boxes[row][3] - new_boxes[row][1])
  36. return np.delete(new_boxes, [0, 1], axis=1)
  37. def kmeans(boxes, k, dist=np.median):
  38. """
  39. Calculates k-means clustering with the Intersection over Union (IoU) metric.
  40. :param boxes: numpy array of shape (r, 2), where r is the number of rows
  41. :param k: number of clusters
  42. :param dist: distance function
  43. :return: numpy array of shape (k, 2)
  44. """
  45. rows = boxes.shape[0]
  46. distances = np.empty((rows, k))
  47. last_clusters = np.zeros((rows,))
  48. np.random.seed()
  49. # the Forgy method will fail if the whole array contains the same rows
  50. clusters = boxes[np.random.choice(rows, k, replace=False)]
  51. while True:
  52. for row in range(rows):
  53. distances[row] = 1 - iou(boxes[row], clusters)
  54. nearest_clusters = np.argmin(distances, axis=1)
  55. if (last_clusters == nearest_clusters).all():
  56. break
  57. for cluster in range(k):
  58. clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)
  59. last_clusters = nearest_clusters
  60. return clusters

聚类生成新anchors的文件dataprocess_clauculate_anchors.py代码中的路径请根据自己的路径进行修改,代码内容如下:

  1. import os
  2. import numpy as np
  3. import xml.etree.cElementTree as et
  4. from kmeans import kmeans, avg_iou
  5. FILE_ROOT = "yolov5/data/" # 根路径
  6. ANNOTATION_ROOT = "Annotations" # 数据集标签文件夹路径
  7. ANNOTATION_PATH = FILE_ROOT + ANNOTATION_ROOT
  8. ANCHORS_TXT_PATH = "yolov5/data/anchors.txt"
  9. CLUSTERS = 9
  10. CLASS_NAMES = ['face']
  11. def load_data(anno_dir, class_names):
  12. xml_names = os.listdir(anno_dir)
  13. boxes = []
  14. for xml_name in xml_names:
  15. xml_pth = os.path.join(anno_dir, xml_name)
  16. tree = et.parse(xml_pth)
  17. width = float(tree.findtext("./size/width"))
  18. height = float(tree.findtext("./size/height"))
  19. for obj in tree.findall("./object"):
  20. cls_name = obj.findtext("name")
  21. if cls_name in class_names:
  22. xmin = float(obj.findtext("bndbox/xmin")) / width
  23. ymin = float(obj.findtext("bndbox/ymin")) / height
  24. xmax = float(obj.findtext("bndbox/xmax")) / width
  25. ymax = float(obj.findtext("bndbox/ymax")) / height
  26. box = [xmax - xmin, ymax - ymin]
  27. boxes.append(box)
  28. else:
  29. continue
  30. return np.array(boxes)
  31. if __name__ == '__main__':
  32. anchors_txt = open(ANCHORS_TXT_PATH, "w")
  33. train_boxes = load_data(ANNOTATION_PATH, CLASS_NAMES)
  34. count = 1
  35. best_accuracy = 0
  36. best_anchors = []
  37. best_ratios = []
  38. for i in range(10): ##### 可以修改,不要太大,否则时间很长
  39. anchors_tmp = []
  40. clusters = kmeans(train_boxes, k=CLUSTERS)
  41. idx = clusters[:, 0].argsort()
  42. clusters = clusters[idx]
  43. # print(clusters)
  44. for j in range(CLUSTERS):
  45. anchor = [round(clusters[j][0] * 640, 2), round(clusters[j][1] * 640, 2)]
  46. anchors_tmp.append(anchor)
  47. print(f"Anchors:{anchor}")
  48. temp_accuracy = avg_iou(train_boxes, clusters) * 100
  49. print("Train_Accuracy:{:.2f}%".format(temp_accuracy))
  50. ratios = np.around(clusters[:, 0] / clusters[:, 1], decimals=2).tolist()
  51. ratios.sort()
  52. print("Ratios:{}".format(ratios))
  53. print(20 * "*" + " {} ".format(count) + 20 * "*")
  54. count += 1
  55. if temp_accuracy > best_accuracy:
  56. best_accuracy = temp_accuracy
  57. best_anchors = anchors_tmp
  58. best_ratios = ratios
  59. anchors_txt.write("Best Accuracy = " + str(round(best_accuracy, 2)) + '%' + "\r\n")
  60. anchors_txt.write("Best Anchors = " + str(best_anchors) + "\r\n")
  61. anchors_txt.write("Best Ratios = " + str(best_ratios))
  62. anchors_txt.close()

运行dataprocess_clauculate_anchors.py生成一个anchors.txt文件,内容如下:

在yolov5目录下的model文件夹下是模型的配置文件,这边提供s、m、l、x版本,逐渐增大(随着架构的增大,训练时间也是逐渐增大)

假设采用yolov5s.yaml,只用修改一个参数,把nc改成自己的类别数根据anchors.txt 中的 Best Anchors 修改,需要取整(可选)

此时需要下载yolov5的预权重文件,请自行下载。

下载后,将yolov5s.pt权重文件放到weights文件夹下即可。

3 训练文件

对train.py文件进行修改后,就可以开始训练。修改如下几处:

三 开始训练

运行train.py

训练结束后,生成的模型路径为:yolov5\runs\train\exp5\weights

四 预测

将模型best.pt复制到yolov5-master/下,并改名yolov5s.pt。

detect.py文件修改如下:

运行detect.py,结果图所存的路径为:yolov5\runs\detect

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号