mirror of
https://github.com/macaodha/batdetect2.git
synced 2026-08-22 03:00:10 +02:00
Add efficient self attention layers
This commit is contained in:
parent
575e0b3d28
commit
906f97df33
@ -306,6 +306,126 @@ class SelfAttention(Block):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EfficientSelfAttentionConfig(BaseConfig):
|
||||||
|
"""Configuration for an ``EfficientSelfAttention`` block.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
Discriminator field; always ``"EfficientSelfAttention"``.
|
||||||
|
attention_channels : int
|
||||||
|
Dimensionality of the query, key, and value projections.
|
||||||
|
temperature : float
|
||||||
|
Scaling factor applied to the weighted values before the final
|
||||||
|
linear projection. Defaults to ``1``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: Literal["EfficientSelfAttention"] = "EfficientSelfAttention"
|
||||||
|
attention_channels: int
|
||||||
|
temperature: float = 1.0
|
||||||
|
|
||||||
|
|
||||||
|
class EfficientSelfAttention(Block):
|
||||||
|
"""An optimized self-attention block operating along the time axis.
|
||||||
|
|
||||||
|
Applies a scaled dot-product self-attention mechanism across the time
|
||||||
|
steps of an input feature map. This version uses a fused QKV linear
|
||||||
|
projection and PyTorch's native scaled dot-product attention (SDPA)
|
||||||
|
for optimal memory usage and execution speed.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
in_channels : int
|
||||||
|
Number of input channels (features per time step).
|
||||||
|
attention_channels : int
|
||||||
|
Dimensionality of the query, key, and value projections.
|
||||||
|
temperature : float, default=1.0
|
||||||
|
Divisor applied together with ``attention_channels`` when scaling
|
||||||
|
the dot-product scores before softmax.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
qkv_proj : nn.Linear
|
||||||
|
Fused linear projection for queries, keys, and values.
|
||||||
|
pro_fun : nn.Linear
|
||||||
|
Final linear projection applied to the attended values.
|
||||||
|
temperature : float
|
||||||
|
Scaling divisor used when computing attention scores.
|
||||||
|
att_dim : int
|
||||||
|
Dimensionality of the attention space (``attention_channels``).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
in_channels: int,
|
||||||
|
attention_channels: int,
|
||||||
|
temperature: float = 1.0,
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
self.in_channels = in_channels
|
||||||
|
self.out_channels = in_channels
|
||||||
|
self.temperature = temperature
|
||||||
|
self.att_dim = attention_channels
|
||||||
|
self.output_channels = in_channels
|
||||||
|
|
||||||
|
self.qkv_proj = nn.Linear(in_channels, 3 * attention_channels)
|
||||||
|
self.pro_fun = nn.Linear(attention_channels, in_channels)
|
||||||
|
|
||||||
|
self.scale_factor = 1.0 / (self.temperature * self.att_dim)
|
||||||
|
|
||||||
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""Apply self-attention along the time dimension."""
|
||||||
|
x = x.squeeze(2).permute(0, 2, 1)
|
||||||
|
|
||||||
|
# Single projection pass
|
||||||
|
qkv = self.qkv_proj(x)
|
||||||
|
|
||||||
|
# Split along the last dimension into Q, K, V
|
||||||
|
query, key, value = torch.chunk(qkv, 3, dim=-1)
|
||||||
|
|
||||||
|
att = F.scaled_dot_product_attention(
|
||||||
|
query,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
attn_mask=None,
|
||||||
|
dropout_p=0.0,
|
||||||
|
is_causal=False,
|
||||||
|
scale=self.scale_factor,
|
||||||
|
)
|
||||||
|
|
||||||
|
op = self.pro_fun(att)
|
||||||
|
|
||||||
|
return op.permute(0, 2, 1).unsqueeze(2)
|
||||||
|
|
||||||
|
def compute_attention_weights(self, x: torch.Tensor) -> torch.Tensor:
|
||||||
|
"""Return the softmax attention weight matrix.
|
||||||
|
|
||||||
|
Useful for visualising which time steps attend to which others.
|
||||||
|
"""
|
||||||
|
x = x.squeeze(2).permute(0, 2, 1)
|
||||||
|
|
||||||
|
qkv = self.qkv_proj(x)
|
||||||
|
query, key, _ = torch.chunk(qkv, 3, dim=-1)
|
||||||
|
|
||||||
|
kk_qq = torch.bmm(key, query.permute(0, 2, 1)) * self.scale_factor
|
||||||
|
att_weights = F.softmax(kk_qq, dim=1)
|
||||||
|
|
||||||
|
return att_weights
|
||||||
|
|
||||||
|
@block_registry.register(EfficientSelfAttentionConfig)
|
||||||
|
@staticmethod
|
||||||
|
def from_config(
|
||||||
|
config: EfficientSelfAttentionConfig,
|
||||||
|
input_channels: int,
|
||||||
|
input_height: int,
|
||||||
|
) -> "EfficientSelfAttention":
|
||||||
|
return EfficientSelfAttention(
|
||||||
|
in_channels=input_channels,
|
||||||
|
attention_channels=config.attention_channels,
|
||||||
|
temperature=config.temperature,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConvConfig(BaseConfig):
|
class ConvConfig(BaseConfig):
|
||||||
"""Configuration for a basic ConvBlock."""
|
"""Configuration for a basic ConvBlock."""
|
||||||
|
|
||||||
@ -558,7 +678,6 @@ class VerticalMean(Block):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class FreqCoordConvDownConfig(BaseConfig):
|
class FreqCoordConvDownConfig(BaseConfig):
|
||||||
"""Configuration for a FreqCoordConvDownBlock."""
|
"""Configuration for a FreqCoordConvDownBlock."""
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ from torch import nn
|
|||||||
from batdetect2.core.configs import BaseConfig
|
from batdetect2.core.configs import BaseConfig
|
||||||
from batdetect2.models.blocks import (
|
from batdetect2.models.blocks import (
|
||||||
Block,
|
Block,
|
||||||
|
EfficientSelfAttentionConfig,
|
||||||
SelfAttentionConfig,
|
SelfAttentionConfig,
|
||||||
VerticalConv,
|
VerticalConv,
|
||||||
VerticalConvConfig,
|
VerticalConvConfig,
|
||||||
@ -167,7 +168,7 @@ class Bottleneck(Block):
|
|||||||
|
|
||||||
|
|
||||||
BottleneckLayerConfig = Annotated[
|
BottleneckLayerConfig = Annotated[
|
||||||
SelfAttentionConfig,
|
SelfAttentionConfig | EfficientSelfAttentionConfig,
|
||||||
Field(discriminator="name"),
|
Field(discriminator="name"),
|
||||||
]
|
]
|
||||||
"""Type alias for the discriminated union of block configs usable in the Bottleneck."""
|
"""Type alias for the discriminated union of block configs usable in the Bottleneck."""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user