|
|
|
@@ -24,7 +24,8 @@ from mindspore.ops import operations as P |
|
|
|
from mindspore.ops import functional as F |
|
|
|
from mindspore.ops import composite as C |
|
|
|
from mindspore.common.initializer import initializer |
|
|
|
from .mobilenet import InvertedResidual, ConvBNReLU |
|
|
|
from mindspore.ops.operations import TensorAdd |
|
|
|
from mindspore import Parameter |
|
|
|
|
|
|
|
|
|
|
|
def _conv2d(in_channel, out_channel, kernel_size=3, stride=1, pad_mod='same'): |
|
|
|
@@ -45,6 +46,129 @@ def _make_divisible(v, divisor, min_value=None): |
|
|
|
return new_v |
|
|
|
|
|
|
|
|
|
|
|
class DepthwiseConv(nn.Cell): |
|
|
|
""" |
|
|
|
Depthwise Convolution warpper definition. |
|
|
|
|
|
|
|
Args: |
|
|
|
in_planes (int): Input channel. |
|
|
|
kernel_size (int): Input kernel size. |
|
|
|
stride (int): Stride size. |
|
|
|
pad_mode (str): pad mode in (pad, same, valid) |
|
|
|
channel_multiplier (int): Output channel multiplier |
|
|
|
has_bias (bool): has bias or not |
|
|
|
|
|
|
|
Returns: |
|
|
|
Tensor, output tensor. |
|
|
|
|
|
|
|
Examples: |
|
|
|
>>> DepthwiseConv(16, 3, 1, 'pad', 1, channel_multiplier=1) |
|
|
|
""" |
|
|
|
def __init__(self, in_planes, kernel_size, stride, pad_mode, pad, channel_multiplier=1, has_bias=False): |
|
|
|
super(DepthwiseConv, self).__init__() |
|
|
|
self.has_bias = has_bias |
|
|
|
self.in_channels = in_planes |
|
|
|
self.channel_multiplier = channel_multiplier |
|
|
|
self.out_channels = in_planes * channel_multiplier |
|
|
|
self.kernel_size = (kernel_size, kernel_size) |
|
|
|
self.depthwise_conv = P.DepthwiseConv2dNative(channel_multiplier=channel_multiplier, |
|
|
|
kernel_size=self.kernel_size, |
|
|
|
stride=stride, pad_mode=pad_mode, pad=pad) |
|
|
|
self.bias_add = P.BiasAdd() |
|
|
|
weight_shape = [channel_multiplier, in_planes, *self.kernel_size] |
|
|
|
self.weight = Parameter(initializer('ones', weight_shape), name='weight') |
|
|
|
|
|
|
|
if has_bias: |
|
|
|
bias_shape = [channel_multiplier * in_planes] |
|
|
|
self.bias = Parameter(initializer('zeros', bias_shape), name='bias') |
|
|
|
else: |
|
|
|
self.bias = None |
|
|
|
|
|
|
|
def construct(self, x): |
|
|
|
output = self.depthwise_conv(x, self.weight) |
|
|
|
if self.has_bias: |
|
|
|
output = self.bias_add(output, self.bias) |
|
|
|
return output |
|
|
|
|
|
|
|
|
|
|
|
class ConvBNReLU(nn.Cell): |
|
|
|
""" |
|
|
|
Convolution/Depthwise fused with Batchnorm and ReLU block definition. |
|
|
|
|
|
|
|
Args: |
|
|
|
in_planes (int): Input channel. |
|
|
|
out_planes (int): Output channel. |
|
|
|
kernel_size (int): Input kernel size. |
|
|
|
stride (int): Stride size for the first convolutional layer. Default: 1. |
|
|
|
groups (int): channel group. Convolution is 1 while Depthiwse is input channel. Default: 1. |
|
|
|
|
|
|
|
Returns: |
|
|
|
Tensor, output tensor. |
|
|
|
|
|
|
|
Examples: |
|
|
|
>>> ConvBNReLU(16, 256, kernel_size=1, stride=1, groups=1) |
|
|
|
""" |
|
|
|
def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, groups=1): |
|
|
|
super(ConvBNReLU, self).__init__() |
|
|
|
padding = (kernel_size - 1) // 2 |
|
|
|
if groups == 1: |
|
|
|
conv = nn.Conv2d(in_planes, out_planes, kernel_size, stride, pad_mode='pad', |
|
|
|
padding=padding) |
|
|
|
else: |
|
|
|
conv = DepthwiseConv(in_planes, kernel_size, stride, pad_mode='pad', pad=padding) |
|
|
|
layers = [conv, nn.BatchNorm2d(out_planes), nn.ReLU6()] |
|
|
|
self.features = nn.SequentialCell(layers) |
|
|
|
|
|
|
|
def construct(self, x): |
|
|
|
output = self.features(x) |
|
|
|
return output |
|
|
|
|
|
|
|
|
|
|
|
class InvertedResidual(nn.Cell): |
|
|
|
""" |
|
|
|
Mobilenetv2 residual block definition. |
|
|
|
|
|
|
|
Args: |
|
|
|
inp (int): Input channel. |
|
|
|
oup (int): Output channel. |
|
|
|
stride (int): Stride size for the first convolutional layer. Default: 1. |
|
|
|
expand_ratio (int): expand ration of input channel |
|
|
|
|
|
|
|
Returns: |
|
|
|
Tensor, output tensor. |
|
|
|
|
|
|
|
Examples: |
|
|
|
>>> ResidualBlock(3, 256, 1, 1) |
|
|
|
""" |
|
|
|
def __init__(self, inp, oup, stride, expand_ratio): |
|
|
|
super(InvertedResidual, self).__init__() |
|
|
|
assert stride in [1, 2] |
|
|
|
|
|
|
|
hidden_dim = int(round(inp * expand_ratio)) |
|
|
|
self.use_res_connect = stride == 1 and inp == oup |
|
|
|
|
|
|
|
layers = [] |
|
|
|
if expand_ratio != 1: |
|
|
|
layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1)) |
|
|
|
layers.extend([ |
|
|
|
# dw |
|
|
|
ConvBNReLU(hidden_dim, hidden_dim, stride=stride, groups=hidden_dim), |
|
|
|
# pw-linear |
|
|
|
nn.Conv2d(hidden_dim, oup, kernel_size=1, stride=1, has_bias=False), |
|
|
|
nn.BatchNorm2d(oup), |
|
|
|
]) |
|
|
|
self.conv = nn.SequentialCell(layers) |
|
|
|
self.add = TensorAdd() |
|
|
|
self.cast = P.Cast() |
|
|
|
|
|
|
|
def construct(self, x): |
|
|
|
identity = x |
|
|
|
x = self.conv(x) |
|
|
|
if self.use_res_connect: |
|
|
|
return self.add(identity, x) |
|
|
|
return x |
|
|
|
|
|
|
|
|
|
|
|
class FlattenConcat(nn.Cell): |
|
|
|
""" |
|
|
|
Concatenate predictions into a single tensor. |
|
|
|
@@ -57,20 +181,17 @@ class FlattenConcat(nn.Cell): |
|
|
|
""" |
|
|
|
def __init__(self, config): |
|
|
|
super(FlattenConcat, self).__init__() |
|
|
|
self.sizes = config.FEATURE_SIZE |
|
|
|
self.length = len(self.sizes) |
|
|
|
self.num_default = config.NUM_DEFAULT |
|
|
|
self.concat = P.Concat(axis=-1) |
|
|
|
self.num_ssd_boxes = config.NUM_SSD_BOXES |
|
|
|
self.concat = P.Concat(axis=1) |
|
|
|
self.transpose = P.Transpose() |
|
|
|
def construct(self, x): |
|
|
|
def construct(self, inputs): |
|
|
|
output = () |
|
|
|
for i in range(self.length): |
|
|
|
shape = F.shape(x[i]) |
|
|
|
mid_shape = (shape[0], -1, self.num_default[i], self.sizes[i], self.sizes[i]) |
|
|
|
final_shape = (shape[0], -1, self.num_default[i] * self.sizes[i] * self.sizes[i]) |
|
|
|
output += (F.reshape(F.reshape(x[i], mid_shape), final_shape),) |
|
|
|
batch_size = F.shape(inputs[0])[0] |
|
|
|
for x in inputs: |
|
|
|
x = self.transpose(x, (0, 2, 3, 1)) |
|
|
|
output += (F.reshape(x, (batch_size, -1)),) |
|
|
|
res = self.concat(output) |
|
|
|
return self.transpose(res, (0, 2, 1)) |
|
|
|
return F.reshape(res, (batch_size, self.num_ssd_boxes, -1)) |
|
|
|
|
|
|
|
|
|
|
|
class MultiBox(nn.Cell): |
|
|
|
@@ -145,7 +266,6 @@ class SSD300(nn.Cell): |
|
|
|
if not is_training: |
|
|
|
self.softmax = P.Softmax() |
|
|
|
|
|
|
|
|
|
|
|
def construct(self, x): |
|
|
|
layer_out_13, output = self.backbone(x) |
|
|
|
multi_feature = (layer_out_13, output) |
|
|
|
|