Atomight-V1-GRAFT-0.8M / modeling.py
NovatasticRoScript's picture
Upload folder using huggingface_hub
cb5d220 verified
Raw
History Blame Contribute Delete
2.97 kB
import torch
import torch.nn as nn
import torch.nn.functional as F
D = 128
D2 = 96
class DepthwiseSeparableConv(nn.Module):
def __init__(self, in_ch, out_ch):
super().__init__()
self.dw = nn.Conv2d(in_ch, in_ch, 3, padding=1, groups=in_ch)
self.pw = nn.Conv2d(in_ch, out_ch, 1)
def forward(self, x):
return self.pw(self.dw(x))
class AtomEncoder(nn.Module):
def __init__(self, embed_dim=D):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(1, 16, 3, stride=2, padding=1), nn.GELU(),
nn.Conv2d(16, 32, 3, stride=2, padding=1), nn.GELU(),
DepthwiseSeparableConv(32, 64), nn.GELU(),
nn.AdaptiveAvgPool2d(1),
)
self.proj = nn.Linear(64, embed_dim)
def forward(self, x):
return self.proj(self.net(x).flatten(1))
class GridRelationalAttention(nn.Module):
def __init__(self, dim=D, heads=4, n_relations=4):
super().__init__()
self.missing_token = nn.Parameter(torch.randn(dim) * 0.02)
self.row_attn = nn.MultiheadAttention(dim, heads, batch_first=True)
self.col_attn = nn.MultiheadAttention(dim, heads, batch_first=True)
self.relation_queries = nn.Parameter(torch.randn(n_relations, dim) * 0.02)
self.cross_attn = nn.MultiheadAttention(dim, heads, batch_first=True)
self.rule_proj = nn.Linear(n_relations * dim, dim)
self.n_relations, self.dim = n_relations, dim
def forward(self, context_panels):
B = context_panels.shape[0]
missing = self.missing_token.expand(B, 1, self.dim)
grid = torch.cat([context_panels, missing], dim=1)
rows_idx = [[0,1,2],[3,4,5],[6,7,8]]
cols_idx = [[0,3,6],[1,4,7],[2,5,8]]
row_vecs = torch.cat([
self.row_attn(grid[:, idx, :], grid[:, idx, :], grid[:, idx, :])[0].mean(1, keepdim=True)
for idx in rows_idx
], dim=1)
col_vecs = torch.cat([
self.col_attn(grid[:, idx, :], grid[:, idx, :], grid[:, idx, :])[0].mean(1, keepdim=True)
for idx in cols_idx
], dim=1)
combined_ctx = torch.cat([row_vecs, col_vecs], dim=1)
rq = self.relation_queries.unsqueeze(0).expand(B, -1, -1)
rel_out, _ = self.cross_attn(rq, combined_ctx, combined_ctx)
return self.rule_proj(rel_out.flatten(1))
class CandidateScorer(nn.Module):
def __init__(self, dim=D):
super().__init__()
self.score_proj = nn.Linear(dim, dim)
def forward(self, rule_embedding, candidate_embeds):
proj_rule = self.score_proj(rule_embedding)
return torch.einsum("bd,bkd->bk", proj_rule, candidate_embeds)
class GRAFT(nn.Module):
def __init__(self, vocab_size, narrator_cls):
super().__init__()
self.encoder = AtomEncoder()
self.gra = GridRelationalAttention()
self.scorer = CandidateScorer()
self.narrator = narrator_cls(vocab_size=vocab_size)