空间金字塔池化(SPP)

1、简介

空间金字塔池化,使得任意大小的特征图都能够转换成固定大小的特征向量,这就是空间金字塔池化的意义(多尺度特征提取出固定大小的特征向量),送入全连接层。整体框架大致为:输入图像,卷积层提取特征,空间金字塔池化提取固定大小特征,全连接层。

具体的流程图如下:

 

2、具体算法的大体流程

    首先通过选择性搜索(selective search),对待检测的图片进行搜索出2000个候选窗口。这一步和R-CNN一样

特征提取阶段。这一步就是和R-CNN最大的区别了,同样是用卷积神经网络进行特征提取,但是SPP-Net用的是金字塔池化。这一步骤的具体操作如下:把整张待检测的图片,输入CNN中,进行一次性特征提取,得到feature maps,然后在feature maps中找到各个候选框的区域,再对各个候选框采用金字塔空间池化,提取出固定长度的特征向量。而R-CNN输入的是每个候选框,然后在进入CNN,因为SPP-Net只需要一次对整张图片进行特征提取,速度是大大地快啊。江湖传说可一个提高100倍的速度,因为R-CNN就相当于遍历一个CNN两千次,而SPP-Net只需要遍历1次。

最后采用SVM算法进行特征向量分类识别,和R-CNN一样。

3、关键步骤解释:

3.1 如何在feature maps中找到原始图片中候选框的对应区域:

候选框是通过一整张原图片进行检测得到的,而feature maps的大小和原始图片的大小是不同的,feature maps是经过原始图片卷积、下采样等一系列操作后得到的。

直接利用计算的公式:假设(x,y)表示特征图上的坐标点,坐标点(x,y)表示原输入图片上的点,那么它们之间有如下转换关系:

(x,y)=(S*x,S*y)

其中S的就是CNN中所有的步长(strides)的乘积,反过来,通过(x,y)坐标求解(x,y),那么计算公式如下:

x=x/S+1

输入原图片检测到的windows,可以得到每个矩形候选框的四个角点,然后再根据公式:

LeftTop:                   x=x/S+1

RightBottom:             x=x/S-1

3.2 空间金字塔池化如何提取特征,得到固定大小的特征向量:

我们假设一个很简单两层网络:输入一张任意大小的图片,假设其大小为(w,h),输出21个神经元。也就是我们输入一张任意大小的特征图的时候,我们希望提取出21个特征。空间金字塔特征提取的过程如下:

 

    如上图所示,当我们输入一张图片的时候,我们利用不同大小的刻度,对一张图片进行了划分。上面示意图中,利用了三种不同大小的刻度(4*4,2*2,1*1),对一张输入的图片进行了划分,最后总共可以得到16+4+1=21个块,我们即将从这21个块中,每个块提取出一个特征,这样刚好就是我们要提取的21维特征向量。

    第一张图片,我们把一张完整的图片,分成了16个块,也就是每个块的大小就是(w/4,h/4);

    第二张图片,划分了4个块,每个块的大小就是(w/2,h/2);

    第三张图片,把一整张图片作为了一个块,也就是块的大小为(w,h)

    空间金字塔最大池化的过程,其实就是从这21个图片块中,分别计算每个块的最大值,从而得到一个输出神经元。最后把一张任意大小的图片转换成了一个固定大小的21维特征(当然你可以设计其它维数的输出,增加金字塔的层数,或者改变划分网格的大小)。上面的三种不同刻度的划分,每一种刻度我们称之为:金字塔的一层,每一个图片块大小我们称之为:windows size了。如果你希望,金字塔的某一层输出n*n个特征,那么你就要用windows size大小为:(w/n,h/n)进行池化了。

(转载:https://blog.csdn.net/xzzppp/article/details/51377731)

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
根据提供的引用内容,YOLOv5使用了一种名为CSPNet的新型网络结构,该结构在主干网络中引入了一种新的块,称为CSP块,以提高特征金字塔的效率。CSP块将输入特征图分成两个部分,其中一部分进行卷积操作,而另一部分则不进行卷积操作。这种方法可以减少计算量,提高特征提取的效率。此外,YOLOv5还使用了一种名为SPP结构的新型池化层,可以在不丢失信息的情况下对不同大小的特征图进行池化操作,从而提高了检测的准确性。 以下是YOLOv5特征金字塔结构的改进的代码实现: ```python import torch.nn as nn class CSPBlock(nn.Module): def __init__(self, in_channels, out_channels, num_blocks): super(CSPBlock, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.conv2 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.conv3 = nn.Conv2d(out_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.conv4 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.blocks = nn.Sequential(*[ResBlock(out_channels) for _ in range(num_blocks)]) self.bn = nn.BatchNorm2d(out_channels) self.relu = nn.LeakyReLU(0.1) def forward(self, x): y1 = self.conv1(x) y2 = self.conv2(x) y2 = self.blocks(y2) y3 = self.conv3(y2) y4 = self.conv4(x) out = self.relu(self.bn(torch.cat([y1, y3], dim=1) + y4)) return out class SPP(nn.Module): def __init__(self, in_channels, out_channels): super(SPP, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) self.pool1 = nn.MaxPool2d(kernel_size=5, stride=1, padding=2) self.pool2 = nn.MaxPool2d(kernel_size=9, stride=1, padding=4) self.pool3 = nn.MaxPool2d(kernel_size=13, stride=1, padding=6) self.bn = nn.BatchNorm2d(out_channels) self.relu = nn.LeakyReLU(0.1) def forward(self, x): x = self.conv1(x) x = self.relu(self.bn(self.conv2(x))) x = torch.cat([x, self.pool1(x), self.pool2(x), self.pool3(x)], dim=1) return x ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值