为何会转战深度学习目标检测算法? 

博主目前在研究计算机视觉的车牌识别项目, 以前使用OpenCV里的LBP Cascade classifier进行目标定位, 发现效果不算太完美, 有时车牌定位不出来, 有时顺带定位出许多不是车牌的部分.  增加了1000多张车牌数据集重新训练cascade classifier, 效果改变不是特别大.   为了确保至少要将车牌区域选出来, 要调整相关detectMultiScale的scaleFactor, minNeighbors参数.

Python: cv2.CascadeClassifier.detectMultiScale(image[, scaleFactor[, minNeighbors[,
flags[, minSize[, maxSize]]]]]) → objects


  • scaleFactor – Parameter specifying how much the image size is reduced at each image scale.
  • minNeighbors – Parameter specifying how many neighbors each candidate rectangle should have to retain it.

eg.

难以避免也会将无关区域也选出, 只有这样, 才能增加车牌区域被选出来的概率.  倘若不多选一些区域, 也许车牌区域就无法被筛选出来.  这种方法, 能定位到车牌的概率挺高, 博主做了统计, 可以达到94% 左右.  缺点是若候选区增多, 速度慢, 且无关区域也变多. 例如, 欲选出车牌区域, 还会附带选出20多个不是车牌的区域(false positives) .  大大降低OCR效率. 

车牌定位正常的图片居多, 但也有少数图片定位不出车牌. 专门把定位不出来的车牌照片挑出来, 设置了2组不同minNeighbors参数做试验对比.  minNeighbors = 0 , 与minNeighbors = 5,  在minNeighbors = 5定位不到的情况下, minNeighbors = 0 定位得到, 但是除此之外, 无关区域太多, 且重叠的框很多.

以上是试验, 下面详细分析一下minNeighbors 这个参数. minNeighbors 表示构成检测目标的相邻矩形的最小个数(默认为3个).如果组成检测目标的小矩形的个数和小于 minNeighbors - 1 都会被排除。如果minNeighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框. 但是别把minNeighbors调太大, 太大连正确的正样本都会被消除.

LBP Cascade classifier 使用滑动窗口以及图像金字塔获得多尺度候选区域, 图像金字塔, 即把图像进行多尺度放缩scaleFactor参数就是这个作用, 使滑动窗口在每一层上滑动, 这个方法的最大优点就是漏检率极低,因为它会对整幅图像都滑动,不会漏掉任何一个可能会目标区域的位置。但是这种优势,是用巨大的搜索空间和时间消耗换来的,检测效率自然会受到较大的影响.  这种方法属于传统计算机视觉的方法, 常用于人脸识别应用场景, 生成候选区域比较耗时. 下图是sliding window 的方式演示.

目标检测算法: 对Faster RCNN论文的理解与实践


切入正题:

由于目标检测对后续的OCR至关重要, 准确快速定位出来, 减少一些错误定位, 也能节省车牌识别整个流程的时间. 博主做了些目标检测算法的综述, 发现应用深度学习神经网络来做定位,能比传统机器学习方法优秀不少, 能做到更准确快速. 目前最优秀的目标检测方法是, RCNN一系列方法.

基于深度学习的目标检测,发展路径大致分两类, 一类是带有Region Proposal, 依次经过RCNN - FAST RCNN - FASTER RCNN - MASK RCNN发展. 一类是without Region Proposal, 这一类有SSD, YOLO. 其中Faster RCNN, 在目标检测领域得到了很多应用,  较为成熟, 有在卫星地图下的地形目标检测, 有人脸检测, 细胞检测等等, 效果卓越. 由于MASK -RCNN较新(其实最优秀, 最准确最快速), 但所能利用的资料不如FASTER RCNN多, 博主决定先将FASTER RCNN算法, 应用到车牌识别场景中. 

由于手头没有可用GPU, 因此需要在CPU下训练,  原论文给的官方代码是Matlab版的, 以及RBG写的python版, 但都是GPU环境下的训练. 因此需要改动代码, 适应在CPU下跑.  这里在CPU下跑faster rcnn有很多坑, 专门开一个博客写这些坑.  包括配置caffe的问题, 如何准备自己的数据集等等.

博主的思路是, 在自己的电脑上跑通一遍小数据量, 小迭代次数的faster rcnn的训练, 排除一些可能遇到的问题, 填坑之后挂在到云服务器上进行训练.  可惜华为云的GPU只支持WIN系统. Win系统不太适合开发啊, 肺腑之言. 博主本科期间Win配置VS, OpenCV耗费很长时间, 且卒.  而Linux 几句命令就能搞定.

于是那就用CPU 吧, 也搜索了一波国内云服务, 阿里比较成熟. 阿里云的GPU支持各种主流系统, Windows, Linux ubuntu, Linux CentOS等等.  到后来, 训练出一个模型之后(不太成熟, 但有点效果), 发现CPU训练跑不动, 还是需要GPU.

放个跑通Faster RCNN demo 测试图:

目标检测算法: 对Faster RCNN论文的理解与实践

这里解释一个概念, 也是我一开始容易混淆的, 目标定位与目标检测的区别,  引用CS231n课内容.

目标定位: 只针对一类目标, 在一张图片中找出某一类目标的位置, 比如dog在哪,  输出4个坐标.

目标检测: 针对多类别目标, 如上图demo所示, 在一张图片中, 找到好几种类目标, 如dog, horse, car, person, 并分别确定出位置.

论文解读:

论文传送门:

论文标题: Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks

论文地址: https://arxiv.org/abs/1506.01497 

Faster RCNN 大致思路是试用RPN(Region  Proposal Networks) 可以筛选出一些高概率可能是目标区域的地方, 以供CNN进行分类. 这一步大大减少了sliding window 在整张图片漫无目的搜索的繁琐.  Faster RCNN 由两部分组成, 第一部分是RPN网络,  产生Proposed Region. 第二部分是Fast RCNN detector, 利用这些proposed region做检测与分类. Faster RCNN的结构如下图所示: 

目标检测算法: 对Faster RCNN论文的理解与实践

以VGG模型为例, Faster RCNN的整个流程如下所示, 可以参照caffe文件, 对照着理解.

/py-faster-rcnn/models/pascal_voc/ZF/faster_rcnn_alt_opt/faster_rcnn_test.pt         

目标检测算法: 对Faster RCNN论文的理解与实践

1. Region Proposal Networks:

Region Proposal Networks(RPN) 起一个"attention"作用, 生成一些建议区域, 让Fast RCNN 集中检测这些区域.  这里简要介绍一下, Faster RCNN 为何会推出Region Proposal Networks这个想法, 在RCNN, Fast RCNN中, 使用slective search的方式生成proposed region. 于是, 想要再缩短点检测时间, 能否把slective search也省略掉, 而使用与fast rcnn共用的神经网络来起到propose region的作用呢?  于是在Faster RCNN 使用了RPN, 一个共用的神经网络来产生建议区域就是这个作用.  

RPN的主要流程概括一下:

生成anchors -> softmax分类器提取foreground anchors -> bbox reg回归foreground anchors -> Proposal Layer生成proposals. RPN的流程如下所示, 上面一条线路是分类作用(cls), 下面一条线路是bounding box regression作用(reg).

目标检测算法: 对Faster RCNN论文的理解与实践  

1.1 Anchor

在最后一层卷积后得到的feature maps上, 滑动sliding window(一层小型网络). 每个sliding window 映射一个低维向量, ZF网络是 256-d,  相当于, feature map上每个点都对应256张特征图, 每个点都是256-dimensions. 

256-d是怎么来的呢?  256-d是什么意思?

论文的图示使用的是zf网络,我们可以查看一下源码中层的信息, 辅助理解论文.

/py-faster-rcnn/models/pascal_voc/ZF/faster_rcnn_alt_opt/faster_rcnn_test.pt         

layer {
  name: "conv5"
  type: "Convolution"
  bottom: "conv4"
  top: "conv5"
  convolution_param {
    num_output: 256
    kernel_size: 3
    pad: 1
    stride: 1
  }
}
layer {
  name: "relu5"
  type: "ReLU"
  bottom: "conv5"
  top: "conv5"
}

#========= RPN ============


layer {
name: "rpn_conv1"
type: "Convolution"
bottom: "conv5"
top: "rpn_conv1"
convolution_param {
num_output: 256
kernel_size: 3 pad: 1 stride: 1
}
}

可以看到conv5输出256维度, 这个也是RPN第一层的输入. 所以意味着生成了256张feature maps. 在这里我的理解是, 用256个 256*3*3 的kernel去滑动,  会形成新的256张叠起来的feature map, 如果每张feature map是 w*h, 则可以看做w*h个256维向量. 此处的特征向量和线性代数里的特征向量不是同一个概念.

目标检测算法: 对Faster RCNN论文的理解与实践

这个向量输出给两个并行的全连接层, box 回归层(reg)和box分类层(cls). 

在feature map上 每个像素点都是anchor的中心, 会生成3种尺度大小(128^2, 256^2, 512^2), 每种尺度大小又带有3种比例(1:1, 1:2, 2:1), 总共3*3 = 9 种建议区域框, 即anchor.  feature map上每个点对应K个anchors, 对应2k个scores(object or not object), 4k个坐标. 如果feature 是 W*H, 则总共有W*H*k个anchor, 这里k=9.  

这些anchor不是产生在feature map 上, 而是产生在原图上. 这里feature map 每一点, 映射到原图就是一小块区域. 以原图上这个区域中心作为anchor 中心, 生成k个anchor box. 但并不是所有的anchor box都用来训练, 最后会随机抽样选取256个anchor box进行训练, 其中128个positive anchors, 128个negative anchors. 这些预测检测框之后还会经过bounding box regression, 进行微调, 使之更加靠近目标区域.

目标检测算法: 对Faster RCNN论文的理解与实践

RPN用multiple references, 即不同尺度不同比例的建议框, 代替了图像金字塔方法, 以及filter金字塔的方法, 可以多尺度地在图像中检测目标. 如下图, 图(a)展示了图像金字塔, 图(b)展示了, 卷积核金字塔, 图(c)即本文使用的multiple references, 即pyramid of anchor.

目标检测算法: 对Faster RCNN论文的理解与实践

这种anchor 具有图像平移不变性.  在计算机视觉中, 所谓的平移不变性, 即目标发生平移, 依旧会被识别为某一类物体, 不会随着平移而识别成其他新的物体. 在本论文中, 就是随着目标的平移, 这些建议区域框也会跟着平移. 放张图片, 举个平移不变性图例.

1.2 Loss Function

1.21 IoU

先介绍一下, Intersection-over-Union (IoU). 引用Coursera deep learning的材料, 如下:

目标检测算法: 对Faster RCNN论文的理解与实践

IoU 就是产生的候选框(predicted bounding box)与原标注框(ground-truth  bounding box)的重叠率. IoU越高, 则定位效果越好. IoU的公式如下, 例如求area C 和 area G的IoU:

目标检测算法: 对Faster RCNN论文的理解与实践

正样本(positive label)的筛选规则: 

1. 一个ground-truth box也许会有多个anchor 与之有交叠, 则筛选出与ground-truth box具有相对最高IoU值的anchor;

2. anchor box 与ground-truth box的IoU > 0.7, 则被筛选出来.

大部分情况, 只要第二条规则就足够, 但需要第一条规则, 是为了在第二条规则找不到正样本的情况下, 放宽条件, 保留anchor和ground-truth box IoU值最高的那个anchor.

负样本筛选规则:

1. anchor box 与ground-truth box的IoU <0.3 的所有anchor.

如果也不是正样本也不是负样本的anchor, 则不参与训练. 

此外, IoU的思想也能用来衡量两个预测框的重叠程度.


1.22 Bounding Box Regression

目的: 用bounding box regression来微调anchor位置, 使之产生的建议框更接近目标区域.  

为什么要使用bounding box regression?  

给出下面这张图示,  绿色是ground-truth box, 红色的是region proposal networks产生的建议区域.  即使红色建议区域被分类器分类为飞机, 但是红色区域与绿色ground-truth box 的IoU <0.5, 仍然会被认为目标检测有误. 因此需要对RPN产生的建议区域做微调(平移与放大). 在Faster RCNN中, 用了两次bounding box regression. 在RCNN系列目标检测算法里(RCNN, FAST RCNN, FASTER RCNN) 都用到了bounding box regression.

目标检测算法: 对Faster RCNN论文的理解与实践

对于一个框, (x, y, w, h)四个参数能够确定一个窗口,  x, y是框中心坐标, w, h是宽高. 我们用A表示anchor box,  anchor A = (Ax, Ay, Aw, Ah), G表示ground-truth box, G = (Gx, Gy, Gw, Gh), G'是经过微调后的预测框G' = (G'x, G'y, G'w, G'h).  预找到一个函数关系, 使F(Ax, Ay, Aw, Ah)=(G'x, G'y, G'w, G'h)≈(Gx, Gy, Gw, Gh). 

目标检测算法: 对Faster RCNN论文的理解与实践

那么怎么从A变到G'呢? 可以采取如下思路, 先平移, 后放缩.

1. 平移

目标检测算法: 对Faster RCNN论文的理解与实践 

2. 放缩

目标检测算法: 对Faster RCNN论文的理解与实践

需要学习的是dx(A), dy(A), dw(A), dh(A)四个变换. 前两个是尺度不变平移变换, 后两个是尺度缩放变换. 需要注意的是: 只有当anchor box 与 Ground-truth box 比较接近, 例如RCNN(IoU >0.6), 才可以近似看成是线性变换.  在本论文, 是在anchor box和Ground-truth box很接近的情况下, 所以可以当做是线性变换. 假设Y≈WX,  学习一组参数W, 使得经过线性回归之后, 预测框G'与G非常接近.

目标检测算法: 对Faster RCNN论文的理解与实践

然而在这里, 函数的输入不是简单的A(Ax, Ay, Aw, Ah), 而是anchor 对应的feature map 上的特征向量, 记为Φ(A),  函数的输出是dx(A), dy(A), dw(A), dh(A)这四个变换, 记为d*(A),  *表示 x,y,w,h,也就是每一个变换对应一个上述目标函数, 有了这4个变换, 我们就能找到G'框. 这里经过dx(A), dy(A), dw(A), dh(A) 变换后得到的是接近G的G', 而不是G(ground-truth box).

这里解释一下真实值t*=(tx, ty, tw, th), t*也就是把A移动到G(Ground truth box), 所需要的变化称为真实值. 可以参照上面平移放缩这四个公式, 反着推导出dx(A), dy(A), dw(A), dh(A), 这里的tx, ty, tw, th也是这样得出, 对应于faster rcnn论文里公式(2)的tx*, ty*, tw*, th* , 只是我用的标记方式不同. 

目标检测算法: 对Faster RCNN论文的理解与实践 

 所以这里, 我们要让预测出来的预测值d*(A)(*表示 x,y,w,h), 最接近这四个真实值.  这里就用到了损失函数的概念. 设计一个损失函数如下:

目标检测算法: 对Faster RCNN论文的理解与实践

求minLoss时, 对应的4个w*, 则可以求出最靠近ground truth box最好的四个变换.

函数的优化目标为: 

目标检测算法: 对Faster RCNN论文的理解与实践

可以利用梯度下降法求出w*. 

Faster RCNN 的bounding box regression 与RCNN, Fast RCNN的bounding box regression 有什么区别?

FASTER RCNN 的Φ(A)是来自anchor对应的feature map上某一点的特征向量,而RCNN, FAST RCNN的Φ(A)是来自于RoI对应的特征向量.

1.23 RPN中Multi-task Loss

这也是RPN 中总的loss function, 把cls, reg都包含进来.

目标检测算法: 对Faster RCNN论文的理解与实践

下标i表示minibatch中, anchor的下标. pi表示anchor i是目标区域的概率, (经过cls生成得分, 分别是object的概率和not object的概率), 如果是正样本pi* = 1,  如果是负样本, pi* = 0. 从上面公式可以看出, 当pi* = 1时, 公式后半项才被**. ti表示anchor box 回归到预测框所需要的4个平移缩放变换参数, ti*表示anchor box 回归到ground-truth box所需要的4个平移缩放变换参数.

Lcls的定义如下:

目标检测算法: 对Faster RCNN论文的理解与实践

Lreg的定义如下:

目标检测算法: 对Faster RCNN论文的理解与实践

R函数定义如下:

目标检测算法: 对Faster RCNN论文的理解与实践

 λ = 10 , Ncls = 256, Nreg = 2400. 论文说这三个参数不是很重要.

1.3 softmax

 RPN使用softmax layer进行分类, 分出是object还是not object两类. softmax的作用是输出多类得分, 每一类得分是一个0~1之间的数值, 所有类的得分数值和 sum = 1, 因此可以当成输入X被分类为某一类的概率, 拿mnist手写字符识别例子打比方, 如果y = 0的概率是0.88, y= 1 的概率是 0.10, y= 2 的概率是0.02, 则这个输入字符更被分类成数字0的概率最大. 这里引用一张coursera deep learning 的课件. 也当做是做记录, 以后自己如果需要用到, 回来回顾一下, 给自己看.

目标检测算法: 对Faster RCNN论文的理解与实践

为什么softmax layer 前后要进行reshape呢?  目的在于便于分类.  在caffe基本数据结构blob中以如下形式保存数据:

blob=[batch_size, channel,height,width]

进入RPN时, 图像已经变成了W x H x256 , 其中 W = M/16, H=N/16 (VGG16模型经过4次pooling 层后的作用), 在进入第一次reshape之前, 输入图像是(M/16) x (N/16) x 18, 18d的,  18代表2类(fg, bg)*9个anchor, 具体可见源码中层信息:

本文主要以VGG16 模型说例

搭配caffe文件./py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt 


layer {
name: "rpn_cls_score"
type: "Convolution"
bottom: "rpn/output"
top: "rpn_cls_score"
convolution_param {
num_output: 18 # 2(bg/fg) * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
}
}


所以blob = [1, 2*9, H,  W], 为了softmax方便, reshape成 blob=[1, 2, 9*H, W], 不影响数据的保存, 因此之后还要再reshape回来.

1.4 Proposal layer

 经过bounding box regression 以后, 通过如上公式学习得到dx(a), dy(a), dw(a), dh(a) 4个变换. Proposal layer 的作用就是把这4个变换, 以及经过softmax 分类后得到的foreground anchor 进行综合, 微调anchor, 得到更精确的 anchor box.  送入RoI pooling.

根据RPN的流程图, 可以看到proposal 有三个输入,  一个是softmax 产生的foreground anchor, 一个是bounding box regression 得到的4个变换,  dx(A), dy(A), dw(A), dh(A), 一个是im_info, im_info保存了原图片进入faster rcnn时的放缩信息, 见Faster RCNN 全流程图, P x Q resize 成 MxN. im_info = [M, N, scale_factor].

查看源码./py-faster-rcnn/lib/rpn/proposal_layer.py,  官方源代码写的比较清晰, proposal layer 的主要功能:


def forward(self, bottom, top):
# Algorithm:
#
# for each (H, W) location i
# generate A anchor boxes centered on cell i
# apply predicted bbox deltas at cell i to each of the A anchors
# clip predicted boxes to image
# remove predicted boxes with either height or width < threshold
# sort all (proposal, score) pairs by score from highest to lowest
# take top pre_nms_topN proposals before NMS
# apply NMS with threshold 0.7 to remaining proposals
# take after_nms_topN proposals after NMS
# return the top proposals (-> RoIs top, scores top)


1. 结合bounding box regression 的4个变换偏移anchor, 产生Proposal

2. 将proposal 限制在原图像之内

3. 移除宽和高都< threshold的预测框

4. 将proposal box 按score 从高到低排序

5. 取前pre_nms_topN 个proposal box

6. NMS非极大值抑制, threshold = 0.7

7. NMS, 之后, 再次排序, 提取前after_nms_topN (e.g. 300) 个 proposals

8. 输出给RoI pooling.

再搭配caffe文件./py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt         , 看一下这一层结构:

layer {
name: 'proposal'
type: 'Python'
bottom: 'rpn_cls_prob_reshape'
bottom: 'rpn_bbox_pred'
bottom: 'im_info'
top: 'rois'
python_param {
module: 'rpn.proposal_layer'
layer: 'ProposalLayer'
param_str: "'feat_stride': 16"
}
}


有三个输入, rpn_cls_prob_reshape是softmax 后reshape的输出, 分类出foreground anchors,  rpn_bbox_pred是bounding box regression 的4个回归变换量, im_info是输入图片resize后的信息.  上文已经说过.  feat_stride是计算偏移量时使用, 把feature map上的点映射回到M x N 图上.

1.41 NMS的概念:

NMS主要作用是消除多余窗口. 例如人脸识别, 每张人脸可能对应好几个框, 每个框都带有一个得分. 步骤:

1. 将所有的框按得分排序, 选出得分最高的框.

2. 遍历剩余的框, 当与得分最高框的IoU > threshold(eg. 0.7), 则删除.

3. 再未处理的框中, 重新按得分排序, 不断重复1.2步, 直到找到最佳框.

目标检测算法: 对Faster RCNN论文的理解与实践

目标检测算法: 对Faster RCNN论文的理解与实践

目标检测算法: 对Faster RCNN论文的理解与实践


1.42 综上总结一下RPN的优势:

本博客开头提到的使用传统CV目标检测方法LBP cascade classifier暴露的问题, 是来自实践经验, 经过多次调参试验得到, 滑动窗口+图像金字塔, 导致效率很低.  接下来给出理论分析, 传统方法对整张图片进行滑动窗口判断, 由于不知道目标的尺度大小, 需要经过一次次的放缩图像, 每一次放缩都进行滑窗检测, 找到目标区域就很慢. RPN虽然也使用滑窗, 但是是在feature map上进行滑动, feature map 相对于原始图像而言, 尺度降低了很多, 如果输入图片resize 后是是MxN, 则输入RPN的feature map 是256 x (M/16) x (N/16).  RPN除了产生9种anchor区域以外, 还会有bounding box regression, 能够回归到更接近目标区域的位置. 除此之外, 对比RCNN, FAST RCNN, 使用共享网络来实现产生建议区域功能. 减小模型大小.

2. Detection Network: Fast RCNN 

至此,以上已经完成了RPN部分,其实已经完成了初步的定位,接下来是Detection部分,即Fast RCNN部分.

Fast RCNN的结构如下:

目标检测算法: 对Faster RCNN论文的理解与实践

2.1 RoI Pooling

 为什么需要RoI pooling?

RoI(Region of interest)是原图上的候选框, 映射回feature map 上, 对应的区域.  在原图上有大大小小不同的proposals,  则映射回*feature map上, RoI 尺度大小也就不同. RoI polling 的目的就是要把不同大小的RoI 调整到固定的尺寸(eg. 7*7),再经过全连接层,转换成固定维度的特征向量,用于最后的分类和回归.

这样做有利于做分类(博主的理解是,固定维度的特征向量可以对应不同了类别的概率,例如minist手写字符分类,经过全连接层后的输出是0-9,10类数字的概率,最有可能的数字类别就是概率最高的那类).倘若没有RoI pooling,则proposals映射回feature map是大小不同的roi区域,经过全连接层后,得到新的特征向量维度也不同,不好用同样的分类器分类.

这里引用微信公众号: 懒人学AI  的说明图来讲解. 

 目标检测算法: 对Faster RCNN论文的理解与实践


目标检测算法: 对Faster RCNN论文的理解与实践

下图说明就是把RoI pooling成2*2尺寸

图片来自于: https://blog.deepsense.ai/region-of-interest-pooling-explained/

目标检测算法: 对Faster RCNN论文的理解与实践


2.2 分类与回归

最后,output送入全连接层,转成固定维度的特征向量,特征向量再分别经过两个全连接层,一个用于softmax分类(多类分类,比如人,狗,车等等),一个再次利用bounding box regression获得proposal的偏移,再次进行回归.参照如上Fast RCNN的结构图,以及如下示意图进行理解.

目标检测算法: 对Faster RCNN论文的理解与实践


3 训练

在论文中采取的是交替训练

相关文章:

  • 2021-12-29
  • 2021-09-17
  • 2022-01-05
  • 2021-09-03
  • 2021-08-10
  • 2021-12-22
  • 2021-05-19
  • 2021-09-10
猜你喜欢
  • 2021-11-14
  • 2021-09-01
  • 2022-12-23
  • 2021-07-02
  • 2021-07-06
相关资源
相似解决方案