金字塔池化系列的理解SPP、ASPP

金字塔池化系列的理解SPP、ASPP

问题

在spp出来之前,所有神经网络都是要输入固定尺寸的图片,比如经常遇到的224×224,图片输入网络前都要resize到224×224,导致图片变形,其中的信息也变形了,从而限制了识别精度。
而SPP和ASPP就是为了解决这个问题,它可以让网络输入原图而不必resize。

SPP结构

在这里插入图片描述
刚看到这张结构图,很多同学可能和我一样懵(原谅我比较笨),别的博客里配的文字也都是比较简单,有些词汇不够通俗,直到我看到了下面这张图:
在这里插入图片描述如图所示,最左边的图图形表示卷积得到的256维特征图,对于每个区域(厚度为256),通过三种方式进行池化:

(1)直接对整个特征图池化,每一维得到一个池化后的值,构成一个1x256的向量

(2)将特征图分成2x2共4份,每份单独进行池化,得到一个1x256的向量,最终得到2x2=4个1x256的向量

(3)将特征图分成4x4共16份,每份单独进行池化,得到一个1x256的向量,,最终得到4x4=16个1x256的向量

将三种划分方式池化得到的结果进行拼接,得到(1+4+16)*256=21x256的特征。

由图中可以看出,整个过程对于输入的尺寸大小完全无关,因此可以处理任意尺寸的候选框。

空间池化层实际就是一种自适应的层,这样无论你的输入是什么尺寸,输出都是固定的(21xchannel)

ASPP结构

在介绍ASPP之前,首先要介绍Atrous Convolution(空洞卷积),它是一种增加感受野的方法。空洞卷积是是为了解决基于FCN思想的语义分割中,输出图像的size要求和输入图像的size一致而需要upsample,但由于FCN中使用pooling操作来增大感受野同时降低分辨率,导致upsample无法还原由于pooling导致的一些细节信息的损失的问题而提出的。为了减小这种损失,自然需要移除pooling层,因此空洞卷积应运而生。
普通卷积这里就不介绍了,我们来看一下空洞卷积的动态图,就一目了然了:
在这里插入图片描述
空洞卷积从字面上很好理解,是在标准的卷积中注入空洞,以此来增加感受野,相比原来的正常卷积,空洞卷积多了一个称之为 dilation rate 的参数,指的是kernel的间隔数量(一般的卷积 dilation rate=1)。
但是,空洞卷积也有其潜在的一些问题:

潜在问题 1:The Gridding Effect

假设我们仅仅多次叠加 dilation rate 2 的 3 x 3 kernel 的话,则会出现这个问题:
在这里插入图片描述
我们发现 kernel 并不连续,也就是并不是所有的 pixel 都用来计算了,因此这里将信息看做 checker-board 的方式会损失信息的连续性。这对 pixel-level dense prediction 的任务来说是致命的。

潜在问题 2:Long-ranged information might be not relevant.

我们从 dilated convolution 的设计背景来看就能推测出这样的设计是用来获取 long-ranged information。然而光采用大 dilation rate 的信息或许只对一些大物体分割有效果,而对小物体来说可能则有弊无利了。如何同时处理不同大小的物体的关系,则是设计好 dilated convolution 网络的关键。

HDC(Hybrid Dilated Convolution)

针对以上几个问题,图森组的文章对其提出了较好的解决的方法。他们设计了一个称之为 HDC 的设计结构。
它有几个特性,可以从一定程度上解决上述问题。这里咱不讨论。我们可以从一张图来对比一下正常空洞卷积与HDC的效果:
在这里插入图片描述
可以看到经过卷积之后,HDC能够获得更多的图像信息,不会出现像正常空洞卷积一样的小方块。

Atrous Spatial Pyramid Pooling (ASPP)

首先看一下ASPP的结构图
在这里插入图片描述
这里设计了几种不同采样率的空洞卷积来捕捉多尺度信息,但我们要明白采样率(dilation rate)并不是越大越好,因为采样率太大,会导致滤波器有的会跑到padding上,产生无意义的权重,因此要选择合适的采样率。

参考链接

https://blog.csdn.net/sinat_33486980/article/details/81902746
https://www.cnblogs.com/bupt213/p/10823653.html

### ASPP 结构简介 空间金字塔池化 (ASPP, Atrous Spatial Pyramid Pooling) 是一种用于语义分割的有效方法,通过多尺度空洞卷积来捕捉不同感受野的信息。这种结构能够有效地增强模型对于物体大小变化的鲁棒性。 ### 使用 PyTorch 实现 ASPP 以下是基于 PyTorch 的 ASPP 模型实现: ```python import torch.nn as nn import torch class ASPP(nn.Module): def __init__(in_channels, out_channels, rates=[1, 6, 12, 18]): super(ASPP, self).__init__() # 创建多个并行的空洞卷积层 modules = [] for rate in rates: modules.append( nn.Sequential( nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=rate, dilation=rate, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU() ) ) # 添加全局平均池化分支 modules.append( nn.Sequential( nn.AdaptiveAvgPool2d((1, 1)), nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU(), nn.UpsamplingBilinear2d(scale_factor=(rates[-1], rates[-1])) ) ) self.convs = nn.ModuleList(modules) # 融合各分支特征图 self.project = nn.Sequential( nn.Conv2d(len(rates)*out_channels + in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU(), nn.Dropout(0.5) ) def forward(self, x): res = [] for conv in self.convs[:-1]: res.append(conv(x)) res.append(self.convs[-1](x)) res = torch.cat(res, dim=1) return self.project(res) aspp_model = ASPP(in_channels=2048, out_channels=256).cuda() # 假设输入通道数为2048,输出通道数为256 input_tensor = torch.randn([1, 2048, 32, 32]).cuda() output = aspp_model(input_tensor) print(output.shape) ``` ### 使用 TensorFlow 实现 ASPP 下面是使用 TensorFlow 和 Keras API 来构建相同的 ASPP 层的方法: ```python from tensorflow.keras.layers import Conv2D, BatchNormalization, ReLU, GlobalAveragePooling2D, UpSampling2D, Concatenate from tensorflow.keras.models import Model import tensorflow as tf def build_aspp_layer(inputs, filters, atrous_rates): branches = [] # 并行应用不同的膨胀率 for rate in atrous_rates: branch = Conv2D(filters=filters, kernel_size=3, strides=1, padding='same', dilation_rate=rate)(inputs) branch = BatchNormalization()(branch) branch = ReLU()(branch) branches.append(branch) # 全局平均池化分支 shape_before = tf.shape(inputs) pool = GlobalAveragePooling2D()(inputs) pool = tf.expand_dims(pool, axis=1) pool = tf.expand_dims(pool, axis=1) pool = Conv2D(filters=filters, kernel_size=1, padding='same')(pool) pool = BatchNormalization()(pool) pool = ReLU()(pool) pool = UpSampling2D(size=(shape_before[1], shape_before[2]), interpolation="bilinear")(pool) branches.append(pool) concatenated = Concatenate(axis=-1)(branches) output_feature = Conv2D(filters=filters, kernel_size=1, padding='same')(concatenated) output_feature = BatchNormalization()(output_feature) output_feature = ReLU()(output_feature) return output_feature # 测试代码片段 dummy_input = tf.random.normal(shape=(1, 32, 32, 2048)) result = build_aspp_layer(dummy_input, 256, [1, 6, 12, 18]) print(result.shape) ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值