MOGANET-CA模块

paper
(1) 前向路径
fc1 和 dwconv:
第一部分是一个标准的 ConvFFN 模块,先用逐点卷积(fc1)将输入特征维度扩展为 4 倍的 feedforward_channels,然后通过深度卷积(dwconv)增强局部特征提取能力。
act 和 drop:
在激活函数后使用 dropout,增强泛化能力。
(2) 特征分解
特征分解 (feat_decompose) 是模块的核心亮点:

全局特征生成:
使用一个逐点卷积(decompose)生成单通道全局特征图 (t),通过 GELU 激活增强非线性建模能力。
特征去偏与差异信息提取:
原始特征减去全局特征 (x - t),提取局部差异信息。
可学习缩放:
使用 ElementScale 调节特定特征的重要性,为每个通道分配动态权重。
特征重整合:
将调整后的特征加回原始特征 (x + t),保留了全局特征,同时增强了局部信息。
这一设计增强了模型在局部细节和全局特征间的权衡能力。

(3) 第二阶段投影
fc2:
最后一层逐点卷积将通道数投影回原始维度,完成特征变换。

import torch
import torch.nn as nn


def build_act_layer(act_type):
    #Build activation layer
    if act_type is None:
        return nn.Identity()
    assert act_type in ['GELU', 'ReLU', 'SiLU']
    if act_type == 'SiLU':
        return nn.SiLU()
    elif act_type == 'ReLU':
        return nn.ReLU()
    else:
        return nn.GELU()

class ElementScale(nn.Module):
    #A learnable element-wise scaler.

    def __init__(self, embed_dims, init_value=0., requires_grad=True):
        super(ElementScale, self).__init__()
        self.scale = nn.Parameter(
            init_value * torch.ones((1, embed_dims, 1, 1)),
            requires_grad=requires_grad
        )

    def forward(self, x):
        return x * self.scale

class ChannelAggregationFFN(nn.Module):
    """An implementation of FFN with Channel Aggregation.

    Args:
        embed_dims (int): The feature dimension. Same as
            `MultiheadAttention`.
        feedforward_channels (int): The hidden dimension of FFNs.
        kernel_size (int): The depth-wise conv kernel size as the
            depth-wise convolution. Defaults to 3.
        act_type (str): The type of activation. Defaults to 'GELU'.
        ffn_drop (float, optional): Probability of an element to be
            zeroed in FFN. Default 0.0.
    """

    def __init__(self,
                 embed_dims,
                 kernel_size=3,
                 act_type='GELU',
                 ffn_drop=0.):
        super(ChannelAggregationFFN, self).__init__()

        self.embed_dims = embed_dims
        self.feedforward_channels = int(embed_dims * 4)

        self.fc1 = nn.Conv2d(
            in_channels=embed_dims,
            out_channels=self.feedforward_channels,
            kernel_size=1)
        self.dwconv = nn.Conv2d(
            in_channels=self.feedforward_channels,
            out_channels=self.feedforward_channels,
            kernel_size=kernel_size,
            stride=1,
            padding=kernel_size // 2,
            bias=True,
            groups=self.feedforward_channels)
        self.act = build_act_layer(act_type)
        self.fc2 = nn.Conv2d(
            in_channels=self.feedforward_channels,
            out_channels=embed_dims,
            kernel_size=1)
        self.drop = nn.Dropout(ffn_drop)

        self.decompose = nn.Conv2d(
            in_channels=self.feedforward_channels,  # C -> 1
            out_channels=1, kernel_size=1,
        )
        self.sigma = ElementScale(
            self.feedforward_channels, init_value=1e-5, requires_grad=True)
        self.decompose_act = build_act_layer(act_type)

    def feat_decompose(self, x):
        # x_d: [B, C, H, W] -> [B, 1, H, W]
        t=self.decompose(x)  #  将多通道用一个通道来表示
        t=self.decompose_act(t) # 对单通道应用GELU激活函数 增加非线性  帮助模型学习更加复杂的模式
        t=x - t #原始特征图减去t  去除或削弱了x与temp相似的特征  如果t是全局或主要特征 那么x-t可以理解成局部或差异信息
        t=self.sigma(t) # 包含一个可学习的参数 用来调整每个通道的权重
        x = x + t  # 将原特征图和缩放之后的特定信息相加
        return x

    def forward(self, x):
        # proj 1
        x = self.fc1(x)
        x = self.dwconv(x)
        x = self.act(x)
        x = self.drop(x)
        # proj 2
        x = self.feat_decompose(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


if __name__ == '__main__':
    input = torch.randn(1, 64, 32, 32).cuda()# 输入 B C H W
    block = ChannelAggregationFFN(embed_dims=64).cuda()
    output = block(input)
    print(input.size())
    print(output.size())

posted @ 2024-11-09 17:04  iceeci  阅读(8)  评论(0编辑  收藏  举报