Download clean/video/pwtf_dvd/inference/model/transformers.py from deepsafe/model-code: direct link, hf CLI and curl.
- Browser
- Download file 18 kB
-
https://huggingface.co/deepsafe/model-code/resolve/main/clean/video/pwtf_dvd/inference/model/transformers.py
- Command line
-
hf download hf://deepsafe/model-code/clean/video/pwtf_dvd/inference/model/transformers.py
-
curl -L -o transformers.py https://huggingface.co/deepsafe/model-code/resolve/main/clean/video/pwtf_dvd/inference/model/transformers.py
18 kB
| import torch | |
| from torch import nn, einsum | |
| import torch.nn.functional as F | |
| from einops import rearrange, repeat | |
| # Removed Rearrange import - not used in inference | |
| # Removed unused imports for inference | |
| from math import sqrt | |
| from config_ftcn import config as my_cfg | |
| # Initialize config | |
| my_cfg.init_with_yaml() | |
| my_cfg.update_with_yaml("ftcn_tt.yaml") | |
| my_cfg.freeze() | |
| # ============================================================================= | |
| # Basic Transformer Components | |
| # ============================================================================= | |
| class Residual(nn.Module): | |
| def __init__(self, fn): | |
| super().__init__() | |
| self.fn = fn | |
| def forward(self, x, **kwargs): | |
| return self.fn(x, **kwargs) + x | |
| class PreNorm(nn.Module): | |
| def __init__(self, dim, fn): | |
| super().__init__() | |
| self.norm = nn.LayerNorm(dim) | |
| self.fn = fn | |
| def forward(self, x, **kwargs): | |
| return self.fn(self.norm(x), **kwargs) | |
| class FeedForward(nn.Module): | |
| def __init__(self, dim, hidden_dim, dropout = 0.): | |
| super().__init__() | |
| self.net = nn.Sequential( | |
| nn.Linear(dim, hidden_dim), | |
| nn.GELU(), | |
| nn.Dropout(dropout), | |
| nn.Linear(hidden_dim, dim), | |
| nn.Dropout(dropout) | |
| ) | |
| def forward(self, x): | |
| return self.net(x) | |
| class Attention(nn.Module): | |
| def __init__(self, dim, heads = 8, dim_head = 64, dropout = 0.): | |
| super().__init__() | |
| inner_dim = dim_head * heads | |
| project_out = not (heads == 1 and dim_head == dim) | |
| self.heads = heads | |
| self.scale = dim_head ** -0.5 | |
| self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False) | |
| self.to_out = nn.Sequential( | |
| nn.Linear(inner_dim, dim), | |
| nn.Dropout(dropout) | |
| ) if project_out else nn.Identity() | |
| def forward(self, x, mask = None): | |
| b, n, _, h = *x.shape, self.heads | |
| qkv = self.to_qkv(x).chunk(3, dim = -1) | |
| q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), qkv) | |
| dots = einsum('b h i d, b h j d -> b h i j', q, k) * self.scale | |
| mask_value = -torch.finfo(dots.dtype).max | |
| if mask is not None: | |
| mask = F.pad(mask.flatten(1), (1, 0), value = True) | |
| assert mask.shape[-1] == dots.shape[-1], 'mask has incorrect dimensions' | |
| mask = rearrange(mask, 'b i -> b () i ()') * rearrange(mask, 'b j -> b () () j') | |
| dots.masked_fill_(~mask, mask_value) | |
| del mask | |
| attn = dots.softmax(dim=-1) | |
| out = einsum('b h i j, b h j d -> b h i d', attn, v) | |
| out = rearrange(out, 'b h n d -> b n (h d)') | |
| out = self.to_out(out) | |
| return out | |
| class Transformer(nn.Module): | |
| def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout = 0.): | |
| super().__init__() | |
| self.layers = nn.ModuleList([]) | |
| for _ in range(depth): | |
| self.layers.append(nn.ModuleList([ | |
| Residual(PreNorm(dim, Attention(dim, heads = heads, dim_head = dim_head, dropout = dropout))), | |
| Residual(PreNorm(dim, FeedForward(dim, mlp_dim, dropout = dropout))) | |
| ])) | |
| def forward(self, x, mask = None): | |
| for attn, ff in self.layers: | |
| x = attn(x, mask = mask) | |
| x = ff(x) | |
| return x | |
| # ============================================================================= | |
| # Utility Functions | |
| # ============================================================================= | |
| def valid_idx(idx, h): | |
| i = idx // h | |
| j = idx % h | |
| if j == 0 or i == h - 1 or j == h - 1: | |
| return False | |
| else: | |
| return True | |
| # ============================================================================= | |
| # Patch Pooling Classes (Simplified for Inference) | |
| # ============================================================================= | |
| class CenterPatchPool(nn.Module): | |
| """Simplified patch pooling for inference - always use center patch""" | |
| def __init__(self): | |
| super().__init__() | |
| def forward(self, x): | |
| # batch,channel,16,7x7 | |
| b, c, t, h, w = x.shape | |
| x = x.reshape(b, c, t, h * w) | |
| idx = h * w // 2 # Always use center patch for inference | |
| x = x[..., idx] | |
| return x | |
| class CenterAvgPool(nn.Module): | |
| """Simplified average pooling for inference - use all valid patches""" | |
| def __init__(self): | |
| super().__init__() | |
| def forward(self, x): | |
| # batch,channel,16,7x7 | |
| b, c, t, h, w = x.shape | |
| x = x.reshape(b, c, t, h * w) | |
| candidates = list(range(h * w)) | |
| candidates = [idx for idx in candidates if valid_idx(idx, h)] | |
| x = x[..., candidates].mean(-1) | |
| return x | |
| class CenterSelect(nn.Module): | |
| """Simplified selection for inference - use all valid patches""" | |
| def __init__(self): | |
| super().__init__() | |
| def forward(self, x): | |
| # batch,7x7 | |
| size = x.shape[1] | |
| h = int(sqrt(size)) | |
| candidates = list(range(size)) | |
| candidates = [idx for idx in candidates if valid_idx(idx, h)] | |
| x = x[:, candidates] | |
| return x | |
| # ============================================================================= | |
| # Vision Transformer Classes | |
| # ============================================================================= | |
| # Removed ViT and VideoiT classes - not used in inference | |
| # ============================================================================= | |
| # Specialized Transformer Classes | |
| # ============================================================================= | |
| # SpatialTransformer class - used by SpatialTransformerE | |
| class SpatialTransformer(nn.Module): | |
| def __init__(self,num_patches, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', dim_head = 64, dropout = 0., emb_dropout = 0.): | |
| super().__init__() | |
| self.dim =dim | |
| self.num_patches=num_patches | |
| self.pos_embedding = nn.Parameter(posemb_sincos_2d(14,14,dim)) | |
| self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.dropout = nn.Dropout(emb_dropout) | |
| self.fre_pos = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.transformer = Transformer(1024, depth, heads, dim_head, mlp_dim, dropout) | |
| self.pool = pool | |
| self.to_latent = nn.Identity() | |
| self.mlp_head = nn.Sequential( | |
| nn.LayerNorm(1024), nn.Linear(1024, 1024) | |
| ) | |
| self.freq_embedding = nn.Sequential(nn.LayerNorm(dim),nn.Linear(dim,dim)) | |
| self.cls_token_pos = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.mlp_head_ste = nn.Linear(dim, 1) | |
| def posemb_loc(self, locs,batch_size): | |
| if locs is not None: | |
| b,n,_ = locs.shape | |
| pos224 =self.pos_embedding.view(14,14,-1) | |
| pos_locs = torch.zeros(batch_size,n, self.dim) | |
| if locs is not None: | |
| # locs[locs>=1] = 0.999999 | |
| loc_x = torch.floor(locs[:,:,0]*6) | |
| loc_y = torch.floor(locs[:,:,1]*6) | |
| loc_x = loc_x.long() | |
| loc_y = loc_y.long() | |
| x_a = locs[:,:,0]*6 - loc_x | |
| y_a = locs[:,:,0]*6 - loc_y | |
| x1_a = torch.sqrt( torch.pow(1-x_a,2) + torch.pow(1-y_a,2)) | |
| x2_a = torch.sqrt( torch.pow(1-x_a,2) + torch.pow(y_a,2)) | |
| x3_a = torch.sqrt( torch.pow(x_a,2) + torch.pow(1-y_a,2)) | |
| x4_a = torch.sqrt( torch.pow(x_a,2) + torch.pow(y_a,2)) | |
| pos_locs[:, :, :] = pos224[loc_x,loc_y,:]*x1_a.unsqueeze(-1)\ | |
| +pos224[loc_x+1,loc_y,:]*x2_a.unsqueeze(-1)\ | |
| +pos224[loc_x,loc_y+1,:]*x3_a.unsqueeze(-1)\ | |
| +pos224[loc_x+1,loc_y+1,:]*x4_a.unsqueeze(-1) | |
| return pos_locs | |
| def forward(self, x,ft_feature,locs): | |
| b, n, _ = x.shape #batch,num_patches,channels # | |
| cls_tokens_pos = repeat(self.cls_token_pos, '() n d -> b n d', b = b) | |
| cls_tokens = repeat(self.cls_token, '() n d -> b n d', b = b) | |
| cls_tokens = cls_tokens+cls_tokens_pos | |
| x += self.pos_embedding | |
| if locs is not None: | |
| posemb_loc = self.posemb_loc(locs,b).clone().detach() | |
| if torch.cuda.is_available() and x.is_cuda: | |
| posemb_loc = posemb_loc.cuda() | |
| posemb_loc += self.fre_pos | |
| ft_feature = ft_feature+posemb_loc | |
| ft_feature = self.freq_embedding(ft_feature) | |
| x = torch.cat((cls_tokens, x,ft_feature), dim=1) | |
| else : | |
| x = torch.cat((cls_tokens, x), dim=1) | |
| x = self.dropout(x) | |
| x = self.transformer(x, mask=None) | |
| x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0] | |
| x = self.to_latent(x) | |
| x = self.mlp_head(x) | |
| return x, self.mlp_head_ste(x.clone()) | |
| import torch | |
| from torch import nn | |
| import torch.nn.functional as F | |
| from einops import repeat | |
| def posemb_sincos_2d(h, w, dim, temperature: int = 10000, dtype=torch.float32): | |
| assert (dim % 4) == 0, "dim must be multiple of 4" | |
| y, x = torch.meshgrid(torch.arange(h), torch.arange(w), indexing="ij") | |
| omega = torch.arange(dim // 4) / (dim // 4 - 1) | |
| omega = 1.0 / (temperature ** omega) | |
| y = y.flatten()[:, None] * omega[None, :] | |
| x = x.flatten()[:, None] * omega[None, :] | |
| pe = torch.cat((x.sin(), x.cos(), y.sin(), y.cos()), dim=1) | |
| return pe.type(dtype) | |
| class SpatialTransformer(nn.Module): | |
| def __init__(self, num_patches, num_classes, dim, depth, heads, mlp_dim, | |
| pool='cls', dim_head=64, dropout=0., emb_dropout=0.): | |
| super().__init__() | |
| self.dim = dim | |
| self.num_patches = num_patches | |
| self.register_buffer('pos_embedding', posemb_sincos_2d(14, 14, dim)) | |
| self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.cls_token_pos = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.fre_pos = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.dropout = nn.Dropout(emb_dropout) | |
| self.spatial_proj = nn.Linear(dim, dim) | |
| self.freq_embedding = nn.Sequential(nn.LayerNorm(dim), nn.Linear(dim, dim)) | |
| self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout) | |
| self.pool = pool | |
| self.to_latent = nn.Identity() | |
| # output ES ∈ R^1024 | |
| self.mlp_head = nn.Sequential(nn.LayerNorm(dim), nn.Linear(dim, 1024)) | |
| self.mlp_head_ste = nn.Linear(dim, 1) | |
| def posemb_loc(self, locs, batch_size): | |
| if locs is None: | |
| return None | |
| # locs: (B, P, 2) in [0,1] | |
| B, P, _ = locs.shape | |
| device, dtype = locs.device, locs.dtype | |
| pos_grid = self.pos_embedding.view(14, 14, self.dim).to(device) # (14,14,dim) - already [196, dim] | |
| S = 13.0 | |
| x_f = (locs[:, :, 0] * S).clamp(0, 13 - 1e-6) | |
| y_f = (locs[:, :, 1] * S).clamp(0, 13 - 1e-6) | |
| ix = torch.floor(x_f).long().clamp(0, 12) | |
| iy = torch.floor(y_f).long().clamp(0, 12) | |
| ix1 = (ix + 1).clamp(max=13) | |
| iy1 = (iy + 1).clamp(max=13) | |
| x_a = (x_f - ix).to(dtype) # frac | |
| y_a = (y_f - iy).to(dtype) | |
| w11 = (1 - x_a) * (1 - y_a) | |
| w12 = x_a * (1 - y_a) | |
| w21 = (1 - x_a) * y_a | |
| w22 = x_a * y_a | |
| p11 = pos_grid[ix, iy, :] # (B,P,dim) via advanced indexing | |
| p12 = pos_grid[ix1, iy, :] | |
| p21 = pos_grid[ix, iy1, :] | |
| p22 = pos_grid[ix1, iy1, :] | |
| pos_locs = (p11 * w11.unsqueeze(-1) + | |
| p12 * w12.unsqueeze(-1) + | |
| p21 * w21.unsqueeze(-1) + | |
| p22 * w22.unsqueeze(-1)) # (B,P,dim) | |
| return pos_locs | |
| def forward(self, x, ft_feature, locs): | |
| # x: (B, N=14*14, dim), ft_feature: (B, P, dim), locs: (B, P, 2) | |
| B, N, _ = x.shape | |
| # cls token (+ pos) | |
| cls_tokens = repeat(self.cls_token, '() n d -> b n d', b=B) | |
| cls_tokens_pos = repeat(self.cls_token_pos, '() n d -> b n d', b=B) | |
| cls_tokens = cls_tokens + cls_tokens_pos | |
| # Wsp z_sp + pos_sp | |
| x = self.spatial_proj(x) | |
| x = x + self.pos_embedding.unsqueeze(0).to(x.device) | |
| # part tokens: Wfreq Z_p + (interp(pos_sp) + pos_freq) | |
| if locs is not None and ft_feature is not None: | |
| pospart = self.posemb_loc(locs, B) # (B,P,dim) | |
| if pospart is not None: | |
| pospart = pospart + self.fre_pos # + posfreq | |
| ft_feature = self.freq_embedding(ft_feature) # Wfreq | |
| if pospart is not None: | |
| ft_feature = ft_feature + pospart | |
| tokens = torch.cat((cls_tokens, x, ft_feature), dim=1) | |
| else: | |
| tokens = torch.cat((cls_tokens, x), dim=1) | |
| tokens = self.dropout(tokens) | |
| tokens = self.transformer(tokens, mask=None) | |
| out = tokens.mean(dim=1) if self.pool == 'mean' else tokens[:, 0] | |
| out = self.to_latent(out) | |
| es = self.mlp_head(out) # ES ∈ R^1024 | |
| ste_score = self.mlp_head_ste(out) # optional head | |
| return es, ste_score | |
| class TimeTransformer(nn.Module): | |
| def __init__(self,num_patches, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', dim_head = 64, dropout = 0., emb_dropout = 0.): | |
| super().__init__() | |
| assert pool in {'cls', 'mean'}, 'pool type must be either cls (cls token) or mean (mean pooling)' | |
| self.num_patches=num_patches | |
| self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, dim)) | |
| self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) | |
| self.dropout = nn.Dropout(emb_dropout) | |
| self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout) | |
| self.freq_embedding = nn.Sequential(nn.LayerNorm(dim),nn.Linear(dim,dim)) | |
| self.pool = pool | |
| self.to_latent = nn.Identity() | |
| self.LN = nn.LayerNorm(dim) | |
| def forward(self, x,ft_t): | |
| b, n, _ = x.shape #batch,num_patches,channels # | |
| cls_tokens = repeat(self.cls_token, '() n d -> b n d', b = b) | |
| ft_t = self.freq_embedding(ft_t) | |
| x +=ft_t.unsqueeze(1) | |
| x = torch.cat((cls_tokens, x), dim=1) | |
| x += self.pos_embedding[:, :(n + 1)] | |
| # x = torch.cat((x,ft_t), dim=1) | |
| x = self.dropout(x) | |
| x = self.transformer(x, mask=None) | |
| x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0] | |
| x = self.to_latent(x) | |
| x = self.LN(x) | |
| return x, None | |
| # ============================================================================= | |
| # FTCN-specific Transformer Classes | |
| # ============================================================================= | |
| class SpatialTransformerE(nn.Module): | |
| def __init__(self, spatial_size=14, time_size = 16, in_channels = 1024, num_parts=5): | |
| super().__init__() | |
| self.num_parts = num_parts | |
| self.in_channels = in_channels | |
| default_params= dict( | |
| dim=self.in_channels, depth=1, heads=16, mlp_dim=2048, dropout=0.1, emb_dropout=0.1, | |
| num_patches = spatial_size ** 2, num_classes = 1 | |
| ) | |
| self.num_patches = spatial_size ** 2 | |
| self.freq_embedding = nn.Linear(2048,1024) | |
| self.freq_embedding.weight.data.normal_(mean=0.0, std=0.02) | |
| self.freq_embedding.bias.data.zero_() | |
| self.pool = nn.AvgPool3d((time_size, 1, 1)) | |
| self.spatial_T = SpatialTransformer( **default_params ) | |
| def forward(self, x, ft, locs): | |
| batch_size = x.shape[0] | |
| x = self.pool(x) | |
| if self.num_parts > 0: | |
| ft = self.freq_embedding(ft.reshape(batch_size*self.num_parts,2048)) | |
| ft = ft.view(batch_size,self.num_parts,1024) | |
| locs = locs.reshape(-1, self.num_parts, 2) | |
| x = x.view(batch_size,self.num_patches,1024) | |
| x = self.spatial_T(x,ft,locs) | |
| return x | |
| class TransformerHead(nn.Module): | |
| def __init__(self, spatial_size=7, time_size=16, in_channels=1024, num_parts=5): | |
| super().__init__() | |
| if my_cfg.model.inco.no_time_pool: | |
| time_size = time_size * 2 | |
| patch_type = my_cfg.model.transformer.patch_type # time | |
| if patch_type == "time": | |
| self.pool = nn.AvgPool3d((1, spatial_size, spatial_size)) | |
| self.num_patches = time_size | |
| elif patch_type == "spatial": | |
| self.pool = nn.AvgPool3d((time_size, 1, 1)) | |
| self.num_patches = spatial_size ** 2 | |
| elif patch_type == "random": | |
| self.pool = CenterPatchPool() | |
| self.num_patches = time_size | |
| elif patch_type == "random_avg": | |
| self.pool = CenterAvgPool() | |
| self.num_patches = time_size | |
| elif patch_type == "all": | |
| self.pool = nn.Identity() | |
| self.num_patches = time_size * spatial_size * spatial_size | |
| else: | |
| raise NotImplementedError(patch_type) | |
| self.dim = my_cfg.model.transformer.dim # False | |
| if self.dim == -1: | |
| self.dim = in_channels # 2048 | |
| my_cfg.model.transformer.dim = self.dim | |
| self.in_channels = in_channels | |
| if self.dim != self.in_channels: | |
| self.fc = nn.Linear(self.in_channels, self.dim) | |
| default_params = dict( | |
| dim=self.dim, depth=6, heads=16, mlp_dim=2048, dropout=0.1, emb_dropout=0.1, | |
| ) | |
| params = my_cfg.model.transformer.to_dict() | |
| for key in default_params: | |
| if key in params: | |
| default_params[key] = params[key] | |
| self.time_T = TimeTransformer( | |
| num_patches=self.num_patches, num_classes=1, **default_params | |
| ) | |
| self.sigmoid = nn.Sigmoid() | |
| def forward(self, x,ft_t): | |
| x = self.pool(x) | |
| x = x.reshape(-1, self.in_channels, self.num_patches) | |
| x = x.permute(0, 2, 1) | |
| if self.dim != self.in_channels: | |
| x = self.fc(x.reshape(-1, self.in_channels)) | |
| x = x.reshape(-1, self.num_patches, self.dim) | |
| x = self.time_T(x,ft_t) | |
| return x |