yolov3

所有“蒙蔽”都来自于不知道yolov3训练的时候,数据是长什么样子,所以在这主要记录的是对于一张图片,如何生成yolov3的label数据,并不是主要分析网络结构,想看网络结构的要失望了~~~
keras yolov3源代码
论文

数据打标

# box_data: (batch, 416, 416, 3)
image_data = np.array(image_data)
# box_data: (batch, 20, 5)
box_data = np.array(box_data)
y_true = preprocess_true_boxes(box_data, input_shape, anchors, num_classes)

yolov3 默认每个图像最多检测20个物体,y_true就是生成的训练label。y_true的格式为 :

[ (batch,13, 13, 3, 25), (batch,26, 26, 3, 25), (batch,52, 52, 3, 25) ]
  • 13,26,52分别代表三种维度的feature-map,也就相当于将原图片分别分为13×13,26×26,52×52个cell。
  • 3表示每个cell需要预测三个大小不同的框(anchor)。
  • 25代表4个坐标,1个置信度还有20个分类。

所以对于一张图像,一共会映射( 13×13×3 + 26×26×3 + 52×52×3 )个anchor,其中(13×13)中每个cell对应的3个anchor大小为 [116. 90.],[156. 198.],[373. 326.];(26×26)中每个cell对应的3个anchor大小为 [ 30. 61.],[ 62. 45.],[ 59. 119.];(52×52)中每个cell对应的3个anchor为[ 10. 13.],[ 16. 30.],[ 33. 23.]。
首先,加入一张图片中有一个物体需要检测,如下图所示:

图片统一调整为416×416大小,其中黄框为待检测物体的ground-true。
  1. 我们需要知道这个框是由三种维度(13×13),(26×26),(52×52)的feature-map中哪一个来进行预测的。
  2. 然后需要知道是对应feature-map中哪个cell预测的。
  3. 最后需知道是与这个cell相关联的三个anchor中哪个回归得到的。

首先求黄框与9种anchor的iou,并且找出最大的那个iou对应的anchor,如下图所示:

由图中可知有9种cell,根据feature-map中感受野的知识,可知卷积网络中越靠后的feature-map感受野越大,也就是对应原始图片中区域越大。13×13,26×26,52×52 三种不同类型的特征图,每个特征点产生三个anchor,也就是一共9个。所以
  1. 13×13的特征图对应 [116. 90.],[156. 198.],[373. 326.]三个anchor;
  2. 26×26对应 [ 30. 61.],[ 62. 45.],[ 59. 119.]三个anchor;
  3. 52×52对应 [ 10. 13.],[ 16. 30.],[ 33. 23.]三个anchor。

由图像可知,best anchor是[116. 90.]也就是13×13特征图中所产生的第一个anchor,这样就解决了问题中(1)和(3)。接下来需要将原始图片中的黄框定位到13×13的特征图中,也就是寻找13×13的特征图中是哪个cell在预测这个黄框。第几行i第几列j,如下图所示:

在得到黄框在(13×13)的feature-map中位置后,对数据进行打标。首先在所有batch打标前会生成一个全0的矩阵y_true,shape为[ (batch,13, 13, 3, 25), (batch,26, 26, 3, 25), (batch,52, 52, 3, 25) ],然后进行填充,对于上述例子在y_true[0][i][j][1]位置进行填充,其余部分为0,如下图所示:
模型在训练的过程中得到的结果统一也是这样的,由此来计算四个损失值进行网络的训练。产生y_true的代码在源代码中对应:preprocess_true_boxes 方法;

yolov3网络的构建

yolov3接收两个输入一个是图片数据:(batch,416,416,3),另一个是上文中提到的打标数据[ (batch,13, 13, 3, 25), (batch,26, 26, 3, 25), (batch,52, 52, 3, 25) ]。首先构建yolo_body,也就是主干网络,用来提取图片的特征并且进行3个尺度的类别预测和坐标回归,最终返回 Model(inputs, [y1,y2,y3]) y1,y2,y3分别对应三个feature-map!首先image通过DarkNet网络提取图片特征,将得到的feature-map进行卷积和concat一系列操作后,得到三个大小的特征图。
图片参考: yolov3框架
yolo_body 输出即为[ (batch,13, 13, 75), (batch,26, 26, 75), (batch,52, 52, 75) ]的三个feature-map。

构建损失函数yolo_loss

yolo_loss接收来在yolo_body的输出,与上文产生的y_true。首先将每个yolo_body的输出reshape为(batch,H,W,3,25)的tensor。这里我们需要知道yolov3中25的前四个分别代表什么意思。首先前两个(tx,ty)代表的是预测box的中心坐标相对于所属cell左上角坐标的偏移量,使用sigmod映射到(0,1)之间保证预测box的中心还在cell中。同时(tw,th)分别表示预测box的宽,高相对于对应anchor的比例。最后anchor的宽高乘以tw,th的e次方得到预测框的宽,高。原论文中如下图所示:

在实际训练中,还进行了一系列的归一化操作(grid_shapes的使用),方便训练。最后使用,使用这个公式的反变换将y_true转变为对应的值:
raw_true_xy = y_true[l][..., :2]*grid_shapes[l][::-1] - grid
raw_true_wh = K.log(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1])

最后yolov3的损失一共有四部分组成:

  1. 回归中心坐标损失:xy_loss
  2. 回归W,H的损失:wh_loss
  3. 置信度损失:confidence_loss
  4. 物体分类损失:class_loss
 xy_loss = object_mask * box_loss_scale * K.binary_crossentropy(raw_true_xy, raw_pred[...,0:2], from_logits=True)
 wh_loss = object_mask * box_loss_scale * 0.5 * K.square(raw_true_wh-raw_pred[...,2:4])
 confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True)+ (1-object_mask) * K.binary_crossentropy(object_mask,raw_pred[...,4:5], from_logits=True) * ignore_mask
 class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[...,5:], from_logits=True)

其中object_mask 为选中labe和predict中具有box的数据,ignore_mask为没有box的数据。其中要注意的是xy_loss和confidence_loss,binary_crossentropy 使用的是二分类交叉损失,wh_loss使用的平方损失。论文中说binary_crossentropy这个损失要比多分类的交叉损失效果要好,至于为啥,还在探索。有一篇讲解yolov3损失很棒的文章:yolov3损失详解
最后对这四个损失进行一些取平均得到最后的损失:

 xy_loss = K.sum(xy_loss) / mf
 wh_loss = K.sum(wh_loss) / mf
 confidence_loss = K.sum(confidence_loss) / mf
 class_loss = K.sum(class_loss) / mf
 loss += xy_loss + wh_loss + confidence_loss + class_loss
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值