原文链接:http://www.luyixian.cn/news_show_304729.aspx

    一起分析网络一些细节与难懂的地方

    backbone:darknet-53
    为了达到更好的分类效果,作者自己设计训练了 darknet-53。作者在 ImageNet 上实验发现这个 darknet-53,的确很强,相对于 ResNet-152 和 ResNet-101,darknet-53 不仅在分类精度上差不多,计算速度还比 ResNet-152 和 ResNet-101 强多了,网络层数也比他们少。

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

    为了加强算法对小目标检测的精确度,YOLO v3 中采用类似 FPN 的 upsample 和融合做法(最后融合了 3 个 scale,其他两个 scale 的大小分别是 26×26 和 52×52),在多个 scale 的 feature map 上做检测。

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

    output

    所谓的多尺度就是来自这 3 条预测之路,y1,y2 和 y3 的深度都是 255,边长的规律是 13:26:52。yolo v3 设定的是每个网格单元预测 3 个 box,所以每个 box 需要有 (x, y, w, h, confidence) 五个基本参数,然后还要有 80 个类别的概率。所以 3×(5 + 80) = 255。这个 255 就是这么来的。

    下面我们具体看看 y1,y2,y3 是如何而来的。
    网络中作者进行了三次检测,分别是在 32 倍降采样,16 倍降采样,8 倍降采样时进行检测, 这样在多尺度的 feature map 上检测跟 SSD 有点像。在网络中使用 up-sample(上采样)的原因: 网络越深的特征表达效果越好,比如在进行 16 倍降采样检测,如果直接使用第四次下采样的特征来检测,这样就使用了浅层特征,这样效果一般并不好。如果想使用 32 倍降采样后的特征,但深层特征的大小太小,因此 yolo_v3 使用了步长为 2 的 up-sample(上采样),把 32 倍降采样得到的 feature map 的大小提升一倍,也就成了 16 倍降采样后的维度。同理 8 倍采样也是对 16 倍降采样的特征进行步长为 2 的上采样,这样就可以使用深层特征进行 detection。

    作者通过上采样将深层特征提取,其维度是与将要融合的特征层维度相同的(channel 不同)。如下图所示,85 层将 13×13×256 的特征上采样得到 26×26×256,再将其与 61 层的特征拼接起来得到 26×26×768。为了得到 channel255,还需要进行一系列的 3×3,1×1 卷积操作,这样既可以提高非线性程度增加泛化性能提高网络精度,又能减少参数提高实时性。52×52×255 的特征也是类似的过程。

    从图中,我们可以看出 y1,y2,y3 的由来。

    Bounding Box
    YOLO v3 的 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。

    感受一下 9 种先验框的尺寸,下图中蓝色框为聚类得到的先验框。黄色框式 ground truth,红框是对象中心点所在的网格。

    这里注意 bounding box 与 anchor box 的区别:
    Bounding box 它输出的是框的位置(中心坐标与宽高),confidence 以及 N 个类别。
    anchor box 只是一个尺度即只有宽高。

    LOSS Function
    YOLOv3 重要改变之一:No more softmaxing the classes。
    YOLO v3 现在对图像中检测到的对象执行多标签分类。
    早期 YOLO,作者曾用 softmax 获取类别得分并用最大得分的标签来表示包含再边界框内的目标,在 YOLOv3 中,这种做法被修正。

    softmax 来分类依赖于这样一个前提,即分类是相互独立的,换句话说,如果一个目标属于一种类别,那么它就不能属于另一种。

    但是,当我们的数据集中存在人或女人的标签时,上面所提到的前提就是去了意义。这就是作者为什么不用 softmax,而用 logistic regression 来预测每个类别得分并使用一个阈值来对目标进行多标签预测。比阈值高的类别就是这个边界框真正的类别。

    用简单一点的语言来说,其实就是对每种类别使用二分类的 logistic 回归,即你要么是这种类别要么就不是,然后便利所有类别,得到所有类别的得分,然后选取大于阈值的类别就好了。

    logistic 回归用于对 anchor 包围的部分进行一个目标性评分 (objectness score),即这块位置是目标的可能性有多大。这一步是在 predict 之前进行的,可以去掉不必要 anchor,可以减少计算量。

    如果模板框不是最佳的即使它超过我们设定的阈值,我们还是不会对它进行 predict。
    不同于 faster R-CNN 的是,yolo_v3 只会对 1 个 prior 进行操作,也就是那个最佳 prior。而 logistic 回归就是用来从 9 个 anchor priors 中找到 objectness score(目标存在可能性得分) 最高的那一个。logistic 回归就是用曲线对 prior 相对于 objectness score 映射关系的线性建模。

    xyloss = object_mask boxloss_scale K.binarycrossentropy(raw_true_xy, raw_pred[…, 0:2],
    from_logits=True)
    wh_loss = object_mask
    boxloss_scale 0.5 K.square(raw_true_wh - raw_pred[…, 2:4])
    confidence_loss = object_mask
    K.binarycrossentropy(object_mask, raw_pred[…, 4:5], from_logits=True) +
    (1 - object_mask)
    K.binarycrossentropy(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

    以上是一段 keras 框架描述的 yolo v3 的 loss_function 代码。忽略恒定系数不看,可以从上述代码看出:除了 w, h 的损失函数依然采用总方误差之外,其他部分的损失函数用的是二值交叉熵。最后加到一起。那么这个 binary_crossentropy 又是个什么玩意儿呢?就是一个最简单的交叉熵而已,一般用于二分类,这里的两种二分类类别可以理解为 “对和不对” 这两种。
    http://www.luyixian.cn/news_show_304729.aspx