YOLOV3

本篇文章整理一下Yolov3, Yolov3是单阶段目标检测的典型代表之一,那么它是如何实现目标检测的呢?

网络架构

画图这里参考了https://github.com/YunYang1994/tensorflow-yolov3

在这里插入图片描述

在这里插入图片描述

  • backbone网络

    darknet53, 结构如下图所示, 它包括5个残差层,在每个残差层之前都由一个下采样操作,通过步长=2的卷积实现的.

    在这里插入图片描述

  • fpn网络

    fpn网络在第一个图中也画的很清楚了,主要是先经过5个(conv + bn + leaky relu)块, 上采样,concat等操作完成.

网络结构弄清楚之后,接下来就是比较核心,也是我长时间没能理解的部分.

head网络

因为yolov3预测的是偏移, 所有需要对其进行处理,才能在计算loss时根据iou来判断正负样本. yolov3的输出的feats是(13, 13, 3, 5*(80 + 5)), (26, 26, 3, 5 * (80 + 5)), (52, 52, 3, 5 * (80 + 5))的tensor.

box_信息的处理:

box_xy = (tf.nn.sigmoid(feats[..., :2]) + grid) / tf.cast(grid_shape[::-1], tf.float32)
box_wh = tf.exp(feats[..., 2:4]) * tf.cast(anchors_tensor, tf.float32) / tf.cast(input_shape[::-1], tf.float32)

在评估阶段还需要计算confidence和class probilites.

box_cofidence = tf.nn.sigmoid(feats[..., 4:5])
box_class_probs = tf.nn.sigmoid(feats[..., 5:])

ground truth 数据集转换

同样 gt bboxes也需要转换成 形如(13, 13, 3, 5+80), (26, 26, 3, 5 + 80), (52, 52, 3, 5 + 80)的tensor.

对于一张图片里的一个gt bbox,它的坐标(x1, y1, x2, y2, cls), 我们将(x1, y1, x2, y2)对应的矩形框与所有的9个anchor box进行iou的计算,最大iou对应的anchor box的位置决定了该bbox在哪个尺寸的特征图中被预测出来.

假设anchor box有以下9个,

10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326

bbox1匹配最大iou的anchor box是第8个 156, 198,那么就由形如(13, 13)的特征图进行预测, 所以我们需要在(13, 13, 3, 5 + 80)的tensor上进行编码该bbox, 其中x,y通过如下方式获得,

x_center, y_center = (x1 + x2) / 2, (y1 + y2) / 2
w, h = x2 - x1, y2 - y1
x_center, w = x_center / input_x, w / input_x
y_center, h = y_center / input_y, h / input_y
new_x = int(x_center * 13)
new_y = int(y_center * 13)

这样,我们就可以编码 (new_x, new_y, 1, :)这个位置的信息了,

true_box[new_x, new_y, 1, 0:4] = scaled_true_box[0:4] #相对输入w和h, 做了归一化处理, 所以取值范围在[0, 1]
true_box[new_x, new_y, 1, 4] = 1
true_box[new_x, new_y, 1, 5 + c] = 1

通过这种方式,可以将一张图像里所有的bbox进行编码,同样可以对一个batch的数据进行编码。最终可以得到一个batch的编码信息,
(batch_size, 13, 13, 3, 5 + 80), (batch_size, 26, 26, 3, 5 + 80), (batch_size, 52, 52, 3, 5 + 80).

计算loss

我们需要在三个不同尺寸的特征图上计算loss. 因为yolov3输出的是偏移,所以我们先需要把gt bbox信息转换成偏移,

raw_true_xy = y_true[l][..., :2] * grid_shapes[l][::-1] - grid  # (batch_size, 13, 13, 3, 2) * (2, ) - (13, 13, 1, 2) => (batch_size, 13, 13, 3, 2)

raw_true_wh = tf.math.log(tf.clip_by_value(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1], 1e-9, 1e9)) # (batch_size, 13, 13, 3, 2) / (3, 2) * (2, 1) => (batch_size, 13, 13, 3, 2)

object_mask_bool = tf.cast(object_mask, tf.bool) # Shape = (batch_size, grid_shape, grid_shape, 3, 1)

xy和wh的loss(只计算正样本)

xy_loss = object_mask * box_loss_scale * tf.nn.sigmoid_cross_entropy_with_logits(labels=raw_true_xy, logits=raw_pred[..., 0:2])
wh_loss = object_mask * box_loss_scale * 0.5 * tf.square(raw_true_wh - raw_pred[..., 2:4])

分类loss(只计算正样本)

class_loss = object_mask * tf.nn.sigmoid_cross_entropy_with_logits(labels=true_class_probs, logits=raw_pred[..., 5:])

confidence loss, 这里既考虑正样本,也考虑负样本.

  • 正样本: gt bbox 对应的位置
  • 负样本: 非 gt bbox对应的位置,而且它与任何gt bbox的iou都小于给定的阈值
  • 为什么需要考虑正负样本? 如果没有负样本带来的loss,也就是只考虑正样本loss,那么当把负样本预测为正样本的时候对最后loss没有影响,但是这是最后的结果中就会出现很多负样本的框. 所以,需要负样本的存在,如果所有非正样本都当做负样本,因为负样本很多,这样会造成当把所有样本都预测为负样本的时候,loss依旧很低,这样模型的输出就会没有正样本. 所以需要一定数量的负样本.
confidence_loss = object_mask * tf.nn.sigmoid_cross_entropy_with_logits(labels=object_mask, logits=raw_pred[..., 4:5]) + \
                          (1 - object_mask) * tf.nn.sigmoid_cross_entropy_with_logits(labels=object_mask, logits=raw_pred[..., 4:5]) * ignore_mask

预测

yolov3 head的输出结果解码成对应原图的坐标,然后经过score排序、nms等,产生最后的预测结果.

与 Faster RCNN等双阶段目标检测的区别

  • yolov3在预测的时候没有产生候选框的过程,而是根据yolov3的输出进行解析.
  • Faster RCNN在预测的时候先产生大约20000个候选框,经过score排序和nms之后剩余300个,然后再对其进行Fast RCNN操作(矫正候选框, 分类), 再经过一次nms,输出最后的预测结果.

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值