mirror of
https://github.com/deepinsight/insightface.git
synced 2026-05-16 05:27:56 +00:00
214 lines
7.0 KiB
Python
214 lines
7.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
|