SPP-NET总结:
详细介绍参考:https://blog.csdn.net/v1_vivian/article/details/73275259
代码参考:https://www.01hai.com/note/av117232
1.CNN中fc层不能接受不同大小的特征向量,空间金字塔池化(Spatial Pyramid Pooling)可以解决这个问题。
(1)
-
⌊⌋:向下取整符号 ⌊59/60⌋=0,有时也用 floor() 表示
-
⌈⌉:向上取整符号 ⌈59/60⌉=1, 有时也用ceil() 表示
那这个代码举个例子:
通过conv5得到特征向量后,根据图像映射得到2k个region proposal。其中一个的大小是(256,7,11)池化数量(4,4)
对应代码中的数就是num=1,c=256,h=7,w=11, level=4 ,那么核的大小kernel_size=7/4 向上取整=2 ,11/4=3 向上取整
步长 stride= 2,3 和上面一样 ,填充padding=1,1 利用卷积计算公式(h+2*p-k_h/s_h)+1=(4,4)这样就得到了(256,4,4)
#coding=utf-8
import math
import torch
import torch.nn.functional as F
# 构建SPP层(空间金字塔池化层)
class SPPLayer(torch.nn.Module):
def __init__(self, num_levels, pool_type='max_pool'):
super(SPPLayer, self).__init__()
self.num_levels = num_levels
self.pool_type = pool_type
def forward(self, x):
num, c, h, w = x.size() # num:样本数量 c:通道数 h:高 w:宽
for i in range(self.num_levels):
level = i+1
kernel_size = (math.ceil(h / level), math.ceil(w / level))
stride = (math.ceil(h / level), math.ceil(w / level))
padding = (math.floor((kernel_size[0]*level-h+1)/2), math.floor((kernel_size[1]*level-w+1)/2))
# 选择池化方式
if self.pool_type == 'max_pool':
tensor = F.max_pool2d(x, kernel_size=kernel_size, stride=stride, padding=padding).view(num, -1)
else:
tensor = F.avg_pool2d(x, kernel_size=kernel_size, stride=stride, padding=padding).view(num, -1)
# 展开、拼接
if (i == 0):
x_flatten = tensor.view(num, -1)
else:
x_flatten = torch.cat((x_flatten, tensor.view(num, -1)), 1)
return x_flatten
2.Mapping a Window to Feature Maps,图像中2k框框映射到特征向量中的框框的方法。
1.输入一幅图进入网络
2.在卷积神经网络的conv5层,提取特征向量图。
3.使用Mapping a Window to Feature Maps,对特征向量图做图像映射。就是对应图中的Regions of Interest 获取2k个region proposal
4.把2k个region proposal 送到SSP 中 得到统一大小的特征向量 对应图中SSP layer
5.再把2k个特征向量送到fc层 ,得到2k个1维向量
6.SVM再分类(个人猜测可能还是数据不足,所以仅仅使用CNN来提取特征,SVM分类)