blob: 6b5f1b4cc2a00c0610032c4a7d5ae90530723067 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import mxnet as mx
from mxnet.gluon import HybridBlock, nn
import numpy as np
import onnxruntime as rt
from mxnet.test_utils import assert_almost_equal
import pytest
import tempfile
def def_model(namespace, op_name, dummy_input=False, **params):
class Model(HybridBlock):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
def forward(self, *inputs):
names = op_name.split('.')
func = getattr(namespace, names[-1])
if dummy_input:
return func(**params), inputs[0]
else:
return func(*inputs, **params)
return Model
def def_model_from_func(func, dummy_input=False, **params):
class Model(HybridBlock):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
def forward(self, *inputs):
if dummy_input:
return func(**params), inputs[0]
else:
return func(*inputs, **params)
return Model
def op_export_test(model_name, Model, inputs, tmp_path, dummy_input=False, onnx_map=None, mx_map=None, rtol=None, atol=None):
def export_to_onnx(model, model_name, inputs):
model_path = '{}/{}'.format(tmp_path, model_name)
model.export(model_path, epoch=0)
sym_file = '{}-symbol.json'.format(model_path)
params_file = '{}-0000.params'.format(model_path)
onnx_file = '{}/{}.onnx'.format(tmp_path, model_name)
mx.onnx.export_model(sym_file, params_file, [inp.shape for inp in inputs],
[inp.dtype for inp in inputs], onnx_file)
return onnx_file
def onnx_rt(onnx_file, inputs):
sess = rt.InferenceSession(onnx_file)
dtype_0 = inputs[0].asnumpy().dtype
input_dict = dict((sess.get_inputs()[i].name, inputs[i].asnumpy()) for i in range(len(inputs)))
pred = sess.run(None, input_dict)
return pred
# create a new model
model = Model()
model.initialize(ctx=mx.cpu(0))
model.hybridize()
pred_mx = model(*inputs)
# this is for ops such as mx.np.concatenate
if isinstance(inputs[0], tuple):
inputs = list(inputs[0])
onnx_file = export_to_onnx(model, model_name, inputs)
pred_onx = onnx_rt(onnx_file, inputs)
if dummy_input:
pred_mx = pred_mx[0]
if isinstance(pred_mx, list):
for i in range(len(pred_mx)):
pred_onx_i = onnx_map(pred_onx[i]) if onnx_map else pred_onx[i]
pred_mx_i = mx_map(pred_mx[i]) if mx_map else pred_mx[i]
assert_almost_equal(pred_onx_i, pred_mx_i, equal_nan=True, rtol=rtol, atol=atol)
else:
pred_onx = onnx_map(pred_onx[0]) if onnx_map else pred_onx[0]
pred_mx = mx_map(pred_mx) if mx_map else pred_mx
assert_almost_equal(pred_onx, pred_mx, equal_nan=True, rtol=rtol, atol=atol)
def test_onnx_export_np_abs(tmp_path):
M = def_model(mx.np, 'abs')
x = mx.np.array([[-2, -1], [0, 99]], dtype='float32')
op_export_test('abs', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'float16', 'int32', 'int64'])
@pytest.mark.parametrize('params', [[(0, 1), (2,3), (1, 1)],
[(None, 1), (2, None), None],
[(0, 0, 0), (None, 4, 5), (None, 1, 2)]])
def test_onnx_export_npx_slice(tmp_path, dtype, params):
M = def_model(mx.npx, 'slice', begin=params[0], end=params[1], step=params[2])
x = mx.np.arange(start=0, stop=60, dtype=dtype).reshape((3, 4, 5))
op_export_test('slice', M, [x], tmp_path)
@pytest.mark.parametrize("dtype", [None, "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(1), (1,2), (2,3,4), (5,6,7)])
def test_onnx_export_np_zeros(tmp_path, dtype, shape):
M = def_model(mx.np, 'zeros', shape=shape, dtype=dtype, dummy_input=True)
x = mx.np.array([1])
op_export_test('zeros', M, [x], tmp_path, dummy_input=True)
@pytest.mark.parametrize("dtype", [None, "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(1), (1,2), (2,3,4), (5,6,7)])
def test_onnx_export_np_ones(tmp_path, dtype, shape):
M = def_model(mx.np, 'ones', shape=shape, dtype=dtype, dummy_input=True)
x = mx.np.array([0])
op_export_test('ones', M, [x], tmp_path, dummy_input=True)
@pytest.mark.parametrize('dtype', [None, 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1), (1,2), (2,3,4), (5,6,7)])
def test_onnx_export_np_zeros_like(tmp_path, dtype, shape):
M = def_model(mx.np, 'zeros_like', dtype=dtype)
x = mx.np.random.uniform(0, 1, shape, dtype='float32')
op_export_test('zeros_like', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', [None, 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1), (1,2), (2,3,4), (5,6,7)])
def test_onnx_export_np_ones_like(tmp_path, dtype, shape):
M = def_model(mx.np, 'ones_like', dtype=dtype)
x = mx.np.random.uniform(0, 1, shape, dtype='float32')
op_export_test('ones_like', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', [None, 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1), (1,2), (2,3,4), (5,6,7)])
@pytest.mark.parametrize('fill_value', [0, 1, -1, 12.34])
def test_onnx_export_np_full_like(tmp_path, dtype, shape, fill_value):
M = def_model(mx.np, 'full_like', dtype=dtype, fill_value=fill_value)
x = mx.np.random.uniform(0, 1, shape, dtype='float32')
op_export_test('full_like', M, [x], tmp_path)
@pytest.mark.parametrize("dtype", ["float32", "float64"])
@pytest.mark.parametrize("axis", [None,0,1])
@pytest.mark.parametrize("start", [0, 0.5, 1])
@pytest.mark.parametrize("step", [0.01, 0.1, 0.5, 1])
@pytest.mark.parametrize("test_data", [ mx.np.random.uniform(0, 1, (10,20)), [[0,1,2,3,4,5],[4,5,6,7,8,9],[8,9,10,11,12,13]]])
def test_onnx_export_npx_arange_like(tmp_path, dtype, axis, start, step, test_data):
M = def_model(mx.npx, 'arange_like', axis=axis, start=start, step=step)
x = mx.np.array(test_data, dtype=dtype)
op_export_test('arange_like', M, [x], tmp_path)
@pytest.mark.parametrize("params", [[0, 2, 1], [0, 50, 0.25], [-100, 100, 0.5], [5, None, 1], [-5, None, -1]])
@pytest.mark.parametrize("dtype", ["float32", "float64", "int32", "int64"])
def test_onnx_export_np_arange(tmp_path, dtype, params):
start, stop, step = params[0], params[1], params[2]
if "int" in dtype:
start = int(start)
stop = int(stop) if stop != None else None
step = int(step)
if step == 0:
step = 1
M = def_model(mx.np, 'arange', dummy_input=True, start=start, stop=stop, step=step, dtype=dtype)
x = mx.np.array([1], dtype='float32')
op_export_test('arange', M, [x], tmp_path, dummy_input=True)
@pytest.mark.parametrize('dtype', ['float32'])
def test_onnx_export_npx_layer_norm(tmp_path, dtype):
x = mx.np.random.uniform(1, 2, (3, 4, 5), dtype=dtype)
axes = list(range(np.shape(np.shape(x))[0]))
axes.append(-1)
for axis in axes:
M = def_model(mx.npx, 'layer_norm', axis=axis)
gamma = mx.np.random.uniform(0, 1, [np.shape(x)[axis]], dtype=dtype)
beta = mx.np.random.uniform(0, 1, [np.shape(x)[axis]], dtype=dtype)
op_export_test('layer_norm', M, [x, gamma, beta], tmp_path)
@pytest.mark.skip(reason='broadcast_axis is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32'])
def test_onnx_export_broadcast_axis(tmp_path, dtype):
M1 = def_model('broadcast_axis', axis=(0, 2), size=(3, 4))
M2 = def_model('broadcast_axis', axis=(0, 2), size=(1, 5))
x1 = mx.nd.array([[[1], [2]]], dtype=dtype)
op_export_test('broadcast_axis_1', M1, [x1], tmp_path)
op_export_test('broadcast_axis_2', M2, [x1], tmp_path)
M3 = def_model('broadcast_axis', axis=(1, 4), size=(3, 5))
x2 = mx.nd.ones((1, 1, 3, 1, 1, 1), dtype=dtype)
op_export_test('broadcast_axis_3', M3, [x2], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
def test_onnx_export_npx_sequence_mask(tmp_path, dtype):
M1 = def_model(mx.npx, 'sequence_mask', use_sequence_length=True, axis=1, value=-5)
M2 = def_model(mx.npx, 'sequence_mask', use_sequence_length=True, axis=0, value=-99)
x = mx.np.array([[[[ 1., 2., 3., 3.5]],
[[ 4., 5., 6., 6.5]]],
[[[ 7., 8., 9., 9.5]],
[[ 10., 11., 12., 12.5]]],
[[[ 13., 14., 15., 15.5]],
[[ 16., 17., 18., 18.5]]]], dtype=dtype)
seq_len1 = mx.np.array([1, 2, 1], dtype=dtype)
seq_len2 = mx.np.array([1, 2], dtype=dtype)
op_export_test('sequence_mask_1', M1, [x, seq_len1], tmp_path)
op_export_test('sequence_mask_2', M2, [x, seq_len2], tmp_path)
@pytest.mark.skip(reason='This op will be adopted in MXNet 2.0 soon')
@pytest.mark.parametrize('dtype', ['float32'])
def test_onnx_export_contrib_interleaved_matmul_selfatt_qk(tmp_path, dtype):
M1 = def_model('contrib.interleaved_matmul_selfatt_qk', heads=3)
x1 = mx.nd.random.uniform(0, 1, (3, 3, 3*3*3), dtype=dtype)
op_export_test('contrib_interleaved_matmul_selfatt_qk_1', M1, [x1], tmp_path)
M2 = def_model('contrib.interleaved_matmul_selfatt_qk', heads=5)
x2 = mx.nd.random.uniform(0, 1, (7, 5, 4*5*6), dtype=dtype)
op_export_test('contrib_interleaved_matmul_selfatt_qk_2', M2, [x2], tmp_path)
@pytest.mark.skip(reason='This op will be adopted in MXNet 2.0 soon')
@pytest.mark.parametrize('dtype', ['float32'])
def test_onnx_export_contrib_interleaved_matmul_selfatt_valatt(tmp_path, dtype):
M = def_model('contrib.interleaved_matmul_selfatt_valatt', heads=6)
x = mx.nd.random.uniform(0, 1, (4, 5, 6*7*3), dtype=dtype)
att = mx.nd.random.uniform(0, 1, (5*6, 4, 4), dtype=dtype)
op_export_test('contrib_interleaved_matmul_selfatt_valatt', M, [x, att], tmp_path)
@pytest.mark.skip(reason='slice_axis is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32'])
def test_onnx_export_slice_axis(tmp_path, dtype):
x = mx.nd.array([[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.]], dtype=dtype)
M1 = def_model('slice_axis', axis=0, begin=1, end=3)
M2 = def_model('slice_axis', axis=0, begin=1, end=None)
M3 = def_model('slice_axis', axis=1, begin=-3, end=-1)
M4 = def_model('slice_axis', axis=-1, begin=-3, end=None)
op_export_test('slice_axis_1', M1, [x], tmp_path)
op_export_test('slice_axis_2', M2, [x], tmp_path)
op_export_test('slice_axis_3', M3, [x], tmp_path)
op_export_test('slice_axis_4', M4, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
def test_onnx_export_npx_reshape(tmp_path, dtype):
x = mx.np.ones((2, 3, 4, 5, 6), dtype=dtype)
M1 = def_model(mx.npx, 'reshape', newshape=(6, 1, 5, -1))
op_export_test('reshape', M1, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
def test_onnx_export_np_reshape(tmp_path, dtype):
x = mx.np.ones((2, 3, 4, 5, 6), dtype=dtype)
M1 = def_model(mx.np, 'reshape', newshape=(6, 1, 5, -1))
op_export_test('reshape', M1, [x], tmp_path)
@pytest.mark.skip(reason='Reshape is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
def test_onnx_export_reshape(tmp_path, dtype):
x = mx.np.ones((2, 3, 4, 5, 6), dtype=dtype)
M1 = def_model(mx.npx, 'reshape', newshape=(6, 1, 0, -1))
op_export_test('reshape_1', M1, [x], tmp_path)
M2 = def_model(mx.np, 'reshape', newshape=(3, -1, 0, 0), reverse=True)
op_export_test('reshape_2', M2, [x], tmp_path)
M3 = def_model(mx.np, 'reshape', newshape=(5, 1, 1, 1, 1, 0 -1, 0), reverse=True)
op_export_test('reshape_3', M3, [x], tmp_path)
M4 = def_model(mx.np, 'reshape', newshape=(-3, -1))
op_export_test('reshape_4', M4, [x], tmp_path)
@pytest.mark.skip(reason='Reshape is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
def test_onnx_export_reshape_special_cases(tmp_path, dtype):
x1 = mx.nd.ones((8, 9), dtype=dtype)
M1 = def_model('reshape', shape=(0, -4, 1, -1))
op_export_test('reshape_spec_1', M1, [x1], tmp_path)
x2 = mx.nd.ones((8, 9, 10), dtype=dtype)
M2 = def_model('reshape', shape=(0, -4, 3, -1, 10))
op_export_test('reshape_spec_2', M2, [x2], tmp_path)
M3 = def_model('reshape', shape=(-4, 2, -1, 10, 9))
op_export_test('reshape_spec_3', M3, [x2], tmp_path)
M4 = def_model('reshape', shape=(-3, 0))
op_export_test('reshape_spec_4', M4, [x2], tmp_path)
x3 = mx.nd.ones((1, 2, 3, 4, 5, 6), dtype=dtype)
M5 = def_model('reshape', shape=(0, 0, -3, -3))
op_export_test('reshape_spec_5', M5, [x3], tmp_path)
x4 = mx.nd.ones((5, 8, 6, 7), dtype=dtype)
M6 = def_model('reshape', shape=(0, -4, -1, 4, 0, 0))
op_export_test('reshape_spec_6', M6, [x4], tmp_path)
x5 = mx.nd.ones((2, 3, 4, 5, 6), dtype=dtype)
M7 = def_model('reshape', shape=(0, 0, -4, 2, 2, 0, 0))
op_export_test('reshape_spec_7', M7, [x5], tmp_path)
x6 = mx.nd.ones((8, 7, 6, 5), dtype=dtype)
M8 = def_model('reshape', shape=(-4, 1, -1, 0, 0, 0))
op_export_test('reshape_spec_8', M8, [x6], tmp_path)
x7 = mx.nd.ones((1000, 2, 3), dtype=dtype)
M9 = def_model('reshape', shape=(-4, 1, 1000, 0, 0))
op_export_test('reshape_spec_9', M9, [x7], tmp_path)
x8 = mx.nd.ones((3, 96, 5), dtype=dtype)
M10 = def_model('reshape', shape=(0, -4, 12, -1, 0))
op_export_test('reshape_spec_10', M10, [x8], tmp_path)
x9 = mx.nd.ones((3, 96, 5), dtype=dtype)
M11 = def_model('reshape', shape=(0, -4, 16, -1, 0))
op_export_test('reshape_spec_11', M11, [x9], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64'])
def test_onnx_export_npx_embedding(tmp_path, dtype):
x = mx.np.array([[ 1., 3.],
[ 0., 2.]], dtype=dtype)
y = mx.np.array([[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 10., 11., 12., 13., 14.],
[ 15., 16., 17., 18., 19.]], dtype=dtype)
M = def_model(mx.npx, 'embedding', input_dim=4, output_dim=5)
op_export_test('embedding', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('num_hidden', [1, 2, 7, 10, 20])
@pytest.mark.parametrize('no_bias', [True, False])
@pytest.mark.parametrize('flatten', [True, False])
def test_onnx_export_npx_fully_connected(tmp_path, dtype, num_hidden, no_bias, flatten):
M = def_model(mx.npx, 'fully_connected', num_hidden=num_hidden, no_bias=no_bias, flatten=flatten)
x = mx.np.random.uniform(-0.5, 0.5, (3, 4, 5))
if (flatten):
weight = mx.np.random.uniform(0, 1, (num_hidden, 4*5))
else:
weight = mx.np.random.uniform(0, 1, (num_hidden, 5))
args = [x, weight]
if not no_bias:
args.append(mx.np.random.uniform(0,1,(num_hidden,)))
op_export_test('fully_connected', M, args, tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float16'])
@pytest.mark.parametrize('shape', [(1,), (3,), (4, 5), (3, 4, 5)])
@pytest.mark.parametrize('act_type', ['elu', 'leaky', 'prelu', 'selu', 'gelu'])
def test_onnx_export_npx_leaky_relu(tmp_path, dtype, shape, act_type):
M = def_model(mx.npx, 'leaky_relu', act_type='leaky')
x = mx.np.random.uniform(-0.5, 0.5, shape, dtype=dtype)
op_export_test('leaky_relu', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'float16', 'int32', 'int64'])
def test_onnx_export_np_concatenate(tmp_path, dtype):
x = mx.np.array([[1,1],[2,2]], dtype=dtype)
y = mx.np.array([[3,3],[4,4],[5,5]], dtype=dtype)
z = mx.np.array([[6,6],[7,7],[8,8]], dtype=dtype)
M1 = def_model(mx.np, 'concatenate', axis=0)
M2 = def_model(mx.np, 'concatenate', axis=1)
M3 = def_model(mx.np, 'concatenate')
op_export_test('concatenate_1', M1, [(x, y, z)], tmp_path)
op_export_test('concatenate_2', M2, [(y, z)], tmp_path)
op_export_test('concatenate_3', M2, [(y, z)], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float16'])
@pytest.mark.parametrize('shape', [(1,), (3,), (4, 5), (3, 4, 5)])
@pytest.mark.parametrize('act_type', ['tanh', 'relu', 'sigmoid', 'softrelu', 'softsign'])
def test_onnx_export_npx_activation(tmp_path, dtype, shape, act_type):
M = def_model(mx.npx, 'activation', act_type=act_type)
x = mx.np.random.uniform(-0.5, 0.5, shape, dtype=dtype)
op_export_test('activation', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('axes', [None, [1,0,2]])
def test_onnx_export_np_transpose(tmp_path, dtype, axes):
if axes != None:
M = def_model(mx.np, 'transpose', axes=axes)
else:
M = def_model(mx.np, 'transpose')
x = mx.np.array([[[1,2],[3,4]],[[5,6],[7,8]]], dtype=dtype)
op_export_test('transpose', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('axis', [0, 1, 2])
def test_onnx_export_np_expand_dims(tmp_path, dtype, axis):
M = def_model(mx.np, 'expand_dims', axis=axis)
x = mx.np.random.uniform(0, 1, (2,3,4), dtype=dtype)
op_export_test('expand_dims', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
def test_onnx_export_np_add(tmp_path, dtype):
M = def_model(mx.np, 'add')
x = mx.np.array([[1,1,1],[1,1,1]], dtype=dtype)
y = mx.np.array([[0],[1]], dtype=dtype)
op_export_test('add', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
def test_onnx_export_np_minimum(tmp_path, dtype):
M = def_model(mx.np, 'minimum')
if 'int' in dtype:
x = mx.np.random.randint(0, 1000, (4, 5, 6), dtype=dtype)
y = mx.np.random.randint(0, 1000, (4, 5, 6), dtype=dtype)
else:
x = mx.np.random.uniform(0, 1000, (4, 5, 6), dtype=dtype)
y = mx.np.random.uniform(0, 1000, (4, 5, 6), dtype=dtype)
op_export_test('minimum', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
def test_onnx_export_np_maximum(tmp_path, dtype):
M = def_model(mx.np, 'maximum')
if 'int' in dtype:
x = mx.np.random.randint(0, 1000, (4, 5, 6), dtype=dtype)
y = mx.np.random.randint(0, 1000, (4, 5, 6), dtype=dtype)
else:
x = mx.np.random.uniform(0, 1000, (4, 5, 6), dtype=dtype)
y = mx.np.random.uniform(0, 1000, (4, 5, 6), dtype=dtype)
op_export_test('maximum', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('axis', [0, 1, 2, -1])
def test_onnx_export_npx_stack(tmp_path, dtype, axis):
M = def_model(mx.np, 'stack', axis=axis)
if 'int' in dtype:
x = mx.np.random.randint(0, 10*9, (3,4,5), dtype=dtype)
y = mx.np.random.randint(0, 10*9, (3,4,5), dtype=dtype)
else:
x = mx.np.random.normal(0, 10*9, (3,4,5), dtype=dtype)
y = mx.np.random.normal(0, 10*9, (3,4,5), dtype=dtype)
op_export_test('stack', M, [(x, y)], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (1, 2, 3, 2, 1)])
@pytest.mark.parametrize('p', [0, 0.1, 0.5, 1])
def test_onnx_export_npx_dropout(tmp_path, dtype, shape, p):
x = mx.np.random.uniform(-100, 100, size=shape).astype(dtype)
M = def_model(mx.npx, 'dropout', p=p)
op_export_test('dropuout', M, [x], tmp_path)
@pytest.mark.parametrize('src_dtype', ['float16', 'float32', 'float64'])
@pytest.mark.parametrize('dst_dtype', ['bool', 'float16', 'float32', 'float64', 'int32', 'int64', 'int8', 'uint8'])
@pytest.mark.parametrize('shape', [(2,3), (4,5,6)])
def test_onnx_export_npx_cast(tmp_path, src_dtype, dst_dtype, shape):
M = def_model(mx.npx, 'cast', dtype=dst_dtype)
x = mx.np.random.uniform(0, 1, size=shape, dtype=src_dtype)
op_export_test('cast', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('temperature', [None, .1, 1., 10.])
def test_onnx_export_softmax(tmp_path, dtype, temperature):
x = mx.np.random.uniform(0, 1, (4, 5, 6), dtype=dtype)
M1 = def_model(mx.npx, 'softmax')
op_export_test('softmax_1', M1, [x], tmp_path)
l2 = mx.np.random.uniform(0, 4, (5, 6)).astype('int32')
M2 = def_model(mx.npx, 'softmax', use_length=True, axis=0, temperature=temperature)
op_export_test('softmax_2', M2, [x, l2], tmp_path)
M3 = def_model(mx.npx, 'softmax', use_length=True, axis=-1, temperature=temperature)
# note that the axis==-1 case uses negative value masking + ONNX softmax
# when valid_len==0 the masked values will NOT be 0
l3 = mx.np.random.uniform(1, 6, (4, 5)).astype('int32')
op_export_test('softmax_3', M3, [x, l3], tmp_path)
M4 = def_model(mx.npx, 'softmax', use_length=True, axis=1, temperature=temperature)
l4 = mx.np.random.uniform(0, 5, (4, 6)).astype('int32')
op_export_test('softmax_4', M4, [x, l4], tmp_path)
@pytest.mark.skip(reason='reverse is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('axis', [0, 1, 2, 3])
def test_onnx_export_reverse(tmp_path, dtype, axis):
x = mx.np.arange(0, 120, dtype=dtype).reshape((2, 3, 4, 5))
M = def_model('reverse', axis=axis)
op_export_test('reverse', M, [x], tmp_path)
@pytest.mark.skip(reason='this version of repeat is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('axis', [None, 0, 1, 2, -1, -2, -3])
@pytest.mark.parametrize('repeats', [2, 1, 3])
def test_onnx_export_repeat(tmp_path, dtype, axis, repeats):
x = mx.np.arange(0, 27, dtype=dtype).reshape((3, 3, 3))
M = def_model(mx.np, 'repeat', axis=axis, repeats=repeats)
op_export_test('repeat', M, [x], tmp_path)
@pytest.mark.skip(reason='BilinearResize2D is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1, 3, 224, 224), (2, 2, 5, 8), (2, 4, 17, 23)])
@pytest.mark.parametrize('params', [{'height': 7, 'width': 13},
{'height': 10, 'width': 16},
{'height': 3, 'width': 5},
{'height': 2, 'width': 4},
{'scale_height': 3, 'scale_width': 2},
{'scale_height': 1.7, 'scale_width': 2.3},
{'scale_height': 0.5, 'scale_width': 0.6},
{'scale_height': 0.8, 'scale_width': 0.13},
{'scale_height': 2.5, 'scale_width': 0.5},
{'scale_height': 3, 'scale_width': 0.2},
])
def test_onnx_export_contrib_BilinearResize2D(tmp_path, dtype, shape, params):
x = mx.random.uniform(0, 1, shape)
M = def_model('contrib.BilinearResize2D', **params)
op_export_test('contrib_BilinearResize2D', M, [x], tmp_path)
@pytest.mark.parametrize('topk', [-1, 2, 3, 4])
@pytest.mark.parametrize('valid_thresh', [0.3, 0.4, 0.8])
@pytest.mark.parametrize('overlap_thresh', [0.4, 0.7, 1.0])
def test_onnx_export_npx_box_nms(tmp_path, topk, valid_thresh, overlap_thresh):
# Note that ONNX NMS op only supports float32
# Also note that onnxruntime's nms has slightly different implementation in handling
# overlaps and score ordering when certain boxes are suppressed than that of mxnet
# the following test tensors are manually tweaked to avoid such diferences
# The purpose of theses tests cases are to show that the high level conversion logic is
# laid out correctly
A = mx.np.array([[
[[[[0.5, 0.1, 0.1, 0.2, 0.2],
[0.4, 0.1, 0.1, 0.2, 0.2],
[0.7, 0.5, 0.5, 0.9, 0.9],
[0.8, 0.1, 0.9, 0.11, 0.91],
[0.001, 0.01, 0.01, 0.02, 0.02]]]],
[[[[0.5, 0.1, 0.1, 0.2, 0.2],
[0.4, 0.1, 0.1, 0.2, 0.2],
[0.7, 0.5, 0.5, 0.9, 0.9],
[0.8, 0.1, 0.9, 0.11, 0.91],
[0.001, 0.01, 0.01, 0.02, 0.02]]]],
[[[[0.4, 0.1, 0.1, 0.2, 0.2],
[0.3, 0.1, 0.1, 0.2, 0.2],
[0.7, 0.5, 0.5, 0.9, 0.9],
[0.8, 0.1, 0.9, 0.11, 0.91],
[0.001, 0.01, 0.01, 0.02, 0.02]]]],
]])
M = def_model(mx.npx, 'box_nms', coord_start=1, force_suppress=True,
overlap_thresh=overlap_thresh, valid_thresh=valid_thresh, score_index=0,
topk=topk, in_format='corner', out_format='corner')
op_export_test('box_nms_manual_coner', M, [A], tmp_path)
B = mx.np.array([
[[[[0.7, 0.5, 0.5, 0.2, 0.2],
[0.6, 0.48, 0.48, 0.2, 0.2],
[0.8, 0.76, 0.76, 0.2, 0.2],
[0.9, 0.7, 0.7, 0.2, 0.2],
[0.001, 0.5, 0.1, 0.02, 0.02]]]],
[[[[0.5, 0.2, 0.2, 0.2, 0.2],
[0.6, 0.4, 0.4, 0.21, 0.21],
[0.7, 0.5, 0.5, 0.9, 0.9],
[0.8, 0.1, 0.9, 0.01, 0.01],
[0.001, 0.6, 0.1, 0.02, 0.02]]]],
])
M = def_model(mx.npx, 'box_nms', coord_start=1, force_suppress=True,
overlap_thresh=overlap_thresh, valid_thresh=valid_thresh, score_index=0,
topk=topk, in_format='center', out_format='center')
op_export_test('box_nms_manual_center', M, [B], tmp_path)
@pytest.mark.skip(reason='greater_scalar is deprecated in MXNet 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("scalar", [0., 0.1, 0.5, 1., 5, 555.])
def test_onnx_export_greater_scalar(tmp_path, dtype, scalar):
if 'int' in dtype:
scalar = int(scalar)
x = mx.np.arange(0, 12, dtype=dtype).reshape((3, 4))
else:
x = mx.np.random.uniform(0, 9999, (5,10), dtype=dtype)
M = def_model(mx.np, 'greater', scalar=scalar)
op_export_test('greater', M, [x], tmp_path)
@pytest.mark.skip(reason='lesser_scalar is deprecated in MXNet 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("scalar", [0., 0.1, 0.5, 1., 5, 555.])
def test_onnx_export_lesser_scalar(tmp_path, dtype, scalar):
if 'int' in dtype:
scalar = int(scalar)
x = mx.nd.arange(0, 12, dtype=dtype).reshape((3, 4))
else:
x = mx.random.uniform(0, 9999, (5,10), dtype=dtype)
M = def_model('_internal._lesser_scalar', scalar=scalar)
op_export_test('_internal._lesser_scalar', M, [x], tmp_path)
@pytest.mark.skip(reason='equal_scalar is deprecated in MXNet 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("scalar", [0., 0.1, 0.5, 1., 5, 555.])
def test_onnx_export_equal_scalar(tmp_path, dtype, scalar):
if 'int' in dtype:
scalar = int(scalar)
x = mx.nd.arange(0, 12, dtype=dtype).reshape((3, 4))
else:
x = mx.random.uniform(0, 9999, (5,10), dtype=dtype)
M = def_model('_internal._equal_scalar', scalar=scalar)
op_export_test('_internal._equal_scalar', M, [x], tmp_path)
@pytest.mark.parametrize('op', ['equal', 'not_equal', 'greater', 'less', 'greater_equal', 'less_equal'])
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(2,3), (4,5,6)])
def test_onnx_export_np_comparison(tmp_path, op, dtype, shape):
M = def_model(mx.np, op)
x = mx.np.random.uniform(-100, 100, shape).astype(dtype)
y = mx.np.random.uniform(-100, 100, shape[1:]).astype(dtype)
op_export_test(op, M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(5,), (3,3), (10,2), (20,30,40)])
def test_onnx_export_np_where(tmp_path, dtype, shape):
M = def_model(mx.np, 'where')
x = mx.np.zeros(shape, dtype=dtype)
y = mx.np.ones(shape, dtype=dtype)
cond = mx.np.random.randint(low=0, high=1, size=shape, dtype='int32')
op_export_test('where', M, [cond, x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int64'])
@pytest.mark.parametrize('axis', [0, 2, -1, -2, -3])
@pytest.mark.parametrize('is_ascend', [True, False, 0, 1, None])
@pytest.mark.parametrize('k', [1, 4])
@pytest.mark.parametrize('dtype_i', ['float32', 'int32', 'int64'])
@pytest.mark.parametrize('ret_typ', ['value', 'indices', 'both'])
def test_onnx_export_npx_topk(tmp_path, dtype, axis, is_ascend, k, dtype_i, ret_typ):
A = mx.np.random.uniform(0, 100, (4, 5, 6)).astype(dtype)
kwargs = {}
if is_ascend is not None:
kwargs['is_ascend'] = is_ascend
M = def_model(mx.npx, 'topk', axis=axis, k=k, dtype=dtype_i, ret_typ=ret_typ, **kwargs)
op_export_test('topk', M, [A], tmp_path)
def test_onnx_link_op_with_multiple_outputs(tmp_path):
A = mx.np.random.uniform(0, 100, (4, 5, 6))
class Model1(HybridBlock):
def __init__(self, **kwargs):
super(Model1, self).__init__(**kwargs)
def forward(self, x):
out1, out2 = mx.npx.topk(x, k=3, ret_typ='both')
out11 = out1 * 2
out22 = out2 + 3
return out11, out22
op_export_test('link_op_with_multiple_outputs_case1', Model1, [A], tmp_path)
class Model2(HybridBlock):
def __init__(self, **kwargs):
super(Model2, self).__init__(**kwargs)
def forward(self, x):
out_ = mx.npx.topk(x, k=3, ret_typ='value')
out = out_ * 3
return out
op_export_test('link_op_with_multiple_outputs_case2', Model2, [A], tmp_path)
class Model3(HybridBlock):
def __init__(self, **kwargs):
super(Model3, self).__init__(**kwargs)
def forward(self, x):
out_ = mx.npx.topk(x, k=3, ret_typ='indices')
out = out_ * 3
return out
op_export_test('link_op_with_multiple_outputs_case3', Model3, [A], tmp_path)
@pytest.mark.skip(reason='maximum_scalar is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (1, 4, 1, 7)])
def test_onnx_maximum_scalar(tmp_path, dtype, shape):
x = mx.random.uniform(0, 10, shape).astype(dtype)
M = def_model('maximum', right=5)
op_export_test('_maximum_scalar', M, [x], tmp_path)
@pytest.mark.skip(reason='minimum_scalar is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (1, 4, 1, 7)])
def test_onnx_minimum_scalar(tmp_path, dtype, shape):
x = mx.random.uniform(0, 10, shape).astype(dtype)
M = def_model('minimum', right=5)
op_export_test('_minimum_scalar', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('fmt', ['corner', 'center'])
@pytest.mark.parametrize('clip', [-1., 0., .5, 5.])
def test_onnx_export_npx_box_decode(tmp_path, dtype, fmt, clip):
# ensure data[0] < data[2] and data[1] < data[3] for corner format
mul = mx.np.array([-1, -1, 1, 1], dtype=dtype)
data = mx.np.random.uniform(0, 1, (2, 3, 4), dtype=dtype) * mul
anchors = mx.np.random.uniform(0, 1, (1, 3, 4), dtype=dtype) * mul
M1 = def_model(mx.npx, 'box_decode', format=fmt, clip=clip)
op_export_test('contrib_box_decode', M1, [data, anchors], tmp_path)
M2 = def_model(mx.npx, 'box_decode', format=fmt, clip=clip, std0=0.3, std1=1.4, std2=0.5, std3=1.6)
op_export_test('contrib_box_decode', M1, [data, anchors], tmp_path)
@pytest.mark.skip(reason='AdaptiveAvgPooling2D is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
def test_onnx_export_contrib_AdaptiveAvgPooling2D(tmp_path, dtype):
x = mx.nd.random.uniform(0, 1, (1, 2, 3, 4), dtype=dtype)
M1 = def_model('contrib.AdaptiveAvgPooling2D')
op_export_test('contrib_AdaptiveAvgPooling2D', M1, [x], tmp_path)
M2 = def_model('contrib.AdaptiveAvgPooling2D', output_size=1)
op_export_test('contrib_AdaptiveAvgPooling2D', M2, [x], tmp_path)
M3 = def_model('contrib.AdaptiveAvgPooling2D', output_size=[1])
op_export_test('contrib_AdaptiveAvgPooling2D', M3, [x], tmp_path)
M4 = def_model('contrib.AdaptiveAvgPooling2D', output_size=[1,1])
op_export_test('contrib_AdaptiveAvgPooling2D', M4, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64'])
@pytest.mark.parametrize('shapes', [((3, 3, 3), (1, 3)), ((4, 5, 6, 7), (6, 7))])
def test_onnx_export_np_mod(tmp_path, dtype, shapes):
A = mx.np.random.uniform(-300, 300, shapes[0]).astype(dtype)
B = mx.np.random.uniform(-30, 30, shapes[1]).astype(dtype)
# test when dividend is zero
B[-1] = 0
M = def_model(mx.np, 'mod')
op_export_test('mod', M, [A, B], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
def test_onnx_export_npx_reshape_like(tmp_path, dtype):
if 'int' in dtype:
x = mx.np.random.randint(0, 10, (2, 2, 3, 2), dtype=dtype)
y = mx.np.random.randint(0, 10, (1, 4, 3, 2), dtype=dtype)
else:
x = mx.np.random.normal(0, 10, (2, 2, 3, 2), dtype=dtype)
y = mx.np.random.normal(0, 10, (1, 4, 3, 2), dtype=dtype)
M1 = def_model(mx.npx, 'reshape_like')
op_export_test('reshape_like1', M1, [x, y], tmp_path)
M2 = def_model(mx.npx, 'reshape_like', lhs_begin=0, lhs_end=2, rhs_begin=1, rhs_end=2)
op_export_test('reshape_like2', M2, [x, y], tmp_path)
M3 = def_model(mx.npx, 'reshape_like', lhs_begin=-4, lhs_end=-2, rhs_begin=-3, rhs_end=-2)
op_export_test('reshape_like3', M3, [x, y], tmp_path)
M4 = def_model(mx.npx, 'reshape_like', lhs_begin=0, lhs_end=None, rhs_begin=1, rhs_end=None)
op_export_test('reshape_like4', M4, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
def test_onnx_export_npx_gather_nd(tmp_path, dtype):
# y[0] == dim(x)
x1 = mx.np.random.uniform(-100, 100, (4, 5, 6, 7)).astype(dtype)
y1 = mx.np.random.randint(-4, 4, (4, 4, 4)).astype(dtype)
M1 = def_model(mx.npx, 'gather_nd')
op_export_test('gather_nd1', M1, [x1, y1], tmp_path)
# y[0] < dim(x)
x2 = mx.np.random.uniform(-100, 100, (4, 5, 6, 7)).astype(dtype)
y2 = mx.np.random.randint(-4, 4, (2,3,4)).astype(dtype)
M2 = def_model(mx.npx, 'gather_nd')
op_export_test('gather_nd2', M2, [x2, y2], tmp_path)
@pytest.mark.skip(reason='UpSampling is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5, 6), (1, 1, 1, 1)])
@pytest.mark.parametrize('scale', [1, 2, 3])
def test_onnx_export_upsampling(tmp_path, dtype, shape, scale):
A = mx.random.uniform(0, 1, shape).astype(dtype)
M = def_model('UpSampling', scale=scale, sample_type='nearest', num_args=1)
op_export_test('UpSampling', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('params', [((4, 5, 6), (0, 2)), ((4, 5, 6), (0, 1)),
((1, 2, 3, 4, 1), (0, 4)),
((4, 5, 1, 6), (0, 2))])
def test_onnx_export_np_swapaxes(tmp_path, dtype, params):
shape = params[0]
dim1, dim2 = params[1]
x = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.np, 'swapaxes', axis1=dim1, axis2=dim2)
op_export_test('swapaxes', M, [x], tmp_path)
@pytest.mark.skip(reason='slice_like is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('axes', [None, (0, 1, 2), (-2, -3), (-2, 0)])
def test_onnx_export_slice_like(tmp_path, dtype, axes):
x = mx.nd.random.uniform(0, 1, (4, 5, 6, 7)).astype(dtype)
if axes is None:
M = def_model('slice_like')
y = mx.nd.zeros((2, 3, 4, 5), dtype=dtype)
op_export_test('slice_like', M, [x, y], tmp_path)
else:
M = def_model('slice_like', axes=axes)
y1 = mx.nd.zeros((2, 3, 4), dtype=dtype)
y2 = mx.nd.zeros((2, 3, 4, 5), dtype=dtype)
y3 = mx.nd.zeros((2, 3, 4, 5, 6), dtype=dtype)
op_export_test('slice_like_1', M, [x, y1], tmp_path)
op_export_test('slice_like_2', M, [x, y2], tmp_path)
op_export_test('slice_like_3', M, [x, y3], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64'])
@pytest.mark.parametrize('axis', [None, 0, 2, -1])
@pytest.mark.parametrize('num_outputs', [2, 5])
def test_onnx_export_npx_slice_channel(tmp_path, dtype, axis, num_outputs):
x = mx.np.zeros((10,20,30,40), dtype=dtype)
if axis is None:
M = def_model(mx.npx, 'slice_channel', num_outputs=num_outputs)
else:
M = def_model(mx.npx, 'slice_channel', axis=axis, num_outputs=num_outputs)
op_export_test('slice_channel', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('lhs_axes', [[1, 3], [3, 1], [-2, -4], [-4, -2]])
@pytest.mark.parametrize('rhs_axes', [[1, 3], [3, 1], [-2, -4], [-4, -2]])
def test_onnx_export_npx_broadcast_like(tmp_path, dtype, lhs_axes, rhs_axes):
x = mx.np.random.normal(0, 10, (2, 1, 1, 1, 6)).astype(dtype)
y = mx.np.random.normal(0, 10, (2, 3, 4, 5, 6)).astype(dtype)
M1 = def_model(mx.npx, 'broadcast_like')
op_export_test('broadcast_like1', M1, [x, y], tmp_path)
M2 = def_model(mx.npx, 'broadcast_like', lhs_axes=lhs_axes, rhs_axes=rhs_axes)
op_export_test('broadcast_like2', M2, [x, y], tmp_path)
@pytest.mark.skip(reason='ROIAlign is deprecated in MXNet 2.0')
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('pooled_size', [(1, 1), (3, 3), (14, 14), (5, 7)])
@pytest.mark.parametrize('spatial_scale', [1, 0.5, 0.0625])
@pytest.mark.parametrize('spatial_ratio', [1, 2, 3, 5])
def test_onnx_export_contrib_ROIAlign(tmp_path, dtype, pooled_size, spatial_scale, spatial_ratio):
data = mx.random.uniform(0, 1, (5, 3, 512, 512)).astype(dtype)
rois = mx.nd.array([[-1, 0, 0, 0, 0],
[0, 0, 0, 63, 63],
[1, 34, 52, 25, 85],
[2, 50, 50, 100, 100],
[3, 0, 0, 127, 127],
[4, 12, 84, 22, 94],
[0, 0, 0, 1, 1]]).astype(dtype)
M = def_model('contrib.ROIAlign', pooled_size=pooled_size, spatial_scale=spatial_scale,
sample_ratio=spatial_ratio)
# according to https://mxnet.apache.org/versions/1.7.0/api/python/docs/api/contrib/symbol/index.html#mxnet.contrib.symbol.ROIAlign
# the returned value for when batch_id < 0 should be all 0's
# however mxnet 1.8 does always behave this way so we set the first roi to 0's manually
def mx_map(x):
x[0] = 0
return x
op_export_test('_contrib_ROIAlign', M, [data, rois], tmp_path, mx_map=mx_map)
@pytest.mark.skip(reason='TODO: the behavior of this op has changed in MXNet 2.0. New conversion function needed')
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('transpose_a', [True, False])
@pytest.mark.parametrize('transpose_b', [True, False])
def test_onnx_export_batch_dot(tmp_path, dtype, transpose_a, transpose_b):
x1 = mx.np.random.normal(0, 10, (2, 3, 4, 5, 6), dtype=dtype)
y1 = mx.np.random.normal(0, 10, (2, 3, 4, 6, 5), dtype=dtype)
M1 = def_model(mx.npx, 'batch_dot')
op_export_test('batch_dot1', M1, [x1, y1], tmp_path)
x2 = mx.np.random.normal(0, 10, (2, 3, 4, 5, 5), dtype=dtype)
y2 = mx.np.random.normal(0, 10, (2, 3, 4, 5, 5), dtype=dtype)
M2 = def_model(mx.npx, 'batch_dot', transpose_a=transpose_a, transpose_b=transpose_b)
op_export_test('batch_dot2', M2, [x2, y2], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 1, 60, 60)])
@pytest.mark.parametrize('count_include_pad', [True, False])
@pytest.mark.parametrize('pooling_convention', ['full', 'valid'])
@pytest.mark.parametrize('kernel', [(3, 3), (4, 5), (14, 14)])
@pytest.mark.parametrize('stride', [None, (1, 1), (2, 2), (3, 4), (4, 5)])
@pytest.mark.parametrize('pad', [None, (1, 1), (3, 4), (4, 5)])
def test_onnx_export_npx_pooling_avg(tmp_path, dtype, shape, count_include_pad, pooling_convention,
kernel, stride, pad):
# mxnet and onnxruntime has different implementation of count_include_pad on the left column
# and bottom row
if count_include_pad == True:
return
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', count_include_pad=count_include_pad, pool_type='avg',
pooling_convention=pooling_convention, layout='NCHW', **kwargs)
# Note here we use np.nan_to_num to map the onnx output because onnxruntime AveragePool will
# output NaN in some edge cases where mxnet outputs 0
op_export_test('pooling_avg', M, [x], tmp_path, onnx_map=np.nan_to_num)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 16, 16, 16), (1, 1, 10, 18, 18)])
@pytest.mark.parametrize('count_include_pad', [True, False])
@pytest.mark.parametrize('pooling_convention', ['full', 'valid'])
@pytest.mark.parametrize('kernel', [(1, 1, 1), (3, 3, 3), (1, 7, 7)])
@pytest.mark.parametrize('stride', [None, (1, 1, 1), (1, 2, 3)])
@pytest.mark.parametrize('pad', [None, (0, 1, 1), (1, 2, 3)])
def test_onnx_export_npx_pooling_avg_3d(tmp_path, dtype, shape, count_include_pad, pooling_convention,
kernel, stride, pad):
# mxnet and onnxruntime has different implementation of count_include_pad on the left column
# and bottom row
if count_include_pad == True:
return
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1] or pad[2] >= kernel[2]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', count_include_pad=count_include_pad, pool_type='avg',
pooling_convention=pooling_convention, layout='NCDHW', **kwargs)
# Note here we use np.nan_to_num to map the onnx output because onnxruntime AveragePool will
# output NaN in some edge cases where mxnet outputs 0
def mx_nan_to_num(a):
return np.nan_to_num(a.asnumpy())
op_export_test('pooling_avg_3d', M, [x], tmp_path, onnx_map=np.nan_to_num, mx_map=mx_nan_to_num)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 1, 60, 60)])
@pytest.mark.parametrize('pooling_convention', ['full', 'valid'])
@pytest.mark.parametrize('kernel', [(3, 3), (4, 5), (14, 14)])
@pytest.mark.parametrize('stride', [None, (1, 1), (2, 2), (3, 4), (4, 5)])
@pytest.mark.parametrize('pad', [None, (1, 1), (3, 4), (4, 5)])
def test_onnx_export_npx_pooling_max(tmp_path, dtype, shape, pooling_convention, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', pool_type='max', pooling_convention=pooling_convention,
layout='NCHW', **kwargs)
op_export_test('pooling_max', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 16, 16, 16), (1, 1, 10, 18, 18)])
@pytest.mark.parametrize('pooling_convention', ['full', 'valid'])
@pytest.mark.parametrize('kernel', [(1, 1, 1), (3, 3, 3), (1, 7, 7)])
@pytest.mark.parametrize('stride', [None, (1, 1, 1), (1, 2, 3)])
@pytest.mark.parametrize('pad', [None, (0, 1, 1), (1, 2, 3)])
def test_onnx_export_npx_pooling_max_3d(tmp_path, dtype, shape, pooling_convention, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1] or pad[2] >= kernel[2]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', pool_type='max', pooling_convention=pooling_convention,
layout='NCDHW', **kwargs)
op_export_test('pooling_max_3d', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 1, 60, 60)])
@pytest.mark.parametrize('p_value', [1, 2])
@pytest.mark.parametrize('kernel', [(3, 3), (4, 5), (14, 14)])
@pytest.mark.parametrize('stride', [None, (1, 1), (2, 2), (3, 4), (4, 5)])
@pytest.mark.parametrize('pad', [None, (1, 1), (3, 4), (4, 5)])
def test_onnx_export_npx_pooling_lp(tmp_path, dtype, shape, p_value, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', pool_type='lp', pooling_convention='valid',
p_value=p_value, layout='NCHW', **kwargs)
op_export_test('pooling_lp', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 16, 16, 16), (1, 1, 10, 18, 18)])
@pytest.mark.parametrize('p_value', [1, 2])
@pytest.mark.parametrize('kernel', [(1, 1, 1), (3, 3, 3), (1, 7, 7)])
@pytest.mark.parametrize('stride', [None, (1, 1, 1), (1, 2, 3)])
@pytest.mark.parametrize('pad', [None, (0, 1, 1), (1, 2, 3)])
def test_onnx_export_npx_pooling_lp_3d(tmp_path, dtype, shape, p_value, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1] or pad[2] >= kernel[2]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
M = def_model(mx.npx, 'pooling', pool_type='lp', pooling_convention='valid',
p_value=p_value, layout='NCDHW', **kwargs)
op_export_test('pooling_lp_3d', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 1, 60, 60)])
@pytest.mark.parametrize('pool_type', ['avg', 'max', 'lp'])
@pytest.mark.parametrize('p_value', [1, 2])
@pytest.mark.parametrize('kernel', [(3, 3), (14, 14)])
@pytest.mark.parametrize('stride', [None, (3, 4)])
@pytest.mark.parametrize('pad', [None, (3, 4)])
def test_onnx_export_npx_pooling_global(tmp_path, dtype, shape, pool_type, p_value, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
# kernel, stride, and pad should have no effect on the results
M = def_model(mx.npx, 'pooling', global_pool=True, pool_type=pool_type, pooling_convention='valid',
p_value=p_value, layout='NCHW', **kwargs)
op_export_test('pooling_global', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 16, 16, 16), (1, 1, 10, 18, 18)])
@pytest.mark.parametrize('pool_type', ['avg', 'max', 'lp'])
@pytest.mark.parametrize('p_value', [1, 2])
@pytest.mark.parametrize('kernel', [(1, 1, 1), (3, 3, 3)])
@pytest.mark.parametrize('stride', [None, (1, 1, 1)])
@pytest.mark.parametrize('pad', [None, (0, 1, 1)])
def test_onnx_export_npx_pooling_global_3d(tmp_path, dtype, shape, pool_type, p_value, kernel, stride, pad):
# onnxruntime requires that pad is smaller than kernel
if pad and (pad[0] >= kernel[0] or pad[1] >= kernel[1] or pad[2] >= kernel[2]):
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
# kernel, stride, and pad should have no effect on the results
M = def_model(mx.npx, 'pooling', global_pool=True, pool_type=pool_type, pooling_convention='valid',
p_value=p_value, layout='NCDHW', **kwargs)
op_export_test('pooling_global_3d', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
def test_onnx_export_np_log2(tmp_path, dtype):
x = mx.np.random.normal(0, 10, (2, 3, 4, 5)).astype(dtype)
M = def_model(mx.np, 'log2')
op_export_test('log2', M, [x], tmp_path)
@pytest.mark.skip(reason='broadcast_mul is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
def test_onnx_export_broadcast_mul(tmp_path, dtype):
M = def_model('broadcast_mul')
x = mx.nd.array([[1,2,3],[4,5,6]], dtype=dtype)
y = mx.nd.array([[0],[3]], dtype=dtype)
op_export_test('broadcast_mul', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 6, 60, 60)])
@pytest.mark.parametrize('num_filter', [2, 4, 32])
@pytest.mark.parametrize('num_group', [1, 2])
@pytest.mark.parametrize('no_bias', [True, False])
@pytest.mark.parametrize('kernel', [(3, 3), (4, 5), (14, 14)])
@pytest.mark.parametrize('stride', [None, (1, 1), (2, 2), (3, 4), (4, 5)])
@pytest.mark.parametrize('pad', [None, (1, 1), (3, 4), (4, 5)])
@pytest.mark.parametrize('dilate', [None, (1, 1)])
def test_onnx_export_npx_convolution(tmp_path, dtype, shape, num_filter, num_group, no_bias,
kernel, stride, pad, dilate):
if shape[1] % num_group:
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
w_shape = (num_filter,) + (shape[1] // num_group,) + kernel
w = mx.np.random.uniform(0, 1, w_shape, dtype=dtype)
b_shape = (num_filter)
b = mx.np.random.uniform(0, 1, b_shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
if dilate:
kwargs['dilate'] = dilate
M = def_model(mx.npx, 'convolution', num_filter=num_filter, num_group=num_group, no_bias=no_bias,
layout='NCHW', **kwargs)
inputs = [x, w] if no_bias else [x, w, b]
op_export_test('convolution', M, inputs, tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 4, 16, 16, 16), (1, 3, 10, 18, 18)])
@pytest.mark.parametrize('num_filter', [2, 4, 32])
@pytest.mark.parametrize('num_group', [1, 2])
@pytest.mark.parametrize('no_bias', [True, False])
@pytest.mark.parametrize('kernel', [(3, 3, 3), (1, 1, 1), (1, 7, 7)])
@pytest.mark.parametrize('stride', [None, (1, 1, 1), (1, 2, 3)])
@pytest.mark.parametrize('pad', [None, (0, 1, 1), (1, 2, 3)])
@pytest.mark.parametrize('dilate', [None, [2, 2, 2]])
def test_onnx_export_npx_convolution_3D(tmp_path, dtype, shape, num_filter, num_group, no_bias,
kernel, stride, pad, dilate):
if shape[1] % num_group:
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
w_shape = (num_filter,) + (shape[1] // num_group,) + kernel
w = mx.np.random.uniform(0, 1, w_shape, dtype=dtype)
b_shape = (num_filter)
b = mx.np.random.uniform(0, 1, b_shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
if dilate:
kwargs['dilate'] = dilate
M = def_model(mx.npx, 'convolution', num_filter=num_filter, num_group=num_group, no_bias=no_bias,
layout='NCDHW', **kwargs)
inputs = [x, w] if no_bias else [x, w, b]
op_export_test('convolution_3d', M, inputs, tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('num_outputs', [1, 3, 9])
@pytest.mark.parametrize('axis', [1, 2, -1, -2])
@pytest.mark.parametrize('squeeze_axis', [True, False, 0, 1])
def test_onnx_export_npx_slice_channel(tmp_path, dtype, num_outputs, axis, squeeze_axis):
shape = (3, 9, 18)
if squeeze_axis and shape[axis] != num_outputs:
return
M = def_model(mx.npx, 'slice_channel', num_outputs=num_outputs, axis=axis, squeeze_axis=squeeze_axis)
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
op_export_test('slice_channel', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('momentum', [0.9, 0.5, 0.1])
def test_onnx_export_npx_batchnorm(tmp_path, dtype, momentum):
x = mx.np.random.normal(0, 10, (2, 3, 4, 5)).astype(dtype)
gamma = mx.np.random.normal(0, 10, (3)).astype(dtype)
beta = mx.np.random.normal(0, 10, (3)).astype(dtype)
moving_mean = mx.np.random.normal(0, 10, (3)).astype(dtype)
moving_var = mx.np.abs(mx.np.random.normal(0, 10, (3))).astype(dtype)
M = def_model(mx.npx, 'batch_norm', eps=1e-5, momentum=momentum, fix_gamma=False, use_global_stats=False)
op_export_test('batch_norm', M, [x, gamma, beta, moving_mean, moving_var], tmp_path)
@pytest.mark.skip(reason='TODO argsort changed spec in 2.0')
# onnxruntime does not seem to support float64 and int32
@pytest.mark.parametrize('dtype', ['float32', 'int64'])
@pytest.mark.parametrize('axis', [0, 2, -1, -2, -3])
@pytest.mark.parametrize('is_ascend', [True, False, 0, 1, None])
@pytest.mark.parametrize('dtype_i', ['float32', 'int32', 'int64'])
def test_onnx_export_argsort(tmp_path, dtype, axis, is_ascend, dtype_i):
A = mx.np.random.uniform(0, 100, (4, 5, 6)).astype(dtype)
kwargs = {}
if is_ascend is not None:
kwargs['is_ascend'] = is_ascend
M = def_model(mx.np, 'argsort', axis=axis, dtype=dtype_i, **kwargs)
op_export_test('argsort', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('reps', [(2, 3), (2, ), (2, 3, 4)])
def test_onnx_export_np_tile(tmp_path, dtype, reps):
x = mx.np.random.normal(0, 100, (5, 6)).astype(dtype)
M = def_model(mx.np, 'tile', reps=reps)
op_export_test('tile', M, [x], tmp_path)
@pytest.mark.skip(reason='TODO take changed spec in 2.0')
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('axis', [-3, -2, -1, 0, 1, 2])
@pytest.mark.parametrize('mode', ['clip', 'wrap'])
def test_onnx_export_take(tmp_path, dtype, axis, mode):
x = mx.np.random.normal(0, 10, (3, 4, 5)).astype(dtype)
y = mx.np.random.randint(-100, 100, (6, 7)).astype(dtype)
M1 = def_model(mx.np, 'take')
op_export_test('take1', M1, [x, y], tmp_path)
M2 = def_model(mx.np, 'take', axis=axis, mode=mode)
op_export_test('take2', M2, [x, y], tmp_path)
@pytest.mark.skip(reason='TODO take changed spec in 2.0')
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('axis', [-3, -2, -1, 0, 1, 2])
def test_onnx_export_take_raise(tmp_path, dtype, axis):
x = mx.nd.random.normal(0, 10, (3, 4, 5)).astype(dtype)
y = mx.random.randint(0, 3, (6, 7)).astype(dtype)
M = def_model('take', axis=axis, mode='raise')
op_export_test('take', M, [x, y], tmp_path)
# onnxruntime currently does not support int32
@pytest.mark.parametrize("dtype", ["float16", "float32", "int64"])
@pytest.mark.parametrize("depth", [1, 3, 5, 10])
@pytest.mark.parametrize("shape", [(1,1), (1,5), (5,5), (3,4,5)])
def test_onnx_export_npx_one_hot(tmp_path, dtype, depth, shape):
M = def_model(mx.npx, 'one_hot', depth=depth, dtype=dtype)
x = mx.np.random.randint(0, 10, shape).astype('int64')
op_export_test('one_hot', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['int32', 'int64', 'float16', 'float32', 'float64'])
@pytest.mark.parametrize('params', [((6, 5, 4), [1, 2, 4, 5, 6]),
((7, 3, 5), [1, 7, 4]),
((3, 2, 1), [1, 2])])
def test_onnx_export_npx_sequence_reverse(tmp_path, dtype, params):
x = mx.np.random.uniform(0, 10, params[0]).astype(dtype)
M1 = def_model(mx.npx, 'sequence_reverse')
op_export_test('SequenceReverse1', M1, [x], tmp_path)
seq_len = mx.np.array(params[1])
M1 = def_model(mx.npx, 'sequence_reverse', use_sequence_length=True)
op_export_test('SequenceReverse1', M1, [x, seq_len], tmp_path)
@pytest.mark.skip(reason='TODO rnn changeed spec in 2.0')
@pytest.mark.parametrize('mode', ['lstm', 'gru', 'rnn_tanh', 'rnn_relu'])
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('state_size', [16, 32])
@pytest.mark.parametrize('input_size', [16, 32, 64])
@pytest.mark.parametrize('num_layers', [1, 2])
@pytest.mark.parametrize('batch_size', [1, 2, 4])
@pytest.mark.parametrize('seq_length', [16])
@pytest.mark.parametrize('bidirectional', [True, False])
def test_onnx_export_RNN(tmp_path, mode, dtype, state_size, input_size, num_layers, batch_size, seq_length, bidirectional):
# TODO: The current implementation fails assertion checks for large parm/state_size.
# for num_layers >= 2, input_size must equal to state_size
if num_layers >= 2 and input_size != state_size:
return
# Currently only bidirectional supports lstm with num_layers = 1
if bidirectional and (mode != 'lstm' or num_layers != 1):
return
b = 1
if bidirectional:
b = 2
factor = 1
if mode == 'gru':
factor = 3
elif mode == 'lstm':
factor = 4
M = def_model(mx.npx, 'rnn', mode=mode, state_size=state_size, state_outputs=True, num_layers=num_layers, p=0, bidirectional=bidirectional)
x = mx.np.random.normal(0, 10, (seq_length, batch_size, input_size)).astype(dtype)
param = mx.np.random.normal(0, 1, [b*num_layers*factor*state_size*input_size +
b*num_layers*factor*state_size*state_size +
b*num_layers*2*factor*state_size]).astype(dtype)
state = mx.np.random.uniform(-1, 1, [b*num_layers, batch_size, state_size]).astype(dtype)
if mode == 'lstm':
cell = mx.np.random.uniform(-1, 1, [b*num_layers, batch_size, state_size]).astype(dtype)
op_export_test('rnn', M, [x, param, state, cell], tmp_path)
elif mode == 'rnn_relu':
# set large atol as relu can outputs big numbers
op_export_test('rnn', M, [x, param, state], tmp_path, atol=1e20)
else:
op_export_test('rnn', M, [x, param, state], tmp_path, atol=1e-2)
@pytest.mark.skip(reason='contrib_div_sqrt_dim is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
def test_onnx_export_contrib_div_sqrt_dim(tmp_path, dtype, shape):
A = mx.nd.random.uniform(-100, 100, shape).astype(dtype)
M = def_model('contrib.div_sqrt_dim')
op_export_test('contrib_div_sqrt_dim', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
@pytest.mark.parametrize('operator', ['sin', 'cos', 'tan', 'tanh', 'arcsin', 'arccos', 'arctan',
'exp', 'log', 'ceil', 'floor'])#'sigmoid', 'relu', 'exp', 'identity'])
def test_onnx_export_np_ufunc(tmp_path, dtype, shape, operator):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.np, operator)
op_export_test('np_ufunc', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
@pytest.mark.parametrize('operator', ['sigmoid', 'relu'])
def test_onnx_export_npx_ufunc(tmp_path, dtype, shape, operator):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.npx, operator)
op_export_test('npx_ufunc', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 64, 64), (2, 6, 60, 60)])
@pytest.mark.parametrize('num_filter', [4, 16, 256])
@pytest.mark.parametrize('num_group', [1, 2])
@pytest.mark.parametrize('no_bias', [False, True])
@pytest.mark.parametrize('kernel', [(2, 2), (3, 4)])
@pytest.mark.parametrize('stride', [(1, 1), (2, 2)])
@pytest.mark.parametrize('pad', [None, (0, 0), (1, 1)])
@pytest.mark.parametrize('dilate', [None, (1, 1)])
@pytest.mark.parametrize('adj', [(0, 0), (1, 1)])
def test_onnx_export_npx_deconvolution(tmp_path, dtype, shape, num_filter, num_group, no_bias,
kernel, stride, pad, dilate, adj):
for i in range(len(stride)):
if stride[i] <= adj[i]:
return
if shape[1] % num_group:
return
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
w_shape = (shape[1],) + (num_filter // num_group,) + kernel
w = mx.np.random.uniform(0, 1, w_shape, dtype=dtype)
b_shape = (num_filter)
b = mx.np.random.uniform(0, 1, b_shape, dtype=dtype)
kwargs = {}
if kernel:
kwargs['kernel'] = kernel
if stride:
kwargs['stride'] = stride
if pad:
kwargs['pad'] = pad
if dilate:
kwargs['dilate'] = dilate
if adj:
kwargs['adj'] = adj
M = def_model(mx.npx, 'deconvolution', num_filter=num_filter, num_group=num_group, no_bias=no_bias,
layout='NCHW', **kwargs)
inputs = [x, w] if no_bias else [x, w, b]
op_export_test('deconvolution', M, inputs, tmp_path)
@pytest.mark.parametrize('dtype', ['float32', 'float16', 'float64'])
@pytest.mark.parametrize('mode', ['edge', 'constant', 'reflect'])
@pytest.mark.parametrize('params', [((3, 4, 5, 6), (0, 0, 0, 0, 2, 3, 4, 5)),
((7, 6, 5, 4, 3), (0, 0, 0, 0, 4, 4, 3, 3, 2, 1))])
def test_onnx_export_npx_pad(tmp_path, dtype, mode, params):
kwargs = {}
kwargs['constant_value'] = 9999.55
kwargs['pad_width'] = params[1]
x = mx.np.random.uniform(0, 1, size=params[0], dtype=dtype)
M = def_model(mx.npx, 'pad', mode=mode, **kwargs)
op_export_test('pad', M, [x], tmp_path)
# Note that due to ONNX limitation, the behavior for when inputs > 2-D is different from that of
# MXNet
@pytest.mark.skip(reason='TODO MXNet 2.0 dot changed behavior')
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('params', [((4, 5), (5, 6), False, False),
((5, 4), (5, 6), True, False),
((5, 4), (6, 5), True, True),
((4, 5), (6, 5), False, True),
((4, 5), (5), False, False),
((4,), (4, 5), False, False),
((4, 5), (5,), False, False)])
def test_onnx_export_dot(tmp_path, dtype, params):
A = mx.np.random.uniform(0, 1, params[0], dtype=dtype)
B = mx.np.random.uniform(0, 1, params[1], dtype=dtype)
M = def_model(mx.np, 'dot', transpose_a=params[2], transpose_b=params[3])
op_export_test('dot', M, [A, B], tmp_path)
@pytest.mark.skip(reason='flatten is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(3, 4, 5, 6), (7, 8)])
def test_onnx_export_flatten(tmp_path, dtype, shape):
x = mx.random.uniform(0, 1, shape, dtype='float32').astype(dtype)
M = def_model('flatten')
op_export_test('flatten', M, [x], tmp_path)
# Note that due to ONNX limitation, the behavior for when inputs > 2-D is different from that of
# MXNet
@pytest.mark.skip(reason='linalg.gemm2 is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('alpha', [1, 1.5])
@pytest.mark.parametrize('params', [((4, 5), (5, 4), False, False),
((4, 5, 6), (4, 6, 5), False, False),
((4, 5, 6, 7), (4, 5, 6, 7), True, False),
((4, 5, 6, 7), (4, 5, 6, 7), False, True),
((4, 5, 9, 7), (4, 5, 6, 9), True, True)])
def test_onnx_export_linalg_gemm2(tmp_path, dtype, alpha, params):
A = mx.random.uniform(0, 1, params[0], dtype=dtype)
B = mx.random.uniform(0, 1, params[1], dtype=dtype)
M = def_model('linalg.gemm2', alpha=alpha, transpose_a=params[2], transpose_b=params[3])
op_export_test('_linalg_gemm2', M, [A, B], tmp_path)
@pytest.mark.skip(reason='LogisticRegressionOutput is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
def test_onnx_export_LogisticRegressionOutput(tmp_path, dtype, shape):
x = mx.random.uniform(0, 1, shape, dtype=dtype)
y = mx.nd.zeros(shape, dtype=dtype)
M = def_model('LogisticRegressionOutput')
op_export_test('LogisticRegressionOutput', M, [x, y], tmp_path)
@pytest.mark.skip(reason='SoftmaxOutput is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32', 'float64'])
@pytest.mark.parametrize('shape', [(4, 5, 6), (6, 7), (3, 4, 5, 6, 7)])
def test_onnx_export_SoftmaxOutput(tmp_path, dtype, shape):
x = mx.random.uniform(0, 1, shape, dtype=dtype)
y = mx.nd.zeros(shape[:-1], dtype=dtype)
M = def_model('SoftmaxOutput')
op_export_test('SoftmaxOutput', M, [x, y], tmp_path)
# Due to ONNX limitation, L2Normalization only supports channel mode for now
@pytest.mark.skip(reason='L2Normalization is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (3, 4, 5, 6, 7)])
def test_onnx_export_L2Normalization(tmp_path, dtype, shape):
x = mx.random.uniform(0, 1, shape, dtype=dtype)
M = def_model('L2Normalization', mode='channel')
op_export_test('L2Normalization', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (3, 4, 5, 6, 7)])
@pytest.mark.parametrize('eps', [0.001, 0.00001])
def test_onnx_export_npx_instance_norm(tmp_path, dtype, shape, eps):
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
gamma = mx.np.random.uniform(0, 1, shape[1:2], dtype=dtype)
beta = mx.np.random.uniform(0, 1, shape[1:2], dtype=dtype)
M = def_model(mx.npx, 'instance_norm', eps=eps)
op_export_test('instance_norm', M, [x, gamma, beta], tmp_path)
# ONNXRuntime only supports 4-D inputs
@pytest.mark.skip(reason='LRN is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(4, 5, 6, 7)])
@pytest.mark.parametrize('alpha', [0.001, 0.00001])
@pytest.mark.parametrize('beta', [0.75, 0.8])
@pytest.mark.parametrize('knorm', [1, 2])
@pytest.mark.parametrize('nsize', [3, 5])
def test_onnx_export_LRN(tmp_path, dtype, shape, alpha, beta, knorm, nsize):
x = mx.random.uniform(0, 1, shape, dtype=dtype)
M = def_model('LRN', alpha=alpha, beta=beta, knorm=knorm, nsize=nsize)
op_export_test('LRN', M, [x], tmp_path)
@pytest.mark.skip(reason='Crop is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float32'])
@pytest.mark.parametrize('shape', [(1, 3, 224, 224), (5, 6, 64, 64)])
@pytest.mark.parametrize('h_w', [(10, 10), (7, 11)])
@pytest.mark.parametrize('offset', [(7, 13), (10, 10)])
@pytest.mark.parametrize('shape2', [None, (10, 10, 16, 16)])
def test_onnx_export_Crop(tmp_path, dtype, shape, h_w, offset, shape2):
x = mx.random.uniform(0, 1, shape, dtype=dtype)
M = def_model('Crop', h_w=h_w, offset=offset, center_crop=False)
if shape2 is not None:
y = mx.random.uniform(0, 1, shape2, dtype=dtype)
op_export_test('Crop', M, [x, y], tmp_path)
else:
op_export_test('Crop', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('shape', [(100,), (3, 4, 5), (6, 7)])
def test_onnx_export_np_reciprocal(tmp_path, dtype, shape):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.np, 'reciprocal')
op_export_test('reciprocal', M, [A], tmp_path)
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize('shape', [(1, 3), (3, 4, 5)])
def test_onnx_export_np_power(tmp_path, shape, dtype):
x = mx.np.random.uniform(-5, 5, shape).astype(dtype)
y = mx.np.random.uniform(-10, 10, shape).astype(dtype)
M = def_model(mx.np, 'power')
op_export_test('power', M, [x, y], tmp_path)
@pytest.mark.skip(reason='broadcast_power is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize('shape', [(1, 3), (3, 4, 5)])
def test_onnx_export_broadcast_power(tmp_path, shape, dtype):
x = mx.nd.random.uniform(-5, 5, shape).astype(dtype)
y = mx.nd.random.uniform(-10, 10, shape).astype(dtype)
M = def_model('broadcast_power')
op_export_test('broadcast_power', M, [x, y], tmp_path)
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64"])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
def test_onnx_export_np_sqrt(tmp_path, dtype, shape):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.np, 'sqrt')
op_export_test('sqrt', M, [A], tmp_path)
@pytest.mark.skip(reason='depth_to_space is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("params", [[(1,4,2,3), 1], [(1,4,2,3), 2]])
def test_onnx_export_depth_to_space(tmp_path, dtype, params):
shape, block_size = params
M = def_model('depth_to_space', block_size=block_size)
x = mx.nd.arange(0, np.prod(shape)).reshape(shape).astype(dtype)
op_export_test('depth_to_space', M, [x], tmp_path)
@pytest.mark.skip(reason='space to depth is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("params", [[(1,4,2,3), 1], [(1,1,4,6),2]])
def test_onnx_export_space_to_depth(tmp_path, dtype, params):
shape, block_size = params
M = def_model('space_to_depth', block_size=block_size)
x = mx.nd.arange(0, np.prod(shape)).reshape(shape).astype(dtype)
op_export_test('space_to_depth', M, [x], tmp_path)
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_np_square(tmp_path, dtype, shape):
M = def_model(mx.np, 'square')
x = mx.np.arange(0, np.prod(shape)).reshape(shape).astype(dtype)
op_export_test('square', M, [x], tmp_path)
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_npx_shape_array(tmp_path, dtype, shape):
M = def_model(mx.npx, 'shape_array')
x = mx.np.arange(0, np.prod(shape)).reshape(shape).astype(dtype)
op_export_test('shape_array', M, [x], tmp_path)
@pytest.mark.skip(reason='hard_sigmoid is deprecaed in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
@pytest.mark.parametrize("alpha", [None, 0.1, 0.4567, 0.9])
@pytest.mark.parametrize("beta", [None, 0.1, 0.4567, 0.5, 0.9])
def test_onnx_export_hard_sigmoid(tmp_path, dtype, shape, alpha, beta):
kwargs = { }
if alpha is not None:
kwargs['alpha'] = alpha
if beta is not None:
kwargs['beta'] = beta
M = def_model('hard_sigmoid', **kwargs)
x = mx.nd.arange(0, np.prod(shape)).reshape(shape).astype(dtype)
op_export_test('hard_sigmoid', M, [x], tmp_path)
@pytest.mark.skip(reason='broadcast_lesser is deprecaed in 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_broadcast_lesser(tmp_path, dtype, shape):
M = def_model('broadcast_lesser')
x = mx.nd.random.uniform(-100, 100, shape).astype(dtype)
y = mx.nd.random.uniform(-100, 100, shape).astype(dtype)
op_export_test('broadcast_lesser', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_npx_broadcast_greater(tmp_path, dtype, shape):
M = def_model(mx.npx, 'broadcast_greater')
x = mx.np.random.uniform(-100, 100, shape).astype(dtype)
y = mx.np.random.uniform(-100, 100, shape).astype(dtype)
op_export_test('broadcast_greater', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize("shape", [(10,5), (1,2,3), (4,5,6)])
@pytest.mark.parametrize('axis', [None, 1])
def test_onnx_export_npx_log_softmax(tmp_path, dtype, shape, axis):
x = mx.np.random.uniform(0, 1, shape, dtype=dtype)
kwargs = {}
if axis is not None:
kwargs['axis'] = axis
M = def_model(mx.npx, 'log_softmax', **kwargs)
op_export_test('log_softmax', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (2,3), (4,5,6)])
def test_onnx_export_np_logical_and(tmp_path, dtype, shape):
M = def_model(mx.np, 'logical_and')
x = mx.np.random.uniform(-1, 1, shape).astype(dtype)
y = mx.np.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('logical_and', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (2,3), (4,5,6)])
def test_onnx_export_np_logical_or(tmp_path, dtype, shape):
M = def_model(mx.np, 'logical_or')
x = mx.np.random.uniform(-1, 1, shape).astype(dtype)
y = mx.np.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('logical_or', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (2,3), (4,5,6)])
def test_onnx_export_np_logical_xor(tmp_path, dtype, shape):
M = def_model(mx.np, 'logical_xor')
x = mx.np.random.uniform(-1, 1, shape).astype(dtype)
y = mx.np.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('logical_xor', M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shapes", [[(1,3),(2,3)], [(2,1,3,1),(2,8,3,9)], [(1,3,6),(5,3,6)]])
def test_onnx_export_np_broadcast_to(tmp_path, dtype, shapes):
in_shape, to_shape = shapes
M = def_model(np, 'broadcast_to', shape=to_shape)
x = mx.np.random.uniform(-100, 100, in_shape).astype(dtype)
op_export_test('broadcast_to', M, [x], tmp_path)
# onnxruntime currently does not support int32
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int64'])
@pytest.mark.parametrize('shape', [(1,), (2, 3), (4, 5, 6)])
def test_onnx_export_np_clip(tmp_path, dtype, shape):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
a_min = mx.np.min(A).astype('float32').asnumpy() + 5
a_max = mx.np.max(A).astype('float32').asnumpy() - 5
M = def_model(mx.np, 'clip', a_min=a_min, a_max=a_max)
op_export_test('clip', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(3, 4, 5), (6, 7), (8,)])
@pytest.mark.parametrize('func', [lambda x : x + np.random.rand(1)[0] * 100,
lambda x : x * np.random.rand(1)[0] * 100,
lambda x : x - np.random.rand(1)[0] * 100,
lambda x : np.random.rand(1)[0] * 100 - x,
lambda x : x / (np.random.rand(1)[0] * 100 + 1),
lambda x : np.random.rand(1)[0] * 100 / x,
lambda x : x ** np.random.rand(1)[0] * 100,
])
def test_onnx_export_np_scalar_op(tmp_path, dtype, shape, func):
A = mx.np.random.uniform(1, 100, shape).astype(dtype)
M = def_model_from_func(func)
op_export_test('_scalar', M, [A], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32'])
@pytest.mark.parametrize('shape', [(1, 1, 1), (2, 3, 4), (5, 6, 7, 8)])
@pytest.mark.parametrize('axis', [None, 0, 1, 2, -1, -2])
@pytest.mark.parametrize('op_name', ['argmax', 'argmin'])
def test_onnx_export_np_arg_max_min(tmp_path, dtype, shape, axis, op_name):
A = mx.np.random.uniform(-100, 100, shape).astype(dtype)
M = def_model(mx.np, op_name, axis=axis)
op_export_test(op_name, M, [A], tmp_path)
# onnx max and min have issue comparing negative float16 values
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [[(2, 3), (2, 3)], [(5, 4), (5, 4)]])
@pytest.mark.parametrize('op_name', ['maximum', 'minimum'])
def test_onnx_export_np_maximum_minimum(tmp_path, dtype, shape, op_name):
lhs = mx.np.random.uniform(1, 100, shape[0]).astype(dtype)
rhs = mx.np.random.uniform(1, 100, shape[1]).astype(dtype)
M = def_model(mx.np, op_name)
op_export_test(op_name, M, [lhs, rhs], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32','int32', 'int64'])
@pytest.mark.parametrize('shape', [(2, 3), (4, 5, 6)])
@pytest.mark.parametrize('axis', [None, 0, 1, -1, (0, 1)])
@pytest.mark.parametrize('keepdims', [True, False])
@pytest.mark.parametrize('op_name', ['max', 'min', 'mean', 'prod', 'sum'])
def test_onnx_export_np_reduce_op(tmp_path, dtype, shape, axis, keepdims, op_name):
x = mx.np.random.uniform(1, 100, size=shape).astype(dtype)
M = def_model(mx.np, op_name, axis=axis, keepdims=keepdims)
op_export_test(op_name, M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1,), (3, ), (4, 5), (3, 4, 5)])
@pytest.mark.parametrize('op_name', ['power', 'add', 'subtract', 'multiply', 'divide'])
def test_onnx_export_np_arithmetic(tmp_path, dtype, shape, op_name):
x = mx.np.random.uniform(1, 100, size=shape).astype(dtype)
y = mx.np.random.uniform(1, 2, size=shape).astype(dtype)
M = def_model(mx.np, op_name)
op_export_test(op_name, M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [[(3, 4), (3, 4)], [(3, 4), (3, 1)], [(3, 4), (4)]])
@pytest.mark.parametrize('op_name', ['add', 'subtract', 'multiply', 'divide'])
def test_onnx_export_np_arithmetic_broadcast_case(tmp_path, dtype, shape, op_name):
x = mx.np.random.uniform(1, 100, size=shape[0]).astype(dtype)
y = mx.np.random.uniform(1, 2, size=shape[1]).astype(dtype)
M = def_model(mx.np, op_name)
op_export_test(op_name, M, [x, y], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape', [(1,), (3, ), (4, 5), (3, 4, 5)])
def test_onnx_export_np_negative(tmp_path, dtype, shape):
x = mx.np.random.uniform(-100, 100, size=shape).astype(dtype)
M = def_model(mx.np, 'negative')
op_export_test('negative', M, [x], tmp_path)
@pytest.mark.skip(reason='addn is deprecated in 2.0')
@pytest.mark.parametrize('dtype', ['float16', 'float32'])
@pytest.mark.parametrize('shape', [(1,), (3, ), (4, 5), (3, 4, 5)])
def test_onnx_export_addn(tmp_path, dtype, shape):
x = mx.nd.random.uniform(-100, 100, shape=shape).astype(dtype)
M = def_model('add_n')
op_export_test('add_n', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize('shape_axis', [[(1, 1), None], [(3, 1, 2, 1), (None)], [(3, 1, 2, 1), (1)],
[(3, 1, 2, 1), (1, 3)]])
def test_onnx_export_np_squeeze(tmp_path, dtype, shape_axis):
x = mx.np.random.uniform(1, 100, size=shape_axis[0]).astype(dtype)
M = def_model(mx.np, 'squeeze', axis=shape_axis[1])
op_export_test('squeeze', M, [x], tmp_path)
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("order", [1, 2])
@pytest.mark.parametrize("keepdims", [0, 1])
@pytest.mark.parametrize("axis", [None, 0, 1, 2, -1, (0, 2), (0, 1, 2)])
@pytest.mark.parametrize("shape", [(4, 5, 6), (3, 4, 5, 6)])
def test_onnx_export_npx_norm(tmp_path, dtype, order, axis, shape, keepdims):
kwargs = {}
if order is not None:
kwargs['ord'] = order
if axis is not None:
kwargs['axis'] = axis
if keepdims is not None:
kwargs['keepdims'] = keepdims
M = def_model(mx.npx, 'norm', **kwargs)
x = mx.np.random.normal(0, 10, shape).astype(dtype)
op_export_test('norm', M, [x], tmp_path)
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'int32', 'int64'])
@pytest.mark.parametrize("shape", [(10,), (2,3), (4,5,6)])
def test_onnx_export_np_logical_not(tmp_path, dtype, shape):
M = def_model(mx.np, 'logical_not')
x = mx.np.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('logical_not', M, [x], tmp_path)
@pytest.mark.skip(reason='TODO random uniform_like changed spec in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_random_uniform_like(tmp_path, dtype, shape):
M = def_model('random.uniform_like')
low = -10
high = 10
x = mx.nd.zeros(shape=shape).astype(dtype)
def rand_check(out):
for i in out:
if i.any() < low or i.any() >= high:
raise Exception("Invalid value")
return np.zeros_like(out)
def rand_check_nd(out):
return rand_check(out.asnumpy())
op_export_test('random.uniform_like', M, [x], tmp_path, mx_map=rand_check_nd, onnx_map=rand_check)
@pytest.mark.skip(reason='TODO random uniform changed spec in 2.0')
@pytest.mark.parametrize("dtype", ["float32", "float64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_random_uniform(tmp_path, dtype, shape):
low = -10
high = 10
M = def_model('random_uniform', low=low, high=high, shape=shape, dtype=dtype, dummy_input=True)
x = mx.nd.array([1], dtype='float32')
def rand_check(out):
for i in out:
if i.any() < low or i.any() >= high:
raise Exception("Invalid value")
return np.zeros_like(out)
def rand_check_nd(out):
return rand_check(out.asnumpy())
op_export_test('random_uniform', M, [x], tmp_path, mx_map=rand_check_nd, onnx_map=rand_check, dummy_input=True)
@pytest.mark.skip(reason='TODO random normal changed spec in 2.0')
@pytest.mark.parametrize("dtype", ["float32", "float64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
@pytest.mark.parametrize("loc", [None, 0, 1, 2])
@pytest.mark.parametrize("scale", [None, 1, 2])
def test_onnx_export_random_normal(tmp_path, dtype, loc, scale, shape):
kwargs = {
'dtype': dtype,
'size': shape,
'dummy_input': True
}
if loc is not None:
kwargs['loc'] = loc
if scale is not None:
kwargs['scale'] = scale
M = def_model(mx.np.random, 'normal', **kwargs)
x = mx.np.array([1], dtype='float32')
def rand_check(out):
return np.zeros_like(out)
def rand_check_nd(out):
return rand_check(out.asnumpy())
op_export_test('random_normal', M, [x], tmp_path, mx_map=rand_check_nd, onnx_map=rand_check, dummy_input=True)
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("spatial_scale", [0.7, 1.0])
def test_onnx_export_npx_roi_pooling(tmp_path, dtype, spatial_scale):
M = def_model(mx.npx, 'roi_pooling', pooled_size=(2,2), spatial_scale=spatial_scale)
x = mx.np.arange(start=0, stop=48, dtype=dtype).reshape((1,1,8,6))
y = mx.np.array([[0,0,0,4,4]], dtype=dtype)
op_export_test('roi_pooling', M, [x, y], tmp_path)
@pytest.mark.skip(reason='rnn_param_concat is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(1,2,3), (1,10)])
@pytest.mark.parametrize("axis", [None, 0, 1])
def test_onnx_export_rnn_param_concat(tmp_path, dtype, shape, axis):
kwargs = {}
if axis is not None:
kwargs['dim'] = axis
M = def_model('_internal._rnn_param_concat', **kwargs)
x = mx.nd.random.uniform(-1, 1, shape).astype(dtype)
y = mx.nd.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('_internal._rnn_param_concat', M, [x, y], tmp_path)
@pytest.mark.skip(reason='size_array is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"])
@pytest.mark.parametrize("shape", [(10,), (1,2,3), (4,5,6)])
def test_onnx_export_size_array(tmp_path, dtype, shape):
M = def_model(mx.np, 'size_array')
x = mx.nd.random.uniform(-1, 1, shape).astype(dtype)
op_export_test('size_array', M, [x], tmp_path)
@pytest.mark.skip(reason='sample_multinomial is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ["float16", "float32"])
@pytest.mark.parametrize("shape", [(1,5), (2,10), (4,5)])
@pytest.mark.parametrize("sample_shape", [(1), (2)])
def test_onnx_export_sample_multinomial(tmp_path, dtype, shape, sample_shape):
kwargs = {}
if sample_shape is not None:
kwargs['shape'] = sample_shape
M = def_model('sample_multinomial', **kwargs)
a = mx.nd.random.uniform(0, 1, shape).astype(dtype)
x = a/a.sum(axis=1, keepdims=1)
def rand_check(out):
return np.zeros_like(out)
def rand_check_nd(out):
return rand_check(out.asnumpy())
op_export_test('sample_multinomial', M, [x], tmp_path, mx_map=rand_check_nd, onnx_map=rand_check)
@pytest.mark.skip(reason='split_v2 is deprecated in 2.0')
@pytest.mark.parametrize("dtype", ['float32', 'int32', 'int64'])
@pytest.mark.parametrize('params', [((2, 4, 6), (1, ), 0, True),
((4, 5, 6), (2, 4), 1, False),
((4, 5, 6, 7), (0, 2, 4), 2, False),
((4, 5, 6, 7), 3, -2, False),
((2, 6, 8), 8, -1, True)])
def test_onnx_export_split_v2(tmp_path, dtype, params):
from onnx.defs import onnx_opset_version
if onnx_opset_version() < 13 and not isinstance(params[1], int):
# opset12 only supports sections. indices is supported since opset13
return
M = def_model('split_v2', indices_or_sections=params[1], axis=params[2], squeeze_axis=params[3])
x = mx.nd.random.uniform(0, 10, params[0]).astype(dtype)
op_export_test('split_v2', M, [x], tmp_path)