1、输入图像
2、将图像送入卷积神经网络中进行特征提取---得到特征图
(特征图的提取,这里用的是darknet53网络,就是来得到特征图)
3、对特征图进行操作,输出想要的形状
(后面就是对特征图简单操作一下,将形状变成(13*13*255、26*26*255、52*52*255))
这里采用了多个尺度,所以得到了3个特征图,其实和yolov1的1个特征图的目的一样。
这个13*13*255本身没有意义,是作者赋予它意义,引导网络,按着作者的意思来进行。
这个13*13就是作者将图片划分成13*13的区域,共有169个网格,每个网格产生3个框,这3个框预测不同的类别,coco数据集是80类,每个框有(c,x,y,w,h)五个参数,所以每个网格有(80+5)* 3 = 255 个参数,所以通道数就是255。
4、将标签变换成一致的形状,进行损失的计算
(自定义的损失函数一般也继承于pytorch的类,因为得到的损失,也要进行梯度计算,相当于通过框架来进行的一些计算,可以自动的求梯度)
4.1---标签变成与网络输出一致的形状,首先要确定网络输出的形状。
网络输出的通道数255中,其中240是类别,另外3个c是置信度,还有3组的(x,y,w,h),其实这里直接写成(x,y,w,h)也可以,就是中心点坐标和宽高,但是这样的话没有一个范围,不便于优化,所以,最好是让这4个值是在0-1之间,那么很自然的想到进行归一化,把w和h都除以宽高,这时候w和h都是在0-1之间了。而对于x和y来说,替换成px和py,px,py是该中心点坐标在这个网格中的相对位置,取值范围也是0-1。所以,这个时候的(x,y,w,h)被替换成了(px,py,w/W,h/H)。替换后的这4个值,范围都在0-1之间。
上面的这个做法是yolov1的操作。
在yolov3的时候,对于x和y的思路基本一样,就是相对于当前网格左上角的偏移值。
但是,w和h,思路做了改变,引进了锚框的机制,就是相当于锚框的长宽,需要偏移多少。这个偏移量基本上都是很小的,这里再次说明了这点,其实预测出来的几个值,没有限制,随便是谁都行,只要可以把这个框给描绘出来,因为锚框的长宽是已知的,也就是人为设定的,所以根据偏移量,其实可以算出预测框的长宽。
锚框:其实就是人为对所有样本来做一个统计,观察到,目标的长宽,差不多是哪几种长宽出现的比较多。提前把这个长宽在图像上设置出来。。对于每一个小网格,都配备3个锚框,不同尺度特征图上,锚框的尺寸也不一样。所以,其实一个点,也就是有9个不同尺度的锚框。
4.2---确定标签的形状
标签也需要转换成一个13*13*255的矩阵,其中通道中的每一个数的含义,都需要和网络输出中的对应上。
1、初始化一个全零的13*13*255的矩阵。
2、计算真实框在哪个网格中(i,j)
3、将真实框的(x,y,w,h)转换成(tx,ty,tw,th)
4、将第(i,j)网格的前15个通道设置为( tx,ty,tw,th ,1, tx,ty,tw,th ,1 , tx,ty,tw,th ),置信度设置为1(这里的tx应该是3个不一样的,是相对于3个锚框的偏移量)
5、将第(i,j)网格的后240个通道设置为(0,0,0,,,1,,,0,0,0)
损失函数部分,可以分为3个部分,第一个部分,就是框的坐标误差;第二个部分,就是框的置信度误差;第三个部分,就是框的类别误差。
前提:以图片中只有一个目标为例。
标签中,只有第(i,j)这个网格的位置,通道数的255个数有值,其他的位置都没有数值。
预测图中,所有的网格位置,每个网格的通道数的255个数,都是有值的。
所以,计算损失的时候,不同网格的不同锚框,计算不一样的损失。
正样本的损失计算: 对tx ty求均方误差,对tw th求均方误差,对80类分类结果求二类交叉熵误差,对置信度C计算二类交叉熵误差(C期望值=1)。
负样本的损失计算:负样本就是边框和真实值IOU<阈值(背景、负样本)只对置信度C计算二分类交叉熵误差(C期望值=0)
其余既不负责预测物体,且IOU较大的边框不参与loss计算
【负样本<阈值】【正样本>阈值,并且与gt的iou最大,也就是只有一个正样本】【不参与计算>阈值】
loss计算中,“负责预测目标”(即正样本)和背景(即负样本),以及不参与计算loss的部分是怎么选择的:
正样本的选择:首先计算目标中心点落在哪个grid上,然后计算这个grid的9个先验框(anchor)和目标真实位置的IOU值(直接计算,不考虑二者的中心位置),取IOU值最大的先验框和目标匹配。于是,找到的 该grid中的 该anchor 负责预测这个目标,其余的网格、anchor都不负责。
负样本的选择:计算各个先验框和所有的目标ground truth之间的IOU,如果某先验框和图像中所有物体最大的IOU都小于阈值(一般0.5),那么就认为该先验框不含目标,记作负样本,其置信度应当为0
不参与计算部分:这部分虽然不负责预测对象,但IOU较大,可以认为包含了目标的一部分,不可简单当作负样本,所以这部分不参与误差计算。
蓝色框为聚类得到的先验框,黄色框是ground truth,红框是目标中心点所在的网格。
不是很理解的地方:
如果匹配的最优先验框所在的grid和gt box所在的grid不重合怎么办?既然不重合,那怎么使用sigmoid来预测中心点基于grid的偏移呢?因为我已经看过了一些开源实现,他还是在gtbox所在的grid里面选择一个IOU最大的anchor来作为匹配结果的
在原论文中,确实是使用先验框来训练的,也就是静态指定。静态指定就没有你说的问题了。动态的话,训练其实也是收敛的,中心点偏移只会发生在训练初期,就算照着错误的训练,慢慢的中心点偏移出grid的情况就会渐渐没有。这两种训练方式我都试过,并没有太大区别。关于动态训练的只是我个人见解,不一定正确哈。静态训练的方法肯定是没有问题的。