Download models/fusion.py from gundo0102/SleepMaMi: direct link, hf CLI and curl.
- Browser
- Download file 4.81 kB
-
https://huggingface.co/gundo0102/SleepMaMi/resolve/main/models/fusion.py
- Command line
-
hf download hf://gundo0102/SleepMaMi/models/fusion.py
-
curl -L -o fusion.py https://huggingface.co/gundo0102/SleepMaMi/resolve/main/models/fusion.py
4.81 kB
| import torch | |
| import torch.nn as nn | |
| from models.transformer_modules import BlockFlashAttn, Mlp, freq_pos_enc, PatchUpsample | |
| class FusionModule(nn.Module): | |
| def __init__(self, encoder_embed_dim=128, | |
| num_heads=4, mlp_ratio=4, norm_layer=nn.LayerNorm, fusion_depth=2, | |
| fusion_method='concat', pos_enc='sinusoidal'): | |
| super().__init__() | |
| self.fusion_method = fusion_method | |
| self.num_heads = num_heads | |
| if self.fusion_method == 'concat': | |
| self.prenorm = norm_layer(encoder_embed_dim * 2) # prenorm for the weighted sum features | |
| # self.merge = nn.Linear(encoder_embed_dim * 2, encoder_embed_dim) | |
| self.merge = Mlp(in_features=encoder_embed_dim * 2, out_features=encoder_embed_dim) | |
| elif self.fusion_method == 'cross_attn': | |
| self.cross_attention_blocks = nn.ModuleList([ | |
| BlockFlashAttn(encoder_embed_dim, num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer) | |
| # BlockFlashAttn(encoder_embed_dim, num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer) | |
| for i in range(fusion_depth)]) | |
| self.post_norm = norm_layer(encoder_embed_dim) | |
| self.pos_enc = pos_enc | |
| if pos_enc == 'rope': | |
| self.rope = freq_pos_enc(dim=encoder_embed_dim // num_heads, max_seq_len=128) | |
| def forward(self, x, y): | |
| if self.fusion_method == 'concat': | |
| x = torch.cat([x, y], dim=-1) | |
| x = self.prenorm(x) # apply prenorm before the forward_features | |
| x = self.merge(x) | |
| elif self.fusion_method == 'cross_attn': | |
| if self.pos_enc == 'rope': | |
| pe = self.rope.unsqueeze(0).to(dtype=x.dtype, device=x.device) # (1, max_seq_len, dim) | |
| pe = pe[:, :x.shape[1], :] # (1, seq_len, dim) | |
| pe = pe.repeat(x.shape[0], 1, 1) # (N, max_seq_len, dim) | |
| pe2 = None | |
| if not x.shape[1] == y.shape[1]: | |
| pe2 = freq_pos_enc(dim=y.shape[2] // self.num_heads, max_seq_len=y.shape[1]) | |
| pe2 = pe2.unsqueeze(0).to(dtype=x.dtype, device=x.device) # (1, max_seq_len, dim) | |
| pe2 = pe2.repeat(x.shape[0], 1, 1) # (N, max_seq_len, dim) | |
| else: | |
| pe = None | |
| for blk in self.cross_attention_blocks: | |
| x, _ = blk(x, y, rope=pe, rope2=pe2) | |
| x = self.post_norm(x) | |
| return x | |
| class FusionUpsampleBlock(nn.Module): | |
| def __init__(self, dim_list, fusion_method='cross_attn', fusion_depth=2, fusion_heads=4, | |
| mlp_ratio=4., norm_layer=nn.LayerNorm, pos_enc='sinusoidal', | |
| use_shared=True, use_upsample=True, modalities=["EEG","EOG"]): | |
| super().__init__() | |
| self.fusion_method = fusion_method | |
| self.use_shared = use_shared | |
| self.use_upsample = use_upsample | |
| self.fusion = nn.ModuleDict() | |
| self.upsampler = nn.ModuleDict() | |
| self.dim_list = dim_list | |
| self.modalities = modalities | |
| for m in self.modalities: | |
| if use_shared: | |
| self.fusion[m] = FusionModule(encoder_embed_dim=dim_list[-1], | |
| mlp_ratio=mlp_ratio, norm_layer=norm_layer, | |
| fusion_method=fusion_method, fusion_depth=fusion_depth, num_heads=fusion_heads, pos_enc=pos_enc) | |
| if use_upsample: | |
| upsampler_list = [] | |
| for i in range(len(dim_list) - 1): | |
| up = 2 if i > 0 else 5 | |
| upsampler_list.append(PatchUpsample(embed_dim=dim_list[1+i], up_dim=dim_list[i], upsample=up, norm_layer=norm_layer)) | |
| self.upsampler[m] = nn.ModuleList(upsampler_list) | |
| def forward(self, x_shared, x_specific): | |
| latents_fused = [] | |
| upsampled = [] | |
| for i, m in enumerate(self.modalities): | |
| if self.use_shared: | |
| x_fused = self.fusion[m](x_specific[-1][i], x_shared[-1][i]) | |
| else: | |
| x_fused = x_specific[-1][i] | |
| latents_fused.append(x_fused) | |
| if self.use_upsample: | |
| for j in range(len(self.dim_list)-2, -1, -1): | |
| x_fused = self.upsampler[m][j](x_fused, x_specific[j][i]) | |
| upsampled.append(x_fused) | |
| return latents_fused, upsampled | |