Download models/vit.py from PeCoLab/EchMo-Vis: direct link, hf CLI and curl.
- Browser
- Download file 5.42 kB
-
https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/vit.py
- Command line
-
hf download hf://PeCoLab/EchMo-Vis/models/vit.py
-
curl -L -o vit.py https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/vit.py
5.42 kB
| import torch | |
| from torch import nn | |
| from torch.nn import Module, ModuleList | |
| from einops import rearrange, repeat | |
| from einops.layers.torch import Rearrange | |
| # helpers | |
| def pair(t): | |
| return t if isinstance(t, tuple) else (t, t) | |
| # classes | |
| class FeedForward(Module): | |
| def __init__(self, dim, hidden_dim, dropout = 0.): | |
| super().__init__() | |
| self.net = nn.Sequential( | |
| nn.LayerNorm(dim), | |
| 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(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.norm = nn.LayerNorm(dim) | |
| self.attend = nn.Softmax(dim = -1) | |
| self.dropout = nn.Dropout(dropout) | |
| 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): | |
| x = self.norm(x) | |
| 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 = self.heads), qkv) | |
| dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale | |
| attn = self.attend(dots) | |
| attn = self.dropout(attn) | |
| out = torch.matmul(attn, v) | |
| out = rearrange(out, 'b h n d -> b n (h d)') | |
| return self.to_out(out) | |
| class Transformer(Module): | |
| def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout = 0.): | |
| super().__init__() | |
| self.norm = nn.LayerNorm(dim) | |
| self.layers = ModuleList([]) | |
| for _ in range(depth): | |
| self.layers.append(ModuleList([ | |
| Attention(dim, heads = heads, dim_head = dim_head, dropout = dropout), | |
| FeedForward(dim, mlp_dim, dropout = dropout) | |
| ])) | |
| def forward(self, x): | |
| for attn, ff in self.layers: | |
| x = attn(x) + x | |
| x = ff(x) + x | |
| return self.norm(x) | |
| class ViT(Module): | |
| def __init__(self, img_size=(128, 1024), patch_size=16, in_chans=2, n_classes=2, embed_dim=128, depth=6, num_heads=8, mlp_ratio=4., emb_dropout=0.2, dropout=0.2): | |
| super().__init__() | |
| image_height, image_width = pair(img_size) | |
| patch_height, patch_width = pair(patch_size) | |
| self.n_classes = n_classes | |
| assert image_height % patch_height == 0 and image_width % patch_width == 0, 'Image dimensions must be divisible by the patch size.' | |
| self.grid_h = image_height // patch_height # 128//16=8 | |
| self.grid_w = image_width // patch_width # 1024//16=64 | |
| num_patches = self.grid_h * self.grid_w | |
| patch_dim = in_chans * patch_height * patch_width | |
| self.to_patch_embedding = nn.Sequential( | |
| Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_height, p2 = patch_width), | |
| nn.LayerNorm(patch_dim), | |
| nn.Linear(patch_dim, embed_dim), | |
| nn.LayerNorm(embed_dim), | |
| ) | |
| self.cls_token = nn.Parameter(torch.randn(1, 1, embed_dim)) # num_cls_tokens = 1 | |
| self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, embed_dim)) | |
| self.dropout = nn.Dropout(emb_dropout) | |
| dim_head = embed_dim // num_heads | |
| mlp_dim = int(embed_dim * mlp_ratio) | |
| self.transformer = Transformer(embed_dim, depth, num_heads, dim_head, mlp_dim, dropout) | |
| self.seg_head = nn.Sequential( | |
| Rearrange('b (h w) d -> b d h w', h=8, w=64, d=128), | |
| # 8×64 → 16×128 | |
| nn.Upsample(scale_factor=(2,2), mode='bilinear', align_corners=False), | |
| nn.Conv2d(128, 64, 3, padding=1, bias=False), | |
| nn.BatchNorm2d(64), | |
| nn.GELU(), | |
| # 16×128 → 32×256 | |
| nn.Upsample(scale_factor=(2,2), mode='bilinear', align_corners=False), | |
| nn.Conv2d(64, 32, 3, padding=1, bias=False), | |
| nn.BatchNorm2d(32), | |
| nn.GELU(), | |
| # 32×256 → 128×1024( | |
| nn.Upsample(scale_factor=(4,4), mode='bilinear', align_corners=False), | |
| nn.Conv2d(32, self.n_classes, 1, padding=0), | |
| ) | |
| def forward(self, img): | |
| batch = img.shape[0] | |
| x = self.to_patch_embedding(img) | |
| cls_tokens = repeat(self.cls_token, '1 1 d -> b 1 d', b=batch) | |
| x = torch.cat((cls_tokens, x), dim = 1) | |
| seq = x.shape[1] | |
| x = x + self.pos_embedding[:, :seq, :] | |
| x = self.dropout(x) | |
| x = self.transformer(x) | |
| # # classification task | |
| # x = x[:, 0] | |
| # x = self.to_latent(x) | |
| # x = self.mlp_head(x) | |
| # segmentation task | |
| x = x[:, 1:, :] # drop CLS, shape (batch, num_patches, embed_dim) | |
| x = self.seg_head(x) | |
| return x | |
| if __name__ == "__main__": | |
| model = ViT() | |
| input_img = torch.randn(2, 2, 128, 1024) | |
| print("input shape:", input_img.shape) # output: torch.Size([2, 2, 128, 1024]) | |
| output = model(input_img) | |
| print("output shape:", output.shape) # output: torch.Size([2, 2, 128, 1024]) | |