【即插即用】GnConv递归门控卷积(附源码)

论文地址:

https://arxiv.org/abs/2207.14284


源码地址:

https://github.com/raoyongming/HorNetGnConvGnConvHorNet

摘要简介:

最近,视觉Transformer在各种任务中取得了巨大成功,这主要得益于基于点积自注意力的新型空间建模机制。在本文中,我们发现视觉Transformer的关键要素,即输入自适应、长距离和高阶空间交互,也可以高效地在基于卷积的框架中实现。

我们提出了一种递归门控卷积(gnConv),它利用门控卷积和递归设计实现高阶空间交互。这种新操作高度灵活且可定制,能与各种卷积变体兼容,并将自注意力中的二阶交互扩展到任意阶,而不会引入大量额外计算。gnConv可以作为一个即插即用的模块,用于改进各种视觉Transformer和基于卷积的模型。

基于gnConv操作,我们构建了一个新的通用视觉骨干网络家族,名为HorNet。在ImageNet分类、COCO目标检测和ADE20K语义分割等多个实验中,HorNet展现出比Swin Transformer和ConvNeXt更优越的性能,而整体架构和训练配置相似。此外,HorNet还表现出对更多训练数据和更大模型尺寸的良好可扩展性。

除了在视觉编码器中的有效性,我们还展示了gnConv可以应用于特定任务的解码器,并在减少计算的同时持续提高密集预测性能。我们的结果表明,gnConv可以成为视觉建模的新基本模块,有效结合视觉Transformer和卷积神经网络(CNN)的优点。相关代码可以在此网址找到。

简单来说,我们发现了一种新的卷积方法,可以像视觉Transformer那样捕捉图像中的高阶空间交互。基于这种新方法,我们创建了一个新的图像处理模型HorNet,它在多个视觉任务中都表现得比现有方法更好。这个新方法不仅适用于图像的主要处理部分,还可以用在特定的任务中,帮助我们更准确地预测图像中的细节,同时减少了计算量。

结构图:
Pytorch版源码:
import torch
import torch.nn as nn
import torch.nn.functional as F

def get_dwconv(dim, kernel, bias):
    return nn.Conv2d(dim, dim, kernel_size=kernel, padding=(kernel-1)//2, bias=bias, groups=dim)

class LayerNorm(nn.Module):
    def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(normalized_shape))
        self.bias = nn.Parameter(torch.zeros(normalized_shape))
        self.eps = eps
        self.data_format = data_format
        if self.data_format not in ["channels_last", "channels_first"]:
            raise NotImplementedError
        self.normalized_shape = (normalized_shape,)

    def forward(self, x):
        if self.data_format == "channels_last":
            return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
        elif self.data_format == "channels_first":
            u = x.mean(1, keepdim=True)
            s = (x - u).pow(2).mean(1, keepdim=True)
            x = (x - u) / torch.sqrt(s + self.eps)
            x = self.weight[:, None, None] * x + self.bias[:, None, None]
            return x

class GnConv(nn.Module):
    def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):
        super().__init__()
        self.order = order
        self.dims = [dim // 2 ** i for i in range(order)]
        self.dims.reverse()
        self.proj_in = nn.Conv2d(dim, 2 * dim, 1)

        if gflayer is None:
            self.dwconv = get_dwconv(sum(self.dims), 7, True)
        else:
            self.dwconv = gflayer(sum(self.dims), h=h, w=w)

        self.proj_out = nn.Conv2d(dim, dim, 1)

        self.pws = nn.ModuleList(
            [nn.Conv2d(self.dims[i], self.dims[i + 1], 1) for i in range(order - 1)]
        )

        self.scale = s

        print('[gconv]', order, '阶与维度=', self.dims, '尺度=%.4f' % self.scale)

    def forward(self, x, mask=None, dummy=False):
        B, C, H, W = x.shape

        fused_x = self.proj_in(x)
        pwa, abc = torch.split(fused_x, (self.dims[0], sum(self.dims)), dim=1)

        dw_abc = self.dwconv(abc) * self.scale

        dw_list = torch.split(dw_abc, self.dims, dim=1)
        x = pwa * dw_list[0]

        for i in range(self.order - 1):
            x = self.pws[i](x) * dw_list[i + 1]

        x = self.proj_out(x)

        return x

class GnBlock(nn.Module):
    def __init__(self, dim, shortcut=False, layer_scale_init_value=1e-6):
        super().__init__()
        self.shortcut = shortcut
        self.norm1 = LayerNorm(dim, eps=1e-6, data_format='channels_first')
        self.gnconv = GnConv(dim, order=5)
        self.norm2 = LayerNorm(dim, eps=1e-6, data_format='channels_last')
        self.pwconv1 = nn.Linear(dim, 2 * dim)
        self.act = nn.GELU()
        self.pwconv2 = nn.Linear(2 * dim, dim)
        self.gamma1 = nn.Parameter(layer_scale_init_value * torch.ones(dim),
                                   requires_grad=True) if layer_scale_init_value > 0 else None
        self.gamma2 = nn.Parameter(layer_scale_init_value * torch.ones((dim)),
                                   requires_grad=True) if layer_scale_init_value > 0 else None


    def forward(self, x):
        B, C, H, W = x.shape
        if self.gamma1 is not None:
            gamma1 = self.gamma1.view(1, C, 1, 1)
        else:
            gamma1 = 1
        x = (x + gamma1 * self.gnconv(self.norm1(x))) if self.shortcut else gamma1 * self.gnconv(self.norm1(x))
        input = x
        x = x.permute(0, 2, 3, 1)  # (N, C, H, W) -> (N, H, W, C)
        x = self.norm2(x)
        x = self.pwconv1(x)
        x = self.act(x)
        x = self.pwconv2(x)
        x = x.permute(0, 3, 1, 2)  # (N, H, W, C) -> (N, C, H, W)
        if self.gamma2 is not None:
            gamma2 = self.gamma2.view(1, C, 1, 1)
            x = gamma2 * x
        else:
            gamma2 = 1
        x = (input + x) if self.shortcut else x
        return x


# 使用一个示例输入进行代码测试
if __name__ == "__main__":
    # 创建一个示例输入张量
    input_tensor = torch.randn(1, 32, 128, 128)  # 批量大小,通道数,高度,宽度
    model = GnBlock(32)  # 使用与输入通道数相同的维度初始化 GnBlock
    output = model(input_tensor)  # 前向传播

    # 打印输出的尺寸
    print("输出尺寸:", output.size())

  • 33
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
YOLOv7引入了递归门控卷积gnConv)来改善目标检测效果。主干特征提取网络为CNN网络,而CNN具有平移不变性和局部性,但缺乏全局建模长距离建模的能力。为了解决这个问题,YOLOv7引入了自然语言处理领域的框架Transformer,并将其与CNN网络相结合形成了CNN Transformer架构。 通过引入递归门控卷积gnConv),YOLOv7实现了高阶空间交互。gnConv是一种门控卷积递归设计,它具有高度的灵活性和可定制性,并能够将自注意力中的二阶交互扩展到任意阶,而不会引入大量额外的计算。这使得gnConv可以作为一个即插即用的模块来改进各种视觉Transformer和基于卷积的模型。 通过引入递归门控卷积,YOLOv7能够充分利用CNN和Transformer两者的优点,提高目标检测的效果。特别是对于小目标以及密集预测任务,经过实验表明,YOLOv7引入递归门控卷积能够产生一定的提升效果。同时,这种改进方法不仅适用于YOLOv7,也可以应用于其他的YOLO网络以及目标检测网络,如YOLOv6、v4、v3、Faster RCNN、SSD等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [YOLOv7改进之二十二:涨点神器——引入递归门控卷积gnConv)](https://blog.csdn.net/m0_70388905/article/details/126142505)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值