Segmentation:HorNet 学习总结

前言

基于新项目的需求,在网上寻找较新的语义分割模型。经过几个模型的结果精度对比,发现HorNet模型比之前的SegFormer模型和SegNext模型在精度上要好一点。因此,对HorNet模型进行了学习,并以该篇文章进行整理总结。

值得注意的是:和其他模型的对比仅是针对精度,并没有在模型计算复杂度,权重参数量以及推理速度上进行全方位对比。因此,针对具体应用场景还是得具体分析。

参考资料如下:

论文原文: HorNet: Efficient High-Order Spatial Interactions with Recursive Gated Convolutions
作者:Yongming Rao^1∗ Wenliang Zhao1∗ Yansong Tang1
单位:清华大学

1.官方代码:https://github.com/raoyongming/HorNet
2.个人测试跑通后的代码,和源码区别不大,只是给出了在linux下运行环境,本地数据配置文件以及本地训练脚本。
https://github.com/heavenle/HorNet_seg

参考博客:
1.作者:芒果汁没有芒果,论文解读|清华&Meta提出HorNet,用递归门控卷积进行高阶空间相互作用
2.作者:Marlowee,CVPR 2022 | HorNet:递归门控卷积的高效高阶空间相互作用
3.如何理解Inductive bias?
4.卷积神经网络为什么具有平移不变性?
5. 论文:Global filter networks for image classification
6. 论文:Dynamic Filter Networks

1. HorNet创新点

1.1 提出问题

在Transformer兴起之前,占据主导地位的还是卷积神经网络(CNN)。CNN之所以这么成功,要归功于卷积的平移等变性,该特性为视觉任务引入了有效的归纳偏置。在CNN中归纳偏置指的就是平移不变性和局部性。这两种特性非常符合图像特点,因此,CNN取得很大的成功。但是这种归纳偏置也是一把双刃剑,虽然可以有效的捕获图像的局部特征,但对全局特征的获取有些疲软。(仅针对标准卷积,不过多讨论空洞卷积等其他变种)

部分名词的个人理解,也可以参考博客【3】【4】:

  1. 平移不变性:指的是图像经过平移后,算子输出的结果不变。举例人脸图像中,无论眼睛平移到任何位置,提取眼睛特征的卷积依旧获得的是同样的特征,输出相同的响应。
  2. 平移等变性:算子在不同位置的工作原理相同,但它的响应随着目标位置的变化而变化。
  3. 局部性:图片上相邻的区域有相似的特征,即同一物体的信息往往都集中在局部
  4. 归纳偏置:归纳指的是总结,偏置指的是有偏向性,归纳偏置就是经过数据训练后总结的某种偏向特性。

因此,基于Transformer自身self-attention的优秀特性,可以弥补CNN中无法高效捕获全局特征的缺陷,并且通过联合CNN中的优秀理念和新的自注意力机制,使得视觉Transformer在各个领域都取得优秀的表现。

那么,是什么使得视觉Transformer的能力优于CNN呢?

在论文中,作者将视觉Transformer的成功归功于3个关键因素是通过自注意操作实现的输入自适应权重生成策略远距离空间建模能力高阶空间交互作用

在我阅读完论文后,空间交互的理解是两个空间位置计算一次算一阶,计算两次算两阶。比如self-attention中的query,key和value就进行了两次空间交互。

在之前的视觉Transformer中,通过self-attention的机制已经实现了输入自适应权重和远距离空间建模能力,但是在高阶空间交互领域还没有人进行研究。在之前视觉任务中,自注意力机制中点积的形式只是二阶空间交互,并没有探索高阶空间交互的作用。

因此,论文作者认为自主力机制点积的有效性在高阶空间交互的前景上还没有被分析。

1.2 分析问题

针对于论文作者引出的问题:高阶空间交互对于网络的优化还没有被研究。

那么为什么高阶空间交互对于网络会有提升作用呢?

论文作者根据普通卷积,动态卷积和自注意力操作进行对比,视觉建模从普通卷积,到动态卷积再到自注意力机制的操作趋势表明,可以通过增加空间交互的阶数来提高网络能力。如论文中该图所示:
在这里插入图片描述
其中,标准卷积如图(a),红色区域表示卷积后的特征,灰色区域表示邻近领域。经过卷积后,红色区域相当于聚合了灰色领域的特征。这其实也是一种隐式空间交互,是卷积核和图像的一次空间交互,它隐藏在卷积操作中。

动态卷积如图(b)所示,可以看出动态卷积是一种显式的空间交互。动态卷积有两个输入,第一个输入会作为特征映射,第二个输入会经过滤波生成网络来生成一组滤波器(如果是一维的话,可以看作是权重)。通过该滤波器和特征映射进行卷积,实现显式的一阶空间交互。这也可以看作是一种注意力机制,通过学习出的包含全局信息的滤波器,来对原始特征进行加权。(咋感觉有点像模板匹配)

可以通过Squeeze-and-Excitation Networks(SENet)网络进行理解,图像经过滤波生成网络生成一组一维的权重,然后加权到原始图像上,实现图像的注意力机制。
在这里插入图片描述

图(c)是自注意力机制的操作。通过计算query和key的相似度来生成相似度权重,再加权到value中。从上图中可以看出,自注意力机制的操作是显式的二阶空间交互。

如果对自注意力机制原理不懂的,可以参考我的另一篇博客Transformer:注意力机制(attention)和自注意力机制(self-attention)的学习总结

从图(a)到图(c)可以看出,网络对于图像的建模能力随着空间交互阶数的提高而增强。

在原文中,作者也做出了如下表述:
在这里插入图片描述

1.3 解决方法

论文作者基于高阶空间交互的理念上,设计出递归门卷积(Recursive Gated Convolutions, 记为 g n C o n v g_{n}Conv gnConv),实现高阶空间相互作用, g n C o n v g_{n}Conv gnConv不是简单地模仿self-attention设计,相比之下它有三个额外的特性:

  • 有效性。基于卷积的实现避免了self-attention的二次复杂度。在执行空间交互过程中逐步增加channel宽度的设计也使能够实现具有有限复杂性的高阶交互;
  • 可扩展性。 g n C o n v g_{n}Conv gnConv可以将self-attention中的两阶空间相互扩展到任意阶,以进一步提高建模能力,并且 g n C o n v g_{n}Conv gnConv兼容各种尺度的卷积核和不同的空间混合策略。
  • 平移等变性。 g n C o n v g_{n}Conv gnConv完全继承了标准卷积的平移等变性,为主要视觉任务引入了有益的归纳偏差,避免了局部注意力带来的不对称性。

g n C o n v g_{n}Conv gnConv的具体实现流程可以如图(d)所示,进行了三阶空间交互。具体原理见下章节。

基于 g n C o n v g_{n}Conv gnConv的设计,构成了一个新的通用backbone网络,记为HorNet

并且,作者通过增加全局滤波器网络(Global filter networks ,简称GF)。来进一步提高模型的输出精度。具体原理见下章节。

原文如下:
在这里插入图片描述

2. HorNet网络结构

2.1 g n C o n v g_{n}Conv gnConv的原理

g n C o n v g_{n}Conv gnConv是由标准卷积、线性投影和元素相乘组成,可以高效的实现远距离空间建模和高阶空间交互能力。且具有与self-attention机制相似的空间混合函数。接下来分别介绍一阶空间交互的原理和高阶空间交互的原理。

2.1.1 一阶空间交互 g C o n v gConv gConv

在CNN中,网络主要使用静态的卷积核来聚合相邻特征,而Vision Transformer则使用multi-head self-attention动态生成权重来聚合空间token,但是由于self-attention输入尺度导致的二阶复杂度,会很大程度上限制了Vision Transformer的应用, g C o n v gConv gConv则通过使用卷积层和全连接层这样的简单操作实现了同等效力的空间交互。

假设输入特征为 x ∈ R H W × C x\in R^{HW \times C} xRHW×C。对于实现 y = g C o n v ( x ) y = gConv(x) y=gConv(x)分为以下四个步骤:

第一步,通过全连接层将 x x x升维到原来的两倍。
[ p 0 ∈ R H W × C , q 0 ∈ R H W × C ] = ϕ i n ( x ) ∈ R H W × 2 C [p_0\in R^{HW \times C}, q_0\in R^{HW \times C}]=\phi_{in}(x)\in R^{HW \times 2C} [p0RHW×C,q0RHW×C]=ϕin(x)RHW×2C
其中 H H H为特征的高度, W W W为特征宽度, C C C为特征的通道数。 ϕ i n \phi_{in} ϕin表示输入的全连接层。

第二步, q 0 q_0 q0进行深度可分离卷积(类似于动态卷积中的滤波器生成网络来生成滤波器权重)。
q 0 ′ = f ( q 0 ) ∈ R H W × C q_{0}^{'}=f(q_0)\in R^{HW \times C} q0=f(q0)RHW×C
其中 f f f表示深度可分离卷积层。

第三步,将 q 0 ′ q_{0}^{'} q0 p 0 p_0 p0进行点乘(空间交互)
p 1 = q 0 ′ ⋅ p 0 ∈ R H W × C p_1 = q_{0}^{'} \cdot p_0\in R^{HW \times C} p1=q0p0RHW×C

第四步,空间交互的结果通过全连接层映射到指定维度。

y = ϕ o u t ( p 1 ) ∈ R H W × C y = \phi_{out}(p_1)\in R^{HW \times C} y=ϕout(p1)RHW×C
其中, ϕ o u t \phi_{out} ϕout表示输出的全连接层。

整体的运行流程如下图所示:
在这里插入图片描述

2.1.2 高阶空间交互 g n C o n v g_{n}Conv gnConv

g n C o n v g_{n}Conv gnConv实现的高阶空间交互同一阶空间交互是一样的原理。同样是以下4个步骤:

第一步,通过全连接层将 x x x升维到原来的两倍。
[ p 0 ∈ R H W × C 0 , q 0 ∈ R H W × C 0 , q 1 ∈ R H W × C 1 , . . . , q n − 1 ∈ R H W × C n − 1 ] = ϕ i n ( x ) ∈ R H W × ( C 0 + ∑ 0 ≤ k ≤ n − 1 C k ) [p_0\in R^{HW \times C_0}, q_0\in R^{HW \times C_0}, q_1\in R^{HW \times C_1}, ... , q_{n-1}\in R^{HW \times C_{n-1}}]=\phi_{in}(x)\in R^{HW \times (C_0+\sum_{0 \leq k \leq n-1}C_{k})} [p0RHW×C0,q0RHW×C0q1RHW×C1,...,qn1RHW×Cn1]=ϕin(x)RHW×(C0+0kn1Ck)
其中 H H H为特征的高度, W W W为特征宽度, C C C为特征的通道数。 ϕ i n \phi_{in} ϕin表示输入的全连接层。

第二步, q 0 , q 1 , q 2 , . . . , q n − 1 q_0,q_1,q_2,...,q_{n-1} q0q1q2...qn1进行深度可分离卷积(类似于动态卷积中的滤波器生成网络来生成滤波器权重)。
q k ′ = f k ( q k ) ∈ R H W × C k         k = 0 , 1 , 2 , . . . . . , n − 1 q_{k}^{'}=f_k(q_k)\in R^{HW \times C_k}\space\space\space\space\space\space\space k=0, 1, 2, ....., n-1 qk=fk(qk)RHW×Ck       k=0,1,2,.....,n1
其中 f k f_k fk表示深度可分离卷积层。

第三步,分别将 q k ′ q_{k}^{'} qk p k p_k pk进行点乘(空间交互)
p k + 1 = q k ′ ⋅ g k ( p k ) / α ∈ R H W × C k         k = 0 , 1 , 2 , . . . . . , n − 1 p_{k+1} = q_{k}^{'} \cdot g_{k}(p_k)/\alpha \in R^{HW \times C_{k} }\space\space\space\space\space\space\space k=0, 1, 2, ....., n-1 pk+1=qkgk(pk)/αRHW×Ck       k=0,1,2,.....,n1

其中 g k g_k gk是全连接层,用来进行升维。因为经过点积后的 p k + 1 p_{k+1} pk+1的维数还是除以上一次迭代的维数 C k C_k Ck,因此需要进行升维到 C k + 1 C_{k+1} Ck+1,来进行下一次迭代。 g k g_k gk的公式如下所示:

g k = { l i n e a r ( C 0 , C 0 ) k = 0 l i n e a r ( C k − 1 , C k ) 1 ≥ k ≥ n − 1 g_k =\left\{ \begin{aligned} linear(C_0, C_0) & &k=0 \\ linear(C_{k-1}, C_k) & & 1 \geq k \geq n-1 \end{aligned} \right. gk={ linear(C0,C0)linear(Ck1,Ck)k=01kn1

C k C_k Ck的具体值由如下公式计算:

C k = C 2 n − 1 − k C_k = \frac{C}{2^{n-1-k}} Ck=2n1kC
其中, n − 1 − k n-1-k n1k表示 C C C的维数是从小到大的。

第四步,空间交互的结果通过全连接层映射到指定维度。

y = ϕ o u t ( p n − 1 ) ∈ R H W × C n − 1 y = \phi_{out}(p_{n-1})\in R^{HW \times C_{n-1}} y=ϕout(pn1)RHW×Cn1
其中, ϕ o u t \phi_{out} ϕout表示输出的全连接层。

这种设计表明 g n C o n v g_{n}Conv gnConv以粗到细的方式执行交互,其中使用较少的通道来计算较低阶空间交互

整体的运行流程如下图所示:
在这里插入图片描述

从论文作者流程图和源码中也可理解 g n C o n v g_{n}Conv gnConv的具体原理:
流程图
在这里插入图片描述
g n C o n v g_{n}Conv gnConv的源码

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, 'order with dims=', self.dims, 'scale=%.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

2.1.3 g n C o n v g_{n}Conv gnConv的计算复杂度

在论文中,作者表明 g n C o n v g_{n}Conv gnConv在以卷积层相似的计算复杂度下,实现了高阶交互作用。并且随着阶数n的增加,总计算复杂度也是严格有上界。

g n C o n v g_{n}Conv gnConv的整体计算复杂度可以分成三块。分别是线性投影(1x1的卷积),深度可分离卷积和回归门。

  • 线性投影:主要是 ϕ i n \phi_{in} ϕin ϕ o u t \phi_{out} ϕout。由于默认是 ϕ i n \phi_{in} ϕin是升维到原来的2C。 ϕ o u t \phi_{out} ϕout是同维数的映射。因此,线性投影的计算复杂度如下公式所示:
    F L O P s ( ϕ i n ) = 2 H W C 2 FLOPs(\phi_{in}) = 2HWC^2 FLOPs(ϕin)=2HWC2
    F L O P s ( ϕ o u t ) = H W C 2 FLOPs(\phi_{out}) = HWC^2 FLOPs(ϕout)=HWC2
    ϕ i n \phi_{in} ϕin做解释,在每个像素上的线性映射是 2 C 2 2C^2 2C2,一共有 H W HW HW个像素,因此总体计算复杂度为 2 H W C 2 2HWC^2 2HWC2
  • 深度可分离卷积:深度可分离卷积中卷积核的尺度为K。那么深度可分离卷积的计算复杂度如下公式所示:
    F L O P s ( d w c o n v ) = H W K 2 ∑ k = 0 n − 1 C 2 n − 1 − k = 2 H W C K 2 ( 1 − 1 2 n ) FLOPs(dwconv) = HWK^2\sum_{k=0}^{n-1}{\frac{C}{2^{n-1-k}}} = 2HWCK^2(1-\frac{1}{2^n}) FLOPs(dwconv)=HWK2k=0n12n1kC=2HWCK2(12n1)
  • 回归门,该操作包含据点乘和函数 g k g_k gk
    F L O P s ( g k ) = H W ∑ k = 0 n − 2 C 2 n − 1 − k C 2 n − 2 − k = H W C 2 2 3 ( 1 − 1 4 n − 1 ) FLOPs(g_k) = HW\sum_{k=0}^{n-2}{\frac{C}{2^{n-1-k}}\frac{C}{2^{n-2-k}}}=HWC^2\frac{2}{3}(1-\frac{1}{4^{n-1}}) FLOPs(gk)=HWk=0n22n1kC2n2kC=HWC232(14n11)
    F L O P s ( e l e m e n t − w i s e   m u l t i p l i c a t i o n ) = H W ∑ k = 0 n − 1 C 2 n − 1 − k = 2 H W C ( 1 − 1 2 n ) FLOPs(element-wise\space multiplication) = HW\sum_{k=0}^{n-1}{\frac{C}{2^{n-1-k}}}=2HWC(1-\frac{1}{2^n}) FLOPs(elementwise multiplication)=HWk=0n12n1kC=2HWC(12n1)
    F L O P s ( R e c u r s i v e G a t i n g ) = F L O P s ( g k ) + F L O P s ( e l e m e n t − w i s e   m u l t i p l i c a t i o n ) FLOPs(RecursiveGating) = FLOPs(g_k) + FLOPs(element-wise\space multiplication) FLOPs(RecursiveGating)=FLOPs(gk)+FLOPs(elementwise multiplication)
    = H W C 2 2 3 ( 1 − 1 4 n ) + 2 H W C ( 1 − 1 2 n ) = H W C ( 2 3 C ( 1 − 1 4 n − 1 ) + 2 − 1 2 n − 1 ) = HWC^2\frac{2}{3}(1-\frac{1}{4^n}) +2HWC(1-\frac{1}{2^n}) =HWC(\frac{2}{3}C(1-\frac{1}{4^{n-1}})+2-\frac{1}{2^{n-1}}) =HWC232(14n1)+2HWC(12n1)=HWC(32C(14n11)+22n11)

最终, g n C o n v g_{n}Conv gnConv的计算复杂度为,
F L O P s ( g n C o n v ) = 2 H W C 2 + H W C 2 + 2 H W C K 2 ( 1 − 1 2 n ) + H W C ( 2 3 C ( 1 − 1 4 n − 1 ) + 2 − 1 2 n − 1 ) FLOPs(g_{n}Conv) = 2HWC^2 +HWC^2 + 2HWCK^2(1-\frac{1}{2^n}) + HWC(\frac{2}{3}C(1-\frac{1}{4^{n-1}})+2-\frac{1}{2^{n-1}}) FLOPs(gnConv)=2HWC2+HWC2+2HWCK2(12n1)+HWC(32C(14n11)+22n11)
= H W C ( ( 11 3 − 2 3 ∗ 1 4 n − 1 ) C + 2 K 2 ( 1 − 1 2 n ) + 2 − 1 2 n − 1 ) =HWC((\frac{11}{3}-\frac{2}{3}*\frac{1}{4^{n-1}})C+2K^2(1-\frac{1}{2^n})+2-\frac{1}{2^{n-1}}) =HWC((311324n11)C+2K2(12n1)+22n11)

可以证明, g n C o n v g_{n}Conv gnConv随着n的增加是严格有上界的,如下公式所示:
F L O P s ( g n C o n v ) ≤ H W C ( 11 3 C + 2 K 2 + 2 ) FLOPs(g_{n}Conv) \leq HWC(\frac{11}{3}C+2K^2+2) FLOPs(gnConv)HWC(311C+2K2+2)

2.1.4 g n C o n v g_{n}Conv gnConv的远距离空间建模(Global Filter模块)

传统卷积网络和视觉Transformer的一个不同在于感受野的不同。传统的卷积网络常采用 3 × 3 3 \times 3 3×3的卷积尺度来进行空间建模,而视觉Transformer会在整个特征图上或者一个局部很大的区域( 7 × 7 7 \times 7 7×7)进行空间建模。大的感受野更容易捕获远距离空间关系。

基于上述思路,为使 g n C o n v g_{n}Conv gnConv可以对远距离空间进行建模,论文作者采用2个措施:

  1. 7 × 7 7 \times 7 7×7的卷积核,7×7是SwinTransformer和ConvNext的默认窗口/卷积核大小。ConvNext的研究表明, 7 × 7 7 \times 7 7×7的卷积核大小在ImageNet分类和各种下游任务上具有良好的性能。
  2. 全局滤波(Global Filter,简称GF)。GF层将频域特征与可学习全局滤波器的相乘法。论文作者使用修改后的GF层,通过使用全局滤波器处理一半的通道,另一半使用3×3深度可分离卷积,并且只在后期使用GF层来保留更多的局部细节。

GF模块在论文是用来替换DWconv,并仅在最后两个stage中进行替换。

GF的流程如下图所示,仍然以1x128x32x32的特征图为例
在这里插入图片描述

GF源码:

class GlobalLocalFilter(nn.Module):
    def __init__(self, dim, h=14, w=8):
        super().__init__()
        self.dw = nn.Conv2d(dim // 2, dim // 2, kernel_size=3, padding=1, bias=False, groups=dim // 2)
        self.complex_weight = nn.Parameter(torch.randn(dim // 2, h, w, 2, dtype=torch.float32) * 0.02)
        trunc_normal_(self.complex_weight, std=.02)
        self.pre_norm = LayerNorm(dim, eps=1e-6, data_format='channels_first')
        self.post_norm = LayerNorm(dim, eps=1e-6, data_format='channels_first')

    def forward(self, x):
    	# LN
        x = self.pre_norm(x)
        # 分成两部分
        x1, x2 = torch.chunk(x, 2, dim=1)
        # 深度可分离卷积
        x1 = self.dw(x1)
        x2 = x2.to(torch.float32)
        B, C, a, b = x2.shape
        x2 = torch.fft.rfft2(x2, dim=(2, 3), norm='ortho')
        weight = self.complex_weight
        if not weight.shape[1:3] == x2.shape[2:4]:
            weight = F.interpolate(weight.permute(3,0,1,2), size=x2.shape[2:4], mode='bilinear', align_corners=True).permute(1,2,3,0)
        # 将weight(dim // 2, h, w, 2)的最后一维合并为(dim // 2, h, w)。内容是将实数和虚数统一表示为a+bj的形式。
        weight = torch.view_as_complex(weight.contiguous())
        x2 = x2 * weight
        x2 = torch.fft.irfft2(x2, s=(a, b), dim=(2, 3), norm='ortho')
        x = torch.cat([x1.unsqueeze(2), x2.unsqueeze(2)], dim=2).reshape(B, 2 * C, a, b)
        x = self.post_norm(x)
        return x

2.1.5 g n C o n v g_{n}Conv gnConv与自注意力机制

论文作者把 g n C o n v g_{n}Conv gnConv与自注意力机制原理进行对比,证明了虽然 g n C o n v g_{n}Conv gnConv的计算方法与自注意有很大的不同,但 g n C o n v g_{n}Conv gnConv也实现了输入自适应空间混合的目标。

这部分我依旧没有看懂论文作者的公式,我个人理解就是通过DWConv会生成不同的动态权重,然后不断和另一个输入做空间交互。其中动态权重就是输入自适应,其结果随着样本的不同而不同。

如果有读者朋友理解原文的可以在评论区指导一下我。以下是我列出的原文部分:

在这里插入图片描述
在这里插入图片描述

2.2 HorNetBlock

g n C o n v g_{n}Conv gnConv可以作为视觉Transformer或cnn中空间混合层的替代算法。作者遵循与Vit和SwinTransformer相同的架构来构建HorNet,其中HorNetBlock包含一个空间混合层和一个前馈网络(FFN)。具体组成如下图所示:
在这里插入图片描述

源码展示:

class Block(nn.Module):
    r""" HorNet block
    """
    def __init__(self, dim, drop_path=0., layer_scale_init_value=1e-6, gnconv=gnconv):
        super().__init__()
        self.norm1 = LayerNorm(dim, eps=1e-6, data_format='channels_first')
        self.gnconv = gnconv(dim) # depthwise conv
        self.norm2 = LayerNorm(dim, eps=1e-6)
        self.pwconv1 = nn.Linear(dim, 4 * dim) # pointwise/1x1 convs, implemented with linear layers
        self.act = nn.GELU()
        self.pwconv2 = nn.Linear(4 * 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
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    def forward(self, x):
        B, C, H, W  = x.shape
        if self.gamma1 is not None:
            gamma1 = self.gamma1.view(C, 1, 1)
        else:
            gamma1 = 1
        # 空间混合层 
        # x + gnconv(layer_normer(x))
        x = x + self.drop_path(gamma1 * self.gnconv(self.norm1(x)))
        
		# 前馈网络(FFN)
        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)
        if self.gamma2 is not None:
            x = self.gamma2 * x
        x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W)

        x = input + self.drop_path(x)
        return x

2.3 HorNet模型整体结构

基于模型的规模和 g n C o n v g_{n}Conv gnConv中深度可分离卷积 f k f_k fk的实现方式,论文作者设计了两个系列的模型变体,分别为
HorNet(T/S/B/L)-7×7 \texttt{HorNet(T/S/B/L)-7×7} HorNet(T/S/B/L)-7×7 HorNet(T/S/B/L)-GF \texttt{HorNet(T/S/B/L)-GF} HorNet(T/S/B/L)-GF。作者针对不同的规模分别确定不同的输入通道,即tiny对应64个channel,small对应96个channel,base对应128个channel以及large对应192个channel。HorNet分为4个stage,这四个stage对应的order(阶数)分别是2、3、4、5,且这四个stage分别重复2、3、18、2次。四个stage在 g n C o n v g_{n}Conv gnConv中分别升维到C、2C、4C、8C。

HorNet,以及SwinTransformer和ConvNeXt的模型结构如下图所示:
在这里插入图片描述
针对于语义分割任务,模型整体结构流程图如下(以1x3x512x512为输入图,模型选择Large):
在这里插入图片描述
图片有点大,我将上图切分成HorNet的编码部分和UperHead的解码部分。

HorNet的编码部分,如下图所示:
在这里插入图片描述
UperHead的解码部分,如下图所示:
在这里插入图片描述

总结

  1. 个人感觉 g n C o n v g_{n}Conv gnConv就像是高阶的动态卷积,通过将输入映射为高维数据,并划分为多个部分,每个部分分别进行DWConv(滤波生成网络)来生成对应的权重,从而进行高阶空间交互。这些权重,都是独属于每个样本的,这就满足了输入自适应。在DWConv中通过选用大尺度卷积核或者GF来实现远距离空间建模
  2. g n C o n v g_{n}Conv gnConv满足了作者提出的视觉Transformer的输入自适应,远距离空间建模,高阶空间交互这三大特性,并以实验证明该观点正确。
  3. 论文作者将GF模块替换最后两个stage中的DWconv。mmcv中的设置如下。无论是在tiny,small,base,large上都是最后两个stage。
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43610114/article/details/128145243