这部分只是简单地说明了YOLOv3作为一个技术报告提出来的,并非论文。
在YOLO9000后,系统开始使用维度聚类生成anchor boxes对边框进行预测。网络为每个边界框预测是个坐标:(tx,ty,tw,th),如果单元格从图像的左上角偏移(cx;cy),并且之前的边框具有宽度和高度pw,ph,预测应为:
维度聚类代码如下所示:
# -*- coding: utf-8 -*-
import numpy as np
class YOLO_Kmeans:
def __init__(self, cluster_number, filename):
self.cluster_number = cluster_number
self.filename = "my_train.txt"
# 此处为标注好的训练集txt文件,格式为:jpg地址 图片坐标(4个),分类(1个)
def iou(self, boxes, clusters):
# 1 box -> k clusters
n = boxes.shape[0]
k = self.cluster_number # 共k类
box_area = boxes[:, 0] * boxes[:, 1] # 取boxes的第0个和第一个数据相乘
box_area = box_area.repeat(k) # 遍历每个元素,遍历中重复复制k次
box_area = np.reshape(box_area, (n, k))
cluster_area = clusters[:, 0] * clusters[:, 1]
cluster_area = np.tile(cluster_area, [1, n])
cluster_area = np.reshape(cluster_area, (n, k))
# 处理w宽矩阵
box_w_matrix = np.reshape(boxes[:, 0].repeat(k), (n, k))
cluster_w_matrix = np.reshape(np.tile(clusters[:, 0], (1, n)), (n, k))
min_w_matrix = np.minimum(cluster_w_matrix, box_w_matrix)
# 处理h高矩阵
box_h_matrix = np.reshape(boxes[:, 1].repeat(k), (n, k))
cluster_h_matrix = np.reshape(np.tile(clusters[:, 1], (1, n)), (n, k))
min_h_matrix = np.minimum(cluster_h_matrix, box_h_matrix)
# 计算交集区域
inter_area = np.multiply(min_w_matrix, min_h_matrix)
result = inter_area / (box_area + cluster_area - inter_area)
return result
# 平均交并比
def avg_iou(self, boxes, clusters):
accuracy = np.mean([np.max(self.iou(boxes. clusters), axis=1)])
return accuracy
# kmean聚类
def kmeans(self,boxes, k, dist=np.median):
box_number = boxes.shape[0]
distances = np.empty((box_number, k))
last_nearest = np.zeros((box_number,))
np.random.seed()
clusters = boxes[np.random.choice(box_number, k, replace=False)] #初始化 k clusters
while True:
distances = 1 - self.ious(boxes, clusters)
current_nearest = np.argmin(distances, axis=1)
if (last_nearest == current_nearest).all():
break # 不继续改变clusters
for cluster in range(k):
clusters[cluster] = dist(boxes[current_nearest == cluster], axis=0)
last_nearest = current_nearest
return clusters
def result2txt(self, data):
f = open("my_anchors.txt",'w') # 将结果写入相应文件
row = np.shape(data)[0]
for i in range(row):
if i == 0:
x_y = "%d,%d" % (data[i][0], data[i][1])
else:
x_y = "%d,%d" % (data[i][0],data[i][1])
f.write(e_y)
f.close()
def txt2boxes(self): # boxes边框数据读取
f = open(self.filename,'r')
dataSet = []
for line in f:
infos = line.split(" ")
length = len(infos)
for i in range(1, length):
width = int(infos[i].split(",")[2]) - int(infos[i].split(",")[0])
height = int(infos[i].split(",")[3]) - int(infos[i].split(",")[1])
dataSet.append([width, height])
result = np.array(dataSet)
f.close()
return result
def txt2clusters(self):
all_boxes = self.txt2boxes()
result = self.kmeans(all_boxes, k=self.cluster_number)
result = result[np.lexsort(result.T[0,None])] # .T[0,None]为转置后取第一行参数
self.result2txt(result)
print("k anchors:\n {}".format(result))
print("Accuracy:{:.2f}%".format(self.avg_iou(all_boxes, result) * 100))
if __name__ == "__main__":
cluster_number = 9 # 9个anchor
filename = "my_train.txt" # 训练txt名称
kmeans = YOLO_Kmeans(cluster_number, filename)
kmeans.txt2clusters()
训练期间使用平方误差作为损失总和。如果对于一些ground truth(正确标记的数据)坐标的值和我们的预测值相减,将其差值平方后作为损失函数的实际值,ground truth值可以通过上面的等式计算转换得到。
YOLOv3使用logistic回归在对每个物体边框进行预测时得到得分。当边框比其他所有的边框更重叠ground truth对象时,该值为1。如果之前的边框并非最佳,但确实与ground truth对象重叠了一定阈值以上,我们会忽略这个预测,按YOLO9000处理方法进行预测。和faster R-CNN不一样的是,我们只为每个正确标记的数据分配一个边界框。如果先前的边框未分配并对物体进行预测,则他不会给坐标预测或者类别预测带来影响,只会影响物体的检测。
每个框使用多标签分类来预测边界框可能包含的类。我们不适用softmax,因为我们发现它对于达到高检测性能来说并非是必要的,所以我们只用了独立的logistic分类器。在训练期间,我们使用对数损失函数(二元交叉熵损失)进行类别预测。
这个公式在我们迁移到更多复杂的开源数据集时帮助很大。在这个数据集中有许多重叠的标签(如行人)。使用softmax会强加一个假设,即每个框中只有一个类别,但通常情况并非如此。
YOLOv3预测三种不同尺度的边框。我们的系统使用类似卷积金字塔的概念在这些尺度下提取特征。从我们的基础特征提取网络引出,我们增加了一些卷积层。在这些卷积层之后,我们用一个3维的编码后的张量预测边框,物体的存在和物体的类。在我们训练coco数据集测试网络时,我们在每个尺度下预测了3个边框所以张量是NN[3*(4+1+80)],对应4个边框偏移量,1个目标置信概率,还有80个类别预测。
接下来,我们将从前两层获得的特征图做2倍上采样。我们也从网络中更浅层的位置获得特征图,并将之和我们的上采样功能合并。这个方法让我们可以从上采样后的特征图获得更有意义的语义信息,同时从更浅层得到的特征图获得更好的粒度细节信息。接着我们增加了一些卷积层来处理这个联合特征图,最终预测得到一个相似的张量,虽然大小为现在的两倍。
我们在最终的尺度多次使用同样的设计预测边框。因此我们第三个尺度的预测会受益于之前所有的计算以及从网络浅层获得的细粒度信息。
我们仍然用k-means聚类算法决定我们的初始预选框。我们选择了9个预选簇和3个尺度,最终在不同尺度上均匀地划分预选簇。在COCO数据集上,我们使用了如下预选框簇:1013,1630,3323,30,61,6245,59119,11690,156198,373*326
我们使用新网络进行特征提取。我们的新网络是基于YOLOv2,Darknet-19网络和新的残差网络的混合方法。我们的网络使用连续的33和11卷积层,现在也有一些shotcut连接以加深网络层数,他有53个卷积层,明显更大,所以称为darknet-53。
这个新网络比Darknet-19功能强大得多,而且比ResNet-101或ResNet-152更有效。以下是一些ImageNet结果:
Table 2. Comparison of backbones. Accuracy, billions of operations,
billion floating point operations per second, and FPS for
various networks.
每个网络都使用相同的设置进行训练,并以256×256的单精度测试进行测试。运行时间是在Titan X上以256×256进行测量的。因此,Darknet-53可与state-of-the-art的分类器相媲美,但浮点运算更少,速度更快。Darknet-53比ResNet-101更好,速度更快1:5倍。 Darknet-53与ResNet-152具有相似的性能,速度提高2倍。
Darknet-53也可以实现每秒最高的测量浮点运算。这意味着网络结构可以更好地利用GPU,从而使其评估效率更高,速度更快。这主要是因为ResNets的层数太多,效率不高。
仍然以完整的图像进行训练,并且并没有进行严格的负样本排除或者类似的东西。我们使用多尺度训练器,大量的数据增强,批标准化,以及所有标准化归一化的东西。我们使用darknet神经网络框架进行训练和测试。
尝试使用普通的anchor box预测机制来预测x,y,使用线性激活偏移为框宽度或高度的倍数。我们发现者这种方法降低了模型的稳定性并且效果不佳。
我们试图用线性激活函数直接预测x,y偏移而非logistic回归,这会引起mAP的几个点下降
我们尝试使用焦点损失,但是它使得mAP降低了2个点。YOLOv3对focal loss解决的问题可能已经足够强大,因为它具有单独的对象预测和条件类别预测。因此,我们不确定是否对于大多数案例来说,这其中并没有误差存在,我们完全不确定