Multi-DConv Head Transposed Self-Attention (MDTA): Differs from standard self-attention by operating on feature channels instead of spatial dimensions. Incorporates depth-wise convolutions for local mixing before attention, achieving linear complexity vs quadratic in vanilla attention. B
| 76 | |
| 77 | |
| 78 | class CABlock(nn.Module): |
| 79 | """Multi-DConv Head Transposed Self-Attention (MDTA): Differs from standard self-attention |
| 80 | by operating on feature channels instead of spatial dimensions. Incorporates depth-wise |
| 81 | convolutions for local mixing before attention, achieving linear complexity vs quadratic |
| 82 | in vanilla attention. Based on SW Zamir, et al., 2022 <https://arxiv.org/abs/2111.09881> |
| 83 | |
| 84 | Args: |
| 85 | spatial_dims: Number of spatial dimensions (2D or 3D) |
| 86 | dim: Number of input channels |
| 87 | num_heads: Number of attention heads |
| 88 | bias: Whether to use bias in convolution layers |
| 89 | flash_attention: Whether to use flash attention optimization. Defaults to False. |
| 90 | |
| 91 | Raises: |
| 92 | ValueError: If flash attention is not available in current PyTorch version |
| 93 | ValueError: If spatial_dims is greater than 3 |
| 94 | """ |
| 95 | |
| 96 | def __init__(self, spatial_dims, dim: int, num_heads: int, bias: bool, flash_attention: bool = False): |
| 97 | super().__init__() |
| 98 | if flash_attention and not hasattr(F, "scaled_dot_product_attention"): |
| 99 | raise ValueError("Flash attention not available") |
| 100 | if spatial_dims > 3: |
| 101 | raise ValueError(f"Only 2D and 3D inputs are supported. Got spatial_dims={spatial_dims}") |
| 102 | self.spatial_dims = spatial_dims |
| 103 | self.num_heads = num_heads |
| 104 | self.temperature = nn.Parameter(torch.ones(num_heads, 1, 1)) |
| 105 | self.flash_attention = flash_attention |
| 106 | |
| 107 | self.qkv = Convolution( |
| 108 | spatial_dims=spatial_dims, in_channels=dim, out_channels=dim * 3, kernel_size=1, bias=bias, conv_only=True |
| 109 | ) |
| 110 | |
| 111 | self.qkv_dwconv = Convolution( |
| 112 | spatial_dims=spatial_dims, |
| 113 | in_channels=dim * 3, |
| 114 | out_channels=dim * 3, |
| 115 | kernel_size=3, |
| 116 | strides=1, |
| 117 | padding=1, |
| 118 | groups=dim * 3, |
| 119 | bias=bias, |
| 120 | conv_only=True, |
| 121 | ) |
| 122 | |
| 123 | self.project_out = Convolution( |
| 124 | spatial_dims=spatial_dims, in_channels=dim, out_channels=dim, kernel_size=1, bias=bias, conv_only=True |
| 125 | ) |
| 126 | |
| 127 | self._attention_fn = self._get_attention_fn() |
| 128 | |
| 129 | def _get_attention_fn(self): |
| 130 | if self.flash_attention: |
| 131 | return self._flash_attention |
| 132 | return self._normal_attention |
| 133 | |
| 134 | def _flash_attention(self, q, k, v): |
| 135 | """Flash attention implementation using scaled dot-product attention.""" |
no outgoing calls
searching dependent graphs…