中国科学院第一区のトップジャーナル | DilateFormer: プラグアンドプレイのマルチスケールのグローバル アテンション メカニズム (ソース コード実装付き)

ガイド

论文:《DilateFormer: 視覚認識用マルチスケール拡張トランス》

Transformerこの論文では、視覚認識タスクの略称である新しいマルチスケール ホールを提案しますDilateFormer元の ViT モデルには、計算の複雑さと受容野のサイズの間のトレードオフに矛盾があります。誰もが知っているように、ViT モデルはグローバル アテンション メカニズムを使用しており、任意の画像ブロック間の長距離のコンテキスト依存関係を確立できますが、グローバル受容野は平方レベルの計算コストをもたらします。同時に、一部の研究では、浅いフィーチャでは直接的なグローバル依存関係モデリングが冗長になる可能性があるため、不要であることが示されています。

これらの問題を克服するために、著者らは新しいアテンション メカニズム、マルチスケール ホール アテンション ( MSDA1) を提案しています。MSDA は、狭い範囲で局所的でまばらなパッチ相互作用をモデル化することができ、これらの発見は、浅いレベルでの ViT に対する世界的な注目におけるパッチ相互作用の分析から得られます。著者は、浅いレベルでは、アテンション行列には局所性疎性という 2 つの重要なプロパティがあることを発見しました。これは、浅いセマンティック モデリングでは、クエリ ブロックから遠く離れたブロックはほとんど無関係であるため、多くの冗長性があることを示しています。

これに基づいて、この論文はさらに を構築しますDilateFormer。これは、最下段に MSDA ブロックをスタックし、高段でグローバル マルチヘッド自己注意ブロックを使用します。このような設計により、モデルは低レベルの情報を処理するときに局所性とスパース性を最大限に活用し、高レベルの情報を処理するときに長距離の依存関係をシミュレートできます。

最終的に、この論文は、DilateFormer モデルがさまざまな視覚タスクの実験を通じて良好な結果を達成したことを発見しました。ImageNet-1K 分類タスクでは、DilateFormer モデルは最先端のモデルと同等のパフォーマンスを発揮しますが、必要な FLOP (浮動小数点演算) は 70% 少なくなります。COCO オブジェクト検出/インスタンス セグメンテーション タスクや ADE20K セマンティック セグメンテーション タスクなどの他のビジョン タスクでも、DilateFormer モデルは優れたパフォーマンスを達成しました。

方法

DilateFormerこれは、ピラミッド構造に基づいた深層学習モデルであり、主に基本的な視覚タスクを処理するように設計されています。DilateFormer の主要な設計コンセプトは、マルチスケール ホール アテンション ( Multi-Scale Dilated Attention, MSDA) を使用して、マルチスケール セマンティック情報を効果的にキャプチャし、セルフ アテンション メカニズムの冗長性を削減することです。

上の図に示すように、DilateFormerシステムの全体的なアーキテクチャは主に 4 つのステージで構成されます。最初と 2 段階目では MSDA が使用され、最後の 2 段階では通常のマルチヘッド セルフ アテンション ( MHSA) が使用されます。画像入力の場合、DilateFormer はまずパッチ埋め込みにオーバーラップ トークナイザーを使用し、次にコンボリューション カーネルのストライド サイズ (1 または 2) を交互に制御することで出力特徴マップの解像度を調整します。前段のパッチでは、カーネル サイズ 3 とストライド 2 が重複するオーバーラップ ダウンサンプラーが採用されています。モデル全体のすべての部分で、条件付き位置埋め込み (CPE) を使用して、位置エンコーディングをさまざまな解像度の入力に適応させます。

DilateFormer の中核部分は MSAD モジュールです。上の図に示すように、MSDA モジュールもマルチヘッド設計を採用し、特徴マップのチャネルを n 個の異なるヘッドに分割し、異なるヘッドで異なるホール レートでスライディング ウィンドウ拡張アテンション (SWDA) を実行します。これにより、集中した受容野内のさまざまなスケールで意味情報を集約でき、複雑な操作や追加の計算コストを必要とせずに自己注意メカニズムの冗長性を効果的に削減できます。具体的な操作は以下の通りです。

  1. 各ヘッドには独立した拡張率があります r r_{i}
  2. 从特征图中获取切片 Q i Q_{i} K i K_{i} V i V_{i} ,执行 SWDA,得到输出 h i h_{i}
  3. 将所有头部的输出连接在一起,然后通过一个线性层进行特征聚合。

以上便是 MSDA 模块的主要工作流程。总体来说,DilateFormer 通过这种混合使用多尺度空洞注意力和多头自注意力的方式,成功地处理了长距离依赖问题,同时保持了计算效率,并能够适应不同尺度和分辨率的输入。

为了适应不同的需求,DilateFormer 设计了几种缩放架构:

代码

多尺度模块实现:

class DilateBlock(nn.Module):
    "Implementation of Dilate-attention block"
    def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False,qk_scale=None, drop=0., attn_drop=0.,
                 drop_path=0.,act_layer=nn.GELU, norm_layer=nn.LayerNorm, kernel_size=3, dilation=[1, 2, 3],
                 cpe_per_block=False):
        super().__init__()
        self.dim = dim
        self.num_heads = num_heads
        self.mlp_ratio = mlp_ratio
        self.kernel_size = kernel_size
        self.dilation = dilation
        self.cpe_per_block = cpe_per_block
        if self.cpe_per_block:
            self.pos_embed = nn.Conv2d(dim, dim, 3, padding=1, groups=dim)
        self.norm1 = norm_layer(dim)
        self.attn = MultiDilatelocalAttention(dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale,
                                                attn_drop=attn_drop, kernel_size=kernel_size, dilation=dilation)

        self.drop_path = DropPath(
            drop_path) if drop_path > 0. else nn.Identity()

        self.norm2 = norm_layer(dim)
        mlp_hidden_dim = int(dim * mlp_ratio)
        self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim,
                       act_layer=act_layer, drop=drop)

    def forward(self, x):
        if self.cpe_per_block:
            x = x + self.pos_embed(x)
        x = x.permute(0, 2, 3, 1)
        x = x + self.drop_path(self.attn(self.norm1(x)))
        x = x + self.drop_path(self.mlp(self.norm2(x)))
        x = x.permute(0, 3, 1, 2)
        #B, C, H, W
        return x

MSDA 具体实现

class DilateAttention(nn.Module):
    "Implementation of Dilate-attention"
    def __init__(self, head_dim, qk_scale=None, attn_drop=0, kernel_size=3, dilation=1):
        super().__init__()
        self.head_dim = head_dim
        self.scale = qk_scale or head_dim ** -0.5
        self.kernel_size=kernel_size
        self.unfold = nn.Unfold(kernel_size, dilation, dilation*(kernel_size-1)//2, 1)
        self.attn_drop = nn.Dropout(attn_drop)

    def forward(self,q,k,v):
        #B, C//3, H, W
        B,d,H,W = q.shape
        q = q.reshape([B, d//self.head_dim, self.head_dim, 1 ,H*W]).permute(0, 1, 4, 3, 2)  # B,h,N,1,d
        k = self.unfold(k).reshape([B, d//self.head_dim, self.head_dim, self.kernel_size*self.kernel_size, H*W]).permute(0, 1, 4, 2, 3)  #B,h,N,d,k*k
        attn = (q @ k) * self.scale  # B,h,N,1,k*k
        attn = attn.softmax(dim=-1)
        attn = self.attn_drop(attn)
        v = self.unfold(v).reshape([B, d//self.head_dim, self.head_dim, self.kernel_size*self.kernel_size, H*W]).permute(0, 1, 4, 3, 2)  # B,h,N,k*k,d
        x = (attn @ v).transpose(1, 2).reshape(B, H, W, d)
        return x

class MultiDilatelocalAttention(nn.Module):
    "Implementation of Dilate-attention"

    def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None,
                 attn_drop=0.,proj_drop=0., kernel_size=3, dilation=[1, 2, 3]):
        super().__init__()
        self.dim = dim
        self.num_heads = num_heads
        head_dim = dim // num_heads
        self.dilation = dilation
        self.kernel_size = kernel_size
        self.scale = qk_scale or head_dim ** -0.5
        self.num_dilation = len(dilation)
        assert num_heads % self.num_dilation == 0, f"num_heads{num_heads} must be the times of num_dilation{self.num_dilation}!!"
        self.qkv = nn.Conv2d(dim, dim * 3, 1, bias=qkv_bias)
        self.dilate_attention = nn.ModuleList(
            [DilateAttention(head_dim, qk_scale, attn_drop, kernel_size, dilation[i])
             for i in range(self.num_dilation)])
        self.proj = nn.Linear(dim, dim)
        self.proj_drop = nn.Dropout(proj_drop)

    def forward(self, x):
        B, H, W, C = x.shape
        x = x.permute(0, 3, 1, 2)# B, C, H, W
        qkv = self.qkv(x).reshape(B, 3, self.num_dilation, C//self.num_dilation, H, W).permute(2, 1, 0, 3, 4, 5)
        #num_dilation,3,B,C//num_dilation,H,W
        x = x.reshape(B, self.num_dilation, C//self.num_dilation, H, W).permute(1, 0, 3, 4, 2 )
        # num_dilation, B, H, W, C//num_dilation
        for i in range(self.num_dilation):
            x[i] = self.dilate_attention[i](qkv[i][0], qkv[i][1], qkv[i][2])# B, H, W,C//num_dilation
        x = x.permute(1, 2, 3, 0, 4).reshape(B, H, W, C)
        x = self.proj(x)
        x = self.proj_drop(x)
        return x

实验

DilateFormer 的各种变体在 Mask R-CNN 和 Cascade Mask R-CNN 两种框架下,相比其他 Transformer 模型,实现了更好的性能,如在 box mAP 和 mask mAP 方面都取得了显著的提升。

在 ADE20K 数据集上进行的语义分割任务,文中使用 Upernet 和 Semantic FPN 两种框架,DilateFormer 在 mIoU 评价指标上超过了 Swin Transformer,同样显示出优异的性能。

再看下 Grad-CAM 的可视化结果,可以看出目标相对来说注意力区域覆盖比较全面和集中,从侧面也能够说明引入多尺度机制的有效性。

总结

在这项工作中,研究者们提出了一个强大且有效的视觉Transformer模型,称为DilateFormer。这种模型可以为各种视觉任务提供强大且通用的表示。提出的多尺度空洞注意力(MSDA)模块考虑了自注意力机制在浅层网络中的局部性和稀疏性,它可以有效地聚合语义多尺度信息,并有效地减少自注意力机制的冗余性,而无需复杂的操作和额外的计算成本。

在大量的实验结果中,DilateFormer 表现出优异的性能,达到了在ImageNet-1k分类和下游视觉任务(如目标检测和语义分割)中的最新水平。该模型通过采用滑动窗口空洞注意(SWDA)操作以及在各个不同尺度上捕捉上下文语义依赖性的 MSDA,进一步提升了性能。

写在最后

欢迎对注意力机制相关研究感兴趣的童鞋扫描屏幕下方二维码或者直接搜索微信号 cv_huber 添加小编好友,备注:学校/公司-研究方向-昵称,与更多小伙伴一起交流学习!

おすすめ

転載: juejin.im/post/7266336495031107620