天天看点

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

一. 背景

本文档以ssd300作为背景网络进行解读,以Tensorflow,Keras为框架

原始代码:

https://github.com/pierluigiferrari/ssd_keras​github.com

分析后的代码:

https://github.com/Freshield/LEARN_detection/tree/master/a4_github_better_ssd/a2_analyze_model​github.com

目前网上基本都网络部分讲的比较多,但是真正训练和预测部分都相对粗略,所以自己网上找了一个相对比较好的ssd检测作为蓝本来分析,然后把相应的过程用大白话给表达出来,方便大家可以更好的理解网络。

二 到 三请看上一篇

于洋:大白话分析——SSD目标检测网络从训练到预测(上)​zhuanlan.zhihu.com

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

四. 数据部分

于洋:大白话分析——SSD目标检测网络从训练到预测(中上)​zhuanlan.zhihu.com

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

五. Loss部分

于洋:大白话分析——SSD目标检测网络从训练到预测(中)​zhuanlan.zhihu.com

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

六. decoder部分

这里我们开始完成最后的预测部分。

Recall一下,我们的输入为图像,shape为bx300x300x3,通过我们的网络预测输出为bx8732x33,其中33为21+4+8,21为相应的类别数,这里是VOC数据集所有是20个类别然后1个背景,后边的4为我们预测出来的编码后的位置信息lx,ly,lw,lh,一定注意,这里是编码后的位置信息,也就是我们需要进行解码之后才是真正的位置。后边的8分别是先验框的4个位置信息以及4个variance的值。这里我们再使用一下介绍先验框时候的图:

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

也就是现在我们之类已经得到了所有先验框预测出来的8732个位置以及当前位置的分类结果也就是置信度,下一步就是要从这8732个框中最后选出a图中的两个框,也就是真正我们的目标框。

这也就是我们decoder的左右,从众多框中挑选出最后我们真正想要得到的框。

  1. 坐标解码

我们这里的y_pred(b,8732,21+4+8)分类+label坐标+先验框坐标+4+4+4是(lx,ly,lw,lh)(pred),(cx,cy,w,h)(anchor),v0,v1,v2,v3。

首先我们这里要根据公式对预测的结果进行解码,我们的解码公式为:

w(pred)= exp(lw × v2)× w(anchor)

h(pred)= exp(lh × v3)× h(anchor)

cx(pred)= w(anchor)× lx × v0 + cx(anchor)

cy(pred)= h(anchor)× lh × v1 + cy(anchor)

这里相当于就是数据部分编码的方法反过来就可以了。

这样我们就可以得到所有预测的cx,cy,w,h位置信息。但是由于之后我们需要计算IOU的信息,所以使用左上右下的形式会比较方便,这里参照数据部分说明的方法,最后我们便得到了xmin,ymin,xmax,ymax形式的四个预测的位置信息。

2. 反归一化

在数据部分的时候,我们的预测值都做了归一化处理,也就是把绝对位置都转换到了0,1相对位置,所以这里我们需要把位置反归一化回去。

其实也非常简单,就是把0,1的比例数值乘以原图大小变为绝对位置即可。

xmin = xmin × 300

ymin = ymin × 300至此,我们的SSD网络已经可以完成了预测后的解码部分~

xmax = xmax × 300

ymax = ymax × 300

这样就得到了反归一化之后,值域在0到300之间的数值

3. 遍历batch,遍历各分类号,找到分类号的预测值

目前,我们的预测矩阵为(b,8732,33),其中的33为21个分类结果,4个已经反归一化的坐标位置以及8个先验框和variance的信息。这里我们遍历batch,得到每个batch的预测结果也就是(8732,33)的矩阵。

然后遍历得到各个分类的分类号好提取出各个分类的预测结果,相当于这里我们针对每个类别单独处理。

举例我们找出第5个类别,也就是把网络的pred[:, [6, 21, 22, 23, 24]] 这几列拿出来,第一个6代表的第5个类别的预测值,然后21到24是坐标的位置,这样取出后,我们得到第五个类别的所有8732个框的预测值和坐标,(8732,5)。这里你可能会疑问,不是要取第5个类别的预测,为什么要把所有8732个框都取出来,因为我们要先取出来所有的,再经过阈值处理等操作就可以去除了,否则如果直接用argmax的操作,可能有些框所有值都低于阈值,就是这个框是不属于任何一个类别的,而argmax会造成这种错分配的情况。

4. 过滤分类阈值

在得到了(8732,5)这个类别的矩阵后,首先我们要针对第零维也就是类别的预测概率值进行阈值处理,这里一般设为0.5,因为这样的话,可以避免一个框分配到两个类别的情况。这样我们得到8732个框中预测值也就是置信度大于0.5的所有框,假设这里有200个框大于0.5,那么这一步后我们的矩阵就变成了(200,5)

5. 进行gready_nms,贪婪非极大值抑制

这里是预测框最重要的一步,也是一般所有目标检测都会用到的技术,也就是NMS,非极大值抑制,而这里是gready_nms也就是贪婪非极大值抑制,我大概网上搜了一下,基本大家用的都是贪婪非极大值抑制,非贪婪的方法暂时没有看到。。。

这里的思想非常简单,其实从名字就可以看出,我们的目的就是找出极大值,然后对非极大值进行抑制,那么这里就会有两个问题:

1)如果寻找极大值

2)如果寻找非极大值并抑制

所以这里首先我们需要有一个评价的标准来评定框的值,这里使用的是分类值也就是置信度来作为评价标准,也就是我们要找出置信度最大的那个框,作为我们的极大值。

为了方便,我们首先把当前的矩阵也就是(200,5)进行复制。

然后通过argmax找到这个置信度最高的框,把它从我们的复制的矩阵中去除并放到返回的矩阵中。

ssd目标检测训练自己的数据_大白话分析——SSD目标检测网络从训练到预测(中下)...

如果看这张图,我们可以发现,比如说当前我们是在对人这个类别进行计算,那么其实目前真实图里会有两个人的框,我们的预测结果为右下,也就是橙色的框有好多个。那么我们可以看到对于一个人周围会有许多框,我们其实就是想把人周围的框变成一个框。那么我们的NMS算法的意思其实就是,先找打一个置信度最高的框,比如是骑在马上的那个人的框,然后计算所有框和他的IOU值,如果IOU大于一个IOU的阈值,也就是说这些框和我置信度最高的框重合度很高,也就是说明这些是多余的框,然后把这些框去除。我们再继续找下一个置信度最高的框,也就是后边小的人,再找出和他IOU重合度高的框,进行去除。那么最后就会得到我们的目标框并去除了附近的干扰的框。这里的大概逻辑是如果你的置信度最高,那么你应该就是那个最正确的框,那和你IOU值高的就是预测同样目标的多余的框。

然后找到了第一个问题的答案后,就是第二个问题,我们对这个复制矩阵剩下的199个框都和这个置信度最高的框进行IOU计算,我们找出所有IOU值大于阈值的,这里使用的阈值大小为0.45,我们把这些框从复制的矩阵去除,然后继续找最大的框再计算IOU去除IOU大于阈值的框直到复制矩阵为空位置。

这样最终我们就会得到我们的目标框,矩阵最终就变成了(n_objects,5),这里为了方便,我们再把当前的类别号放进去,也就变为了(n_objects,6),然后放到最终的返回矩阵中。

6. 进行top_k保留

这里还有一个设置为top_k,一般设置为200,也就是说如果最后预测的n_objects大于top_k也就是200,那么我只取置信度最高的200个,不过一般一张图并不会有那么多目标,所以一般并不会进行计算

7. 反transform数据增强

是不是觉得我们现在已经可以直接得到预测的结果了?其实再decoder部分最一开始说的有个不太严谨的地方,就是我们的图片输入为bx300x300x3,这的确是我们网络的输入,不过回顾数据部分讲解的时候,我们的原图输入是不定大小的,而通过我们的transform的方法之后,图片才变成bx300x300x3的大小,而label的位置也相应的进行了变化。所以在最后的这里,我们需要按照transform的方法进行反transform回去的操作,由于一般预测其实只会做resize的操作,所以这里我们只需要反resize会图片的原始大小,并把预测的坐标按照相应的方法映射到原图的位置即可。

至此,我们的SSD网络已经可以完成了预测后的解码部分~

继续阅读