目标检测, 即在一幅图里框出某个目标位置. 有 2 个任务.
定位出目标的边界框
识别出边界框内的物体的类别
Sliding-Windows detectors
一种暴力的目标检测方法就是使用滑动窗口, 从左到右, 从上到下扫描图片, 然后用分类器识别窗口中的目标. 为了检测出不同的目标, 或者同一目标但大小不同, 必须使用不同大小, 不同宽高比的滑动窗口.
把滑动窗口框出来的图片块 resize(因为很多分类器只接受固定大小的图片输入)后, 送给 CNN 分类器, CNN 提取出 4096 个特征. 然后使用 SVM 做分类, 用线性回归做 bounding box 预测.
伪代码如下
- for Windows in Windows
- patch = get_patch(image, Windows)
- results = detector(patch)
提高性能的一个明显的方法就是减少 Windows 数量.
Selective Search
相比于暴力搜索, 我们使用一种区域建议 (region proposal) 方法去创建 roi(感兴趣区域 region of intrest). 在 selective search(SS)中, 我们从将每一个像素作为一个 group 开始, 接下来我们计算每一个 group 的 texture, 然后合并最接近的 group. 为例避免某个区域吞并了其他区域, 我们优先合并较小的 group, 不断的合并各个 group 直到不能再合并了. 如下图: 第一行图显示了 region 是怎么不断地增长的, 第二行的蓝色框显示了在不断地合并的过程里, 是怎么产生 ROI 的.
R-CNN
R-CNN 采取区域建议方法创建 2000 个 ROI. 然后这些区域的图片被送到 CNN, 提取特征, 然后送给全连接层做边界框预测和类别预测
流程如下:
由于有了数量少质量高的 ROI,R-CNN 相比于暴力的滑动窗口搜索, 要快的多, 也准确的多.
- ROIs = region_proposal(image)
- for ROI in ROIs
- patch = get_patch(image, ROI)
- results = detector(patch)
- Boundary box regressor
区域建议方法是需要大量算力的. 为了加速 ROI 寻找的过程, 我们往往选择一个不需要巨量算力的区域建议方法来创建 ROI, 再用线性回归器 (使用全连接层) 对边界框做微调.
Fast R-CNN
R-CNN 需要大量的 ROI, 并且这些 ROI 很多都是重叠的. 所以 R-CNN 在无论是训练还是推理都很慢. 如果我们有 2000 个建议区域, 每一个都要被 CNN 处理一次, 也就是说, 对于不同的 ROI, 特征提取重复了 2000 次.
换个思路, 对整幅图片做特征提取, 然后在特征图的基础上做 ROI 的查找. 通过池化层做 resize, 然后送给全连接层做边界框预测和分类. 由于只做了一次特征提取, Fast R-CNN 的性能显著提高.
流程如下:
伪代码如下:
- feature_maps = process(image)
- ROIs = region_proposal(image)
- for ROI in ROIs
- patch = roi_pooling(feature_maps, ROI)
- results = detector2(patch)
由于把特征提取这一步抽到了 for 循环外部, 性能大幅提升. 相比 R-CNN,Fast R-CNN 在训练上快了 10 倍, 推理上快了 150 倍.
Fast R-CNN 的一个要点是整个网络 (包括特征提取, 分类, 边界框回归) 是端到端的训练, 并且采用了 multi-task losses(分类 loss + 边界框定位 loss), 提高了准确率.
ROI pooling
由于 Fast R-CNN 使用全连接层, 我们采用 ROI 池化, 把不同 size 的 ROI 转换成固定 size.
以 8*8 的特征图转换为 2*2 为例
左上: CNN 得到的原始特征图
右上: 叠加蓝色的 ROI 到特征图上
左下: 将 ROI 分割成目标维度. 比如要转换成 2*2 的, 那我们把 ROI 分成 4 份, 每一份大小近似.
右下: 对每一份做 max pooling(即选出该部分最大的). 得到我们想要的 ROI 对应的特征图.
然后就可以把这些 2*2 的特征图送给分类器和线性回归器去做分类和边界框预测了.
Faster R-CNN
Fast R-CNN 依赖于区域建议方法, 比如 selective search. 但是, 这些算法只能跑在 CPU 上, 速度很慢. 在测试中, Fast R-CNN 做出一次预测要 2.3 秒, 其中 2 秒都花在了生成 2000 个 ROI.
- feature_maps = process(image)
- ROIs = region_proposal(image) # Expensive!
- for ROI in ROIs
- patch = roi_pooling(feature_maps, ROI)
- results = detector2(patch)
在流程上, Faster R-CNN 与 Fast R-CNN 是一致的, 只是将得到 ROI 的方式改为由一个 region proposal network(RPN)得到. RPN 效率要高的多, 每张图生成 ROI 的时间仅在 10ms.
Region proposal network
RPN 接受卷积网络输出的特征图作为输入, 用如下的 ZF 网络做区域建议. 也可以用其他的网络比如 VGG 或者 ResNet 去做更全面的特征提取, 代价是速度的下降. ZF 网络输出 256 个值, 送到两个全连接层, 一个用于预测边界框(boudary box), 一个用于预测 2 个 objectness scores.objectness 衡量 bounding box 是否包含一个 object. 我们可以用一个回归器去计算出一个 single objectness score. 但是为简单起见, Fast R-CNN 使用一个分类器, 分类器分出的类别有 2 种: 即包含目标和不包含.
对特征图中的每一个位置, RPN 做出 k 个猜测. 所以 RPN 输出 4*k 个坐标, 2*k 个 score. 如下表示对一个 8*8 的特征图, 用 3*3 的 filter, 最终得到 8*8*3 个 ROI.
后面我们将继续微调我们的猜测. 由于我们需要有一个正确的猜测, 我们初始化的猜测最好有不同的 shape, 不同的 size. 所以, Faster R-CNN 不是随机乱猜的边界框, 它预测相对于我们称之为 anchors 的参考框 (reference box) 左上角的偏移. 我们限定偏移的大小, 这样我们最终预测出的 bounding box 依然是与 anchors 类似的.
为了每个位置能够得到 k 个预测, 每个位置需要 k 个 anchor. 每一个预测都与一个特定的 anchor 有关. 不同的位置共享同样的 anchor shape.
这些 anchors 不是瞎选的, 要尽可能地覆盖到 real-life objects, 并且要尽量有合理的尺度和宽高比. 这样可以使得每次的 prediction 更准确. 这个策略使得训练的早期可以更容易更稳定.
Faster R-CNN uses far more anchors. It deploys 9 anchor boxes: 3 different scales at 3 different aspect ratio. Using 9 anchors per location, it generates 2 * 9 objectness scores and 4 * 9 coordinates per location.
Performance for R-CNN methods
Region-base Fully Convolutional Networks (R-FCN)
假设一下我们只有一个检测脸部中右眼的 feature map, 我们可以用它来定位整张脸吗? 答案是肯定的, 因为右眼位于面部的左上角, 所以我们可以用来定位整张脸.
如果我们有其他专门用于检测左眼, 鼻子或嘴巴的特征图, 我们可以将这些结果结合起来, 更好地定位人脸.
在 Faster R-CNN 中, 我们最终会将整幅图片的 feature map 切成相应的 roi 对应的 feature map, 再送给多个全连接层去做预测. 有 2000 个 ROI 的时候, 这一步的代价是很高昂的.
- feature_maps = process(image)
- ROIs = region_proposal(feature_maps)
- for ROI in ROIs
- patch = roi_pooling(feature_maps, ROI)
- class_scores, box = detector(patch) # Expensive!
- class_probabilities = softmax(class_scores)
R-FCN 通过减少每一个 roi 的处理时间提速. 下面是伪代码
- feature_maps = process(image)
- ROIs = region_proposal(feature_maps)
- score_maps = compute_score_map(feature_maps)
- for ROI in ROIs
- V = region_roi_pool(score_maps, ROI)
- class_scores, box = average(V) # Much simpler!
- class_probabilities = softmax(class_scores)
考虑一个 5*5 的 feature map, 其中蓝色部分的 feature 构成了我们想要检测的 object. 我们将蓝色部分划分为 3*3 的区域. 现在我们可以创建一个新的 feature map, 仅仅用来检测 object 的 top left corner(TL). 如下:
由于我们将 object 分成了 9 个部分, 我们从整幅图的 feature map 中得到 9 个 feature map, 每一个 feature map 负责检测 object 的相应区域. 这些 feature map 我们称之为 position-sensitive score maps, 因为每个 map 都只 detect(scores)一个 object 的子区域.
假设下图的红色虚线框是 ROI. 我们将其划分成 3*3 的区域, 然后考虑每个区域包含目标的对应位置的可能性. 例如, top-left ROI 区域包含左眼的可能. 我们把结果存储在一个 3*3 的 vote array 里. 比如, vote_array[0][0]存储了一个 score, 表示我们是否发现了目标的 top-left region.
这个依据 score map 和 ROI 得到 vote array 的过程称之为 position-sensitive ROI-pool. 这个过程和前文提过的 ROI pool 很类似.
计算出所有的值以后, 取平均, 就得到了 class score.
假设我们有 C 种目标待检测. 我们扩展为 C+1 种, 即包含一种 class for the background(non-object). 每一种目标都有自己的 3*3 个 score map. 所以一共有(C+1)*3*3 个 score maps. 使用这些 score maps 我们可以为每一个类别都算出一个 class score. 然后用 softmax 可以计算出每一个类别的 class probability.
整体流程如下, 下图中 k=3.
R-FCN 的一个示例
原文 link:https://medium.com/@jonathan_hui/what-do-we-learn-from-region-based-object-detectors-faster-r-cnn-r-fcn-fpn-7e354377a7c9
来源: https://www.cnblogs.com/sdu20112013/p/11022480.html