| """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
|
|
|