vit-cifar10 / model.py
heissanjay's picture
Upload model.py with huggingface_hub
6f17eed verified
Raw
History Blame Contribute Delete
5.6 kB
import torch
import numpy as np
import torch.nn as nn
from dataclasses import dataclass
@dataclass
class ModelConfig:
img_size: int = 32
patch_size: int = 4
in_channels: int = 3
embed_dim: int = 768
config = ModelConfig()
class PatchEmbeddings(nn.Module):
def __init__(self, img_size, patch_size, in_channels, embed_dim):
super().__init__()
self.img_size = img_size
self.patch_size = patch_size
self.in_channels = in_channels
self.embed_dim = embed_dim
self.proj = nn.Conv2d(
in_channels, embed_dim,
kernel_size = patch_size,
stride=patch_size
)
def forward(self, x):
x = self.proj(x) # [batch, embed, H/P(8), W/P(8)]
x = x.flatten(2) # [batch, embed, 64 (8 x 8 )]
x = x.transpose(1, 2) #[batch, 64, embed]
return x
class Attention(nn.Module):
def __init__(self, dim, n_heads=12, qkv_bias=True, attn_drop=0., proj_drop=0.):
super().__init__()
self.n_heads = n_heads
self.dim = dim
self.head_dim = dim // n_heads
self.scale = self.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):
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.n_heads, self.head_dim).permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2] # (B, H, N, D)
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
x = self.proj_drop(x)
return x
class MLP(nn.Module):
def __init__(self, in_features, hidden_features=None, out_features=None, drop=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 = nn.GELU()
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)
x = self.drop(x)
return x
class Block(nn.Module):
def __init__(self, dim, n_heads, mlp_ratio=4., qkv_bias=True,
attn_drop=0., proj_drop=0.):
super().__init__()
self.norm1 = nn.LayerNorm(dim)
self.attn = Attention(dim=dim, n_heads=n_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=proj_drop)
self.norm2 = nn.LayerNorm(dim)
self.mlp = MLP(
in_features = dim,
hidden_features = int(dim * mlp_ratio),
drop = proj_drop
)
def forward(self, x):
x = x + self.attn(self.norm1(x))
x = x + self.mlp(self.norm2(x))
return x
class VisionTransformer(nn.Module):
def __init__(
self,
img_size=config.img_size,
patch_size=config.patch_size,
in_channels=config.in_channels,
num_classes = 10,
embed_dim = 768,
depth=12,
n_heads=12,
mlp_ratio=4,
qkv_bias=True,
attn_drop=0.,
proj_drop=0.,
):
super().__init__()
self.num_classes=num_classes
self.embed_dim=embed_dim
self.patch_embed=PatchEmbeddings(
img_size=img_size,
patch_size=patch_size,
in_channels=in_channels,
embed_dim=embed_dim
)
num_patches = (img_size // patch_size) ** 2
self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches+1, embed_dim))
self.pos_drop = nn.Dropout(p=proj_drop)
self.blocks = nn.Sequential(*[
Block(
dim=embed_dim,
n_heads=n_heads,
mlp_ratio=mlp_ratio,
qkv_bias=qkv_bias,
attn_drop=attn_drop,
proj_drop=proj_drop
)
for _ in range(depth)
])
self.norm = nn.LayerNorm(embed_dim)
self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity()
self._init_weights()
def _init_weights(self):
torch.nn.init.normal_(self.cls_token, std=0.02)
torch.nn.init.normal_(self.pos_embed, std=0.02)
self.apply(self._init_other)
def _init_other(self, m):
if isinstance(m, nn.Linear):
torch.nn.init.xavier_uniform_(m.weight)
if isinstance(m, nn.Linear) and m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m ,nn.LayerNorm):
nn.init.constant_(m.bias, 0)
nn.init.constant_(m.weight, 1.0)
def forward(self, x):
B = x.shape[0]
x = self.patch_embed(x)
cls_token = self.cls_token.expand(B, -1, -1)
x = torch.cat((cls_token, x), dim=1)
x = x + self.pos_embed
x = self.pos_drop(x)
x = self.blocks(x)
x = self.norm(x)
cls_final = x[:, 0]
logits = self.head(cls_final)
return logits