YoloV3学习笔记(五)—— 网络架构

YoloV3学习笔记(五)

  • YoloV3学习笔记(五)—— 网络架构
    • 一、总体架构
    • 二、Darknet
    • 三、输出
    • 四、Bounding Box
    • 五、Loss function

YoloV3学习笔记(五)—— 网络架构

在上一节中,主要介绍了cfg文件的代码注释,但是还是不懂得YoloV3的网络架构是如何搭建的。

一、总体架构

YoloV3学习笔记(五)—— 网络架构_第1张图片
DBL: Darknetconv2d_BN_Leaky=conv+BN+Leaky relu

BN: Batch Normalization (详情可点击)

resn: n代表数字,有res1,res2, … ,res8等等,表示这个Resblock_body里含有多少个res_unit(详情可点击)

concat: 张量拼接。将darknet中间层和后面的某一层的上采样进行拼接。拼接的操作和残差层add的操作是不一样的,拼接会扩充张量的维度,而add只是直接相加不会导致张量维度的改变。

此处介绍了一个模型结构可视化神器:点击
下载:点击

二、Darknet

与YoloV2相比,整个V3结构里面,是没有池化层和全连接层的。前向传播过程中,张量的尺寸变换是通过改变卷积核的步长来实现的,比如stride=(2, 2),这就等于将图像边长缩小了一半(即面积缩小到原来的1/4)。在Yolo_V2中,要经历5次缩小,会将特征图缩小到原输入尺寸的1/2^5,即1/32。若输入为416x416,则输出为13x13(416/32=13)。

YoloV2主体框架如下:

YoloV3学习笔记(五)—— 网络架构_第2张图片

YoloV3主体框架如下:
YoloV3学习笔记(五)—— 网络架构_第3张图片
比较

YoloV2中对于前向过程中张量尺寸变换,都是通过 最大池化来进行,一共有5次。而v3是通过卷积核增大步长来进行,也是5次。(darknet-53最后面有一个全局平均池化,在yolo-v3里面没有这一层,所以张量维度变化只考虑前面那5次)。这也是416x416输入得到13x13输出的原因。

YoloV3使用了darknet-53的前面的52层(没有全连接层),Yolov3这个网络是一个全卷积网络,大量使用残差的跳层连接,并且为了降低池化带来的梯度负面效果,作者直接摒弃了Pooling,用conv的stride来实现降采样。在这个网络结构中,使用的是步长为2的卷积来进行降采样。

三、输出

YoloV3学习笔记(五)—— 网络架构_第4张图片

Yolov3输出了3个不同尺度的feature map,这个借鉴了FPN(feature pyramid networks),采用多尺度来对不同size的目标进行检测,越精细的grid cell就可以检测出越精细的物体。y1,y2和y3的深度都是255,边长的规律是13:26:52。

作者在3条预测支路采用的也是全卷积的结构,其中最后一个卷积层的卷积核个数是255,是针对COCO数据集的80类:3*(80+4+1)=255,3表示一个grid cell包含3个bounding box,80表示80个类,4表示框的4个坐标信息(tx,ty,tw,th),1表示objectness score。

四、Bounding Box

YoloV3的Bounding Box由YoloV2又做出了更好的改进。在yolo_v2和yolo_v3中,都采用了对图像中的object采用k-means聚类。 feature map中的每一个cell都会预测3个边界框(bounding box) ,每个bounding box都会预测三个东西:(1)每个框的位置(4个值,中心坐标tx和ty,,框的高度bh和宽度bw),(2)一个objectness prediction ,(3)N个类别,coco数据集80类,voc20类。

三次检测,每次对应的感受野不同,32倍降采样的感受野最大,适合检测大的目标,所以在输入为416×416时,每个cell的三个anchor box为(116 ,90); (156 ,198); (373 ,326)。16倍适合一般大小的物体,anchor box为(30,61); (62,45); (59,119)。8倍的感受野最小,适合检测小目标,因此anchor box为(10,13); (16,30); (33,23)。所以当输入为416×416时,实际总共有(52×52+26×26+13×13)×3=10647个proposal box。

在这里插入图片描述
回看代码(是不是终于知道下面那九个坐标是怎么得出来的吧)
YoloV3学习笔记(五)—— 网络架构_第5张图片
注意
Bounding box :它输出的是框的位置(中心坐标与宽高),confidence以及N个类别。
Anchor box :只是一个尺度即只有宽高。

五、Loss function

对掌握Yolo来讲,loss function还是非常重要的。但yolo系列论文里面只有yolo v1明确提了损失函数的公式。对于yolo这样一种讨喜的目标检测算法,就连损失函数都非常讨喜。在v1中使用了一种叫sum-square error的损失计算方法,就是简单的差方相加而已。在目标检测任务里,以下几个关键信息是需要确定的:
(x,y),(w,h),class,confidence
损失函数也应该由上述四类各自特点确定。最后加到一起就可以组成最终的loss_function了,也就是一个loss_function搞定端到端的训练。

	lxy, lwh, lcls, lconf = ft([0]), ft([0]), ft([0]), ft([0])
    txy, twh, tcls, indices = build_targets(model, targets)#在13 26 52维度中找到大于iou阈值最适合的anchor box 作为targets
    #txy[维度(0:2),(x,y)] twh[维度(0:2),(w,h)] indices=[0,anchor索引,gi,gj]

    # Define criteria
    MSE = nn.MSELoss()
    CE = nn.CrossEntropyLoss()
    BCE = nn.BCEWithLogitsLoss()

    # Compute losses
    h = model.hyp  # hyperparameters
    bs = p[0].shape[0]  # batch size
    k = h['k'] * bs  # loss gain
    for i, pi0 in enumerate(p):  # layer i predictions, i
        b, a, gj, gi = indices[i]  # image, anchor, gridx, gridy
        tconf = torch.zeros_like(pi0[..., 0])  # conf

        # Compute losses
        if len(b):  # number of targets
            pi = pi0[b, a, gj, gi]  # predictions closest to anchors 找到p中与targets对应的数据lxy
            tconf[b, a, gj, gi] = 1  # conf
            # pi[..., 2:4] = torch.sigmoid(pi[..., 2:4])  # wh power loss (uncomment)

            lxy += (k * h['xy']) * MSE(torch.sigmoid(pi[..., 0:2]),txy[i])  # xy loss
            lwh += (k * h['wh']) * MSE(pi[..., 2:4], twh[i])  # wh yolo loss
            lcls += (k * h['cls']) * CE(pi[..., 5:], tcls[i])  # class_conf loss

        # pos_weight = ft([gp[i] / min(gp) * 4.])
        # BCE = nn.BCEWithLogitsLoss(pos_weight=pos_weight)
        lconf += (k * h['conf']) * BCE(pi0[..., 4], tconf)  # obj_conf loss
    loss = lxy + lwh + lconf + lcls

以上是一段pytorch框架描述的yolov3 的loss_function代码。

如果使用的是keras框架,则相应的loss_function代码如下所示:

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)

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

参考文章
https://blog.csdn.net/litt1e/article/details/88907542
https://blog.csdn.net/leviopku/article/details/82660381
https://blog.csdn.net/legalhighhigh/article/details/81409551

你可能感兴趣的:(YOLOV3,深度学习,pytorch)