样本中含有噪声,或者与标签无关的冗余信息,会导致深度学习算法的效果有所降低
背景复杂,会对分类的结果造成不利影响,剔除这些背景的特征,可以有效提高识别的效果
这种方法原本应用在强噪振动信号,应该也可以应用在复杂背景的图像上
深度残差收缩网络面向的是数据包含噪声的情况。事实上,这里的“噪声”,可以有更宽泛的解释。“噪声”不仅可以指数据获取过程中所掺杂的噪声,而且可以指“与当前任务无关的信息”。
比如说,我们在训练一个猫狗分类器的时候,如果图像中存在老鼠,那么老鼠就可以理解为一种噪声。
软阈值化在残差收缩网络中是作为非线性映射,而现在深度学习最常用的非线性映射是ReLU激活函数。所以下面进行了两者的对比。
软阈值化和ReLU的梯度都要么为0,要么为1,都有利于梯度的反向传播
ReLU将低于0的特征,全部删除(置为0);大于0的特征,全部保留(保持不变)
软阈值函数呢?它将某个区间,也就是[-阈值,阈值]这一区间内的特征删除(置为零);将这个区间之外的部分,包括大于阈值和小于-阈值的部分,保留下来(虽然朝向0进行了收缩)。下图展示了阈值t=10的情况:
避免了人工设置阈值的麻烦。(人工设置阈值一直是一个大麻烦,而残差收缩网络用注意力机制解决了这个大麻烦)。
注意力:
首先是 Squeeze 操作,我们顺着空间维度来进行特征压缩,将每个二维的特征通道变成一个实数,这个实数某种程度上具有全局的感受野,并且输出的维度和输入的特征通道数相匹配。它表征着在特征通道上响应的全局分布,而且使得靠近输入的层也可以获得全局的感受野,这一点在很多任务中都是非常有用的。
其次是 Excitation 操作,它是一个类似于循环神经网络中门的机制。通过参数 w 来为每个特征通道生成权重,其中参数 w 被学习用来显式地建模特征通道间的相关性。
最后是一个 Reweight 的操作,我们将 Excitation 的输出的权重看做是进过特征选择后的每个特征通道的重要性,然后通过乘法逐通道加权到先前的特征上,完成在通道维度上的对原始特征的重标定
度残差收缩网络就是将残差模式下的 SENet 中的“重新加权”替换成了“软阈值化”。
在图(a)中,整个特征图共用一个阈值
在图©中,特征图的每个通道各有一个独立的阈值
是(各个特征通道的绝对值的平均值)×(一组 0 和 1 之间的系数)。
首先评估各个特征通道的重要程度,然后根据其重要程度赋予各个特征通道合适的权重。
SE模块是在channel维度上做attention或者gating操作,这种注意力机制让模型可以更加关注信息量最大的channel特征
这里我们使用 global average pooling 作为 Squeeze 操作。紧接着两个 Fully Connected 层组成一个 Bottleneck 结构去建模通道间的相关性,并输出和输入特征同样数目的权重。我们首先将特征维度降低到输入的 1/16,然后经过 ReLu 激活后再通过一个 Fully Connected 层升回到原来的维度。这样做比直接用一个 Fully Connected 层的好处在于:1)具有更多的非线性,可以更好地拟合通道间复杂的相关性;2)极大地减少了参数量和计算量。然后通过一个 Sigmoid 的门获得 0~1 之间归一化的权重,最后通过一个 Scale 的操作来将归一化后的权重加权到每个通道的特征上。
本文提出了两种深度残差收缩网络,即通道间共享阈值的深度残差收缩网络、通道间不同阈值的深度残差收缩网络,
在软阈值化中,共考虑了两种阈值,也就是通道间共享的阈值、通道间不同的阈值。这也是所提出方法名称的由来
总结:
残差收缩网络的阈值,是在注意力机制下,根据每个样本的情况,单独设置的。也就是,每个样本,都有自己的一组独特的阈值。因此,残差收缩网络适用于各个样本中噪声含量不同的情况。
残差收缩网络应该可以用于弱噪声的数据。残差收缩网络中的阈值,是根据样本自身的情况,通过一个小型子网络自动获得的。如果样本所含噪声很少,那么阈值可以被自动设置得很低(接近于0),从而“软阈值化”就退化成了“直接相等”。在这种情况下,软阈值化,就相当于不存在了。
class Shrinkage(nn.Module):
def __init__(self, gap_size, channel):
super(Shrinkage, self).__init__()
self.gap = nn.AdaptiveAvgPool2d(gap_size)
self.fc = nn.Sequential(
nn.Linear(channel, channel),
nn.BatchNorm1d(channel),
nn.ReLU(inplace=True),
nn.Linear(channel, 1),
nn.Sigmoid(),
)
def forward(self, x):
x_raw = x
x = torch.abs(x)
x_abs = x
x = self.gap(x)
x = torch.flatten(x, 1)
average = torch.mean(x, dim=1, keepdim=True)
# average = x
x = self.fc(x)
x = torch.mul(average, x)
缩放参数𝛼乘以|𝑥|的平均值以获得阈值。,软阈值化的阈值不仅需要为正,而且不能太大。如果阈值大于特征图的最大绝对值,软阈值的输出将为零
x = x.unsqueeze(2).unsqueeze(2)
# 软阈值化
sub = x_abs - x
zeros = sub - sub
n_sub = torch.max(sub, zeros)
阈值由下式表示
如果阈值大于特征图的最大绝对值,软阈值的输出将为零
x = torch.mul(torch.sign(x_raw), n_sub)
return x
在图像分类任务中,这个模型效果不太行,与baseline相比,几乎没有提升,还有点下降,对于图像来讲这个还是慎用,因为它将channel给平均下来了。
class Shrinkage(nn.Module):
def __init__(self, gap_size, channel):
super(Shrinkage, self).__init__()
self.gap = nn.AdaptiveAvgPool2d(gap_size)
self.fc = nn.Sequential(
nn.Linear(channel, channel),
nn.BatchNorm1d(channel),
nn.ReLU(inplace=True),
nn.Linear(channel, 1),# 可能应该是nn.Linear(channel, channel)
nn.Sigmoid(),
)
def forward(self, x):
x_raw = x
x = torch.abs(x)
x_abs = x
x = self.gap(x)
x = torch.flatten(x, 1)
# average = torch.mean(x, dim=1, keepdim=True)
average = x
x = self.fc(x)
x = torch.mul(average, x)
x = x.unsqueeze(2).unsqueeze(2)
# 软阈值化
sub = x_abs - x
zeros = sub - sub
n_sub = torch.max(sub, zeros)
x = torch.mul(torch.sign(x_raw), n_sub)
return x
全局平均池化 GAP