mirror of
https://github.com/deepinsight/insightface.git
synced 2026-05-18 14:55:42 +00:00
166 lines
6.0 KiB
Python
166 lines
6.0 KiB
Python
import sys
|
|
import os
|
|
import mxnet as mx
|
|
import mxnet.ndarray as nd
|
|
import mxnet.gluon as gluon
|
|
import mxnet.gluon.nn as nn
|
|
import mxnet.autograd as ag
|
|
import symbol_utils
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
|
from config import config
|
|
|
|
def Act():
|
|
if config.net_act=='prelu':
|
|
return nn.PReLU()
|
|
else:
|
|
return nn.Activation(config.net_act)
|
|
|
|
def ConvBlock(channels, kernel_size, strides, **kwargs):
|
|
out = nn.HybridSequential(**kwargs)
|
|
with out.name_scope():
|
|
out.add(
|
|
nn.Conv2D(channels, kernel_size, strides=strides, padding=1, use_bias=False),
|
|
nn.BatchNorm(scale=True),
|
|
Act()
|
|
#nn.Activation('relu')
|
|
)
|
|
return out
|
|
|
|
def Conv1x1(channels, is_linear=False, **kwargs):
|
|
out = nn.HybridSequential(**kwargs)
|
|
with out.name_scope():
|
|
out.add(
|
|
nn.Conv2D(channels, 1, padding=0, use_bias=False),
|
|
nn.BatchNorm(scale=True)
|
|
)
|
|
if not is_linear:
|
|
#out.add(nn.Activation('relu'))
|
|
out.add(Act())
|
|
return out
|
|
|
|
def DWise(channels, strides, kernel_size=3, **kwargs):
|
|
out = nn.HybridSequential(**kwargs)
|
|
with out.name_scope():
|
|
out.add(
|
|
nn.Conv2D(channels, kernel_size, strides=strides, padding=kernel_size // 2, groups=channels, use_bias=False),
|
|
nn.BatchNorm(scale=True),
|
|
Act()
|
|
#nn.Activation('relu')
|
|
)
|
|
return out
|
|
|
|
class SepCONV(nn.HybridBlock):
|
|
def __init__(self, inp, output, kernel_size, depth_multiplier=1, with_bn=True, **kwargs):
|
|
super(SepCONV, self).__init__(**kwargs)
|
|
with self.name_scope():
|
|
self.net = nn.HybridSequential()
|
|
cn = int(inp*depth_multiplier)
|
|
|
|
if output is None:
|
|
self.net.add(
|
|
nn.Conv2D(in_channels=inp, channels=cn, groups=inp, kernel_size=kernel_size, strides=(1,1), padding=kernel_size // 2
|
|
, use_bias=not with_bn)
|
|
)
|
|
else:
|
|
self.net.add(
|
|
nn.Conv2D(in_channels=inp, channels=cn, groups=inp, kernel_size=kernel_size, strides=(1,1), padding=kernel_size // 2
|
|
, use_bias=False),
|
|
nn.BatchNorm(),
|
|
Act(),
|
|
#nn.Activation('relu'),
|
|
nn.Conv2D(in_channels=cn, channels=output, kernel_size=(1,1), strides=(1,1)
|
|
, use_bias=not with_bn)
|
|
)
|
|
|
|
self.with_bn = with_bn
|
|
self.act = Act()
|
|
#self.act = nn.Activation('relu')
|
|
if with_bn:
|
|
self.bn = nn.BatchNorm()
|
|
def hybrid_forward(self, F ,x):
|
|
x = self.net(x)
|
|
if self.with_bn:
|
|
x = self.bn(x)
|
|
if self.act is not None:
|
|
x = self.act(x)
|
|
return x
|
|
|
|
class ExpandedConv(nn.HybridBlock):
|
|
def __init__(self, inp, oup, t, strides, kernel=3, same_shape=True, **kwargs):
|
|
super(ExpandedConv, self).__init__(**kwargs)
|
|
|
|
self.same_shape = same_shape
|
|
self.strides = strides
|
|
with self.name_scope():
|
|
self.bottleneck = nn.HybridSequential()
|
|
self.bottleneck.add(
|
|
Conv1x1(inp*t, prefix="expand_"),
|
|
DWise(inp*t, self.strides, kernel, prefix="dwise_"),
|
|
Conv1x1(oup, is_linear=True, prefix="linear_")
|
|
)
|
|
def hybrid_forward(self, F, x):
|
|
out = self.bottleneck(x)
|
|
if self.strides == 1 and self.same_shape:
|
|
out = F.elemwise_add(out, x)
|
|
return out
|
|
|
|
def ExpandedConvSequence(t, k, inp, oup, repeats, first_strides, **kwargs):
|
|
seq = nn.HybridSequential(**kwargs)
|
|
with seq.name_scope():
|
|
seq.add(ExpandedConv(inp, oup, t, first_strides, k, same_shape=False))
|
|
curr_inp = oup
|
|
for i in range(1, repeats):
|
|
seq.add(ExpandedConv(curr_inp, oup, t, 1))
|
|
curr_inp = oup
|
|
return seq
|
|
|
|
class MNasNet(nn.HybridBlock):
|
|
def __init__(self, m=1.0, **kwargs):
|
|
super(MNasNet, self).__init__(**kwargs)
|
|
|
|
self.first_oup = int(32*m)
|
|
self.second_oup = int(16*m)
|
|
#self.second_oup = int(32*m)
|
|
self.interverted_residual_setting = [
|
|
# t, c, n, s, k
|
|
[3, int(24*m), 3, 2, 3, "stage2_"], # -> 56x56
|
|
[3, int(40*m), 3, 2, 5, "stage3_"], # -> 28x28
|
|
[6, int(80*m), 3, 2, 5, "stage4_1_"], # -> 14x14
|
|
[6, int(96*m), 2, 1, 3, "stage4_2_"], # -> 14x14
|
|
[6, int(192*m), 4, 2, 5, "stage5_1_"], # -> 7x7
|
|
[6, int(320*m), 1, 1, 3, "stage5_2_"], # -> 7x7
|
|
]
|
|
self.last_channels = int(1024*m)
|
|
|
|
with self.name_scope():
|
|
self.features = nn.HybridSequential()
|
|
self.features.add(ConvBlock(self.first_oup, 3, 1, prefix="stage1_conv0_"))
|
|
self.features.add(SepCONV(self.first_oup, self.second_oup, 3, prefix="stage1_sepconv0_"))
|
|
inp = self.second_oup
|
|
for i, (t, c, n, s, k, prefix) in enumerate(self.interverted_residual_setting):
|
|
oup = c
|
|
self.features.add(ExpandedConvSequence(t, k, inp, oup, n, s, prefix=prefix))
|
|
inp = oup
|
|
|
|
self.features.add(Conv1x1(self.last_channels, prefix="stage5_3_"))
|
|
#self.features.add(nn.GlobalAvgPool2D())
|
|
#self.features.add(nn.Flatten())
|
|
#self.output = nn.Dense(num_classes)
|
|
def hybrid_forward(self, F, x):
|
|
x = self.features(x)
|
|
#x = self.output(x)
|
|
return x
|
|
|
|
def num_output_channel(self):
|
|
return self.last_channels
|
|
|
|
def get_symbol():
|
|
net = MNasNet(config.net_multiplier)
|
|
data = mx.sym.Variable(name='data')
|
|
data = data-127.5
|
|
data = data*0.0078125
|
|
body = net(data)
|
|
fc1 = symbol_utils.get_fc1(body, config.emb_size, config.net_output, input_channel=net.num_output_channel())
|
|
return fc1
|
|
|