"""Transformer block used by Flexibrain downstream heads. Reference: - Brain-Harmony / BrainHarmonix official codebase: https://github.com/hzlab/Brain-Harmony - The official README marks the project license as CC BY-NC-SA 4.0. Only the small Block/Attention/MLP subset required by the downstream head is kept here; the rest of the Brain-Harmony repository is intentionally not vendored into Flexibrain. """ import torch import torch.nn as nn def drop_path(x, drop_prob: float = 0.0, training: bool = False): if drop_prob == 0.0 or not training: return x keep_prob = 1 - drop_prob shape = (x.shape[0],) + (1,) * (x.ndim - 1) random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device) random_tensor.floor_() return x.div(keep_prob) * random_tensor class DropPath(nn.Module): def __init__(self, drop_prob=0.0): super().__init__() self.drop_prob = float(drop_prob) def forward(self, x): return drop_path(x, self.drop_prob, self.training) class MLP(nn.Module): def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.0): super().__init__() out_features = out_features or in_features hidden_features = hidden_features or in_features self.fc1 = nn.Linear(in_features, hidden_features) self.act = act_layer() self.fc2 = nn.Linear(hidden_features, out_features) self.drop = nn.Dropout(drop) def forward(self, x): x = self.fc1(x) x = self.act(x) x = self.drop(x) x = self.fc2(x) return self.drop(x) class Attention(nn.Module): def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0.0, proj_drop=0.0): super().__init__() self.num_heads = num_heads head_dim = dim // num_heads self.scale = qk_scale or head_dim ** -0.5 self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) self.proj = nn.Linear(dim, dim) self.proj_drop = nn.Dropout(proj_drop) def forward(self, x, attention_mask=None, output_attentions=False): B, N, C = x.shape 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] attn = (q @ k.transpose(-2, -1)) * self.scale if attention_mask is not None: valid = attention_mask.bool() key_mask = ~valid[:, None, None, :] attn = attn.masked_fill(key_mask, torch.finfo(attn.dtype).min) attn = self.attn_drop(attn.softmax(dim=-1)) x = (attn @ v).transpose(1, 2).reshape(B, N, C) x = self.proj_drop(self.proj(x)) return (x, attn) if output_attentions else (x, None) class Block(nn.Module): def __init__(self, dim, num_heads, mlp_ratio=4.0, qkv_bias=False, qk_scale=None, drop=0.0, attn_drop=0.0, drop_path=0.0, act_layer=nn.GELU, norm_layer=nn.LayerNorm, attn_mode=None): super().__init__() self.norm1 = norm_layer(dim) self.norm2 = norm_layer(dim) self.attn = Attention(dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop) self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() self.mlp = MLP(in_features=dim, hidden_features=int(dim * mlp_ratio), act_layer=act_layer, drop=drop) def forward(self, x, attention_mask=None, return_attention=False): y, attn = self.attn(self.norm1(x), attention_mask=attention_mask, output_attentions=return_attention) x = x + self.drop_path(y) x = x + self.drop_path(self.mlp(self.norm2(x))) return (x, attn) if return_attention else x