本文代码参考:
https://github.com/lars76/kmeans-anchor-boxes
Yolov3中默认的9个anchors是作者通过对voc数据聚类得到的。
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
不过,当我们训练自己的数据时,如果也采用默认的anchors,可能就不太适合了,
这里我们需要对自己的数据重新做聚类,得到适合自己数据的anchors。
本文聚类的数据是VOC2012里面的person类别数据,关于数据抽取,可以参考我上一篇博客:
https://blog.csdn.net/c2250645962/article/details/104840953
代码如下:
import glob
import xml.etree.ElementTree as ET
import numpy as np
from kmeans import kmeans, avg_iou
ANNOTATIONS_PATH = "./VOCPerson/Annotations"
CLUSTERS = 9
def load_dataset(path):
dataset = []
for xml_file in glob.glob("{}/*xml".format(path)):
# print(xml_file)
tree = ET.parse(xml_file)
height = int(tree.findtext("./size/height"))
width = int(tree.findtext("./size/width"))
for obj in tree.iter("object"):
xmin = int(float(obj.findtext("bndbox/xmin"))) / width
ymin = int(float(obj.findtext("bndbox/ymin"))) / height
xmax = int(float(obj.findtext("bndbox/xmax"))) / width
ymax = int(float(obj.findtext("bndbox/ymax"))) / height
dataset.append([xmax - xmin, ymax - ymin])
return np.array(dataset)
data = load_dataset(ANNOTATIONS_PATH)
print('data shape is {}'.format(data.shape))
out = kmeans(data, k=CLUSTERS)
yolov3clusters = [[10,13],[16,30],[33,23],[30,61],[62,45],[59,119],[116,90],[156,198],[373,326]]
yolov3out= np.array(yolov3clusters)/416.0
print("self data Accuracy: {:.2f}%".format(avg_iou(data, out) * 100))
print("yolov3 Accuracy: {:.2f}%".format(avg_iou(data, yolov3out) * 100))
# 生成resize到416对应的anchor
print("Boxes:\n {}-{}".format(out[:, 0]*416, out[:, 1]*416))
# print("Boxes:\n {}".format(out))
ratios = np.around(out[:, 0] / out[:, 1], decimals=2).tolist()
print("Ratios:\n {}".format(sorted(ratios)))
注意代码中的
yolov3clusters = [[10,13],[16,30],[33,23],[30,61],[62,45],[59,119],[116,90],[156,198],[373,326]]
yolov3out= np.array(yolov3clusters)/416.0
这两行是拿yolov3默认的9个anchors出来,为了后面跟自己聚类得到的anchors做计算avg_iou比较。
只需要改变ANNOTATIONS_PATH = "./VOCPerson/Annotations"
为自己数据的标注文件路径即可。
我这里的标注文件如下图:
运行结果如下:
data shape is (14470, 2)
self data Accuracy: 71.85%
yolov3 Accuracy: 60.80%
Boxes:
[ 24.128 12.48 92.352 213.824 107.328 42.432 143.104 342.784 58.24 ]-[ 61.01333333 29.952 270.67733333 332.8 159.744
108.71466667 289.536 382.13953488 193.63363363]
Ratios:
[0.3, 0.34, 0.39, 0.4, 0.42, 0.49, 0.64, 0.67, 0.9]
由结果可以看出,使用yolov3默认的9个anchors计算得到的平均iou是60.80%,
而自己聚类得到的9个anchors计算得到的平均iou是71.85%。
9个anchor取整分别是(24,61),(13,30),(92,271),(214,333),(107,160),(42,108),(143,290),(343,382),(58,193)
对他们排序,然后得到用于替换原来默认anchors如下:
anchors = 13,30, 24,61, 42,108, 58,193, 92,271, 107,160, 143,290, 214,333, 343,382
那么,使用自己聚类得到的anchors去训练效果应该会更好。
将聚类得到的9个anchors,按照大小排列替代yolov3的cfg文件中的9个anchors即可。