FcaNet: Frequency Channel Attention Networks论文总结和代码详解

论文:https://arxiv.org/abs/2012.11879

中文版:FcaNet: Frequency Channel Attention Networks

源码:https://github.com/cfzd/FcaNethttps://gitee.com/yasuo_hao/FcaNet

目录

一、论文背景和出发点

二、创新点

三、离散余弦变换(DCT)和通道注意力

四、Multi-Spectral Channel Attention的具体实现

五、频率分量的选择标准

六、Multi-Spectral Channel Attention代码实现

七、实验

八、总结


一、论文背景和出发点

问题:许多工作都集中在如何设计高效的通道注意机制上,而忽略了一个基本问题,即由于大量的信息丢失,通道注意机制使用标量来表示通道会很困难。(传统的GAP操作,即“平均”操作会极大的抑制特征的多样性,而且会造成大量信息的丢失。)

出发点:在这项工作中,我们从不同的角度出发,将信道表示问题视为使用频率分析的压缩过程。基于频率分析,我们从数学上证明了传统的全局平均池是频域特征分解的一个特例。(为使用离散余弦变换压缩信道提供了可能性。)

有了这些证明,我们自然地推广了信道注意机制在频域中的压缩,并提出了我们的多谱信道注意方法,称为FcaNet。(传统的GAP操作压缩通道的效果不好,因此作者提出使用离散余弦变换(DCT)来压缩信道。)

简单地来说,作者将通道注意力视为一个压缩问题,传统的方式使用全局平均化池会造成大量信息丢失,所以作者建议在信道注意力机制中使用离散余弦变换(DCT)来压缩通道。

二、创新点

1. 证明了传统GAP(全局平均化池)是DCT(离散余弦变换)的特例。

2. 提出了三种频率分量选择标准以及建议的多光谱信道注意力框架,以实现FcaNet。

3. 大量实验表明,该方法在ImageNet和COCO数据集上都取得了最先进的结果,计算成本与SENet相同。在ImageNet数据集上的结果,如下图所示:

三、离散余弦变换(DCT)和通道注意力

1. 离散余弦变换DCT

作用:

(1)2维DCT的基函数

(2)2维DCT

DCT变换就是将原图像和DCT基函数进行内积运算。

 其中f^{2d}\in \mathbb{R}^{H\times W}x^{2d}的2D DCT频谱,x^{2d}\in \mathbb{R}^{H\times W}是输入图像,Hx^{2d}的高度,Wx^{2d}的宽度,B^{i,j}是2维DCT的基函数,h ∈ { 0, 1, · · · , H−1 },w ∈ { 0, 1, · · · , W−1 }。

(3)逆2维DCT

2. 通道注意力

传统方式的阐述,以SE模块为例。

(1)注意力向量

其中,att\in \mathbb{R}^C是注意力向量,sigmoid是sigmoid函数,fc代表映射函数,如全连接层或一维卷积,compress:R^{C\times H\times W}\mapsto R^C是一种压缩方法(SE模块中使用全局平均池化GAP)。详情可参考:SENet的Squeeze操作和Excitation操作

(2)缩放

在获得所有通道的注意力向量后,输入X的每个通道按相应的注意力值进行缩放:

其中,X̃是注意力机制的输出,att_i是注意力向量的第i个元素,X_{:,i,:,:}是输入图像的第i个通道。详情可参考:SENet的Scale操作

3. 证明:GAP是2D-DCT的特例

将2维DCT公式中的h和w都置为0,得到:

f^{2d}_{0,0}表示最低频率分量与gap函数成正比,由上式可见,gap函数是2维DCT的一种特例。

结论在信道注意机制中使用GAP意味着只保留最低频率的信息。

推广:除了低频信息以外,其他频率的所有分量也表示信道的有用信息不应被遗弃,所以作者提出在注意力机制中将GAP推广到2D DCT,并用2D DCT的多个频率分量压缩更多信息。

四、Multi-Spectral Channel Attention的具体实现

多光谱通道注意力模块,如下图所示:

1. 分割

沿通道维度方向将输入X分成\left [ X_0,X_1,\cdots ,X_{n-1} \right ]

其中,X_i \in R^{C' \times H \times W} , i \in \{0, 1,\cdots , n-1\}, C' = \frac{C}{n},通道数C被分为了n份。

2. 压缩

对于每个X_i,分配相应的2D-DCT频率分量用作每个X_i的压缩,得到的{Freq}^i构成通道注意力的各个分量。

 其中,[u_i,v_i]是对应于X^i的频率分量2维指数,{Freq}^i \in {\mathbb{R}^{C'}}是压缩后的C'维向量。

3. 拼接

对每个{Freq}^i进行拼接操作,得到多光谱向量。

其中,Freq\in R^C是获得的多光谱向量。

4. 多光谱通道注意力

为了获取通道注意力,多光谱向量还要经过全连接层和sigmoid处理。整个多光谱通道注意力框架可以表示为:

获取到通道注意力之后的步骤与SEnet基本一致。

五、频率分量的选择标准

如何为每个X_i选择频率分量指数[u_i,v_i]是一个重要问题,作者提出了三个选择标准。

1. FcaNet LF(低频)

只选择低频分量。

2. FcaNet TS(两步选择)

第一步:分别评估通道注意力中每个频率分量的结果。

第二步:根据评估结果,我们选择了性能最高的Top-k频率分量。

3. FcaNet NAS(神经结构搜索)

使用神经结构搜索来搜索信道的最佳频率分量。

对于每个X_i,将一组连续变量\alpha =\{\alpha(u,v)\}配给搜索组件。该X_i的频率分量可以表示为:

其中O是包含所有2D DCT频率分量索引的集合。训练后,X_i的频率分量等于\{\alpha(u,v)\}中的最大值。

六、Multi-Spectral Channel Attention代码实现

步骤

1. 先选择标准频率分量,主要是获取频率分量对应的h、w,源码中使用mapper_x,mapper_y表示。

def get_freq_indices(method):
    assert method in ['top1','top2','top4','top8','top16','top32',
                      'bot1','bot2','bot4','bot8','bot16','bot32',
                      'low1','low2','low4','low8','low16','low32']
    num_freq = int(method[3:])
    if 'top' in method:
        all_top_indices_x = [0,0,6,0,0,1,1,4,5,1,3,0,0,0,3,2,4,6,3,5,5,2,6,5,5,3,3,4,2,2,6,1]
        all_top_indices_y = [0,1,0,5,2,0,2,0,0,6,0,4,6,3,5,2,6,3,3,3,5,1,1,2,4,2,1,1,3,0,5,3]
        mapper_x = all_top_indices_x[:num_freq]
        mapper_y = all_top_indices_y[:num_freq]
    elif 'low' in method:
        all_low_indices_x = [0,0,1,1,0,2,2,1,2,0,3,4,0,1,3,0,1,2,3,4,5,0,1,2,3,4,5,6,1,2,3,4]
        all_low_indices_y = [0,1,0,1,2,0,1,2,2,3,0,0,4,3,1,5,4,3,2,1,0,6,5,4,3,2,1,0,6,5,4,3]
        mapper_x = all_low_indices_x[:num_freq]
        mapper_y = all_low_indices_y[:num_freq]
    elif 'bot' in method:
        all_bot_indices_x = [6,1,3,3,2,4,1,2,4,4,5,1,4,6,2,5,6,1,6,2,2,4,3,3,5,5,6,2,5,5,3,6]
        all_bot_indices_y = [6,4,4,6,6,3,1,4,4,5,6,5,2,2,5,1,4,3,5,0,3,1,1,2,4,2,1,1,5,3,3,3]
        mapper_x = all_bot_indices_x[:num_freq]
        mapper_y = all_bot_indices_y[:num_freq]
    else:
        raise NotImplementedError
    return mapper_x, mapper_y

2. 参考数学公式,构建dct波滤器

源码如下

    def build_filter(self, pos, freq, POS):
        result = math.cos(math.pi * freq * (pos + 0.5) / POS) / math.sqrt(POS) 
        if freq == 0:
            return result
        else:
            return result * math.sqrt(2)
    
    def get_dct_filter(self, tile_size_x, tile_size_y, mapper_x, mapper_y, channel):
        dct_filter = torch.zeros(channel, tile_size_x, tile_size_y)

        c_part = channel // len(mapper_x)

        for i, (u_x, v_y) in enumerate(zip(mapper_x, mapper_y)):
            for t_x in range(tile_size_x):
                for t_y in range(tile_size_y):
                    # 构建DCT滤波器,对应数学公式
                    dct_filter[i * c_part: (i+1)*c_part, t_x, t_y] = self.build_filter(t_x, u_x, tile_size_x) * self.build_filter(t_y, v_y, tile_size_y)
                        
        return dct_filter

3.  dct波滤器与输入图像X进行点乘,注意这里的dct波滤器是一组波滤器,与输入图像X进行点乘,实际上是每一个X_i与其对应的dct波滤器进行点乘,再经过torch.sum(x, dim=[2,3])消去X的H、W,完成R^{C\times H\times W}\mapsto R^C压缩过程,即可得到X的2D DCT频谱,即多光谱向量

源码如下: 

class MultiSpectralDCTLayer(nn.Module):
    """
    Generate dct filters
    """
    def __init__(self, height, width, mapper_x, mapper_y, channel):
        super(MultiSpectralDCTLayer, self).__init__()
        
        assert len(mapper_x) == len(mapper_y)
        assert channel % len(mapper_x) == 0

        self.num_freq = len(mapper_x)

        # fixed DCT init
        # 返回一组DCT滤波器
        self.register_buffer('weight', self.get_dct_filter(height, width, mapper_x, mapper_y, channel))
        
        # fixed random init
        # self.register_buffer('weight', torch.rand(channel, height, width))

        # learnable DCT init
        # self.register_parameter('weight', self.get_dct_filter(height, width, mapper_x, mapper_y, channel))
        
        # learnable random init
        # self.register_parameter('weight', torch.rand(channel, height, width))

        # num_freq, h, w

    def forward(self, x):
        assert len(x.shape) == 4, 'x must been 4 dimensions, but got ' + str(len(x.shape))
        # n, c, h, w = x.shape
        
        # DCT变换
        # x与DCT滤波器内积
        x = x * self.weight
        # 消去x的2,3维
        result = torch.sum(x, dim=[2,3])
        return result

4.  X的多光谱向量,再经过全连接层 + relu激活 + 全连接层 + sigmoid激活,最终可得到一个通道注意力向量。通道注意力向量与原图像x相乘,进行重新加权。

源码如下

class MultiSpectralAttentionLayer(torch.nn.Module):
    def __init__(self, channel, dct_h, dct_w, reduction = 16, freq_sel_method = 'top16'):
        super(MultiSpectralAttentionLayer, self).__init__()
        self.reduction = reduction
        self.dct_h = dct_h
        self.dct_w = dct_w

        mapper_x, mapper_y = get_freq_indices(freq_sel_method)
        self.num_split = len(mapper_x)
        mapper_x = [temp_x * (dct_h // 7) for temp_x in mapper_x] 
        mapper_y = [temp_y * (dct_w // 7) for temp_y in mapper_y]
        # make the frequencies in different sizes are identical to a 7x7 frequency space
        # eg, (2,2) in 14x14 is identical to (1,1) in 7x7

        # 返回x的多光谱向量
        self.dct_layer = MultiSpectralDCTLayer(dct_h, dct_w, mapper_x, mapper_y, channel)
        # 全连接层 + relu激活 + 全连接层 + sigmoid激活,返回一个通道注意力向量
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        n,c,h,w = x.shape
        x_pooled = x
        if h != self.dct_h or w != self.dct_w:
            x_pooled = torch.nn.functional.adaptive_avg_pool2d(x, (self.dct_h, self.dct_w))
            # If you have concerns about one-line-change, don't worry.   :)
            # In the ImageNet models, this line will never be triggered. 
            # This is for compatibility in instance segmentation and object detection.
        y = self.dct_layer(x_pooled)

        y = self.fc(y).view(n, c, 1, 1)
        # 通道注意力向量与原图像x相乘
        return x * y.expand_as(x)

这篇博文有部分代码的详细注解:FcaNet从频域角度重新思考CV注意力机制

七、实验

数据集:ImageNet,COCO数据集。

网络:ResNet-34、ResNet-50、ResNet-101和ResNet-152。

1. 在ImageNet上不同注意力方法的比较

 在相同的计算成本下,FcaNet优于对比的不同注意力方法。

2. 在CoCo上不同注意力方法的比较

  在不同的数据集上,FcaNet依然优于对比的不同注意力方法。

八、总结

在本文中,研究了通道注意力的一个基本问题,即如何表示通道,并将此问题视为一个压缩过程。证明了GAP是DCT的一个特例,并提出了具有多谱注意力模块的FcaNet,它在频域上推广了现有的信道注意力机制。同时,在多谱框架中探索了频率分量的不同组合,并提出了频率分量选择的三个标准。在相同数量的参数和计算成本的情况下,本文提出的方法可以始终优于SENet。与其他通道注意力方法相比,我们在图像分类、对象检测和实例分割方面也取得了最先进的性能。此外,FcaNet简单而有效。本文提出的方法可以在现有信道注意力方法的基础上,只需更改几行代码即可实现。

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: fcanet是一种频道注意力网络,它可以在图像分类和目标检测等任务中提高模型的性能。该网络通过学习每个频道的重要性来自适应地调整每个频道的权重,从而提高模型的准确性和鲁棒性。fcanet是一种有效的深度学习模型,已经在许多计算机视觉任务中得到了广泛应用。 ### 回答2: FCANet是一种用于解决计算机视觉领域中图像分类问题的深度神经网络。该神经网络通过引入一种新的注意力机制来改善模型的性能,称为频道注意网络。FCANet可以有效地对图像分类问题进行建模和处理。 FCANet中的新注意力机制,即频道注意网络,旨在通过自适应地对通道加权来对抽取的特征进行进一步处理。这个权重因子是根据特征通道上全局平均池化操作的输出构建的,从而可以自适应地学习在输入特征通道的不同权重下进行特征选择的偏好。因此,FCANet能够更好地利用输入特征的不同通道间的信息。 与其他基于注意力机制的模型相比,频道注意网络具有以下优点: 1. 独特性:频道注意网络是一种独特的注意力机制,与其他注意力模型不同。 2. 自适应性:通过自适应地学习通道之间的关系和选择权重,FCANet可以更好地适应复杂的视觉场景。 3. 鲁棒性:频道注意网络可以有效地过滤掉不重要的特征通道,并在同时具有噪声和变化的情况下保持高度鲁棒性。 FCANet的应用场景非常广泛,可以应用于图像分类、目标检测、语义分割和图像生成等多种计算机视觉任务中。它是当前计算机视觉领域中极具前景的深度学习技术之一。 ### 回答3: FCANet是一种基于频率通道注意力的神经网络模型。它通过对频域和通道维度之间的关系进行建模来增强卷积神经网络的性能。频率通道注意力是一种用于增强CNN网络的新技术,可以帮助网络更好地区分出不同类别之间的细节信息。 FCANet的主要优点在于它可以自适应地学习到每个通道的重要性并加以利用。如果一些通道很少使用,则它们的权重将被降低,从而提高其他通道的权重,这可以更好地利用网络的资源。此外,FCANet还能够学习到不同频率上的不同特征,进一步提升模型的性能。 FCANet的结构由两个主要部分组成:频率放大模块和通道注意力模块。频率放大模块将输入的图像转换为频率域,增加了模型对低频和高频细节的感知能力,从而增强了网络的特征提取能力。通道注意力模块则通过对不同通道之间的关系建模,提高了模型区分不同类别之间细节的能力。 总而言之,FCANet是一种全新的神经网络模型,它通过在频率和通道维度上建模关系,提升了模型的特征提取和分类能力。它具有很好的应用前景,在图像识别、语音识别等领域有广泛的应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向岸看

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值