3 SoftPool方法
从这里开始正式介绍SoftPool中信息的正向传播和反向传播。考虑activation map(a)中的 local region (R),其维数为C×H×W,通道数为C,通道高度为H,通道宽度为W。为了简化符号这里省略通道维数,并假设R是与考虑的二维空间区域的激活相对应的索引集。对于大小为k×k的池化kernel定义。池化操作的输出为,对应的梯度用表示。
3.1 Exponential maximum kernels
SoftPool受到Riesenhuber和Poggio的皮层神经模拟以及早期使用Boureau等人的手工编码特征的池化实验的影响。该方法以自然指数(e)为基础,保证了较大的激活值对输出的影响较大。
SoftPool是可微的,这意味着所有在局部邻域内的激活在反向传播期间将被分配至少一个最小梯度值。这与使用最大池化的方法相反。SoftPool利用激活区域内的最大近似R。每一个指数为的激活应用一个权重,该权重计算为该激活的自然指数与邻域R内所有激活的自然指数之和的比值:
权重与相应的激活值一起用作非线性变换。较高的激活比较低的激活占更多的主导地位。因为大多数池化操作都是在高维的特征空间中执行的,突出显示具有更大效果的激活比简单地选择最大值是一种更平衡的方法。
在后一种情况下,丢弃大部分激活会带来丢失重要信息的风险。相反,平均池化中激活的贡献相等,可以显著降低整体区域特征强度。
SoftPool操作的输出值是通过对内核邻域R内所有加权激活的标准求和得到的:
与其他基于最大池化和平均池化的方法相比,使用区域的softmax产生归一化结果,其概率分布与每个激活值相对于核区域的邻近激活值成比例。这与最大激活值选择或对内核区域的所有激活取平均形成了直接对比,而内核区域的输出激活是没有规则化的。因此是可微的。
Pytorch实现soft_pool2d如下:
def soft_pool2d(x, kernel_size=2, stride=None, force_inplace=False): if x.is_cuda and not force_inplace: return CUDA_SOFTPOOL2d.apply(x, kernel_size, stride) kernel_size = _pair(kernel_size) if stride is None: stride = kernel_size else: stride = _pair(stride) # Get input sizes _, c, h, w = x.size() # Create per-element exponential value sum : Tensor [b x 1 x h x w] e_x = torch.sum(torch.exp(x),dim=1,keepdim=True) # Apply mask to input and pool and calculate the exponential sum # Tensor: [b x c x h x w] -> [b x c x h' x w'] return F.avg_pool2d(x.mul(e_x), kernel_size, stride=stride).mul_(sum(kernel_size)).div_(F.avg_pool2d(e_x, kernel_size, stride=stride).mul_(sum(kernel_size)))
3.2 Gradient calculation
完整的向前和向后信息流下图所示:
在训练的更新阶段,所有网络参数的梯度都是根据在上一层计算的误差导数进行更新的。当在整个网络体系结构中反向传播时,这会创建一个更新链。在SoftPool中,梯度更新与前向传播过程中计算的权重成比例。这对应于较小激活的梯度更新小于实质性激活的梯度更新。
Softmax与max或随机池化不同,Softmax是可微的。因此,在反向传播期间,一个最小的非零权值将被分配给一个核区域内的每一个激活。这样就可以计算出该区域每一次激活的梯度。
在SoftPool实现中使用了给定精度级别有限范围的可能值,保留了softmax的可微性质,通过给定每个类型使用的比特数分配一个较低的算术限制。这可以防止算术下溢。也为内核值和最终求和中使用的生成的激活值实现了这种机制。
3.3 Feature preservation
Sub-Sampling的一个整体目标是在保持输入的代表性特征的同时最小化整体分辨率。创建原始输入的无代表性的下采样可能对整个模型的性能有负面影响,因此输入的表示可能对任务也会有负面影响。
目前广泛使用的池化技术在某些情况下可能是无效的。Avg Pooling降低了该区域内所有激活的效果,而Max Pooling仅选择该区域内单个激活最高的激活。
SoftPool的作用介于这两种池化方法之间,因为该区域的所有激活都对最终输出有贡献,而较高的激活比较低的激活占主导地位。该方法可以平衡Avg Pooling和Max Pooling的影响,同时利用两者的有利属性。
下图显示了SoftPool可以保留的详细级别的示例,即使在图像被大量抽样的情况下颜色与原始图像保持一致。
3.4 Spatio-temporal kernels
CNN也被扩展到使用3D输入来表示额外的维度,如深度和时间。为了适应这些输入,可以通过在内核中包含一个额外的维度对SoftPool进行扩展;对于一个具有维度的输入激活映射,以T为时间范围,将二维空间核区域R转换为三维时空区域,其中三维空间在时间维度上运行。
产生的输出现在包含压缩的时空信息。通过增加维度,所需的池化属性(如有限的信息丢失、可微函数以及较低的计算和内存开销)变得更加重要。Pytorch实现soft_pool3d如下:
def soft_pool3d(x, kernel_size=2, stride=None, force_inplace=False): if x.is_cuda and not force_inplace: return CUDA_SOFTPOOL3d.apply(x, kernel_size, stride) kernel_size = _triple(kernel_size) if stride is None: stride = kernel_size else: stride = _triple(stride) # Get input sizes _, c, d, h, w = x.size() # Create per-element exponential value sum : Tensor [b x 1 x d x h x w] e_x = torch.sum(torch.exp(x),dim=1,keepdim=True) # Apply mask to input and pool and calculate the exponential sum # Tensor: [b x c x d x h x w] -> [b x c x d' x h' x w'] return F.avg_pool3d(x.mul(e_x), kernel_size, stride=stride).mul_(sum(kernel_size)).div_(F.avg_pool3d(e_x, kernel_size, stride=stride).mul_(sum(kernel_size)))
4 实验结果
4.1 ImageNet-1K分类
通过上表可以看出,直接在Backbone的基础上把池化方法替换为SotfPool,效果有明显的提升。
4.2 视频分类实验
可以看出即使是3D CNN Model中SoftPool依然有效。
5 参考
[1].Refining activation downsampling with SoftPool.
[2].https://github.com/alexandrosstergiou/SoftPool.