# 一文搞懂池化层！Pooling详解(网络下采样篇)

#### 一. 池化的目的及作用

• 增大网络感受野
• 抑制噪声，降低信息冗余
• 降低模型计算量，降低网络优化难度
• 防止网络过拟合
• 使模型对输入的特征位置变化更加鲁棒

#### 二. 池化函数分类详解

##### 1. Max Pooling(最大池化)

# Torch 实现
torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)

##### 2. Average Pooling(平均池化)

torch.nn.AvgPool1d(kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)

##### 3. Global Average Pooling(全局平均池化)

class GlobalAvgPool1d(nn.Module):
def __init__(self):
super(GlobalAvgPool1d,self).__init__()
def forward(self, x):
return nn.AvgPool1d(x,kernel_size=x.shape[2])

##### 4. Mix Pooling(混合池化)

将AvgPool1d与MaxPool1d加权求和即可

##### 5. Stochastic Pooling(随机池化)

• 先将矩阵中的元素同时除以它们的和sum，得到概率矩阵
• 按照概率随机选中元素
• pooling得到的值就是方格位置的值

class StochasticPool2DLayer(nn.Module):
def __init__(self, pool_size=2, maxpool=True, training=False, grid_size=None, **kwargs):
super(StochasticPool2DLayer, self).__init__(**kwargs)
self.pool_size = pool_size
self.maxpool_flag = maxpool
self.training = training
if grid_size:
self.grid_size = grid_size
else:
self.grid_size = pool_size
self.Maxpool = torch.nn.MaxPool2d(kernel_size=self.pool_size, stride=1)
def forward(self, x, training=False, **kwargs):
if self.maxpool_flag:
x = self.Maxpool(x)
if not self.training:
x = self.Avgpool(x)
return x # [:, :, ::self.pool_size, ::self.pool_size]
else:
w, h = x.data.shape[2:]
n_w, n_h = w//self.grid_size, h//self.grid_size
n_sample_per_grid = self.grid_size//self.pool_size
idx_w = []
idx_h = []
if w>2 and h>2:
for i in range(n_w):
offset = self.grid_size * i
if i < n_w - 1:
this_n = self.grid_size
else:
this_n = x.data.shape[2] - offset

this_idx, _ = torch.sort(torch.randperm(this_n)[:n_sample_per_grid])
idx_w.append(offset + this_idx)
for i in range(n_h):
offset = self.grid_size * i
if i < n_h - 1:
this_n = self.grid_size
else:
this_n = x.data.shape[3] - offset
this_idx, _ = torch.sort(torch.randperm(this_n)[:n_sample_per_grid])
idx_h.append(offset + this_idx)
idx_w = torch.cat(idx_w, dim=0)
idx_h = torch.cat(idx_h, dim=0)
else:
idx_w = torch.LongTensor([0])
idx_h = torch.LongTensor([0])
output = x[:, :, idx_w.cuda()][:, :, :, idx_h.cuda()]
return output

##### 6. Power Average Pooling(幂平均池化)

torch.nn.LPPool1d(norm_type, kernel_size, stride=None, ceil_mode=False)

##### 7. Detail-Preserving Pooling(DPP池化)

• Detail-Preserving Image Downscaling

• 其中是原图，是output，[]表示取对于坐标像素值

• 其中是施加到输入随后的下采样，其随后由一个近似的二维高斯滤波器平滑化的箱式滤波器的结果。如下展示了DPID的结构图，是用近似高斯分布的filter smooth后的图像：
• 下图展示了DPID的滤波图，与普通双边滤波器不同，它奖励输入强度的差异，使得与的差异较大的像素值贡献更大
• Detail-Preserving Pooling
• a. 将上部分中的L2Norm替换成一个可学习的generic scalar reward function：

• b. 首先给出weight的表示：

• c. 这里给出了两种reward function：

• d. 作者又补充了的生成：

DPP池化允许缩减规模以专注于重要的结构细节，可学习的参数控制着细节的保存量，此外，由于细节保存和规范化相互补充，DPP可以与随机合并方法结合使用，以进一步提高准确率

class DetailPooling(nn.Module):
def __init__(self, tensor_size, asymmetric=False, lite=True,
*args, **kwargs):
super(DetailPooling, self).__init__()
self._lambda = nn.Parameter(torch.Tensor(1))
self._alpha = nn.Parameter(torch.Tensor(1))
self.asymmetric = asymmetric
self.lite = lite
if self.lite:
self.weight = torch.FloatTensor([[[[1, 2, 1]]]])
self.weight = self.weight.expand((tensor_size[1], 1, 1, 3))
else:
self.weight = nn.Parameter(torch.rand(*(tensor_size[1], 1, 3, 3)))
self.weight = nn.init.xavier_normal_(self.weight, gain=0.01)
self.tensor_size = tensor_size[:2] + \
F.avg_pool2d(torch.rand(1, 1, tensor_size[2],
tensor_size[3]), (2, 2)).size()[2:]
def forward(self, tensor):
self._alpha.data.pow_(2).pow_(.5)
self._lambda.data.pow_(2).pow_(.5)
if self.lite:
if tensor.is_cuda and not self.weight.is_cuda:
self.weight = self.weight.cuda()
equation2 = F.conv2d(F.conv2d(padded_tensor, self.weight, groups=tensor.size(1)), self.weight.transpose(2, 3), groups=tensor.size(1)).div(16)
else:
eps = 1e-6
if self.asymmetric:
else:
equation56 = equation56.pow(2).pow(self._lambda)
equation7 = equation4.div(F.avg_pool2d(F.pad(equation4, (0, 1, 0, 1), mode="replicate"), (2, 2), (1, 1)).add(1e-8))
equation8 = F.avg_pool2d(tensor.mul(equation7), (2, 2))
return equation8

##### 8. Local Importance Pooling(局部重要性池化)

CNN通常使用空间下采样层来缩小特征图，以实现更大的接受场和更少的内存消耗，但对于某些任务而言，这些层可能由于不合适的池化策略而丢失一些重要细节，最终损失模型精度。为此，作者从局部重要性的角度提出了局部重要性池化，通过基于输入学习自适应重要性权重，LIP可以在下采样过程中自动增加特征判别功能

1. 下采样的位置要尽可能非固定间隔
2. 重要性的函数需通过学习获得

LIP首先在原特征图上学习一个类似于注意力的特征图，然后再和原特征图进行加权求均值，公式可表述如下：

Local Importance Pooling可以学习自适应和可判别性的特征图以汇总下采样特征，同时丢弃无信息特征。这种池化机制能极大保留物体大部分细节，对于一些细节信息异常丰富的任务至关重要

def lip2d(x, logit, kernel size=3, stride=2, padding=1):
weight = torch.exp(logit)
return F.avg pool2d(x∗weight , kernel size, stride, padding)/F.avg pool2d(

##### 9. Soft Pooling(软池化)

SoftPool的计算流程如下：

1. 特征图透过滑动视窗来框选局部数值
2. 框选的局部数值会先经过指数计算，计算出的值为对应的特征数值的权重
3. 将各自的特征数值与其相对应的权重相乘
4. 最后进行加总

SoftPool的数学定义如下：

• 计算特征数值的权重，其中为框选的局部区域，为特征数值

• 将相应的特征数值与权重相乘后做加总操作：

class SOFTPOOL1d(Function):
def forward(ctx, input, kernel=2, stride=None):
no_batch = False
if len(input.size()) == 2:
no_batch = True
input.unsqueeze_(0)
B, C, D = input.size()
kernel = _single(kernel)
if stride is None:
stride = kernel
else:
stride = _single(stride)
oD = (D-kernel[0]) // stride[0] + 1
output = input.new_zeros((B, C, oD))
softpool_cuda.forward_1d(input.contiguous(), kernel, stride, output)
ctx.save_for_backward(input)
ctx.kernel = kernel
ctx.stride = stride
if no_batch:
return output.squeeze_(0)
return output
softpool_cuda.backward_1d(*saved)
saved[-1][torch.isnan(saved[-1])] = 0
return saved[-1], None, None


• 序言：七十年代末，一起剥皮案震惊了整个滨河市，随后出现的几起案子，更是在滨河造成了极大的恐慌，老刑警刘岩，带你破解...
沈念sama阅读 78,954评论 1 174
• 序言：滨河连续发生了三起死亡事件，死亡现场离奇诡异，居然都是意外死亡，警方通过查阅死者的电脑和手机，发现死者居然都...
沈念sama阅读 26,937评论 1 143
• 文/潘晓璐 我一进店门，熙熙楼的掌柜王于贵愁眉苦脸地迎上来，“玉大人，你说我怎么就摊上这事。” “怎么了？”我有些...
开封第一讲书人阅读 30,608评论 0 102
• 文/不坏的土叔 我叫张陵，是天一观的道长。 经常有香客问我，道长，这世上最难降的妖魔是什么？ 我笑而不...
开封第一讲书人阅读 16,804评论 0 87
• 正文 为了忘掉前任，我火速办了婚礼，结果婚礼上，老公的妹妹穿的比我还像新娘。我一直安慰自己，他们只是感情好，可当我...
茶点故事阅读 22,088评论 0 144
• 文/花漫 我一把揭开白布。 她就那样静静地躺着，像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上，一...
开封第一讲书人阅读 18,155评论 0 87
• 那天，我揣着相机与录音，去河边找鬼。 笑死，一个胖子当着我的面吹牛，可吹牛的内容都是我干的。 我是一名探鬼主播，决...
沈念sama阅读 10,931评论 2 162
• 文/苍兰香墨 我猛地睁开眼，长吁一口气：“原来是场噩梦啊……” “哼！你这毒妇竟也来了？” 一声冷哼从身侧响起，我...
开封第一讲书人阅读 10,360评论 0 78
• 想象着我的养父在大火中拼命挣扎，窒息，最后皮肤化为焦炭。我心中就已经是抑制不住地欢快，这就叫做以其人之道，还治其人...
爱写小说的胖达阅读 8,879评论 5 112
• 序言：老挝万荣一对情侣失踪，失踪者是张志新（化名）和其女友刘颖，没想到半个月后，有当地人在树林里发现了一具尸体，经...
沈念sama阅读 12,142评论 0 130
• 正文 独居荒郊野岭守林人离奇死亡，尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
茶点故事阅读 10,900评论 1 126
• 正文 我和宋清朗相恋三年，在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
茶点故事阅读 11,710评论 0 129
• 白月光回国，霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前， 不然我有一百种方法让你生不如死。]我...
爱写小说的胖达阅读 6,538评论 0 17
• 序言：一个原本活蹦乱跳的男人离奇死亡，死状恐怖，灵堂内的尸体忽然破棺而出，到底是诈尸还是另有隐情，我是刑警宁泽，带...
沈念sama阅读 9,326评论 2 116
• 正文 年R本政府宣布，位于F岛的核电站，受9级特大地震影响，放射性物质发生泄漏。R本人自食恶果不足惜，却给世界环境...
茶点故事阅读 12,452评论 3 124
• 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹，春花似锦、人声如沸。这庄子的主人今日做“春日...
开封第一讲书人阅读 8,173评论 0 3
• 文/苍兰香墨 我抬头看了看天上的太阳。三九已至，却和暖如春，着一层夹袄步出监牢的瞬间，已是汗流浃背。 一阵脚步声响...
开封第一讲书人阅读 8,388评论 0 77
• 我被黑心中介骗来泰国打工， 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留，地道东北人。 一个月前我还...
沈念sama阅读 12,919评论 2 133
• 正文 我出身青楼，却偏偏与公主长得像，于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子，可洞房花烛夜当晚...
茶点故事阅读 13,563评论 2 130