diff --git a/tools/coreml/converter/_layers.py b/tools/coreml/converter/_layers.py index 8f4bc1a8a02c..6590b13b108f 100644 --- a/tools/coreml/converter/_layers.py +++ b/tools/coreml/converter/_layers.py @@ -220,6 +220,49 @@ def convert_activation(net, node, module, builder): output_name = output_name) +def convert_leakyrelu(net, node, module, builder): + """Convert a leakyrelu layer from mxnet to coreml. + + Parameters + ---------- + network: net + A mxnet network object. + + layer: node + Node to convert. + + module: module + An module for MXNet + + builder: NeuralNetworkBuilder + A neural network builder object. + """ + + input_name, output_name = _get_input_output_name(net, node) + name = node['name'] + inputs = node['inputs'] + args, _ = module.get_params() + mx_non_linearity = _get_attrs(node)['act_type'] + if mx_non_linearity == 'elu': + non_linearity = 'ELU' + slope = _get_attrs(node)['slope'] if 'slope' in _get_attrs(node) else 0.25 + params = slope + elif mx_non_linearity == 'leaky': + non_linearity = 'LEAKYRELU' + slope = _get_attrs(node)['slope'] if 'slope' in _get_attrs(node) else 0.25 + params = [slope] + elif mx_non_linearity == 'prelu': + non_linearity = 'PRELU' + params = args[_get_node_name(net, inputs[1][0])].asnumpy() + else: + raise TypeError('Unknown activation type %s' % mx_non_linearity) + builder.add_activation(name = name, + non_linearity = non_linearity, + input_name = input_name, + output_name = output_name, + params = params) + + def convert_elementwise_add(net, node, module, builder): """Convert an elementwise add layer from mxnet to coreml. @@ -335,6 +378,7 @@ def convert_convolution(net, node, module, builder): border_mode = "valid" n_filters = int(param['num_filter']) + n_groups = int(param['num_group']) if 'num_group' in param else 1 W = args[_get_node_name(net, inputs[1][0])].asnumpy() if has_bias: @@ -361,7 +405,7 @@ def convert_convolution(net, node, module, builder): stride_height=stride_height, stride_width=stride_width, border_mode=border_mode, - groups=1, + groups=n_groups, W=W, b=Wb, has_bias=has_bias, diff --git a/tools/coreml/converter/_mxnet_converter.py b/tools/coreml/converter/_mxnet_converter.py index 2d91eb86a965..c5fd37b34aed 100644 --- a/tools/coreml/converter/_mxnet_converter.py +++ b/tools/coreml/converter/_mxnet_converter.py @@ -38,11 +38,14 @@ 'elemwise_add' : _layers.convert_elementwise_add, 'Reshape' : _layers.convert_reshape, 'Deconvolution' : _layers.convert_deconvolution, + 'LeakyReLU' : _layers.convert_leakyrelu, } _MXNET_SKIP_LAYERS = [ '_MulScalar', 'Dropout', + '_minus_scalar', + '_mul_scalar', ] def _mxnet_remove_batch(input_data): diff --git a/tools/coreml/test/test_mxnet_converter.py b/tools/coreml/test/test_mxnet_converter.py index bc850690a572..192090588fde 100644 --- a/tools/coreml/test/test_mxnet_converter.py +++ b/tools/coreml/test/test_mxnet_converter.py @@ -192,6 +192,33 @@ def test_tiny_tanh_activation_random_input(self): net = mx.sym.Activation(net, name='tanh1', act_type="tanh") self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_tiny_elu_leakyrelu_random_input(self): + np.random.seed(1988) + input_shape = (1, 10) + net = mx.sym.Variable('data') + net = mx.sym.FullyConnected(data=net, name='fc1', num_hidden=5) + slope = 0.1 + net = mx.sym.LeakyReLU(net, name='elu1', act_type="elu", slope=slope) + self._test_mxnet_model(net, input_shape=input_shape, mode='random') + + def test_tiny_leaky_leakyrelu_random_input(self): + np.random.seed(1988) + input_shape = (1, 10) + net = mx.sym.Variable('data') + net = mx.sym.FullyConnected(data=net, name='fc1', num_hidden=5) + slope = 0.1 + net = mx.sym.LeakyReLU(net, name='leaky1', act_type="leaky", slope=slope) + self._test_mxnet_model(net, input_shape=input_shape, mode='random') + + def test_tiny_prelu_leakyrelu_random_input(self): + np.random.seed(1988) + input_shape = (1, 10) + net = mx.sym.Variable('data') + net = mx.sym.FullyConnected(data=net, name='fc1', num_hidden=5) + gamma = mx.sym.Variable('gamma') + net = mx.sym.LeakyReLU(net, gamma=gamma, name='prelu1', act_type="prelu") + self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_really_tiny_conv_random_input(self): np.random.seed(1988) input_shape = (1, 1, 10, 10) @@ -408,6 +435,26 @@ def test_really_tiny_conv_random_input_multi_filter(self): ) self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_really_tiny_conv_random_input_multi_group(self): + np.random.seed(1988) + input_shape = (1, 16, 10, 10) + num_filter = 16 + num_group = 4 + kernel = (1, 1) + stride = (1, 1) + pad = (0, 0) + net = mx.sym.Variable('data') + net = mx.symbol.Convolution( + data=net, + num_filter=num_filter, + num_group=num_group, + kernel=kernel, + stride=stride, + pad=pad, + name='conv_1' + ) + self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_tiny_conv_random_3d_input(self): np.random.seed(1988) input_shape = (1, 3, 10, 10) @@ -444,6 +491,26 @@ def test_tiny_conv_random_input_multi_filter(self): ) self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_tiny_conv_random_input_multi_group(self): + np.random.seed(1988) + input_shape = (1, 16, 10, 10) + num_filter = 16 + num_group = 4 + kernel = (5, 5) + stride = (1, 1) + pad = (0, 0) + net = mx.sym.Variable('data') + net = mx.symbol.Convolution( + data=net, + num_filter=num_filter, + num_group=num_group, + kernel=kernel, + stride=stride, + pad=pad, + name='conv_1' + ) + self._test_mxnet_model(net, input_shape=input_shape, mode='random') + def test_conv_random(self): np.random.seed(1988) input_shape = (1, 3, 10, 10)