0. 前言
- Feature Pyramid Networks for Object Detection - 原文
- 很搓的源码:irvingzhang0512/tf_eager_object_detection
- 参考资料:Poster(推荐)
- 参考源码:
- DetectionTeamUCAS/FPN_Tensorflow:
- 帮助最大,感谢作者。
- 提供了 在pascal 中训练的pre-treained mdoel,提供了很多训练结果(可用于对比)。
- Viredery/tf-eager-fasterrcnn:虽然这个repo的名字叫做faster rcnn,但其实是fpn……
- DetectionTeamUCAS/FPN_Tensorflow:
- 复现结果:
- 在Pascal VOC 2007 trainval set上训练,在 Pascal VOC 2007 test set 上测试。
- 都是 FPN-Resnet50 的结果,更多模型正在训练中……
- FPN_Tensorflow 的结果是0.7426
- 将 FPN_Tensorflow 预训练模型导入复现模型,得到的结果是0.7430
- 对复现模型进行三次训练,得到的结果是 0.7465、0.7377、0.7392
- 某些巧合:
- 复现过 vgg16 Faster R-CNN、Resnet101 Faster R-CNN、Resnet50 FPN这三个模型,每个模型都训练过超过3次。
- 巧合在于:对于每一类模型,第一次训练的结果都是最好的。
- 在tf-faster-rcnn中提到,在pascal上训练的结果却是会存在一些不确定性……所以下一步是实现coco训练集上的训练与评估,希望去除这种巧合……
1. FPN 论文内容
1.1. 素质四连
- 要解决什么问题?
- Faster R-CNN 对小目标的检测效果不好。
- 使用 image pyramid(其实就是对同一张图片,压缩到不同尺寸进行将检测)虽然能够提高小目标检测效果,但太费时间。
- 目标:在多个尺度上进行检测(提高性能),同时希望耗时短。 learning generic feature representations to detect objects present in multiscale
- 用了什么方法解决?
- 使用 Feature Pyramid Network 进行多尺度检测,保持小目标检测效果的同时,大大提高运行效率。
- 效果如何?
- 当时在 COCO 上性能达到最优。
- 同时,预测是运行效率达到6FPS。
- 还存在什么问题?
- 从最终mAP来说,性能还是不如 image pyramid。
1.2. 多尺度检测的方法
- Featurized image pyramid
- 上图左一
- 本质:将同一张图片resize到多个尺寸,分别进行检测。
- 优点:性能强。
- 缺点:需要的计算量大。
- Single feature map
- 上图中
- 本质:获取多个尺寸特征图,多个特征图分别进行检测。
- 举例:SSD。
- 优点:计算速度快。
- 缺点:最终效果一般。
- Pyramidal feature hierarchy
- 上图右
- 本质:只对一个特征图进行检测。
- 举例:Faster R-CNN。
- 优点:计算速度快。
- 缺点:效果一般。
- Feature Pyramid Network
- 上图
- 本质:获取多个特征图(不是像SSD那样简单的通过Conv获取,而是多层特征图融合)。
- 优点:计算速度快、性能好(相比于SSD、Faster R-CNN)。
- Feature Pyramid 的实现细节如下图所示。
2. FPN TensorFlow Eager 实现细节
- FPN是建立在Faster R-CNN的基础上,所以这里主要介绍FPN与Faster R-CNN之间的区别。
2.1. Feature Map
- Faster R-CNN:只输出一张特征图。
- FPN:生成多张特征图(5张特征图)。
- 思考:本质就是实现论文中Feature Pyramid Network结构。
- 遇到的问题一:
- 问题描述:使用
tf.keras
建立模型时,习惯使用的函数式API不能解决在upsample的过程中通过tf.shape
指定目标shape的问题。- 上述upsample的方法包括
tf.image.resize_bilinear
以及tf.keras.layers.UpSampling2D
。 - 为了使用函数式API研究了好久,什么tensorflow v1.12中存在XXX bug,所以需要使用v1.13(我也不升级版本后是否真能解决这个问题)。v1.13版本需要CUDA10支持,而服务器是多人使用,也不敢自作主张升级CUDA,加上linux水平有限,也没仔细研究有没有解决方案。
- 上述upsample的方法包括
- 问题解决:使用
tf.keras
中另外一种定义模型的方式,定义tf.keras.Model
的子类,在构造函数中定义所有使用到的layers,重写__call__
方法,完成模型构建。- 这种方法定义模型其实本来就会,开始就是偷懒,函数式API构造起来比较方便,这种方式写起来比较麻烦……
- 问题描述:使用
- 遇到的问题二:
- 这个就比较坑了……真的没想到……
slim
中实现的 resnet v1 结构与keras_applications
中的 resnet v1 的结构并不一样……- 不同之处:
- slim的
bottleneck
结构中使用了resnet_utils.conv2d_same
,而该函数与普通的padding为same
的卷基层并不完全一致。 - slim与keras都构建了由多个
bottleneck
线性连接组成的stack
结构,stack
结构可指定参数stride
。其中,slim中指定的stride作用于stack
的最后一个bottleneck
;keras中指定的stride作用于stack
的第一个bottleneck
。
- slim的
- 看上面的描述可能有点晕,其实问题不大……两个结构用于训练都能得到差不多的效果。
- 我碰到这个问题主要因为,参考的源码
FPN_Tensorflow
使用了slim构建resnet,而自己使用tf.keras。当希望将FPN_Tensorflow
的预训练模型导入自己复现的模型时,由于resnet实现的差异导致导入后模型训练结果非常差……
2.2. Anchros
- Faster R-CNN:输入一张特征图,输出anchros结果。
- FPN:输入若干特征图,分别获取每张特征图对应的anchors,将所有anchors拼接得到最终结果。
2.3. RPN Head
- Faster R-CNN:输入一张特征图,输出 rpn score 以及 rpn pred bbox 结果。
- FPN:输入若干特征图,分别获取每张特征图对应的 rpn score 以及 rpn pred bbox ,将所有rpn score 以及 rpn pred bbox 分别拼接得到最终结果。
2.4. ROI Pooling
- Faster R-CNN:在同一张特征图上进行 ROI Pooling操作。
- FPN:需要在多张特征图上进行ROI Pooling操作。
- 具体每个roi与哪张特征图对应,则通过论文中给出的公式计算得到。公式具体计算的细节就不展开了,看论文吧。
2.5. 其他操作
- 其他操作包括:Region Proposal, Anchor Target, Proposal Target 以及识别网络中最终的 Roi Head 结果。
- 这些操作与Faster R-CNN完全相同……
3. 后记(碎碎念,记录心情,请跳过)
- 实现Faster R-CNN花了几个月,实现FPN就只需要不到一周了,美滋滋……
- 前两天定位了一个内存泄漏的BUG……这个BUG导致之前都不在稍大的数据集上(VOC Pascal 2007 & 2012, COCO)训练模型。这个BUG解决了,终于可以在更多数据集上训练了。
- 下一步就是实现梦寐以求的Mask R-CNN了,重要快要追上最新的研究了……
- 然而,复现的运行效率实在不行训练时,TODO list上就有性能调优。
- 训练时间开始边长了(Pascal VOC 2007 训练FPN-Renset50需要30小时左右,那如果训练COCO的话……),要考虑实现多GPU版本了。