TinyFaceNet-1M / code /model.py
sraivante's picture
TinyFaceNet-1M: ArcFace-distilled 1M-param face embedding, INT8 ONNX, full recipe
902df3d verified
Raw History Blame Contribute Delete
1.92 kB
import torch, torch.nn as nn
class DW(nn.Module): # depthwise-separable bottleneck (MobileFaceNet style)
def __init__(s,i,o,st,exp=2):
super().__init__(); h=i*exp; s.res=(st==1 and i==o)
s.b=nn.Sequential(nn.Conv2d(i,h,1,bias=False),nn.BatchNorm2d(h),nn.PReLU(h),
nn.Conv2d(h,h,3,st,1,groups=h,bias=False),nn.BatchNorm2d(h),nn.PReLU(h),
nn.Conv2d(h,o,1,bias=False),nn.BatchNorm2d(o))
def forward(s,x): return x+s.b(x) if s.res else s.b(x)
class TinyFaceNet(nn.Module):
"""~1.0M params, 112x112 in, 128-d embedding."""
def __init__(s,emb=128,n_cls=10,w=1.6):
super().__init__(); c=lambda v:int(v*w)
s.stem=nn.Sequential(nn.Conv2d(3,c(32),3,2,1,bias=False),nn.BatchNorm2d(c(32)),nn.PReLU(c(32)),
nn.Conv2d(c(32),c(32),3,1,1,groups=c(32),bias=False),nn.BatchNorm2d(c(32)),nn.PReLU(c(32)))
cfg=[(c(32),c(48),2),(c(48),c(48),1),(c(48),c(48),1),(c(48),c(96),2),(c(96),c(96),1),(c(96),c(96),1),(c(96),c(96),1),
(c(96),c(128),2),(c(128),c(128),1),(c(128),c(128),1)]
s.blocks=nn.Sequential(*[DW(i,o,st) for i,o,st in cfg])
s.head=nn.Sequential(nn.Conv2d(c(128),c(256),1,bias=False),nn.BatchNorm2d(c(256)),nn.PReLU(c(256)),
nn.Conv2d(c(256),c(256),7,1,0,groups=c(256),bias=False),nn.BatchNorm2d(c(256)),
nn.Flatten(),nn.Linear(c(256),emb,bias=False),nn.BatchNorm1d(emb))
s.distill=nn.Linear(emb,512) # training-only: map to teacher space
s.cls=nn.Linear(emb,n_cls) # training-only
def forward(s,x): return s.head(s.blocks(s.stem(x)))
if __name__=="__main__":
m=TinyFaceNet(); core=sum(p.numel() for n,p in m.named_parameters() if not n.startswith(("distill","cls")))
print("deploy params",core, "total",sum(p.numel() for p in m.parameters())); print(m(torch.zeros(2,3,112,112)).shape)