2D 目标检测
目录
简介
基础
目录:
IOU
定义:
numpy实现
import numpy as np
def compute_iou(box1, box2, wh=False):
"""
compute the iou of two boxes.
Args:
box1, box2: [xmin, ymin, xmax, ymax] (wh=False) or [xcenter, ycenter, w, h] (wh=True)
wh: the format of coordinate.
Return:
iou: iou of box1 and box2.
"""
if wh == False:
xmin1, ymin1, xmax1, ymax1 = box1
xmin2, ymin2, xmax2, ymax2 = box2
else:
xmin1, ymin1 = int(box1[0]-box1[2]/2.0), int(box1[1]-box1[3]/2.0)
xmax1, ymax1 = int(box1[0]+box1[2]/2.0), int(box1[1]+box1[3]/2.0)
xmin2, ymin2 = int(box2[0]-box2[2]/2.0), int(box2[1]-box2[3]/2.0)
xmax2, ymax2 = int(box2[0]+box2[2]/2.0), int(box2[1]+box2[3]/2.0)
## 获取矩形框交集对应的左上角和右下角的坐标(intersection)
xx1 = np.max([xmin1, xmin2])
yy1 = np.max([ymin1, ymin2])
xx2 = np.min([xmax1, xmax2])
yy2 = np.min([ymax1, ymax2])
## 计算两个矩形框面积
area1 = (xmax1-xmin1) * (ymax1-ymin1)
area2 = (xmax2-xmin2) * (ymax2-ymin2)
inter_area = (np.max([0, xx2-xx1])) * (np.max([0, yy2-yy1]))#计算交集面积
iou = inter_area / (area1+area2-inter_area+1e-6)#计算交并比
return iou
重点是:
xx1 = np.max([xmin1, xmin2])
yy1 = np.max([ymin1, ymin2])
xx2 = np.min([xmax1, xmax2])
yy2 = np.min([ymax1, ymax2])NMS
参考:https://zhuanlan.zhihu.com/p/78504109
定义:
非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素,可以理解为局部最大搜索。
Why:
目标检测的输出个数是未知的,除了Ground-Truth(标注数据)训练,模型永远无法百分百确信自己要在一张图上预测多少物体。
目标检测中,模型往往会提出远高于实际数量的区域提议, 模型的输出边界框往往是堆叠在一起的。因此,我们需要NMS从堆叠的边框中挑出最好的那个。
When:
NMS使用在回归边框之后,即所有的框已经被分类且精修了位置。且所有区域提议的预测结果已经由置信度与阈值初步筛选之后。
How:
最大的置信度B_BOX为局部最大值,与其 IOU > 阈值的 Box 是它的局部比较对象要被抑制。
算法输入
算法对一幅图产生的所有的候选框,每个框有坐标与对应的打分(置信度)。
如一组5维数组:
- 每个组表明一个边框,组数是待处理边框数
- 4个数表示框的坐标:X_max,X_min,Y_max,Y_min
- 1个数表示对应分类下的置信度
注意:每次输入的不是一张图所有的边框,而是一张图中属于某个类的所有边框(因此极端情况下,若所有框的都被判断为背景类,则NMS不执行;反之若存在物体类边框,那么有多少类物体则分别执行多少次NMS)。
除此之外还有一个自行设置的参数:阈值 TH
算法输出
输入的一个子集,同样是一组5维数组,表示筛选后的边界框。
算法流程
- 将所有的框按类别划分,并剔除背景类,因为无需NMS。
- 对每个物体类中的边界框(B_BOX),按照分类置信度降序排列。
- 在某一类中,选择置信度最高的边界框B_BOX1,将B_BOX1从输入列表中去除,并加入输出列表。
- 逐个计算B_BOX1与其余B_BOX2的交并比IoU,若IoU(B_BOX1,B_BOX2) > 阈值TH,则在输入去除B_BOX2。
- 重复步骤3~4,直到输入列表为空,完成一个物体类的遍历。
- 重复2~5,直到所有物体类的NMS处理完成。
- 输出列表,算法结束
Python 实现
注意,这里的NMS是单类别的!多类别则只需要在外加一个for循环遍历每个种类即可
def py_cpu_nms(dets, thresh):
"""Pure Python NMS baseline."""
#dets某个类的框,x1、y1、x2、y2、以及置信度score
#eg:dets为[[x1,y1,x2,y2,score],[x1,y1,y2,score]……]]
# thresh是IoU的阈值
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
scores = dets[:, 4]
#每一个检测框的面积,注意 + 1 先计算
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
#order是按照score降序排序的,得到的是排序的本来的索引,不是排完序的原数组
order = scores.argsort()[::-1]
keep = [] #保留的结果框集合
while order.size > 0:
i = order[0]
keep.append(i) #保留该类剩余box中得分最高的一个
#得到相交区域,左上及右下
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
#计算相交的面积,不重叠时面积为0,防止为负,照例+1
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
#计算IoU:重叠面积 /(面积1+面积2-重叠面积)
ovr = inter / (areas[i] + areas[order[1:]] - inter)
#保留IoU小于阈值的box
inds = np.where(ovr <= thresh)[0]
# 更新 order
# 因为ovr数组的长度比order数组少一个,所以这里要将所有下标后移一位
order = order[inds + 1]
return keep解释:
# [::-1] 取从后向前(相反)的元素
# [:-1] 除了最后一个取全部
# [2::-1] 取从下标0——2的元素翻转读取
# .argsort() np 的从小到大排序返回索引
order = scores.argsort()[::-1] # 降序从大到小排列
#计算当前概率最大矩形框与其他矩形框的相交框的坐标
# 由于numpy的broadcast机制,得到的是向量
#
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])
Soft-NMS
NMS存在问题
红色框和绿色框是当前的检测结果,二者的得分分别是0.95和0.80。如果按照传统的NMS进行处理,首先选中得分最高的红色框,然后绿色框就会因为与之重叠面积过大而被删掉。
另一方面,NMS的阈值也不太容易确定,设小了会出现下图的情况(绿色框因为和红色框重叠面积较大而被删掉),设置过高又容易增大误检。
Soft-NMS引入
思路:不要粗鲁地删除所有IOU大于阈值的框,而是降低其置信度。
soft NMS算法的大致思路为:M为当前得分最高框,bi 为待处理框,bi 和M的IOU越大,bi 的得分_si_ 就下降的越厉害。
确定函数:
NMS算法可以用下面的式子表示:
soft NMS中:
(1)线性加权:
(2)高斯加权:
但是上面这个公式是不连续的,这样会导致box集合中的score出现断层,因此就有了下面这个Soft NMS式子(也是大部分实验中采用的式子):
综上,soft-nms的核心就是降低置信度。比如一张人脸上有3个重叠的bounding box, 置信度分别为0.9, 0.7, 0.85 。选择得分最高的建议框,经过第一次处理过后,得分变成了0.9, 065, 0.55(此时将得分最高的保存在D中)。这时候再选择第二个bounding box作为得分最高的,处理后置信度分别为0.65, 0.45(这时候3个框也都还在),最后选择第三个,处理后得分不改变。最终经过soft-nms抑制后的三个框的置信度分别为0.9, 0.65, 0.45。最后设置阈值,将得分si小于阈值的去掉。
多尺度
FPN 特征金字塔
实现细节:https://zhuanlan.zhihu.com/p/35854548
简介
FPN是一个多尺度物体检测特征提取方法,然而大尺寸的物体检测效果一直比较理想,所以FPN主要大幅提升了小像素目标检测的效果。
思想:
把高层的特征传下来,补充低层的语义,这样就可以获得高分辨率、强语义的特征,有利于小目标的检测。
# 先从 resnet 抽取四个不同阶段的特征图 C2-C5。
_, C2, C3, C4, C5 =
resnet_graph(input_image, config.BACKBONE,stage5=True, train_bn=config.TRAIN_BN)
# Top-down Layers 构建自上而下的网络结构
# 从 C5开始处理,先卷积来转换特征图尺寸
P5 = KL.Conv2D(256, (1, 1), name=\'fpn_c5p5\')(C5)
# 上采样之后的P5和卷积之后的 C4像素相加得到 P4,后续的过程就类似了
P4 = KL.Add(name="fpn_p4add")([
KL.UpSampling2D(size=(2, 2), name="fpn_p5upsampled")(P5),
KL.Conv2D(256, (1, 1),name=\'fpn_c4p4\')(C4)])
P3 = KL.Add(name="fpn_p3add")([
KL.UpSampling2D(size=(2, 2), name="fpn_p4upsampled")(P4),
KL.Conv2D(256, (1, 1), name=\'fpn_c3p3\')(C3)])
P2 = KL.Add(name="fpn_p2add")([
KL.UpSampling2D(size=(2, 2),name="fpn_p3upsampled")(P3),
KL.Conv2D(256, (1, 1), name=\'fpn_c2p2\')(C2)])
# P2-P5最后又做了一次3*3的卷积,作用是消除上采样带来的混叠效应
# Attach 3x3 conv to all P layers to get the final feature maps.
P2 = KL.Conv2D(256, (3, 3), padding="SAME", name="fpn_p2")(P2)
P3 = KL.Conv2D(256, (3, 3), padding="SAME",name="fpn_p3")(P3)
P4 = KL.Conv2D(256, (3, 3), padding="SAME",name="fpn_p4")(P4)
P5 = KL.Conv2D(256, (3, 3), padding="SAME",name="fpn_p5")(P5)
# P6 is used for the 5th anchor scale in RPN. Generated by
# subsampling from P5 with stride of 2.
P6 = KL.MaxPooling2D(pool_size=(1, 1), strides=2,name="fpn_p6")(P5)
# 注意 P6是用在 RPN 目标区域提取网络里面的,而不是用在 FPN 网络
# Note that P6 is used in RPN, but not in the classifier heads.
rpn_feature_maps = [P2, P3, P4, P5, P6]
# 最后得到了5个融合了不同层级特征的特征图列表;细节理解
1、 怎么做的上采样?
C5是 resnet最顶层的输出,它会先通过一个1×1的卷积层,同时把通道数转为256,得到FPN 的最上面的一层 P5。 C5 -> P5 直接复制
这里的实现使用的是最简单的上采样,没有使用线性插值,没有使用反卷积,而是直接复制。
2、 怎么做的横向连接,横向连接的作用是什么?
像素加法 add, 不是Concate
4就是上采样之后的 P5加上1×1 卷积之后的 C4,这里的横向连接实际上就是像素加法,先把 P5和C4转换到一样的尺寸,再直接进行相加。
如果不进行特征的融合(也就是说去掉所有的1x1侧连接),虽然理论上分辨率没变,语义也增强了,但是AP下降了10%左右!作者认为这些特征上下采样太多次了,导致它们不适于定位。
3、特征融合为什么不用concate
简短地说:add等价于concat之后对应通道共享同一个卷积核,且add来替代concat,这样更节省参数和计算量(concat之后一般还要接卷积恢复维度)。
如果不在乎计算量且数据足够的时候,用concat也是可以的,因为这两个本身就是包含关系。实际上concat在skip connection里用的也比add更普遍,比如题主提到的U-Net[6]、DenseNet[7]。yolov3里就是concat,做concat操作的两层通道数不同
Add 也有缺点会带来信息损失。concate保留了信息。
4、为什么相加前要通过1×1的卷积层?
1x1的卷积我认为有三个作用:
1、使bottom-up对应层降维至256;
2、缓冲作用,防止梯度直接影响bottom-up主干网络,更稳定;
3、组合特征。
5、融合特征后为什么又使用了3×3卷积?
另外这里 P2-P5最后又做了一次3×3的卷积,作用是消除上采样带来的混叠效应。
6、上面得到的5个融合了不同层级的特征图怎么使用?
这里只使用P2-P5四个特征图,不同大小的ROI使用不同特征图ROIpooling。
7、如何确定某个 ROI 使用哪一层特征图进行 ROIpooling ?
不同尺度的ROI,使用不同特征层作为ROI pooling层的输入,大尺度ROI就用后面一些的金字塔层,比如P5;小尺度ROI就用前面一点的特征层,比如P4。
具体层级判断:
224是ImageNet的标准输入,k0是基准值,设置为5,代表P5层的输出(原图大小就用P5层),w和h是ROI区域的长和宽,image_area是输入图片的长乘以宽,即输入图片的面积,假设ROI是112 * 112的大小,那么k = k0-1 = 5-1 = 4,意味着该ROI应该使用P4的特征层。k值会做取整处理,防止结果不是整数。
FPN 的其他
BiFPN (也就是大名鼎鼎的 EfficientDet)
NAS-FPN
两阶段论文
简介:
先进行区域生成(region proposal,RP)(一个有可能包含待检物体的预选框),再通过卷积神经网络进行样本分类。
任务:特征提取—>生成RP—>分类/定位回归。
常见的two stage目标检测算法有:R-CNN、SPP-Net、Fast R-CNN、Faster R-CNN和R-FCN等。
Faster RCNN
By Shaoqing Ren, Kaiming He, Ross Girshick, and Jian Sun
参考 https://zhuanlan.zhihu.com/p/31426458
目录:
改进:
Faster RCNN则抛弃了传统的滑动窗口和Selective Search方法,直接使用RPN生成检测框。
系统框架:
详细结构:
四个主要部分:
- Conv layers。作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv+relu+pooling层提取image的feature maps。该feature maps被共享用于后续RPN层和全连接层。
- Region Proposal Networks。RPN网络用于生成region proposals。该层通过softmax判断anchors属于positive或者negative,再利用bounding box regression修正anchors获得精确的proposals。
- Roi Pooling。该层收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
- Classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。
Region Proposal Networks
其实RPN最终就是在原图尺度上,设置了密密麻麻的候选Anchor。然后用cnn去判断哪些Anchor是里面有目标的positive anchor,哪些是没目标的negative anchor。所以,仅仅是个二分类而已!
输入:feature maps
操作:
- 3x3的滑窗操作, 得到一个channel是256维的特征图,尺寸与input的特征图相同,维度是256HW。
- 两次1x1卷积操作,一个得到2k score, 一个得到4k coordinates。
上面一条通过softmax分类anchors获得positive和negative分类,下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的Proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。
anchors box
每次滑窗所划到的3x3的区域,就以该区域中心点为坐标,生成9个anchor
Anchor一共有多少个?原图800x600,VGG下采样16倍,feature map每个点设置9个Anchor,所以:
上文提到的k就是anchors的数量,所以2k个分数就是9个anchors的共18个分数,36个坐标。对于每个anchor, 计算anchor与ground-truth bounding boxes的IoU,大于0.7则判定为有目标,小于0.3则判定为背景,介于0.3-0.7,则设为0,不参与训练
positive和negative anchor 判定
推理时,采用 Softmax判断。
训练时:计算anchor与ground-truth bounding boxes的IoU,大于0.7则判定为有目标,小于0.3则判定为背景,介于0.3-0.7,则设为0,不参与训练。
补充:全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练
RPN的Loss
上述公式中 表示anchors index,
表示positive softmax probability,
代表对应的GT predict概率(即当第i个anchor与GT间IoU>0.7,认为是该anchor是positive,
;反之IoU<0.3时,认为是该anchor是negative,
;至于那些0.3<IoU<0.7的anchor则不参与训练);
代表predict bounding box,
代表对应positive anchor对应的GT box。
代价函数有两部分, 注意回归误差这一项中,,也就是说,如果anchor不包含目标,那么box输出位置是不算误差的,对于 ,只计算 判定 为有目标的anchor。
分类:交叉熵损失 回归:smooth L1 损失
self.rpn_loss_cls = F.cross_entropy(rpn_cls_score, rpn_label)
self.rpn_loss_box = _smooth_l1_loss(rpn_bbox_pred, rpn_bbox_targets, rpn_bbox\
inside_weights,rpn_bbox_outside_weights, sigma=3, dim=[1,2,3])soomth L1 loss,计算公式如下:
** bounding box regression 原理**
RoI Pooling
Faster-RCNN论文中在RoI-Head网络中,将128个RoI区域对应的feature map进行截取,而后利用RoI pooling层输出7×7大小的feature map。
RoI Pooling层则负责收集proposal,并计算出proposal feature maps,送入后续网络。从图2中可以看到Rol pooling层有2个输入:
- 原始的feature maps
- RPN输出的proposal boxes(大小各不相同)
Why?
proposals 的 box 大小形状各不相同
前沿两阶段
一阶段论文
YOLO
YOLO v1
参考:https://zhuanlan.zhihu.com/p/32525231
创新:
faster-RCNN 整体还是采用了RCNN 那种 proposal+classifier 的思想,只不过是将提取 proposal 的步骤放在 CNN 中实现了,而 YOLO 则采用直接回归的思路。
流程
1、输入的图片分割成 网格
2、每个单元格会预测 个边界框(bounding box)以及边界框的置信度(confidence score).
注意:置信度其实包含两个方面,一是这个边界框含有目标的可能性大小,二是这个边界框的准确度
3、每一个单元格其还要给出预测出 个类别概率值,其表征的是由该单元格负责预测的边界框其目标属于各个类别的概率,一般会根据类别置信度来过滤网络的预测框。
总结:每个单元格需要预测 个值。如果将输入图片划分为 网格,那么最终预测值为 大小的张量
网络具体:
Yolo采用卷积网络来提取特征,最后使用全连接层来得到预测值。对于卷积层和全连接层,采用Leaky ReLU激活函数: 。但是最后一层却采用线性激活函数。
缺点:
1、Yolo各个单元格仅仅预测 个边界框,而且属于一个类别,小物体,Yolo的表现会不如人意.(SSD使用多尺度单元格)——没使用anchor box,同时Yolo对于在物体的宽高比方面泛化率低。
2、由于损失函数的问题,定位误差是影响检测效果的主要原因。
检测框分配:
边界框的大小与位置可以用4个值来表征: ,其中 是边界框的中心坐标,而 是边界框的宽与高。
中心坐标的预测值 是相对于每个单元格左上角坐标点的偏移值,并且单位是相对于单元格大小的。
而边界框的 预测值是相对于整个图片的宽与高的比例,这样理论上4个元素的大小应该在 范围。
损失函数
\begin{equation}\begin{array}{l}
\lambda_{\text {coord }} \sum_{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{1}{i j}^{\text {obj }}\left[\left(x{i}-\hat{x}{i}\right)^{2}+\left(y{i}-\hat{y}{i}\right)^{2}\right] \
\qquad \begin{array}{rl}
+\lambda{\text {coord }} \sum_{i=0}^{S^{2}} \sum_{j=0}^{B} & \mathbb{1}{i j}^{\text {obj }}\left[(\sqrt{w{i}}-\sqrt{\hat{w}{i}})^{2}+(\sqrt{h{i}}-\sqrt{\hat{h}{i}})^{2}\right] \
& +\sum{i=0}^{S^{2}} \sum_{j=0}^{B} \mathbb{1}{i j}^{\text {obj }}\left(C{i}-\hat{C}{i}\right)^{2} \
+\lambda{\text {noobj }} \sum_{i=0}^{S^{2}} \sum_{j=0}^{B} & \mathbb{1}{i j}^{\text {noobj }}\left(C{i}-\hat{C}{i}\right)^{2} \
& +\sum{i=0}^{S^{2}} \mathbb{1}{i}^{\text {obj }} \sum{c \in \text { classes }}\left(p_{i}(c)-\hat{p}_{i}(c)\right)^{2}
\end{array}
\end{array}\end{equation}
定位误差采用较大的权重 , 置信度的权重
实际上较小的边界框的坐标误差应该要比较大的边界框要更敏感。为了保证这一点,将网络的边界框的宽与高预测改为对其平方根的预测, 即预测值变为 .
Yolo v2
变化
1、Batch Normalization
通过对 YOLO 的每一个卷积层增加 Batch Normalization,最终使得 mAP 提高了 2%,同时还使模型正则化。使用 Batch Normalization 可以从模型中去掉 Dropout,而不会产生过拟合。
2、High resolution classifier (高分辨率预训练)
目前业界标准的检测方法,都要先把分类器(classifier)放在ImageNet上进行预训练。从 Alexnet 开始,大多数的分类器都运行在小于 256×256 的图片上。而现在 YOLO 从 224×224 增加到了 448×448,这就意味着网络需要适应新的输入分辨率。
为了适应新的分辨率,YOLO v2 的分类网络以 448×448 的分辨率先在 ImageNet上进行微调,微调 10 个 epochs,让网络有时间调整滤波器(filters),好让其能更好的运行在新分辨率上,还需要调优用于检测的 Resulting Network。最终通过使用高分辨率,mAP 提升了 4%。
3、Convolution with anchor boxes
YOLO 一代包含有全连接层,从而能直接预测 Bounding Boxes 的坐标值。 Faster R-CNN 的方法只用卷积层与 Region Proposal Network 来预测 Anchor Box 偏移值与置信度,而不是直接预测坐标值。作者发现通过预测偏移量而不是坐标值能够简化问题,让神经网络学习起来更容易。
4、Dimension clusters
在训练集的 Bounding Boxes 上跑一下 k-means聚类,得到Anchor Box 的尺寸。
5、Multi-Scale Training
作者希望 YOLOv2 能健壮地运行于不同尺寸的图片之上。
区别于之前的补全图片的尺寸的方法,YOLOv2 每迭代几次都会改变网络参数。每 10 个 Batch,网络会随机地选择一个新的图片尺寸,由于使用了下采样参数是 32,所以不同的尺寸大小也选择为 32 的倍数 {320,352…..608},最小 320320,最大 608608,网络会自动改变尺寸,并继续训练的过程。
6、Datasets combination with wordtree
用 WordTree 把数据集合中的类别映射到分层树中的同义词上,例如上图 Figure 6,WordTree 混合 ImageNet 与 COCO。号称训练9000类。
Yolo v3
变化
1、多尺度预测 (类FPN),并使用了 anchor box
YOLO v3可以进行3种不同尺度的预测。检测层在分别具有步幅32,16,8的三种不同尺寸的特征图上进行检测。
2.更好的基础分类网络(类ResNet)和分类器 darknet-53
3.分类器-类别预测:
YOLOv3 不使用 Softmax 对每个框进行分类,主要考虑因素有:
- Softmax 使得每个框分配一个类别(得分最高的一个),而对于 Open Images这种数据集,目标可能有重叠的类别标签,因此 Softmax不适用于多标签分类。
- Softmax 可被独立的多个 logistic 分类器替代,且准确率不会下降。
- 分类损失采用 binary cross-entropy loss.
聚类 anchor box
在YOLOv3中,获取数据集的全部anchor box,通过K-Means算法,将这些边界框的宽高,聚类为9类,获取9个聚类中心,面积从小到大排列,作为9个anchor box。
EarlyStopping
训练或验证集中的loss不再减小,即减小的程度小于某个阈值,则会停止训练。
Yolo v4
特点
- YOLOv4 可以在一块普通的GPU(1080Ti)上完成训练,同时能够达到实时性
- 试验对比了大量的近几年来最新的深度学习技巧, 也提出了自己的创新
贡献
- 设计了强大而高效的检测模型,任何人都可以用 1080 Ti 和 2080 Ti训练这个超快而精准的模型。
- 验证了很多近几年 SOTA 的深度学习目标检测训练技巧。
- 修改了很多 SOTA 的方法, 让它们对单GPU训练更加高效,例如 CBN,PAN,SAM等。
技巧梳理
作者将那些增加模型性能,只在训练阶段耗时增多,但不影响推理耗时的技巧称为 ——赠品(bag of freebies),也就是白给的提高精度的方法。而那些微微提高了推理耗时,却显著提升性能的,叫做——特价(bag of specials),就是那些不免费,但很实惠的技巧。
赠品(bag of freebies)
数据增强方法
其他:
- 随机裁剪、旋转(Rotation)、翻转(Flip)、
- 加噪声
- MixUp
- CutMix
- Blur [blɜːr] 模糊
新引入:
- Mosaic [moʊˈzeɪɪk] 嵌合体
把四张图拼成一张图来训练,变相的等价于增大了mini-batch。这是从CutMix混合两张图的基础上改进。
正则化方法
- DropOut
- DropConnect
- DropBlock
Bounding box 回归 loss 的改进
- MSE
- IOU
- GIOU
- DIOU
- CIoU
特价(bag of specials)
增大感受野技巧
- SPP
- ASPP
- RFB
特征融合集成
- FPN
- SFAM
- ASFF
- BiFPN (也就是大名鼎鼎的 EfficientDet)
后处理非最大值抑制算法
- soft-NMS
- DIoU NMS
注意力机制
- Squeeze-and-Excitation (SE), 增加2%计算量(但推理时有10%的速度),可以提升1%的ImageNet top-1精度。
- Spatial Attention Module (SAM),增加0.1%计算量,提升0.5%的top-1准确率。
激活函数
- ReLU
- LReLU
difficult to train
- PReLU
- ReLU6
- SELU
choose
- Swish
- Mish
适应单 GPU 训练技巧
- 数据增强方法 Mosaic (马赛克) 和 自对抗训练(Self Adversarial Training, SAT)
- 修改版本的 SAM,修改版本的PAN和跨批量归一化(Cross mini-Batch Normalization)
- 使用遗传算法选择最优超参数
跨批量归一化 CmBN
这里的CmBN,是对CBN的改进,收集一个batch内多个mini-batch内的统计数据。BN, CBN, CmBN的区别如下图所示:
完整结构
CSPDarknet53 (backbone) + SPP+PAN(Neck,也就是特征增强模块)+ YoloV3组成
RetinaNet——首次 Focal Loss
Anchor free
FCOS
训练难度大 4 gpu 训练
CenterNet(Objects as Points)
其他前沿一阶段
损失函数汇总
分类损失函数
可参考 https://zhuanlan.zhihu.com/p/35709485
交叉熵(softmax)损失
Faster RCNN YOLO_1 YOLO_2 等都是用的softmax。 而YOLO V3使用 Sigmoid。
Softmax函数:
其梯度:
Focal Loss
参考 https://zhuanlan.zhihu.com/p/80594704
解决难易样本数量不平衡(注意,有区别于正负样本数量不平衡)的问题
思想:
易分样本(即,置信度高的样本)对模型的提升效果非常小,模型应该主要关注与那些难分样本(这个假设是有问题的,是GHM的主要改进对象)
二分类版:
标准CE:
为了解决正负样本不平衡的问题,我们通常会在交叉熵损失的前面加上一个参数 ,即:
进一步 为解决难以样本不均衡 把高置信度(p)样本的损失再降低一些:
举个例, 取2时,如果
,
,损失衰减了1000倍!
综合最终的 Focal Loss:
实验表明 取2, 取0.25的时候效果最佳。
参数 控制难易样本比重, 控制正负样本比重。
2D 框回归损失函数
常用的有:L1 Loss、Smooth L1 Loss、L2 Loss、IoU Loss
具体参考 https://zhuanlan.zhihu.com/p/112640903
L1 Loss
L2 Loss
Smooth L1 Loss
其实是 L1 Loss 与 L2 Loss 的综合
在 较小时使用的L2 Loss的形式,以获得较小的梯度(收敛速度),防止在极值点附近震荡。
L1 Loss 相比较于L2 Loss收敛速度慢,0点处无梯度且其他位置梯度为常数,因此在极值点附近容易产生震荡,但其对离群点的处理上要好于L2 Loss。(离群点指远离序列的一般水平的极端大值和极端小值也称为歧异值)
Faster RCNN中:
soomth L1 loss,计算公式如下:
YOLO_v1中:
3D 目标检测
逆投影
其中 , 为相机焦距, , 为主点偏移,可以从相机内参矩阵得到。
语义分割
介绍
评价标准:
-
Pixel Accuracy (PA)
分类正确的像素点数和所有的像素点数的比例 -
Mean Pixel Accuracy (MPA)
计算每一类分类正确的像素点数和该类的所有像素点数的比例然后求平均 -
Mean Intersection over Union (MIoU)
计算每一类的IoU然后求平均。
相关论文
一个不错的分享:https://zhuanlan.zhihu.com/p/44958351
FCN
可参考:https://zhuanlan.zhihu.com/p/31428783
FCN提出可以把后面几个全连接都换成卷积,这样就可以获得一张2维的feature map,后接softmax获得每个像素点的分类信息,从而解决了分割问题
FCN是语义分割的开山之作,主要特色有两点:
1.全连接层换成卷积层
2.不同尺度的信息融合FCN-8S,16s,32s.
注意FCN采取的是逐点相加加操作add融合,U-Net是concate操作。
缺点:
1、是得到的结果还是不够精细
2、是对各个像素进行分类,没有充分考虑像素与像素之间的关系。
U-Net
特点:能够适应很小的训练集(大约30张图),完全对称。
U-net用于解决小样本的简单问题分割,比如医疗影片的分割。它遵循的基本原理与FCN一样:
1.Encoder-Decoder结构:前半部分为多层卷积池化,不断扩大感受野,用于提取特征。后半部分上采样回复图片尺寸。
2.更丰富的信息融合:如灰色剪头,更多的前后层之间的信息融合。这里是把前面层的输出和后面层concat(串联)到一起,区别于FCN的逐元素加和。不同Feature map串联到一起后,后面接卷积层,可以让卷积核在channel上自己做出选择。注意的是,在串联之前,需要把前层的feature map crop到和后层一样的大小。
语义分割网络在特征融合时也有2种办法:
- FCN式的逐点相加,对应caffe的EltwiseLayer层,对应tensorflow的tf.add()
- U-Net式的channel维度拼接融合,对应caffe的ConcatLayer层,对应tensorflow的tf.concat()
总结一下,CNN图像语义分割也就基本上是这个套路:
- 下采样+上采样:Convlution + Deconvlution/Resize
- 多尺度特征融合:特征逐点相加/特征channel维度拼接
- 获得像素级别的segement map:对每一个像素点进行判断类别
看,即使是更复杂的DeepLab v3+依然也是这个基本套路
DeepLab
介绍:
- 首先它是个 VGG-16
- 然后为了使图像语义分割更准确,5 个 max-pooling 层 skip 了后两个(具体实现上,看G站上的代码,似乎没有去除,而是保留了后两个 max-pooling ,只是将 stride = 2 改为 stride = 1,kernal = 3),最后卷积层的输出整体 stride 从 32x 下降至 8x。
- 参考 Uno Whoiam:空洞卷积(Dilated Convolution):有之以为利,无之以为用 ,由于后两个 max-pooling 影响了其后的卷积层,使其视野分别下降了 2x 和 4x,为了保持其原来的视野,便将其改成空洞卷积,dilation 分别为 2 和 4,理念与DRN一致:
- 当然,它也是一个全卷积网络 Uno Whoiam:FCN:从图片分类到像素分类 ,即将全连接层替换成
的卷积层,输出和原图大小一致的特征图,对每个像素分类。
- 使用双线性插值上采样 8x 得到和原图大小一致的像素分类图。
- 使用 CRF(条件随机场)使最后分类结果的边缘更加精细:
- 多尺寸预测,希望获得更好的边界信息,与FCN skip layer类似,具体实现上,在输入图片与前四个 max pooling 后添加
和
的卷积层,这四个预测结果与最终模型输出拼接(concatenate)到一起,相当于多了128*5=640个channel。
DeepLabv2
DeepLabv2 相对于 v1 最大的改动是增加了受 SPP(Spacial Pyramid Pooling) 启发得来的 ASPP(Atrous Spacial Pyramid Pooling),在模型最后进行像素分类之前增加一个类似 Inception 的结构,包含不同 rate(空洞间隔) 的 Atrous Conv(空洞卷积),增强模型识别不同尺寸的同一物体的能力
DeepLabv3
- 使用了Multi-Grid 策略,即在模型后端多加几层不同 rate 的空洞卷积:
- 将 batch normalization 加入到 ASPP模块.
- 具有不同 atrous rates 的 ASPP 能够有效的捕获多尺度信息。不过,论文发现,随着sampling rate的增加,有效filter特征权重(即有效特征区域,而不是补零区域的权重)的数量会变小,极端情况下,当空洞卷积的 rate 和 feature map 的大小一致时,
卷积会退化成
:为了保留较大视野的空洞卷积的同时解决这个问题,DeepLabv3 的 ASPP 加入了 全局池化层+conv1x1+双线性插值上采样 的模块:
DeepLabv3+
- V3+ 最大的改进是将 DeepLab 的 DCNN 部分看做 Encoder,将 DCNN 输出的特征图上采样成原图大小的部分看做 Decoder ,构成 Encoder+Decoder 体系。
2、借鉴MobileNet,使用 Depth-wise 空洞卷积+ 卷积
3、使用修改过的 Xception
最新前沿论文
最新前沿方向
上下文关系的获取
- 基于金字塔的方法: PSPNet DeepLab 等
有几种方法如PSPNet采用基于金字塔的模块或全局池化来有规律的聚合区域或全局上下文信息。然而,它们捕获了同类的上下文关系,却忽略了不同类别的上下文。
- 基于注意力的方法:DANet(non-local)、CCNet、Context Prior for Scene Segmentation
最近基于注意力的方法,如通道注意力、空间注意力,有选择地聚合不同类别之间的上下文信息。
DANet
引入了双注意力机制(Dual[ˈduːəl] Attention)来获取上下文关系:通道(channel)以及空间(spatial)的 Attention 机制。