常见网络
常见网络
目标检测
R-CNN
-
参考:https://blog.csdn.net/weixin_41923961/article/details/80113669
- 测试过程
-
输入一张测试图像, 使用selective search算法提取出大约1000-2000个建议框
- selective search算法的OpenCV使用
im = cv2.imread('./test.jpg') ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation() ss.setBaseImage(im) ss.switchToSelectiveSearchFast() # ss.switchToSelectiveSearchQuality() rects = ss.process() print('Total number of region proposals: ', len(rects)) for i, rect in enumerate(rects): x, y, w, h = rect cv2.rectangle(im, (x, y), (x + w, y + h), (0, 0, 255), 1, cv2.LINE_AA) cv2.imshow('output.jpeg', im) cv2.waitKey(0)
-
取出一个建议框, 取出里面的图片, resize到227x227(R-CNN使用的AlexNet, AlexNet需要输入227x277大小的图片), 将其输入到AlexNet中, 每一个建议框都这样操作, 一个建议框得到4096个特征, 如果有2000个建议狂, 则有2000x4096个维度
-
将得到的2000x4096的特征放入到20个SVM(SVM是一个2分类的分类器, 这里有20个类别)分类器中, 得到2000x20维度的矩阵
-
2000x20个矩阵每一列就是一个物体的得分, 从2000列中挑选出同一类别的列向量, 对他们的建议框进行NMS抑制去掉重叠的框
-
使用20个回归器对物体的建议框进行修正, 得到bounding box, 在训练时, 因为建议框是通过selective search得到的, 不能够修改, 学习的是建议框到bounding box的变化
-
- 流程图
- 测试过程
Fast R-CNN
- 之前的R-CNN的效率很低, 因为它对原图进行selective search, 生成大约2000个候选框, 在分别把这2000个候选框输入到网络中, 分别预测类别和回归框; 此外对输入的图片的尺寸越有要求, 要277x277, 所以对图片要么crop, 要么warp, 这其实都不是很可靠
- Fast R-CNN提出RoIPooling和特征框
-
特征框: 既然在原图上生成候选框再将这些候选框都输入到网络中很耗时间, Fast R-CNN就将原始图直接输入到AlexNet网络中, 得到的就是了feature maps, 将原图提取到的候选框映射到feature maps上, 成了特征框
-
RoIPooling: 参考了SPPNet中SPP池化, RoIPooling是SPP池化的单尺度形式, 加入FC要接受4维特征, 则RoIPooling将feature maps中的特征框划分成4份, 对每一份取最大值就可以了
-
下图是输入到RoIPooling的特征图, fc接受的是4, 因此需要池化到2x2
! -
黑色框为特征框
- 将RoI分成4份, 因为无法整除, 所以大小不一
- 注意: 在Fast R-CNN中, region proposal得到的x,y,w,h为小数, 这里将他们取整, 这里有一个细节: 取整之后, 此时的region proposal已经和一开始的region proposal有了偏差, 在目标检测中问题不大, 但是在图像分割会有很大的误差, 因为mask是逐像素的
-
-
全连接的参数使用SVD分解来加速算法
-
- 流程图
Faster R-CNN
-
Fast R-CNN速度还是太慢了, 通过selective search方法生成候选框的实现要比分类更耗时, Faster R-CNN不在使用selective search生成候选框, 而是通过一个RPN网络得出出候选框
-
RPN有anchor的概念, 原图经过卷积之后输入到RPN分支网络, RPN取slide window对feature maps进行滑动, 在slide window中的每一个像素都有9个anchor, 分别为1:1, 2:1, 1:2比例的, 还要判断anchor中有无物体, 有则保留, 没有则去掉, 再使用NMS去重, 得出了候选框, 剩余分布和Fast R-CNN一样
-
流程图
- 详细一点的
- 别人的
Mask R-CNN
-
Mask R-CNN可以理解为FPN-ResNet + Faster-RCNN, 把Faster-RCNN的RoIPooling改成了RoiAlign(提高mask的精度, 处理对齐问题, 采用双线性插值), 使用FPN-ResNet提取特征, 多一个分支来训练mask
-
总的流程图
-
mask损失
- 与FCN分割的损失不同, FCN是上采样得到和原图一样尺寸的图, 通道数为类别个数, 一口气对每个像素的多个类别进行softmax
- 而Mask R-CNN不同, 则为了避免类之间的竞争, 采用sigmoid函数, 比较之后此类的损失, 而不是一口气直接比较多个类的损失
池化
SPPNet
- 实现代码
class SPPLayer(nn.Module):
def __init__(self, sides):
"""
Parameters
----------
sides : array-like
A list of side lengths
"""
super(SPPLayer, self).__init__()
self.sides = sides
def forward(self, x):
out = None
for side in self.sides:
ksize = tuple(map(lambda v: math.ceil(v / side), x.size()[2:]))
strides = tuple(map(lambda v: math.floor(v / side), x.size()[2:]))
paddings = (math.floor(ksize[0] * side - x.size()[2]), math.floor(ksize[1] * side - x.size()[3]))
output = nn.MaxPool2d(ksize, strides, paddings)(x)
if out is None:
out = output.view(-1)
else:
out = t.cat([out, output.view(-1)])
return out
- 结构
损失函数
L1
- 公式: \(L_1={1\over{m}}\sum_{i=1}^{m}|h(x)-\hat{y}|\)
- 一个样本且不求均值时的导数: \(L'_1=\pm{h'(x)}\)
L2
- 公式: \(L_2={1\over{m}}\sum_{i=1}^m{(h(x)-\hat{y})}^2\)
- 一个样本且不求均值时的导数: \(L'_2=2h'(x)(h(x)-\hat{y})\)
Smooth L1 Loss
- 公式: