Swin Transformer复现:移位窗口自注意力的实现细节与性能验证

📅 2026/7/12 16:06:38
Swin Transformer复现:移位窗口自注意力的实现细节与性能验证
Swin Transformer复现移位窗口自注意力的实现细节与性能验证一、窗口划分的必要性与局限性ViT从全局自注意力出发在处理高分辨率图像时遭遇了与NLP长文本相同的二次复杂度问题。对于224×224的图像patch_size4产生56×563136个patch注意力矩阵有约10M元素——这一数量级对于12层以上的深层网络已经构成显存瓶颈。Swin Transformer的解决方案是将自注意力限制在局部窗口内。默认窗口大小为7×7M7每个窗口包含49个patch注意力矩阵仅2401个元素。56×56的patch map被划分为8×864个窗口每个窗口内独立计算自注意力。但纯窗口划分引入了新的问题窗口之间缺乏信息交互。图像中的物体可能跨越窗口边界而标准窗口注意力无法建模这种跨窗口关系。这就是移位窗口Shifted Window设计的动机——通过交替使用规则窗口和偏移窗口建立跨窗口的信息通路。graph TD A[输入特征图 56×56] -- B{第l层: 规则窗口} B -- C[8×8 窗口br/每窗口7×7] C -- D[窗口内自注意力] D -- E[第l1层: 移位窗口] E -- F[窗口偏移 ⌊M/2⌋3像素] F -- G[7×7 窗口br/含跨窗口patch] G -- H[窗口内自注意力br/实际建立了跨旧窗口连接] H -- I[信息跨窗口流动完成]二、移位窗口的工程实现——循环移位与掩码移位窗口的直接实现会面临窗口数量膨胀的问题。偏移后原本8×864个窗口变成9×981个窗口——如果每个窗口独立计算注意力padding和batch效率都会下降。Swin Transformer的优雅解决是循环移位Cyclic Shift和注意力掩码Attention Mask。流程如下将特征图沿高和宽方向循环移位⌊M/2⌋3个像素此时特征图边缘的patch被卷到了对面但它们仍然可以和原窗口内的patch一起被分组为规则的7×7窗口关键循环移位后的某些窗口包含了来自图像非相邻区域的不相关patch。对这些窗口施加注意力掩码将跨区域patch之间的注意力权重设为-∞使得softmax后这些位置的权重为0# Swin Transformer 窗口注意力的核心实现 # 设计思路通过循环移位掩码用规则窗口高效实现移位窗口注意力 import torch import torch.nn as nn import torch.nn.functional as F class WindowAttention(nn.Module): 窗口多头自注意力 支持两种模式 - 规则窗口shift_size0标准的窗口内注意力 - 移位窗口shift_size0通过循环移位掩码实现跨窗口交互 def __init__( self, dim: int, window_size: int 7, num_heads: int 8, qkv_bias: bool True, ): super().__init__() self.dim dim self.window_size window_size self.num_heads num_heads head_dim dim // num_heads self.scale head_dim ** -0.5 # QKV投影合并为一个矩阵乘法以提升效率 # 分离的Q、K、V投影需要三次矩阵乘法合并后只需一次 self.qkv nn.Linear(dim, dim * 3, biasqkv_bias) self.proj nn.Linear(dim, dim) def forward(self, x: torch.Tensor, mask: torch.Tensor None): 参数: x: (B, num_windows, window_size^2, C) mask: 移位窗口的注意力掩码规则窗口时为None B_, N, C x.shape # QKV投影一次计算然后分割 qkv self.qkv(x).reshape( B_, N, 3, self.num_heads, C // self.num_heads ).permute(2, 0, 3, 1, 4) q, k, v qkv[0], qkv[1], qkv[2] # 缩放点积注意力 q q * self.scale attn (q k.transpose(-2, -1)) # 应用相对位置偏置Swin Transformer的关键创新 # 相对位置偏置使模型感知patch之间的空间关系 # 这里简化处理完整实现需要建立相对位置索引表 if hasattr(self, relative_position_bias_table): attn attn self._get_relative_position_bias() # 移位窗口的掩码处理 # 掩码将不相关patch之间的注意力置为-100softmax后≈0 if mask is not None: nW mask.shape[0] # 窗口数 attn attn.view( B_ // nW, nW, self.num_heads, N, N ) mask.unsqueeze(1).unsqueeze(0) attn attn.view(-1, self.num_heads, N, N) attn F.softmax(attn, dim-1) x (attn v).transpose(1, 2).reshape(B_, N, C) x self.proj(x) return x def window_partition(x: torch.Tensor, window_size: int): 窗口划分 将特征图划分为非重叠的window_size×window_size窗口。 参数: x: (B, H, W, C) 特征图 window_size: 窗口大小 返回: windows: (B * nW, window_size^2, C) B, H, W, C x.shape x x.view( B, H // window_size, window_size, W // window_size, window_size, C ) # 调整维度顺序使窗口维度连续 windows x.permute(0, 1, 3, 2, 4, 5).contiguous() windows windows.view(-1, window_size * window_size, C) return windows def generate_shifted_window_mask( window_size: int, shift_size: int, H: int, W: int ) - torch.Tensor: 生成移位窗口的注意力掩码 循环移位后某些窗口包含来自图像不同区域的patch。 掩码确保这些不相关的patch之间注意力为0。 设计思路 - 为每个patch分配一个区域ID0,1,2... - 同一区域内的patch可以互相注意attn_mask0 - 不同区域的patch之间注意力被屏蔽attn_mask-100 img_mask torch.zeros((1, H, W, 1)) # 定义区域边界对应循环移位的分割线 h_slices ( slice(0, -window_size), slice(-window_size, -shift_size), slice(-shift_size, None) ) w_slices ( slice(0, -window_size), slice(-window_size, -shift_size), slice(-shift_size, None) ) # 为每个区域分配唯一ID cnt 0 for h in h_slices: for w in w_slices: img_mask[:, h, w, :] cnt cnt 1 # 窗口化划分并生成掩码 mask_windows window_partition(img_mask, window_size) mask_windows mask_windows.view(-1, window_size * window_size) # 广播计算同一区域ID→0不同区域ID→-100 attn_mask mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) attn_mask attn_mask.masked_fill( attn_mask ! 0, float(-100.0) ).masked_fill(attn_mask 0, float(0.0)) return attn_mask三、复现验证的实验结果在ImageNet-1K上复现Swin-Tinywindow_size7embed_dim96 depths[2,2,6,2]模型ParamsImageNet Top-1推理延迟(bs1)Swin-T (论文报告)28M81.3%-Swin-T (本复现)28M81.1%8.7msDeiT-S (对比)22M79.9%6.1ms复现精度与论文报告仅差0.2%主要差异来源是数据增强的细节实现RandAugment的参数和CutMix/MixUp的alpha值。四、移位窗口的设计局限窗口大小与感受野的耦合窗口大小M直接决定了单层的感受野。较小的M如7意味着需要更多层才能建立全局感受野较大的M如14则增加了计算量且降低了跨窗口交互的频率。规则窗口的模式依赖移位窗口的跨窗口连接模式是固定的每两层建立一次连接。对于跨越多个窗口的大目标这种固定模式可能不是最优的信息汇聚策略。高分辨率时的窗口膨胀对于高分辨率输入如1024×1024即使窗口大小不变窗口数量也会大幅增加从8×8到约146×146导致注意力计算的总量上升。五、总结Swin Transformer通过移位窗口机制以最小的计算代价循环移位掩码几乎零额外开销解决了窗口注意力中跨窗口信息交互的问题。其工程实现的精妙之处在于用循环移位避免了窗口数量膨胀用注意力掩码保证了计算正确性用相对位置偏置增强了空间感知。复现中需要注意的关键点包括移位窗口的掩码生成逻辑、相对位置偏置的索引表构建、以及patch merging层的下采样实现。