1、置信区间和置信度
当样本数据很大时,呈现正太分布。
这就是置信区间,区间为 63 + -3,置信度为 95%。
2、IoU的简介及原理解析
IoU 的全称为交并比(Intersection over Union),通过这个名称我们大概可以猜到 IoU 的计算方法。IoU 计算的是 “预测的边框” 和 “真实的边框” 的交集和并集的比值。
def iou(set_a, set_b):
#Tue Mar 17 14:39:16 2020
'''
一维 iou 的计算
'''
x1, x2 = set_a # (left, right)
y1, y2 = set_b # (left, right)
low = max(x1, y1)
high = min(x2, y2)
# intersection
if high-low<0:
inter = 0
else:
inter = high-low
# union
union = (x2 - x1) + (y2 - y1) - inter
# iou
iou = inter / union
return iou
def iou1(box1, box2):
'''
两个框(二维)的 iou 计算
注意:边框以左上为原点
box:[top, left, bottom, right]
'''
in_h = min(box1[2], box2[2]) - max(box1[0], box2[0])
in_w = min(box1[3], box2[3]) - max(box1[1], box2[1])
inter = 0 if in_h<0 or in_w<0 else in_h*in_w
union = (box1[2] - box1[0]) * (box1[3] - box1[1]) + \
(box2[2] - box2[0]) * (box2[3] - box2[1]) - inter
iou = inter / union
return iou
def IoU_calculator(x, y, w, h, l_x, l_y, l_w, l_h):
"""calaulate IoU
Args:
x: net predicted x,x为预测框的中心x
y: net predicted y,y为预测框的中心y
w: net predicted width
h: net predicted height
l_x: label x
l_y: label y
l_w: label width
l_h: label height
Returns:
IoU
"""
# convert to coner
x_max = x + w/2
y_max = y + h/2
x_min = x - w/2
y_min = y - h/2
l_x_max = l_x + l_w/2
l_y_max = l_y + l_h/2
l_x_min = l_x - l_w/2
l_y_min = l_y - l_h/2
# calculate the inter
inter_x_max = tf.minimum(x_max, l_x_max)
inter_x_min = tf.maximum(x_min, l_x_min)
inter_y_max = tf.minimum(y_max, l_y_max)
inter_y_min = tf.maximum(y_min, l_y_min)
inter_w = inter_x_max - inter_x_min
inter_h = inter_y_max - inter_y_min
'''tf.less_equal(a,threshold)判断每一个数是否小于threshold
#判断每一个数是否大于threshold
greater = tf.greater(x, threshold)
#判断每一个数是否小于threshold
less = tf.less(x,threshold)
#判断每一个数是否大于等于threshold
greater_equal=tf.greater_equal(x, threshold)
#判断每一个数是否小于等于threshold
less_equal=tf.less_equal(x, threshold)
#判断每一个数是否等于threshold
equal = tf.equal(x, threshold)
#判断每一个数是否不等于threshold
not_equal=tf.not_equal(x, threshold)
sess.run(tf.logical_and(True, False))逻辑或
sess.run(tf.logical_or(True, False))逻辑与
tf.cond()类似于c语言中的if...else...,用来控制数据流向
'''
inter = tf.cond(tf.logical_or(tf.less_equal(inter_w,0), tf.less_equal(inter_h,0)),
lambda:tf.cast(0,tf.float32),
lambda:tf.multiply(inter_w,inter_h))
# calculate the union
union = w*h + l_w*l_h - inter
IoU = inter / union
return IoU
# -*- coding: utf-8 -*-
"""
整个代码如下:
Created on@author: User
"""
import numpy as np
import tensorflow as tf
def iou(set_a, set_b):
#Tue Mar 17 14:39:16 2020
'''
一维 iou 的计算
'''
x1, x2 = set_a # (left, right)
y1, y2 = set_b # (left, right)
low = max(x1, y1)
high = min(x2, y2)
# intersection
if high-low<0:
inter = 0
else:
inter = high-low
# union
union = (x2 - x1) + (y2 - y1) - inter
# iou
iou = inter / union
return iou
def iou1(box1, box2):
'''
两个框(二维)的 iou 计算
注意:边框以左上为原点
box:[top, left, bottom, right]
'''
in_h = min(box1[2], box2[2]) - max(box1[0], box2[0])
in_w = min(box1[3], box2[3]) - max(box1[1], box2[1])
inter = 0 if in_h<0 or in_w<0 else in_h*in_w
union = (box1[2] - box1[0]) * (box1[3] - box1[1]) + \
(box2[2] - box2[0]) * (box2[3] - box2[1]) - inter
iou = inter / union
return iou
def IoU_calculator(x, y, w, h, l_x, l_y, l_w, l_h):
"""calaulate IoU
Args:
x: net predicted x,x为预测框的中心x
y: net predicted y,y为预测框的中心y
w: net predicted width
h: net predicted height
l_x: label x
l_y: label y
l_w: label width
l_h: label height
Returns:
IoU
"""
# convert to coner
x_max = x + w/2
y_max = y + h/2
x_min = x - w/2
y_min = y - h/2
l_x_max = l_x + l_w/2
l_y_max = l_y + l_h/2
l_x_min = l_x - l_w/2
l_y_min = l_y - l_h/2
# calculate the inter
inter_x_max = tf.minimum(x_max, l_x_max)
inter_x_min = tf.maximum(x_min, l_x_min)
inter_y_max = tf.minimum(y_max, l_y_max)
inter_y_min = tf.maximum(y_min, l_y_min)
inter_w = inter_x_max - inter_x_min
inter_h = inter_y_max - inter_y_min
'''tf.less_equal(a,threshold)判断每一个数是否小于threshold
#判断每一个数是否大于threshold
greater = tf.greater(x, threshold)
#判断每一个数是否小于threshold
less = tf.less(x,threshold)
#判断每一个数是否大于等于threshold
greater_equal=tf.greater_equal(x, threshold)
#判断每一个数是否小于等于threshold
less_equal=tf.less_equal(x, threshold)
#判断每一个数是否等于threshold
equal = tf.equal(x, threshold)
#判断每一个数是否不等于threshold
not_equal=tf.not_equal(x, threshold)
sess.run(tf.logical_and(True, False))逻辑或
sess.run(tf.logical_or(True, False))逻辑与
tf.cond()类似于c语言中的if...else...,用来控制数据流向
'''
inter = tf.cond(tf.logical_or(tf.less_equal(inter_w,0), tf.less_equal(inter_h,0)),
lambda:tf.cast(0,tf.float32),
lambda:tf.multiply(inter_w,inter_h))
# calculate the union
union = w*h + l_w*l_h - inter
IoU = inter / union
return IoU
if __name__=="__main__":
set_a=np.array([6.8,7.3])
set_b=np.array([7.0,8.5])
with tf.Session() as sess:
print(sess.run(IoU_calculator(3, 5, 4, 4, 4, 6, 4, 4)))
print(iou(set_a,set_b))
3AP指标
AP:PR曲线下的面积
PR曲线:横坐标是recall(正确分类占应该正确被分类的比例),纵坐标是precision(分类正确的占总样本的比例)。
IOU:全称intersection-over-union,交/并。
FPN特征金字塔
为获取不同层次的特征我们使用特征金字塔
识别不同大小的物体,常用的解决方案是构造多尺度金字塔。如上图a所示,这是一个特征图像金字塔,整个过程是先对原始图像构造图像金字塔,然后在图像金字塔的每一层提出不同的特征,然后进行相应的预测(BB的位置)。这种方法的缺点是计算量大,需要大量的内存;优点是可以获得较好的检测精度。
如上图b所示,这是一种改进的思路,学者们发现我们可以利用卷积网络本身的特性,即对原始图像进行卷积和池化操作,通过这种操作我们可以获得不同尺寸的feature map,这样其实就类似于在图像的特征空间中构造金字塔。实验表明,浅层的网络更关注于细节信息,高层的网络更关注于语义信息,而高层的语义信息能够帮助我们准确的检测出目标,因此我们可以利用最后一个卷积层上的feature map来进行预测。这种方法存在于大多数深度网络中,比如VGG、ResNet、Inception,它们都是利用深度网络的最后一层特征来进行分类。这种方法的优点是速度快、需要内存少。它的缺点是我们仅仅关注深层网络中最后一层的特征,却忽略了其它层的特征,但是细节信息可以在一定程度上提升检测的精度。
图c所示的架构,它的设计思想就是同时利用低层特征和高层特征,分别在不同的层同时进行预测,这是因为我的一幅图像中可能具有多个不同大小的目标,区分不同的目标可能需要不同的特征,对于简单的目标我们仅仅需要浅层的特征就可以检测到它,对于复杂的目标我们就需要利用复杂的特征来检测它。整个过程就是首先在原始图像上面进行深度卷积,然后分别在不同的特征层上面进行预测。它的优点是在不同的层上面输出对应的目标,不需要经过所有的层才输出对应的目标(即对于有些目标来说,不需要进行多余的前向操作),这样可以在一定程度上对网络进行加速操作,同时可以提高算法的检测性能。它的缺点是获得的特征不鲁棒,都是一些弱特征(因为很多的特征都是从较浅的层获得的)。FPN啦,它的架构如图d所示,整个过程如下所示,首先我们在输入的图像上进行深度卷积,然后对Layer2上面的特征进行降维操作(即添加一层1x1的卷积层),对Layer4上面的特征就行上采样操作,使得它们具有相应的尺寸,然后对处理后的Layer2和处理后的Layer4执行加法操作(对应元素相加),将获得的结果输入到Layer5中去。这次我们使用了更深的层来构造特征金字塔,这样做是为了使用更加鲁棒的信息;除此之外,我们将处理过的低层特征和处理过的高层特征进行累加,这样做的目的是因为低层特征可以提供更加准确的位置信息,而多次的降采样和上采样操作使得深层网络的定位信息存在误差,因此我们将其结合其起来使用,这样我们就构建了一个更深的特征金字塔,融合了多层特征信息,并在不同的特征进行输出。
从rpn的代码直观上可以感觉到的是,主要包含三部分,一是RPN网络的搭建及初始化,二是proposals 的生成,及对应的文本/非文本分数值的计算,最后一个就是对应的loss函数的定义,这里loss函数包含两个一个是回归loss,另一个是分类loss。重点是proposals的生成,首先要产生anchors,本代码中有五个级别的anchors(32,64,128,256,512)。
首先建立特征金字塔,滑动窗口的位置选在从resnet_v1_101/block4,作为p5,然后进行一次池化操作,作为P6,然后,依次对resnet_v1_101,的block4,block3,block2,分别进行上采样-卷积-求加-卷积,依次形成相应的特征金字塔层,返回的是多个尺寸的feature_map(p2,p3,p4,p5,p6,其中p6是由p5最大池化后处理得到的)。
从图中可以看出+的意义为:左边的底层特征层通过1*1的卷积得到与上一层特征层相同的通道数;上层的特征层通过上采样得到与下一层特征层一样的长和宽再进行相加,从而得到了一个融合好的新的特征层。举个例子说就是:C4层经过1*1卷积得到与P5相同的通道,P5经过上采样后得到与C4相同的长和宽,最终两者进行相加,得到了融合层P4,其他的以此类推。
针对金字塔的每一层即相对应的feature-map生成anchors,每层金字塔特定的feature-map上用到的anchor都有对应的大小((P2, 32), (P3, 64), (P4, 128), (P5, 256), (P6, 512)),生成anchors中有一个base_anchor ,还有一个anchor_scales,首先base_anchor根据anchor_scales进行大小的缩放,
然后,根据anchor_ratios的值进行长宽比的缩放,从而有多个anchor尺寸的选择。然后,将feature_map*步长会得到相应的中心点,由下列代码最终得到final_anchor
由于使用到了FPN,在论文中也有说到每层的feature map 的scale是保持不变的,只是改变每层的ratio,且越深scale的值就越小,因为越深的话feature map就越小。论文中提供的每层的scale为(32, 64, 128, 256, 512),ratio为(0.5, 1, 2),所有每一层的每一个像素点都会产生3个锚框,而总共会有15种不同大小的锚框。
Fast R-CNN框架
首先CNN进行卷积获取特征图,region proposal采用滑动窗口获取不同尺度的目标框。然后映射到特征图上得到ROIS,POI pooling层把尺寸规划到统一大小。全连接层对ROIS进行分类和回归操作。
Mask Rcnn
参考博客 Mask Rcnn整体架构
Faster-RCNN 整体架构
对比两张图可以很明显的看出,在Faster-RCNN的基础之上,Mask-RCNN加入了Mask branch(FCN)用于生成物体的掩模(object mask), 同时把RoI pooling 修改成为了RoI Align 用于处理mask与原图中物体不对齐的问题。因为在提取feature maps的主干conv layers中不好把FPN的结构绘制进去,所有在架构中就没有体现出了FPN的作用,将在后面讲述。
内容
遵循自下而上的原则,依次的从backbone,FPN,RPN,anchors RoIAlign,classification,box regression,mask这几个方面讲解。
1、backbone
2、(RPN,anchors )
3、RoIAlign
可以看出来在RoI pooling中出现了两次的取整,虽然在feature maps上取整看起来只是小数级别的数,但是当把feature map还原到原图上时就会出现很大的偏差,比如第一次的取整是舍去了0.78,还原到原图时是0.78*32=25,第一次取整就存在了25个像素点的偏差,在第二次的取整后的偏差更加的大。对于分类和物体检测来说可能这不是一个很大的误差,但是对于实例分割而言,这是一个非常大的偏差,因为mask出现没对齐的话在视觉上是很明显的。而RoIAlign的提出就是为了解决这个问题,解决不对齐的问题。
3.1RoIAlign的思想
就是取消了取整的这种粗暴做法,而是通过双线性插值(听我师姐说好像有一篇论文用到了积分,而且性能得到了一定的提高)来得到固定四个点坐标的像素值,从而使得不连续的操作变得连续起来,返回到原图的时候误差也就更加的小。
1.划分7*7的bin(可以直接精确的映射到feature map上来划分bin,不用第一次ROI的量化)
2.接着是对每一个bin中进行双线性插值,得到四个点(在论文中也说到过插值一个点的效果其实和四个点的效果是一样的,在代码中作者为了方便也就采用了插值一个点)
3.通过插完值之后再进行max pooling得到最终的7 *7的ROI,即完成了RoIAlign的过程。是不是觉得大佬提出来的高大上名字的方法还是挺简单的。
4、classifier
论文中提到用1024个神经元的全连接网络,但是在代码中作者用卷积深度为1024的卷积层来代替这个全连接层。
5、mask
mask的预测也是在ROI之后的,通过FCN(Fully Convolution Network)来进行的。注意这个是实现的语义分割而不是实例分割。因为每个ROI只对应一个物体,只需对其进行语义分割就好,相当于了实例分割了,这也是Mask-RCNN与其他分割框架的不同,是先分类再分割。
该模型的训练和预测是分开的,不是套用同一个流程。在训练的时候,classifier和mask都是同时进行的;在预测的时候,显示得到classifier的结果,然后再把此结果传入到mask预测中得到mask,有一定的先后顺序。
代码总体框架
两张流程图其实已经把作者的代码各个关键部分都展示出来了,并写出了哪些层是在training中用,哪些层是在predict中用,及其层的输出和需要的输入。可以清晰的看出training和predict过程是存在较大的差异的,也是之前说过的,training的时候mask与classifier是并行的,predict时候是先classifier再mask,并且两个模型的输入输出差异也较大。
Mask Scoring RCNN
代码实验 摘要:在大多数实例分割的任务中,实例分类的置信度被当作mask的质量衡量指标。mask的质量被量化为实例mask和它的ground truth之间的IOU,显然,mask的质量和分类的质量其实没有很强的相关性。在这篇文章中,我们研究了这个问题(如何研究,带着这个问题去思考),并且提出了Mask Scoring R-CNN, 其实包含一个网络块network block去学习预测实例mask的质量(这个网络块怎么设计的)。这个网络模块利用实例特征(Features map)和相应的预测的mask去回归mask IOU。这个mask scoring策略可以解决的问题:mask score和mask quality不匹配的问题。
mask score(通常是分类的分数)和mask quality不匹配
可以看到在Mask R-CNN中,分类得分很高,mask质量却很不尽人意。
第一张图片男人左侧身子mask没有覆盖,女人的腿mask缺失;
第二张图片猫的头mask没有覆盖;
第三张图像小象的mask只有一点点;
第四张图片红色衣服的人mask残缺。
mask的质量和分类的质量在mask-rcnn中并没有很好的关联。
背景:大多数实例分割的pipeline,例如Mask R-CNN, instance mask 的score是与分类的置信度是共享的,都是通过特征作用于分类器进行预测。使用分类的置信度去衡量mask的质量是不合适的,因为它只能区分proposal的语义上的类别,并不能意识到实例mask的实际质量和完整性。
受到AP指标的启发,使用像素级的IOU(between the predicted mask and its ground truth mask)去描述实例分割的质量,我们提出了一个网络去直接学习IOU。我们称这个IOU为MaskIou, 在测试阶段一旦我们获得MaskIoU,mask score会重新评估通过预测MaskIoU和分类的分数。于是,mask score既能识别语义类别,又能识别实例掩码的完整性。
MaskIOU head:这是一个MaskIoU的预测网络。输入:RoIfeature;输出:mask head
相关工作
在实例分割中,前人的工作主要Mask R-CNN, MaskLab。然而这些方法都有一个潜在的缺点就是mask的质量仅仅依靠分类分数去测量的。简而言之,就是对已分类的特征进行上采样填充为原图相同的分辨率的图片。
从mask质量的角度来说,这些方法的AP会下降的原因:一个mask,有较高的IOU(higer IoU against ground truth), 如果它有很低的mask score,很容易被视为一个低优先级,这样一来,AP就会相应的下降。(不是理解,这些方法中,mask score就是分类分数,如果分类分数很低,他的优先级就会降。于是乎,mask很好,但是分类分数较低的,我们就不会选择,导致最终的AP有下降)
现在采用高评分和低Mask IoU作为惩罚检测,发现Mask IoU和mask score 相关性很好。
怎么设计的这个网络:
(1)我们将RoIAlign层的feature与预测的mask连接起来作为MaskIoU head的输入;
(2)使用max pooling让预测掩码与RoI feature 具有相同空间大小;
(3)Mask IOU包含4个卷积层和3个全连接层。
如何训练样本
为训练样本,训练样本要求proposal box与匹配的ground truth的IOU大于0.5。为了产生回归目标,我们得到目标类的预测掩码并将掩码二值化(使用0.5的阈值)。
然后我们将输入二值化的mask,以相应的ground truth作为回归目标,使用L2 loss进行MaskIOU回归。
L2 loss
具体假设掩码R-CNN的R-CNN阶段输出N个边框框,其中选取SoftNMS后的top-k(即k = 100)计分框。然后将前k个盒送入掩模头,生成多类掩模。这是标准的掩码R-CNN推断过程。我们也遵循这个过程,并输入top-k目标掩码来预测掩码。将预测的掩模与分类分数相乘,得到新的校准掩模分数作为最终掩模的可信度。
实验表明MS R-CNN对骨干网络不敏感,可以在所有骨干网络上实现稳定的改善。
结论: