实现yolo时踩过的坑!
终于把yolo v3框架写好了。支持多模型、多数据集、任意输出层数量、任意anchor数量、模型剪枝还适配k210.不要太好用~
这里记录一下我之前的实现的问题出在哪里。
错误地计算了ignore mask
从yolo v2
开始就会计算正确box
与预测box
直接iou
关系,如果iou score
大于阈值,那么说明这个预测box
是成功预测到了这个对象的,极大的提高了模型的recall
。
但是我在开源的yolo v2
中使用Boolean mask
函数时忽略了一点,比如batch
为16,那么输出label
的尺寸为\([16,7,10,3,25]\),直接使用Boolean mask
会得到正确box
尺寸为\([?,4]\)。然后我把这个\([?,4]\)与预测出来的box
\([16,7,10,3,4]\)计算iou score
。
乍一看还以为没什么毛病,其实这里最大的毛病就是整个batch
的正确box
都与整个batch
的预测box
都做了iou score
,如果这时候计算最优iou score
,很有可能这个最优的预测box
不属于这张图片!数据直接出现了混合,这就是根源问题。
在新的写的代码中,我用了map
的方式处理每张图片,既提高了效率,又避免了错误。
题外话一句。。我现在都惊讶我之前的yolo v2
为啥效果还行,很有可能误打误撞搞了个数据集mix
的效果。。。
更新:
通过对比腾讯优图所开源的yolo3
的代码,我发现这个ignore mask
不但需要每张图像单独计算,还需要单一输出层与全局的目标进行计算,因为我用的是tf.keras
,所以没办法在不使用hack
的方式下传入整张图像的bbox
数组,所以我在label
中多加了一维,标记全局的对象位置.
以下代码为我目前的标签制作代码:
- 避免了
inf
- 避免了对象重叠(原版yolo也没有考虑到这一点)
- 添加了全局的对象标记.
这些问题消除之后,我的yolo
所计算出的loss
与腾讯优图所开源的yolo
完全一致.终于完美复现出yolo
的效果了~
labels = [np.zeros((self.out_hw[i][0], self.out_hw[i][1], len(self.anchors[i]), |
anchor的尺度
前面我有个文章也写了,anchor
的作用就是让预测wh
与真实wh
直接的比例接近与1,那么细细想来,anchor
的尺度是对应图片尺度\([224,320]\)还是对应栅格的尺度,还是对应全局的0-1
都没有什么关系,只不过anchor
的尺度就代表做标签的时候label
要转换的尺度。所以为了方便起见,直接把anchor
尺度设置为全局的0-1
就完事了,还减少运算量。
loss出现NaN
问题原因在于图片标签的width
与height
出现了0
,导致log(0)=-inf
的问题.
解决起来很简单,在制作标签的时候限制width
与height
范围即可.
label中的极端情况的考虑
bbox到达边界值
当bbox
的中心点位于边界值最大值时,如下图所示. \[\begin{aligned}
index&=floor(x*w) \\
\because w&=3,x=1 \Rightarrow floor(1*3)=3
\end{aligned}
\]
但使用3
进行索引就会报错,所以我们需要限制一下bbox
的中心坐标不能大于等于\(1\).
+-------+-------+-------+
| | | |
| | | |
| | | +---------+
+-------+-------+--|----+ |
| | | | | |
| | | | center |
| | | | | |
+-------+-------+--|----+ |
| | | +---------+
| | | |
| | | |
+-------+-------+-------+
当两个目标的label相同时
如下图所示,当两个bbox
真的非常靠近时,就会出现他们的label
所在的位置都是相同的,就会出现label
被覆盖的问题了.目前我将相同label
时,后面的label
分配给次优的anchor
.
+---------------+-------+
| +---------+ | |
| +|--------+| | |
| || | || | |
+-||--------||----------+
| || | || | |
| || | || | |
| || | || | |
+-|+---------+----------+
| +---------+ | |
| | | |
| | | |
+-------+-------+-------+
数据增强
数据增强我使用gluoncv
的方式,首先是图像crop
与resize
,使用的是ssd
所提出的带iou
约束的crop
方式,resize
之后结合imgaug
库进行数据增强,效果不错。如果可以再进一步,可以使用谷歌提出的autoaugment
策略。我这里暂时还没用mixup
,gluoncv
里面应该是有使用的。
IOULoss
推荐使用ciou loss
,我测试之后map
提高了4个点,效果相当不错。几个iou loss
的实现方式我总结在这里