diff --git a/conftest.py b/conftest.py index 861abc14b843..88e21f494113 100644 --- a/conftest.py +++ b/conftest.py @@ -31,23 +31,17 @@ # taken from the 20 (arbitrary number) of tests as from # https://ci.tlcpack.ai/job/tvm/job/main/2907/testReport _slowest_tests = [ - "tests/python/frontend/tensorflow/test_forward.py::test_forward_broadcast_args", - "tests/python/frontend/tensorflow/test_forward.py::test_forward_broadcast_to", "tests/python/topi/python/test_topi_conv2d_int8.py::test_conv2d_nchw[int8]", "tests/python/topi/python/test_topi_conv2d_int8.py::test_conv2d_nchw[uint8]", "tests/python/topi/python/test_topi_upsampling.py::test_upsampling3d", "tests/python/topi/python/test_topi_upsampling.py::test_upsampling3d", "tests/python/topi/python/test_topi_conv2d_int8.py::test_conv2d_nchw[int8]", - "tests/python/frontend/tflite/test_forward.py::test_all_elemwise", - "tests/python/frontend/pytorch/test_object_detection.py::test_detection_models", "tests/python/topi/python/test_topi_conv2d_int8.py::test_conv2d_nchw[uint8]", "tests/python/topi/python/test_topi_conv2d_NCHWc.py::test_conv2d_NCHWc", "tests/python/topi/python/test_topi_conv2d_hwnc_tensorcore.py::test_conv2d_hwnc_tensorcore", "tests/python/contrib/test_tensorrt.py::test_binary[compile]", - "tests/python/frontend/pytorch/test_forward.py::test_segmentation_models", "tests/python/topi/python/test_topi_conv2d_NCHWc.py::test_conv2d_NCHWc", "tests/python/relay/test_py_converter.py::test_global_recursion", - "tests/python/frontend/tensorflow/test_forward.py::test_forward_ptb", "tests/python/relay/test_op_level6.py::test_topk", "tests/python/topi/python/test_topi_conv2d_winograd.py::test_conv2d_nchw", "tests/python/relay/test_py_converter.py::test_global_recursion", diff --git a/tests/lint/pylint.sh b/tests/lint/pylint.sh index 90e50dfa9433..4d10b01485a0 100755 --- a/tests/lint/pylint.sh +++ b/tests/lint/pylint.sh @@ -41,17 +41,5 @@ python3 -m pylint tests/python/contrib/test_hexagon/conv2d/*.py --rcfile="$(dirn python3 -m pylint tests/python/contrib/test_hexagon/topi/*.py --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/contrib/test_hexagon/metaschedule_e2e/*.py --rcfile="$(dirname "$0")"/pylintrc -# tests/python/frontend tests -python3 -m pylint tests/python/frontend/caffe/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/caffe2/*.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/darknet/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/coreml/*.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/keras/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/darknet/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/oneflow/*.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/tensorflow/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/pytorch/test_forward.py --rcfile="$(dirname "$0")"/pylintrc -python3 -m pylint tests/python/frontend/tflite/test_forward.py --rcfile="$(dirname "$0")"/pylintrc - # tests/python/contrib/test_msc tests python3 -m pylint tests/python/contrib/test_msc/*.py --rcfile="$(dirname "$0")"/pylintrc diff --git a/tests/python/frontend/caffe/test_forward.py b/tests/python/frontend/caffe/test_forward.py deleted file mode 100644 index d0ba1dfac40b..000000000000 --- a/tests/python/frontend/caffe/test_forward.py +++ /dev/null @@ -1,1166 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, unspecified-encoding -""" -Caffe testcases -==================== -This article is a test script to test Caffe operator with Relay. -""" -import os -import logging -import numpy as np -import pytest - -from google.protobuf import text_format -import caffe -from caffe import layers as L, params as P -from caffe.proto import caffe_pb2 as pb - -import tvm -import tvm.testing -from tvm import relay -from tvm.contrib import graph_executor -from tvm.contrib.download import download_testdata - -os.environ["GLOG_minloglevel"] = "2" - -logging.basicConfig(level=logging.ERROR) - -CURRENT_DIR = os.path.join(os.path.expanduser("~"), ".tvm_test_data", "caffe_test") - -####################################################################### -# Generic functions for TVM & Caffe -# ------------------------------------------ - - -def _create_dir(d_path): - """If the directory is not existed, create it""" - if not (os.path.exists(d_path) and os.path.isdir(d_path)): - os.makedirs(d_path) - - -def _list_to_str(ll): - """Convert list or tuple to str, separated by underline.""" - if isinstance(ll, (tuple, list)): - tmp = [str(i) for i in ll] - res = "_".join(tmp) - return res - - -def _gen_filename_str(op_name, data_shape, *args, **kwargs): - """Combining the filename according to the op_name, shape and other args.""" - file_dir = os.path.join(CURRENT_DIR, op_name) - _create_dir(file_dir) - res = op_name + "_" - shape_str = _list_to_str(list(data_shape)) - res += shape_str - for arg in args: - if isinstance(arg, (tuple, list)): - res += "_" + _list_to_str(arg) - elif isinstance(arg, (int, float, str)): - res += "_" + str(arg) - for _, v in kwargs.items(): - if isinstance(v, (tuple, list)): - res += "_" + _list_to_str(v) - elif isinstance(v, (int, float, str)): - res += "_" + str(v) - res = res.replace(".", "_") - res = res.replace("-", "_") - proto_file = os.path.join(file_dir, res + ".prototxt") - blob_file = os.path.join(file_dir, res + ".caffemodel") - solver_file = os.path.join(file_dir, res + "_solver.prototxt") - - return (proto_file, blob_file, solver_file) - - -def _save_prototxt(n_netspec, f_path): - """Generate .prototxt file according to caffe.NetSpec""" - s = n_netspec.to_proto() - with open(f_path, "w") as f: - f.write(str(s)) - - -def _save_solver(solver_file, proto_file, blob_file): - """Define a solver proto, you can change the configs.""" - blob_file_prefix = blob_file.split(".caffemodel")[0] - s = pb.SolverParameter() - s.train_net = proto_file - s.base_lr = 0.01 - s.momentum = 0.9 - s.weight_decay = 0.0005 - s.lr_policy = "inv" - s.gamma = 0.0001 - s.power = 0.75 - s.display = 1 - s.max_iter = 100000 - s.snapshot = 100000 - s.snapshot_prefix = blob_file_prefix - - with open(solver_file, "w") as f: - f.write(str(s)) - - -def _save_caffemodel(solver_file, blob_file): - """Generate .caffemodel file.""" - solver = caffe.SGDSolver(solver_file) - solver.net.save(blob_file) - - -def _gen_model_files(n_netspec, proto_file, blob_file, solver_file): - _save_prototxt(n_netspec, proto_file) - _save_solver(solver_file, proto_file, blob_file) - _save_caffemodel(solver_file, blob_file) - - -def _siso_op(data, func, *args, **kwargs): - """Create single input and single output Caffe op""" - n = caffe.NetSpec() - n.data = L.Input(input_param={"shape": {"dim": list(data.shape)}}) - n.output = func(n.data, *args, **kwargs) - return n - - -def _miso_op(data_list, func, *args, **kwargs): - """Create multi input and single output Caffe op""" - n = caffe.NetSpec() - if not isinstance(data_list, (tuple, list)): - raise TypeError(f"Need tuple or list but get {type(data_list)}") - input_list = [] - for idx, data in enumerate(data_list): - n["data" + str(idx)] = L.Input(input_param={"shape": {"dim": list(data.shape)}}) - input_list.append(n["data" + str(idx)]) - n.output = func(*input_list, *args, **kwargs) - return n - - -def _simo_op(data, func, *args, **kwargs): - """Create single input and multi output Caffe op""" - n = caffe.NetSpec() - n.data = L.Input(input_param={"shape": {"dim": list(data.shape)}}) - output_list = func(n.data, *args, **kwargs) - for idx, out in enumerate(output_list): - n["output" + str(idx)] = out - return n - - -def _run_caffe(data, proto_file, blob_file): - """Run caffe model by Caffe according to .caffemodel and .prototxt""" - net = caffe.Net(proto_file, blob_file, caffe.TEST) - if isinstance(data, (list, tuple)): - for idx, d in enumerate(data): - net.blobs["data" + str(idx)].data[...] = d - else: - net.blobs["data"].data[...] = data - out = net.forward() - - caffe_output = [] - for i in range(len(out.keys())): - if "output" + str(i) not in out.keys(): - caffe_output.clear() - return list(out.values()) - caffe_output.append(out["output" + str(i)]) - return caffe_output - - -def _run_tvm(data, proto_file, blob_file): - """Run caffe model by TVM according to .caffemodel and .prototxt""" - init_net = pb.NetParameter() - predict_net = pb.NetParameter() - - # load model - with open(proto_file, "r") as f: - text_format.Merge(f.read(), predict_net) - # load blob - with open(blob_file, "rb") as f: - init_net.ParseFromString(f.read()) - - shape_dict = {} - dtype_dict = {} - if isinstance(data, (tuple, list)): - for idx, d in enumerate(data): - shape_dict["data" + str(idx)] = d.shape - dtype_dict["data" + str(idx)] = "float32" - else: - shape_dict = {"data": data.shape} - dtype_dict = {"data": "float32"} - - mod, params = relay.frontend.from_caffe(init_net, predict_net, shape_dict, dtype_dict) - - target = "llvm" - - dev = tvm.cpu(0) - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target=target, params=params) - dtype = "float32" - m = graph_executor.GraphModule(lib["default"](dev)) - if isinstance(data, (tuple, list)): - for idx, d in enumerate(data): - m.set_input("data" + str(idx), tvm.nd.array(d.astype(dtype))) - else: - m.set_input("data", tvm.nd.array(data.astype(dtype))) - # execute - m.run() - tvm_output = [] - # get outputs - for i in range(m.get_num_outputs()): - tvm_output.append(m.get_output(i).numpy()) - return tvm_output - - -def _compare_caffe_tvm(caffe_out, tvm_out, is_network=False): - for i, _ in enumerate(caffe_out): - if is_network: - caffe_out[i] = caffe_out[i][:1] - tvm.testing.assert_allclose(caffe_out[i], tvm_out[i], rtol=1e-5, atol=1e-5) - - -def _test_op(data, func_op, op_name, **kwargs): - """Single op testing pipline.""" - shape_list = [] - if isinstance(data, (list, tuple)): - n = _miso_op(data, func_op, **kwargs) - for d in data: - shape_list.extend(list(d.shape)) - else: - output_num = 1 - if "ntop" in kwargs: - output_num = kwargs["ntop"] - if output_num == 1: - n = _siso_op(data, func_op, **kwargs) - else: - n = _simo_op(data, func_op, **kwargs) - shape_list = list(data.shape) - - # obtain the .caffemodel file and .prototxt file - (proto_file, blob_file, solver_file) = _gen_filename_str(op_name, shape_list, **kwargs) - _gen_model_files(n, proto_file, blob_file, solver_file) - # run model in Caffe - caffe_out = _run_caffe(data, proto_file, blob_file) - # run model in TVM - tvm_out = _run_tvm(data, proto_file, blob_file) - _compare_caffe_tvm(caffe_out, tvm_out) - - -def _test_network(data, proto_file, blob_file): - # run model in Caffe - caffe_out = _run_caffe(data, proto_file, blob_file) - # run model in TVM - tvm_out = _run_tvm(data, proto_file, blob_file) - _compare_caffe_tvm(caffe_out, tvm_out, is_network=True) - - -####################################################################### -# BatchNorm -# ----------- - - -def _test_batchnorm(data, moving_average_fraction=0.999, eps=1e-5): - """One iteration of BatchNorm""" - _test_op( - data, L.BatchNorm, "BatchNorm", moving_average_fraction=moving_average_fraction, eps=eps - ) - - -def test_forward_BatchNorm(): - """BatchNorm""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_batchnorm(data) - _test_batchnorm(data, moving_average_fraction=0.88, eps=1e-4) - - -####################################################################### -# Concat -# ----------- - - -def _test_concat(data_list, axis=1): - """One iteration of Concat""" - _test_op(data_list, L.Concat, "Concat", axis=axis) - - -def test_forward_Concat(): - """Concat""" - _test_concat([np.random.rand(1, 3, 10, 10), np.random.rand(1, 2, 10, 10)], axis=1) - _test_concat([np.random.rand(3, 10, 10), np.random.rand(2, 10, 10)], axis=0) - _test_concat([np.random.rand(3, 10), np.random.rand(2, 10)], axis=0) - - -####################################################################### -# Convolution -# ----------- - - -def _test_convolution(data, **kwargs): - """One iteration of Convolution""" - _test_op(data, L.Convolution, "Convolution", **kwargs) - - -def test_forward_Convolution(): - """Convolution""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_convolution( - data, - num_output=20, - bias_term=True, - pad=0, - kernel_size=3, - stride=2, - dilation=1, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_convolution( - data, - num_output=20, - bias_term=False, - pad=[1, 2], - kernel_size=3, - stride=2, - dilation=1, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_convolution( - data, - num_output=20, - bias_term=True, - pad=[1, 2], - kernel_size=[3, 5], - stride=[2, 1], - dilation=[1, 2], - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_convolution( - np.random.rand(1, 2, 10, 10).astype(np.float32), - num_output=20, - bias_term=True, - pad=[1, 2], - kernel_size=[3, 5], - stride=[2, 1], - dilation=[1, 2], - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - group=2, - ) - _test_convolution( - data, - num_output=20, - bias_term=True, - pad_h=1, - pad_w=2, - kernel_h=3, - kernel_w=5, - stride_h=2, - stride_w=1, - dilation=[1, 2], - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - - -####################################################################### -# Crop -# ----------- - - -def _test_crop(data, **kwargs): - """One iteration of Crop""" - _test_op(data, L.Crop, "Crop", **kwargs) - - -def test_forward_Crop(): - """Crop""" - _test_crop([np.random.rand(10, 10, 120, 120), np.random.rand(10, 5, 50, 60)]) - _test_crop([np.random.rand(10, 10, 120, 120), np.random.rand(10, 5, 50, 60)], axis=1) - _test_crop([np.random.rand(10, 10, 120, 120), np.random.rand(10, 5, 50, 60)], axis=1, offset=2) - _test_crop( - [np.random.rand(10, 10, 120, 120), np.random.rand(10, 5, 50, 60)], axis=1, offset=[1, 2, 4] - ) - _test_crop( - [np.random.rand(10, 10, 120, 120), np.random.rand(10, 5, 50, 60)], axis=2, offset=[2, 4] - ) - _test_crop([np.random.rand(10, 120, 120), np.random.rand(5, 50, 60)], axis=1, offset=[2, 4]) - _test_crop([np.random.rand(120, 120), np.random.rand(50, 60)], axis=0, offset=[2, 4]) - - -####################################################################### -# Deconvolution -# ----------- - - -def _test_deconvolution(data, **kwargs): - """One iteration of Deconvolution""" - _test_op(data, L.Deconvolution, "Deconvolution", **kwargs) - - -def test_forward_Deconvolution(): - """Deconvolution""" - data = np.random.rand(1, 16, 32, 32).astype(np.float32) - _test_deconvolution( - data, - convolution_param=dict( - num_output=20, - bias_term=True, - pad=0, - kernel_size=3, - stride=2, - dilation=1, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ), - ) - _test_deconvolution( - data, - convolution_param=dict( - num_output=20, - bias_term=False, - pad=[1, 2], - kernel_size=3, - stride=2, - dilation=1, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ), - ) - _test_deconvolution( - data, - convolution_param=dict( - num_output=20, - bias_term=True, - pad_h=1, - pad_w=2, - kernel_h=3, - kernel_w=5, - stride_h=2, - stride_w=1, - dilation=1, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ), - ) - _test_deconvolution( - data, - convolution_param=dict( - num_output=16, - bias_term=False, - pad=0, - kernel_size=2, - stride=2, - dilation=1, - group=16, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ), - ) - data = np.random.rand(1, 100, 32, 32).astype(np.float32) - _test_deconvolution( - data, - convolution_param=dict( - num_output=100, - bias_term=False, - pad=0, - kernel_size=2, - stride=2, - dilation=1, - group=100, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ), - ) - - -####################################################################### -# Dropout -# ----------- - - -def _test_dropout(data, **kwargs): - """One iteration of Dropout""" - _test_op(data, L.Dropout, "Dropout", **kwargs) - - -def test_forward_Dropout(): - """Dropout""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_dropout(data) - _test_dropout(data, dropout_ratio=0.7) - - -####################################################################### -# Eltwise -# ----------- - - -def _test_eltwise(data_list, **kwargs): - """One iteration of Eltwise""" - _test_op(data_list, L.Eltwise, "Eltwise", **kwargs) - - -def test_forward_Eltwise(): - """Eltwise""" - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=0, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=1, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=2, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=1, - coeff=[0.5, 1], - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=0, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=1, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=2, - ) - _test_eltwise( - [ - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - np.random.rand(1, 3, 10, 11).astype(np.float32), - ], - operation=1, - coeff=[0.5, 1, 0.2, 1.8, 3.1, 0.1], - ) - - -####################################################################### -# Flatten -# ----------- - - -def _test_flatten(data, axis=1): - """One iteration of Flatten""" - _test_op(data, L.Flatten, "Flatten", axis=axis) - - -def test_forward_Flatten(): - """Flatten""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_flatten(data) - _test_flatten(data, axis=1) - - -####################################################################### -# Flatten -# ----------- - - -def _test_inner_product(data, **kwargs): - """One iteration of InnerProduct""" - _test_op(data, L.InnerProduct, "InnerProduct", **kwargs) - - -def test_forward_InnerProduct(): - """InnerProduct""" - data = np.random.rand(1, 3, 10, 10) - _test_inner_product(data, num_output=20, bias_term=False, weight_filler=dict(type="xavier")) - _test_inner_product( - data, - num_output=20, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_inner_product( - np.random.rand(20, 10).astype(np.float32), - num_output=30, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - - -####################################################################### -# LRN -# ----------- - - -def _test_lrn(data, local_size=5, alpha=1.0, beta=0.75, k=1.0): - """One iteration of LRN""" - _test_op(data, L.LRN, "LRN", local_size=local_size, alpha=alpha, beta=beta, k=k) - - -def test_forward_LRN(): - """LRN""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_lrn(data) - _test_lrn(data, local_size=3) - _test_lrn(data, local_size=3, alpha=2.0) - _test_lrn( - data, - local_size=3, - alpha=2.0, - beta=0.5, - ) - _test_lrn(data, local_size=3, alpha=2.0, beta=0.5, k=2.0) - - -####################################################################### -# Permute -# ------- - - -def _test_permute(data, **kwargs): - """One iteration of Permute.""" - _test_op(data, L.Permute, "Permute", **kwargs) - - -def test_forward_Permute(): - """Permute""" - data = np.random.rand(2, 3, 4).astype(np.float32) - _test_permute(data, permute_param={"order": [0, 1, 2]}) - _test_permute(data, permute_param={"order": [0, 2, 1]}) - _test_permute(data, permute_param={"order": [1, 0, 2]}) - _test_permute(data, permute_param={"order": [1, 2, 0]}) - _test_permute(data, permute_param={"order": [2, 0, 1]}) - _test_permute(data, permute_param={"order": [2, 1, 0]}) - - -####################################################################### -# Pooling -# ----------- - - -def _test_pooling(data, **kwargs): - """One iteration of Pooling.""" - _test_op(data, L.Pooling, "Pooling", **kwargs) - - -def test_forward_Pooling(): - """Pooing""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - # MAX Pooling - _test_pooling(data, kernel_size=2, stride=2, pad=0, pool=P.Pooling.MAX) - _test_pooling( - data, kernel_h=2, kernel_w=3, stride_h=2, stride_w=1, pad_h=1, pad_w=2, pool=P.Pooling.MAX - ) - _test_pooling(data, pool=P.Pooling.MAX, global_pooling=True) - - # AVE Pooing - _test_pooling(data, kernel_size=2, stride=2, pad=0, pool=P.Pooling.AVE) - _test_pooling( - data, kernel_h=2, kernel_w=3, stride_h=2, stride_w=1, pad_h=1, pad_w=2, pool=P.Pooling.AVE - ) - _test_pooling(data, pool=P.Pooling.AVE, global_pooling=True) - - -####################################################################### -# Power -# ----- -def _test_power(data, **kwargs): - """One iteration of Power.""" - _test_op(data, L.Power, "Power", **kwargs) - - -def test_forward_Power(): - """Power""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_power(data, power_param={"power": 0.37, "scale": 0.83, "shift": -2.4}) - _test_power(data, power_param={"power": 0.37, "scale": 0.83, "shift": 0.0}) - _test_power(data, power_param={"power": 0.0, "scale": 0.83, "shift": -2.4}) - _test_power(data, power_param={"power": 1.0, "scale": 0.83, "shift": -2.4}) - _test_power(data, power_param={"power": 2.0, "scale": 0.34, "shift": -2.4}) - _test_power(data, power_param={"power": 1.0, "scale": 1.0, "shift": 0.0}) - - -####################################################################### -# PReLU -# ----------- - - -def _test_prelu(data, **kwargs): - """One iteration of PReLU.""" - _test_op(data, L.PReLU, "PReLU", **kwargs) - - -def test_forward_PReLU(): - """PReLU""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_prelu(data, filler=dict(type="constant", value=0.5)) - _test_prelu(data) - _test_prelu(np.random.rand(10, 20).astype(np.float32)) - - -####################################################################### -# ReLU -# ----------- - - -def _test_relu(data, **kwargs): - """One iteration of ReLU.""" - _test_op(data, L.ReLU, "ReLU", **kwargs) - - -def test_forward_ReLU(): - """ReLU""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_relu(data) - _test_relu(np.random.rand(10, 20).astype(np.float32)) - - -####################################################################### -# Reshape -# ----------- - - -def _test_reshape(data, **kwargs): - """One iteration of Reshape.""" - _test_op(data, L.Reshape, "Reshape", **kwargs) - - -def test_forward_Reshape(): - """Reshape""" - data = np.random.rand(1, 8, 6).astype(np.float32) - _test_reshape(data, reshape_param={"shape": {"dim": [4, 3, 4]}}) - _test_reshape(data, reshape_param={"shape": {"dim": [2, 0, 3]}}) - _test_reshape(data, reshape_param={"shape": {"dim": [2, 0, -1]}}) - _test_reshape(data, reshape_param={"shape": {"dim": [0, -1]}}) - - _test_reshape(data, reshape_param={"shape": {"dim": [2, 3]}, "axis": 2}) - _test_reshape(data, reshape_param={"shape": {"dim": [4, 3, 4]}, "axis": 1}) - _test_reshape(data, reshape_param={"shape": {"dim": [4, 3, 4]}, "axis": -3}) - - _test_reshape(data, reshape_param={"shape": {"dim": [2, 4]}, "axis": 1, "num_axes": 1}) - _test_reshape(data, reshape_param={"shape": {"dim": [3, 16]}, "axis": 1, "num_axes": 2}) - - -####################################################################### -# Scale -# ----------- - - -def _test_scale(data, **kwargs): - """One iteration of Scale.""" - _test_op(data, L.Scale, "Scale", **kwargs) - - -def test_forward_Scale(): - """Scale""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_scale(data, filler=dict(type="xavier")) - _test_scale(data, filler=dict(type="xavier"), bias_term=True, bias_filler=dict(type="xavier")) - - -####################################################################### -# Sigmoid -# ----------- - - -def _test_sigmoid(data, **kwargs): - """One iteration of Sigmoid.""" - _test_op(data, L.Sigmoid, "Sigmoid", **kwargs) - - -def test_forward_Sigmoid(): - """Sigmoid""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_sigmoid(data) - - -####################################################################### -# Slice -# ----------- - - -def _test_slice(data, **kwargs): - """One iteration of Slice""" - _test_op(data, L.Slice, "Slice", **kwargs) - - -def test_forward_Slice(): - """Slice""" - data = np.random.rand(1, 3, 10, 10).astype(np.float32) - _test_slice(data, ntop=2, slice_param=dict(axis=1, slice_point=[1])) - _test_slice(data, ntop=2, slice_param=dict(axis=-1, slice_point=[1])) - _test_slice(data, ntop=3, slice_param=dict(axis=2, slice_point=[1, 6])) - _test_slice(data, ntop=3) - - -####################################################################### -# Softmax -# ----------- - - -def _test_softmax(data, **kwargs): - """One iteration of Softmax""" - _test_op(data, L.Softmax, "Softmax", **kwargs) - - -def test_forward_Softmax(): - """Softmax""" - _test_softmax(np.random.rand(1, 3, 10, 10).astype(np.float32)) - _test_softmax(np.random.rand(1, 3, 10, 10).astype(np.float32), axis=2) - _test_softmax(np.random.rand(10, 10).astype(np.float32), axis=0) - _test_softmax(np.random.rand(2, 10, 10).astype(np.float32), axis=1) - - -####################################################################### -# TanH -# ----------- - - -def _test_tanh(data, **kwargs): - """One iteration of TanH""" - _test_op(data, L.TanH, "TanH", **kwargs) - - -def test_forward_TanH(): - """TanH""" - _test_tanh(np.random.rand(1, 3, 10, 10).astype(np.float32)) - _test_tanh(np.random.rand(3, 10, 10).astype(np.float32)) - _test_tanh(np.random.rand(10, 10).astype(np.float32)) - _test_tanh(np.random.rand(10).astype(np.float32)) - - -####################################################################### -# Reduction -# ----------- - - -def _test_reduction(data, **kwargs): - """One iteration of Reduction""" - _test_op(data, L.Reduction, "Reduction", **kwargs) - - -def test_forward_Reduction(): - """Reduction""" - reduction_op = {"SUM": 1, "ASUM": 2, "SUMSQ": 3, "MEAN": 4} - _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["SUM"], axis=0) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUM"], axis=3 - ) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUM"], axis=1 - ) - _test_reduction( - np.random.rand(10).astype(np.float32), operation=reduction_op["SUM"], axis=0, coeff=0.5 - ) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), - operation=reduction_op["SUM"], - axis=3, - coeff=5.0, - ) - _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["ASUM"]) - _test_reduction( - np.random.rand(10, 20).astype(np.float32), operation=reduction_op["ASUM"], axis=1 - ) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["ASUM"], axis=3 - ) - _test_reduction( - np.random.rand(10).astype(np.float32), operation=reduction_op["ASUM"], axis=0, coeff=0.0 - ) - _test_reduction( - np.random.rand(10, 20, 30).astype(np.float32), - operation=reduction_op["ASUM"], - axis=2, - coeff=7.0, - ) - _test_reduction( - np.random.rand(10, 20, 30, 40, 10).astype(np.float32), - operation=reduction_op["ASUM"], - axis=3, - coeff=1.0, - ) - _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["SUMSQ"], axis=0) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUMSQ"], axis=3 - ) - _test_reduction( - np.random.rand(10).astype(np.float32), operation=reduction_op["SUMSQ"], axis=0, coeff=0.0 - ) - _test_reduction( - np.random.rand(10, 20, 30, 40, 50).astype(np.float32), - operation=reduction_op["SUMSQ"], - axis=4, - coeff=2.0, - ) - _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["MEAN"], axis=0) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["MEAN"], axis=3 - ) - _test_reduction( - np.random.rand(10).astype(np.float32), operation=reduction_op["MEAN"], axis=0, coeff=0.0 - ) - _test_reduction( - np.random.rand(10, 20, 30, 40).astype(np.float32), - operation=reduction_op["MEAN"], - axis=3, - coeff=2.0, - ) - - -####################################################################### -# Embed -# ----------- - - -def _test_embed(data, **kwargs): - """One iteration of Embed""" - _test_op(data, L.Embed, "Embed", **kwargs) - - -def test_forward_Embed(): - """Embed""" - k = 20 - data = list(i for i in range(k)) - np.random.shuffle(data) - # dimension is 1 - data = np.asarray(data) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=False, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - # dimension is 2 - data = np.reshape(data, [4, 5]) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=False, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - # dimension is 3 - data = np.reshape(data, [2, 2, 5]) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=False, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - # dimension is 4 - data = np.reshape(data, [2, 2, 5, 1]) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=True, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - _test_embed( - data, - num_output=30, - input_dim=k, - bias_term=False, - weight_filler=dict(type="xavier"), - bias_filler=dict(type="xavier"), - ) - - -####################################################################### -# Mobilenetv2 -# ----------- - - -def _test_mobilenetv2(data): - """One iteration of Mobilenetv2""" - mean_val = np.array([103.939, 116.779, 123.68], dtype=np.float32) - mean_val = np.reshape(mean_val, (1, 3, 1, 1)) - mean_val = np.tile(mean_val, (1, 1, 224, 224)) - data_process = data - mean_val - data_process = data_process / 58.8 - data_process = data_process.astype(np.float32) - - proto_file_url = ( - "https://github.com/shicai/MobileNet-Caffe/raw/master/mobilenet_v2_deploy.prototxt" - ) - blob_file_url = ( - "https://github.com/shicai/MobileNet-Caffe/blob/master/mobilenet_v2.caffemodel?raw=true" - ) - proto_file = download_testdata(proto_file_url, "mobilenetv2.prototxt", module="model") - blob_file = download_testdata(blob_file_url, "mobilenetv2.caffemodel", module="model") - _test_network(data_process, proto_file, blob_file) - - -def test_forward_Mobilenetv2(): - """Mobilenetv2""" - data = np.random.randint(0, 256, size=(1, 3, 224, 224)).astype(np.float32) - _test_mobilenetv2(data) - - -####################################################################### -# Alexnet -# ----------- - - -def _test_alexnet(data): - """One iteration of Alexnet""" - mean_val = np.array([103.939, 116.779, 123.68], dtype=np.float32) - mean_val = np.reshape(mean_val, (1, 3, 1, 1)) - mean_val = np.tile(mean_val, (1, 1, 227, 227)) - data_process = data - mean_val - data_process = data_process.astype(np.float32) - - proto_file_url = ( - "https://github.com/BVLC/caffe/raw/master/models/" + "bvlc_alexnet/deploy.prototxt" - ) - blob_file_url = "http://dl.caffe.berkeleyvision.org/bvlc_alexnet.caffemodel" - proto_file = download_testdata(proto_file_url, "alexnet.prototxt", module="model") - blob_file = download_testdata(blob_file_url, "alexnet.caffemodel", module="model") - _test_network(data_process, proto_file, blob_file) - - -@pytest.mark.skip(reason="See https://github.com/apache/tvm/issues/13227") -def test_forward_Alexnet(): - """Alexnet""" - data = np.random.randint(0, 256, size=(1, 3, 227, 227)).astype(np.float32) - _test_alexnet(data) - - -####################################################################### -# Resnet50 -# ----------- - - -def _test_resnet50(data): - """One iteration of Resnet50""" - mean_val = np.array([103.939, 116.779, 123.68], dtype=np.float32) - mean_val = np.reshape(mean_val, (1, 3, 1, 1)) - mean_val = np.tile(mean_val, (1, 1, 224, 224)) - data_process = data - mean_val - data_process = data_process.astype(np.float32) - - proto_file_url = ( - "https://github.com/fernchen/CaffeModels/raw/master/resnet/ResNet-50-deploy.prototxt" - ) - blob_file_url = ( - "https://github.com/fernchen/CaffeModels/raw/master/resnet/ResNet-50-model.caffemodel" - ) - - proto_file = download_testdata(proto_file_url, "resnet50.prototxt", module="model") - blob_file = download_testdata(blob_file_url, "resnet50.caffemodel", module="model") - - _test_network(data_process, proto_file, blob_file) - - -def test_forward_Resnet50(): - """Resnet50""" - data = np.random.randint(0, 256, size=(1, 3, 224, 224)).astype(np.float32) - _test_resnet50(data) - - -####################################################################### -# Inceptionv4 -# ----------- - - -def _test_inceptionv1(data): - """One iteration of Inceptionv4""" - mean_val = np.array([103.939, 116.779, 123.68], dtype=np.float32) - mean_val = np.reshape(mean_val, (1, 3, 1, 1)) - mean_val = np.tile(mean_val, (1, 1, 224, 224)) - data_process = data - mean_val - data_process = data_process / 58.8 - data_process = data_process.astype(np.float32) - - proto_file_url = ( - "https://github.com/BVLC/caffe/raw/master/models" + "/bvlc_googlenet/deploy.prototxt" - ) - blob_file_url = "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel" - proto_file = download_testdata(proto_file_url, "inceptionv1.prototxt", module="model") - blob_file = download_testdata(blob_file_url, "inceptionv1.caffemodel", module="model") - _test_network(data_process, proto_file, blob_file) - - -@pytest.mark.skip(reason="See issue https://github.com/apache/tvm/issues/13227") -def test_forward_Inceptionv1(): - """Inceptionv4""" - data = np.random.randint(0, 256, size=(1, 3, 224, 224)).astype(np.float32) - _test_inceptionv1(data) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/caffe2/model_zoo/__init__.py b/tests/python/frontend/caffe2/model_zoo/__init__.py deleted file mode 100644 index 946367f9ed4f..000000000000 --- a/tests/python/frontend/caffe2/model_zoo/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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. - -"""Store for caffe2 examples and common models.""" -from __future__ import absolute_import as _abs -import os -import sys -import importlib -from caffe2.python.models.download import ModelDownloader -from . import squeezenet - -models = [ - "squeezenet", - "resnet50", - "vgg19", -] - -mf = ModelDownloader() - - -class Model: - def __init__(self, model_name): - self.init_net, self.predict_net, self.value_info = mf.get_c2_model(model_name) - - -for model in models: - try: - locals()["c2_" + model] = importlib.import_module("caffe2.python.models." + model) - except ImportError: - locals()["c2_" + model] = Model(model) - -# squeezenet -def relay_squeezenet(): - return squeezenet.get_workload() diff --git a/tests/python/frontend/caffe2/model_zoo/squeezenet.py b/tests/python/frontend/caffe2/model_zoo/squeezenet.py deleted file mode 100644 index 06e99567e5a8..000000000000 --- a/tests/python/frontend/caffe2/model_zoo/squeezenet.py +++ /dev/null @@ -1,135 +0,0 @@ -# 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. - -# coding: utf-8 -# pylint: disable=unused-argument - -""" -Symbol of SqueezeNet - -Reference: -Iandola, Forrest N., et al. -"Squeezenet: Alexnet-level accuracy with 50x fewer parameters and< 0.5 mb model size." (2016). -""" - -from tvm import relay -from tvm.relay.testing import create_workload - -# Helpers -def _make_fire(net, squeeze_channels, expand1x1_channels, expand3x3_channels, prefix=""): - net = _make_fire_conv(net, squeeze_channels, 1, 0, f"{prefix}/squeeze1x1") - - left = _make_fire_conv(net, expand1x1_channels, 1, 0, f"{prefix}/expand1x1") - right = _make_fire_conv(net, expand3x3_channels, 3, 1, f"{prefix}/expand3x3") - # NOTE : Assume NCHW layout here - net = relay.concatenate((left, right), axis=1) - return net - - -def _make_fire_conv(net, channels, kernel_size, padding=0, prefix=""): - net = relay.nn.conv2d( - net, - relay.var(f"{prefix}_weight"), - channels=channels, - kernel_size=(kernel_size, kernel_size), - padding=(padding, padding), - ) - net = relay.nn.bias_add(net, relay.var(f"{prefix}_bias")) - net = relay.nn.relu(net) - return net - - -# Net -def get_net(batch_size, image_shape, num_classes, dtype): - """Get symbol of SqueezeNet - - Parameters - ---------- - batch_size : int - The batch size used in the model - - image_shape : tuple - The input image shape - - num_classes: int - The number of classification results - - dtype : str - The data type - - """ - data_shape = (batch_size,) + image_shape - net = relay.var("data", shape=data_shape, dtype=dtype) - net = relay.nn.conv2d( - net, - relay.var("conv1_weight"), - channels=64, - kernel_size=(3, 3), - strides=(2, 2), - padding=(0, 0), - ) - net = relay.nn.bias_add(net, relay.var("conv1_bias")) - net = relay.nn.relu(net) - net = relay.nn.max_pool2d(net, pool_size=(3, 3), strides=(2, 2)) - net = _make_fire(net, 16, 64, 64, "fire2") - net = _make_fire(net, 16, 64, 64, "fire3") - net = relay.nn.max_pool2d(net, pool_size=(3, 3), strides=(2, 2)) - net = _make_fire(net, 32, 128, 128, "fire4") - net = _make_fire(net, 32, 128, 128, "fire5") - net = relay.nn.max_pool2d(net, pool_size=(3, 3), strides=(2, 2)) - net = _make_fire(net, 48, 192, 192, "fire6") - net = _make_fire(net, 48, 192, 192, "fire7") - net = _make_fire(net, 64, 256, 256, "fire8") - net = _make_fire(net, 64, 256, 256, "fire9") - net = relay.nn.dropout(net, rate=0.5) - net = relay.nn.conv2d(net, relay.var("conv10_weight"), channels=num_classes, kernel_size=(1, 1)) - net = relay.nn.bias_add(net, relay.var("conv10_bias")) - net = relay.nn.relu(net) - net = relay.nn.global_avg_pool2d(net) - net = relay.nn.softmax(net, axis=1) - args = relay.analysis.free_vars(net) - return relay.Function(args, net) - - -def get_workload(batch_size=1, image_shape=(3, 224, 224), num_classes=1000, dtype="float32"): - """Get benchmark workload for SqueezeNet - - Parameters - ---------- - batch_size : int, optional - The batch size used in the model - - num_classes : int, optional - Number of classes - - image_shape : tuple, optional - The input image shape - - dtype : str, optional - The data type - - Returns - ------- - net : relay.Function - The computational graph - - params : dict of str to NDArray - The parameters. - """ - - net = get_net(batch_size, image_shape, num_classes, dtype) - return create_workload(net) diff --git a/tests/python/frontend/caffe2/test_forward.py b/tests/python/frontend/caffe2/test_forward.py deleted file mode 100644 index 9758d937c254..000000000000 --- a/tests/python/frontend/caffe2/test_forward.py +++ /dev/null @@ -1,257 +0,0 @@ -# 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. -""" -Caffe2 testcases -==================== -This article is a test script to test Caffe2 operator with Relay. -""" -from collections import namedtuple -import numpy as np - -from caffe2.python import workspace, core -from caffe2.proto import caffe2_pb2 -from model_zoo import c2_squeezenet, c2_resnet50, c2_vgg19 -import tvm -from tvm.contrib import graph_executor -from tvm import relay - -import tvm.testing - - -def get_tvm_output(model, input_data, target, device, output_shape, output_dtype="float32"): - """Generic function to execute and get tvm output""" - # supporting multiple inputs in caffe2 in a bit tricky, - # because the input names can appear at the beginning or end of model.predict_net.external_input - assert isinstance(input_data, np.ndarray) - - # here we use the first input blob to the first op to get the input name - input_names = model.predict_net.op[0].input[0] - shape_dict = {input_names: input_data.shape} - dtype_dict = {input_names: input_data.dtype} - mod, params = relay.frontend.from_caffe2( - model.init_net, model.predict_net, shape_dict, dtype_dict - ) - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target, params=params) - - m = graph_executor.GraphModule(lib["default"](device)) - - # set inputs - m.set_input(input_names, tvm.nd.array(input_data.astype(input_data.dtype))) - - # execute - m.run() - - # get outputs - if isinstance(output_shape, list) and isinstance(output_dtype, list): - tvm_output_list = [] - for i, s in enumerate(output_shape): - tvm_output = m.get_output(i, tvm.nd.empty((s), output_dtype[i])) - tvm_output_list.append(tvm_output.numpy()) - return tvm_output_list - else: - tvm_output = m.get_output(0, tvm.nd.empty((output_shape), output_dtype)) - return tvm_output.numpy() - - -def get_caffe2_output(model, x, dtype="float32"): - workspace.RunNetOnce(model.init_net) - - input_blob = model.predict_net.op[0].input[0] - workspace.FeedBlob(input_blob, x.astype(dtype)) - workspace.RunNetOnce(model.predict_net) - - output_blob = model.predict_net.external_output[0] - c2_output = workspace.FetchBlob(output_blob) - return c2_output - - -def verify_caffe2_forward_impl(model, data_shape, out_shape): - dtype = "float32" - data = np.random.uniform(size=data_shape).astype(dtype) - c2_out = get_caffe2_output(model, data, dtype) - for target, dev in tvm.testing.enabled_targets(): - tvm_out = get_tvm_output(model, data, target, dev, out_shape, dtype) - tvm.testing.assert_allclose(c2_out, tvm_out, rtol=1e-5, atol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_squeezenet1_1(): - verify_caffe2_forward_impl(c2_squeezenet, (1, 3, 224, 224), (1, 1000, 1, 1)) - - -@tvm.testing.uses_gpu -def test_forward_resnet50(): - verify_caffe2_forward_impl(c2_resnet50, (1, 3, 224, 224), (1, 1000)) - - -@tvm.testing.uses_gpu -def test_forward_vgg19(): - verify_caffe2_forward_impl(c2_vgg19, (1, 3, 224, 224), (1, 1000)) - - -Model = namedtuple("Model", ["init_net", "predict_net"]) - - -@tvm.testing.uses_gpu -def test_elementwise_add(): - """Elewise_add""" - data_shape = (1, 16, 9, 9) - init_net = caffe2_pb2.NetDef() - init_net.name = "test_init_net" - init_net.external_output[:] = ["A", "B"] - init_net.op.extend( - [ - core.CreateOperator( - "GivenTensorFill", - [], - ["A"], - shape=data_shape, - values=np.random.uniform(size=data_shape).flatten().tolist(), - ), - core.CreateOperator( - "GivenTensorFill", - [], - ["B"], - shape=data_shape, - values=np.random.uniform(size=data_shape).flatten().tolist(), - ), - ] - ) - - predict_net = caffe2_pb2.NetDef() - predict_net.name = "test_predict_net" - predict_net.external_input[:] = ["A", "B"] - predict_net.external_output[:] = ["C"] - predict_net.op.extend( - [ - core.CreateOperator( - "Add", - ["A", "B"], - ["C"], - ) - ] - ) - - model = Model(init_net, predict_net) - verify_caffe2_forward_impl(model, data_shape, data_shape) - - -@tvm.testing.uses_gpu -def test_elementwise_add_with_broadcast(): - """Elewise_add_with_broadcast""" - data_shape = (1, 16, 9, 9) - init_net = caffe2_pb2.NetDef() - init_net.name = "test_init_net" - init_net.external_output[:] = ["A", "B"] - init_net.op.extend( - [ - core.CreateOperator( - "GivenTensorFill", - [], - ["A"], - shape=data_shape, - values=np.random.uniform(size=data_shape).flatten().tolist(), - ), - core.CreateOperator( - "GivenTensorFill", - [], - ["B"], - shape=(1,), - values=np.random.uniform(size=1).flatten().tolist(), - ), - ] - ) - - predict_net = caffe2_pb2.NetDef() - predict_net.name = "test_predict_net" - predict_net.external_input[:] = ["A", "B"] - predict_net.external_output[:] = ["C"] - predict_net.op.extend( - [ - core.CreateOperator( - "Add", - ["A", "B"], - ["C"], - broadcast=1, - ) - ] - ) - - model = Model(init_net, predict_net) - verify_caffe2_forward_impl(model, data_shape, data_shape) - - -@tvm.testing.uses_gpu -def test_normalize_yuv(): - """Normalize_yuv""" - data_shape = (1, 3, 96, 96) - init_net = caffe2_pb2.NetDef() - init_net.name = "test_init_net" - init_net.external_output[:] = ["A", "mean", "std"] - init_net.op.extend( - [ - core.CreateOperator( - "GivenTensorFill", - [], - ["A"], - shape=data_shape, - values=np.random.uniform(size=data_shape).flatten().tolist(), - ), - core.CreateOperator( - "GivenTensorFill", - [], - ["mean"], - shape=( - 1, - 3, - ), - values=np.random.uniform(size=3).flatten().tolist(), - ), - core.CreateOperator( - "GivenTensorFill", - [], - ["std"], - shape=( - 1, - 3, - ), - values=np.random.uniform(size=3).flatten().tolist(), - ), - ] - ) - - predict_net = caffe2_pb2.NetDef() - predict_net.name = "test_predict_net" - predict_net.external_input[:] = ["A", "mean", "std"] - predict_net.external_output[:] = ["C"] - predict_net.op.extend( - [ - core.CreateOperator( - "NormalizePlanarYUV", - ["A", "mean", "std"], - ["C"], - ) - ] - ) - - model = Model(init_net, predict_net) - verify_caffe2_forward_impl(model, data_shape, data_shape) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/caffe2/test_graph.py b/tests/python/frontend/caffe2/test_graph.py deleted file mode 100644 index 3bf5beff3fce..000000000000 --- a/tests/python/frontend/caffe2/test_graph.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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. -"""Test graph equality of caffe2 models.""" -from model_zoo import c2_squeezenet, relay_squeezenet -import tvm -from tvm import relay -from tvm.relay import transform - - -def compare_graph(lhs_mod, rhs_mod): - lhs_mod = transform.InferType()(lhs_mod) - rhs_mod = transform.InferType()(rhs_mod) - tvm.ir.assert_structural_equal(lhs_mod["main"], rhs_mod["main"]) - - -def test_squeeze_net(): - shape_dict = {"data": (1, 3, 224, 224)} - dtype_dict = {"data": "float32"} - mod, _, = relay.frontend.from_caffe2( - c2_squeezenet.init_net, c2_squeezenet.predict_net, shape_dict, dtype_dict - ) - relay_mod, _ = relay_squeezenet() - compare_graph(mod, relay_mod) - - -if __name__ == "__main__": - test_squeeze_net() diff --git a/tests/python/frontend/coreml/model_zoo/__init__.py b/tests/python/frontend/coreml/model_zoo/__init__.py deleted file mode 100644 index ea2f3478fde4..000000000000 --- a/tests/python/frontend/coreml/model_zoo/__init__.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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. -"""coreml model zoo for testing purposes.""" -import os -from PIL import Image -import numpy as np -from tvm.contrib.download import download_testdata - - -def get_mobilenet(): - url = "https://docs-assets.developer.apple.com/coreml/models/MobileNet.mlmodel" - dst = "mobilenet.mlmodel" - real_dst = download_testdata(url, dst, module="coreml") - return os.path.abspath(real_dst) - - -def get_resnet50(): - url = "https://docs-assets.developer.apple.com/coreml/models/Resnet50.mlmodel" - dst = "resnet50.mlmodel" - real_dst = download_testdata(url, dst, module="coreml") - return os.path.abspath(real_dst) - - -def get_cat_image(): - """Get cat image""" - url = ( - "https://gist.githubusercontent.com/zhreshold/" - + "bcda4716699ac97ea44f791c24310193/raw/fa7ef0e9c9a5daea686d6473a62aacd1a5885849/cat.png" - ) - dst = "cat.png" - real_dst = download_testdata(url, dst, module="data") - img = Image.open(real_dst).resize((224, 224)) - # CoreML's standard model image format is BGR - img_bgr = np.array(img)[:, :, ::-1] - img = np.transpose(img_bgr, (2, 0, 1))[np.newaxis, :] - return np.asarray(img) diff --git a/tests/python/frontend/coreml/test_forward.py b/tests/python/frontend/coreml/test_forward.py deleted file mode 100644 index 26ddcba6ef41..000000000000 --- a/tests/python/frontend/coreml/test_forward.py +++ /dev/null @@ -1,851 +0,0 @@ -# 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. -""" -CoreML testcases -==================== -This article is a test script to test CoreML operator with Relay. -""" -from os import path -from enum import Enum -import tempfile -import numpy as np -import model_zoo -import coremltools as cm -from coremltools.models.neural_network import NeuralNetworkBuilder -from coremltools.models import datatypes -from tensorflow import keras - -import tvm -import tvm.topi.testing -import tvm.testing -from tvm.contrib import graph_executor -from tvm.topi.testing import conv2d_nchw_python -from tvm import relay - - -def get_tvm_output( - func, x, params, target, device, out_shape=(1, 1000), input_name="image", dtype="float32" -): - """Generic function to execute and get tvm output""" - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(func, target, params=params) - m = graph_executor.GraphModule(lib["default"](device)) - # set inputs - m.set_input(input_name, tvm.nd.array(x.astype(dtype))) - m.run() - # get outputs - out = m.get_output(0, tvm.nd.empty(out_shape, dtype)) - return out.numpy() - - -def run_model_checkonly(model_file, model_name="", input_name="image"): - model = cm.models.MLModel(model_file) - x = model_zoo.get_cat_image() - shape_dict = {input_name: x.shape} - # Some Relay passes change operators on the fly. Ensuring that we generate - # new graph for each target. - for target, dev in tvm.testing.enabled_targets(): - mod, params = relay.frontend.from_coreml(model, shape_dict) - tvm_output = get_tvm_output(mod["main"], x, params, target, dev) - print(target, dev, model_name, "prediction id: ", np.argmax(tvm_output.flat)) - - -@tvm.testing.uses_gpu -def test_mobilenet_checkonly(): - model_file = model_zoo.get_mobilenet() - run_model_checkonly(model_file, "mobilenet") - - -@tvm.testing.uses_gpu -def test_resnet50_checkonly(): - model_file = model_zoo.get_resnet50() - run_model_checkonly(model_file, "resnet50") - - -def run_tvm_graph( - coreml_model, target, device, input_data, input_name, output_shape, output_dtype="float32" -): - """Generic function to compile on relay and execute on tvm""" - if isinstance(input_data, list): - shape_dict = {} - dtype_dict = {} - for i, inp in enumerate(input_name): - shape_dict[inp] = input_data[i].shape - dtype_dict[inp] = input_data[i].dtype - else: - shape_dict = {input_name: input_data.shape} - dtype_dict = {input_name: input_data.dtype} - - mod, params = relay.frontend.from_coreml(coreml_model, shape_dict) - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target, params=params) - - m = graph_executor.GraphModule(lib["default"](device)) - # set inputs - if isinstance(input_data, list): - for i, inp in enumerate(input_name): - m.set_input(inp, tvm.nd.array(input_data[i].astype(input_data[i].dtype))) - else: - m.set_input(input_name, tvm.nd.array(input_data.astype(input_data.dtype))) - - # execute - m.run() - # get outputs - if isinstance(output_shape, list) and isinstance(output_dtype, list): - tvm_output_list = [] - for i, s in enumerate(output_shape): - tvm_output = m.get_output(i, tvm.nd.empty((s), output_dtype[i])) - tvm_output_list.append(tvm_output.numpy()) - return tvm_output_list - else: - if not output_shape: - tvm_output = m.get_output(0) - else: - tvm_output = m.get_output(0, tvm.nd.empty((output_shape), output_dtype)) - return tvm_output.numpy() - - -def verify_add_layer_params(input_dim, alpha=2): - """Verify add layer params""" - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - - b_np = np.add(a_np1, a_np2) + alpha - inputs = [("input1", datatypes.Array(*input_dim)), ("input2", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="Add", alpha=alpha, input_names=["input1", "input2"], output_name="output", mode="ADD" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np1, a_np2], ["input1", "input2"], b_np.shape, dtype - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_add_layer_params(): - verify_add_layer_params((1, 2, 2), 0) - verify_add_layer_params((1, 2, 2), 1) - verify_add_layer_params((1, 3, 3), 2) - - -def verify_multiply_layer_params(input_dim, alpha): - """Verify multiply layer params""" - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - - b_np = np.multiply(a_np1, a_np2) * alpha - inputs = [("input1", datatypes.Array(*input_dim)), ("input2", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="Mul", - alpha=alpha, - input_names=["input1", "input2"], - output_name="output", - mode="MULTIPLY", - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np1, a_np2], ["input1", "input2"], b_np.shape, dtype - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_multiply_layer_params(): - verify_multiply_layer_params((1, 2, 2), 0) - verify_multiply_layer_params((1, 2, 2), 1) - verify_multiply_layer_params((1, 3, 3), 2) - - -def verify_concat_layer_params(input1_dim, input2_dim): - """Verify concat layer params""" - dtype = "float32" - - a_np1 = np.random.uniform(size=input1_dim).astype(dtype) - a_np2 = np.random.uniform(size=input2_dim).astype(dtype) - - b_np = np.concatenate((a_np1, a_np2), axis=1) - inputs = [("input1", datatypes.Array(*input1_dim)), ("input2", datatypes.Array(*input2_dim))] - output = [("output", datatypes.Array(*b_np.shape))] # pylint:disable=not-an-iterable - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="Concate", input_names=["input1", "input2"], output_name="output", mode="CONCAT" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np1, a_np2], ["input1", "input2"], b_np.shape, dtype - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_concat_layer_params(): - verify_concat_layer_params((1, 1, 2, 2), (1, 2, 2, 2)) - verify_concat_layer_params((1, 2, 4, 4), (1, 3, 4, 4)) - - -def _verify_upsample_layer_params(input_dim, scale, mode): - dtype = "float32" - - a_np = np.full(input_dim, 1, dtype=dtype) - - if mode == "NN": - method = "nearest_neighbor" - coord_trans = "asymmetric" - else: - method = "linear" - coord_trans = "align_corners" - - b_np = tvm.topi.testing.resize2d_python(a_np, (scale, scale), "NCHW", method, coord_trans) - - input_data = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(input_data, output) - builder.add_upsample( - name="Upsample", - scaling_factor_h=scale, - scaling_factor_w=scale, - mode=mode, - input_name="input", - output_name="output", - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, a_np, "input", b_np.shape, dtype) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_upsample_layer_params(): - """Upsample Layer Params""" - _verify_upsample_layer_params((1, 16, 32, 32), 2, "NN") - _verify_upsample_layer_params((1, 4, 6, 6), 3, "BILINEAR") - - -def _verify_l2_normalize(input_dim, eps): - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - b_np = tvm.topi.testing.l2_normalize_python(a_np, eps, 1) - - input_data = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(input_data, output) - builder.add_l2_normalize(name="L2", epsilon=eps, input_name="input", output_name="output") - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, a_np, "input", b_np.shape, dtype) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_l2_normalize(): - _verify_l2_normalize((1, 3, 20, 20), 0.001) - - -def _verify_lrn(input_dim, size, bias, alpha, beta): - dtype = "float32" - axis = 1 - a_np = np.random.uniform(size=input_dim).astype(dtype) - b_np = tvm.topi.testing.lrn_python(a_np, size, axis, bias, alpha, beta) - - input_data = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(input_data, output) - builder.add_lrn( - name="LRN", - input_name="input", - output_name="output", - alpha=alpha, - beta=beta, - k=bias, - local_size=size, - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, a_np, "input", b_np.shape, dtype) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_lrn(): - _verify_lrn((1, 3, 10, 20), 3, 1.0, 1.0, 0.5) - - -def _verify_average(input_dim1, input_dim2, axis=0): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim1).astype(dtype) - a_np2 = np.random.uniform(size=input_dim2).astype(dtype) - - b_np = np.mean((a_np1, a_np2), axis=axis, dtype=float) - - inputs = [("input1", datatypes.Array(*input_dim1)), ("input2", datatypes.Array(*input_dim2))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="MEAN", input_names=["input1", "input2"], output_name="output", mode="AVE" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np1, a_np2], ["input1", "input2"], b_np.shape, dtype - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_average(): - _verify_average((1, 3, 20, 20), (1, 3, 20, 20)) - # disable tests for now because ValueError: setting an array element with a sequence. - # The requested array has an inhomogeneous shape after 1 dimensions. The detected shape - # was (2,) + inhomogeneous part. - # _verify_average((3, 20, 20), (1, 3, 20, 20)) - # _verify_average((20, 20), (1, 3, 20, 20)) - - -def _verify_max(input_dim): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - a_np3 = np.random.uniform(size=input_dim).astype(dtype) - - b_np = np.max((a_np1, a_np2, a_np3), axis=0) - - inputs = [ - ("input1", datatypes.Array(*input_dim)), - ("input2", datatypes.Array(*input_dim)), - ("input3", datatypes.Array(*input_dim)), - ] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="Max", input_names=["input1", "input2", "input3"], output_name="output", mode="MAX" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, - target, - dev, - [a_np1, a_np2, a_np3], - ["input1", "input2", "input3"], - b_np.shape, - dtype, - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_max(): - _verify_max((1, 3, 20, 20)) - _verify_max((20, 20)) - - -def _verify_min(input_dim): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - a_np3 = np.random.uniform(size=input_dim).astype(dtype) - - b_np = np.min((a_np1, a_np2, a_np3), axis=0) - - inputs = [ - ("input1", datatypes.Array(*input_dim)), - ("input2", datatypes.Array(*input_dim)), - ("input3", datatypes.Array(*input_dim)), - ] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_elementwise( - name="Min", input_names=["input1", "input2", "input3"], output_name="output", mode="MIN" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, - target, - dev, - [a_np1, a_np2, a_np3], - ["input1", "input2", "input3"], - b_np.shape, - dtype, - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_min(): - _verify_min((1, 3, 20, 20)) - _verify_min((20, 20)) - - -def verify_unary_sqrt(input_dim): - """Verify unary sqrt""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = np.sqrt(a_np) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary(name="sqrt", input_name="input", output_name="output", mode="sqrt") - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_rsqrt(input_dim, epsilon=0): - """Verify unary rsqrt""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = 1 / np.sqrt(a_np + epsilon) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary( - name="rsqrt", input_name="input", output_name="output", mode="rsqrt", epsilon=epsilon - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_inverse(input_dim, epsilon=0): - """Verify unary inverse""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = 1 / (a_np + epsilon) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary( - name="inverse", input_name="input", output_name="output", mode="inverse", epsilon=epsilon - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_power(input_dim, alpha): - """Verify unary power""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = np.power(a_np, alpha) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary( - name="power", input_name="input", output_name="output", mode="power", alpha=alpha - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_exp(input_dim): - """Verify unary exp""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = np.exp(a_np) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary(name="exp", input_name="input", output_name="output", mode="exp") - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_log(input_dim): - """Verify unary log""" - dtype = "float32" - - a_np = np.random.uniform(size=input_dim).astype(dtype) - ref_val = np.log(a_np) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary(name="log", input_name="input", output_name="output", mode="log") - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_abs(input_dim): - """Verify unary abs""" - dtype = "float32" - - a_np = np.random.uniform(-100.0, 100.0, size=input_dim).astype(dtype) - ref_val = np.abs(a_np) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary(name="abs", input_name="input", output_name="output", mode="abs") - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def verify_unary_threshold(input_dim, alpha): - """Verify unary threshold""" - dtype = "float32" - - a_np = np.random.uniform(-100.0, 100.0, size=input_dim).astype(dtype) - ref_val = np.maximum(a_np, alpha) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_unary( - name="threshold", input_name="input", output_name="output", mode="threshold", alpha=alpha - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_unary(): - """All unary""" - verify_unary_sqrt((1, 3, 20, 20)) - verify_unary_rsqrt((1, 3, 20, 20)) - verify_unary_rsqrt((1, 3, 20, 20), epsilon=1e-6) - verify_unary_inverse((1, 3, 20, 20)) - verify_unary_inverse((1, 3, 20, 20), epsilon=1e-6) - verify_unary_power((1, 3, 20, 20), alpha=0.5) - verify_unary_power((1, 3, 20, 20), alpha=4) - verify_unary_exp((1, 3, 20, 20)) - verify_unary_log((1, 3, 20, 20)) - verify_unary_abs((1, 3, 20, 20)) - verify_unary_threshold((1, 3, 20, 20), alpha=-6.0) - verify_unary_threshold((1, 3, 20, 20), alpha=5.0) - - -@tvm.testing.uses_gpu -def test_forward_reduce(): - """Reduce""" - - class ReduceAxis(Enum): - # pylint: disable=invalid-name - CHW = 0 - HW = 1 - C = 2 - H = 3 - W = 4 - - def _verify_reduce(input_dim, mode, axis, ref_func, dtype="float32"): - print(input_dim, mode, axis) - a_np = np.random.uniform(size=input_dim).astype(dtype) - - # translate to axis from coreml format - if axis == ReduceAxis.CHW: - np_axis = (-3, -2, -1) - elif axis == ReduceAxis.HW: - np_axis = (-2, -1) - elif axis == ReduceAxis.C: - np_axis = -3 - elif axis == ReduceAxis.H: - np_axis = -2 - elif axis == ReduceAxis.W: - np_axis = -1 - - if ref_func is np.argmax: - ref_val = np.expand_dims(ref_func(a_np, np_axis), np_axis).astype(dtype) - else: - ref_val = ref_func(a_np, np_axis, keepdims=True) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_reduce( - name=mode, input_name="input", output_name="output", axis=axis.name, mode=mode - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5, atol=1e-5) - - dshapes = [[10, 10], [1, 10, 10], [1, 3, 10, 10]] - for dshape in dshapes: - for axis in ReduceAxis: - if len(dshape) < 3 and axis in [ReduceAxis.CHW, ReduceAxis.C]: - # input must have rank at least 3 - continue - _verify_reduce(dshape, "sum", axis, np.sum) - _verify_reduce(dshape, "avg", axis, np.mean) - _verify_reduce(dshape, "prod", axis, np.prod) - _verify_reduce(dshape, "min", axis, np.min) - _verify_reduce(dshape, "max", axis, np.max) - if axis in [ReduceAxis.C, ReduceAxis.H, ReduceAxis.W]: - # For mode ArgMax, axis must be [-1] or [-2] or [-3] - _verify_reduce(dshape, "argmax", axis, np.argmax, dtype="int32") - - -def verify_reshape(input_dim, target_shape, mode): - """Reshape""" - dtype = "float32" - - a_np = np.random.uniform(-100.0, 100.0, size=input_dim).astype(dtype) - ref_val = np.reshape(a_np, target_shape) - - inputs = [("input", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*ref_val.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.add_reshape( - name="reshape", - input_name="input", - output_name="output", - target_shape=target_shape, - mode=mode, - ) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input"], ref_val.shape, dtype) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def test_forward_reshape(): - for mode in [0, 1]: - verify_reshape((20,), (1, 2, 2, 5), mode) - verify_reshape((1, 3, 20, 20), (1, 12, 10, 10), mode) - - -def _verify_split(input_dim, out_nums): - dtype = "float32" - - a_np = np.random.uniform(-100.0, 100.0, size=input_dim).astype(dtype) - ref_val = np.split(a_np, out_nums, axis=-3) - - inputs = [("input", datatypes.Array(*input_dim))] - - output_names = [] - outputs = [] - output_shapes = [] - for i, out in enumerate(ref_val): - output_name = "output" + str(i) - output_names = output_names + [output_name] - outputs = outputs + [(output_name, datatypes.Array(*out.shape))] - output_shapes = output_shapes + [out.shape] - - builder = NeuralNetworkBuilder(inputs, outputs) - builder.add_split(name="split", input_name="input", output_names=output_names) - - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np], ["input"], output_shapes, [dtype] * len(output_shapes) - ) - tvm.testing.assert_allclose(out, ref_val, rtol=1e-5) - - -def test_forward_split(): - """Split""" - _verify_split( - ( - 1, - 4, - 4, - 4, - ), - 2, - ) - _verify_split( - ( - 1, - 3, - 30, - 20, - ), - 3, - ) - - -def verify_image_scaler(input_dim, blue_bias=0.0, green_bias=0.0, red_bias=0.0, image_scale=1.0): - """Verify image scaler""" - dtype = "float32" - a_np = np.random.uniform(size=input_dim).astype(dtype) - # make sure it is valid image format CHW. - assert len(a_np.shape) == 3 and a_np.shape[0] == 3 - b_np = np.zeros(a_np.shape, dtype=dtype) - b_np[0, :, :] = image_scale * a_np[0, :, :] + blue_bias - b_np[1, :, :] = image_scale * a_np[1, :, :] + green_bias - b_np[2, :, :] = image_scale * a_np[2, :, :] + red_bias - b_np = np.add(a_np, b_np) - inputs = [("input1", datatypes.Array(*input_dim)), ("input2", datatypes.Array(*input_dim))] - output = [("output", datatypes.Array(*b_np.shape))] - builder = NeuralNetworkBuilder(inputs, output) - builder.set_pre_processing_parameters( - image_input_names=["input1"], - is_bgr=True, - blue_bias=blue_bias, - green_bias=green_bias, - red_bias=red_bias, - image_scale=image_scale, - ) - # add one add layer to make CoreML model format valid - # add layer has been tested before. - builder.add_elementwise( - name="add", input_names=["input1", "input2"], output_name="output", alpha=0, mode="ADD" - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph( - model, target, dev, [a_np, a_np], ["input1", "input2"], b_np.shape, dtype - ) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_image_scaler(): - verify_image_scaler((3, 224, 224), image_scale=0.17) - verify_image_scaler( - (3, 224, 224), - blue_bias=-1.7669800519943237, - green_bias=-1.985260009765625, - red_bias=-2.102560043334961, - image_scale=0.379, - ) - - -def verify_convolution(input_dim, filter_, padding): - """Verify convolution""" - dtype = "float32" - _, c, h, width = input_dim - out_c, _, kernel_h, kernel_w = filter_ - a_np = np.random.uniform(size=input_dim).astype(dtype) - w_np = np.random.uniform(size=(out_c, c, kernel_h, kernel_w)).astype(dtype) - w_np_cm = np.transpose(w_np, axes=(2, 3, 1, 0)) - b_np = conv2d_nchw_python(a_np, w_np, [1, 1], padding) - inputs = [("input1", datatypes.Array(c, h, width))] - output = [("output", datatypes.Array(*b_np.shape))] # pylint:disable=not-an-iterable - builder = NeuralNetworkBuilder(inputs, output) - builder.add_convolution( - name="conv", - kernel_channels=3, - output_channels=out_c, - height=kernel_h, - width=kernel_w, - stride_height=1, - stride_width=1, - border_mode=padding.lower(), - groups=1, - W=w_np_cm, - b=None, - has_bias=False, - is_deconv=False, - input_name="input1", - output_name="output", - ) - model = cm.models.MLModel(builder.spec) - for target, dev in tvm.testing.enabled_targets(): - out = run_tvm_graph(model, target, dev, [a_np], ["input1"], output_shape=None) - tvm.testing.assert_allclose(out, b_np, rtol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_convolution(): - verify_convolution((1, 3, 224, 224), filter_=(32, 3, 3, 3), padding="VALID") - verify_convolution((1, 3, 224, 224), filter_=(32, 3, 3, 3), padding="SAME") - - -def test_can_build_keras_to_coreml_to_relay(): - """Test multiple conversion paths and importing from a saved file.""" - model = keras.models.Sequential() - model.add( - keras.layers.Conv2D( - filters=6, - kernel_size=(1, 1), - activation="relu", - padding="same", - input_shape=(3, 3, 1), - data_format="channels_first", - ) - ) - - with tempfile.TemporaryDirectory() as tmpdir: - kmodel_fn = path.join(tmpdir, "c1mdl.h5") - model.save(kmodel_fn) - - mdl = cm.convert( - kmodel_fn, convert_to="neuralnetwork", minimum_deployment_target=cm.target.macOS11 - ) - model_file = path.join(tmpdir, "c1.mlmodel") - mdl.save(model_file) - - mdl = cm.models.MLModel(model_file) - desc = mdl.get_spec().description - iname = desc.input[0].name - ishape = desc.input[0].type.multiArrayType.shape - shape_dict = {} - for i in mdl.get_spec().description.input: - iname = i.name - ishape = i.type.multiArrayType.shape - shape_dict[iname] = ishape - mod, params = relay.frontend.from_coreml(mdl, shape_dict) - - with tvm.transform.PassContext(opt_level=3): - relay.build(mod, "llvm", params=params) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/darknet/test_forward.py b/tests/python/frontend/darknet/test_forward.py deleted file mode 100644 index e78e35ff5c7c..000000000000 --- a/tests/python/frontend/darknet/test_forward.py +++ /dev/null @@ -1,537 +0,0 @@ -# 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. -# pylint: disable=unused-argument -""" -Test Darknet Models -=================== -This article is a test script to test darknet models with Relay. -All the required models and libraries will be downloaded from the internet -by the script. -""" -from cffi import FFI -import numpy as np -import tvm -from tvm.contrib import graph_executor -from tvm.contrib.download import download_testdata - -from tvm.relay.testing.darknet import LAYERTYPE -from tvm.relay.testing.darknet import __darknetffi__ -from tvm.relay.frontend.darknet import ACTIVATION -from tvm import relay - -REPO_URL = "https://github.com/dmlc/web-data/blob/main/darknet/" - -# Lazily initialized -DARKNET_TEST_IMAGE_PATH = None -LIB = None - - -def _lib(): - global LIB - lib = "libdarknet2.0.so" - url = REPO_URL + "lib/" + lib + "?raw=true" - if LIB is None: - LIB = __darknetffi__.dlopen(download_testdata(url, lib, module="darknet")) - - return LIB - - -def _darknet_test_image_path(): - global DARKNET_TEST_IMAGE_PATH - if DARKNET_TEST_IMAGE_PATH is None: - name = "dog.jpg" - url = REPO_URL + "data/" + name + "?raw=true" - DARKNET_TEST_IMAGE_PATH = download_testdata(url, name, module="data") - return DARKNET_TEST_IMAGE_PATH - - -def astext(program, unify_free_vars=False): - """check that program is parsable in text format""" - text = program.astext() - if isinstance(program, relay.Expr): - roundtrip_program = tvm.relay.parse_expr(text) - else: - roundtrip_program = tvm.relay.fromtext(text) - - tvm.ir.assert_structural_equal(roundtrip_program, program, map_free_vars=True) - - -def _read_memory_buffer(shape, data, dtype="float32"): - length = 1 - for x in shape: - length *= x - data_np = np.zeros(length, dtype=dtype) - for i in range(length): - data_np[i] = data[i] - return data_np.reshape(shape) - - -def _get_tvm_output(net, data, build_dtype="float32", states=None): - """Compute TVM output""" - dtype = "float32" - mod, params = relay.frontend.from_darknet(net, data.shape, dtype) - # verify that from_darknet creates a valid, parsable relay program - mod = relay.transform.InferType()(mod) - astext(mod) - - target = "llvm" - lib = relay.build(mod, target, params=params) - - # Execute on TVM - dev = tvm.cpu(0) - m = graph_executor.GraphModule(lib["default"](dev)) - # set inputs - m.set_input("data", tvm.nd.array(data.astype(dtype))) - if states: - for name in states.keys(): - m.set_input(name, tvm.nd.array(states[name].astype(dtype))) - m.run() - # get outputs - tvm_out = [] - for i in range(m.get_num_outputs()): - tvm_out.append(m.get_output(i).numpy()) - return tvm_out - - -def _load_net(cfg_url, cfg_name, weights_url, weights_name): - cfg_path = download_testdata(cfg_url, cfg_name, module="darknet") - weights_path = download_testdata(weights_url, weights_name, module="darknet") - net = _lib().load_network(cfg_path.encode("utf-8"), weights_path.encode("utf-8"), 0) - return net - - -def verify_darknet_frontend(net, build_dtype="float32"): - """Test network with given input image on both darknet and tvm""" - - def get_darknet_output(net, img): - _lib().network_predict_image(net, img) - out = [] - for i in range(net.n): - layer = net.layers[i] - if layer.type == LAYERTYPE.REGION: - attributes = np.array( - [ - layer.n, - layer.out_c, - layer.out_h, - layer.out_w, - layer.classes, - layer.coords, - layer.background, - ], - dtype=np.int32, - ) - out.insert(0, attributes) - out.insert(0, _read_memory_buffer((layer.n * 2,), layer.biases)) - layer_outshape = (layer.batch, layer.out_c, layer.out_h, layer.out_w) - out.insert(0, _read_memory_buffer(layer_outshape, layer.output)) - elif layer.type == LAYERTYPE.YOLO: - attributes = np.array( - [layer.n, layer.out_c, layer.out_h, layer.out_w, layer.classes, layer.total], - dtype=np.int32, - ) - out.insert(0, attributes) - out.insert(0, _read_memory_buffer((layer.total * 2,), layer.biases)) - out.insert(0, _read_memory_buffer((layer.n,), layer.mask, dtype="int32")) - layer_outshape = (layer.batch, layer.out_c, layer.out_h, layer.out_w) - out.insert(0, _read_memory_buffer(layer_outshape, layer.output)) - elif i == net.n - 1: - if layer.type == LAYERTYPE.CONNECTED: - darknet_outshape = (layer.batch, layer.out_c) - elif layer.type in [LAYERTYPE.SOFTMAX]: - darknet_outshape = (layer.batch, layer.outputs) - else: - darknet_outshape = (layer.batch, layer.out_c, layer.out_h, layer.out_w) - out.insert(0, _read_memory_buffer(darknet_outshape, layer.output)) - return out - - dtype = "float32" - - img = _lib().letterbox_image( - _lib().load_image_color(_darknet_test_image_path().encode("utf-8"), 0, 0), net.w, net.h - ) - darknet_output = get_darknet_output(net, img) - batch_size = 1 - data = np.empty([batch_size, img.c, img.h, img.w], dtype) - i = 0 - for c in range(img.c): - for h in range(img.h): - for k in range(img.w): - data[0][c][h][k] = img.data[i] - i = i + 1 - - tvm_out = _get_tvm_output(net, data, build_dtype) - for tvm_outs, darknet_out in zip(tvm_out, darknet_output): - tvm.testing.assert_allclose(darknet_out, tvm_outs, rtol=1e-3, atol=1e-3) - - -def _test_rnn_network(net, states): - """Test network with given input data on both darknet and tvm""" - - def get_darknet_network_predict(net, data): - return _lib().network_predict(net, data) - - ffi = FFI() - np_arr = np.zeros([1, net.inputs], dtype="float32") - np_arr[0, 2] = 1 - cffi_arr = ffi.cast("float*", np_arr.ctypes.data) - tvm_out = _get_tvm_output(net, np_arr, states=states)[0] - darknet_output = get_darknet_network_predict(net, cffi_arr) - darknet_out = np.zeros(net.outputs, dtype="float32") - for i in range(net.outputs): - darknet_out[i] = darknet_output[i] - last_layer = net.layers[net.n - 1] - darknet_outshape = (last_layer.batch, last_layer.outputs) - darknet_out = darknet_out.reshape(darknet_outshape) - tvm.testing.assert_allclose(darknet_out, tvm_out, rtol=1e-4, atol=1e-4) - - -def test_forward_extraction(): - """test extraction model""" - model_name = "extraction" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_alexnet(): - """test alexnet model""" - model_name = "alexnet" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_resnet50(): - """test resnet50 model""" - model_name = "resnet50" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_resnext50(): - """test resnet50 model""" - model_name = "resnext50" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_yolov2(): - """test yolov2 model""" - model_name = "yolov2" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - build_dtype = {} - verify_darknet_frontend(net, build_dtype) - _lib().free_network(net) - - -def test_forward_yolov3(): - """test yolov3 model""" - model_name = "yolov3" - cfg_name = model_name + ".cfg" - weights_name = model_name + ".weights" - cfg_url = "https://github.com/pjreddie/darknet/blob/master/cfg/" + cfg_name + "?raw=true" - weights_url = "http://pjreddie.com/media/files/" + weights_name + "?raw=true" - net = _load_net(cfg_url, cfg_name, weights_url, weights_name) - build_dtype = {} - verify_darknet_frontend(net, build_dtype) - _lib().free_network(net) - - -def test_forward_convolutional(): - """test convolutional layer""" - net = _lib().make_network(1) - layer = _lib().make_convolutional_layer(1, 224, 224, 3, 32, 1, 3, 2, 0, 1, 0, 0, 0, 0) - net.layers[0] = layer - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_dense(): - """test fully connected layer""" - net = _lib().make_network(1) - layer = _lib().make_connected_layer(1, 75, 20, 1, 0, 0) - net.layers[0] = layer - net.w = net.h = 5 - _lib().resize_network(net, 5, 5) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_dense_batchnorm(): - """test fully connected layer with batchnorm""" - net = _lib().make_network(1) - layer = _lib().make_connected_layer(1, 12, 2, 1, 1, 0) - for i in range(5): - layer.rolling_mean[i] = np.random.rand(1) - layer.rolling_variance[i] = np.random.rand(1) + 0.5 - layer.scales[i] = np.random.rand(1) - net.layers[0] = layer - net.w = net.h = 2 - _lib().resize_network(net, 2, 2) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_maxpooling(): - """test maxpooling layer""" - net = _lib().make_network(1) - layer = _lib().make_maxpool_layer(1, 224, 224, 3, 2, 2, 0) - net.layers[0] = layer - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_avgpooling(): - """test avgerage pooling layer""" - net = _lib().make_network(1) - layer = _lib().make_avgpool_layer(1, 224, 224, 3) - net.layers[0] = layer - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_conv_batch_norm(): - """test batch normalization layer""" - net = _lib().make_network(1) - layer = _lib().make_convolutional_layer(1, 224, 224, 3, 32, 1, 3, 2, 0, 1, 1, 0, 0, 0) - for i in range(32): - layer.rolling_mean[i] = np.random.rand(1) - layer.rolling_variance[i] = np.random.rand(1) + 0.5 - net.layers[0] = layer - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_shortcut(): - """test shortcut layer""" - net = _lib().make_network(3) - layer_1 = _lib().make_convolutional_layer(1, 224, 224, 3, 32, 1, 3, 2, 0, 1, 0, 0, 0, 0) - layer_2 = _lib().make_convolutional_layer(1, 111, 111, 32, 32, 1, 1, 1, 0, 1, 0, 0, 0, 0) - layer_3 = _lib().make_shortcut_layer(1, 0, 111, 111, 32, 111, 111, 32) - layer_3.activation = ACTIVATION.RELU - layer_3.alpha = 1 - layer_3.beta = 1 - net.layers[0] = layer_1 - net.layers[1] = layer_2 - net.layers[2] = layer_3 - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_reorg(): - """test reorg layer""" - net = _lib().make_network(2) - layer_1 = _lib().make_convolutional_layer(1, 222, 222, 3, 32, 1, 3, 2, 0, 1, 0, 0, 0, 0) - layer_2 = _lib().make_reorg_layer(1, 110, 110, 32, 2, 0, 0, 0) - net.layers[0] = layer_1 - net.layers[1] = layer_2 - net.w = net.h = 222 - _lib().resize_network(net, 222, 222) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_region(): - """test region layer""" - net = _lib().make_network(2) - layer_1 = _lib().make_convolutional_layer(1, 19, 19, 3, 425, 1, 1, 1, 0, 1, 0, 0, 0, 0) - layer_2 = _lib().make_region_layer(1, 19, 19, 5, 80, 4) - layer_2.softmax = 1 - net.layers[0] = layer_1 - net.layers[1] = layer_2 - net.w = net.h = 19 - _lib().resize_network(net, 19, 19) - build_dtype = {} - verify_darknet_frontend(net, build_dtype) - _lib().free_network(net) - - -def test_forward_yolo_op(): - """test yolo layer""" - net = _lib().make_network(2) - layer_1 = _lib().make_convolutional_layer(1, 224, 224, 3, 14, 1, 3, 2, 0, 1, 0, 0, 0, 0) - layer_2 = _lib().make_yolo_layer(1, 111, 111, 2, 9, __darknetffi__.NULL, 2) - net.layers[0] = layer_1 - net.layers[1] = layer_2 - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - build_dtype = {} - verify_darknet_frontend(net, build_dtype) - _lib().free_network(net) - - -def test_forward_upsample(): - """test upsample layer""" - net = _lib().make_network(1) - layer = _lib().make_upsample_layer(1, 19, 19, 3, 3) - layer.scale = 1 - net.layers[0] = layer - net.w = net.h = 19 - _lib().resize_network(net, 19, 19) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_l2normalize(): - """test l2 normalization layer""" - net = _lib().make_network(1) - layer = _lib().make_l2norm_layer(1, 224 * 224 * 3) - layer.c = layer.out_c = 3 - layer.h = layer.out_h = 224 - layer.w = layer.out_w = 224 - net.layers[0] = layer - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_elu(): - """test elu activation layer""" - net = _lib().make_network(1) - layer_1 = _lib().make_convolutional_layer(1, 224, 224, 3, 32, 1, 3, 2, 0, 1, 0, 0, 0, 0) - layer_1.activation = ACTIVATION.ELU - net.layers[0] = layer_1 - net.w = net.h = 224 - _lib().resize_network(net, 224, 224) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_softmax(): - """test softmax layer""" - net = _lib().make_network(1) - layer_1 = _lib().make_softmax_layer(1, 75, 1) - layer_1.temperature = 1 - net.layers[0] = layer_1 - net.w = net.h = 5 - _lib().resize_network(net, net.w, net.h) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_softmax_temperature(): - """test softmax layer""" - net = _lib().make_network(1) - layer_1 = _lib().make_softmax_layer(1, 75, 1) - layer_1.temperature = 0.8 - net.layers[0] = layer_1 - net.w = net.h = 5 - _lib().resize_network(net, net.w, net.h) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_activation_logistic(): - """test logistic activation layer""" - net = _lib().make_network(1) - batch = 1 - h = 224 - width = 224 - c = 3 - n = 32 - groups = 1 - size = 3 - stride = 2 - padding = 0 - activation = ACTIVATION.LOGISTIC - batch_normalize = 0 - binary = 0 - xnor = 0 - adam = 0 - layer_1 = _lib().make_convolutional_layer( - batch, - h, - width, - c, - n, - groups, - size, - stride, - padding, - activation, - batch_normalize, - binary, - xnor, - adam, - ) - net.layers[0] = layer_1 - net.w = width - net.h = h - _lib().resize_network(net, net.w, net.h) - verify_darknet_frontend(net) - _lib().free_network(net) - - -def test_forward_rnn(): - """test RNN layer""" - net = _lib().make_network(1) - batch = 1 - inputs = 4 - outputs = 4 - steps = 1 - activation = ACTIVATION.RELU - batch_normalize = 0 - adam = 0 - layer_1 = _lib().make_rnn_layer( - batch, inputs, outputs, steps, activation, batch_normalize, adam - ) - net.layers[0] = layer_1 - net.inputs = inputs - net.outputs = outputs - net.w = net.h = 0 - _lib().resize_network(net, net.w, net.h) - states = {"rnn0_state": np.zeros([1, net.inputs])} - _test_rnn_network(net, states) - _lib().free_network(net) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/keras/test_forward.py b/tests/python/frontend/keras/test_forward.py deleted file mode 100644 index 52505e259d23..000000000000 --- a/tests/python/frontend/keras/test_forward.py +++ /dev/null @@ -1,926 +0,0 @@ -# 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. -"""Unit tests for various models and operators""" -from packaging import version as package_version -import numpy as np - -try: - import tensorflow.compat.v1 as tf -except ImportError: - import tensorflow as tf - -from tensorflow import keras as tf_keras - -# prevent Keras from using up all gpu memory -import keras - -import pytest -import tvm -from tvm import relay -from tvm.contrib import graph_executor -import tvm.testing - -if tf.executing_eagerly(): - GPUS = tf.config.experimental.list_physical_devices("GPU") - for gpu in GPUS: - tf.config.experimental.set_memory_growth(gpu, True) -else: - from keras.backend.tensorflow_backend import set_session - - CONFIG = tf.ConfigProto() - CONFIG.gpu_options.per_process_gpu_memory_fraction = 0.5 - set_session(tf.Session(config=CONFIG)) - - -def pytest_generate_tests(metafunc): - """ - This function generates the list of tests for pytest, based - on scenarios that will change the parameters in which the - tests use to run. - https://docs.pytest.org/en/latest/example/parametrize.html - """ - idlist = [] - argvalues = [] - for scenario in metafunc.cls.scenarios: - idlist.append(scenario[0]) - items = scenario[1].items() - argnames = [x[0] for x in items] - argvalues.append([x[1] for x in items]) - metafunc.parametrize(argnames, argvalues, ids=idlist, scope="class") - - -# Scenarios: -# - classic keras, using keras from "import keras" -# - tensorflow keras, using keras from "from tensorflow import keras as tf_keras" -USING_CLASSIC_KERAS = ("keras", {"keras_mod": keras}) -USING_TENSORFLOW_KERAS = ("tf_keras", {"keras_mod": tf_keras}) - - -def verify_keras_frontend(keras_model, need_transpose=True, layout="NCHW"): - """Generic function to generate and compare Keras and TVM output""" - # Keras frontend currently supports tensorflow backend only. - assert keras.backend.backend() == "tensorflow" - - if layout != "NCHW": - need_transpose = False - - in_shapes = [] - for layer in keras_model._input_layers: - if tf.executing_eagerly(): - in_shapes.append(tuple(dim if dim is not None else 1 for dim in layer.input.shape)) - else: - in_shapes.append( - tuple(dim.value if dim.value is not None else 1 for dim in layer.input.shape) - ) - - def get_keras_output(in_data): - return keras_model.predict(in_data) - - def get_tvm_output(in_data, target, dev, dtype="float32"): - shape_dict = {name: x.shape for (name, x) in zip(keras_model.input_names, in_data)} - mod, params = relay.frontend.from_keras(keras_model, shape_dict, layout=layout) - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target, params=params) - m = graph_executor.GraphModule(lib["default"](dev)) - for name, x in zip(keras_model.input_names, in_data): - m.set_input(name, tvm.nd.array(x.astype(dtype))) - m.run() - return [m.get_output(i).numpy() for i in range(m.get_num_outputs())] - - def to_channels_first(arr): - return arr.transpose([0, -1] + list(range(1, arr.ndim - 1))) - - def to_channels_last(arr): - return arr.transpose([0] + list(range(2, arr.ndim)) + [1]) - - in_data = [np.random.uniform(size=shape, low=-1.0, high=1.0) for shape in in_shapes] - keras_out = get_keras_output(in_data) - keras_out = keras_out if isinstance(keras_out, list) else [keras_out] - for target, dev in tvm.testing.enabled_targets(): - inputs = [to_channels_first(x) for x in in_data] if need_transpose else in_data - tvm_out = get_tvm_output(inputs, target, dev) - for kout, tout in zip(keras_out, tvm_out): - if need_transpose: - tout = to_channels_last(tout) - tvm.testing.assert_allclose(kout, tout, rtol=1e-5, atol=1e-5) - - -def get_mobilenet(keras_mod): - if hasattr(keras_mod.applications, "MobileNet"): - # Keras 2.4.x and older - mobilenet_mod = keras_mod.applications.MobileNet - else: - # Keras 2.6.x and newer - mobilenet_mod = keras_mod.applications.mobilenet.MobileNet - - return mobilenet_mod - - -@tvm.testing.uses_gpu -class TestKeras: - """Keras test""" - - scenarios = [USING_CLASSIC_KERAS, USING_TENSORFLOW_KERAS] - - def test_forward_merge(self, keras_mod): - """test_forward_merge""" - data = keras_mod.layers.Input(shape=(32, 32, 3)) - conv2d_x = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data) - conv2d_y = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(conv2d_x) - conv2d_z = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(conv2d_y) - merge_funcs = [ - keras_mod.layers.Add(), - keras_mod.layers.Subtract(), - keras_mod.layers.Multiply(), - keras_mod.layers.Maximum(), - keras_mod.layers.Minimum(), - keras_mod.layers.Average(), - keras_mod.layers.Concatenate(), - ] - for merge_func in merge_funcs: - class_name = type(merge_func).__name__ - if class_name in ("Subtract", "Dot"): - out = merge_func([conv2d_x, conv2d_y]) - else: - out = merge_func([conv2d_x, conv2d_y, conv2d_z]) - keras_model = keras_mod.models.Model(data, out) - verify_keras_frontend(keras_model) - - def test_forward_concatenate(self, keras_mod): - """test_forward_concatenate""" - data1 = keras_mod.layers.Input(shape=(1, 2, 2)) - data2 = keras_mod.layers.Input(shape=(1, 1, 2)) - merge_func = keras_mod.layers.Concatenate(axis=2) - out = merge_func([data1, data2]) - keras_model = keras_mod.models.Model([data1, data2], out) - verify_keras_frontend(keras_model, layout="NHWC") - verify_keras_frontend(keras_model, layout="NCHW") - # test default axis (e.g., -1) - data1 = keras_mod.layers.Input(shape=(1, 2, 2)) - data2 = keras_mod.layers.Input(shape=(1, 2, 3)) - merge_func = keras_mod.layers.Concatenate() - out = merge_func([data1, data2]) - keras_model = keras_mod.models.Model([data1, data2], out) - verify_keras_frontend(keras_model, layout="NHWC") - verify_keras_frontend(keras_model, layout="NCHW") - # test axis at last dimension - data1 = keras_mod.layers.Input(shape=(1, 2, 2)) - data2 = keras_mod.layers.Input(shape=(1, 2, 3)) - merge_func = keras_mod.layers.Concatenate(axis=3) - out = merge_func([data1, data2]) - keras_model = keras_mod.models.Model([data1, data2], out) - verify_keras_frontend(keras_model, layout="NHWC") - verify_keras_frontend(keras_model, layout="NCHW") - - def test_forward_merge_dot(self, keras_mod): - """test_forward_merge_dot""" - data1 = keras_mod.layers.Input(shape=(2, 2)) - data2 = keras_mod.layers.Input(shape=(2, 2)) - merge_funcs = [ - keras_mod.layers.Dot(axes=[1, 2]), - keras_mod.layers.Dot(axes=[2, 1]), - keras_mod.layers.Dot(axes=[1, 1]), - keras_mod.layers.Dot(axes=[2, 2]), - keras_mod.layers.Dot(axes=1), - keras_mod.layers.Dot(axes=2), - ] - for merge_func in merge_funcs: - out = merge_func([data1, data2]) - keras_model = keras_mod.models.Model([data1, data2], out) - verify_keras_frontend(keras_model) - - def test_forward_activations(self, keras_mod): - """test_forward_activations""" - data = keras_mod.layers.Input(shape=(32, 32, 3)) - act_funcs = [ - keras_mod.layers.Activation("softmax"), - keras_mod.layers.Softmax(), - keras_mod.layers.Softmax(axis=-1), - keras_mod.layers.Softmax(axis=1), - keras_mod.layers.Softmax(axis=2), - keras_mod.layers.Softmax(axis=3), - keras_mod.layers.Activation("softplus"), - keras_mod.layers.Activation("relu"), - keras_mod.layers.Activation("softsign"), - keras_mod.layers.Activation("hard_sigmoid"), - keras_mod.layers.Activation("sigmoid"), - keras_mod.layers.Activation("tanh"), - keras_mod.layers.Activation("linear"), - keras_mod.layers.Activation("selu"), - keras_mod.layers.Activation("swish"), - keras_mod.layers.ReLU(), - keras_mod.layers.ReLU(max_value=6.0), - keras_mod.layers.ReLU(max_value=6.0, threshold=0.0), - keras_mod.layers.ReLU(max_value=6.0, threshold=1.0), - keras_mod.layers.ReLU(max_value=6.0, threshold=1.0, negative_slope=0.0), - keras_mod.layers.ReLU(max_value=6.0, threshold=1.0, negative_slope=0.5), - keras_mod.layers.ReLU(max_value=6.0, threshold=1.0, negative_slope=1.0), - keras_mod.layers.LeakyReLU(alpha=0.3), - keras_mod.layers.PReLU(weights=np.random.rand(1, 32, 32, 3)), - keras_mod.layers.ELU(alpha=0.5), - keras_mod.layers.ThresholdedReLU(theta=0.5), - ] - for act_func in act_funcs: - x = act_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - verify_keras_frontend(keras_model, need_transpose=False, layout="NHWC") - # Test the input dimension = 1 - data = keras_mod.layers.Input(shape=(11,)) - act_func = keras_mod.layers.Softmax() - x = act_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - verify_keras_frontend(keras_model, need_transpose=False, layout="NHWC") - - def test_forward_activations_except(self, keras_mod): - """ - test invalid attribute alpha=None for LeakyReLU and ELU. - after version 2.3.1 in keras, checking was added to reject the invalid api call: - LeakyReLU(alpha=None) and ELU(alpha=None), - (see issue: https://github.com/tensorflow/tensorflow/pull/47017) - Thus, it's necessary to check the keras version to avoid crash at LeakyReLU(alpha=None) - and ELU(alpha=None) - """ - if package_version.parse(keras_mod.__version__.split("-tf")[0]) <= package_version.parse( - "2.3.1" - ): - act_funcs = [ - keras_mod.layers.LeakyReLU(alpha=None), - keras_mod.layers.ELU(2, 3, 4), - keras_mod.layers.ReLU(threshold=None), - ] - data = keras_mod.layers.Input(shape=(2, 3, 4)) - for act_func in act_funcs: - layer = act_func(data) - keras_model = keras_mod.models.Model(data, layer) - with pytest.raises(tvm.error.OpAttributeInvalid): - verify_keras_frontend(keras_model) - - def test_forward_dense(self, keras_mod): - """test_forward_dense""" - data = keras_mod.layers.Input(shape=(32, 32, 1)) - x = keras_mod.layers.Flatten()(data) - x = keras_mod.layers.Dropout(0.5)(x) - x = keras_mod.layers.Dense(10, activation="relu", kernel_initializer="uniform")(x) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # RNN dense - data = keras_mod.layers.Input(shape=(1, 32)) - x = keras_mod.layers.Dense(32, activation="relu", kernel_initializer="uniform")(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(120, 2560), name="image_set") - x = keras_mod.layers.Dense(1, activation="linear", name="e")(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(10, 12, 2560), name="image_set") - x = keras_mod.layers.Dense(32, activation="linear", name="e")(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_permute(self, keras_mod): - data = keras_mod.layers.Input(shape=(2, 3, 4)) - x = keras_mod.layers.Permute([2, 3, 1])(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_sequential(self, keras_mod): - """test_forward_sequential""" - keras_model = keras_mod.models.Sequential( - [ - keras_mod.layers.Dense(16, input_dim=32, activation="relu"), - keras_mod.layers.Dropout(0.5), - keras_mod.layers.Dense(8, activation="relu"), - keras_mod.layers.Dropout(0.5), - keras_mod.layers.Dense(1, activation="sigmoid"), - ] - ) - verify_keras_frontend(keras_model) - - def test_forward_pool(self, keras_mod): - """test_forward_pool""" - data = keras_mod.layers.Input(shape=(32, 32, 1)) - # maxpool - x = keras_mod.layers.MaxPooling2D((3, 3), strides=(1, 1), padding="same")(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # avgpool - y = keras_mod.layers.AveragePooling2D((3, 3), strides=(1, 1), padding="same")(data) - keras_model = keras_mod.models.Model(data, y) - verify_keras_frontend(keras_model) - # reject the invalid input shape - data = keras_mod.layers.Input(shape=(0, 3, 6, 4)) - x = keras_mod.layers.GlobalAveragePooling3D()(data) - keras_model = keras_mod.models.Model(data, x) - with pytest.raises(ValueError): - verify_keras_frontend(keras_model) - - def test_forward_conv1d(self, keras_mod): - """test_forward_conv1d""" - data = keras_mod.layers.Input(shape=(32, 3)) - conv_funcs = [ - keras_mod.layers.Conv1D(filters=10, kernel_size=(3,), strides=(2,), padding="same"), - keras_mod.layers.Conv1D( - filters=10, kernel_size=(3,), dilation_rate=(2,), padding="same" - ), - keras_mod.layers.Conv1D(filters=1, kernel_size=(3,), padding="valid", use_bias=False), - keras_mod.layers.Conv1D(filters=10, kernel_size=(2,), padding="valid"), - # Enable when relay conv1dtranspose handles NWC - # keras.layers.Conv1DTranspose(filters=10, kernel_size=(3), padding="valid"), - ] - for conv_func in conv_funcs: - x = conv_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NWC") - - def test_forward_conv(self, keras_mod): - """test_forward_conv""" - data = keras_mod.layers.Input(shape=(32, 32, 3)) - conv_funcs = [ - keras_mod.layers.Conv2D(filters=10, kernel_size=(3, 3), strides=(2, 2), padding="same"), - keras_mod.layers.Conv2D( - filters=10, kernel_size=(3, 3), dilation_rate=(2, 2), padding="same" - ), - keras_mod.layers.Conv2D(filters=1, kernel_size=(3, 3), padding="same"), - keras_mod.layers.DepthwiseConv2D(kernel_size=(3, 3), padding="same"), - keras_mod.layers.Conv2DTranspose(filters=10, kernel_size=(3, 3), padding="valid"), - keras_mod.layers.SeparableConv2D(filters=10, kernel_size=(3, 3), padding="same"), - keras_mod.layers.SeparableConv2D(filters=10, kernel_size=(3, 3), dilation_rate=(2, 2)), - keras_mod.layers.SeparableConv2D(filters=2, kernel_size=(3, 3), dilation_rate=2), - ] - for conv_func in conv_funcs: - x = conv_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - - def test_forward_conv_transpose(self, keras_mod): - """test_forward_conv_transpose""" - data = keras_mod.layers.Input(shape=(32, 32, 128)) - conv_funcs = [ - keras_mod.layers.Conv2DTranspose(filters=64, kernel_size=(2, 2), padding="valid"), - keras_mod.layers.Conv2DTranspose( - filters=2, kernel_size=(3, 3), strides=(2, 2), output_padding=(1, 1) - ), - ] - for conv_func in conv_funcs: - x = conv_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NHWC") - - def test_forward_batch_norm(self, keras_mod): - """test_forward_batch_norm""" - data = keras_mod.layers.Input(shape=(32, 32, 3)) - batch_norm_funcs = [ - keras_mod.layers.BatchNormalization( - axis=-1, - momentum=0.99, - epsilon=0.001, - center=True, - scale=False, - beta_initializer="zeros", - gamma_initializer="ones", - moving_mean_initializer="zeros", - moving_variance_initializer="ones", - ), - keras_mod.layers.BatchNormalization( - axis=-1, - momentum=0.99, - epsilon=0.001, - center=True, - scale=True, - beta_initializer="zeros", - gamma_initializer="ones", - moving_mean_initializer="zeros", - moving_variance_initializer="ones", - ), - keras_mod.layers.BatchNormalization( - axis=-1, - momentum=0.99, - epsilon=0.001, - center=False, - scale=True, - beta_initializer="zeros", - gamma_initializer="ones", - moving_mean_initializer="zeros", - moving_variance_initializer="ones", - ), - keras_mod.layers.BatchNormalization( - axis=-1, - momentum=0.99, - epsilon=0.001, - center=False, - scale=False, - beta_initializer="zeros", - gamma_initializer="ones", - moving_mean_initializer="zeros", - moving_variance_initializer="ones", - ), - ] - for batch_norm_func in batch_norm_funcs: - x = batch_norm_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - - def test_forward_upsample(self, keras_mod, interpolation="nearest"): - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.UpSampling2D(size=(3, 3), interpolation=interpolation)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # Height and width are not equal for the attribute size - data = keras_mod.layers.Input(shape=(2, 1, 3)) - x = keras_mod.layers.UpSampling2D(size=(1, 2), interpolation=interpolation)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - - def test_forward_reshape(self, keras_mod): - """test_forward_reshape""" - # input_shape len is 3, target_shape len is 3 - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Reshape(target_shape=(16, 64, 3))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # input_shape len is 3, target_shape len is 2 - data = keras_mod.layers.Input(shape=(32, 8, 3)) - x = keras_mod.layers.Reshape(target_shape=(256, 3))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # input_shape len is 2, target_shape len is 3 - data = keras_mod.layers.Input(shape=(256, 3)) - x = keras_mod.layers.Reshape(target_shape=(8, 32, 3))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - # input_shape len is 2, target_shape len is 1 - data = keras_mod.layers.Input(shape=(2, 8)) - x = keras_mod.layers.Reshape(target_shape=(16,))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - # input_shape len is 1, target_shape len is 2 - data = keras_mod.layers.Input(shape=(16,)) - x = keras_mod.layers.Reshape(target_shape=(4, 4))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - # input_shape len is 2, target_shape len is 2 - data = keras_mod.layers.Input(shape=(2, 8)) - x = keras_mod.layers.Reshape(target_shape=(4, 4))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - # "non-square" target shape - data = keras_mod.layers.Input(shape=(15,)) - x = keras_mod.layers.Reshape(target_shape=(5, 3))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - # modify channel dim - data = keras_mod.layers.Input(shape=(3, 2, 4)) - x = keras_mod.layers.Reshape(target_shape=(3, 8))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model) - - def test_forward_crop(self, keras_mod): - """test_forward_crop""" - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Cropping2D(cropping=((1, 1), (1, 1)))(data) - x = keras_mod.layers.Cropping2D(cropping=(1, 1))(x) - x = keras_mod.layers.Cropping2D(cropping=1)(x) - x = keras_mod.layers.Cropping2D(cropping=((0, 1), (1, 0)))(x) - x = keras_mod.layers.Cropping2D(cropping=(1, 0))(x) - x = keras_mod.layers.Cropping2D(cropping=0)(x) - x = keras_mod.layers.Add()([x, x]) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NHWC") - verify_keras_frontend(keras_model, layout="NHWC") - - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Cropping2D(cropping=(2, 1))(data) - x = keras_mod.layers.Cropping2D(cropping=(1, 2))(x) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NHWC") - verify_keras_frontend(keras_model, layout="NCHW") - - def test_forward_multi_inputs(self, keras_mod): - data1 = keras_mod.layers.Input(shape=(32, 32, 3)) - data2 = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data1) - y = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data2) - average_z = keras_mod.layers.Average()([x, y]) - out = keras_mod.layers.GlobalAveragePooling2D()(average_z) - keras_model = keras_mod.models.Model([data1, data2], out) - verify_keras_frontend(keras_model) - - def test_forward_multi_outputs(self, keras_mod): - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data) - x = keras_mod.layers.GlobalAveragePooling2D()(x) - y = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data) - y = keras_mod.layers.GlobalAveragePooling2D()(y) - keras_model = keras_mod.models.Model(data, [x, y]) - verify_keras_frontend(keras_model) - - def test_forward_reuse_layers(self, keras_mod): - """test_forward_reuse_layers""" - # reuse conv2d - data = keras_mod.layers.Input(shape=(32, 32, 3)) - conv2d = keras_mod.layers.Conv2D(8, (3, 3), padding="same") - x = conv2d(data) - y = conv2d(data) - add_z = keras_mod.layers.Add()([x, y]) - out = keras_mod.layers.GlobalAveragePooling2D()(add_z) - keras_model = keras_mod.models.Model(data, out) - verify_keras_frontend(keras_model) - # reuse add - data = keras_mod.layers.Input(shape=(32, 32, 3)) - x = keras_mod.layers.Conv2D(8, (3, 3), padding="same")(data) - add = keras_mod.layers.Add() - x = add([x, x]) - x = add([x, x]) - out = keras_mod.layers.GlobalAveragePooling2D()(x) - keras_model = keras_mod.models.Model(data, out) - verify_keras_frontend(keras_model) - - def test_forward_lstm(self, keras_mod): - """test_forward_lstm""" - data = keras_mod.layers.Input(shape=(10, 32)) - rnn_funcs = [ - keras_mod.layers.LSTM(16), - keras_mod.layers.LSTM(16, return_sequences=True), - keras_mod.layers.LSTM(16, go_backwards=True), - keras_mod.layers.LSTM(16, return_sequences=True, go_backwards=True), - keras_mod.layers.LSTM(16, return_sequences=True, use_bias=False), - ] - for rnn_func in rnn_funcs: - x = rnn_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_rnn(self, keras_mod): - """test_forward_rnn""" - data = keras_mod.layers.Input(shape=(1, 32)) - rnn_funcs = [ - keras_mod.layers.LSTM( - units=16, return_state=False, recurrent_activation="sigmoid", activation="tanh" - ), - keras_mod.layers.LSTM( - units=16, - return_state=False, - recurrent_activation="sigmoid", - activation="tanh", - use_bias=False, - ), - keras_mod.layers.SimpleRNN(units=16, return_state=False, activation="tanh"), - keras_mod.layers.SimpleRNN( - units=16, return_state=False, activation="tanh", use_bias=False - ), - keras_mod.layers.SimpleRNN( - units=16, return_state=False, activation="tanh", go_backwards=True - ), - keras_mod.layers.GRU( - units=16, - return_state=False, - recurrent_activation="sigmoid", - activation="tanh", - reset_after=False, - ), - keras_mod.layers.GRU( - units=16, - return_state=False, - recurrent_activation="sigmoid", - activation="tanh", - reset_after=False, - use_bias=False, - ), - keras_mod.layers.GRU( - units=16, - return_state=False, - recurrent_activation="sigmoid", - activation="tanh", - reset_after=False, - use_bias=False, - go_backwards=True, - ), - ] - for rnn_func in rnn_funcs: - x = rnn_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_vgg16(self, keras_mod, layout="NCHW"): - """test_forward_vgg16""" - if hasattr(keras_mod.applications, "VGG16"): - # Keras 2.4.x and older - vgg16_mod = keras_mod.applications.VGG16 - else: - # Keras 2.6.x and newer - vgg16_mod = keras_mod.applications.vgg16.VGG16 - - keras_model = vgg16_mod( - include_top=True, weights="imagenet", input_shape=(224, 224, 3), classes=1000 - ) - verify_keras_frontend(keras_model, layout=layout) - - def test_forward_xception(self, keras_mod, layout="NCHW"): - """test_forward_vgg16""" - if hasattr(keras_mod.applications, "Xception"): - # Keras 2.4.x and older - xception_mod = keras_mod.applications.Xception - else: - # Keras 2.6.x and newer - xception_mod = keras_mod.applications.xception.Xception - - keras_model = xception_mod( - include_top=True, weights="imagenet", input_shape=(299, 299, 3), classes=1000 - ) - verify_keras_frontend(keras_model, layout=layout) - - def test_forward_resnet50(self, keras_mod, layout="NCHW"): - """test_forward_resnet50""" - if hasattr(keras_mod.applications, "ResNet50"): - # Keras 2.4.x and older - resnet50_mod = keras_mod.applications.ResNet50 - else: - # Keras 2.6.x and newer - resnet50_mod = keras_mod.applications.resnet.ResNet50 - - keras_model = resnet50_mod( - include_top=True, weights="imagenet", input_shape=(224, 224, 3), classes=1000 - ) - verify_keras_frontend(keras_model, layout=layout) - - def test_forward_inception_v3(self, keras_mod, layout="NCHW"): - """test_forward_inception_v3""" - if hasattr(keras_mod.applications, "InceptionV3"): - # Keras 2.4.x and older - inception_v3_mod = keras_mod.applications.InceptionV3 - else: - # Keras 2.6.x and newer - inception_v3_mod = keras_mod.applications.inception_v3.InceptionV3 - - keras_model = inception_v3_mod( - include_top=True, weights=None, input_shape=(299, 299, 3), classes=1000 - ) - verify_keras_frontend(keras_model, layout=layout) - - def test_forward_mobilenet(self, keras_mod, layout="NCHW"): - mobilenet_mod = get_mobilenet(keras_mod) - - keras_model = mobilenet_mod( - include_top=True, weights="imagenet", input_shape=(224, 224, 3), classes=1000 - ) - verify_keras_frontend(keras_model, layout=layout) - - def test_forward_conv3d(self, keras_mod): - """test_forward_conv3d""" - data = keras_mod.layers.Input(shape=(32, 32, 32, 3)) - conv_funcs = [ - keras_mod.layers.Conv3D( - filters=10, kernel_size=(3, 3, 3), strides=(2, 2, 2), padding="same" - ), - keras_mod.layers.Conv3D( - filters=10, kernel_size=(3, 3, 3), dilation_rate=(2, 2, 2), padding="same" - ), - keras_mod.layers.Conv3D( - filters=1, kernel_size=(3, 3, 3), padding="valid", use_bias=False - ), - keras_mod.layers.Conv3D(filters=10, kernel_size=(2, 2, 2), padding="valid"), - ] - for conv_func in conv_funcs: - x = conv_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_conv3d_transpose(self, keras_mod): - """test_forward_conv3d_transpose""" - data = keras_mod.layers.Input(shape=(32, 32, 32, 3)) - conv_funcs = [ - keras_mod.layers.Conv3DTranspose( - filters=10, kernel_size=(3, 3, 3), strides=(2, 2, 2), padding="same" - ), - keras_mod.layers.Conv3DTranspose( - filters=10, kernel_size=(1, 1, 1), dilation_rate=(1, 1, 1), padding="same" - ), - keras_mod.layers.Conv3DTranspose( - filters=1, kernel_size=(3, 3, 3), padding="valid", use_bias=False - ), - keras_mod.layers.Conv3DTranspose(filters=10, kernel_size=(2, 2, 2), padding="valid"), - keras_mod.layers.Conv3DTranspose( - filters=2, kernel_size=(3, 3, 3), strides=(2, 2, 2), output_padding=(1, 1, 1) - ), - ] - for conv_func in conv_funcs: - x = conv_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_pool3d(self, keras_mod): - """test_forward_pool3d""" - data = keras_mod.layers.Input(shape=(32, 32, 32, 1)) - pool_funcs = [ # maxpool - keras_mod.layers.MaxPooling3D(pool_size=(2, 2, 2), strides=(1, 1, 1), padding="same"), - keras_mod.layers.MaxPooling3D(pool_size=(3, 3, 3), strides=(2, 2, 2), padding="valid"), - # avgpool - keras_mod.layers.AveragePooling3D( - pool_size=(3, 3, 3), strides=(2, 2, 2), padding="same" - ), - keras_mod.layers.AveragePooling3D( - pool_size=(2, 2, 2), strides=(1, 1, 1), padding="valid" - ), - ] - for pool_func in pool_funcs: - x = pool_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_upsample3d(self, keras_mod): - data = keras_mod.layers.Input(shape=(32, 32, 32, 3)) - x = keras_mod.layers.UpSampling3D(size=(2, 3, 4))(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_zero_padding3d(self, keras_mod): - """test_forward_zero_padding3d""" - data = keras_mod.layers.Input(shape=(32, 32, 32, 3)) - pad_funcs = [ # Integer - keras_mod.layers.ZeroPadding3D(padding=2), - # tuple of 3 ints - keras_mod.layers.ZeroPadding3D(padding=(1, 2, 3)), - # tuple of 3 tuples of 2 ints - keras_mod.layers.ZeroPadding3D(padding=((1, 1), (2, 2), (2, 2))), - # tuple of 3 tuples of 2 ints different values - keras_mod.layers.ZeroPadding3D(padding=((1, 2), (2, 3), (3, 2))), - ] - for pad_func in pad_funcs: - x = pad_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_embedding(self, keras_mod): - """test_forward_embedding""" - data = keras_mod.layers.Input(shape=(2, 4), dtype="int32") - x = keras_mod.layers.Embedding(10, 3)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(2, 3, 4), dtype="int32") - x = keras_mod.layers.Embedding(4, 5)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(6, 2, 3, 4), dtype="int32") - x = keras_mod.layers.Embedding(4, 5)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_repeat_vector(self, keras_mod): - """test_forward_repeat_vector""" - data = keras_mod.layers.Input(shape=(5,), dtype="float32") - x = keras_mod.layers.Dense(6)(data) - x = keras_mod.layers.RepeatVector(2)(x) - - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(10,), dtype="float32") - x = keras_mod.layers.RepeatVector(3)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - data = keras_mod.layers.Input(shape=(4,), dtype="float32") - x = keras_mod.layers.RepeatVector(1)(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, need_transpose=False) - - def test_forward_global_pool3d(self, keras_mod): - """test_forward_zero_padding3d""" - data = keras_mod.layers.Input(shape=(32, 32, 32, 1)) - pool_funcs = [ # global maxpool - keras_mod.layers.GlobalMaxPooling3D(), - # global avgpool - keras_mod.layers.GlobalAveragePooling3D(), - ] - for pool_func in pool_funcs: - x = pool_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NDHWC") - - def test_forward_nested_layers(self, keras_mod): - """test_forward_nested_layers""" - mobilenet_mod = get_mobilenet(keras_mod) - - sub_model = mobilenet_mod(include_top=False, weights="imagenet", input_shape=(224, 224, 3)) - keras_model = keras_mod.Sequential( - [ - sub_model, - keras_mod.layers.GlobalAveragePooling2D(), - keras_mod.layers.Dense(1024, activation="relu"), - keras_mod.layers.Dense(2, activation="sigmoid"), - ] - ) - verify_keras_frontend(keras_model) - - def test_forward_l2_normalize(self, keras_mod): - """test_forward_l2_normalize""" - data = keras_mod.layers.Input(shape=(16, 12, 8)) - k_backend = keras_mod.backend - l2_funcs = [ - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, axis=-2)), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(x=v, axis=-1)), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(axis=1, x=v)), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, 2)), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, axis=3)), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, axis=(2, 3))), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, (1, 2))), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, axis=[-2, -1])), - keras_mod.layers.Lambda(lambda v: k_backend.l2_normalize(v, [-3, -2])), - ] - for l2_func in l2_funcs: - x = l2_func(data) - keras_model = keras_mod.models.Model(data, x) - verify_keras_frontend(keras_model, layout="NCHW") - verify_keras_frontend(keras_model, layout="NHWC") - - def test_forward_time_distributed(self, keras_mod): - """test_forward_time_distributed""" - conv2d_inputs = keras_mod.Input(shape=(10, 128, 128, 3)) - conv_2d_layer = keras_mod.layers.Conv2D(64, (3, 3)) - conv2d_model = keras_mod.models.Model( - conv2d_inputs, keras_mod.layers.TimeDistributed(conv_2d_layer)(conv2d_inputs) - ) - verify_keras_frontend(conv2d_model, layout="NDHWC") - - dense_inputs = keras_mod.Input(shape=(5, 1)) - dense_layer = keras_mod.layers.Dense(1) - dense_model = keras_mod.models.Model( - dense_inputs, keras_mod.layers.TimeDistributed(dense_layer)(dense_inputs) - ) - verify_keras_frontend(dense_model, need_transpose=False) - - def test_simplernn_with_infertype(self, keras_mod): - """This test case is from https://github.com/apache/tvm/issues/14868""" - input_shape = (2, 2, 2) - x = keras_mod.layers.Input(shape=input_shape[1:], dtype="float32") - layer = keras_mod.layers.SimpleRNN(units=4) - y = layer(x) - model = keras_mod.models.Model(x, y) - mod, _ = relay.frontend.from_keras(model, {model.input_names[0]: input_shape}) - relay.transform.InferType()(mod) - - -if __name__ == "__main__": - for k in [keras, tf_keras]: - sut = TestKeras() - sut.test_forward_concatenate(keras_mod=k) - sut.test_forward_merge_dot(keras_mod=k) - sut.test_forward_merge(keras_mod=k) - sut.test_forward_activations(keras_mod=k) - sut.test_forward_activations_except(keras_mod=k) - sut.test_forward_dense(keras_mod=k) - sut.test_forward_permute(keras_mod=k) - sut.test_forward_sequential(keras_mod=k) - sut.test_forward_pool(keras_mod=k) - sut.test_forward_conv(keras_mod=k) - sut.test_forward_conv1d(keras_mod=k) - sut.test_forward_batch_norm(keras_mod=k) - sut.test_forward_upsample(keras_mod=k, interpolation="nearest") - sut.test_forward_upsample(keras_mod=k, interpolation="bilinear") - sut.test_forward_reshape(keras_mod=k) - sut.test_forward_crop(keras_mod=k) - sut.test_forward_multi_inputs(keras_mod=k) - sut.test_forward_multi_outputs(keras_mod=k) - sut.test_forward_reuse_layers(keras_mod=k) - sut.test_forward_lstm(keras_mod=k) - sut.test_forward_rnn(keras_mod=k) - sut.test_forward_vgg16(keras_mod=k) - sut.test_forward_vgg16(keras_mod=k, layout="NHWC") - sut.test_forward_xception(keras_mod=k) - sut.test_forward_resnet50(keras_mod=k) - sut.test_forward_resnet50(keras_mod=k, layout="NHWC") - sut.test_forward_inception_v3(keras_mod=k) - sut.test_forward_inception_v3(keras_mod=k, layout="NHWC") - sut.test_forward_mobilenet(keras_mod=k) - sut.test_forward_mobilenet(keras_mod=k, layout="NHWC") - sut.test_forward_conv3d(keras_mod=k) - sut.test_forward_conv3d_transpose(keras_mod=k) - sut.test_forward_pool3d(keras_mod=k) - sut.test_forward_global_pool3d(keras_mod=k) - sut.test_forward_upsample3d(keras_mod=k) - sut.test_forward_zero_padding3d(keras_mod=k) - sut.test_forward_embedding(keras_mod=k) - sut.test_forward_repeat_vector(keras_mod=k) - sut.test_forward_l2_normalize(keras_mod=k) - sut.test_forward_time_distributed(keras_mod=k) - sut.test_simplernn_with_infertype(keras_mod=k) diff --git a/tests/python/frontend/mxnet/model_zoo/__init__.py b/tests/python/frontend/mxnet/model_zoo/__init__.py deleted file mode 100644 index 2c324a060d25..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/__init__.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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. - -"""MXNet model zoo for testing purposes.""" -from __future__ import absolute_import -from . import mlp, vgg, resnet, dqn, inception_v3, squeezenet, dcgan -import tvm.relay.testing - -# mlp -def mx_mlp(): - num_class = 10 - return mlp.get_symbol(num_class) - - -def relay_mlp(): - num_class = 10 - return tvm.relay.testing.mlp.get_workload(1, num_class)[0] - - -# vgg -def mx_vgg(num_layers): - num_class = 1000 - return vgg.get_symbol(num_class, num_layers) - - -def relay_vgg(num_layers): - num_class = 1000 - return tvm.relay.testing.vgg.get_workload(1, num_class, num_layers=num_layers)[0] - - -# resnet -def mx_resnet(num_layers): - num_class = 1000 - return resnet.get_symbol(num_class, num_layers, "3,224,224") - - -def relay_resnet(num_layers): - num_class = 1000 - return tvm.relay.testing.resnet.get_workload(1, num_class, num_layers=num_layers)[0] - - -# dqn -mx_dqn = dqn.get_symbol - - -def relay_dqn(): - return tvm.relay.testing.dqn.get_workload(1)[0] - - -# squeezenet -def mx_squeezenet(version): - return squeezenet.get_symbol(version=version) - - -def relay_squeezenet(version): - return tvm.relay.testing.squeezenet.get_workload(1, version=version)[0] - - -# inception -mx_inception_v3 = inception_v3.get_symbol - - -def relay_inception_v3(): - return tvm.relay.testing.inception_v3.get_workload(1)[0] - - -# dcgan generator -mx_dcgan = dcgan.get_symbol - - -def relay_dcgan(batch_size): - return tvm.relay.testing.dcgan.get_workload(batch_size=batch_size)[0] diff --git a/tests/python/frontend/mxnet/model_zoo/dcgan.py b/tests/python/frontend/mxnet/model_zoo/dcgan.py deleted file mode 100644 index 67c20ccc65c9..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/dcgan.py +++ /dev/null @@ -1,91 +0,0 @@ -# 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. -# pylint: disable=unused-argument -""" -The MXNet symbol of DCGAN generator - -Adopted from: -https://github.com/tqchen/mxnet-gan/blob/main/mxgan/generator.py - -Reference: -Radford, Alec, Luke Metz, and Soumith Chintala. -"Unsupervised representation learning with deep convolutional generative adversarial networks." -arXiv preprint arXiv:1511.06434 (2015). -""" - -import mxnet as mx - - -def deconv2d(data, ishape, oshape, kshape, name, stride=(2, 2)): - """a deconv layer that enlarges the feature map""" - target_shape = (oshape[-2], oshape[-1]) - pad_y = (kshape[0] - 1) // 2 - pad_x = (kshape[1] - 1) // 2 - adj_y = (target_shape[0] + 2 * pad_y - kshape[0]) % stride[0] - adj_x = (target_shape[1] + 2 * pad_x - kshape[1]) % stride[1] - - net = mx.sym.Deconvolution( - data, - kernel=kshape, - stride=stride, - pad=(pad_y, pad_x), - adj=(adj_y, adj_x), - num_filter=oshape[0], - no_bias=True, - name=name, - ) - return net - - -def deconv2d_bn_relu(data, prefix, **kwargs): - """a block of deconv + batch norm + relu""" - eps = 1e-5 + 1e-12 - - net = deconv2d(data, name="%s_deconv" % prefix, **kwargs) - net = mx.sym.BatchNorm(net, eps=eps, name="%s_bn" % prefix) - net = mx.sym.Activation(net, name="%s_act" % prefix, act_type="relu") - return net - - -def get_symbol(oshape=(3, 64, 64), ngf=128, code=None): - """get symbol of dcgan generator""" - assert oshape[-1] == 64, "Only support 64x64 image" - assert oshape[-2] == 64, "Only support 64x64 image" - - code = mx.sym.Variable("data") if code is None else code - net = mx.sym.FullyConnected( - code, name="g1", num_hidden=ngf * 8 * 4 * 4, no_bias=True, flatten=False - ) - net = mx.sym.Activation(net, act_type="relu") - # 4 x 4 - net = mx.sym.reshape(net, shape=(-1, ngf * 8, 4, 4)) - # 8 x 8 - net = deconv2d_bn_relu( - net, ishape=(ngf * 8, 4, 4), oshape=(ngf * 4, 8, 8), kshape=(4, 4), prefix="g2" - ) - # 16x16 - net = deconv2d_bn_relu( - net, ishape=(ngf * 4, 8, 8), oshape=(ngf * 2, 16, 16), kshape=(4, 4), prefix="g3" - ) - # 32x32 - net = deconv2d_bn_relu( - net, ishape=(ngf * 2, 16, 16), oshape=(ngf, 32, 32), kshape=(4, 4), prefix="g4" - ) - # 64x64 - net = deconv2d(net, ishape=(ngf, 32, 32), oshape=oshape[-3:], kshape=(4, 4), name="g5_deconv") - net = mx.sym.Activation(net, act_type="tanh") - return net diff --git a/tests/python/frontend/mxnet/model_zoo/dqn.py b/tests/python/frontend/mxnet/model_zoo/dqn.py deleted file mode 100644 index df611c701258..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/dqn.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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. -""" -The mxnet symbol of Nature DQN - -Reference: -Mnih, Volodymyr, et al. -"Human-level control through deep reinforcement learning." -Nature 518.7540 (2015): 529. -""" - -import mxnet as mx - - -def get_symbol(num_action=18): - data = mx.sym.Variable(name="data") - net = mx.sym.Convolution(data, kernel=(8, 8), stride=(4, 4), num_filter=32, name="conv1") - net = mx.sym.Activation(net, act_type="relu", name="relu1") - net = mx.sym.Convolution(net, kernel=(4, 4), stride=(2, 2), num_filter=64, name="conv2") - net = mx.sym.Activation(net, act_type="relu", name="relu2") - net = mx.sym.Convolution(net, kernel=(3, 3), stride=(1, 1), num_filter=64, name="conv3") - net = mx.sym.Activation(net, act_type="relu", name="relu3") - net = mx.sym.FullyConnected(net, num_hidden=512, name="fc4") - net = mx.sym.Activation(net, act_type="relu", name="relu4") - net = mx.sym.FullyConnected(net, num_hidden=num_action, name="fc5", flatten=False) - - return net diff --git a/tests/python/frontend/mxnet/model_zoo/inception_v3.py b/tests/python/frontend/mxnet/model_zoo/inception_v3.py deleted file mode 100644 index 872662a01c10..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/inception_v3.py +++ /dev/null @@ -1,368 +0,0 @@ -# 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. -""" -Inception V3, suitable for images with around 299 x 299 - -Reference: -Szegedy, Christian, et al. "Rethinking the Inception Architecture for Computer Vision." arXiv preprint arXiv:1512.00567 (2015). - -Adopted from https://github.com/apache/incubator-mxnet/blob/master/ - example/image-classification/symbols/inception-v3.py -""" -import mxnet as mx -import numpy as np - - -def Conv(data, num_filter, kernel=(1, 1), stride=(1, 1), pad=(0, 0), name=None, suffix=""): - conv = mx.sym.Convolution( - data=data, - num_filter=num_filter, - kernel=kernel, - stride=stride, - pad=pad, - no_bias=True, - name="%s%s_conv2d" % (name, suffix), - ) - bn = mx.sym.BatchNorm(data=conv, eps=2e-5, name="%s%s_batchnorm" % (name, suffix)) - act = mx.sym.Activation(data=bn, act_type="relu", name="%s%s_relu" % (name, suffix)) - return act - - -def Inception7A( - data, num_1x1, num_3x3_red, num_3x3_1, num_3x3_2, num_5x5_red, num_5x5, pool, proj, name -): - tower_1x1 = Conv(data, num_1x1, name=("%s_conv" % name)) - tower_5x5 = Conv(data, num_5x5_red, name=("%s_tower" % name), suffix="_conv") - tower_5x5 = Conv( - tower_5x5, num_5x5, kernel=(5, 5), pad=(2, 2), name=("%s_tower" % name), suffix="_conv_1" - ) - tower_3x3 = Conv(data, num_3x3_red, name=("%s_tower_1" % name), suffix="_conv") - tower_3x3 = Conv( - tower_3x3, - num_3x3_1, - kernel=(3, 3), - pad=(1, 1), - name=("%s_tower_1" % name), - suffix="_conv_1", - ) - tower_3x3 = Conv( - tower_3x3, - num_3x3_2, - kernel=(3, 3), - pad=(1, 1), - name=("%s_tower_1" % name), - suffix="_conv_2", - ) - pooling = mx.sym.Pooling( - data=data, - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - pool_type=pool, - name=("%s_pool_%s_pool" % (pool, name)), - ) - cproj = Conv(pooling, proj, name=("%s_tower_2" % name), suffix="_conv") - concat = mx.sym.Concat( - *[tower_1x1, tower_5x5, tower_3x3, cproj], name="ch_concat_%s_chconcat" % name - ) - return concat - - -# First Downsample -def Inception7B(data, num_3x3, num_d3x3_red, num_d3x3_1, num_d3x3_2, pool, name): - tower_3x3 = Conv( - data, num_3x3, kernel=(3, 3), pad=(0, 0), stride=(2, 2), name=("%s_conv" % name) - ) - tower_d3x3 = Conv(data, num_d3x3_red, name=("%s_tower" % name), suffix="_conv") - tower_d3x3 = Conv( - tower_d3x3, - num_d3x3_1, - kernel=(3, 3), - pad=(1, 1), - stride=(1, 1), - name=("%s_tower" % name), - suffix="_conv_1", - ) - tower_d3x3 = Conv( - tower_d3x3, - num_d3x3_2, - kernel=(3, 3), - pad=(0, 0), - stride=(2, 2), - name=("%s_tower" % name), - suffix="_conv_2", - ) - pooling = mx.sym.Pooling( - data=data, - kernel=(3, 3), - stride=(2, 2), - pad=(0, 0), - pool_type="max", - name=("max_pool_%s_pool" % name), - ) - concat = mx.sym.Concat(*[tower_3x3, tower_d3x3, pooling], name="ch_concat_%s_chconcat" % name) - return concat - - -def Inception7C( - data, - num_1x1, - num_d7_red, - num_d7_1, - num_d7_2, - num_q7_red, - num_q7_1, - num_q7_2, - num_q7_3, - num_q7_4, - pool, - proj, - name, -): - tower_1x1 = Conv(data=data, num_filter=num_1x1, kernel=(1, 1), name=("%s_conv" % name)) - tower_d7 = Conv(data=data, num_filter=num_d7_red, name=("%s_tower" % name), suffix="_conv") - tower_d7 = Conv( - data=tower_d7, - num_filter=num_d7_1, - kernel=(1, 7), - pad=(0, 3), - name=("%s_tower" % name), - suffix="_conv_1", - ) - tower_d7 = Conv( - data=tower_d7, - num_filter=num_d7_2, - kernel=(7, 1), - pad=(3, 0), - name=("%s_tower" % name), - suffix="_conv_2", - ) - tower_q7 = Conv(data=data, num_filter=num_q7_red, name=("%s_tower_1" % name), suffix="_conv") - tower_q7 = Conv( - data=tower_q7, - num_filter=num_q7_1, - kernel=(7, 1), - pad=(3, 0), - name=("%s_tower_1" % name), - suffix="_conv_1", - ) - tower_q7 = Conv( - data=tower_q7, - num_filter=num_q7_2, - kernel=(1, 7), - pad=(0, 3), - name=("%s_tower_1" % name), - suffix="_conv_2", - ) - tower_q7 = Conv( - data=tower_q7, - num_filter=num_q7_3, - kernel=(7, 1), - pad=(3, 0), - name=("%s_tower_1" % name), - suffix="_conv_3", - ) - tower_q7 = Conv( - data=tower_q7, - num_filter=num_q7_4, - kernel=(1, 7), - pad=(0, 3), - name=("%s_tower_1" % name), - suffix="_conv_4", - ) - pooling = mx.sym.Pooling( - data=data, - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - pool_type=pool, - name=("%s_pool_%s_pool" % (pool, name)), - ) - cproj = Conv( - data=pooling, num_filter=proj, kernel=(1, 1), name=("%s_tower_2" % name), suffix="_conv" - ) - # concat - concat = mx.sym.Concat( - *[tower_1x1, tower_d7, tower_q7, cproj], name="ch_concat_%s_chconcat" % name - ) - return concat - - -def Inception7D( - data, num_3x3_red, num_3x3, num_d7_3x3_red, num_d7_1, num_d7_2, num_d7_3x3, pool, name -): - tower_3x3 = Conv(data=data, num_filter=num_3x3_red, name=("%s_tower" % name), suffix="_conv") - tower_3x3 = Conv( - data=tower_3x3, - num_filter=num_3x3, - kernel=(3, 3), - pad=(0, 0), - stride=(2, 2), - name=("%s_tower" % name), - suffix="_conv_1", - ) - tower_d7_3x3 = Conv( - data=data, num_filter=num_d7_3x3_red, name=("%s_tower_1" % name), suffix="_conv" - ) - tower_d7_3x3 = Conv( - data=tower_d7_3x3, - num_filter=num_d7_1, - kernel=(1, 7), - pad=(0, 3), - name=("%s_tower_1" % name), - suffix="_conv_1", - ) - tower_d7_3x3 = Conv( - data=tower_d7_3x3, - num_filter=num_d7_2, - kernel=(7, 1), - pad=(3, 0), - name=("%s_tower_1" % name), - suffix="_conv_2", - ) - tower_d7_3x3 = Conv( - data=tower_d7_3x3, - num_filter=num_d7_3x3, - kernel=(3, 3), - stride=(2, 2), - name=("%s_tower_1" % name), - suffix="_conv_3", - ) - pooling = mx.sym.Pooling( - data=data, - kernel=(3, 3), - stride=(2, 2), - pool_type=pool, - name=("%s_pool_%s_pool" % (pool, name)), - ) - # concat - concat = mx.sym.Concat(*[tower_3x3, tower_d7_3x3, pooling], name="ch_concat_%s_chconcat" % name) - return concat - - -def Inception7E( - data, - num_1x1, - num_d3_red, - num_d3_1, - num_d3_2, - num_3x3_d3_red, - num_3x3, - num_3x3_d3_1, - num_3x3_d3_2, - pool, - proj, - name, -): - tower_1x1 = Conv(data=data, num_filter=num_1x1, kernel=(1, 1), name=("%s_conv" % name)) - tower_d3 = Conv(data=data, num_filter=num_d3_red, name=("%s_tower" % name), suffix="_conv") - tower_d3_a = Conv( - data=tower_d3, - num_filter=num_d3_1, - kernel=(1, 3), - pad=(0, 1), - name=("%s_tower" % name), - suffix="_mixed_conv", - ) - tower_d3_b = Conv( - data=tower_d3, - num_filter=num_d3_2, - kernel=(3, 1), - pad=(1, 0), - name=("%s_tower" % name), - suffix="_mixed_conv_1", - ) - tower_3x3_d3 = Conv( - data=data, num_filter=num_3x3_d3_red, name=("%s_tower_1" % name), suffix="_conv" - ) - tower_3x3_d3 = Conv( - data=tower_3x3_d3, - num_filter=num_3x3, - kernel=(3, 3), - pad=(1, 1), - name=("%s_tower_1" % name), - suffix="_conv_1", - ) - tower_3x3_d3_a = Conv( - data=tower_3x3_d3, - num_filter=num_3x3_d3_1, - kernel=(1, 3), - pad=(0, 1), - name=("%s_tower_1" % name), - suffix="_mixed_conv", - ) - tower_3x3_d3_b = Conv( - data=tower_3x3_d3, - num_filter=num_3x3_d3_2, - kernel=(3, 1), - pad=(1, 0), - name=("%s_tower_1" % name), - suffix="_mixed_conv_1", - ) - pooling = mx.sym.Pooling( - data=data, - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - pool_type=pool, - name=("%s_pool_%s_pool" % (pool, name)), - ) - cproj = Conv( - data=pooling, num_filter=proj, kernel=(1, 1), name=("%s_tower_2" % name), suffix="_conv" - ) - # concat - concat = mx.sym.Concat( - *[tower_1x1, tower_d3_a, tower_d3_b, tower_3x3_d3_a, tower_3x3_d3_b, cproj], - name="ch_concat_%s_chconcat" % name, - ) - return concat - - -def get_symbol(num_classes=1000, **kwargs): - data = mx.sym.Variable(name="data") - # stage 1 - conv = Conv(data, 32, kernel=(3, 3), stride=(2, 2), name="conv") - conv_1 = Conv(conv, 32, kernel=(3, 3), name="conv_1") - conv_2 = Conv(conv_1, 64, kernel=(3, 3), pad=(1, 1), name="conv_2") - pool = mx.sym.Pooling(data=conv_2, kernel=(3, 3), stride=(2, 2), pool_type="max", name="pool") - # stage 2 - conv_3 = Conv(pool, 80, kernel=(1, 1), name="conv_3") - conv_4 = Conv(conv_3, 192, kernel=(3, 3), name="conv_4") - pool1 = mx.sym.Pooling(data=conv_4, kernel=(3, 3), stride=(2, 2), pool_type="max", name="pool1") - - # # stage 3 - in3a = Inception7A(pool1, 64, 64, 96, 96, 48, 64, "avg", 32, "mixed") - in3b = Inception7A(in3a, 64, 64, 96, 96, 48, 64, "avg", 64, "mixed_1") - in3c = Inception7A(in3b, 64, 64, 96, 96, 48, 64, "avg", 64, "mixed_2") - in3d = Inception7B(in3c, 384, 64, 96, 96, "max", "mixed_3") - # stage 4 - in4a = Inception7C(in3d, 192, 128, 128, 192, 128, 128, 128, 128, 192, "avg", 192, "mixed_4") - in4b = Inception7C(in4a, 192, 160, 160, 192, 160, 160, 160, 160, 192, "avg", 192, "mixed_5") - in4c = Inception7C(in4b, 192, 160, 160, 192, 160, 160, 160, 160, 192, "avg", 192, "mixed_6") - in4d = Inception7C(in4c, 192, 192, 192, 192, 192, 192, 192, 192, 192, "avg", 192, "mixed_7") - in4e = Inception7D(in4d, 192, 320, 192, 192, 192, 192, "max", "mixed_8") - # stage 5 - in5a = Inception7E(in4e, 320, 384, 384, 384, 448, 384, 384, 384, "avg", 192, "mixed_9") - in5b = Inception7E(in5a, 320, 384, 384, 384, 448, 384, 384, 384, "max", 192, "mixed_10") - # pool - pool = mx.sym.Pooling( - data=in5b, kernel=(8, 8), stride=(1, 1), pool_type="avg", name="global_pool" - ) - flatten = mx.sym.Flatten(data=pool, name="flatten") - fc1 = mx.sym.FullyConnected(data=flatten, num_hidden=num_classes, name="fc1", flatten=False) - softmax = mx.sym.SoftmaxOutput(data=fc1, name="softmax") - return softmax diff --git a/tests/python/frontend/mxnet/model_zoo/mlp.py b/tests/python/frontend/mxnet/model_zoo/mlp.py deleted file mode 100644 index 45f33f991de5..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/mlp.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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. - -""" -a simple multilayer perceptron -""" -import mxnet as mx - - -def get_symbol(num_classes=10, **kwargs): - data = mx.symbol.Variable("data") - data = mx.sym.Flatten(data=data) - try: - fc1 = mx.symbol.FullyConnected(data=data, name="fc1", num_hidden=128, flatten=False) - act1 = mx.symbol.Activation(data=fc1, name="relu1", act_type="relu") - fc2 = mx.symbol.FullyConnected(data=act1, name="fc2", num_hidden=64, flatten=False) - act2 = mx.symbol.Activation(data=fc2, name="relu2", act_type="relu") - fc3 = mx.symbol.FullyConnected(data=act2, name="fc3", num_hidden=num_classes, flatten=False) - mlp = mx.symbol.softmax(data=fc3, name="softmax") - except: - fc1 = mx.symbol.FullyConnected(data=data, name="fc1", num_hidden=128) - act1 = mx.symbol.Activation(data=fc1, name="relu1", act_type="relu") - fc2 = mx.symbol.FullyConnected(data=act1, name="fc2", num_hidden=64) - act2 = mx.symbol.Activation(data=fc2, name="relu2", act_type="relu") - fc3 = mx.symbol.FullyConnected(data=act2, name="fc3", num_hidden=num_classes) - mlp = mx.symbol.softmax(data=fc3, name="softmax") - return mlp diff --git a/tests/python/frontend/mxnet/model_zoo/resnet.py b/tests/python/frontend/mxnet/model_zoo/resnet.py deleted file mode 100644 index 00e68958b462..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/resnet.py +++ /dev/null @@ -1,326 +0,0 @@ -# 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. - -""" -Adapted from https://github.com/tornadomeet/ResNet/blob/master/symbol_resnet.py -Original author Wei Wu - -Implemented the following paper: - -Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun. "Identity Mappings in Deep Residual Networks" -""" -import mxnet as mx -import numpy as np - - -def residual_unit( - data, - num_filter, - stride, - dim_match, - name, - bottle_neck=True, - bn_mom=0.9, - workspace=256, - memonger=False, -): - """Return ResNet Unit symbol for building ResNet - Parameters - ---------- - data : str - Input data - num_filter : int - Number of output channels - bnf : int - Bottle neck channels factor with regard to num_filter - stride : tuple - Stride used in convolution - dim_match : Boolean - True means channel number between input and output is the same, otherwise means differ - name : str - Base name of the operators - workspace : int - Workspace used in convolution operator - """ - if bottle_neck: - bn1 = mx.sym.BatchNorm( - data=data, fix_gamma=False, eps=2e-5, momentum=bn_mom, name=name + "_bn1" - ) - act1 = mx.sym.Activation(data=bn1, act_type="relu", name=name + "_relu1") - conv1 = mx.sym.Convolution( - data=act1, - num_filter=int(num_filter * 0.25), - kernel=(1, 1), - stride=stride, - pad=(0, 0), - no_bias=True, - workspace=workspace, - name=name + "_conv1", - ) - bn2 = mx.sym.BatchNorm( - data=conv1, fix_gamma=False, eps=2e-5, momentum=bn_mom, name=name + "_bn2" - ) - act2 = mx.sym.Activation(data=bn2, act_type="relu", name=name + "_relu2") - conv2 = mx.sym.Convolution( - data=act2, - num_filter=int(num_filter * 0.25), - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - no_bias=True, - workspace=workspace, - name=name + "_conv2", - ) - bn3 = mx.sym.BatchNorm( - data=conv2, fix_gamma=False, eps=2e-5, momentum=bn_mom, name=name + "_bn3" - ) - act3 = mx.sym.Activation(data=bn3, act_type="relu", name=name + "_relu3") - conv3 = mx.sym.Convolution( - data=act3, - num_filter=num_filter, - kernel=(1, 1), - stride=(1, 1), - pad=(0, 0), - no_bias=True, - workspace=workspace, - name=name + "_conv3", - ) - if dim_match: - shortcut = data - else: - shortcut = mx.sym.Convolution( - data=act1, - num_filter=num_filter, - kernel=(1, 1), - stride=stride, - no_bias=True, - workspace=workspace, - name=name + "_sc", - ) - if memonger: - shortcut._set_attr(mirror_stage="True") - return conv3 + shortcut - else: - bn1 = mx.sym.BatchNorm( - data=data, fix_gamma=False, momentum=bn_mom, eps=2e-5, name=name + "_bn1" - ) - act1 = mx.sym.Activation(data=bn1, act_type="relu", name=name + "_relu1") - conv1 = mx.sym.Convolution( - data=act1, - num_filter=num_filter, - kernel=(3, 3), - stride=stride, - pad=(1, 1), - no_bias=True, - workspace=workspace, - name=name + "_conv1", - ) - bn2 = mx.sym.BatchNorm( - data=conv1, fix_gamma=False, momentum=bn_mom, eps=2e-5, name=name + "_bn2" - ) - act2 = mx.sym.Activation(data=bn2, act_type="relu", name=name + "_relu2") - conv2 = mx.sym.Convolution( - data=act2, - num_filter=num_filter, - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - no_bias=True, - workspace=workspace, - name=name + "_conv2", - ) - if dim_match: - shortcut = data - else: - shortcut = mx.sym.Convolution( - data=act1, - num_filter=num_filter, - kernel=(1, 1), - stride=stride, - no_bias=True, - workspace=workspace, - name=name + "_sc", - ) - if memonger: - shortcut._set_attr(mirror_stage="True") - return conv2 + shortcut - - -def resnet( - units, - num_stages, - filter_list, - num_classes, - image_shape, - bottle_neck=True, - bn_mom=0.9, - workspace=256, - dtype="float32", - memonger=False, -): - """Return ResNet symbol of - Parameters - ---------- - units : list - Number of units in each stage - num_stages : int - Number of stage - filter_list : list - Channel size of each stage - num_classes : int - Output size of symbol - dataset : str - Dataset type, only cifar10 and imagenet supports - workspace : int - Workspace used in convolution operator - dtype : str - Precision (float32 or float16) - """ - num_unit = len(units) - assert num_unit == num_stages - data = mx.sym.Variable(name="data") - if dtype == "float32": - # data = mx.sym.identity(data=data, name='id') - data = data - else: - if dtype == "float16": - data = mx.sym.Cast(data=data, dtype=np.float16) - data = mx.sym.BatchNorm(data=data, fix_gamma=True, eps=2e-5, momentum=bn_mom, name="bn_data") - (nchannel, height, width) = image_shape - if height <= 32: # such as cifar10 - body = mx.sym.Convolution( - data=data, - num_filter=filter_list[0], - kernel=(3, 3), - stride=(1, 1), - pad=(1, 1), - no_bias=True, - name="conv0", - workspace=workspace, - ) - else: # often expected to be 224 such as imagenet - body = mx.sym.Convolution( - data=data, - num_filter=filter_list[0], - kernel=(7, 7), - stride=(2, 2), - pad=(3, 3), - no_bias=True, - name="conv0", - workspace=workspace, - ) - body = mx.sym.BatchNorm(data=body, fix_gamma=False, eps=2e-5, momentum=bn_mom, name="bn0") - body = mx.sym.Activation(data=body, act_type="relu", name="relu0") - body = mx.sym.Pooling(data=body, kernel=(3, 3), stride=(2, 2), pad=(1, 1), pool_type="max") - - for i in range(num_stages): - body = residual_unit( - body, - filter_list[i + 1], - (1 if i == 0 else 2, 1 if i == 0 else 2), - False, - name="stage%d_unit%d" % (i + 1, 1), - bottle_neck=bottle_neck, - workspace=workspace, - memonger=memonger, - ) - for j in range(units[i] - 1): - body = residual_unit( - body, - filter_list[i + 1], - (1, 1), - True, - name="stage%d_unit%d" % (i + 1, j + 2), - bottle_neck=bottle_neck, - workspace=workspace, - memonger=memonger, - ) - bn1 = mx.sym.BatchNorm(data=body, fix_gamma=False, eps=2e-5, momentum=bn_mom, name="bn1") - relu1 = mx.sym.Activation(data=bn1, act_type="relu", name="relu1") - # Although kernel is not used here when global_pool=True, we should put one - pool1 = mx.sym.Pooling( - data=relu1, global_pool=True, kernel=(7, 7), pool_type="avg", name="pool1" - ) - flat = mx.sym.Flatten(data=pool1) - try: - fc1 = mx.sym.FullyConnected(data=flat, num_hidden=num_classes, name="fc1", flatten=False) - except: - fc1 = mx.sym.FullyConnected(data=flat, num_hidden=num_classes, name="fc1") - if dtype == "float16": - fc1 = mx.sym.Cast(data=fc1, dtype=np.float32) - return mx.sym.softmax(data=fc1, name="softmax") - - -def get_symbol(num_classes, num_layers, image_shape, conv_workspace=256, dtype="float32", **kwargs): - """ - Adapted from https://github.com/tornadomeet/ResNet/blob/master/train_resnet.py - Original author Wei Wu - """ - image_shape = [int(l) for l in image_shape.split(",")] - (nchannel, height, width) = image_shape - if height <= 28: - num_stages = 3 - if (num_layers - 2) % 9 == 0 and num_layers >= 164: - per_unit = [(num_layers - 2) // 9] - filter_list = [16, 64, 128, 256] - bottle_neck = True - elif (num_layers - 2) % 6 == 0 and num_layers < 164: - per_unit = [(num_layers - 2) // 6] - filter_list = [16, 16, 32, 64] - bottle_neck = False - else: - raise ValueError( - "no experiments done on num_layers {}, you can do it yourself".format(num_layers) - ) - units = per_unit * num_stages - else: - if num_layers >= 50: - filter_list = [64, 256, 512, 1024, 2048] - bottle_neck = True - else: - filter_list = [64, 64, 128, 256, 512] - bottle_neck = False - num_stages = 4 - if num_layers == 18: - units = [2, 2, 2, 2] - elif num_layers == 34: - units = [3, 4, 6, 3] - elif num_layers == 50: - units = [3, 4, 6, 3] - elif num_layers == 101: - units = [3, 4, 23, 3] - elif num_layers == 152: - units = [3, 8, 36, 3] - elif num_layers == 200: - units = [3, 24, 36, 3] - elif num_layers == 269: - units = [3, 30, 48, 8] - else: - raise ValueError( - "no experiments done on num_layers {}, you can do it yourself".format(num_layers) - ) - - return resnet( - units=units, - num_stages=num_stages, - filter_list=filter_list, - num_classes=num_classes, - image_shape=image_shape, - bottle_neck=bottle_neck, - workspace=conv_workspace, - dtype=dtype, - ) diff --git a/tests/python/frontend/mxnet/model_zoo/squeezenet.py b/tests/python/frontend/mxnet/model_zoo/squeezenet.py deleted file mode 100644 index 146f7fa7e8e6..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/squeezenet.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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. -""" -Symbol of SqueezeNet - -Reference: -Iandola, Forrest N., et al. -"Squeezenet: Alexnet-level accuracy with 50x fewer parameters and< 0.5 mb model size." (2016). -""" - -import mxnet as mx - -# Helpers -def _make_fire(net, squeeze_channels, expand1x1_channels, expand3x3_channels): - net = _make_fire_conv(net, squeeze_channels, 1, 0) - - left = _make_fire_conv(net, expand1x1_channels, 1, 0) - right = _make_fire_conv(net, expand3x3_channels, 3, 1) - # NOTE : Assume NCHW layout here - net = mx.sym.concat(left, right, dim=1) - - return net - - -def _make_fire_conv(net, channels, kernel_size, padding=0): - net = mx.sym.Convolution( - net, num_filter=channels, kernel=(kernel_size, kernel_size), pad=(padding, padding) - ) - net = mx.sym.Activation(net, act_type="relu") - return net - - -# Net -def get_symbol(num_classes=1000, version="1.0", **kwargs): - """Get symbol of SqueezeNet - - Parameters - ---------- - num_classes: int - The number of classification results - - version : str, optional - "1.0" or "1.1" of SqueezeNet - """ - assert version in [ - "1.0", - "1.1", - ], "Unsupported SqueezeNet version {version}:" "1.0 or 1.1 expected".format(version=version) - net = mx.sym.Variable("data") - if version == "1.0": - net = mx.sym.Convolution(net, num_filter=96, kernel=(7, 7), stride=(2, 2), pad=(3, 3)) - net = mx.sym.Activation(net, act_type="relu") - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 16, 64, 64) - net = _make_fire(net, 16, 64, 64) - net = _make_fire(net, 32, 128, 128) - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 32, 128, 128) - net = _make_fire(net, 48, 192, 192) - net = _make_fire(net, 48, 192, 192) - net = _make_fire(net, 64, 256, 256) - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 64, 256, 256) - else: - net = mx.sym.Convolution(net, num_filter=64, kernel=(3, 3), stride=(2, 2), pad=(1, 1)) - net = mx.sym.Activation(net, act_type="relu") - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 16, 64, 64) - net = _make_fire(net, 16, 64, 64) - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 32, 128, 128) - net = _make_fire(net, 32, 128, 128) - net = mx.sym.Pooling(data=net, kernel=(3, 3), pool_type="max", stride=(2, 2)) - net = _make_fire(net, 48, 192, 192) - net = _make_fire(net, 48, 192, 192) - net = _make_fire(net, 64, 256, 256) - net = _make_fire(net, 64, 256, 256) - net = mx.sym.Dropout(net, p=0.5) - net = mx.sym.Convolution(net, num_filter=num_classes, kernel=(1, 1)) - net = mx.sym.Activation(net, act_type="relu") - net = mx.sym.Pooling(data=net, global_pool=True, kernel=(13, 13), pool_type="avg") - net = mx.sym.flatten(net) - return mx.sym.softmax(net) diff --git a/tests/python/frontend/mxnet/model_zoo/vgg.py b/tests/python/frontend/mxnet/model_zoo/vgg.py deleted file mode 100644 index 157803446811..000000000000 --- a/tests/python/frontend/mxnet/model_zoo/vgg.py +++ /dev/null @@ -1,108 +0,0 @@ -# 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. - -"""References: - -Simonyan, Karen, and Andrew Zisserman. "Very deep convolutional networks for -large-scale image recognition." arXiv preprint arXiv:1409.1556 (2014). -""" - -import mxnet as mx -import numpy as np - - -def get_feature(internel_layer, layers, filters, batch_norm=False, **kwargs): - for i, num in enumerate(layers): - for j in range(num): - internel_layer = mx.sym.Convolution( - data=internel_layer, - kernel=(3, 3), - pad=(1, 1), - num_filter=filters[i], - name="conv%s_%s" % (i + 1, j + 1), - ) - if batch_norm: - internel_layer = mx.symbol.BatchNorm( - data=internel_layer, name="bn%s_%s" % (i + 1, j + 1) - ) - internel_layer = mx.sym.Activation( - data=internel_layer, act_type="relu", name="relu%s_%s" % (i + 1, j + 1) - ) - internel_layer = mx.sym.Pooling( - data=internel_layer, - pool_type="max", - kernel=(2, 2), - stride=(2, 2), - name="pool%s" % (i + 1), - ) - return internel_layer - - -def get_classifier(input_data, num_classes, **kwargs): - flatten = mx.sym.Flatten(data=input_data, name="flatten") - try: - fc6 = mx.sym.FullyConnected(data=flatten, num_hidden=4096, name="fc6", flatten=False) - relu6 = mx.sym.Activation(data=fc6, act_type="relu", name="relu6") - drop6 = mx.sym.Dropout(data=relu6, p=0.5, name="drop6") - fc7 = mx.sym.FullyConnected(data=drop6, num_hidden=4096, name="fc7", flatten=False) - relu7 = mx.sym.Activation(data=fc7, act_type="relu", name="relu7") - drop7 = mx.sym.Dropout(data=relu7, p=0.5, name="drop7") - fc8 = mx.sym.FullyConnected(data=drop7, num_hidden=num_classes, name="fc8", flatten=False) - except: - fc6 = mx.sym.FullyConnected(data=flatten, num_hidden=4096, name="fc6") - relu6 = mx.sym.Activation(data=fc6, act_type="relu", name="relu6") - drop6 = mx.sym.Dropout(data=relu6, p=0.5, name="drop6") - fc7 = mx.sym.FullyConnected(data=drop6, num_hidden=4096, name="fc7") - relu7 = mx.sym.Activation(data=fc7, act_type="relu", name="relu7") - drop7 = mx.sym.Dropout(data=relu7, p=0.5, name="drop7") - fc8 = mx.sym.FullyConnected(data=drop7, num_hidden=num_classes, name="fc8") - return fc8 - - -def get_symbol(num_classes, num_layers=11, batch_norm=False, dtype="float32", **kwargs): - """ - Parameters - ---------- - num_classes : int, default 1000 - Number of classification classes. - num_layers : int - Number of layers for the variant of densenet. Options are 11, 13, 16, 19. - batch_norm : bool, default False - Use batch normalization. - dtype: str, float32 or float16 - Data precision. - """ - vgg_spec = { - 11: ([1, 1, 2, 2, 2], [64, 128, 256, 512, 512]), - 13: ([2, 2, 2, 2, 2], [64, 128, 256, 512, 512]), - 16: ([2, 2, 3, 3, 3], [64, 128, 256, 512, 512]), - 19: ([2, 2, 4, 4, 4], [64, 128, 256, 512, 512]), - } - if num_layers not in vgg_spec: - raise ValueError( - "Invalide num_layers {}. Possible choices are 11,13,16,19.".format(num_layers) - ) - layers, filters = vgg_spec[num_layers] - data = mx.sym.Variable(name="data") - if dtype == "float16": - data = mx.sym.Cast(data=data, dtype=np.float16) - feature = get_feature(data, layers, filters, batch_norm) - classifier = get_classifier(feature, num_classes) - if dtype == "float16": - classifier = mx.sym.Cast(data=classifier, dtype=np.float32) - symbol = mx.sym.softmax(data=classifier, name="softmax") - return symbol diff --git a/tests/python/frontend/mxnet/test_forward.py b/tests/python/frontend/mxnet/test_forward.py deleted file mode 100644 index cf206a3d5261..000000000000 --- a/tests/python/frontend/mxnet/test_forward.py +++ /dev/null @@ -1,2369 +0,0 @@ -# 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 operator -import random - -import numpy as np -import pytest -import tvm -import tvm.testing -from tvm import relay, te -from tvm.contrib import graph_executor - -import model_zoo -import mxnet as mx -from mxnet import gluon -from mxnet.gluon.model_zoo import vision - - -def verify_mxnet_frontend_impl( - mx_symbol, - data_shape=(1, 3, 224, 224), - out_shape=(1, 1000), - gluon_impl=False, - name=None, - dtype="float32", -): - """Use name different from test to avoid pytest picking it up""" - if gluon_impl: - - def get_gluon_output(name, x): - try: - net = vision.get_model(name) - except RuntimeError: - pytest.skip(reason="mxnet downloads no longer supported") - net.collect_params().initialize(mx.init.Xavier()) - net_sym = gluon.nn.SymbolBlock( - outputs=net(mx.sym.var("data")), - inputs=mx.sym.var("data"), - params=net.collect_params(), - ) - out = net_sym(mx.nd.array(x.astype(dtype))).asnumpy() - return out, net_sym - - else: - - def get_mxnet_output(symbol, x, dtype="float32"): - from collections import namedtuple - - Batch = namedtuple("Batch", ["data"]) - mod = mx.mod.Module(symbol, label_names=None) - mod.bind(data_shapes=[("data", x.shape)], for_training=False) - mod.init_params() - mod.forward(Batch([mx.nd.array(x.astype(dtype))])) - out = mod.get_outputs()[0].asnumpy() - args, auxs = mod.get_params() - return out, args, auxs - - def get_tvm_output(symbol, x, args, auxs, target, dev, dtype="float32"): - shape_dict = {"data": x.shape} - if gluon_impl: - mod, params = relay.frontend.from_mxnet(symbol, shape_dict) - else: - mod, params = relay.frontend.from_mxnet( - symbol, shape_dict, arg_params=args, aux_params=auxs - ) - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target, params=params) - m = graph_executor.GraphModule(lib["default"](dev)) - # set inputs - m.set_input("data", tvm.nd.array(x.astype(dtype))) - m.run() - # get outputs - out = m.get_output(0, tvm.nd.empty(out_shape, dtype)) - return out.numpy() - - # random input - x = np.random.uniform(size=data_shape) - if gluon_impl: - gluon_out, gluon_sym = get_gluon_output(name, x) - for target, dev in tvm.testing.enabled_targets(): - tvm_out = get_tvm_output(gluon_sym, x, None, None, target, dev, dtype) - tvm.testing.assert_allclose(gluon_out, tvm_out, rtol=1e-5, atol=1e-5) - else: - mx_out, args, auxs = get_mxnet_output(mx_symbol, x, dtype) - assert "data" not in args - for target, dev in tvm.testing.enabled_targets(): - tvm_out = get_tvm_output(mx_symbol, x, args, auxs, target, dev, dtype) - tvm.testing.assert_allclose(mx_out, tvm_out, rtol=1e-5, atol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_mlp(): - mlp = model_zoo.mx_mlp() - verify_mxnet_frontend_impl(mlp, data_shape=(1, 1, 28, 28), out_shape=(1, 10)) - - -@tvm.testing.uses_gpu -def test_forward_vgg(): - for n in [11]: - mx_sym = model_zoo.mx_vgg(n) - verify_mxnet_frontend_impl(mx_sym) - - -@tvm.testing.uses_gpu -def test_forward_resnet(): - for n in [18]: - mx_sym = model_zoo.mx_resnet(18) - verify_mxnet_frontend_impl(mx_sym) - - -@tvm.testing.uses_gpu -def test_forward_leaky_relu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.LeakyReLU(data) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - mx_sym = mx.sym.LeakyReLU(data, act_type="leaky") - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_elu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.LeakyReLU(data, act_type="elu") - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_rrelu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.LeakyReLU(data, act_type="rrelu", lower_bound=0.3, upper_bound=0.7) - verify_mxnet_frontend_impl(mx_sym[0], (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_prelu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.LeakyReLU(data, act_type="prelu") - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_gelu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.LeakyReLU(data, act_type="gelu") - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_softrelu(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.Activation(data, act_type="softrelu") - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_fc_flatten(): - # test flatten=True option in mxnet 0.11.1 - data = mx.sym.var("data") - try: - mx_sym = mx.sym.FullyConnected(data, num_hidden=100, flatten=True) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 100)) - mx_sym = mx.sym.FullyConnected(mx.sym.Flatten(data), num_hidden=100, flatten=False) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 100)) - except: - pass - - -@tvm.testing.uses_gpu -def test_forward_clip(): - data = mx.sym.var("data") - data = mx.sym.concat(data, -data, dim=1) # negative part explicitly - mx_sym = mx.sym.clip(data, a_min=0, a_max=1) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 6, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_split(): - data = mx.sym.var("data") - mx_sym = mx.sym.split(data, axis=1, num_outputs=4, squeeze_axis=False) - verify_mxnet_frontend_impl(mx_sym, (1, 4, 2, 1), (1, 1, 2, 1)) - - -@tvm.testing.uses_gpu -def test_forward_split_squeeze(): - data = mx.sym.var("data") - mx_sym = mx.sym.split(data, axis=1, num_outputs=4, squeeze_axis=True) - verify_mxnet_frontend_impl(mx_sym, (1, 4, 2, 1), (1, 2, 1)) - - -@tvm.testing.uses_gpu -def test_forward_expand_dims(): - data = mx.sym.var("data") - mx_sym = mx.sym.expand_dims(data, axis=1) - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 1, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_pooling(): - data = mx.sym.var("data") - mx_sym = mx.sym.Pooling(data, kernel=(3, 3), pad=(1, 1), pool_type="avg") - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8), (1, 20, 8, 8)) - - mx_sym = mx.sym.Pooling(data, kernel=(3, 3), pad=(1, 1), pool_type="max") - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8), (1, 20, 8, 8)) - - -@tvm.testing.uses_gpu -def test_forward_pooling3d(): - data = mx.sym.var("data") - mx_sym = mx.sym.Pooling(data, kernel=(3, 3, 3), pad=(1, 1, 1), pool_type="avg") - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8, 8), (1, 20, 8, 8, 8)) - - mx_sym = mx.sym.Pooling(data, kernel=(3, 3, 3), pad=(1, 1, 1), pool_type="max") - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8, 8), (1, 20, 8, 8, 8)) - - -@tvm.testing.uses_gpu -def test_forward_adaptive_pooling(): - data = mx.sym.var("data") - mx_sym = mx.sym.contrib.AdaptiveAvgPooling2D(data, output_size=(1,)) - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8), (1, 20, 1, 1)) - - mx_sym = mx.sym.contrib.AdaptiveAvgPooling2D(data, output_size=(3, 3)) - verify_mxnet_frontend_impl(mx_sym, (1, 20, 8, 8), (1, 20, 3, 3)) - - -@tvm.testing.uses_gpu -def test_forward_lrn(): - data = mx.sym.var("data") - mx_sym = mx.sym.LRN(data, alpha=2, beta=2, knorm=1, nsize=5) - verify_mxnet_frontend_impl(mx_sym, (1, 10, 24, 24), (1, 10, 24, 24)) - - -@tvm.testing.uses_gpu -def test_forward_ones(): - data = mx.sym.var("data") - ones = mx.sym.ones(shape=(2, 3, 4), dtype="float32") - mx_sym = mx.sym.elemwise_add(data, ones) - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_zeros(): - data = mx.sym.var("data") - zeros = mx.sym.zeros(shape=(2, 3, 4), dtype="float32") - mx_sym = mx.sym.elemwise_add(data, zeros) - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_ones_like(): - data = mx.sym.var("data") - mx_sym = mx.sym.ones_like(data, dtype="float32") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_make_loss(): - data = mx.sym.var("data") - ones = mx.sym.ones(shape=(2, 3, 4), dtype="float32") - mx_sym = mx.sym.make_loss((data - ones) ** 2 / 2, dtype="float32") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_zeros_like(): - data = mx.sym.var("data") - mx_sym = mx.sym.zeros_like(data, dtype="float32") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4), (2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_argmax(): - data = mx.sym.var("data") - mx_sym = mx.sym.argmax(data, axis=1) - verify_mxnet_frontend_impl(mx_sym, (5, 3), (5,)) - - -@tvm.testing.uses_gpu -def test_forward_argmin(): - data = mx.sym.var("data") - mx_sym = mx.sym.argmin(data, axis=0) - verify_mxnet_frontend_impl(mx_sym, (5, 4), (4,)) - - -@tvm.testing.uses_gpu -def test_forward_slice(): - data = mx.sym.var("data") - mx_sym = mx.sym.slice(data, begin=(0, 1), end=(2, 4)) - verify_mxnet_frontend_impl(mx_sym, (3, 4), (2, 3)) - mx_sym = mx.sym.slice(data, begin=(-1, 1), end=(-3, 4), step=(-1, 2)) - verify_mxnet_frontend_impl(mx_sym, (3, 4), (2, 2)) - - -@tvm.testing.uses_gpu -def test_forward_where(): - cond = mx.sym.var("cond") - x = mx.sym.var("x") - y = mx.sym.var("y") - dshape = (2, 2) - dtype = "float32" - mx_sym = mx.sym.where(cond, x, y) - np_cond = np.array([[0, 1], [-1, 0]]).astype(dtype) - np_x = np.random.uniform(size=dshape).astype(dtype) - np_y = np.random.uniform(size=dshape).astype(dtype) - mx_cond = mx.nd.array(np_cond) - mx_x = mx.nd.array(np_x) - mx_y = mx.nd.array(np_y) - shapes = {"cond": dshape, "x": dshape, "y": dshape} - mod = mx.mod.Module(mx_sym, label_names=None, data_names=["cond", "x", "y"]) - mod.bind(data_shapes=shapes.items(), for_training=False) - mod.init_params() - args, auxs = mod.get_params() - mx_out = mx.nd.where(mx_cond, mx_x, mx_y).asnumpy() - - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, args, auxs) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - np_cond, np_x, np_y - ) - tvm.testing.assert_allclose(op_res.numpy(), mx_out) - - -@tvm.testing.uses_gpu -def test_forward_arange(): - def _mx_symbol(F, start, stop, step): - if start is None and step is None: - sym = F.arange(stop) - elif start is None: - sym = F.arange(stop, step=step) - elif step is None: - sym = F.arange(start, stop) - else: - sym = F.arange(start, stop, step) - return sym - - def verify(start, stop, step): - ref_res = _mx_symbol(mx.nd, start, stop, step) - mx_sym = _mx_symbol(mx.sym, start, stop, step) - mod, _ = relay.frontend.from_mxnet(mx_sym, {}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor( - kind, mod=mod, device=dev, target=target - ).evaluate()() - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify(0, 20, None) - verify(0, 20, 2) - verify(1, 20, None) - verify(1, 20, 2) - verify(1, 20, 1.5) - verify(1, 20.5, None) - verify(1, 20, 3) - verify(20, 1, -1) - verify(20, 1, -1.5) - - -def _mx_symbol(F, op_name, inputs): - op = getattr(F, op_name) - return op(*inputs) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_ops(): - for op in [ - "broadcast_add", - "broadcast_plus", - "broadcast_sub", - "broadcast_minus", - "broadcast_mul", - "broadcast_div", - "broadcast_mod", - "broadcast_maximum", - "broadcast_minimum", - "broadcast_equal", - "broadcast_not_equal", - "broadcast_greater", - "broadcast_greater_equal", - "broadcast_lesser", - "broadcast_lesser_equal", - "broadcast_power", - "broadcast_logical_or", - "broadcast_logical_and", - "broadcast_logical_xor", - ]: - a_shape = (3, 4, 5) - b_shape = (4, 5) - if op == "broadcast_mod": - dtype = "int32" - a_np = np.random.randint(1, 100, size=a_shape).astype(dtype) - b_np = np.random.randint(1, 100, size=b_shape).astype(dtype) - else: - dtype = "float32" - a_np = np.random.uniform(size=a_shape).astype(dtype) - b_np = np.random.uniform(size=b_shape).astype(dtype) - mx_sym = _mx_symbol(mx.sym, op, [mx.sym.var("a"), mx.sym.var("b")]) - ref_res = _mx_symbol(mx.nd, op, [mx.nd.array(a_np), mx.nd.array(b_np)]) - shapes = {"a": a_shape, "b": b_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np, b_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - -@tvm.testing.uses_gpu -def test_forward_elemwise_ops(): - for op in [ - "elemwise_add", - "elemwise_sub", - "elemwise_mul", - "elemwise_div", - "maximum", - "minimum", - operator.lt, - operator.le, - operator.eq, - operator.ne, - operator.gt, - operator.ge, - ]: - shape = (3, 4, 5) - dtype = "float32" - a_np = np.random.uniform(size=shape).astype(dtype) - b_np = np.random.uniform(size=shape).astype(dtype) - if type(op) == str: - mx_sym = _mx_symbol(mx.sym, op, [mx.sym.var("a"), mx.sym.var("b")]) - ref_res = _mx_symbol(mx.nd, op, [mx.nd.array(a_np), mx.nd.array(b_np)]) - else: - mx_sym = op(mx.sym.var("a"), mx.sym.var("b")) - ref_res = op(mx.nd.array(a_np), mx.nd.array(b_np)) - shapes = {"a": shape, "b": shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np, b_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - -@tvm.testing.uses_gpu -def test_forward_softmin(): - data = mx.sym.var("data") - mx_sym = mx.sym.softmin(data) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 3, 100, 100)) - - mx_sym = mx.sym.softmin(data, axis=2) - verify_mxnet_frontend_impl(mx_sym, (1, 3, 100, 100), (1, 3, 100, 100)) - - -@tvm.testing.uses_gpu -def test_forward_unary_ops(): - for op in [ - "abs", - "sqrt", - "ceil", - "floor", - "round", - "reciprocal", - "trunc", - "softsign", - "hard_sigmoid", - "cos", - "sin", - "tan", - "cosh", - "sinh", - "tanh", - "arccos", - "arcsin", - "arctan", - "arccosh", - "arcsinh", - "arctanh", - ]: - shape = (1, 3, 4, 5) - dtype = "float32" - a_np = np.random.uniform(size=shape).astype(dtype) - mx_sym = _mx_symbol(mx.sym, op, [mx.sym.var("a")]) - ref_res = _mx_symbol(mx.nd, op, [mx.nd.array(a_np)]) - shapes = {"a": shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5, atol=1e-5) - - -@tvm.testing.uses_gpu -def test_forward_scalar_ops(): - for op in [ - operator.add, - operator.sub, - operator.mul, - operator.truediv, - operator.pow, - operator.lt, - operator.le, - operator.eq, - operator.ne, - operator.gt, - operator.ge, - ]: - dtype = "float32" - a_shape = (3, 4, 5) - a_np = np.random.uniform(size=a_shape).astype(dtype) - b_scalar = 2.3 - mx_sym = op(mx.sym.var("a"), b_scalar) - ref_res = op(mx.nd.array(a_np), b_scalar) - shapes = {"a": a_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - for op in ["maximum", "minimum"]: - dtype = "float32" - a_shape = (3, 4, 5) - a_np = np.random.uniform(size=a_shape).astype(dtype) - b_scalar = 2.3 - mx_sym = _mx_symbol(mx.sym, op, [mx.sym.var("a"), b_scalar]) - ref_res = _mx_symbol(mx.nd, op, [mx.nd.array(a_np), b_scalar]) - shapes = {"a": a_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - -@tvm.testing.uses_gpu -def test_forward_slice_axis(): - def verify(shape, axis, begin, end): - data_np = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.slice_axis(mx.nd.array(data_np), axis, begin, end) - mx_sym = mx.sym.slice_axis(mx.sym.var("data"), axis, begin, end) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((3, 4), 0, 1, 2) - verify((3, 4), 0, 1, None) - verify((3, 4), 1, 0, 2) - verify((3, 4), 1, -3, -1) - verify((3, 4), -1, -3, -1) - - -@tvm.testing.uses_gpu -def test_forward_slice_like(): - def verify(x_shape, y_shape, axes): - x_np = np.random.uniform(size=x_shape).astype("float32") - y_np = np.random.uniform(size=y_shape).astype("float32") - if axes is None: - ref_res = mx.nd.slice_like(mx.nd.array(x_np), mx.nd.array(y_np)) - mx_sym = mx.sym.slice_like(mx.sym.var("x"), mx.sym.var("y")) - else: - ref_res = mx.nd.slice_like(mx.nd.array(x_np), mx.nd.array(y_np), axes=axes) - mx_sym = mx.sym.slice_like(mx.sym.var("x"), mx.sym.var("y"), axes=axes) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": x_shape, "y": y_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np, y_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((3, 4), (2, 3), None) - verify((3, 4), (2, 3), (0, 1)) - verify((3, 4), (2, 3), (0)) - verify((3, 4), (2, 3), (-1)) - - -@tvm.testing.uses_gpu -def test_forward_sequence_reverse(): - def verify(shape, seq_lengths, use_seq_lengths, seq_axis): - data_np = np.random.uniform(size=shape).astype("float32") - - ref_res_args = [mx.nd.array(data_np), None, use_seq_lengths, seq_axis] - mx_sym_args = [mx.sym.var("data"), None, use_seq_lengths, seq_axis] - from_mxnet_args = [{"data": shape}, {"data": "float32"}] - in_data = [data_np] - - if use_seq_lengths and seq_lengths: - seq_lengths_np = np.array(seq_lengths).astype("int32") - ref_res_args[1] = mx.nd.array(seq_lengths_np) - mx_sym_args[1] = mx.sym.var("seq_lengths") - from_mxnet_args[0].update({"seq_lengths": seq_lengths_np.shape}) - from_mxnet_args[1].update({"seq_lengths": "int32"}) - in_data.append(seq_lengths_np) - - ref_res = mx.nd.SequenceReverse(*ref_res_args) - mx_sym = mx.sym.SequenceReverse(*mx_sym_args) - mod, _ = relay.frontend.from_mxnet(mx_sym, *from_mxnet_args) - - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - *in_data - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((3, 4), [1, 2, 3, 1], True, 0) - verify((3, 4), None, False, 0) - verify((3, 5, 5, 6), [1, 2, 3, 1, 3], True, 0) - # MXNet accepts axis value as 0 only - # verify((3, 4, 5, 6), None, False, 2) - - -@tvm.testing.uses_gpu -def test_forward_l2_normalize(): - data = mx.sym.var("data") - mx_sym = mx.sym.L2Normalization(data, mode="channel") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4, 5), (2, 3, 4, 5)) - - mx_sym = mx.sym.L2Normalization(data, mode="instance") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4, 5), (2, 3, 4, 5)) - - mx_sym = mx.sym.L2Normalization(data, mode="spatial") - verify_mxnet_frontend_impl(mx_sym, (2, 3, 4, 5), (2, 3, 4, 5)) - - -@tvm.testing.uses_gpu -def test_forward_logistic_regression_output(): - data_shape = (1, 10) - dtype = "float32" - data_np = np.random.uniform(size=data_shape).astype(dtype) - label_np = np.random.uniform(size=data_shape).astype(dtype) - mx_sym = mx.symbol.LogisticRegressionOutput(mx.sym.var("data"), mx.sym.var("label")) - ref_res = mx.nd.LogisticRegressionOutput(mx.nd.array(data_np), mx.nd.array(label_np)) - shapes = {"data": data_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - -@tvm.testing.uses_gpu -def test_forward_dot(): - def verify(a_shape, b_shape, transpose_b=False): - dtype = "float32" - a_np = np.random.uniform(size=a_shape).astype(dtype) - b_np = np.random.uniform(size=b_shape).astype(dtype) - mx_sym = mx.symbol.dot(mx.sym.var("a"), mx.sym.var("b"), transpose_b=transpose_b) - ref_res = mx.nd.dot(mx.nd.array(a_np), mx.nd.array(b_np), transpose_b=transpose_b) - shapes = {"a": a_shape, "b": b_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np, b_np - ) - tvm.testing.assert_allclose( - op_res.numpy(), ref_res.asnumpy(), rtol=1e-05, atol=1e-05 - ) - - verify((1, 256), (256, 1)) - verify((1, 256), (1, 256), transpose_b=True) - verify((5,), (5,)) - verify((3,), (3, 5)) - verify((3,), (5, 3), transpose_b=True) - verify((3,), (3, 5, 3, 5)) - verify((3,), (5, 5, 3, 3), transpose_b=True) - verify((10, 1), (1,)) - verify((1, 1), (4, 3, 2, 1), transpose_b=True) - verify((4, 3, 2, 1), (1,)) - verify((1, 2, 3, 4), (1, 4), transpose_b=True) - verify((4, 1, 1), (1, 2, 3)) - verify((1, 1, 4), (2, 3, 4), transpose_b=True) - - -@tvm.testing.uses_gpu -def test_forward_shape_array(): - def verify(shape): - x_np = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.shape_array(mx.nd.array(x_np)) - mx_sym = mx.sym.shape_array(mx.sym.var("x")) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1,)) - verify((3, 4, 5)) - verify((3, 4, 5, 6)) - - -@tvm.testing.uses_gpu -def test_forward_squeeze(): - def verify(shape, axis): - x_np = np.random.uniform(size=shape).astype("float32") - if axis is None: - ref_res = mx.nd.squeeze(mx.nd.array(x_np)) - mx_sym = mx.sym.squeeze(mx.sym.var("x")) - else: - ref_res = mx.nd.squeeze(mx.nd.array(x_np), axis=axis) - mx_sym = mx.sym.squeeze(mx.sym.var("x"), axis=axis) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1, 3, 1), None) - verify((1, 3, 1), 0) - verify((1, 3, 1), 2) - verify((1, 3, 1), (0, 2)) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_axis(): - def verify(shape, axis, size): - x_np = np.random.uniform(size=shape).astype("float32") - for op in ["broadcast_axis", "broadcast_axes"]: - mx_sym = _mx_symbol(mx.sym, op, [mx.sym.var("x"), axis, size]) - ref_res = _mx_symbol(mx.nd, op, [mx.nd.array(x_np), axis, size]) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor( - kind, mod=mod, device=dev, target=target - ).evaluate()(x_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1, 2, 1), 2, 3) - verify((1, 2, 1), (0, 2), (2, 3)) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_to(): - def verify(input_shape, shape): - x_np = np.random.uniform(size=input_shape).astype("float32") - ref_res = mx.nd.broadcast_to(mx.nd.array(x_np), shape=shape) - mx_sym = mx.sym.broadcast_to(mx.sym.var("x"), shape=shape) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": input_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1, 2, 3), (3, 2, 3)) - verify((4, 1, 32, 32), (4, 8, 32, 32)) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_like(): - def verify(input_shape, like_shape): - x_np = np.random.uniform(size=input_shape).astype("float32") - y_np = np.random.uniform(size=like_shape).astype("float32") - ref_res = mx.nd.broadcast_like(mx.nd.array(x_np), mx.nd.array(y_np)) - mx_sym = mx.sym.broadcast_like(mx.sym.var("x"), mx.sym.var("y")) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": input_shape, "y": like_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np, y_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1, 2, 3), (3, 2, 3)) - verify((4, 1, 32, 32), (4, 8, 32, 32)) - - -@tvm.testing.uses_gpu -def test_forward_logical_not(): - a_shape = (3, 4, 5) - dtype = "float32" - a_np = np.random.uniform(size=a_shape).astype(dtype) - mx_sym = mx.sym.logical_not(mx.sym.var("a")) - ref_res = mx.nd.logical_not(mx.nd.array(a_np)) - shapes = {"a": a_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - -@tvm.testing.uses_gpu -def test_forward_full(): - def verify(val, shape, dtype): - dev = mx.cpu() - ref_res = mx.nd.full(shape, val, dtype=dtype) - mx_sym = mx.sym.full(shape, val, dtype=dtype) - mod, _ = relay.frontend.from_mxnet(mx_sym, {}) - for target, dev in tvm.testing.enabled_targets(): - # Skip testing graph executor because this op will be optimized out - # by constant folding. - for kind in ["debug"]: - op_res = relay.create_executor( - kind, mod=mod, device=dev, target=target - ).evaluate()() - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify(2, (3, 4), "float32") - verify(2, (3, 4), "int32") - verify(3.5, (1, 3, 4), "float32") - - -@tvm.testing.uses_gpu -def test_forward_embedding(): - def verify(data_shape, weight_shape): - in_dim, out_dim = weight_shape - x_np = np.random.randint(0, weight_shape[0], size=data_shape).astype("float32") - w_np = np.random.uniform(size=weight_shape).astype("float32") - ref_res = mx.nd.Embedding( - mx.nd.array(x_np), mx.nd.array(w_np), input_dim=in_dim, output_dim=out_dim - ) - mx_sym = mx.sym.Embedding( - mx.sym.var("x"), mx.sym.var("w"), input_dim=in_dim, output_dim=out_dim - ) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": data_shape, "w": weight_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x=x_np, w=w_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((2, 2), (4, 5)) - verify((2, 3, 4), (4, 5)) - - -@tvm.testing.uses_gpu -def test_forward_smooth_l1(): - data = mx.sym.var("data") - mx_sym = mx.sym.smooth_l1(data) - verify_mxnet_frontend_impl(mx_sym, (3, 4), (3, 4)) - mx_sym = mx.sym.smooth_l1(data, scalar=1.0) - verify_mxnet_frontend_impl(mx_sym, (3, 4), (3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_take(): - def verify(shape, indices_src, axis, mode="clip"): - x_np = np.random.uniform(size=shape).astype("float32") - indices_np = np.array(indices_src, dtype="float32") - ref_res = mx.nd.take(mx.nd.array(x_np), mx.nd.array(indices_np), axis, mode) - mx_sym = mx.sym.take(mx.sym.var("x"), mx.sym.var("y"), axis, mode) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape, "y": indices_np.shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np, indices_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((2, 2), [[[1, 0], [0, 1]]], 0) - verify((2, 2), [[[1, 0], [0, 1]]], 1) - verify((4, 3, 5, 6), [[2, 1, 0, 0]], -2) - verify((3, 4), [-1, 5], 0) - verify((3, 4), [-1, 5], 0, mode="wrap") - verify((3, 4), [-1, 5], 1) - verify((3, 4), [-1, 5], 1, mode="wrap") - - -@tvm.testing.uses_gpu -def test_forward_gather_nd(): - def verify(xshape, yshape, y_data, error=False): - x_data = np.random.uniform(size=xshape).astype("float32") - ref_res = mx.nd.gather_nd(mx.nd.array(x_data), mx.nd.array(y_data)) - mx_sym = mx.sym.gather_nd(mx.sym.var("x_data"), mx.sym.var("y_data")) - mod, _ = relay.frontend.from_mxnet( - mx_sym, {"x_data": xshape, "y_data": yshape}, {"x_data": "float32", "y_data": "int32"} - ) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_data, y_data - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((2, 2), (2, 3), [[1, 1, 0], [0, 1, 0]]) - verify((2, 2, 2), (2, 2), [[0, 1], [1, 0]]) - verify((3, 2, 2), (2, 2), [[0, 1], [1, 0]]) - verify((3, 2), (2, 2, 3), [[[0, 1, 2], [2, 0, 1]], [[0, 0, 0], [1, 1, 1]]]) - verify((1, 4), (1, 1), [[0]]) - - -@tvm.testing.uses_gpu -def test_forward_bilinear_resize(): - # add tests including scale_height and scale_width when mxnet is updated to version 1.5 - data = mx.sym.var("data") - mx_sym = mx.sym.contrib.BilinearResize2D(data, height=5, width=10) - verify_mxnet_frontend_impl(mx_sym, (1, 2, 3, 4), (1, 2, 5, 10)) - - -@tvm.testing.uses_gpu -def test_forward_grid_generator(): - def verify(shape, transform_type, target_shape): - x = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.GridGenerator(mx.nd.array(x), transform_type, target_shape) - mx_sym = mx.sym.GridGenerator(mx.sym.var("x"), transform_type, target_shape) - shape_dict = {"x": x.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5, atol=1e-5) - - verify((4, 6), "affine", (16, 32)) - verify((4, 2, 16, 16), "warp", None) - verify((1, 2, 16, 16), "warp", None) - - -@tvm.testing.uses_gpu -def test_forward_bilinear_sampler(): - def verify(data_shape, grid_shape): - data = np.random.uniform(size=data_shape).astype("float32") - grid = np.random.uniform(low=-1.5, high=1.5, size=grid_shape).astype("float32") - ref_res = mx.nd.BilinearSampler(mx.nd.array(data), mx.nd.array(grid)) - mx_sym = mx.sym.BilinearSampler(mx.sym.var("data"), mx.sym.var("grid")) - shape_dict = {"data": data.shape, "grid": grid.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data, grid - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5, atol=1e-5) - - verify((4, 4, 16, 32), (4, 2, 8, 8)) - verify((4, 4, 16, 32), (4, 2, 32, 32)) - - -@tvm.testing.uses_gpu -def test_forward_rnn_layer(): - def verify( - mode, - seq_len, - input_size, - hidden_size, - num_layers, - batch=1, - init_states=True, - bidirectional=False, - ): - if mode == "rnn": - layer = gluon.rnn.RNN(hidden_size, num_layers, bidirectional=bidirectional) - elif mode == "gru": - layer = gluon.rnn.GRU(hidden_size, num_layers, bidirectional=bidirectional) - else: # mode == "lstm" - layer = gluon.rnn.LSTM(hidden_size, num_layers, bidirectional=bidirectional) - num_states = 2 if mode == "lstm" else 1 - layer.initialize() - layer.hybridize() - - dtype = "float32" - directions = 2 if bidirectional else 1 - data_np = np.random.uniform(size=(seq_len, batch, input_size)).astype(dtype) - data_mx = mx.nd.array(data_np) - - if init_states: - shape_dict = {"data0": data_np.shape} - inputs = {"data0": data_np} - state_shape = (num_layers * directions, batch, hidden_size) - states_np = [] - states_mx = [] - for i in range(num_states): - s = np.random.uniform(size=state_shape).astype(dtype) - states_np.append(s) - states_mx.append(mx.nd.array(s)) - shape_dict["data%s" % (i + 1)] = s.shape - inputs["data%s" % (i + 1)] = s - mx_out, mx_states = layer(data_mx, states_mx) - mx_res = [mx_out] + mx_states - else: - shape_dict = {"data": data_np.shape} - inputs = {"data": data_np} - mx_res = layer(data_mx) - - mx_sym = layer._cached_graph[1] - mx_params = {} - for name, param in layer.collect_params().items(): - mx_params[name] = param._reduce() - - mod, params = relay.frontend.from_mxnet(mx_sym, shape=shape_dict, arg_params=mx_params) - for target, dev in tvm.testing.enabled_targets(): - # only test graph executor because debug runtime is too slow - for kind in ["graph"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - **inputs, **params - ) - if init_states: - assert len(op_res) == len(mx_res) - for i, val in enumerate(op_res): - tvm.testing.assert_allclose(val.numpy(), mx_res[i].asnumpy(), rtol=1e-3) - else: - tvm.testing.assert_allclose(op_res.numpy(), mx_res.asnumpy(), rtol=1e-3) - - for mode in ["rnn", "gru", "lstm"]: - verify(mode, 1, 64, 64, 1) - verify(mode, 10, 64, 64, 2) - verify(mode, 10, 64, 32, 2) - verify(mode, 10, 64, 32, 2, batch=2) - verify(mode, 10, 32, 64, 1, bidirectional=True) - # The following two codeblocks need to be fixed for mxnet 1.5 - # verify(mode, 10, 64, 64, 3, init_states=False) - # verify(mode, 10, 64, 64, 3, batch=2, bidirectional=True, init_states=False) - - -@tvm.testing.uses_gpu -def test_forward_Crop(): - def verify(xshape, yshape, offset=None): - x_data = np.random.uniform(size=xshape).astype("float32") - y_data = np.random.uniform(size=yshape).astype("float32") - if offset is None: - mx_sym = mx.sym.Crop(mx.sym.var("x"), mx.sym.var("y")) - ref_res = mx.nd.Crop(mx.nd.array(x_data), mx.nd.array(y_data)) - else: - mx_sym = mx.sym.Crop(mx.sym.var("x"), mx.sym.var("y"), offset=offset) - ref_res = mx.nd.Crop(mx.nd.array(x_data), mx.nd.array(y_data), offset=offset) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": xshape, "y": yshape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - func = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate() - if offset is None or offset == (0, 0): - op_res = func(x_data, y_data) - else: - op_res = func(x_data) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((1, 3, 40, 40), (1, 3, 20, 20)) - verify((1, 3, 40, 40), (1, 3, 20, 20), (0, 0)) - verify((1, 3, 40, 40), (1, 3, 20, 20), (10, 10)) - verify((5, 32, 40, 40), (5, 32, 25, 25)) - verify((5, 32, 40, 40), (5, 32, 25, 25), (5, 5)) - - -@tvm.testing.uses_gpu -def test_forward_argsort(): - def verify(shape, axis, is_ascend, dtype="float32"): - x_np = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.argsort(mx.nd.array(x_np), axis=axis, is_ascend=is_ascend, dtype=dtype) - mx_sym = mx.sym.argsort(mx.sym.var("x"), axis=axis, is_ascend=is_ascend, dtype=dtype) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((2, 3, 4), axis=0, is_ascend=False) - verify((1, 4, 6), axis=1, is_ascend=True) - verify((3, 5, 6), axis=-3, is_ascend=False, dtype="int32") - - -@tvm.testing.uses_gpu -def test_forward_topk(): - def verify(shape, k, axis, ret_type, is_ascend=None, dtype="float32"): - x_np = np.random.uniform(size=shape).astype("float32") - if is_ascend is None: - ref_res = mx.nd.topk(mx.nd.array(x_np), k=k, axis=axis, ret_typ=ret_type, dtype=dtype) - mx_sym = mx.sym.topk(mx.sym.var("x"), k=k, axis=axis, ret_typ=ret_type, dtype=dtype) - else: - ref_res = mx.nd.topk( - mx.nd.array(x_np), - k=k, - axis=axis, - ret_typ=ret_type, - is_ascend=is_ascend, - dtype=dtype, - ) - mx_sym = mx.sym.topk( - mx.sym.var("x"), k=k, axis=axis, ret_typ=ret_type, is_ascend=is_ascend, dtype=dtype - ) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - if isinstance(ref_res, list): - assert len(op_res) == len(ref_res) - for i, t in enumerate(op_res): - tvm.testing.assert_allclose(t.numpy(), ref_res[i].asnumpy()) - else: - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((3, 4), k=1, axis=0, ret_type="both") - verify((3, 4), k=1, axis=-1, ret_type="indices") - verify((3, 5, 6), k=2, axis=2, ret_type="value", is_ascend=False) - verify((3, 5, 6), k=2, axis=1, ret_type="value", is_ascend=True) - verify((3, 5, 6), k=0, axis=2, ret_type="both", dtype="int32") - - -@tvm.testing.uses_gpu -def test_forward_sequence_mask(): - def verify(shape, use_sequence_length, value, axis, dtype, itype): - data_np = np.random.uniform(size=shape).astype(dtype) - valid_length_np = np.random.randint(0, shape[axis], size=shape[1 - axis]).astype(itype) - if use_sequence_length: - ref_res = mx.nd.SequenceMask( - mx.nd.array(data_np, dtype=dtype), - sequence_length=mx.nd.array(valid_length_np, dtype=itype), - use_sequence_length=use_sequence_length, - value=value, - axis=axis, - ) - mx_sym = mx.sym.SequenceMask( - mx.sym.var("data"), - sequence_length=mx.sym.var("valid_length"), - use_sequence_length=use_sequence_length, - value=value, - axis=axis, - ) - mod, _ = relay.frontend.from_mxnet( - mx_sym, - {"data": shape, "valid_length": valid_length_np.shape}, - dtype={"data": dtype, "valid_length": itype}, - ) - else: - ref_res = mx.nd.SequenceMask( - mx.nd.array(data_np, dtype=dtype), - use_sequence_length=use_sequence_length, - value=value, - axis=axis, - ) - mx_sym = mx.sym.SequenceMask( - mx.sym.var("data"), use_sequence_length=use_sequence_length, value=value, axis=axis - ) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": shape}, dtype={"data": dtype}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - if use_sequence_length is False and kind == "graph": - # Disable the test for 'graph' when it's identity. - continue - func = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate() - if use_sequence_length: - op_res = func(data_np, valid_length_np) - else: - op_res = func(data_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((5, 10), True, 0.0, 0, "float32", "float32") - verify((5, 4, 3), True, 1.0, 1, "float32", "float32") - verify((5, 4, 3), False, 1.0, 1, "float64", "float64") - verify((5, 4, 3, 2), True, 1.0, 0, "float32", "float32") - - -@tvm.testing.uses_gpu -def test_forward_contrib_div_sqrt_dim(): - def verify(shape): - x_np = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.contrib.div_sqrt_dim(mx.nd.array(x_np)) - mx_sym = mx.sym.contrib.div_sqrt_dim(mx.sym.var("x")) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"x": shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify((3, 4)) - verify((3, 4, 5)) - - -@tvm.testing.uses_gpu -def test_forward_batch_norm(): - def verify(shape, axis=1, fix_gamma=False): - x = np.random.uniform(size=shape).astype("float32") - gamma = np.random.uniform(size=(shape[axis])).astype("float32") - beta = np.random.uniform(size=(shape[axis])).astype("float32") - moving_mean = np.random.uniform(size=(shape[axis])).astype("float32") - moving_var = np.abs(np.random.uniform(size=(shape[axis])).astype("float32")) + 0.5 - ref_res = mx.nd.BatchNorm( - mx.nd.array(x), - mx.nd.array(gamma), - mx.nd.array(beta), - mx.nd.array(moving_mean), - mx.nd.array(moving_var), - axis=axis, - use_global_stats=True, - fix_gamma=fix_gamma, - ) - mx_sym = mx.sym.BatchNorm( - mx.sym.var("x"), - mx.sym.var("gamma"), - mx.sym.var("beta"), - mx.sym.var("mean"), - mx.sym.var("var"), - axis=axis, - use_global_stats=True, - fix_gamma=fix_gamma, - ) - - shape_dict = { - "x": x.shape, - "gamma": gamma.shape, - "beta": beta.shape, - "mean": moving_mean.shape, - "var": moving_var.shape, - } - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - # print(mod) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, gamma, beta, moving_mean, moving_var - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3) - - verify((2, 3, 4, 5)) - verify((2, 3, 4, 5), axis=0) - verify((2, 3, 4, 5), axis=-1) - verify((2, 3, 4, 5), fix_gamma=True) - - -@tvm.testing.uses_gpu -def test_forward_instance_norm(): - def verify(shape, axis=1, epsilon=1e-5): - x = np.random.uniform(size=shape).astype("float32") - gamma = np.random.uniform(size=(shape[axis])).astype("float32") - beta = np.random.uniform(size=(shape[axis])).astype("float32") - ref_res = mx.nd.InstanceNorm(mx.nd.array(x), mx.nd.array(gamma), mx.nd.array(beta), epsilon) - mx_sym = mx.sym.InstanceNorm( - mx.sym.var("x"), mx.sym.var("gamma"), mx.sym.var("beta"), epsilon - ) - shape_dict = {"x": x.shape, "gamma": gamma.shape, "beta": beta.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, gamma, beta - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=2e-5, atol=1e-5) - - verify((2, 3, 4, 5)) - verify((32, 64, 80, 64)) - verify((8, 6, 5)) - verify((8, 7, 6, 5, 4)) - - -@tvm.testing.uses_gpu -def test_forward_layer_norm(): - def verify(shape, axis=-1): - x = np.random.uniform(size=shape).astype("float32") - gamma = np.random.uniform(size=(shape[axis])).astype("float32") - beta = np.random.uniform(size=(shape[axis])).astype("float32") - ref_res = mx.nd.LayerNorm(mx.nd.array(x), mx.nd.array(gamma), mx.nd.array(beta), axis=axis) - mx_sym = mx.sym.LayerNorm( - mx.sym.var("x"), mx.sym.var("gamma"), mx.sym.var("beta"), axis=axis - ) - shape_dict = {"x": x.shape, "gamma": gamma.shape, "beta": beta.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, gamma, beta - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((2, 5)) - verify((2, 5), axis=0) - verify((2, 5, 6)) - - -@tvm.testing.uses_gpu -def test_forward_group_norm(): - def verify(shape, num_groups=1): - x = np.random.uniform(size=shape).astype("float32") - gamma = np.random.uniform(size=(shape[1])).astype("float32") - beta = np.random.uniform(size=(shape[1])).astype("float32") - ref_res = mx.nd.GroupNorm( - data=mx.nd.array(x), - gamma=mx.nd.array(gamma), - beta=mx.nd.array(beta), - num_groups=num_groups, - ) - mx_sym = mx.sym.GroupNorm( - mx.sym.var("x"), mx.sym.var("gamma"), mx.sym.var("beta"), num_groups=num_groups - ) - shape_dict = {"x": x.shape, "gamma": gamma.shape, "beta": beta.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, gamma, beta - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((1, 4, 2), num_groups=4) - # TODO(trevmorr): MXNet GroupNorm implementation is bugged for cases when num_groups != num_channels - # https://github.com/apache/incubator-mxnet/pull/18199 - # verify((1, 4, 2, 3), num_groups=2) - # verify((1, 4, 2, 3)) - - -@tvm.testing.uses_gpu -def test_forward_one_hot(): - def verify(indices_shape, depth, on_value, off_value, dtype): - x = np.random.randint(0, 5, size=indices_shape) - ref_res = mx.nd.one_hot(mx.nd.array(x), depth, on_value, off_value, dtype) - mx_sym = mx.sym.one_hot(mx.sym.var("x"), depth, on_value, off_value, dtype) - shape_dict = {"x": x.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x.astype("float32") - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((3,), 3, 1, 0, "int32") - verify((3,), 3, 1.0, 0.0, "float32") - verify((2, 2), 5, 2, -2, "int32") - verify((2, 2), 5, 0.5, -0.5, "float32") - verify((3, 2, 4, 5), 6, 1, 0, "int32") - verify((3, 2, 4, 5), 6, 1.0, 0.0, "float32") - - -@tvm.testing.uses_gpu -def test_forward_pad(): - def verify(data_shape, out_shape, mode, pad_width, constant_value=0.0): - data = mx.sym.var("data") - mx_sym = mx.sym.pad(data, mode=mode, pad_width=pad_width, constant_value=constant_value) - verify_mxnet_frontend_impl(mx_sym, data_shape=data_shape, out_shape=out_shape) - - verify( - data_shape=(1, 1, 3, 5), - out_shape=(1, 1, 6, 12), - mode="constant", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4), - ) - verify( - data_shape=(1, 1, 3, 5), - out_shape=(1, 1, 6, 12), - mode="constant", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4), - constant_value=3.0, - ) - verify( - data_shape=(1, 1, 3, 5), - out_shape=(1, 1, 6, 12), - mode="edge", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4), - ) - verify( - data_shape=(1, 1, 3, 5), - out_shape=(1, 1, 6, 12), - mode="reflect", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4), - ) - verify( - data_shape=(1, 1, 3, 5, 7), - out_shape=(1, 1, 6, 12, 18), - mode="constant", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4, 5, 6), - ) - verify( - data_shape=(1, 1, 3, 5, 7), - out_shape=(1, 1, 6, 12, 18), - mode="constant", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4, 5, 6), - constant_value=3.0, - ) - verify( - data_shape=(1, 1, 3, 5, 7), - out_shape=(1, 1, 6, 12, 18), - mode="edge", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4, 5, 6), - ) - verify( - data_shape=(1, 1, 3, 5, 7), - out_shape=(1, 1, 6, 12, 18), - mode="reflect", - pad_width=(0, 0, 0, 0, 1, 2, 3, 4, 5, 6), - ) - - -@tvm.testing.uses_gpu -def test_forward_slice(): - def verify(data_shape, out_shape, begin, end): - data = mx.sym.var("data") - mx_sym = mx.sym.slice(data, begin=begin, end=end) - verify_mxnet_frontend_impl(mx_sym, data_shape=data_shape, out_shape=out_shape) - - verify(data_shape=(1, 1, 10), out_shape=(1, 1, 8), begin=(0, 0, 2), end=(1, 1, 10)) - verify( - data_shape=(1, 1, 10), out_shape=(1, 1, 8), begin=(None, None, 2), end=(None, None, None) - ) - - -@tvm.testing.uses_gpu -def test_forward_convolution(): - def verify(data_shape, kernel_size, stride, pad, num_filter, is_depthwise=False): - if is_depthwise: - groups = data_shape[1] - weight_shape = ( - data_shape[1], - num_filter // groups, - ) + kernel_size - else: - groups = 1 - weight_shape = ( - num_filter, - data_shape[1], - ) + kernel_size - x = np.random.uniform(size=data_shape).astype("float32") - weight = np.random.uniform(size=weight_shape).astype("float32") - bias = np.random.uniform(size=num_filter).astype("float32") - ref_res = mx.nd.Convolution( - data=mx.nd.array(x), - weight=mx.nd.array(weight), - bias=mx.nd.array(bias), - kernel=kernel_size, - stride=stride, - pad=pad, - num_filter=num_filter, - num_group=groups, - ) - mx_sym = mx.sym.Convolution( - mx.sym.var("x"), - mx.sym.var("weight"), - mx.sym.var("bias"), - kernel=kernel_size, - stride=stride, - pad=pad, - num_filter=num_filter, - num_group=groups, - ) - shape_dict = {"x": x.shape, "weight": weight.shape, "bias": bias.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, weight, bias - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3) - - verify(data_shape=(1, 1, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(20, 1, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(1, 8, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(20, 8, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(1, 1, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(20, 1, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(1, 8, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(20, 8, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify( - data_shape=(1, 8, 32, 32), - kernel_size=(3, 3), - stride=(1, 1), - pad=(1, 1), - num_filter=8, - is_depthwise=True, - ) - verify( - data_shape=(1, 1, 16, 16, 16), - kernel_size=(3, 3, 3), - stride=(1, 1, 1), - pad=(1, 1, 1), - num_filter=2, - ) - verify( - data_shape=(20, 1, 16, 16, 16), - kernel_size=(3, 3, 3), - stride=(1, 1, 1), - pad=(1, 1, 1), - num_filter=2, - ) - verify( - data_shape=(1, 8, 16, 16, 16), - kernel_size=(3, 3, 3), - stride=(2, 2, 2), - pad=(1, 1, 1), - num_filter=2, - ) - verify( - data_shape=(20, 8, 16, 16, 16), - kernel_size=(3, 3, 3), - stride=(1, 1, 1), - pad=(1, 1, 1), - num_filter=2, - ) - - -@tvm.testing.uses_gpu -def test_forward_deconvolution(): - def verify(data_shape, kernel_size, stride, pad, num_filter): - weight_shape = (data_shape[1], num_filter) + kernel_size - x = np.random.uniform(size=data_shape).astype("float32") - weight = np.random.uniform(size=weight_shape).astype("float32") - bias = np.random.uniform(size=num_filter).astype("float32") - ref_res = mx.nd.Deconvolution( - data=mx.nd.array(x), - weight=mx.nd.array(weight), - bias=mx.nd.array(bias), - kernel=kernel_size, - stride=stride, - pad=pad, - num_filter=num_filter, - no_bias=False, - ) - mx_sym = mx.sym.Deconvolution( - mx.sym.var("x"), - mx.sym.var("weight"), - mx.sym.var("bias"), - kernel=kernel_size, - stride=stride, - pad=pad, - num_filter=num_filter, - no_bias=False, - ) - shape_dict = {"x": x.shape, "weight": weight.shape, "bias": bias.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x, weight, bias - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify(data_shape=(1, 1, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(20, 1, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(1, 8, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(20, 8, 1024 * 16), kernel_size=(17,), stride=(2,), pad=(8,), num_filter=4) - verify(data_shape=(1, 1, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(20, 1, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(1, 8, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - verify(data_shape=(20, 8, 32, 32), kernel_size=(3, 3), stride=(1, 1), pad=(1, 1), num_filter=2) - - -@tvm.testing.uses_gpu -def test_forward_cond(): - def verify(a_np, b_np): - a_nd, b_nd = mx.nd.array(a_np), mx.nd.array(b_np) - pred = a_nd * b_nd < 5 - then_func = lambda: (a_nd + 5) * (b_nd + 5) - else_func = lambda: (a_nd - 5) * (b_nd - 5) - ref_res = mx.nd.contrib.cond(pred, then_func, else_func) - - a_sym, b_sym = mx.sym.var("a"), mx.sym.var("b") - pred = a_sym * b_sym < 5 - then_func = lambda: (a_sym + 5) * (b_sym + 5) - else_func = lambda: (a_sym - 5) * (b_sym - 5) - mx_sym = mx.sym.contrib.cond(pred, then_func, else_func) - - shape_dict = {"a": a_np.shape, "b": b_np.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["debug", "vm"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np, b_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3) - - verify(np.asarray([1.0], "float32"), np.asarray([2.0], "float32")) - verify(np.asarray([4.0], "float32"), np.asarray([3.0], "float32")) - - -@tvm.testing.uses_gpu -def test_forward_amp_cast(): - def verify(from_dtype, to_dtype): - from_np = np.random.uniform(size=(1, 3, 18)).astype(from_dtype) - x_var = mx.sym.var("x", dtype=from_dtype) - mx_sym = mx.sym.amp_cast(x_var, dtype=to_dtype) - shape_dict = {"x": (1, 3, 18)} - dtype_dict = {"x": from_dtype} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict, dtype_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "vm", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - from_np - ) - assert op_res.dtype == to_dtype, op_res.dtype - tvm.testing.assert_allclose(op_res.numpy(), from_np.astype(to_dtype)) - - verify("float32", "float16") - verify("float16", "float32") - - -@tvm.testing.uses_gpu -def test_forward_amp_multicast(): - def verify(dtypes, cast_narrow, expected_dtype): - x_nps = [np.random.uniform(size=(1, 3, 18)).astype(dtype) for dtype in dtypes] - x_vars = [mx.sym.var(str(i), dtype=dtype) for i, dtype in enumerate(dtypes)] - mx_sym = mx.sym.amp_multicast(*x_vars, cast_narrow=cast_narrow, num_outputs=len(dtypes)) - shape_dict = {} - dtype_dict = {} - for i, dtype in enumerate(dtypes): - shape_dict[str(i)] = (1, 3, 18) - dtype_dict[str(i)] = dtype - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict, dtype_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "vm", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - *x_nps - ) - for i, res in enumerate(op_res): - assert res.dtype == expected_dtype, res.dtype - tvm.testing.assert_allclose(res.numpy(), x_nps[i].astype(expected_dtype)) - - verify(["float32", "float16"], False, "float32") - verify(["float32", "float16"], True, "float16") - verify(["float32", "float32"], False, "float32") - verify(["float32", "float32"], True, "float32") - verify(["float16", "float16"], False, "float16") - verify(["float16", "float16"], True, "float16") - - -@tvm.testing.uses_gpu -def test_forward_unravel_index(): - def verify(x, shape, dtype): - a_np = np.array(x).astype(dtype) - mx_sym = _mx_symbol(mx.sym, "unravel_index", [mx.sym.var("a"), shape]) - ref_res = _mx_symbol(mx.nd, "unravel_index", [mx.nd.array(a_np), shape]) - shapes = {"a": a_np.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shapes, dtype) - - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "vm", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - a_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - for dtype in ["int32", "int64"]: - verify([0, 1, 2, 3], [2, 2], dtype) - verify([144, 13, 45], [6, 7, 10, 2], dtype) - verify([456], [6, 7, 10, 2], dtype) - - # In below example, 5 is out of bound for array of size 4. - # MXNet implementation provides different result than TVM - # TVM implementation is inline with Tensorflow - # Ideally error should be thrown just like Numpy - # verify([0, 1, 2, 5], [2, 2], dtype) - - -@tvm.testing.uses_gpu -def test_forward_swap_axis(): - def _verify_swap_axis(in_shape, out_shape, dim1, dim2): - data = mx.sym.var("data") - mx_sym = mx.sym.swapaxes(data, dim1, dim2) - verify_mxnet_frontend_impl(mx_sym, in_shape, out_shape) - - _verify_swap_axis((4, 5), (5, 4), 0, 1) - _verify_swap_axis((2, 4, 4, 5), (2, 5, 4, 4), 1, 3) - # MXNet errors out when dim1 == dim2 - # _verify_swap_axis((4, 5), (5, 4), 0, 0) - - -@tvm.testing.uses_gpu -def test_forward_depth_to_space(): - def verify(shape, blocksize=2): - x = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.depth_to_space(mx.nd.array(x), blocksize) - mx_sym = mx.sym.depth_to_space(mx.sym.var("x"), blocksize) - shape_dict = { - "x": x.shape, - } - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((1, 18, 3, 3), 3) - - -@tvm.testing.uses_gpu -def test_forward_space_to_depth(): - def verify(shape, blocksize=2): - x = np.random.uniform(size=shape).astype("float32") - ref_res = mx.nd.space_to_depth(mx.nd.array(x), blocksize) - mx_sym = mx.sym.space_to_depth(mx.sym.var("x"), blocksize) - shape_dict = { - "x": x.shape, - } - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - x - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((1, 1, 9, 9), 3) - - -@tvm.testing.uses_gpu -def test_forward_correlation(): - def verify(data_shape, kernel_size, max_displacement, stride1, stride2, pad_size, is_multiply): - data1 = np.random.uniform(size=data_shape).astype("float32") - data2 = np.random.uniform(size=data_shape).astype("float32") - ref_res = mx.nd.Correlation( - data1=mx.nd.array(data1), - data2=mx.nd.array(data2), - kernel_size=kernel_size, - max_displacement=max_displacement, - stride1=stride1, - stride2=stride2, - pad_size=pad_size, - is_multiply=is_multiply, - ) - mx_sym = mx.sym.Correlation( - data1=mx.sym.var("data1"), - data2=mx.sym.var("data2"), - kernel_size=kernel_size, - max_displacement=max_displacement, - stride1=stride1, - stride2=stride2, - pad_size=pad_size, - is_multiply=is_multiply, - ) - shape_dict = {"data1": data1.shape, "data2": data2.shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data1, data2 - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify( - (1, 3, 10, 10), - kernel_size=1, - max_displacement=4, - stride1=1, - stride2=1, - pad_size=4, - is_multiply=False, - ) - verify( - (5, 1, 15, 15), - kernel_size=1, - max_displacement=5, - stride1=1, - stride2=1, - pad_size=5, - is_multiply=False, - ) - verify( - (5, 1, 15, 15), - kernel_size=1, - max_displacement=5, - stride1=1, - stride2=1, - pad_size=5, - is_multiply=True, - ) - verify( - (5, 1, 15, 15), - kernel_size=1, - max_displacement=10, - stride1=1, - stride2=2, - pad_size=10, - is_multiply=True, - ) - verify( - (5, 1, 4, 4), - kernel_size=3, - max_displacement=1, - stride1=1, - stride2=1, - pad_size=2, - is_multiply=True, - ) - verify( - (5, 1, 4, 4), - kernel_size=3, - max_displacement=1, - stride1=2, - stride2=1, - pad_size=2, - is_multiply=True, - ) - verify( - (5, 1, 4, 4), - kernel_size=3, - max_displacement=1, - stride1=2, - stride2=1, - pad_size=2, - is_multiply=False, - ) - verify( - (5, 1, 6, 4), - kernel_size=3, - max_displacement=1, - stride1=2, - stride2=1, - pad_size=2, - is_multiply=False, - ) - verify( - (5, 1, 11, 11), - kernel_size=5, - max_displacement=1, - stride1=1, - stride2=1, - pad_size=2, - is_multiply=False, - ) - - -@tvm.testing.uses_gpu -def test_forward_arange_like(): - def verify(data_shape, start=None, step=None, axis=None): - attrs = {} - if start is not None: - attrs["start"] = start - if step is not None: - attrs["step"] = step - if axis is not None: - attrs["axis"] = axis - data = mx.sym.var("data") - data_np = np.random.uniform(size=data_shape).astype("float32") - ref_res = mx.nd.contrib.arange_like(mx.nd.array(data_np), **attrs) - - mx_sym = mx.sym.contrib.arange_like(data, **attrs) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph"]: - op_res = relay.create_executor( - kind, mod=mod, device=dev, target=target - ).evaluate()() - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy()) - - verify(data_shape=(3,), start=0.0, step=1.0) - verify(data_shape=(3, 4, 5), start=0.0, step=1.0) - verify(data_shape=(3, 4, 5), start=0.0, step=1.0, axis=-1) - verify(data_shape=(3, 4, 5), start=2.0, step=3.0, axis=1) - - -@tvm.testing.uses_gpu -def test_forward_interleaved_matmul_selfatt_qk(): - def verify(batch, seq_length, num_heads, head_dim): - data_shape = (seq_length, batch, num_heads * head_dim * 3) - data = mx.sym.var("data") - data_np = np.random.uniform(size=data_shape).astype("float32") - ref_res = mx.nd.contrib.interleaved_matmul_selfatt_qk(mx.nd.array(data_np), heads=num_heads) - - mx_sym = mx.sym.contrib.interleaved_matmul_selfatt_qk(data, heads=num_heads) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - verify(1, 10, 3, 16) - verify(3, 10, 6, 8) - - -@tvm.testing.uses_gpu -def test_forward_interleaved_matmul_selfatt_valatt(): - def verify(batch, seq_length, num_heads, head_dim): - data_shape = (seq_length, batch, num_heads * head_dim * 3) - weight_shape = (batch * num_heads, seq_length, seq_length) - data = mx.sym.var("data") - weight = mx.sym.var("weight") - data_np = np.random.uniform(size=data_shape).astype("float32") - weight_np = np.random.uniform(size=weight_shape).astype("float32") - ref_res = mx.nd.contrib.interleaved_matmul_selfatt_valatt( - mx.nd.array(data_np), mx.nd.array(weight_np), heads=num_heads - ) - - mx_sym = mx.sym.contrib.interleaved_matmul_selfatt_valatt(data, weight, heads=num_heads) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape, "weight": weight_shape}) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data=data_np, weight=weight_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - verify(1, 10, 4, 16) - verify(3, 10, 6, 8) - - -@tvm.testing.uses_gpu -def test_forward_box_nms(): - def verify( - data_shape, - overlap_thresh=0.5, - valid_thresh=0, - topk=1, - coord_start=2, - score_index=1, - id_index=0, - force_suppress=False, - in_format="corner", - ): - dtype = "float32" - data = np.random.uniform(low=0, high=1, size=data_shape).astype(dtype) - ref_res = mx.nd.contrib.box_nms( - mx.nd.array(data), - overlap_thresh=overlap_thresh, - valid_thresh=valid_thresh, - topk=topk, - coord_start=coord_start, - score_index=score_index, - id_index=id_index, - force_suppress=force_suppress, - background_id=-1, - in_format=in_format, - out_format=in_format, - ) - mx_sym = mx.sym.contrib.box_nms( - mx.sym.var("data"), - overlap_thresh=overlap_thresh, - valid_thresh=valid_thresh, - topk=topk, - coord_start=coord_start, - score_index=score_index, - id_index=id_index, - force_suppress=force_suppress, - background_id=-1, - in_format=in_format, - out_format=in_format, - ) - shape_dict = {"data": data_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - if tvm.contrib.thrust.can_use_thrust( - tvm.target.Target(target + " -libs=thrust"), "tvm.contrib.thrust.sort" - ): - target += " -libs=thrust" - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((1, 10, 6)) - # No valid boxes - verify((1, 10, 6), valid_thresh=1) - - -@tvm.testing.uses_gpu -def test_forward_box_decode(): - def verify(data_shape, anchor_shape, stds=[1, 1, 1, 1], clip=-1, in_format="corner"): - dtype = "float32" - data = np.random.uniform(low=-2, high=2, size=data_shape).astype(dtype) - anchors = np.random.uniform(low=-2, high=2, size=anchor_shape).astype(dtype) - ref_res = mx.nd.contrib.box_decode( - mx.nd.array(data), - mx.nd.array(anchors), - stds[0], - stds[1], - stds[2], - stds[3], - clip, - in_format, - ) - mx_sym = mx.sym.contrib.box_decode( - mx.sym.var("data"), - mx.sym.var("anchors"), - stds[0], - stds[1], - stds[2], - stds[3], - clip, - in_format, - ) - shape_dict = {"data": data_shape, "anchors": anchor_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data, anchors - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((1, 10, 4), (1, 10, 4)) - verify((4, 10, 4), (1, 10, 4)) - verify((1, 10, 4), (1, 10, 4), stds=[2, 3, 0.5, 1.5]) - verify((1, 10, 4), (1, 10, 4), clip=1) - verify((1, 10, 4), (1, 10, 4), in_format="center") - - -@tvm.testing.uses_gpu -def test_forward_softmax(): - def verify(data_shape, axis, use_length, length): - dtype = "float32" - x = np.random.uniform(low=-100, high=100, size=data_shape).astype(dtype) - if use_length: - ref_res = mx.nd.softmax( - data=mx.nd.array(x), - length=mx.nd.array(length, dtype="int32"), - axis=axis, - use_length=use_length, - ) - mx_sym = mx.symbol.softmax( - data=mx.sym.var("data"), - length=mx.sym.var("length"), - axis=axis, - use_length=use_length, - ) - shape_dict = {"data": data_shape, "length": (length.shape)} - dtype_dict = {"data": dtype, "length": "int32"} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict, dtype_dict) - else: - ref_res = mx.nd.softmax(data=mx.nd.array(x), axis=axis) - mx_sym = mx.symbol.softmax(data=mx.sym.var("data"), axis=axis) - shape_dict = {"data": data_shape} - mod, _ = relay.frontend.from_mxnet(mx_sym, shape_dict) - - for target, dev in tvm.testing.enabled_targets(): - for kind in ["graph", "debug"]: - func = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate() - if use_length: - op_res = func(x, length) - else: - op_res = func(x) - - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-3, atol=1e-5) - - verify((2, 3, 5), -1, False, None) - verify((2, 3, 5), 2, False, None) - verify((2, 3), -1, True, np.array([2, 1]).astype("int32")) - verify((2, 3, 4), -1, True, np.array([[3, 4, 2], [2, 1, 1]]).astype("int32")) - verify((2, 3, 4), 2, True, np.array([[3, 4, 2], [1, 2, 1]]).astype("int32")) - - -@pytest.mark.skipif(not hasattr(mx.sym.np, "pad"), reason="mx.sym.np.pad hasn't been publish yet") -@pytest.mark.parametrize( - "data_shape, pad_width", - [ - ((1, 1, 3, 5), ((0, 0), (0, 0), (1, 2), (3, 4))), - ((1, 1, 3, 5, 7), ((0, 0), (0, 0), (1, 2), (3, 4), (5, 6))), - ], -) -@pytest.mark.parametrize("mode", ["constant", "edge", "reflect"]) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32"]) -@pytest.mark.parametrize("constant_value", [0.0, 3.0]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_pad(data_shape, pad_width, mode, dtype, constant_value, target, dev, kind): - data_np = np.random.uniform(size=data_shape).astype(dtype) - data = mx.sym.var("data") - if mode == "constant": - ref_res = np.pad(data_np, mode=mode, pad_width=pad_width, constant_values=constant_value) - mx_sym = mx.sym.np.pad( - data.as_np_ndarray(), mode=mode, pad_width=pad_width, constant_values=constant_value - ) - else: - ref_res = np.pad(data_np, mode=mode, pad_width=pad_width) - mx_sym = mx.sym.np.pad(data.as_np_ndarray(), mode=mode, pad_width=pad_width) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res, rtol=1e-5) - - -@pytest.mark.skipif( - not hasattr(mx.sym.np, "pad"), reason="test'll abort with Mxnet 1.x, skip for now" -) -@pytest.mark.parametrize("data_shape", [(2, 2, 2), (2, 7, 2)]) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "bool"]) -@pytest.mark.parametrize("axes", [(1, 0, 2), None]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_transpose(data_shape, axes, dtype, target, dev, kind): - data_np = np.random.uniform(size=data_shape).astype(dtype) - data = mx.sym.var("data") - ref_res = mx.np.transpose(mx.np.array(data_np), axes=axes) - mx_sym = mx.sym.np.transpose(data.as_np_ndarray(), axes=axes) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize( - "data_shape1, data_shape2, axis", - [ - ((2, 2), (2, 2), 1), - ((2, 4), (2, 3), 1), - ((1, 3, 2), (1, 3, 5), 2), - ((1, 3, 3), (1, 3, 3), 1), - ((1, 3), (1, 3), 0), - ], -) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_concatenate(data_shape1, data_shape2, axis, dtype, target, dev, kind): - data_np1 = np.random.uniform(size=data_shape1).astype(dtype) - data_np2 = np.random.uniform(size=data_shape2).astype(dtype) - data1 = mx.sym.var("data1") - data2 = mx.sym.var("data2") - ref_res = mx.np.concatenate([mx.np.array(data_np1), mx.np.array(data_np2)], axis=axis) - mx_sym = mx.sym.np.concatenate([data1.as_np_ndarray(), data2.as_np_ndarray()], axis=axis) - mod, _ = relay.frontend.from_mxnet( - mx_sym, shape={"data1": data_shape1, "data2": data_shape2}, dtype=dtype - ) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np1, data_np2 - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize( - "data_shape1, data_shape2, axis", - [ - ((3,), (3,), 0), - ((3,), (3,), -1), - ((1, 3, 2), (1, 3, 2), 2), - ((1, 3, 3), (1, 3, 3), 1), - ((1, 3), (1, 3), 0), - ], -) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_stack(data_shape1, data_shape2, axis, dtype, target, dev, kind): - data_np1 = np.random.uniform(size=data_shape1).astype(dtype) - data_np2 = np.random.uniform(size=data_shape2).astype(dtype) - data1 = mx.sym.var("data1") - data2 = mx.sym.var("data2") - ref_res = mx.np.stack([mx.np.array(data_np1), mx.np.array(data_np2)], axis=axis) - mx_sym = mx.sym.np.stack([data1.as_np_ndarray(), data2.as_np_ndarray()], axis=axis) - mod, _ = relay.frontend.from_mxnet( - mx_sym, shape={"data1": data_shape1, "data2": data_shape2}, dtype=dtype - ) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np1, data_np2 - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize("data_shape", [(2, 2, 2), (2, 7, 2), (2, 2, 2, 1, 2, 3, 1), (1, 8)]) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "bool"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_np_copy(data_shape, dtype, target, dev, kind): - data_np = np.random.uniform(size=data_shape).astype(dtype) - data = mx.sym.var("data") - ref_res = mx.np.copy(mx.np.array(data_np)) - mx_sym = mx.sym.np.copy(data.as_np_ndarray()) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "bool"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -@pytest.mark.parametrize( - "data_shape,out_shape,reverse", - [ - ((2, 3, 8), (-2, -2, 2, -1), False), - ((8, 3, 3, 3, 4, 4), (-6, 2, -1, -4), False), - ((8, 3, 3, 3, 4, 4), (-5, -4), False), - ((1, 8, 3, 3, 3, 4, 4), (-3, -5, -4), False), - ((8, 1, 3, 4), (-2, -3, -1), False), - ((8, 3, 3, 3, 3, 8), (-4, -5), True), - ((8, 3, 2, 4, 8), (-4, -1, 2, -6), True), - ((3, 2, 4, 8, 1, 1), (-4, -1, 2, -6, -5, -3), True), - ((2, 4, 1, 8), (-4, -3, -1, 2, -6), True), - ], -) -def test_forward_npx_reshape(data_shape, out_shape, dtype, target, reverse, dev, kind): - data_np = np.random.uniform(size=data_shape).astype(dtype) - data = mx.sym.var("data") - ref_res = mx.npx.reshape(mx.np.array(data_np), newshape=out_shape, reverse=reverse) - mx_sym = mx.sym.npx.reshape(data.as_np_ndarray(), newshape=out_shape, reverse=reverse) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize( - "data_shape", [(2, 2, 2), (2, 7, 2), (2, 2, 2, 1, 2, 3, 1), (1, 8), (2, 2), (1, 3)] -) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_binary(data_shape, dtype, target, dev, kind): - ref_ops = [mx.np.power, mx.np.multiply, mx.np.add, mx.np.subtract, mx.np.less] - mx_ops = [ - mx.sym.np.power, - mx.sym.np.multiply, - mx.sym.np.add, - mx.sym.np.subtract, - mx.sym.np.less, - ] - for i in range(len(ref_ops)): - ref_op = ref_ops[i] - mx_op = mx_ops[i] - # mx.np.power only support float type - if ref_op == mx.np.power and dtype not in ["float64", "float32"]: - continue - data_np1 = np.random.uniform(size=data_shape).astype(dtype) - data_np2 = np.random.uniform(size=data_shape).astype(dtype) - data1 = mx.sym.var("lhs") - data2 = mx.sym.var("rhs") - ref_res = ref_op(mx.np.array(data_np1), mx.np.array(data_np2)) - mx_sym = mx_op(data1.as_np_ndarray(), data2.as_np_ndarray()) - mod, _ = relay.frontend.from_mxnet( - mx_sym, shape={"lhs": data_shape, "rhs": data_shape}, dtype=dtype - ) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np1, data_np2 - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize( - "data_shape", [(2, 2, 2), (2, 7, 2), (2, 2, 2, 1, 2, 3, 1), (1, 8), (2, 2), (1, 3)] -) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("scalar", [1.0, 2.0, 3.0, 4.0]) -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_binary_scalar(data_shape, dtype, scalar, target, dev, kind): - ref_ops = [mx.np.power, mx.np.multiply, mx.np.add, mx.np.subtract, mx.np.true_divide] - mx_ops = [ - mx.sym.np.power, - mx.sym.np.multiply, - mx.sym.np.add, - mx.sym.np.subtract, - mx.sym.np.true_divide, - ] - for i in range(len(ref_ops)): - ref_op = ref_ops[i] - mx_op = mx_ops[i] - # mx.np.power only support float type - if ref_op == mx.np.power and dtype not in ["float64", "float32"]: - continue - data_np1 = np.random.uniform(size=data_shape).astype(dtype) - data1 = mx.sym.var("lhs") - ref_res = ref_op(mx.np.array(data_np1), scalar) - mx_sym = mx_op(data1.as_np_ndarray(), scalar) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape={"lhs": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - data_np1 - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize( - "data_shape", [(2, 2, 2), (2, 7, 2), (2, 2, 2, 1, 2, 3, 1), (1, 8), (2, 2), (1, 3)] -) -@pytest.mark.parametrize("dtype", ["float64", "float32"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_tanh(data_shape, dtype, target, dev, kind): - data_np1 = np.random.uniform(size=data_shape).astype(dtype) - data1 = mx.sym.var("data") - ref_res = mx.np.tanh(mx.np.array(data_np1)) - mx_sym = mx.sym.np.tanh(data1.as_np_ndarray()) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape={"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np1) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.skipif(not hasattr(mx.np, "where"), reason="mx.np.where hasn't been publish yet") -@pytest.mark.parametrize( - "data_shape,cond_shape", - [[(2, 2, 2), (2, 2, 2)], [(2, 7, 2), (7, 2)], [(2, 2), (1, 2)], [(1, 3), (3, 3)]], -) -@pytest.mark.parametrize("data_dtype", ["float64", "float32", "int64", "int32", "bool"]) -@pytest.mark.parametrize("cond_dtype", ["float64", "float32", "int64", "int32", "bool"]) -@pytest.mark.parametrize("scalar", [1.0, 2.0]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -def test_forward_npi_where_rscalar( - data_shape, cond_shape, data_dtype, cond_dtype, scalar, target, dev, kind -): - if data_dtype == "bool": - scalar = scalar == 0.0 - cond_np = np.random.uniform(size=cond_shape).astype(cond_dtype) - data_np = np.random.uniform(size=data_shape).astype(data_dtype) - cond = mx.sym.var("condition") - data = mx.sym.var("x") - ref_res = mx.np.where(mx.np.array(cond_np), mx.np.array(data_np), scalar) - mx_sym = mx.sym.np.where(cond.as_np_ndarray(), data.as_np_ndarray(), scalar) - dtypeDic = {} - dtypeDic["condition"] = cond_dtype - dtypeDic["x"] = data_dtype - mod, _ = relay.frontend.from_mxnet( - mx_sym, shape={"condition": cond_shape, "x": data_shape}, dtype=dtypeDic - ) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()( - cond_np, data_np - ) - tvm.testing.assert_allclose(op_res.numpy(), ref_res.asnumpy(), rtol=1e-5) - - -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "bool"]) -@tvm.testing.parametrize_targets -@pytest.mark.parametrize("kind", ["graph", "vm", "debug"]) -@pytest.mark.parametrize( - "data_shape, axis, indices_or_sections, squeeze_axis", - [ - ((3, 2, 1), 1, 2, False), - ((3, 2, 1), 0, 3, False), - ((3, 2, 1), 0, 3, True), - ((3, 2, 1), 0, (1, 2), False), - ], -) -def test_forward_split_v2( - data_shape, axis, dtype, indices_or_sections, squeeze_axis, target, dev, kind -): - data_np = np.random.uniform(size=data_shape).astype(dtype) - data = mx.sym.var("data") - ref_res = mx.ndarray.split_v2( - mx.nd.array(data_np), indices_or_sections, axis=axis, squeeze_axis=squeeze_axis - ) - mx_sym = mx.sym.split_v2( - data.as_nd_ndarray(), indices_or_sections, axis=axis, squeeze_axis=squeeze_axis - ) - mod, _ = relay.frontend.from_mxnet(mx_sym, {"data": data_shape}, dtype=dtype) - op_res = relay.create_executor(kind, mod=mod, device=dev, target=target).evaluate()(data_np) - op_res_ = [] - for arr in op_res: - op_res_.append(arr.numpy().tolist()) - ref_res_ = [] - for arr in ref_res: - ref_res_.append(arr.asnumpy().tolist()) - tvm.testing.assert_allclose(op_res_, ref_res_, rtol=1e-5) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/mxnet/test_graph.py b/tests/python/frontend/mxnet/test_graph.py deleted file mode 100644 index 63ce763f1725..000000000000 --- a/tests/python/frontend/mxnet/test_graph.py +++ /dev/null @@ -1,123 +0,0 @@ -# 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 - -import tvm -from tvm import te -from tvm import relay -from tvm.relay import transform -import model_zoo - - -def compare_graph(lhs_mod, rhs_mod): - lhs_mod = transform.InferType()(lhs_mod) - rhs_mod = transform.InferType()(rhs_mod) - tvm.ir.assert_structural_equal(lhs_mod["main"], rhs_mod["main"]) - - -def test_mlp(): - shape = {"data": (1, 1, 28, 28)} - mx_fun = model_zoo.mx_mlp() - mod, _ = relay.frontend.from_mxnet(mx_fun, shape=shape) - relay_fun = model_zoo.relay_mlp() - compare_graph(mod, relay_fun) - - -def test_vgg(): - shape = {"data": (1, 3, 224, 224)} - for n in [11, 13, 16, 19]: - mx_sym = model_zoo.mx_vgg(n) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape=shape) - relay_mod = model_zoo.relay_vgg(n) - compare_graph(mod, relay_mod) - - -def test_resnet(): - shape = {"data": (1, 3, 224, 224)} - for n in [18, 34, 50, 101]: - mx_sym = model_zoo.mx_resnet(n) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape=shape) - relay_mod = model_zoo.relay_resnet(n) - compare_graph(mod, relay_mod) - - -def test_squeezenet(): - shape = {"data": (1, 3, 224, 224)} - for version in ["1.0", "1.1"]: - mx_sym = model_zoo.mx_squeezenet(version) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape) - relay_mod = model_zoo.relay_squeezenet(version) - compare_graph(mod, relay_mod) - - -def test_inception_v3(): - shape = {"data": (1, 3, 299, 299)} - mx_sym = model_zoo.mx_inception_v3() - mod, _ = relay.frontend.from_mxnet(mx_sym, shape) - relay_mod = model_zoo.relay_inception_v3() - compare_graph(mod, relay_mod) - - -def test_dqn(): - shape = {"data": (1, 4, 84, 84)} - mx_sym = model_zoo.mx_dqn() - mod, _ = relay.frontend.from_mxnet(mx_sym, shape) - relay_mod = model_zoo.relay_dqn() - compare_graph(mod, relay_mod) - - -def test_dcgan(): - shape = {"data": (2, 100)} - mx_sym = model_zoo.mx_dcgan() - mod, _ = relay.frontend.from_mxnet(mx_sym, shape) - relay_mod = model_zoo.relay_dcgan(batch_size=2) - compare_graph(mod, relay_mod) - - -def test_multi_outputs(): - xshape = (10, 27) - yshape = (10, 9) - - def mx_compose(F, **kwargs): - x = F.sym.Variable("x") - y = F.sym.Variable("y") - z = F.sym.split(x, **kwargs) - return F.sym.broadcast_sub(F.sym.broadcast_add(z[0], z[2]), y) - - def relay_compose(F, **kwargs): - x = F.var("x", shape=xshape) - y = F.var("y", shape=yshape) - z = F.split(x, **kwargs) - z = F.subtract(F.add(z[0], z[2]), y) - func = relay.Function(relay.analysis.free_vars(z), z) - return tvm.IRModule.from_expr(func) - - mx_sym = mx_compose(mx, num_outputs=3, axis=1) - mod, _ = relay.frontend.from_mxnet(mx_sym, shape={"x": xshape, "y": yshape}) - relay_mod = relay_compose(relay, indices_or_sections=3, axis=1) - compare_graph(mod, relay_mod) - - -if __name__ == "__main__": - test_mlp() - test_resnet() - test_vgg() - test_multi_outputs() - test_dqn() - test_dcgan() - test_squeezenet() - test_inception_v3() diff --git a/tests/python/frontend/mxnet/test_qnn_ops_utils.py b/tests/python/frontend/mxnet/test_qnn_ops_utils.py deleted file mode 100644 index adbb0a74558b..000000000000 --- a/tests/python/frontend/mxnet/test_qnn_ops_utils.py +++ /dev/null @@ -1,224 +0,0 @@ -# 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 numpy as np -import tvm -from tvm import relay -from tvm.contrib import graph_executor -from tvm.relay.frontend.mxnet_qnn_op_utils import ( - dequantize_mxnet_min_max, - quantize_mxnet_min_max, - get_mkldnn_int8_scale, - get_mkldnn_uint8_scale, - quantize_conv_bias_mkldnn_from_var, -) - - -def test_mkldnn_dequantize(): - def dequantize_test_driver(in_dtype, quant_args, in_data, verify_output_data): - shape = in_data.shape - input_data = relay.var("input_data", shape=shape, dtype=in_dtype) - min_range = quant_args["min_range"] - max_range = quant_args["max_range"] - dequantized_output = dequantize_mxnet_min_max( - input_data, min_range=min_range, max_range=max_range, in_dtype=in_dtype - ) - mod = relay.Function(relay.analysis.free_vars(dequantized_output), dequantized_output) - mod = tvm.IRModule.from_expr(mod) - with tvm.transform.PassContext(opt_level=3): - graph, lib, params = relay.build(mod, "llvm", params=None) - rt_mod = graph_executor.create(graph, lib, device=tvm.cpu(0)) - rt_mod.set_input(input_data=in_data) - rt_mod.set_input(**params) - rt_mod.run() - res = rt_mod.get_output(0).numpy() - assert np.allclose(res, verify_output_data) - assert res.dtype == np.float32 - - def test_uint8_to_float32(): - data = np.array([0, 1, 2, 3, 4, 251, 252, 253, 254, 255]).astype("uint8").reshape((2, 5)) - output = ( - np.array( - [ - 0.0, - 0.25048923, - 0.50097847, - 0.7514677, - 1.0019569, - 62.8728, - 63.123287, - 63.373775, - 63.624268, - 63.874756, - ] - ) - .astype("float32") - .reshape((2, 5)) - ) - quant_args = {"min_range": -63.5, "max_range": 64} - dequantize_test_driver( - in_dtype="uint8", quant_args=quant_args, in_data=data, verify_output_data=output - ) - - def test_int8_to_float32(): - data = ( - np.array([-126, -125, -124, -123, -122, 123, 124, 125, 126, 127]) - .astype("int8") - .reshape((2, 5)) - ) - output = ( - np.array( - [ - -63.247063, - -62.745102, - -62.24314, - -61.74118, - -61.23922, - 61.74118, - 62.24314, - 62.745102, - 63.247063, - 63.749023, - ] - ) - .astype("float32") - .reshape((2, 5)) - ) - dequantize_args = {"min_range": -63.5, "max_range": 64} - dequantize_test_driver( - in_dtype="int8", quant_args=dequantize_args, in_data=data, verify_output_data=output - ) - - test_uint8_to_float32() - test_int8_to_float32() - - -def test_mkldnn_quantize(): - def quantize_test_driver(out_dtype, quant_args, in_data, verify_output_data): - shape = in_data.shape - input_data = relay.var("input_data", shape=shape, dtype="float32") - min_range = quant_args["min_range"] - max_range = quant_args["max_range"] - quantized_output, _, _ = quantize_mxnet_min_max( - input_data, min_range=min_range, max_range=max_range, out_dtype=out_dtype - ) - mod = relay.Function(relay.analysis.free_vars(quantized_output), quantized_output) - mod = tvm.IRModule.from_expr(mod) - with tvm.transform.PassContext(opt_level=3): - graph, lib, params = relay.build(mod, "llvm", params=None) - rt_mod = graph_executor.create(graph, lib, device=tvm.cpu(0)) - rt_mod.set_input(input_data=in_data) - rt_mod.set_input(**params) - rt_mod.run() - res = rt_mod.get_output(0).numpy() - assert np.allclose(res, verify_output_data) - assert res.dtype == verify_output_data.dtype - - def test_float32_to_uint8(): - data = ( - np.array( - [ - 0.0, - 0.25048923, - 0.50097847, - 0.7514677, - 1.0019569, - 62.8728, - 63.123287, - 63.373775, - 63.624268, - 63.874756, - ] - ) - .astype("float32") - .reshape((2, 5)) - ) - output = np.array([0, 1, 2, 3, 4, 251, 252, 253, 254, 255]).astype("uint8").reshape((2, 5)) - - quant_args = {"min_range": -63.5, "max_range": 64} - quantize_test_driver( - out_dtype="uint8", quant_args=quant_args, in_data=data, verify_output_data=output - ) - - def test_float32_to_int8(): - data = ( - np.array( - [ - -63.247063, - -62.745102, - -62.24314, - -61.74118, - -61.23922, - 61.74118, - 62.24314, - 62.745102, - 63.247063, - 63.749023, - ] - ) - .astype("float32") - .reshape((2, 5)) - ) - output = ( - np.array([-126, -125, -124, -123, -122, 123, 124, 125, 126, 127]) - .astype("int8") - .reshape((2, 5)) - ) - - quant_args = {"min_range": -63.5, "max_range": 64} - quantize_test_driver( - out_dtype="int8", quant_args=quant_args, in_data=data, verify_output_data=output - ) - - test_float32_to_uint8() - test_float32_to_int8() - - -def test_get_mkldnn_int8_scale(): - range_min = -3.904039 - range_max = 3.904039 - expected = 0.03061991354976495 - output = get_mkldnn_int8_scale(range_max=range_max, range_min=range_min) - assert np.allclose(output, expected) - - -def test_get_mkldnn_uint8_scale(): - range_min = 0.0 - range_max = 55.77269 - expected = 0.21828841189047482 - output = get_mkldnn_uint8_scale(range_max=range_max, range_min=range_min) - assert np.allclose(output, expected) - - -def test_quantize_conv_bias_mkldnn_from_var(): - bias_var = relay.var("bias", shape=(3,), dtype="float32") - bias_scale = tvm.nd.array(np.array([0.5, 0.6, 0.7])) - output = quantize_conv_bias_mkldnn_from_var(bias_var, bias_scale) - assert isinstance(output, tvm.relay.expr.Call) - attrs = output.attrs - assert attrs.axis == 0 - assert attrs.out_dtype == "int32" - assert output.op.name == "qnn.quantize" - assert output.args[1].data == bias_scale - - -if __name__ == "__main__": - test_mkldnn_dequantize() - test_mkldnn_quantize() - test_get_mkldnn_int8_scale() - test_get_mkldnn_uint8_scale() - test_quantize_conv_bias_mkldnn_from_var() diff --git a/tests/python/frontend/oneflow/test_forward.py b/tests/python/frontend/oneflow/test_forward.py deleted file mode 100644 index fda5f1b723c7..000000000000 --- a/tests/python/frontend/oneflow/test_forward.py +++ /dev/null @@ -1,963 +0,0 @@ -# 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. -# pylint: disable=arguments-differ, unused-argument -"""Unit tests for various models and operators""" -import os - -import numpy as np -import oneflow as flow -from packaging import version as package_version -import tvm -import tvm.testing -import tvm.topi.testing -from tvm import relay - -MODEL_HOME = "test_model" - - -def mkdir(path): - # init - path = path.strip() - path = path.rstrip("\\") - - if not os.path.exists(path): - os.makedirs(path) - else: - print(f"{path} is already here") - - -def rmdir(path): - for root, dirs, files in os.walk(path, topdown=False): - for name in files: - os.remove(os.path.join(root, name)) - for name in dirs: - os.rmdir(os.path.join(root, name)) - os.removedirs(path) - - -def assert_shape(out1, out2): - if out1.shape != out2.shape: - msg = "Output shapes {} and {} don't match" - raise AssertionError(msg.format(out1.shape, out2.shape)) - - -class OneFlowGraph(flow.nn.Graph): - def __init__(self, module): - super().__init__() - self.m = module - - def build(self, x): - out = self.m(x) - return out - - -class OneFlowGraphV2(flow.nn.Graph): - def __init__(self, module): - super().__init__() - self.m = module - - def build(self, input_1, input_2, input_3): - out = self.m(input_1, input_2, input_3) - return out - - -class OneFlowGraphV3(flow.nn.Graph): - def __init__(self, module): - super().__init__() - self.m = module - - def build(self, input_1, input_2): - out = self.m(input_1, input_2) - return out - - -def get_oneflow_output(model, inputs): - flow_output = model(inputs) - return flow_output.numpy() - - -def get_oneflow_concat_output(model, input1, input2, input3): - flow_output = model(input1, input2, input3).numpy() - return flow_output - - -def get_oneflow_elementwise_output(model, input1, input2): - return model(input1, input2).numpy() - - -def get_tvm_output(graph, model_path, inputs: flow.tensor, target="llvm", dtype="float32"): - """Generic function to execute and get tvm output""" - inputs_numpy = inputs.numpy() - if target == "llvm": - device = tvm.cpu(0) - elif target == "cuda": - device = tvm.cuda(0) - - mod, params = relay.frontend.from_oneflow(graph, model_path) - with tvm.transform.PassContext(opt_level=10): - intrp = relay.build_module.create_executor("graph", mod, device, target) - tvm_output = intrp.evaluate()(tvm.nd.array(inputs_numpy.astype(dtype)), **params).numpy() - return tvm_output - - -def get_tvm_concat_output( - graph, - model_path, - input1: flow.tensor, - input2: flow.tensor, - input3: flow.tensor, - target="llvm", - dtype="float32", -): - """Generic function to execute and get tvm concat output""" - input1_numpy = input1.numpy() - input2_numpy = input2.numpy() - input3_numpy = input3.numpy() - if target == "llvm": - device = tvm.cpu(0) - elif target == "cuda": - device = tvm.cuda(0) - - mod, params = relay.frontend.from_oneflow(graph, model_path) - with tvm.transform.PassContext(opt_level=10): - intrp = relay.build_module.create_executor("graph", mod, device, target) - tvm_output = intrp.evaluate()( - tvm.nd.array(input1_numpy.astype(dtype)), - tvm.nd.array(input2_numpy.astype(dtype)), - tvm.nd.array(input3_numpy.astype(dtype)), - **params, - ).numpy() - return tvm_output - - -def get_tvm_elementwise_output( - graph, - model_path, - input1: flow.tensor, - input2: flow.tensor, - target="llvm", - dtype="float32", -): - """Generic function to execute and get tvm elementwise output""" - input1_numpy = input1.numpy() - input2_numpy = input2.numpy() - if target == "llvm": - device = tvm.cpu(0) - elif target == "cuda": - device = tvm.cuda(0) - - mod, params = relay.frontend.from_oneflow(graph, model_path) - with tvm.transform.PassContext(opt_level=10): - intrp = relay.build_module.create_executor("graph", mod, device, target) - tvm_output = intrp.evaluate()( - tvm.nd.array(input1_numpy.astype(dtype)), - tvm.nd.array(input2_numpy.astype(dtype)), - **params, - ).numpy() - return tvm_output - - -def verify_conv( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 224, 224), - dtype=flow.float32, - ), - device="llvm", -): - """verify_conv""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_pool( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 224, 224), - dtype=flow.float32, - ), - device="llvm", -): - """verify_pool""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_normalization( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 224, 224), - dtype=flow.float32, - ), - device="llvm", -): - """verify_normalization""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - # write params - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_upsample( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 50, 50), - dtype=flow.float32, - ), - device="llvm", -): - """verify_upsample""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_convtran( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 50, 50), - dtype=flow.float32, - ), - device="llvm", -): - """verify_convtran""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_activation( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(10, 10), - dtype=flow.float32, - ), - device="llvm", -): - """verify_activation""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_math( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(100, 1), - dtype=flow.float32, - ), - device="llvm", -): - """verify_math""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_matmul( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs1=flow.tensor(np.random.randn(2, 5), dtype=flow.float32), - inputs2=flow.tensor(np.random.randn(5, 2), dtype=flow.float32), - device="llvm", -): - """verify_matmul""" - if device == "cuda": - model.to(device) - inputs1 = inputs1.to(device) - inputs2 = inputs2.to(device) - - graph = OneFlowGraphV3(model) - graph._compile(inputs1, inputs2) - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_elementwise_output(graph, inputs1, inputs2) - out_tvm = get_tvm_elementwise_output(graph, MODEL_HOME, inputs1, inputs2, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -def verify_concat( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs1=flow.tensor(np.random.randn(2, 5, 5, 4), dtype=flow.float32), - inputs2=flow.tensor(np.random.randn(2, 5, 5, 2), dtype=flow.float32), - inputs3=flow.tensor(np.random.randn(2, 5, 5, 3), dtype=flow.float32), - device="llvm", -): - """verify_concat""" - if device == "cuda": - model.to(device) - inputs1 = inputs1.to(device) - inputs2 = inputs2.to(device) - inputs3 = inputs3.to(device) - - graph = OneFlowGraphV2(model) - graph._compile(inputs1, inputs2, inputs3) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_concat_output(graph, inputs1, inputs2, inputs3) - out_tvm = get_tvm_concat_output(graph, MODEL_HOME, inputs1, inputs2, inputs3, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -# defs/nn -@tvm.testing.uses_gpu -def test_conv2d(): - """Conv2d""" - - class Conv2dModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.conv = flow.nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1) - - def forward(self, x): - x = self.conv(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model = Conv2dModel() - model.eval() - - for device in ["llvm"]: - verify_conv(model, device=device) - - -@tvm.testing.uses_gpu -def test_pool2d(): - """Pool2d""" - - class MaxPool2dModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.pool = flow.nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - - def forward(self, x): - x = self.pool(x) - return x - - class AvgPool2dModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.pool = flow.nn.AvgPool2d(kernel_size=3, stride=2, padding=1) - - def forward(self, x): - x = self.pool(x) - return x - - class AdaptiveAvgPool2dModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.pool = flow.nn.AdaptiveAvgPool2d((None, 7)) - - def forward(self, x): - x = self.pool(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model1 = MaxPool2dModel().eval() - model2 = AvgPool2dModel().eval() - model3 = AdaptiveAvgPool2dModel().eval() - - for device in ["llvm"]: - verify_pool(model1, device=device) - verify_pool(model2, device=device) - verify_pool(model3, device=device) - - -@tvm.testing.uses_gpu -def test_normalization(): - """Normalization""" - - class BatchNorm2dModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.normalization = flow.nn.BatchNorm2d(3) - - def forward(self, x): - x = self.normalization(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model = BatchNorm2dModel().eval() - - for device in ["llvm"]: - verify_normalization(model, device=device) - - -@tvm.testing.uses_gpu -def test_upsample(): - """Upsample""" - - class UpsampleModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.upsample = flow.nn.Upsample(scale_factor=2.0, mode="nearest") - - def forward(self, x): - x = self.upsample(x) - return x - - class UpsampleBiliModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.upsample = flow.nn.UpsamplingBilinear2d(scale_factor=2.0) - - def forward(self, x): - x = self.upsample(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model1 = UpsampleModel().eval() - model2 = UpsampleBiliModel().eval() - - for device in ["llvm"]: - verify_upsample(model1, device=device) - verify_upsample(model2, device=device) - - -@tvm.testing.uses_gpu -def test_convtran(): - """ConvTran""" - - class ConvTranModel(flow.nn.Module): - def __init__(self): - super().__init__() - self.convtran = flow.nn.ConvTranspose2d(3, 4, (3, 5), stride=(2, 1), padding=(4, 2)) - - def forward(self, x): - x = self.convtran(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model = ConvTranModel().eval() - - for device in ["llvm"]: - verify_convtran(model, device=device) - - -@tvm.testing.uses_gpu -def test_activation(): - """Activation""" - - class Softmax(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Softmax() - - def forward(self, x): - x = self.active(x) - return x - - class Softplus(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Softplus() - - def forward(self, x): - x = self.active(x) - return x - - class Softsign(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Softsign() - - def forward(self, x): - x = self.active(x) - return x - - class Tanh(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Tanh() - - def forward(self, x): - x = self.active(x) - return x - - class ReLU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.ReLU() - - def forward(self, x): - x = self.active(x) - return x - - class ReLU6(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.ReLU6() - - def forward(self, x): - x = self.active(x) - return x - - class PReLU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.PReLU() - - def forward(self, x): - x = self.active(x) - return x - - class SELU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.SELU() - - def forward(self, x): - x = self.active(x) - return x - - class SiLU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.SiLU() - - def forward(self, x): - x = self.active(x) - return x - - class LeakyReLU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.LeakyReLU(0.1) - - def forward(self, x): - x = self.active(x) - return x - - class GELU(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.GELU() - - def forward(self, x): - x = self.active(x) - return x - - class HardTanh(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Hardtanh() - - def forward(self, x): - x = self.active(x) - return x - - class TensorSoftmax(flow.nn.Module): - def forward(self, x): - x = x.softmax(dim=-1) - return x - - class Threshold(flow.nn.Module): - def __init__(self): - super().__init__() - self.active = flow.nn.Threshold(0.5, 0.2) - - def forward(self, x): - x = self.active(x) - return x - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - model1 = Softmax().eval() - model2 = Softplus().eval() # pylint: disable=unused-variable - model3 = Softsign().eval() - model4 = Tanh().eval() - model5 = ReLU().eval() - model6 = ReLU6().eval() - model7 = PReLU().eval() - model8 = SELU().eval() - model9 = SiLU().eval() - model10 = LeakyReLU().eval() - model11 = GELU().eval() - model12 = HardTanh().eval() - model13 = TensorSoftmax().eval() - - for device in ["llvm"]: - verify_activation(model1, device=device) - verify_activation(model2, device=device) - verify_activation(model3, device=device) - verify_activation(model4, device=device) - verify_activation(model5, device=device) - verify_activation(model6, device=device) - verify_activation(model7, device=device) - verify_activation(model8, device=device) - verify_activation(model9, device=device) - verify_activation(model10, device=device) - verify_activation(model11, device=device) - verify_activation(model12, device=device) - verify_activation( - model13, - device=device, - inputs=flow.tensor(np.random.rand(1, 12, 197, 197).astype(np.float32)), - ) - - # Threshold was introduced in the version 0.8.0 of oneflow - if package_version.parse(flow.__version__) >= package_version.parse("0.8.0"): - model14 = Threshold().eval() - verify_activation(model14, device="llvm") - - -@tvm.testing.uses_gpu -def test_math(): - """Math""" - - class Sigmoid(flow.nn.Module): - def forward(self, x): - return flow.sigmoid(x) - - class Sign(flow.nn.Module): - def forward(self, x): - return flow.sign(x) - - class Reciprocal(flow.nn.Module): - def forward(self, x): - return flow.reciprocal(x) - - class Pow(flow.nn.Module): - def forward(self, x): - return flow.pow(x, 2.0) - - class Log(flow.nn.Module): - def forward(self, x): - return flow.log(x) - - class Log2(flow.nn.Module): - def forward(self, x): - return flow.log1p(x) - - class Exp(flow.nn.Module): - def forward(self, x): - return flow.exp(x) - - class Exp2(flow.nn.Module): - def forward(self, x): - return flow.expm1(x) - - class Variance(flow.nn.Module): - def forward(self, x): - return flow.var(x, 1, unbiased=False, keepdim=True) - - model1 = Sigmoid().eval() - model2 = Sign().eval() - model3 = Log().eval() - model4 = Log2().eval() - model5 = Exp().eval() - model6 = Exp2().eval() - model7 = Reciprocal().eval() - model8 = Pow().eval() - model9 = Variance().eval() - - for device in ["llvm"]: - verify_math(model1, device=device) - verify_math(model2, device=device) - verify_math(model3, device=device) - verify_math(model4, device=device) - verify_math(model5, device=device) - verify_math(model6, device=device) - verify_math(model7, device=device) - verify_math(model8, device=device) - verify_math(model9, device=device) - - -@tvm.testing.uses_gpu -def test_slice(): - """Slice""" - - class Slice(flow.nn.Module): - def forward(self, x): - tup_list = [[None, None, None], [0, 5, 2], [0, 6, 3]] - out = flow.slice(x, slice_tup_list=tup_list) - return out - - model = Slice().eval() - - for device in ["llvm"]: - verify_math( - model, device=device, inputs=flow.tensor(np.random.randn(3, 6, 9).astype(np.float32)) - ) - - -@tvm.testing.uses_gpu -def test_concat(): - """Concat""" - - class Concat(flow.nn.Module): - def forward(self, input_1, input_2, input_3): - out = flow.cat([input_1, input_2, input_3], dim=-1) - return out - - model = Concat().eval() - - for device in ["llvm"]: - verify_concat(model, device=device) - - -@tvm.testing.uses_gpu -def test_add_constant(): - """ConstantAdd""" - - class ConstantAdd(flow.nn.Module): - def forward(self, x): - out = flow.add(1.0, x) - return out - - model = ConstantAdd().eval() - - for device in ["llvm"]: - verify_math( - model, device=device, inputs=flow.tensor(np.random.randn(3, 6, 9).astype(np.float32)) - ) - - -@tvm.testing.uses_gpu -def test_logical(): - class LogicalGreater(flow.nn.Module): - def forward(self, x): - return x > 1.0 - - model1 = LogicalGreater().eval() - - for device in ["llvm"]: - verify_math( - model1, device=device, inputs=flow.tensor(np.random.randn(3, 6, 9).astype(np.float32)) - ) - - -@tvm.testing.uses_gpu -def test_expand(): - class Expand(flow.nn.Module): - def forward(self, x): - return x.expand(2, -1, -1) - - model1 = Expand().eval() - - for device in ["llvm"]: - verify_math( - model1, device=device, inputs=flow.tensor(np.random.randn(1, 6, 9).astype(np.float32)) - ) - - -@tvm.testing.uses_gpu -def test_matmul(): - """MatMul""" - - class MatMul(flow.nn.Module): - def forward(self, x, y): - return flow._C.matmul(x, y) - - class MatMulTranspose(flow.nn.Module): - def forward(self, x, y): - return flow._C.matmul(x, y, transpose_b=True) - - class BatchMatMul(flow.nn.Module): - def forward(self, x, y): - return flow._C.batch_matmul(x, y) - - class BroadCastMatMul(flow.nn.Module): - def forward(self, x, y): - return flow._C.matmul(x, y) - - model1 = MatMul().eval() - model2 = MatMulTranspose().eval() - model3 = BatchMatMul().eval() - model4 = BroadCastMatMul().eval() - - for device in ["llvm"]: - verify_matmul( - model1, - device=device, - inputs1=flow.tensor(np.random.randn(2, 3).astype(np.float32)), - inputs2=flow.tensor(np.random.randn(3, 3).astype(np.float32)), - ) - verify_matmul( - model2, - device=device, - inputs1=flow.tensor(np.random.randn(1, 2).astype(np.float32)), - inputs2=flow.tensor(np.random.randn(3, 2).astype(np.float32)), - ) - verify_matmul( - model3, - device=device, - inputs1=flow.tensor(np.random.randn(2, 1, 2).astype(np.float32)), - inputs2=flow.tensor(np.random.randn(2, 2, 3).astype(np.float32)), - ) - verify_matmul( - model4, - device=device, - inputs1=flow.tensor(np.random.randn(3, 8, 8, 16).astype(np.float32)), - inputs2=flow.tensor(np.random.randn(16, 8).astype(np.float32)), - ) - - -if __name__ == "__main__": - test_conv2d() - test_pool2d() - test_normalization() - test_upsample() - test_convtran() - test_activation() - test_math() - test_slice() - test_concat() - test_add_constant() - test_logical() - test_expand() - test_matmul() - rmdir("log") diff --git a/tests/python/frontend/oneflow/test_vision_models.py b/tests/python/frontend/oneflow/test_vision_models.py deleted file mode 100644 index 03478dc41e33..000000000000 --- a/tests/python/frontend/oneflow/test_vision_models.py +++ /dev/null @@ -1,149 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name -# pylint: disable=arguments-differ, unused-argument -"""Unit tests for various models and operators""" -import os - -import numpy as np -import oneflow as flow -from flowvision.models.alexnet import alexnet -from flowvision.models.squeezenet import squeezenet1_0 -from flowvision.models.shufflenet_v2 import shufflenet_v2_x0_5 -from flowvision.models.mobilenet import mobilenet_v2 -from flowvision.models.ghostnet import ghostnet -from flowvision.models.vision_transformer import vit_base_patch16_224 -import tvm -import tvm.testing -import tvm.topi.testing -from tvm import relay - -MODEL_HOME = "test_model" - - -def mkdir(path): - # init - path = path.strip() - path = path.rstrip("\\") - - if not os.path.exists(path): - os.makedirs(path) - else: - print(f"{path} is already here") - - -def rmdir(path): - for root, dirs, files in os.walk(path, topdown=False): - for name in files: - os.remove(os.path.join(root, name)) - for name in dirs: - os.rmdir(os.path.join(root, name)) - os.removedirs(path) - - -def assert_shape(out1, out2): - if out1.shape != out2.shape: - msg = "Output shapes {} and {} don't match" - raise AssertionError(msg.format(out1.shape, out2.shape)) - - -class OneFlowGraph(flow.nn.Graph): - def __init__(self, module): - super().__init__() - self.m = module - - def build(self, x): - out = self.m(x) - return out - - -def get_oneflow_output(model, inputs): - flow_output = model(inputs) - return flow_output.numpy() - - -def get_tvm_output(graph, model_path, inputs: flow.tensor, target="llvm", dtype="float32"): - """Generic function to execute and get tvm output""" - inputs_numpy = inputs.numpy() - if target == "llvm": - device = tvm.cpu(0) - elif target == "cuda": - device = tvm.cuda(0) - - mod, params = relay.frontend.from_oneflow(graph, model_path) - with tvm.transform.PassContext(opt_level=10): - intrp = relay.build_module.create_executor("graph", mod, device, target) - tvm_output = intrp.evaluate()(tvm.nd.array(inputs_numpy.astype(dtype)), **params).numpy() - return tvm_output - - -def verify_model( - model, - name="", - rtol=1e-5, - atol=1e-5, - inputs=flow.tensor( - np.random.rand(1, 3, 224, 224), - dtype=flow.float32, - ), - device="llvm", -): - """Generic function to generate and compare oneflow and TVM output""" - if device == "cuda": - model.to(device) - inputs = inputs.to(device) - - graph = OneFlowGraph(model) - graph._compile(inputs) - - mkdir(MODEL_HOME) - flow.save(model.state_dict(), MODEL_HOME) - - out_flow = get_oneflow_output(graph, inputs) - out_tvm = get_tvm_output(graph, MODEL_HOME, inputs, target=device) - rmdir(MODEL_HOME) - - assert_shape(out_flow, out_tvm) - tvm.testing.assert_allclose(out_flow, out_tvm, rtol=rtol, atol=atol) - - -@tvm.testing.uses_gpu -def test_vision_models(): - """Vision models test""" - - if os.path.exists(MODEL_HOME): - rmdir(MODEL_HOME) - - vision_alexnet = alexnet().eval() - vision_squeezenet = squeezenet1_0().eval() - vision_shufflenet = shufflenet_v2_x0_5().eval() - vision_mobilenetv2 = mobilenet_v2().eval() - vision_ghostnet = ghostnet().eval() - vision_vit = vit_base_patch16_224().eval() - - for device in ["llvm"]: - verify_model(vision_alexnet, device=device) - verify_model(vision_squeezenet, device=device) - verify_model(vision_shufflenet, device=device) - verify_model(vision_mobilenetv2, device=device) - verify_model(vision_ghostnet, device=device) - verify_model(vision_vit, device=device) - - -if __name__ == "__main__": - test_vision_models() - rmdir("log") diff --git a/tests/python/frontend/onnx/test_forward.py b/tests/python/frontend/onnx/test_forward.py deleted file mode 100644 index a81352bb679f..000000000000 --- a/tests/python/frontend/onnx/test_forward.py +++ /dev/null @@ -1,8716 +0,0 @@ -# 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. -# pylint: disable=unused-argument -""" -ONNX testcases -================ -This article is a test script to test ONNX operator with Relay. -""" -import glob -import os -import platform -import re -import copy -import tempfile -import pytest -import scipy -import numpy as np - -import tvm -import tvm.testing -import tvm.topi.testing -from tvm import relay -from tvm.contrib import graph_executor, utils -from tvm.relay.frontend.common import infer_type -from tvm.relay.build_module import bind_params_by_name -from relay.utils.tag_span import _create_span, _set_span, _verify_structural_equal_with_span - -import onnx -import onnxruntime.backend -from onnx import TensorProto, helper, mapping, numpy_helper -from onnxruntime.quantization import CalibrationDataReader, quantize_static - -import torch -import torchvision -from torch.nn import Linear, Module, Sequential - - -def get_input_data_shape_dict(graph_def, input_data): - """Get input data shape""" - if isinstance(input_data, list): - input_names = {} - shape_dict = {} - for i, _ in enumerate(input_data): - input_names[i] = graph_def.graph.input[i].name - input_ = input_data[i] - - if input_ is None or not hasattr(input_, "shape") or input_.shape == (): - # Skip adding input shape data when the input data is None; - # This is to enable optional arguments for onnx operators. - continue - - elif isinstance(input_, list): - shape_dict[input_names[i]] = (len(input_),) - - else: - shape_dict[input_names[i]] = input_.shape - - else: - input_names = graph_def.graph.input[0].name - shape_dict = {input_names: input_data.shape} - - return input_names, shape_dict - - -def get_tvm_output_with_vm( - graph_def, - input_data, - target, - dev, - opset=None, - freeze_params=False, - convert_config=None, - validate_structural_equal=True, -): - """Generic function to execute and get tvm output with vm executor""" - if not isinstance(input_data, list): - input_data = [input_data] - _, shape_dict = get_input_data_shape_dict(graph_def, input_data) - - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_onnx( - graph_def, - shape_dict, - opset=opset, - freeze_params=freeze_params, - convert_config=convert_config, - ) - # handle the bfloat16 so we explicitly allocate - # bfloat16 arrays as input - for i, param in enumerate(mod["main"].params): - if param.type_annotation.dtype == "bfloat16": - input_data[i] = tvm.nd.empty(input_data[i].shape, "bfloat16").copyfrom( - input_data[i] - ) - - if validate_structural_equal: - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_onnx( - graph_def, - shape_dict, - opset=opset, - freeze_params=freeze_params, - convert_config=convert_config, - ) - tvm.ir.assert_structural_equal(mod, mod_with_span) - - result = relay.create_executor("vm", mod=mod, device=dev, target=target).evaluate()( - *input_data, **params - ) - if isinstance(result, tvm.runtime.NDArray): - return result.numpy() - return [r.numpy() for r in result] - - -def get_tvm_output( - graph_def, - input_data, - target, - dev, - output_shape=None, - output_dtype="float32", - opset=None, - opt_level=1, - convert_config=None, -): - """Generic function to execute and get tvm output""" - # TODO: Resolve the issues and remove the following lines - input_names, shape_dict = get_input_data_shape_dict(graph_def, input_data) - - mod, params = relay.frontend.from_onnx( - graph_def, shape_dict, opset=opset, convert_config=convert_config - ) - - with tvm.transform.PassContext(opt_level=opt_level): - graph, lib, params = relay.build(mod, target, params=params) - - m = graph_executor.create(graph, lib, dev) - # set inputs - if isinstance(input_data, list): - for i, _ in enumerate(input_names): - # Its possible for some onnx inputs to not be needed in the tvm - # module, confirm its present before setting. - # pylint: disable=unnecessary-list-index-lookup - m.set_input(input_names[i], tvm.nd.array(input_data[i].astype(input_data[i].dtype))) - else: - m.set_input(input_names, tvm.nd.array(input_data.astype(input_data.dtype))) - - m.set_input(**params) - # execute - m.run() - # get outputs - if isinstance(output_shape, list): - tvm_output_list = [] - for i, _ in enumerate(output_shape): - tvm_output = m.get_output(i) - tvm_output_list.append(tvm_output.numpy()) - return tvm_output_list - else: - tvm_output = m.get_output(0) - return tvm_output.numpy() - - -def get_onnxruntime_output(model, inputs): - """Generic function to generate onnxruntime output""" - rep = onnxruntime.backend.prepare(model.SerializeToString(), "CPU") - if isinstance(inputs, list) and len(inputs) == 1: - inp = inputs[0] - else: - inp = inputs - output = rep.run(inp) - # Unpack output if there's only a single value. - if len(output) == 1: - output = output[0] - return output - - -def verify_with_ort_with_inputs( - model, - inputs, - out_shape=None, - target=None, - dev=None, - use_vm=False, - opset=None, - freeze_params=False, - dtype="float32", - rtol=1e-5, - atol=1e-5, - apply_softmax=False, - opt_level=1, - convert_config=None, -): - """verify_with_ort_with_inputs""" - if opset is not None: - model.opset_import[0].version = opset - - ort_out = get_onnxruntime_output(model, inputs) - if use_vm: - tvm_out = get_tvm_output_with_vm( - model, - inputs, - target, - dev, - opset=opset, - freeze_params=freeze_params, - convert_config=convert_config, - ) - else: - tvm_out = get_tvm_output( - model, - inputs, - target, - dev, - out_shape, - dtype, - opset=opset, - opt_level=opt_level, - convert_config=convert_config, - ) - - if not isinstance(tvm_out, list): - tvm_out = [tvm_out] - if not isinstance(ort_out, list): - ort_out = [ort_out] - for tvm_val, ort_val in zip(tvm_out, ort_out): - if apply_softmax: - ort_val = scipy.special.softmax(ort_val) - tvm_val = scipy.special.softmax(tvm_val) - tvm.testing.assert_allclose(ort_val, tvm_val, rtol=rtol, atol=atol) - assert ort_val.dtype == tvm_val.dtype - - -def verify_with_ort( - model, - input_shapes, - out_shape=None, - target=None, - dev=None, - use_vm=False, - opset=None, - freeze_params=False, - dtype="float32", - rtol=1e-5, - atol=1e-5, -): - """verify_with_ort""" - inputs = [np.random.uniform(size=ishape).astype(dtype) for ishape in input_shapes] - verify_with_ort_with_inputs( - model, - inputs, - out_shape=out_shape, - target=target, - dev=dev, - use_vm=use_vm, - opset=opset, - freeze_params=freeze_params, - dtype=dtype, - rtol=rtol, - atol=atol, - ) - - -def quantize_and_verify_with_ort( - onnx_model, input_names, input_shapes, target, dev, rtol=1e-5, atol=1e-5 -): - """quantize_and_verify_with_ort""" - input_arrays = [np.random.random(shape).astype("float32") for shape in input_shapes] - - class RandomDataReader(CalibrationDataReader): - # pylint: disable=missing-class-docstring - def __init__(self, n=10): - input_dict = dict(zip(input_names, input_shapes)) - self.data = iter( - [ - { - name: np.random.random(shape).astype("float32") - for name, shape in input_dict.items() - } - for _ in range(n) - ] - ) - - def get_next(self): - return next(self.data, None) - - t_dir = tvm.contrib.utils.tempdir() - model_fp32 = os.path.join(t_dir.temp_dir, "model.onnx") - onnx.save_model(onnx_model, model_fp32) - model_quant = os.path.join(t_dir.temp_dir, "model.quant.onnx") - _ = quantize_static( # pylint: disable=assignment-from-no-return - model_fp32, model_quant, RandomDataReader() - ) - # opt_level=1 will cause error with qnn lowering - model = onnx.load(model_quant) - verify_with_ort_with_inputs( - model, input_arrays, opt_level=2, target=target, dev=dev, use_vm=True, rtol=rtol, atol=atol - ) - - -def make_constant_node(name, data_type, dims, vals): - return helper.make_node( - "Constant", - inputs=[], - outputs=[name], - value=helper.make_tensor(name=name, data_type=data_type, dims=dims, vals=vals), - ) - - -def is_version_greater_than(ver): - return "".join(re.findall(r"(\d+\.)(\d+\.)(\d)", onnx.__version__)[0]) > "".join( - re.findall(r"(\d+\.)(\d+\.)(\d)", ver)[0] - ) - - -@tvm.testing.parametrize_targets -def test_reshape(target, dev): - """test_reshape""" - in_shape = (4, 3, 3, 4) - ref_shape = (6, 2, 4, 3) - - ref_array = np.array(ref_shape) - ref_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["ref_in"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=onnx.TensorProto.INT32, - dims=ref_array.shape, - vals=ref_array.flatten().astype(int), - ), - ) - reshape_node = helper.make_node("Reshape", ["in", "ref_in"], ["out"]) - - graph = helper.make_graph( - [ref_node, reshape_node], - "reshape_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(ref_shape))], - ) - - model = helper.make_model(graph, producer_name="reshape_test") - - x = np.random.uniform(size=in_shape).astype("int32") - tvm_out = get_tvm_output(model, x, target, dev, ref_shape, "float32") - tvm.testing.assert_allclose(ref_shape, tvm_out.shape) - - -@tvm.testing.parametrize_targets -def test_double_reshape(target, dev): - """test_double_reshape""" - in_shape = (4, 3, 3, 4) - ref_shape = (6, 2, 4, 3) - - ref_array = np.array(ref_shape) - ref_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["ref_in"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=onnx.TensorProto.INT32, - dims=ref_array.shape, - vals=ref_array.flatten().astype(int), - ), - ) - reshape_node1 = helper.make_node("Reshape", ["in", "ref_in"], ["out1"]) - reshape_node2 = helper.make_node("Reshape", ["in", "ref_in"], ["out2"]) - add_node = helper.make_node("Add", ["out1", "out2"], ["out"]) - - graph = helper.make_graph( - [ref_node, reshape_node1, reshape_node2, add_node], - "reshape_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(ref_shape))], - ) - - model = helper.make_model(graph, producer_name="reshape_test") - - x = np.random.uniform(size=in_shape).astype("int32") - tvm_out = get_tvm_output(model, x, target, dev, ref_shape, "float32") - tvm.testing.assert_allclose(ref_shape, tvm_out.shape) - - -@tvm.testing.parametrize_targets -def test_expand(target, dev): - """test_expand""" - - def _test_expand(name, data, shape, ref_data, dtype="int32"): - shape_array = np.array(shape) - if dtype == "int32": - shape_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["shape"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=onnx.TensorProto.INT32, - dims=shape_array.shape, - vals=shape_array.flatten().astype("int32"), - ), - ) - elif dtype == "int64": - shape_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["shape"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=onnx.TensorProto.INT64, - dims=shape_array.shape, - vals=shape_array.flatten().astype("int64"), - ), - ) - else: - raise TypeError("Invalid dtype") - expand_node = helper.make_node("Expand", ["in", "shape"], ["out"]) - - graph = helper.make_graph( - [shape_node, expand_node], - "expand_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(data.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(ref_data.shape))], - ) - - model = helper.make_model(graph, producer_name=name) - - tvm_out = get_tvm_output_with_vm(model, data, target, dev, freeze_params=True) - tvm.testing.assert_allclose(ref_data, tvm_out) - - in_shape = (3, 1) - shape = (3, 4) - data = np.random.uniform(size=in_shape).astype(np.float32) - ref_data = np.tile(data, 4) - _test_expand("expand_with_dim_unchanged_test", data, shape, ref_data, "int32") - _test_expand("expand_with_dim_unchanged_test", data, shape, ref_data, "int64") - - in_shape = (3, 1) - shape = (2, 1, 6) - data = np.random.uniform(size=in_shape).astype(np.float32) - ref_data = data * np.ones(shape, dtype=np.float32) - _test_expand("expand_larger_target_shape_test", data, shape, ref_data, "int32") - _test_expand("expand_larger_target_shape_test", data, shape, ref_data, "int64") - - in_shape = (1, 1) - shape = (3,) - data = np.random.uniform(size=in_shape).astype(np.float32) - ref_data = data * np.ones(shape, dtype=np.float32) - _test_expand("expand_smaller_target_shape_test", data, shape, ref_data, "int32") - _test_expand("expand_smaller_target_shape_test", data, shape, ref_data, "int64") - - -@tvm.testing.parametrize_targets -def test_depth_to_space(target, dev): - """test_depth_to_space""" - - def verify_depth_to_space(inshape, outshape, mode, block_size): - node = onnx.helper.make_node( - "DepthToSpace", inputs=["x"], outputs=["y"], blocksize=block_size - ) - - graph = helper.make_graph( - [node], - "depth_to_space_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(inshape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(outshape))], - ) - - model = helper.make_model(graph, producer_name="depth_to_space_test") - - verify_with_ort(model, [inshape], [outshape], target, dev) - - # current onnx.checker use OpSet-1 version of DepthToSpace, which doesn't have a mode argument. - # TO-DO, we can add mode argument to test CRD mode and DCR mode - # in the future when we update to a newer onnx version. - verify_depth_to_space((1, 8, 2, 3), (1, 2, 4, 6), mode="CRD", block_size=2) - - -@tvm.testing.parametrize_targets -def test_space_to_depth(target, dev): - """test_space_to_depth""" - - def verify_space_to_depth(inshape, outshape, block_size): - node = onnx.helper.make_node( - "SpaceToDepth", inputs=["x"], outputs=["y"], blocksize=block_size - ) - - graph = helper.make_graph( - [node], - "space_to_depth_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(inshape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(outshape))], - ) - - model = helper.make_model(graph, producer_name="space_to_depth_test") - - verify_with_ort(model, [inshape], [outshape], target, dev) - - verify_space_to_depth((1, 1, 4, 6), (1, 4, 2, 3), 2) - - -@tvm.testing.parametrize_targets -def test_shape(target, dev): - """test_shape""" - in_shape = (4, 3, 3, 4) - ref_shape = (6, 2, 4, 3) - - ref_array = np.array(ref_shape) - ref_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["ref_in"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=onnx.TensorProto.INT32, - dims=ref_array.shape, - vals=ref_array.flatten().astype(int), - ), - ) - reshape_node = helper.make_node("Reshape", ["in", "ref_in"], ["out"]) - - shape_node = helper.make_node("Shape", ["out"], ["final_out"]) - - graph = helper.make_graph( - [ref_node, reshape_node, shape_node], - "shape_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("final_out", TensorProto.FLOAT, list(ref_shape))], - ) - - model = helper.make_model(graph, producer_name="shape_test") - - x = np.random.uniform(size=in_shape).astype("int32") - tvm_out = get_tvm_output(model, x, target, dev, ref_shape, "int32") - tvm.testing.assert_allclose(ref_shape, tvm_out) - - -@tvm.testing.parametrize_targets -def test_power(target, dev): - """test_power""" - - def _test_power_iteration(x_shape, y_shape): - if isinstance(y_shape, int): - y_shape = [y_shape] - - x = np.random.uniform(size=x_shape).astype(np.float32) - y = np.random.uniform(size=y_shape).astype(np.float32) - - np_res = np.power(x, y).astype(np.float32) - - res = helper.make_node("Pow", ["x", "y"], ["out"]) - - graph = helper.make_graph( - [res], - "power_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("y", TensorProto.FLOAT, list(y_shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(np_res.shape))], - ) - - model = helper.make_model(graph, producer_name="power_test") - - tvm_out = get_tvm_output(model, [x, y], target, dev, np_res.shape) - tvm.testing.assert_allclose(np_res, tvm_out, rtol=1e-5, atol=1e-5) - - _test_power_iteration((1, 3), (1)) - _test_power_iteration((2, 3), (2, 3)) - _test_power_iteration((2, 3), (1, 3)) - - -@tvm.testing.parametrize_targets -def test_range(target, dev): - """test_range""" - - def verify_range(start, limit, delta, dtype): - dtype_map = { - "float32": TensorProto.FLOAT, - "int32": TensorProto.INT32, - "int64": TensorProto.INT64, - } - dtype_onnx = dtype_map[dtype] - y = helper.make_node("Range", ["start", "limit", "delta"], ["output"]) - graph = helper.make_graph( - [y], - "range_test", - inputs=[ - helper.make_tensor_value_info("start", dtype_onnx, []), - helper.make_tensor_value_info("limit", dtype_onnx, []), - helper.make_tensor_value_info("delta", dtype_onnx, []), - ], - outputs=[ - helper.make_tensor_value_info( - "output", dtype_onnx, np.arange(start, limit, delta).shape - ) - ], - ) - model = helper.make_model(graph, producer_name="range_test") - inputs = [np.array(x).astype(dtype) for x in [start, limit, delta]] - verify_with_ort_with_inputs(model, inputs, target=target, dev=dev, use_vm=True) - - for t in ["float32", "int32", "int64"]: - verify_range(0, 10, 1, t) - verify_range(2, 8, 2, t) - verify_range(-3, 6, 4, t) - verify_range(-2, -7, -1, t) - - -@tvm.testing.parametrize_targets -def test_squeeze(target, dev): - """test_squeeze""" - - def test_squeeze_once(in_shape, out_shape, axes=None): - y = helper.make_node("Squeeze", ["in"], ["out"], axes=axes) - - graph = helper.make_graph( - [y], - "squeeze_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="squeeze_test") - x = np.random.uniform(size=in_shape).astype("float32") - verify_with_ort_with_inputs(model, [x], [out_shape], target=target, dev=dev, opset=11) - - test_squeeze_once((1, 3, 1, 3, 1, 1), (3, 3), [0, 2, 4, 5]) - test_squeeze_once((1, 3, 1, 3, 1, 1), (3, 3)) # empty axis. - test_squeeze_once((), ()) # scalar testing. - - -@tvm.testing.parametrize_targets -def test_flatten(target, dev): - """test_flatten""" - - def verify_flatten(in_shape, axis, ref_shape): - flatten_node = helper.make_node("Flatten", ["in"], ["out"], axis=axis) - - graph = helper.make_graph( - [flatten_node], - "flatten_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(ref_shape))], - ) - - model = helper.make_model(graph, producer_name="flatten_test") - verify_with_ort(model, [in_shape], target=target, dev=dev) - - verify_flatten((1, 3, 4, 4), 1, (1, 48)) - verify_flatten((1,), 1, (1, 1)) - - -@tvm.testing.parametrize_targets -def test_unsqueeze(target, dev): - """test_unsqueeze""" - in_shape = (3, 3) - axis = (0, 3, 4) - out_shape = (1, 3, 3, 1, 1) - y = helper.make_node("Unsqueeze", ["in"], ["out"], axes=list(axis)) - - graph = helper.make_graph( - [y], - "squeeze_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="squeeze_test") - verify_with_ort(model, [in_shape], target=target, dev=dev, opset=11) - - -@tvm.testing.parametrize_targets -def test_unsqueeze_with_neg_axes(target, dev): - def verify_unsqueeze_with_neg_axes(opset=11): - in_shape = (2, 3, 4) - axis = (-2, -1) - out_shape = (2, 3, 4, 1, 1) - if opset < 13: - y = helper.make_node("Unsqueeze", ["in"], ["out"], axes=list(axis)) - nodes = [y] - else: - axes = np.array(list(axis)).astype(np.int64) - axes = helper.make_node( - "Constant", - inputs=[], - outputs=["axes"], - value=onnx.helper.make_tensor( - name="const_axes", - data_type=onnx.TensorProto.INT64, - dims=axes.shape, - vals=axes.flatten().astype(int), - ), - ) - y = helper.make_node("Unsqueeze", ["in", "axes"], ["out"]) - nodes = [axes, y] - - graph = helper.make_graph( - nodes, - "squeeze_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="squeeze_test") - verify_with_ort(model, [in_shape], target=target, dev=dev, opset=opset) - - verify_unsqueeze_with_neg_axes() - verify_unsqueeze_with_neg_axes(opset=13) - - -@tvm.testing.parametrize_targets -def test_gather(target, dev): - """test_gather""" - - def verify_gather(in_shape, indices, axis, dtype): - x = np.random.uniform(size=in_shape).astype(dtype) - indices = np.array(indices, dtype="int64") - out_np = np.take(x, indices, axis=axis) - - y = helper.make_node("Gather", ["in", "indices"], ["out"], axis=axis) - - graph = helper.make_graph( - [y], - "gather_test", - inputs=[ - helper.make_tensor_value_info( - "in", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], list(in_shape) - ), - helper.make_tensor_value_info("indices", TensorProto.INT64, list(indices.shape)), - ], - outputs=[ - helper.make_tensor_value_info( - "out", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], list(out_np.shape) - ) - ], - ) - model = helper.make_model(graph, producer_name="gather_test") - verify_with_ort_with_inputs(model, [x, indices], target=target, dev=dev, dtype=dtype) - - verify_gather((4,), [1], 0, "int32") - verify_gather((1, 4), [0], 0, "int32") - verify_gather((4,), [[[1, 0], [0, 1]]], 0, "float32") - verify_gather((2, 2), [[[1, 0], [0, 1]]], 1, "int32") - verify_gather((3, 3, 3), [[[1, 0]]], -1, "int32") - verify_gather((4, 3, 5, 6), [[2, 1, 0, 0]], 0, "float32") - - -@tvm.testing.parametrize_targets -def test_dynamic_gather(target, dev): - """test_dynamic_gather""" - dtype = "float32" - in_shape = [2, 2] - indices = 1 - axis = 1 - x = np.random.uniform(size=in_shape).astype(dtype) - indices = np.array(indices, dtype="int64") - out_np = np.take(x, indices, axis=axis) - - indices = helper.make_node( - "Constant", - inputs=[], - outputs=["indices"], - value=onnx.helper.make_tensor( - name="const_indices", - data_type=onnx.TensorProto.INT64, - dims=[], - vals=[1], - ), - ) - y = helper.make_node("Gather", ["in", "indices"], ["out"], axis=axis) - - graph = helper.make_graph( - [indices, y], - "gather_test", - inputs=[ - helper.make_tensor_value_info( - "in", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], ["?", "?"] - ), - ], - outputs=[ - helper.make_tensor_value_info( - "out", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], ["?"] * len(out_np.shape) - ) - ], - ) - model = helper.make_model(graph, producer_name="dynamic_gather_test") - - mod, params = relay.frontend.from_onnx(model) - - result = relay.create_executor("vm", mod=mod, device=dev, target=target).evaluate()(x, **params) - tvm.testing.assert_allclose(out_np, result.numpy(), rtol=1e-5, atol=1e-5) - - -@tvm.testing.parametrize_targets -def test_gatherelements(target, dev): - """test_gatherelements""" - - def verify_gatherelements(in_shape, indices, axis): - x = np.random.uniform(size=in_shape).astype("float32") - indices = np.array(indices, dtype="int32") - - y = helper.make_node("GatherElements", ["data", "indices"], ["output"], axis=axis) - graph = helper.make_graph( - [y], - "gather_elements_test", - inputs=[ - helper.make_tensor_value_info("data", TensorProto.FLOAT, list(in_shape)), - helper.make_tensor_value_info("indices", TensorProto.INT32, list(indices.shape)), - ], - outputs=[helper.make_tensor_value_info("output", TensorProto.FLOAT, list(in_shape))], - ) - model = helper.make_model(graph, producer_name="gather_elements_test") - - verify_with_ort_with_inputs(model, [x, indices], target=target, dev=dev) - - verify_gatherelements((4,), [3, 0, 2, 1], 0) - verify_gatherelements((2, 2), [[1, 0], [0, 1]], 0) - verify_gatherelements((2, 2), [[0, 0], [1, 0]], 1) - verify_gatherelements((2, 2), [[1, 0], [0, 1]], 1) - - indices = [ - [[1, 0, 0], [1, 0, 1], [0, 1, 1]], - [[1, 1, 1], [1, 2, 1], [1, 0, 1]], - [[1, 2, 1], [1, 2, 1], [1, 2, 1]], - ] - - verify_gatherelements((3, 3, 3), indices, 2) - - -@tvm.testing.parametrize_targets -def test_scatter(target, dev): - """test_scatter""" - - def verify_scatter(in_shape, indices, axis): - x = np.random.uniform(size=in_shape).astype("float32") - indices = np.array(indices, dtype="int32") - updates = np.random.uniform(size=indices.shape).astype("float32") - - y = helper.make_node("Scatter", ["data", "indices", "updates"], ["output"], axis=axis) - - graph = helper.make_graph( - [y], - "scatter_test", - inputs=[ - helper.make_tensor_value_info("data", TensorProto.FLOAT, list(in_shape)), - helper.make_tensor_value_info("indices", TensorProto.INT32, list(indices.shape)), - helper.make_tensor_value_info("updates", TensorProto.FLOAT, list(indices.shape)), - ], - outputs=[helper.make_tensor_value_info("output", TensorProto.FLOAT, list(in_shape))], - ) - model = helper.make_model(graph, producer_name="scatter_test") - # Scatter operator has been supported from version 9 and - # deprecated since version 11 of the default ONNX operator set - verify_with_ort_with_inputs(model, [x, indices, updates], target=target, dev=dev, opset=9) - - verify_scatter((4,), [1], 0) - verify_scatter((1, 4), [[0]], 0) - verify_scatter((4,), [2, 3], 0) - verify_scatter((2, 2), [[1, 0], [0, 1]], 1) - verify_scatter((3, 3, 3), [[[-1, -3]]], -1) - verify_scatter((4, 3, 5, 6), [[[[2, 1, 0, 0]]]], 0) - - -@tvm.testing.parametrize_targets -def test_scatter_elements(target, dev): - """test_scatter_elements""" - - def verify_scatter_elements(in_shape, indices, axis=0, reduction="update"): - x = np.random.uniform(size=in_shape).astype("float32") - indices = np.array(indices, dtype="int32") - updates = np.random.uniform(size=indices.shape).astype("float32") - - scatter_elements_node = helper.make_node( - "ScatterElements", - ["data", "indices", "updates"], - ["output"], - axis=axis, - reduction=reduction, - ) - - graph = helper.make_graph( - [scatter_elements_node], - "scatter_elements_test", - inputs=[ - helper.make_tensor_value_info("data", TensorProto.FLOAT, list(in_shape)), - helper.make_tensor_value_info("indices", TensorProto.INT32, list(indices.shape)), - helper.make_tensor_value_info("updates", TensorProto.FLOAT, list(indices.shape)), - ], - outputs=[helper.make_tensor_value_info("output", TensorProto.FLOAT, list(in_shape))], - ) - model = helper.make_model(graph, producer_name="scatter_elements_test") - verify_with_ort_with_inputs(model, [x, indices, updates], target=target, dev=dev) - - # Usual scatter for 1d input - verify_scatter_elements((4,), [2, 3]) - # Usual scatter with specified positive axis - verify_scatter_elements((2, 2), [[1, 0], [0, 1]], 1) - # Usual scatter for 3d input with spicified negative indices and axis - verify_scatter_elements((3, 3, 3), [[[-1, -3]]], -1) - # Usual scatter for 4d input - verify_scatter_elements((4, 3, 5, 6), [[[[2, 1, 0, 0]]]]) - # Scatter elements with addition reduction of duplicates - verify_scatter_elements( - (3, 3, 3), - [[[0, 2, 1], [1, 1, 1], [2, 1, 0]], [[0, 2, 1], [1, 1, 1], [2, 1, 0]]], - 0, - "add", - ) - # Scatter elements with reduction and specified axis - verify_scatter_elements((3, 3, 3), [[[2, 2, 2], [1, 1, 1], [0, 0, 0]]], 2, "add") - # Scatter elements with multiplication reduction of duplicates - verify_scatter_elements( - (3, 3, 3), - [[[0, 2, 1], [1, 1, 1], [2, 1, 0]], [[0, 2, 1], [1, 1, 1], [2, 1, 0]]], - 0, - "mul", - ) - # TODO(vvchernov): min and max options are supported from 18 version, but CI supports 17 only - # # Scatter elements with min reduction of duplicates - # verify_scatter_elements( - # (3, 3, 3), - # [[[0, 2, 1], [1, 1, 1], [2, 1, 0]], [[0, 2, 1], [1, 1, 1], [2, 1, 0]]], - # 0, - # "min", - # ) - # # Scatter elements with max reduction of duplicates - # verify_scatter_elements( - # (3, 3, 3), - # [[[0, 2, 1], [1, 1, 1], [2, 1, 0]], [[0, 2, 1], [1, 1, 1], [2, 1, 0]]], - # 0, - # "max", - # ) - - -@tvm.testing.parametrize_targets -def test_slice(target, dev): - """test_slice""" - - def _test_slice_iteration_v1(indata, outdata, starts, ends, axes=None): - if axes: - y = helper.make_node("Slice", ["in"], ["out"], axes=axes, starts=starts, ends=ends) - else: - y = helper.make_node("Slice", ["in"], ["out"], starts=starts, ends=ends) - - graph = helper.make_graph( - [y], - "slice_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(indata.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name="slice_test") - verify_with_ort_with_inputs( - model, [indata], [outdata.shape], opset=1, target=target, dev=dev - ) - - def _test_slice_iteration_v10(indata, outdata, **attrs): - starts = attrs["starts"] - ends = attrs["ends"] - axes = None if "axes" not in attrs else attrs["axes"] - steps = None if "steps" not in attrs else attrs["steps"] - starts = np.asarray(starts) - ends = np.asarray(ends) - inputs = [ - helper.make_tensor_value_info("data", TensorProto.FLOAT, list(indata.shape)), - helper.make_tensor_value_info("starts", TensorProto.INT64, list(starts.shape)), - helper.make_tensor_value_info("ends", TensorProto.INT64, list(ends.shape)), - ] - initializer = [ - helper.make_tensor("starts", TensorProto.INT64, list(starts.shape), starts), - helper.make_tensor("ends", TensorProto.INT64, list(ends.shape), ends), - ] - nodes = [] - - if "add_noop_to_input_attrs" in attrs: - - def add_noop_to_input_attr(attr_name, attr): - output_name = attr_name + "_output" - - ref_shape = list(np.array(attr).shape) - ref_shape.insert(0, 1) - ref_shape = tuple(ref_shape) - ref_array = np.array(ref_shape) - ref_node = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["ref_in_" + attr_name], - value=onnx.helper.make_tensor( - name="const_tensor__1_" + attr_name, - data_type=onnx.TensorProto.INT64, - dims=ref_array.shape, - vals=ref_array.flatten().astype(int), - ), - ) - in_shape = np.array(attr).shape - in_array = np.array(in_shape) - ref_node2 = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=["input_shape_" + attr_name], - value=onnx.helper.make_tensor( - name="const_tensor__2_" + attr_name, - data_type=onnx.TensorProto.INT64, - dims=in_array.shape, - vals=in_array.flatten().astype(int), - ), - ) - - reshape1_node = helper.make_node( - "Reshape", [attr_name, "ref_in_" + attr_name], ["reshape_" + attr_name] - ) - reshape2_node = helper.make_node( - "Reshape", ["reshape_" + attr_name, "input_shape_" + attr_name], [output_name] - ) - return [ref_node, ref_node2, reshape1_node, reshape2_node] - - slice_inputs = [] - for attr_name in ["starts", "ends", "axes", "steps"]: - if attr_name not in attrs: - continue - if "add_noop_to_input_attrs" in attrs and attr_name in attrs["add_noop_to_input_attrs"]: - nodes.extend(add_noop_to_input_attr(attr_name, attrs[attr_name])) - slice_inputs.append(attr_name + "_output") - else: - slice_inputs.append(attr_name) - - if axes: - axes = np.asarray(axes) - inputs.append( - helper.make_tensor_value_info("axes", TensorProto.INT64, list(axes.shape)) - ) - initializer.append( - helper.make_tensor("axes", TensorProto.INT64, list(axes.shape), axes) - ) - - if steps: - assert axes is not None and len(axes) == len(steps) - steps = np.asarray(steps) - inputs.append( - helper.make_tensor_value_info("steps", TensorProto.INT64, list(axes.shape)) - ) - initializer.append( - helper.make_tensor("steps", TensorProto.INT64, list(steps.shape), steps) - ) - - y = helper.make_node("Slice", ["data", *slice_inputs], ["out"]) - - nodes.append(y) - graph = helper.make_graph( - nodes, - "slice_test", - inputs=inputs, - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(outdata.shape))], - initializer=initializer, - ) - model = helper.make_model(graph, producer_name="slice_test") - verify_with_ort_with_inputs( - model, [indata], opset=10, freeze_params=True, use_vm=True, target=target, dev=dev - ) - - x = np.random.randn(20, 10, 5).astype(np.float32) - _test_slice_iteration_v1(x, x[0:3, 0:10], starts=(0, 0), ends=(3, 10), axes=(0, 1)) - _test_slice_iteration_v1(x, x[0:3, 0:10], starts=(0, 0), ends=(10, 3), axes=(1, 0)) - _test_slice_iteration_v1(x, x[:, :, 3:4], starts=(0, 0, 3), ends=(20, 10, 4)) - _test_slice_iteration_v1(x, x[:, 1:1000], starts=(1,), ends=(1000,), axes=(1,)) - _test_slice_iteration_v1(x, x[:, 0:-1], starts=(0,), ends=(-1,), axes=(1,)) - _test_slice_iteration_v10(x, x[0:3, 0:10], starts=(0, 0), ends=(3, 10), axes=(0, 1)) - _test_slice_iteration_v10(x, x[0:3, 0:10], starts=(0, 0), ends=(10, 3), axes=(1, 0)) - _test_slice_iteration_v10(x, x[:, :, 3:4], starts=(0, 0, 3), ends=(20, 10, 4)) - _test_slice_iteration_v10(x, x[:, 1:1000], starts=(1,), ends=(1000,), axes=(1,)) - _test_slice_iteration_v10(x, x[:, 0:-1], starts=(0,), ends=(-1,), axes=(1,)) - _test_slice_iteration_v10(x, x[:, 0:-1], starts=(0,), ends=(-1,), axes=(-1,)) - _test_slice_iteration_v10( - x, - x[0:3, 0:10], - starts=(0, 0), - ends=(3, 10), - axes=(0, 1), - add_noop_to_input_attrs=["starts"], - ) - _test_slice_iteration_v10( - x, x[:, :, 3:4], starts=(0, 0, 3), ends=(20, 10, 4), add_noop_to_input_attrs=["ends"] - ) - _test_slice_iteration_v10( - x, x[:, 1:1000], starts=(1,), ends=(1000,), axes=(1,), add_noop_to_input_attrs=["axes"] - ) - _test_slice_iteration_v10( - x, - x[:, 0:-1], - starts=(0,), - ends=(-1,), - axes=(1,), - add_noop_to_input_attrs=["starts", "ends"], - ) - _test_slice_iteration_v10( - x, - x[0:3, 0:10], - starts=(0, 0), - ends=(3, 10), - axes=(0, 1), - add_noop_to_input_attrs=["ends", "axes"], - ) - _test_slice_iteration_v10( - x, - x[:, :, 3:4], - starts=(0, 0, 3), - ends=(20, 10, 4), - add_noop_to_input_attrs=["starts", "axes"], - ) - _test_slice_iteration_v10( - x, - x[:, 1:1000], - starts=(1,), - ends=(1000,), - axes=(1,), - add_noop_to_input_attrs=["starts", "ends", "axes"], - ) - x = np.random.randn(1, 1, 1, 128).astype(np.float32) - _test_slice_iteration_v10( - x, x, starts=(0, 0), ends=(9223372036854775807, 9223372036854775807), axes=(0, 3) - ) - - x = np.random.randn(4, 4).astype(np.float32) - _test_slice_iteration_v10( - x, x[:, 1::2], starts=(1,), ends=(9223372036854775807,), axes=(1,), steps=(2,) - ) - _test_slice_iteration_v10( - x, - x[0::1, 1::2], - starts=(0, 1), - ends=(4, 4), - axes=(0, 1), - steps=(1, 2), - ) - - -def _test_onnx_op_elementwise( - target, dev, inshape, outfunc, npargs, dtype, opname, kwargs, opset=None, verify=True -): - indata = np.random.uniform(-1, 1, size=inshape).astype(dtype) - outdata = outfunc(indata, **npargs) - - y = helper.make_node(opname, ["in"], ["out"], **kwargs) - - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - - graph = helper.make_graph( - [y], - opname + "_test", - inputs=[helper.make_tensor_value_info("in", ONNX_DTYPE, list(indata.shape))], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name=opname + "_test") - if verify: - verify_with_ort_with_inputs( - model, [indata], [outdata.shape], opset=opset, dtype=dtype, target=target, dev=dev - ) - else: - get_tvm_output( - model, - [indata], - target, - dev, - [outdata.shape], - dtype, - opset=opset, - opt_level=3, - ) - - -@tvm.testing.parametrize_targets -def test_floor(target, dev): - _test_onnx_op_elementwise(target, dev, (2, 4, 5, 6), np.floor, {}, "float32", "Floor", {}) - - -@tvm.testing.parametrize_targets -def test_ceil(target, dev): - _test_onnx_op_elementwise(target, dev, (2, 4, 5, 6), np.ceil, {}, "float32", "Ceil", {}) - - -@tvm.testing.parametrize_targets -def test_clip(target, dev): - """test_clip""" - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - np.clip, - {"a_min": -1.0, "a_max": 1.0}, - "float32", - "Clip", - {"min": -1.0, "max": 1.0}, - opset=6, - ) - - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - np.clip, - {"a_min": -np.inf, "a_max": 1.0}, - "float32", - "Clip", - {"max": 1.0}, - opset=6, - ) - - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - np.clip, - {"a_min": -1.0, "a_max": np.inf}, - "float32", - "Clip", - {"min": -1.0}, - opset=6, - ) - - -@tvm.testing.parametrize_targets -def test_clip_min_max_as_inputs(target, dev): - """test_clip_min_max_as_inputs""" - input_shape = (2, 4, 5, 6) - nodes = [ - make_constant_node("min", onnx.TensorProto.FLOAT, (), [0.0]), - make_constant_node("max", onnx.TensorProto.FLOAT, (), [6.0]), - ] - input_names = ["in", "min", "max"] - nodes.append(helper.make_node("Clip", inputs=input_names, outputs=["out"])) - graph = helper.make_graph( - nodes, - "clip_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(input_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(input_shape))], - ) - model = helper.make_model(graph, producer_name="clip_test") - - verify_with_ort(model, [input_shape], out_shape=[input_shape], target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_round(target, dev): - _test_onnx_op_elementwise(target, dev, (2, 4, 5, 6), np.round, {}, "float32", "Round", {}) - _test_onnx_op_elementwise( - target, dev, (2, 4, 5, 6), np.round, {}, "float64", "Round", {}, verify=False - ) # TODO: enable verification once ORT supports float64 - - -def _test_finite_ops(target, dev, inshape, outfunc, npargs, dtype, opname, kwargs): - indata = np.random.choice(a=[np.nan, np.inf, -np.inf, 0.5, 1.0, 0], size=inshape).astype(dtype) - - outdata = outfunc(indata, **npargs) - y = helper.make_node(opname, ["in"], ["out"], **kwargs) - - graph = helper.make_graph( - [y], - opname + "_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(indata.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.BOOL, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name=opname + "_test") - verify_with_ort_with_inputs( - model, [indata], [outdata.shape], dtype=dtype, target=target, dev=dev - ) - - -@tvm.testing.parametrize_targets -def test_isinf(target, dev): - _test_finite_ops(target, dev, (2, 4, 5, 6), np.isinf, {}, "float32", "IsInf", {}) - - -@tvm.testing.parametrize_targets -def test_isnan(target, dev): - """test_isnan""" - _test_finite_ops(target, dev, (2, 4, 5, 6), np.isnan, {}, "float32", "IsNaN", {}) - - -@tvm.testing.parametrize_targets -def test_gather_nd(target, dev): - """test_gather_nd""" - - def verify_gather_nd(in_shape, indices, out_shape, dtype="float32", batch_dims=0, opset=11): - x = np.random.uniform(size=in_shape).astype(dtype) - indices = np.array(indices, dtype="int64") - - y = helper.make_node("GatherND", ["in", "indices"], ["out"]) - - if opset >= 12: - batch_dims_attr = helper.make_attribute("batch_dims", batch_dims) - y.attribute.append(batch_dims_attr) - - graph = helper.make_graph( - [y], - "gather_test", - inputs=[ - helper.make_tensor_value_info( - "in", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], list(in_shape) - ), - helper.make_tensor_value_info("indices", TensorProto.INT64, list(indices.shape)), - ], - outputs=[ - helper.make_tensor_value_info( - "out", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], list(out_shape) - ) - ], - ) - model = helper.make_model(graph, producer_name="gather_test") - verify_with_ort_with_inputs( - model, [x, indices], [out_shape], opset=opset, target=target, dev=dev - ) - - verify_gather_nd([2, 2], [[0, 0], [1, 1]], [2], "int32") - verify_gather_nd([2, 2], [[1], [0]], [2, 2]) - verify_gather_nd([2, 2, 2], [[0, 1], [1, 0]], [2, 2]) - verify_gather_nd([2, 2, 2], [[[0, 1]], [[1, 0]]], [2, 1, 2]) - - if is_version_greater_than("1.6.0"): - verify_gather_nd([2, 2, 2], [[1], [0]], [2, 2], batch_dims=1, opset=12) - verify_gather_nd( - (3, 2, 2, 3, 4), - np.random.randint(low=0, high=2, size=(3, 2, 3), dtype="int64"), - (3, 2), - batch_dims=2, - opset=12, - ) - - -@tvm.testing.parametrize_targets -def test_onehot(target, dev): - """test_onehot""" - indices_shape = [10] - indices_array = np.random.randint(low=0, high=9, size=indices_shape, dtype="int32") - depth = 10 - values = np.asarray([0, 1]).astype("int32") - out_np = np.eye(depth)[indices_array.reshape(-1)] - - onehot_node = helper.make_node("OneHot", ["indices", "depth", "values"], ["out"]) - - graph = helper.make_graph( - [onehot_node], - "onehot_test", - inputs=[ - helper.make_tensor_value_info("indices", TensorProto.INT32, indices_shape), - helper.make_tensor_value_info("depth", TensorProto.INT32, [1]), - helper.make_tensor_value_info("values", TensorProto.INT32, values.shape), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.INT32, out_np.shape)], - ) - - model = helper.make_model(graph, producer_name="onehot_test") - - # TODO(jwfromm): Replace test against np with test against onnxrt once we update versions. - tvm_out = get_tvm_output_with_vm( - model, [indices_array, np.array([depth]).astype("int32"), values], target, dev - ) - tvm.testing.assert_allclose(out_np, tvm_out, rtol=1e-5, atol=1e-5) - - -@tvm.testing.parametrize_targets -def test_gemm(target, dev): - """test_gemm""" - - def verify_gemm(a_shape, b_shape, c_shape=None, freeze_params=False, dtype="float32"): - out_shape = [a_shape[0], b_shape[1]] - a_array = np.random.uniform(size=a_shape).astype(dtype) - b_array = np.random.uniform(size=b_shape).astype(dtype) - input_names = ["a", "b"] - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - input_nodes = [ - helper.make_tensor_value_info("a", ONNX_DTYPE, list(a_shape)), - helper.make_tensor_value_info("b", ONNX_DTYPE, list(b_shape)), - ] - input_values = [a_array, b_array] - if c_shape is not None: - c_array = np.random.uniform(size=c_shape).astype(dtype) - input_names.append("c") - input_nodes.append(helper.make_tensor_value_info("c", ONNX_DTYPE, list(c_shape))) - input_values.append(c_array) - - gemm_node = helper.make_node("Gemm", input_names, ["out"]) - - graph = helper.make_graph( - [gemm_node], - "gemm_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="gemm_test") - atol = 1e-5 - rtol = 1e-5 - if dtype == "float16": - atol = 1e-3 - rtol = 1e-3 - verify_with_ort_with_inputs( - model, - input_values, - freeze_params=freeze_params, - dtype=dtype, - atol=atol, - rtol=rtol, - target=target, - dev=dev, - ) - - verify_gemm(a_shape=(4, 3), b_shape=(3, 4)) - verify_gemm(a_shape=(4, 3), b_shape=(3, 4), c_shape=(4,)) - verify_gemm(a_shape=(4, 3), b_shape=(3, 4), c_shape=(4,), freeze_params=True) - verify_gemm(a_shape=(4, 3), b_shape=(3, 4), c_shape=(4,), freeze_params=True, dtype="float16") - - -@tvm.testing.parametrize_targets -def test_matmul(target, dev): - """test_matmul""" - - def test_one_matmul(a_shape, b_shape): - out_shape = np.matmul(np.zeros(a_shape), np.zeros(b_shape)).shape - - a_array = np.random.uniform(size=a_shape).astype("float32") - b_array = np.random.uniform(size=b_shape).astype("float32") - - mul_node = helper.make_node("MatMul", ["a", "b"], ["out"]) - - graph = helper.make_graph( - [mul_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="matmul_test") - verify_with_ort_with_inputs(model, [a_array, b_array], target=target, dev=dev) - - test_one_matmul((4, 3), (3, 4)) - test_one_matmul((3,), (3, 1)) - test_one_matmul((1, 3), (3,)) - test_one_matmul((3,), (3,)) - - -@tvm.testing.parametrize_targets -def test_batch_matmul(target, dev): - """test_batch_matmul""" - - def verify_batch_matmul(a_shape, b_shape, out_shape, convert_config=None): - a_array = np.random.uniform(size=a_shape).astype("float32") - b_array = np.random.uniform(size=b_shape).astype("float32") - - mul_node = helper.make_node("MatMul", ["a", "b"], ["out"]) - - graph = helper.make_graph( - [mul_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, out_shape)], - ) - - model = helper.make_model(graph, producer_name="matmul_test") - verify_with_ort_with_inputs( - model, - [a_array, b_array], - use_vm=True, - target=target, - dev=dev, - convert_config=convert_config, - ) - - verify_batch_matmul((2, 3, 4, 3), (2, 3, 3, 4), (2, 3, 4, 4)) - verify_batch_matmul((2, 4, 3), (3, 4), (2, 4, 4)) - verify_batch_matmul((2, 3, 4, 3), (3, 4), (2, 3, 4, 4)) - # Test implicit broadcasting. - verify_batch_matmul((5,), (5, 5, 4), (5, 4)) - verify_batch_matmul((5, 4, 5), (5,), (5, 4)) - verify_batch_matmul((4, 3), (2, 3, 4), (2, 4, 4)) - verify_batch_matmul((2, 4, 3), (1, 3, 4), (2, 4, 4)) - verify_batch_matmul((1, 4, 3), (2, 3, 4), (2, 4, 4)) - verify_batch_matmul((4, 32, 16), (16, 32), (4, 32, 32)) - verify_batch_matmul((4, 32, 16, 32), (32, 16), (4, 32, 16, 16)) - verify_batch_matmul((4, 32, 16, 32), (1, 32, 32, 16), (4, 32, 16, 16)) - verify_batch_matmul((4, 1, 16, 32), (1, 32, 32, 16), (4, 32, 16, 16)) - # Test transb=False - verify_batch_matmul( - (2, 3, 4, 3), - (2, 3, 3, 4), - (2, 3, 4, 4), - convert_config={"use_nt_batch_matmul": False}, - ) - - -@tvm.testing.parametrize_targets -def test_use_nt_batch_matmul(target, dev): - """test_use_nt_batch_matmul""" - a_shape = (2, 3, 4) - b_shape = (2, 4, 3) - out_shape = [2, 3, 3] - a_array = np.random.uniform(size=a_shape).astype("float32") - b_array = np.random.uniform(size=b_shape).astype("float32") - - for use_nt_batch_matmul in [True, False]: - mul_node = helper.make_node("MatMul", ["a", "b"], ["out"]) - - graph = helper.make_graph( - [mul_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="matmul_test") - _, shape_dict = get_input_data_shape_dict(model, [a_array, b_array]) - - mod, _ = relay.frontend.from_onnx( - model, shape_dict, convert_config={"use_nt_batch_matmul": use_nt_batch_matmul} - ) - has_transpose_op = "transpose" in str(mod) - # use_nt_batch_matmul implies, TVM converts qualified onnx `matmul` - # to `transpose(weight) + nn.batch_matmul_NT`, otherwise to `nn.batch_matmul` - assert has_transpose_op == use_nt_batch_matmul - - -@tvm.testing.parametrize_targets -def test_matmulinteger16(target, dev): - """test_matmulinteger16""" - - def verify_matmulinteger16(a_shape, b_shape, out_shape): - a_dtype = "int16" - b_dtype = "int16" - low = np.iinfo(np.int16).min - high = np.iinfo(np.int16).max - - a_proto = TensorProto.INT16 - b_proto = TensorProto.INT16 - out_proto = TensorProto.INT32 - a_array = np.random.randint(low, high, size=a_shape).astype(a_dtype) - b_array = np.random.randint(low, high, size=b_shape).astype(b_dtype) - - mul_node = helper.make_node("MatMulInteger16", ["a", "b"], ["out"], domain="com.microsoft") - - graph = helper.make_graph( - [mul_node], - "matmuli16_test", - inputs=[ - helper.make_tensor_value_info("a", a_proto, list(a_shape)), - helper.make_tensor_value_info("b", b_proto, list(b_shape)), - ], - outputs=[helper.make_tensor_value_info("out", out_proto, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="matmuli16_test") - verify_with_ort_with_inputs(model, [a_array, b_array], target=target, dev=dev) - - # 2D computation to verify matmul op - verify_matmulinteger16((4, 3), (3, 4), (4, 4)) - verify_matmulinteger16((5, 7), (7, 8), (5, 8)) - # Verify 3D matmul using batch_matmul op - verify_matmulinteger16((2, 4, 3), (1, 3, 4), (2, 4, 4)) - verify_matmulinteger16((1, 4, 3), (2, 3, 4), (2, 4, 4)) - # Test implicit broadcasting - verify_matmulinteger16((2, 3, 5, 3), (2, 3, 3, 5), (2, 3, 5, 5)) - verify_matmulinteger16((2, 7, 3), (3, 7), (2, 7, 7)) - verify_matmulinteger16((2, 3, 4, 3), (3, 4), (2, 3, 4, 4)) - - -def verify_simple_dynamic_model(a_shape, b_shape, target, dev): - """verify_simple_dynamic_model""" - - def verify_model(model, a_shape, b_shape): - a_array = np.random.uniform(size=a_shape).astype("float32") - b_array = np.random.uniform(size=b_shape).astype("float32") - # matmul - out_np = np.matmul(a_array, b_array) - # relu - out_np[out_np < 0] = 0 - - tvm_out = model(a_array, b_array).numpy() - tvm.testing.assert_allclose(out_np, tvm_out, rtol=1e-5, atol=1e-5) - - mul_node = helper.make_node("MatMul", ["a", "b"], ["out"]) - relu_node = helper.make_node("Relu", ["out"], ["relu"]) - - a_array = np.random.uniform(size=a_shape).astype("float32") - b_array = np.random.uniform(size=b_shape).astype("float32") - # matmul - out_np = np.matmul(a_array, b_array) - - graph = helper.make_graph( - [mul_node, relu_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ], - outputs=[helper.make_tensor_value_info("relu", TensorProto.FLOAT, list(out_np.shape))], - ) - - model = helper.make_model(graph, producer_name="matmul_test") - - a_anys = [relay.Any()] * len(a_shape) - b_anys = [relay.Any()] * len(b_shape) - - mod, _ = relay.frontend.from_onnx(model, {"a": a_anys, "b": b_anys}) - model = relay.create_executor("vm", mod=mod, device=dev, target=target).evaluate() - verify_model(model, a_shape, b_shape) - verify_model(model, [a * 2 for a in a_shape], [b * 2 for b in b_shape]) - verify_model(model, [a * 3 for a in a_shape], [b * 3 for b in b_shape]) - - -# TODO(mbrookhart, electriclilies): Add CUDA as a target once batch matmul is fixed -@tvm.testing.parametrize_targets("llvm") -def test_batch_matmul_dynamic_model(target, dev): - verify_simple_dynamic_model((2, 3, 4, 3), (2, 3, 3, 4), target, dev) - verify_simple_dynamic_model((2, 4, 3), (3, 4), target, dev) - verify_simple_dynamic_model((2, 3, 4, 3), (3, 4), target, dev) - - -@tvm.testing.parametrize_targets -def test_lrn(target, dev): - """test_lrn""" - - def verify_lrn(shape, nsize, dtype, alpha=None, beta=None, bias=None): - in_array = np.random.uniform(size=shape).astype(dtype) - - if alpha is None and beta is None and bias is None: - alpha = 0.0001 - beta = 0.75 - bias = 1.0 - node = onnx.helper.make_node("LRN", inputs=["in"], outputs=["out"], size=nsize) - else: - node = onnx.helper.make_node( - "LRN", inputs=["in"], outputs=["out"], alpha=alpha, beta=beta, bias=bias, size=nsize - ) - - graph = helper.make_graph( - [node], - "lrn_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(shape))], - ) - model = helper.make_model(graph, producer_name="lrn_test") - verify_with_ort_with_inputs(model, [in_array], target=target, dev=dev) - - verify_lrn((5, 5, 5, 5), 3, "float32") - verify_lrn((5, 5, 5, 5), 3, "float32", alpha=0.0002, beta=0.5, bias=2.0) - - -@tvm.testing.parametrize_targets -def test_instance_norm(target, dev): - """test_instance_norm""" - - def verify_instance_norm(shape, axis=1): - x = np.random.randn(*shape).astype(np.float32) - gamma = np.random.randn(shape[1]).astype(np.float32) - beta = np.random.randn(shape[1]).astype(np.float32) - epsilon = 1e-5 - - node = onnx.helper.make_node( - "InstanceNormalization", - inputs=["x", "gamma", "beta"], - outputs=["y"], - epsilon=epsilon, - ) - graph = helper.make_graph( - [node], - "instance_norm_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(shape)), - helper.make_tensor_value_info("gamma", TensorProto.FLOAT, (shape[1],)), - helper.make_tensor_value_info("beta", TensorProto.FLOAT, (shape[1],)), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(shape))], - ) - model = helper.make_model(graph, producer_name="instance_norm_test") - verify_with_ort_with_inputs( - model, [x, gamma, beta], out_shape=[shape], target=target, dev=dev - ) - - verify_instance_norm((2, 3, 4, 5)) - verify_instance_norm((32, 64, 80, 64)) - verify_instance_norm((8, 6, 5)) - verify_instance_norm((8, 7, 6, 5, 4)) - - -@tvm.testing.parametrize_targets -def test_upsample_nearest(target, dev): - """test_upsample_nearest""" - scale = 2 - in_shape = (1, 1, 3, 3) - out_shape = (1, 1, 3 * scale, 3 * scale) - y = helper.make_node("Upsample", ["in"], ["out"], mode="nearest", scales=[1.0, 1.0, 2.0, 2.0]) - - in_array = np.random.uniform(size=in_shape).astype(np.float32) - - graph = helper.make_graph( - [y], - "upsample_nearest_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="upsample_nearest_test") - verify_with_ort_with_inputs(model, [in_array], [out_shape], opset=7, target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_upsample_nearest_default(target, dev): - """test_upsample_nearest_default""" - scale = 2 - in_shape = (1, 1, 3, 3) - out_shape = (1, 1, 3 * scale, 3 * scale) - y = helper.make_node("Upsample", ["in"], ["out"], scales=[1.0, 1.0, 2.0, 2.0]) - - in_array = np.random.uniform(size=in_shape).astype(np.float32) - - graph = helper.make_graph( - [y], - "upsample_nearest_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="upsample_nearest_test") - verify_with_ort_with_inputs(model, [in_array], [out_shape], opset=7, target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_upsample3d_nearest(target, dev): - """test_upsample3d_nearest""" - scale = 2 - in_shape = (1, 1, 3, 3, 3) - out_shape = (1, 1, 3 * scale, 3 * scale, 3 * scale) - y = helper.make_node( - "Upsample", ["in"], ["out"], mode="nearest", scales=[1.0, 1.0, 2.0, 2.0, 2.0] - ) - - in_array = np.random.uniform(size=in_shape).astype(np.float32) - - graph = helper.make_graph( - [y], - "upsample_nearest_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="upsample_nearest_test") - # Upsample is deprecated after opset 9 - verify_with_ort_with_inputs(model, [in_array], [out_shape], opset=7, target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_upsample_bilinear(target, dev): - """test_upsample_bilinear""" - scale = 2 - in_shape = (1, 1, 3, 3) - out_shape = (1, 1, 3 * scale, 3 * scale) - y = helper.make_node("Upsample", ["in"], ["out"], mode="linear", scales=[1.0, 1.0, 2.0, 2.0]) - - in_array = np.random.uniform(size=in_shape).astype(np.float32) - - graph = helper.make_graph( - [y], - "upsample_bilinear_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="upsample_bilinear_test") - verify_with_ort_with_inputs(model, [in_array], [out_shape], opset=7, target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_upsample3d_trilinear(target, dev): - """test_upsample3d_trilinear""" - scale = 2 - in_shape = (1, 1, 3, 3, 3) - out_shape = (1, 1, 3 * scale, 3 * scale, 3 * scale) - y = helper.make_node("Upsample", ["in", "scales"], ["out"], mode="linear") - scales = [1.0, 1.0, 2.0, 2.0, 2.0] - in_array = np.random.uniform(size=in_shape).astype(np.float32) - out_array = tvm.topi.testing.resize3d_python( - in_array, - (scale, scale, scale), - "NCDHW", - "linear", - coordinate_transformation_mode="asymmetric", - ) - - ref_array = np.array(scales) - ref_node = helper.make_node( - "Constant", - inputs=[], - outputs=["scales"], - value=onnx.helper.make_tensor( - name="const_tensor", - data_type=TensorProto.FLOAT, - dims=ref_array.shape, - vals=ref_array.flatten().astype(float), - ), - ) - - graph = helper.make_graph( - [ref_node, y], - "upsample_trilinear_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(in_shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="upsample_trilinear_test") - # TODO(jwfromm): Trilinear upsampling not supported in 1.0.0 onnxruntime. - # Replace topi comparison with verify_with_ort once we update. - tvm_out = get_tvm_output(model, in_array, target, dev, out_shape, "float32") - tvm.testing.assert_allclose(out_array, tvm_out, rtol=1e-5, atol=1e-5) - - -# TODO: Fix softmax with dynamic input on cuda and enable this test -@tvm.testing.known_failing_targets("cuda") -@tvm.testing.parametrize_targets -def test_softmax(target, dev): - """test_softmax""" - - def verify_softmax(inshape, axis, opset=None, dynamic=False): - opname = "Softmax" - outshape = inshape - node_list = [] - input_node_list = [helper.make_tensor_value_info("in", TensorProto.FLOAT, list(inshape))] - output_node_list = [helper.make_tensor_value_info("out", TensorProto.FLOAT, list(outshape))] - input_list = [np.random.uniform(size=inshape).astype(np.float32)] - softmax_inputs = ["in"] - - if dynamic: - input_node_list.append( - helper.make_tensor_value_info("shape", TensorProto.INT64, [len(inshape)]) - ) - input_list.append(np.asarray(inshape)) - reshape_node = helper.make_node("Reshape", ["in", "shape"], ["dynamic_in"]) - softmax_inputs[0] = "dynamic_in" - node_list += [reshape_node] - - y = helper.make_node(opname, softmax_inputs, ["out"]) - if axis is not None: - axis_attr = helper.make_attribute("axis", axis) - y.attribute.append(axis_attr) - node_list.append(y) - - graph = helper.make_graph( - node_list, - opname + "_test", - inputs=input_node_list, - outputs=output_node_list, - ) - - model = helper.make_model(graph, producer_name=opname + "_test") - verify_with_ort_with_inputs( - model, input_list, use_vm=True, opset=opset, target=target, dev=dev - ) - - verify_softmax((1, 10), None) - verify_softmax((1, 10), 1) - verify_softmax((1, 2, 3, 10), 0) - verify_softmax((1, 2, 3, 10), 2) - verify_softmax((1, 2, 3, 4, 10), 3) - verify_softmax((1, 2, 3, 4, 10), 4) - verify_softmax((1, 10), -1, dynamic=True) - verify_softmax((1, 2, 3, 10), -1, dynamic=True) - verify_softmax((1, 10), -1, opset=8, dynamic=True) - verify_softmax((1, 2, 3, 10), -1, opset=8, dynamic=True) - - -@tvm.testing.parametrize_targets -def test_forward_min(target, dev): - """test_forward_min""" - - def verify_min(input_dim): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - a_np3 = np.random.uniform(size=input_dim).astype(dtype) - - min_node = helper.make_node("Min", ["a_np1", "a_np2", "a_np3"], ["out"]) - - graph = helper.make_graph( - [min_node], - "Min_test", - inputs=[ - helper.make_tensor_value_info("a_np1", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np2", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np3", TensorProto.FLOAT, list(input_dim)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(input_dim))], - ) - - model = helper.make_model(graph, producer_name="Min_test") - verify_with_ort_with_inputs(model, [a_np1, a_np2, a_np3], target=target, dev=dev) - - verify_min((1, 3, 20, 20)) - verify_min((20, 20)) - - -@tvm.testing.parametrize_targets -def test_forward_max(target, dev): - """test_forward_max""" - - def verify_max(input_dim): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - a_np3 = np.random.uniform(size=input_dim).astype(dtype) - - max_node = helper.make_node("Max", ["a_np1", "a_np2", "a_np3"], ["out"]) - - graph = helper.make_graph( - [max_node], - "Max_test", - inputs=[ - helper.make_tensor_value_info("a_np1", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np2", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np3", TensorProto.FLOAT, list(input_dim)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(input_dim))], - ) - - model = helper.make_model(graph, producer_name="Max_test") - verify_with_ort_with_inputs(model, [a_np1, a_np2, a_np3], target=target, dev=dev) - - verify_max((1, 3, 20, 20)) - verify_max((20, 20)) - - -@tvm.testing.parametrize_targets -def test_forward_mean(target, dev): - """test_forward_mean""" - - def verify_mean(input_dim): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - a_np2 = np.random.uniform(size=input_dim).astype(dtype) - a_np3 = np.random.uniform(size=input_dim).astype(dtype) - - mean_node = helper.make_node("Mean", ["a_np1", "a_np2", "a_np3"], ["out"]) - - graph = helper.make_graph( - [mean_node], - "Mean_test", - inputs=[ - helper.make_tensor_value_info("a_np1", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np2", TensorProto.FLOAT, list(input_dim)), - helper.make_tensor_value_info("a_np3", TensorProto.FLOAT, list(input_dim)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(input_dim))], - ) - - model = helper.make_model(graph, producer_name="Mean_test") - verify_with_ort_with_inputs(model, [a_np1, a_np2, a_np3], target=target, dev=dev) - - verify_mean((1, 3, 20, 20)) - verify_mean((20, 20)) - - -@tvm.testing.parametrize_targets -def test_forward_hardsigmoid(target, dev): - """test_forward_hardsigmoid""" - - def verify_hardsigmoid(input_dim, alpha, beta): - dtype = "float32" - - a_np1 = np.random.uniform(size=input_dim).astype(dtype) - - hardsigmoid_node = helper.make_node( - "HardSigmoid", ["a_np1"], ["out"], alpha=alpha, beta=beta - ) - - graph = helper.make_graph( - [hardsigmoid_node], - "HardSigmoid_test", - inputs=[helper.make_tensor_value_info("a_np1", TensorProto.FLOAT, list(input_dim))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(input_dim))], - ) - - model = helper.make_model(graph, producer_name="HardSigmoid_test") - verify_with_ort_with_inputs(model, [a_np1], target=target, dev=dev) - - verify_hardsigmoid((1, 3, 20, 20), 0.5, 0.6) - verify_hardsigmoid((20, 20), 0.3, 0.4) - - -# TODO (mbrookhart, electriclilies) Fix argmin on GPU and enable this test -@tvm.testing.known_failing_targets("cuda") -@tvm.testing.parametrize_targets -def test_forward_arg_min_max(target, dev): - """test_forward_arg_min_max""" - - def verify_argreduce(input_dim, op_name, axis=None, keepdims=None): - a_np1 = np.random.uniform(-10, 10, input_dim).astype(np.int32) - out_shape = list(a_np1.shape) - def_axis = axis if axis is not None else 0 - if keepdims == 1 or keepdims is None: - out_shape[def_axis] = 1 - else: - out_shape.pop(def_axis) - - node = onnx.helper.make_node(op_name, inputs=["a_np1"], outputs=["out"]) - - if keepdims is not None: - keepdims_attr = helper.make_attribute("keepdims", keepdims) - node.attribute.append(keepdims_attr) - if axis is not None: - axis_attr = helper.make_attribute("axis", axis) - node.attribute.append(axis_attr) - - graph = helper.make_graph( - [node], - "argreduce_test", - inputs=[helper.make_tensor_value_info("a_np1", TensorProto.INT32, list(a_np1.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.INT64, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="argreduce_test") - verify_with_ort_with_inputs(model, [a_np1], target=target, dev=dev) - - # Verify argmin and argmax - verify_argreduce([3, 4, 4], "ArgMin") - verify_argreduce([3, 4, 4], "ArgMax") - verify_argreduce([3, 4, 4], "ArgMin", axis=1) - verify_argreduce([3, 4, 4], "ArgMax", axis=0) - verify_argreduce([3, 4, 4], "ArgMin", keepdims=0) - verify_argreduce([3, 4, 4], "ArgMax", keepdims=1) - for axis in [None, 0, 1, 2]: - for keepdims in [None, True, False]: - verify_argreduce([3, 4, 4], "ArgMin", axis, keepdims) - verify_argreduce([3, 4, 4], "ArgMax", axis, keepdims) - - -@tvm.testing.parametrize_targets -def test_constantofshape(target, dev): - """test_constantofshape""" - - def verify_constantofshape(input_dim, value, dtype): - fill_node = helper.make_node( - "ConstantOfShape", - ["input"], - ["output"], - value=helper.make_tensor( - "value", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], (1,), (value,) - ), - ) - - inputs = [helper.make_tensor_value_info("input", TensorProto.INT64, [len(input_dim)])] - - graph = helper.make_graph( - [fill_node], - "fill_test", - inputs, - outputs=[ - helper.make_tensor_value_info( - "output", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)], input_dim - ) - ], - ) - - model = helper.make_model(graph, producer_name="fill_test") - input_np = np.array(input_dim).astype("int64") - verify_with_ort_with_inputs(model, [input_np], use_vm=True, target=target, dev=dev) - - verify_constantofshape((2, 3, 4, 5), 10, "float32") - verify_constantofshape((3, 3), 0, "int32") - verify_constantofshape((1, 2, 3), -1, "float32") - - -@tvm.testing.parametrize_targets -def test_pad(target, dev): - """test_pad""" - - def verify_pad(indata, pads, mode="constant", value=0.0): - indata = np.array(indata).astype(np.float32) - # numpy expect result - len_dim = len(pads) // 2 - np_pads = [(pads[i], pads[i + len_dim]) for i in range(len_dim)] - # onnx graph - if mode in ["edge", "reflect"]: - outdata = np.pad(indata, pad_width=np_pads, mode=mode) - node = helper.make_node( - "Pad", - inputs=["input"], - outputs=["output"], - mode=mode, - pads=pads, - ) - else: - outdata = np.pad(indata, pad_width=np_pads, mode="constant", constant_values=value) - node = helper.make_node( - "Pad", inputs=["input"], outputs=["output"], mode="constant", pads=pads, value=value - ) - graph = helper.make_graph( - [node], - "pad_test", - inputs=[helper.make_tensor_value_info("input", TensorProto.FLOAT, list(indata.shape))], - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(outdata.shape)) - ], - ) - model = helper.make_model(graph, producer_name="pad_test") - verify_with_ort_with_inputs( - model, [indata], [outdata.shape], dtype="float32", opset=2, target=target, dev=dev - ) - - def verify_pad_v11(indata, pads, mode="constant", value=0.0): - indata = np.array(indata).astype(np.float32) - # numpy expect result - len_dim = len(pads) // 2 - np_pads = [(pads[i], pads[i + len_dim]) for i in range(len_dim)] - pads = np.array(pads) - # onnx graph - if mode in ["edge", "reflect"]: - inputs = [indata] - outdata = np.pad(indata, pad_width=np_pads, mode=mode) - node = helper.make_node("Pad", inputs=["input", "pads"], outputs=["output"], mode=mode) - graph = helper.make_graph( - [node], - "pad_test", - inputs=[ - helper.make_tensor_value_info("input", TensorProto.FLOAT, list(indata.shape)), - helper.make_tensor_value_info("pads", TensorProto.INT64, (len(pads),)), - ], - initializer=[helper.make_tensor("pads", TensorProto.INT64, (len(pads),), pads)], - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(outdata.shape)) - ], - ) - else: - inputs = [indata] - outdata = np.pad(indata, pad_width=np_pads, mode="constant", constant_values=value) - node = helper.make_node( - "Pad", - inputs=["input", "pads", "constant_value"], - outputs=["output"], - mode="constant", - ) - graph = helper.make_graph( - [node], - "pad_test", - inputs=[ - helper.make_tensor_value_info("input", TensorProto.FLOAT, list(indata.shape)), - helper.make_tensor_value_info("pads", TensorProto.INT64, (len(pads),)), - helper.make_tensor_value_info("constant_value", TensorProto.FLOAT, (1,)), - ], - initializer=[ - helper.make_tensor("pads", TensorProto.INT64, (len(pads),), pads), - helper.make_tensor("constant_value", TensorProto.FLOAT, (1,), [value]), - ], - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(outdata.shape)) - ], - ) - model = helper.make_model(graph, producer_name="pad_test") - verify_with_ort_with_inputs(model, inputs, opset=11, use_vm=True, target=target, dev=dev) - - verify_pad(np.random.randn(2, 2).astype(np.float32), [0, 1, 0, 0], "constant", 0.0) - verify_pad(np.random.randn(2, 3).astype(np.float32), [1, 0, 0, 1], "constant", 0.0) - verify_pad(np.random.randn(3, 2).astype(np.float32), [0, 0, 1, 0], "constant", 5.0) - verify_pad(np.random.randn(1, 3, 4, 5).astype(np.float32), [0, 0, 1, 1, 0, 0, 1, 1], "edge") - verify_pad(np.random.randn(1, 3, 4, 5).astype(np.float32), [0, 0, 1, 1, 0, 0, 1, 1], "reflect") - - verify_pad_v11(np.random.randn(2, 2).astype(np.float32), [0, 1, 0, 0], "constant", 0.0) - verify_pad_v11(np.random.randn(2, 3).astype(np.float32), [1, 0, 0, 1], "constant", 0.0) - verify_pad_v11(np.random.randn(3, 2).astype(np.float32), [0, 0, 1, 0], "constant", 5.0) - verify_pad_v11(np.random.randn(1, 3, 4, 5).astype(np.float32), [0, 0, 1, 1, 0, 0, 1, 1], "edge") - verify_pad_v11( - np.random.randn(1, 3, 4, 5).astype(np.float32), [0, 0, 1, 1, 0, 0, 1, 1], "reflect" - ) - - -@tvm.testing.parametrize_targets -def test_all_reduce_funcs(target, dev): - """test_all_reduce_funcs""" - - def verify_reduce_func(func, data, axis, keepdims): - inshape = data.shape - outshape = np.sum(data, axis=axis, keepdims=keepdims == 1).shape - - if axis: - node = onnx.helper.make_node( - func, inputs=["x"], outputs=["y"], axes=axis, keepdims=keepdims - ) - else: - node = onnx.helper.make_node(func, inputs=["x"], outputs=["y"], keepdims=keepdims) - - graph = helper.make_graph( - [node], - "reduce_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(inshape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(outshape))], - ) - - model = helper.make_model(graph, producer_name="reduce_test") - - verify_with_ort_with_inputs( - model, - [data], - [outshape], - opset=11, - target=target, - dev=dev, - rtol=1e-4, - atol=1e-4, - ) - - funcs = [ - "ReduceMax", - "ReduceMean", - "ReduceMin", - "ReduceProd", - "ReduceSum", - "ReduceSumSquare", - "ReduceLogSum", - "ReduceLogSumExp", - "ReduceL1", - "ReduceL2", - ] - - for func in funcs: - verify_reduce_func(func, np.array(1.0).astype(np.float32), axis=None, keepdims=False) - - for keepdims in [True, False]: - verify_reduce_func( - func, np.random.randn(3, 2, 2).astype(np.float32), axis=None, keepdims=keepdims - ) - - verify_reduce_func( - func, np.random.randn(3, 2, 3).astype(np.float32), axis=None, keepdims=keepdims - ) - - verify_reduce_func( - func, np.random.randn(3, 3, 3).astype(np.float32), axis=(1,), keepdims=keepdims - ) - - verify_reduce_func( - func, np.random.randn(3, 3, 3, 1).astype(np.float32), axis=(1, 2), keepdims=keepdims - ) - - verify_reduce_func( - func, np.random.randn(3, 3, 3, 1).astype(np.float32), axis=(1,), keepdims=keepdims - ) - - verify_reduce_func( - func, np.random.randn(1, 3, 4, 1).astype(np.float32), axis=(1,), keepdims=keepdims - ) - - -@tvm.testing.parametrize_targets -def test_split(target, dev): - """test_split""" - - def verify_split(indata, outdatas, split, axis=0, pass_split=True, opset=11): - indata = np.array(indata).astype(np.float32) - outdatas = [np.array(o).astype(np.float32) for o in outdatas] - inputs = [helper.make_tensor_value_info("input", TensorProto.FLOAT, list(indata.shape))] - input_names = ["input"] - initializer = [] - - if split: - split_index = range(len(split)) - else: - split_index = range(len(outdatas)) - - if pass_split: - if opset >= 13: - input_names.append("split") - np_split = np.array(split).astype(np.int64) - inputs.append( - helper.make_tensor_value_info("split", TensorProto.INT64, list(np_split.shape)) - ) - # TODO(mbrookhart): Support dynamic split, edit this test case to remove split from - # the initializer and add it back to the input data - indata = [indata] # , np_split] - initializer.append( - helper.make_tensor("split", TensorProto.INT64, list(np_split.shape), np_split) - ) - node = helper.make_node( - "Split", - inputs=input_names, - outputs=[f"output_{i}" for i in range(len(split_index))], - axis=axis, - ) - - if pass_split and opset < 13: - split_attr = helper.make_attribute("split", split) - node.attribute.append(split_attr) - - graph = helper.make_graph( - [node], - "split_test", - inputs=inputs, - initializer=initializer, - outputs=[ - helper.make_tensor_value_info( - f"output_{i}", TensorProto.FLOAT, list(outdatas[i].shape) - ) - for i in range(len(split_index)) - ], - ) - model = helper.make_model(graph, producer_name="split_test") - verify_with_ort_with_inputs( - model, - indata, - out_shape=list(range(len(split_index))), - opset=opset, - target=target, - dev=dev, - use_vm=True, - freeze_params=(opset >= 13), - ) - - # 1D - verify_split([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], [2, 2, 2], 0) - verify_split( - [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], [2, 2, 2], 0, False - ) - verify_split([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [[1.0, 2.0], [3.0], [4.0, 5.0, 6.0]], [2, 1, 3], 0) - verify_split( - [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [[1.0, 2.0], [3.0], [4.0, 5.0, 6.0]], [2, 1, 3], 0, opset=13 - ) - # 2D - verify_split( - [[1.0, 2.0, 3.0, 4.0], [7.0, 8.0, 9.0, 10.0]], - [[[1.0, 2.0], [7.0, 8.0]], [[3.0, 4.0], [9.0, 10.0]]], - [2, 2], - 1, - ) - verify_split( - [[1.0, 2.0, 3.0, 4.0], [7.0, 8.0, 9.0, 10.0]], - [[[1.0, 2.0], [7.0, 8.0]], [[3.0, 4.0], [9.0, 10.0]]], - [2, 2], - 1, - opset=13, - ) - # Split evenly (unstack) - verify_split([1, 2, 3], [[1], [2], [3]], False, 0, False) - # Split a single value to a single value - verify_split([1], [[1]], [1], pass_split=True) - # Test that the default case modifies nothing when split list has length one - verify_split([[1.0, 2.0]], [[1.0, 2.0]], [2], 1) - verify_split([[1.0, 2.0]], [[1.0, 2.0]], [1], 0) - - -@tvm.testing.parametrize_targets -def test_binary_ops(target, dev): - """test_binary_ops""" - in_shape = (1, 2, 3, 3) - dtype = "float32" - out_shape = in_shape - - def verify_binary_ops(op, x, y, out_type="float32"): - out = helper.make_node(op, ["in1", "in2"], ["out"]) - graph = helper.make_graph( - [out], - "_test", - inputs=[ - helper.make_tensor_value_info("in1", TensorProto.FLOAT, x.shape), - helper.make_tensor_value_info("in2", TensorProto.FLOAT, y.shape), - ], - outputs=[ - helper.make_tensor_value_info( - "out", mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(out_type)], list(out_shape) - ) - ], - ) - model = helper.make_model(graph, producer_name="_test") - verify_with_ort_with_inputs(model, [x, y], target=target, dev=dev) - - x = np.random.uniform(size=in_shape).astype(dtype) - y = np.random.uniform(size=in_shape).astype(dtype) - z_array = np.random.uniform(size=(3,)).astype(dtype) - verify_binary_ops("Add", x, y) - verify_binary_ops("Add", x, z_array) - verify_binary_ops("Sub", x, y) - verify_binary_ops("Sub", x, z_array) - verify_binary_ops("Mul", x, y) - verify_binary_ops("Mul", x, z_array) - verify_binary_ops("Div", x, y) - verify_binary_ops("Div", x, z_array) - verify_binary_ops("Sum", x, y) - verify_binary_ops("Sum", x, z_array) - verify_binary_ops("Greater", x, y, "bool") - verify_binary_ops("Greater", x, z_array, "bool") - verify_binary_ops("GreaterOrEqual", x, y, "bool") - verify_binary_ops("GreaterOrEqual", x, z_array, "bool") - verify_binary_ops("Less", x, y, "bool") - verify_binary_ops("Less", x, z_array, "bool") - verify_binary_ops("LessOrEqual", x, y, "bool") - verify_binary_ops("LessOrEqual", x, z_array, "bool") - verify_binary_ops("Equal", x, y, "bool") - verify_binary_ops("Equal", x, z_array, "bool") - - -@tvm.testing.parametrize_targets -def test_unary_ops(target, dev): - """test_unary_ops""" - in_shape = (1, 2, 3, 3) - _ = "float32" - out_shape = in_shape - - def verify_unary_ops(op, x, rtol=1e-5, atol=1e-5, dtype="float32"): - x = x.astype(dtype) - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - out = helper.make_node(op, ["in1"], ["out"]) - graph = helper.make_graph( - [out], - "_test", - inputs=[ - helper.make_tensor_value_info("in1", ONNX_DTYPE, list(in_shape)), - ], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, list(out_shape))], - ) - model = helper.make_model(graph, producer_name="_test") - verify_with_ort_with_inputs(model, [x], rtol=rtol, atol=atol, target=target, dev=dev) - - x = np.random.uniform(size=in_shape) - verify_unary_ops("Neg", x) - verify_unary_ops("Abs", x) - verify_unary_ops("Reciprocal", x) - verify_unary_ops("Reciprocal", x, dtype="float16") - verify_unary_ops("Sqrt", x) - verify_unary_ops("Relu", x) - verify_unary_ops("Exp", x) - verify_unary_ops("Log", x) - verify_unary_ops("Log", x) - verify_unary_ops("Acos", x) - verify_unary_ops("Acosh", x) - verify_unary_ops("Asin", x) - verify_unary_ops("Asinh", x) - verify_unary_ops("Atan", x) - verify_unary_ops("Atanh", x) - verify_unary_ops("Cos", x) - verify_unary_ops("Cosh", x) - verify_unary_ops("Sin", x) - verify_unary_ops("Sinh", x) - verify_unary_ops("Tan", x) - verify_unary_ops("Tanh", x) - verify_unary_ops("Sigmoid", x) - verify_unary_ops("Softsign", x) - - -@tvm.testing.parametrize_targets -def test_leaky_relu(target, dev): - def leaky_relu_x(x, alpha): - return np.where(x >= 0, x, x * alpha) - - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - leaky_relu_x, - {"alpha": 0.25}, - "float32", - "LeakyRelu", - {"alpha": 0.25}, - ) - - -@tvm.testing.parametrize_targets -def test_elu(target, dev): - def elu_x(x, alpha): - return np.where(x > 0, x, alpha * (np.exp(x) - 1.0)) - - _test_onnx_op_elementwise( - target, dev, (2, 4, 5, 6), elu_x, {"alpha": 0.25}, "float32", "Elu", {"alpha": 0.25} - ) - - -@tvm.testing.parametrize_targets -def test_selu(target, dev): - def selu_x(x, alpha, gamma): - return gamma * np.where(x > 0, x, alpha * (np.exp(x) - 1.0)) - - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - selu_x, - {"alpha": 0.25, "gamma": 0.3}, - "float32", - "Selu", - {"alpha": 0.25, "gamma": 0.3}, - ) - - -@pytest.mark.skip("Currently ONNX Runtime in CI does not support domain version of 18") -@tvm.testing.parametrize_targets -def test_mish(target, dev): - def mish_x(x): - return x * np.tanh(np.log1p(np.exp(x))) - - _test_onnx_op_elementwise(target, dev, (2, 4, 5, 6), mish_x, {}, "float64", "Mish", {}) - - -@tvm.testing.parametrize_targets -def test_prelu(target, dev): - """test_prelu""" - - def verify_prelu(x_shape, a_shape): - node = helper.make_node("PRelu", inputs=["X", "slope"], outputs=["Y"]) - - graph = helper.make_graph( - [node], - "prelu_test", - inputs=[ - helper.make_tensor_value_info("X", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("slope", TensorProto.FLOAT, list(a_shape)), - ], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(x_shape))], - ) - - model = helper.make_model(graph, producer_name="prelu_test") - - verify_with_ort( - model, - [x_shape, a_shape], - out_shape=[list(x_shape)], - use_vm=True, - target=target, - dev=dev, - ) - - verify_prelu([3, 4, 5, 6], [1, 4, 1, 1]) - verify_prelu([1, 8, 5, 6], [1, 8, 1, 1]) - verify_prelu([2, 12, 16, 16], [1, 12, 1, 1]) - verify_prelu([2, 12, 16, 16], [1]) # Test alpha broadcasting. - verify_prelu([3, 1], [3, 1]) # Test non NCHW workload. - - -@tvm.testing.parametrize_targets -def test_thresholded_relu(target, dev): - def thresholded_relu_x(x, alpha): - out_np = np.clip(x, alpha, np.inf) - out_np[out_np == alpha] = 0 - return out_np - - _test_onnx_op_elementwise( - target, - dev, - (2, 4, 5, 6), - thresholded_relu_x, - {"alpha": 0.25}, - "float32", - "ThresholdedRelu", - {"alpha": 0.25}, - ) - - -@tvm.testing.parametrize_targets -def test_logsoftmax(target, dev): - _test_onnx_op_elementwise( - target, - dev, - (1, 4), - tvm.topi.testing.log_softmax_python, - {}, - "float32", - "LogSoftmax", - {"axis": 1}, - ) - - -def check_torch_conversion(model, input_size, target, dev): - dummy_input = torch.randn(*input_size) - file_name = f"{model.__name__}.onnx" - # Set verbose=True for more output - torch.onnx.export(model(), dummy_input, file_name, export_params=True, verbose=False) - onnx_model = onnx.load(file_name) - input_data = np.random.uniform(size=input_size).astype("float32") - verify_with_ort_with_inputs( - onnx_model, [input_data], apply_softmax=True, target=target, dev=dev - ) - - -@tvm.testing.parametrize_targets -def test_resnet(target, dev): - check_torch_conversion(torchvision.models.resnet18, (1, 3, 224, 224), target, dev) - # check_torch_conversion(torchvision.models.resnet101, (1,3,224,224)) - - -# def test_alexnet(): -# Torch's ONNX export does not support the adaptive pooling used by AlexNet? -# check_torch_conversion(torchvision.models.alexnet, (1,3,224,224)) - -# Torch's ONNX export does not support the adaptive pooling used by vgg16? -# def test_vgg16(): -# check_torch_conversion(torchvision.models.vgg16, (1,3,224,224)) - -# TODO(@jroesch): Update Torch + ONNX to support this import. -# def test_squeezenet(): -# # Torch's ONNX export does not support the max pooling used by Squezenet -# check_torch_conversion(torchvision.models.squeezenet1_0, (1,3,224,224)) - - -@tvm.testing.parametrize_targets -def test_densenet(target, dev): - check_torch_conversion(torchvision.models.densenet161, (1, 3, 224, 224), target, dev) - - -@tvm.testing.parametrize_targets -def test_inception(target, dev): - check_torch_conversion(torchvision.models.inception_v3, (1, 3, 224, 224), target, dev) - - -# TODO(@jroesch): Update Torch + ONNX to support this import. -# def test_googlenet(): -# check_torch_conversion(torchvision.models.googlenet, (1,3,224,224)) - -# TODO(@jroesch): Update Torch + ONNX to support this import. -# def test_shufflenetv2(): -# check_torch_conversion(torchvision.models.shufflenetv2, (1,3,224,224)) - - -@tvm.testing.parametrize_targets -def test_sign(target, dev): - def sign_x(x): - return np.sign(x) - - _test_onnx_op_elementwise(target, dev, (3, 4, 5, 6), sign_x, {}, "float32", "Sign", {}) - - -@tvm.testing.parametrize_targets -def test_not(target, dev): - """test_not""" - - def verify_not(indata, dtype): - x = indata.astype(dtype) - - node = helper.make_node( - "Not", - inputs=["in"], - outputs=["out"], - ) - - graph = helper.make_graph( - [node], - "not_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.BOOL, list(x.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.BOOL, list(x.shape))], - ) - - model = helper.make_model(graph, producer_name="not_test") - verify_with_ort_with_inputs(model, [x], target=target, dev=dev) - - # 2d - verify_not(indata=(np.random.randn(3, 4) > 0), dtype=bool) - # 3d - verify_not(indata=(np.random.randn(3, 4, 5) > 0), dtype=bool) - # 4d - verify_not(indata=(np.random.randn(3, 4, 5, 6) > 0), dtype=bool) - - -@tvm.testing.parametrize_targets -def test_and(target, dev): - """test_and""" - - def verify_and(indata, dtype): - x = indata[0].astype(dtype) - y = indata[1].astype(dtype) - outdata = np.logical_and(x, y) - - node = helper.make_node( - "And", - inputs=["in1", "in2"], - outputs=["out"], - ) - - graph = helper.make_graph( - [node], - "and_test", - inputs=[ - helper.make_tensor_value_info("in1", TensorProto.BOOL, list(x.shape)), - helper.make_tensor_value_info("in2", TensorProto.BOOL, list(y.shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.BOOL, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name="and_test") - verify_with_ort_with_inputs(model, [x, y], [outdata.shape], target=target, dev=dev) - - # 2d - x = np.random.randn(3, 4) > 0 - y = np.random.randn(3, 4) > 0 - verify_and(indata=[x, y], dtype=bool) - - # 3d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(3, 4, 5) > 0 - verify_and(indata=[x, y], dtype=bool) - - # 4d - x = np.random.randn(3, 4, 5, 6) > 0 - y = np.random.randn(3, 4, 5, 6) > 0 - verify_and(indata=[x, y], dtype=bool) - - # 3d vs 1d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(5) > 0 - verify_and(indata=[x, y], dtype=bool) - - # 3d vs 2d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(4, 5) > 0 - verify_and(indata=[x, y], dtype=bool) - - -@tvm.testing.parametrize_targets -def test_tile(target, dev): - """test_tile""" - - def verify_tile_v6(indata, repeats, outdata): - node = helper.make_node("Tile", inputs=["input", "repeats"], outputs=["out"]) - graph = helper.make_graph( - [node], - "tile_test", - inputs=[ - helper.make_tensor_value_info("input", TensorProto.FLOAT, list(indata.shape)), - helper.make_tensor_value_info("repeats", TensorProto.INT64, list(repeats.shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name="tile_test") - verify_with_ort_with_inputs( - model, [indata, repeats], use_vm=True, opset=6, target=target, dev=dev - ) - - x = np.random.rand(2, 3, 4, 5).astype(np.float32) - repeats = np.random.randint(low=1, high=10, size=(np.ndim(x),)).astype(np.int64) - z_array = np.tile(x, repeats) - verify_tile_v6(x, repeats, z_array) - - -@tvm.testing.parametrize_targets -def test_erf(target, dev): - """test_erf""" - - def verify_erf(indata, outdata): - node = helper.make_node("Erf", inputs=["in"], outputs=["out"]) - graph = helper.make_graph( - [node], - "erf_test", - inputs=[helper.make_tensor_value_info("in", TensorProto.FLOAT, list(indata.shape))], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(outdata.shape))], - ) - model = helper.make_model(graph, producer_name="erf_test") - verify_with_ort_with_inputs(model, [indata], [outdata.shape], target=target, dev=dev) - - x = np.random.rand(2, 3, 4, 6).astype(np.float32) - z_array = scipy.special.erf(x) - verify_erf(x, z_array) - - -@tvm.testing.parametrize_targets -def test_where(target, dev): - """test_where""" - - def verify_where(condition, x, y, dtype, outdata, dynamic=False): - node_list = [] - where_inputs = ["condition", "x", "y"] - if dynamic: - shape_node = helper.make_node("Shape", ["x"], ["shape"]) - reshape_node = helper.make_node("Reshape", ["x", "shape"], ["X"]) - where_inputs[1] = "X" - node_list += [shape_node, reshape_node] - node = helper.make_node("Where", inputs=where_inputs, outputs=["out"]) - node_list.append(node) - graph = helper.make_graph( - node_list, - "where_test", - inputs=[ - helper.make_tensor_value_info("condition", TensorProto.BOOL, list(condition.shape)), - helper.make_tensor_value_info("x", dtype, list(x.shape)), - helper.make_tensor_value_info("y", dtype, list(y.shape)), - ], - outputs=[helper.make_tensor_value_info("out", dtype, list(outdata.shape))], - ) - model = helper.make_model(graph, producer_name="where_test") - verify_with_ort_with_inputs( - model, [condition, x, y], [outdata.shape], use_vm=True, target=target, dev=dev - ) - - condition = np.array([[1, 0], [1, 1]], dtype=bool) - x = np.array([[1, 2], [3, 4]], dtype=np.int64) - y = np.array([[9, 8], [7, 6]], dtype=np.int64) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.INT64, outdata) - - x = np.array([[1, 2], [3, 4]], dtype=np.float32) - y = np.array([[9, 8], [7, 6]], dtype=np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - - x = np.array(1, dtype=np.float32) - y = np.array([2], dtype=np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - - x = np.array([2], dtype=np.float32) - y = np.array(1, dtype=np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - - condition = np.array(1, dtype=bool) - x = np.array([[1, 2], [3, 4]], dtype=np.float32) - y = np.array([[5, 6], [7, 8]], dtype=np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - - x = np.array([[1, 2], [3, 4]], dtype=np.float32) - y = np.array([[1], [7]], dtype=np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - verify_where(condition, x, y, TensorProto.FLOAT, outdata, dynamic=True) - - condition = np.random.uniform(size=(3, 1)) < 0.5 - x = np.random.uniform(size=2).astype(np.float32) - y = np.random.uniform(size=2).astype(np.float32) - outdata = np.where(condition, x, y) - verify_where(condition, x, y, TensorProto.FLOAT, outdata) - - -@tvm.testing.parametrize_targets -def test_or(target, dev): - """test_or""" - - def verify_or(indata, dtype): - x = indata[0].astype(dtype) - y = indata[1].astype(dtype) - outdata = np.logical_or(x, y) - - node = helper.make_node( - "Or", - inputs=["in1", "in2"], - outputs=["out"], - ) - - graph = helper.make_graph( - [node], - "or_test", - inputs=[ - helper.make_tensor_value_info("in1", TensorProto.BOOL, list(x.shape)), - helper.make_tensor_value_info("in2", TensorProto.BOOL, list(y.shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.BOOL, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name="or_test") - verify_with_ort_with_inputs(model, [x, y], [outdata.shape], target=target, dev=dev) - - # 2d - x = np.random.randn(3, 4) > 0 - y = np.random.randn(3, 4) > 0 - verify_or(indata=[x, y], dtype=bool) - - # 3d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(3, 4, 5) > 0 - verify_or(indata=[x, y], dtype=bool) - - # 4d - x = np.random.randn(3, 4, 5, 6) > 0 - y = np.random.randn(3, 4, 5, 6) > 0 - verify_or(indata=[x, y], dtype=bool) - - # 3d vs 1d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(5) > 0 - verify_or(indata=[x, y], dtype=bool) - - # 3d vs 2d - x = np.random.randn(3, 4, 5) > 0 - y = np.random.randn(4, 5) > 0 - verify_or(indata=[x, y], dtype=bool) - - -@tvm.testing.parametrize_targets -def test_batch_norm(target, dev): - """test_batch_norm""" - - def verify_batch_norm(in_shape): - batchnorm = onnx.helper.make_node( - "BatchNormalization", inputs=["x", "scale", "B", "mean", "var"], outputs=["Y"] - ) - - graph = helper.make_graph( - [batchnorm], - "batchnorm_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(in_shape)), - helper.make_tensor_value_info("scale", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("B", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("mean", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("var", TensorProto.FLOAT, [in_shape[1]]), - ], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(in_shape))], - ) - - model = helper.make_model(graph, producer_name="batchnorm_test") - # X, scale, b, mean, var - inshapes = [in_shape, in_shape[1], in_shape[1], in_shape[1], in_shape[1]] - verify_with_ort(model, inshapes, out_shape=[in_shape], target=target, dev=dev) - - verify_batch_norm([1, 3, 224, 224]) - verify_batch_norm([1, 3, 24, 24]) - verify_batch_norm([16, 3, 24, 24]) - verify_batch_norm([16, 16, 24, 24]) - verify_batch_norm([16, 16, 10, 10]) - - -@tvm.testing.parametrize_targets -def test_batch_norm_dynamic_subgraph(target, dev): - """test_batch_norm_dynamic_subgraph""" - - def verify_batch_norm_dynamic_subgraph(in_shape, o_shape): - - batchnorm = onnx.helper.make_node( - "BatchNormalization", inputs=["x", "scale", "B", "mean", "var"], outputs=["Y"] - ) - - shape_node = helper.make_node("Shape", ["Y"], ["shape"]) - reshape_node = helper.make_node("Reshape", ["in", "shape"], ["out"]) - graph = helper.make_graph( - [batchnorm, shape_node, reshape_node], - "batchnorm_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(in_shape)), - helper.make_tensor_value_info("in", TensorProto.FLOAT, list(o_shape)), - helper.make_tensor_value_info("scale", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("B", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("mean", TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info("var", TensorProto.FLOAT, [in_shape[1]]), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, list(in_shape))], - ) - - model = helper.make_model(graph, producer_name="batchnorm_test") - - # X, inp, scale, b, mean, var - inshapes = [in_shape, o_shape, in_shape[1], in_shape[1], in_shape[1], in_shape[1]] - verify_with_ort(model, inshapes, out_shape=[in_shape], use_vm=True, target=target, dev=dev) - - verify_batch_norm_dynamic_subgraph([16, 16, 10, 10], [160, 160]) - - -@tvm.testing.parametrize_targets -def test_conv(target, dev): - """test_conv""" - - def verify_conv( - x_shape, - w_shape, - y_shape, - padding, - kernel_shape, - strides, - dilations, - group=1, - auto_pad="NOTSET", - unset_pad=False, - ): - if unset_pad: - node = helper.make_node( - "Conv", - inputs=["x", "W"], - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - group=group, - ) - elif padding is None: - ## autopadding with unset default attributes - kwargs = {} - if not all(list(s == 1 for s in strides)): - kwargs["strides"] = strides - if not all(list(d == 1 for d in dilations)): - kwargs["dilations"] = dilations - - node = helper.make_node( - "Conv", - inputs=["x", "W"], - outputs=["y"], - # Default values for other attributes: - auto_pad=auto_pad, - group=group, - **kwargs, - ) - else: - node = helper.make_node( - "Conv", - inputs=["x", "W"], - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - group=group, - pads=padding, - ) - - graph = helper.make_graph( - [node], - "conv_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("W", TensorProto.FLOAT, list(w_shape)), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(y_shape))], - ) - - model = helper.make_model(graph, producer_name="conv_test") - - verify_with_ort( - model, - [x_shape, w_shape], - [y_shape], - use_vm=True, - target=target, - dev=dev, - ) - - def repeat(num, dims): - return tuple(num for _ in range(dims)) - - for dims in [1, 2, 3]: - # Convolution with padding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution with asymmetric padding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(4, dims), - repeat(0, dims) + repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution without padding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution with autopadding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with valid autopadding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="VALID", - ) - # Convolution with unset padding - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - True, - ) - # Convolution with non uniform stride - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with dilation - verify_conv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(2, dims), - repeat(3, dims), - repeat(1, dims), - repeat(2, dims), - ) - - # TODO(jwfromm): Merge with other tests once group_conv3d is supported. - for dims in [1, 2, 3]: - # Group Convolution - verify_conv( - (1, 8) + repeat(5, dims), - (8, 1) + repeat(3, dims), - (1, 8) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - group=8, - ) - - verify_conv( - (1, 12) + repeat(5, dims), - (30, 4) + repeat(3, dims), - (1, 30) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - group=3, - ) - - -@tvm.testing.parametrize_targets -def test_convtranspose(target, dev): - """test_convtranspose""" - - def verify_convtranspose_with_output_shape( - x_shape, - w_shape, - output_shape, - kernel_shape, - strides, - dilations, - auto_pad="SAME_UPPER", - group=1, - ): - node = helper.make_node( - "ConvTranspose", - inputs=["x", "W"], - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - output_shape=output_shape, - auto_pad=auto_pad, - ) - - if group is not None: - group_attr = helper.make_attribute("group", group) - node.attribute.append(group_attr) - - graph = helper.make_graph( - [node], - "ConvTranspose_with_output_shape_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("W", TensorProto.FLOAT, list(w_shape)), - ], - outputs=[ - helper.make_tensor_value_info("y", TensorProto.FLOAT, [1, 1] + list(output_shape)) - ], - ) - - model = helper.make_model(graph, producer_name="convtranspose_output_shape_test") - - verify_with_ort(model, [x_shape, w_shape], use_vm=True, target=target, dev=dev) - - def verify_convtranspose_with_padding( - x_shape, - w_shape, - padding, - kernel_shape, - strides, - dilations, - auto_pad="NOTSET", - unset_pad=False, - group=1, - ): - node = helper.make_node( - "ConvTranspose", - inputs=["x", "W"], - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - ) - if not unset_pad: - if padding is None: - pad_attr = helper.make_attribute("auto_pad", auto_pad) - else: - pad_attr = helper.make_attribute("pads", padding) - node.attribute.append(pad_attr) - - if group is not None: - group_attr = helper.make_attribute("group", group) - node.attribute.append(group_attr) - - graph = helper.make_graph( - [node], - "convtranspose_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("W", TensorProto.FLOAT, list(w_shape)), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, ["?"] * len(x_shape))], - ) - - model = helper.make_model(graph, producer_name="convtranspose_pad_test") - - verify_with_ort(model, [x_shape, w_shape], use_vm=True, target=target, dev=dev) - - def verify_convtranspose(x_shape, w_shape, y_shape, p, group=1): - node = onnx.helper.make_node( - "ConvTranspose", - inputs=["x", "W"], - outputs=["y"], - strides=[3, 2], - kernel_shape=[3, 3], - pads=p, - ) - - if group is not None: - group_attr = helper.make_attribute("group", group) - node.attribute.append(group_attr) - - graph = helper.make_graph( - [node], - "verify_convtranspose_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("W", TensorProto.FLOAT, list(w_shape)), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(y_shape))], - ) - - model = helper.make_model(graph, producer_name="convtranspose_test") - verify_with_ort(model, [x_shape, w_shape], y_shape, opset=11, target=target, dev=dev) - - # Convolution Transpose with padding - # (1, 1, 3, 3) input tensor - # (1, 2, 3, 3) tensor for convolution weights - # (1, 2, 7, 3) output tensor - # [1, 2, 1, 2] list for pads - verify_convtranspose((1, 1, 3, 3), (1, 2, 3, 3), (1, 2, 7, 3), [1, 2, 1, 2]) - # Test undefined groups. - verify_convtranspose((1, 1, 3, 3), (1, 2, 3, 3), (1, 2, 7, 3), [1, 2, 1, 2], group=None) - - if "llvm" in target: - # GPU does not support groups != 1 for convtranspose, so only test llvm - # Test depthwise-convolution - verify_convtranspose((1, 10, 3, 3), (10, 1, 3, 3), (1, 10, 7, 3), [1, 2, 1, 2], group=10) - - # Test grouped-convolution - verify_convtranspose((1, 10, 3, 3), (10, 1, 3, 3), (1, 5, 7, 3), [1, 2, 1, 2], group=5) - - def repeat(num, dims): - return tuple(num for _ in range(dims)) - - # Once onnxruntime update is complete - for dims in [1, 2, 3]: - # Convolution with padding - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution without padding - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution with unset padding - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - True, - ) - # Convolution with autopadding - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with valid autopadding - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="VALID", - ) - # Convolution with non uniform stride - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with default stride - verify_convtranspose_with_padding( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(1, dims), - repeat(3, dims), - None, - repeat(1, dims), - ) - # Convolution with dilation - # TODO(mbrookhart): Relay doesn't currently support convtranspose with dilation - # verify_convtranspose_with_padding( - # (1, 1) + repeat(5, D), - # (1, 1) + repeat(3, D), - # 2 * repeat(2, D), - # repeat(3, D), - # repeat(1, D), - # repeat(2, D), - # ) - - # Convolution with output_shape - for dims in [1, 2, 3]: - for num in range(60, 66): - verify_convtranspose_with_output_shape( - (1, 1) + repeat(32, dims), - (1, 1) + repeat(4, dims), - repeat(num, dims), - repeat(4, dims), - repeat(2, dims), - repeat(1, dims), - ) - - verify_convtranspose_with_output_shape( - (1, 1) + repeat(32, dims), - (1, 1) + repeat(4, dims), - repeat(num, dims), - repeat(4, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_LOWER", - ) - - verify_convtranspose_with_output_shape( - (1, 1) + repeat(32, dims), - (1, 2) + repeat(4, dims), - repeat(num, dims), - repeat(4, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - - verify_convtranspose_with_output_shape( - (1, 1, 3, 3), - (1, 2, 3, 3), - (6, 6), - (3, 3), - (2, 2), - (1, 1), - auto_pad="SAME_UPPER", - ) - - verify_convtranspose_with_output_shape( - (1, 1, 3, 3), - (1, 2, 3, 3), - (6, 6), - (3, 3), - (2, 2), - (1, 1), - auto_pad="SAME_LOWER", - ) - - -@tvm.testing.parametrize_targets -def test_unsqueeze_constant(target, dev): - """test_unsqueeze_constant""" - - class Flatten(Module): - def forward(self, input_): - return input_.view(input_.size(0), -1) - - with tempfile.NamedTemporaryFile() as f: - file_name = f.name - input_size = (1, 16, 32, 32) - dummy_input = torch.randn(*input_size) - layer = Sequential(Flatten(), Linear(16 * 32 * 32, 64)) - torch.onnx.export(layer, dummy_input, file_name, export_params=True) - - onnx_model = onnx.load(file_name) - relay.frontend.from_onnx(onnx_model, {"onnx::Reshape_0": input_size}) - - -@tvm.testing.parametrize_targets -def test_pooling(target, dev): - """test_pooling""" - - def verify_pooling(x_shape, kernel_shape, strides, pads, out_shape, mode, auto_pad="NOTSET"): - _ = np.random.uniform(size=x_shape).astype("float32") - - if mode == "max": - node_type = "MaxPool" - elif mode == "average": - node_type = "AveragePool" - else: - raise ValueError(f"Pool method {mode} is not supported.") - - pool_node = helper.make_node( - node_type, inputs=["x"], outputs=["y"], kernel_shape=kernel_shape, strides=strides - ) - - if pads is None: - pad_attr = helper.make_attribute("auto_pad", auto_pad) - else: - pad_attr = helper.make_attribute("pads", pads) - pool_node.attribute.append(pad_attr) - - if mode == "max": - storage_attr = helper.make_attribute("storage_order", 0) - pool_node.attribute.append(storage_attr) - - graph = helper.make_graph( - [pool_node], - "pooling_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="pooling_test") - verify_with_ort( - model, - [x_shape], - [out_shape], - use_vm=False, - target=target, - dev=dev, - ) - - for mode in ["max", "average"]: - # Pool1D - verify_pooling( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[1], - pads=[1, 1], - out_shape=[1, 1, 32], - mode=mode, - ) - # Pool2D - verify_pooling( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[1, 1], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 32, 32], - mode=mode, - ) - - # Pool1D with stride - verify_pooling( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[2], - pads=[1, 1], - out_shape=[1, 1, 16], - mode=mode, - ) - # Pool2D with stride - verify_pooling( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[2, 2], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 16, 16], - mode=mode, - ) - - # Pool1D with stride and autopadding - verify_pooling( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[2], - pads=None, - out_shape=[1, 1, 16], - mode=mode, - auto_pad="SAME_UPPER", - ) - # Pool2D with stride and autopadding - verify_pooling( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[2, 2], - pads=None, - out_shape=[1, 1, 16, 16], - mode=mode, - auto_pad="SAME_UPPER", - ) - - # Pool3D with stride - verify_pooling( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - strides=[2, 2, 2], - pads=[1, 1, 1, 1, 1, 1], - out_shape=[1, 1, 16, 16, 16], - mode=mode, - ) - - # Pool3D with stride and autopadding - verify_pooling( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - strides=[2, 2, 2], - pads=None, - out_shape=[1, 1, 16, 16, 16], - mode=mode, - auto_pad="SAME_UPPER", - ) - - -@tvm.testing.parametrize_targets -def test_global_pooling(target, dev): - """test_global_pooling""" - - def verify_global_pooling(x_shape, mode): - out_shape = x_shape[:2] + [1] * (len(x_shape) - 2) - - if mode == "max": - node_type = "GlobalMaxPool" - elif mode == "average": - node_type = "GlobalAveragePool" - else: - raise ValueError(f"Pool method {mode} is not supported.") - - pool_node = helper.make_node(node_type, inputs=["x"], outputs=["y"]) - - graph = helper.make_graph( - [pool_node], - "global_pooling_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="global_pooling_test") - verify_with_ort( - model, - [x_shape], - [out_shape], - use_vm=False, - target=target, - dev=dev, - ) - - # Test each pooling mode across all N-D inputs. - for mode in ["average", "max"]: - # 1D Pooling (NCW) - verify_global_pooling([1, 8, 8], mode) - verify_global_pooling([4, 1, 4], mode) - # 2D Pooling (NCHW) - verify_global_pooling([1, 8, 8, 8], mode) - verify_global_pooling([4, 1, 6, 4], mode) - # 3D Pooling (NCDHW) - verify_global_pooling([1, 8, 6, 8, 8], mode) - verify_global_pooling([4, 1, 2, 6, 4], mode) - - -@pytest.mark.skip("flaky") -@tvm.testing.parametrize_targets -def test_qlinear_average_pool(target, dev): - """test_qlinear_average_pool""" - - def verify_qlinear_average_pool( - x_shape, kernel_shape, strides, pads, out_shape, auto_pad="NOTSET" - ): - input_nodes = [ - helper.make_tensor_value_info("X", TensorProto.FLOAT, list(x_shape)), - ] - - output_nodes = [ - helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(out_shape)), - ] - - input_names = ["X"] - - node = helper.make_node( - "AveragePool", - inputs=input_names, - outputs=["Y"], - kernel_shape=kernel_shape, - strides=strides, - ) - - if pads is None: - pad_attr = helper.make_attribute("auto_pad", auto_pad) - else: - pad_attr = helper.make_attribute("pads", pads) - node.attribute.append(pad_attr) - - graph = helper.make_graph( - [node], - "qlinear_average_pool_test", - inputs=input_nodes, - outputs=output_nodes, - ) - - model = helper.make_model(graph, producer_name="qlinear_average_pool_Test") - quantize_and_verify_with_ort(model, input_names, [x_shape], target, dev) - - # Pool1D - verify_qlinear_average_pool( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[1], - pads=[1, 1], - out_shape=[1, 1, 32], - ) - # Pool2D - verify_qlinear_average_pool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[1, 1], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 32, 32], - ) - - # Pool1D with stride - verify_qlinear_average_pool( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[2], - pads=[1, 1], - out_shape=[1, 1, 16], - ) - # Pool2D with stride - verify_qlinear_average_pool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[2, 2], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 16, 16], - ) - - # Pool1D with stride and autopadding - verify_qlinear_average_pool( - x_shape=[1, 1, 32], - kernel_shape=[3], - strides=[2], - pads=None, - out_shape=[1, 1, 16], - auto_pad="SAME_UPPER", - ) - # Pool2D with stride and autopadding - verify_qlinear_average_pool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - strides=[2, 2], - pads=None, - out_shape=[1, 1, 16, 16], - auto_pad="SAME_UPPER", - ) - - # Pool3D with stride - verify_qlinear_average_pool( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - strides=[2, 2, 2], - pads=[1, 1, 1, 1, 1, 1], - out_shape=[1, 1, 16, 16, 16], - ) - - # Pool3D with stride and autopadding - verify_qlinear_average_pool( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - strides=[2, 2, 2], - pads=None, - out_shape=[1, 1, 16, 16, 16], - auto_pad="SAME_UPPER", - ) - - -@tvm.testing.parametrize_targets -def test_qlinear_global_average_pool(target, dev): - """test_qlinear_global_average_pool""" - - def verify_qlinear_global_average_pool(x_shape): - out_shape = x_shape[:2] + [1] * (len(x_shape) - 2) - - node_type = "GlobalAveragePool" - - input_names = ["X"] - - pool_node = helper.make_node(node_type, inputs=input_names, outputs=["Y"]) - - graph = helper.make_graph( - [pool_node], - "qlinear_global_average_pool_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, list(x_shape))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="qlinear_global_average_pool_test") - quantize_and_verify_with_ort(model, input_names, [x_shape], target, dev) - - # 1D Pooling (NCW) - verify_qlinear_global_average_pool([1, 8, 8]) - verify_qlinear_global_average_pool([4, 1, 4]) - - # 2D Pooling (NCHW) - verify_qlinear_global_average_pool([1, 8, 8, 8]) - verify_qlinear_global_average_pool([4, 1, 6, 4]) - - # 3D Pooling (NCDHW) - verify_qlinear_global_average_pool([1, 8, 6, 8, 8]) - verify_qlinear_global_average_pool([4, 1, 2, 6, 4]) - - -@tvm.testing.parametrize_targets -def test_mod(target, dev): - """test_mod""" - - def verify_mod(x_shape, y_shape, fmod, out_shape, dtype="float32"): - x_np = np.random.uniform(-100.0, 100.0, x_shape).astype(dtype) - y_np = np.random.uniform(-100.0, 100.0, y_shape).astype(dtype) - y_np = np.where(y_np == 0, 1, y_np) # remove 0's to avoid division by zero error - - mod_node = helper.make_node("Mod", inputs=["x", "y"], outputs=["z"], fmod=fmod) - - onnx_dtype = TensorProto.FLOAT if dtype == "float32" else TensorProto.INT32 - graph = helper.make_graph( - [mod_node], - "mod_test", - inputs=[ - helper.make_tensor_value_info("x", onnx_dtype, list(x_shape)), - helper.make_tensor_value_info("y", onnx_dtype, list(y_shape)), - ], - outputs=[helper.make_tensor_value_info("z", onnx_dtype, list(out_shape))], - ) - model = helper.make_model(graph, producer_name="mod_test") - verify_with_ort_with_inputs(model, [x_np, y_np], [out_shape], target=target, dev=dev) - - # Mod - verify_mod( - x_shape=[1, 32, 32], y_shape=[1, 1, 32], fmod=0, out_shape=(1, 32, 32), dtype="int32" - ) - verify_mod( - x_shape=[1, 32, 32, 32], - y_shape=[1, 32, 32, 32], - fmod=0, - out_shape=(1, 32, 32, 32), - dtype="int32", - ) - - # fmod - verify_mod( - x_shape=[1, 32, 32], y_shape=[1, 32, 32], fmod=1, out_shape=(1, 32, 32), dtype="int32" - ) - verify_mod(x_shape=[1, 1, 32, 32], y_shape=[1, 32, 32, 32], fmod=1, out_shape=(1, 32, 32, 32)) - verify_mod(x_shape=[1, 32, 32, 32], y_shape=[1, 1, 32, 32], fmod=1, out_shape=(1, 32, 32, 32)) - verify_mod( - x_shape=[1, 32, 32, 32], - y_shape=[1, 32, 32, 32], - fmod=1, - out_shape=(1, 32, 32, 32), - dtype="int32", - ) - verify_mod(x_shape=[1, 32, 32, 32], y_shape=[1, 32, 32, 32], fmod=1, out_shape=(1, 32, 32, 32)) - - -@tvm.testing.parametrize_targets -def test_xor(target, dev): - """test_xor""" - - def verify_xor(x_shape, y_shape): - x_np = np.random.choice(a=[False, True], size=x_shape).astype("bool") - y_np = np.random.choice(a=[False, True], size=y_shape).astype("bool") - - np_out = np.logical_xor(x_np, y_np) - out_shape = np_out.shape - - xor_node = helper.make_node("Xor", inputs=["x", "y"], outputs=["z"]) - - onnx_dtype = TensorProto.BOOL - graph = helper.make_graph( - [xor_node], - "xor_test", - inputs=[ - helper.make_tensor_value_info("x", onnx_dtype, list(x_shape)), - helper.make_tensor_value_info("y", onnx_dtype, list(y_shape)), - ], - outputs=[helper.make_tensor_value_info("z", onnx_dtype, list(out_shape))], - ) - model = helper.make_model(graph, producer_name="xor_test") - verify_with_ort_with_inputs(model, [x_np, y_np], [out_shape], target=target, dev=dev) - - # XOR - verify_xor(x_shape=[1, 32, 32], y_shape=[1, 32, 32]) - - # Xor broadcast - verify_xor(x_shape=[1, 32, 32], y_shape=[1, 1, 32]) - - -@tvm.testing.parametrize_targets -def test_max_roi_pool(target, dev): - """test_max_roi_pool""" - - def verify_max_roi_pool(x_shape, rois_shape, pooled_shape, spatial_scale, out_shape): - if spatial_scale is None: - pool_node = helper.make_node( - "MaxRoiPool", inputs=["x", "rois"], outputs=["y"], pooled_shape=pooled_shape - ) - else: - pool_node = helper.make_node( - "MaxRoiPool", - inputs=["x", "rois"], - outputs=["y"], - pooled_shape=pooled_shape, - spatial_scale=spatial_scale, - ) - - graph = helper.make_graph( - [pool_node], - "pool_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape)), - helper.make_tensor_value_info("rois", TensorProto.FLOAT, list(rois_shape)), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="pool_test") - verify_with_ort(model, [x_shape, rois_shape], [out_shape], target=target, dev=dev) - - verify_max_roi_pool( - x_shape=[1, 3, 6, 6], - rois_shape=[3, 5], - pooled_shape=[1, 1], - spatial_scale=None, - out_shape=[3, 3, 1, 1], - ) - - verify_max_roi_pool( - x_shape=[1, 3, 10, 10], - rois_shape=[4, 5], - pooled_shape=[2, 2], - spatial_scale=2.0, - out_shape=[4, 3, 2, 2], - ) - - -@tvm.testing.parametrize_targets -def test_lppool(target, dev): - """test_lppool""" - - def verify_lppool(x_shape, kernel_shape, p, strides, pads, out_shape, auto_pad="NOTSET"): - kwargs = {} - if p is not None: - kwargs["p"] = p - if pads is None: - pool_node = helper.make_node( - "LpPool", - inputs=["x"], - outputs=["y"], - kernel_shape=kernel_shape, - auto_pad=auto_pad, - strides=strides, - **kwargs, - ) - else: - pool_node = helper.make_node( - "LpPool", - inputs=["x"], - outputs=["y"], - kernel_shape=kernel_shape, - pads=pads, - strides=strides, - **kwargs, - ) - - graph = helper.make_graph( - [pool_node], - "lppool_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="lppool_test") - verify_with_ort( - model, - [x_shape], - [out_shape], - use_vm=True, - target=target, - dev=dev, - ) - - # Pool1D - verify_lppool( - x_shape=[1, 1, 32], kernel_shape=[3], p=2, strides=[1], pads=[1, 1], out_shape=[1, 1, 32] - ) - - # Pool2D - verify_lppool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - p=2, - strides=[1, 1], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 32, 32], - ) - - # Pool1D with stride - verify_lppool( - x_shape=[1, 1, 32], kernel_shape=[3], p=2, strides=[2], pads=[1, 1], out_shape=[1, 1, 16] - ) - - # Pool2D with stride - verify_lppool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - p=2, - strides=[2, 2], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 16, 16], - ) - - # Pool1D with stride and autopadding - verify_lppool( - x_shape=[1, 1, 32], - kernel_shape=[3], - p=2, - strides=[2], - pads=None, - out_shape=[1, 1, 16], - auto_pad="SAME_UPPER", - ) - - # Pool2D with stride and autopadding - verify_lppool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - p=2, - strides=[2, 2], - pads=None, - out_shape=[1, 1, 16, 16], - auto_pad="SAME_UPPER", - ) - - # Pool2D with empty stride - verify_lppool( - x_shape=[1, 3, 32, 32], - kernel_shape=[2, 2], - p=4, - strides=None, - pads=None, - out_shape=[1, 3, 32, 32], - auto_pad="SAME_LOWER", - ) - - # Pool3D with stride - verify_lppool( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - p=2, - strides=[2, 2, 2], - pads=[1, 1, 1, 1, 1, 1], - out_shape=[1, 1, 16, 16, 16], - ) - - # Pool3D with stride and autopadding - verify_lppool( - x_shape=[1, 1, 32, 32, 32], - kernel_shape=[3, 3, 3], - p=2, - strides=[2, 2, 2], - pads=None, - out_shape=[1, 1, 16, 16, 16], - auto_pad="SAME_UPPER", - ) - # Pool2D with empty p - verify_lppool( - x_shape=[1, 1, 32, 32], - kernel_shape=[3, 3], - p=None, - strides=[1, 1], - pads=[1, 1, 1, 1], - out_shape=[1, 1, 32, 32], - ) - - -def verify_global_lppool(x_shape, p, out_shape, target, dev): - """verify_global_lppool""" - pool_node = helper.make_node( - "GlobalLpPool", - inputs=["x"], - outputs=["y"], - p=p, - ) - - graph = helper.make_graph( - [pool_node], - "global_lppool_test", - inputs=[helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x_shape))], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(out_shape))], - ) - - model = helper.make_model(graph, producer_name="global_lppool_test") - verify_with_ort(model, [x_shape], out_shape, use_vm=True, target=target, dev=dev) - - -@tvm.testing.parametrize_targets -def test_global_lppool(target, dev): - """test_global_lppool""" - # LpPool1D - verify_global_lppool(x_shape=[1, 15, 16], p=2, out_shape=[1, 15, 1], target=target, dev=dev) - - # LpPool2D - verify_global_lppool( - x_shape=[1, 15, 32, 32], p=2, out_shape=[1, 15, 1, 1], target=target, dev=dev - ) - - # LpPool2D - verify_global_lppool( - x_shape=[1, 15, 32, 32], p=3, out_shape=[1, 15, 1, 1], target=target, dev=dev - ) - - # LpPool3D - verify_global_lppool( - x_shape=[1, 15, 3, 32, 32], p=2, out_shape=[1, 15, 1, 1, 1], target=target, dev=dev - ) - - -def verify_rnn( - seq_length, - batch_size, - input_size, - hidden_size, - rnn_type="LSTM", - use_bias=False, - activations=None, - alphas=None, - betas=None, - use_initial_state=False, - use_peep=False, - linear_before_reset=False, - directions=1, - layout=0, - rtol=1e-5, - atol=1e-5, - target=None, - dev=None, - use_sequence_lens=False, -): - """verify_rnn""" - if rnn_type == "RNN": - multiplier = 1 - elif rnn_type == "LSTM": - multiplier = 4 - elif rnn_type == "GRU": - multiplier = 3 - else: - raise NotImplementedError(f"{rnn_type} RNNs not yet supported.") - - if directions not in [1, 2]: - raise ValueError(f"Direction should be either 1 or 2 (for bidirectional LSTMs)") - - def get_inputs(): - input_names = [] - input_values = [] - input_tensors = [] - - def register(np_arr, name, shape=None): - input_values.append(np_arr) - input_names.append(name) - - # Map of numpy dtypes to the protobuf equivalent - dtype_map = { - "float32": TensorProto.FLOAT, - "int32": TensorProto.INT32, - "int8": TensorProto.INT8, - } - - if np_arr.dtype.name not in dtype_map: - raise ValueError(f"Unknown dtype we don't know how to handle {np.dtype.name}") - if shape is None: - shape = list(np_arr.shape) - proto_type = dtype_map[np_arr.dtype.name] - input_tensors.append(helper.make_tensor_value_info(name, proto_type, shape)) - - if layout == 1: - x_np = np.random.uniform(size=(batch_size, seq_length, input_size)).astype("float32") - else: - x_np = np.random.uniform(size=(seq_length, batch_size, input_size)).astype("float32") - w_np = np.random.uniform(size=(directions, multiplier * hidden_size, input_size)).astype( - "float32" - ) - r_np = np.random.uniform(size=(directions, multiplier * hidden_size, hidden_size)).astype( - "float32" - ) - register(x_np, "X") - register(w_np, "W") - register(r_np, "R") - - if use_bias: - b_np = np.random.uniform(size=(directions, multiplier * 2 * hidden_size)).astype( - "float32" - ) - register(b_np, "B") - - if use_sequence_lens: - sequence_np = np.random.uniform(0, seq_length, size=(batch_size)).astype("int32") - register(sequence_np, "sequence_lens") - - if use_initial_state: - assert use_bias is True, "Initial states must have bias specified." - - if not use_sequence_lens: - sequence_np = np.repeat(seq_length, batch_size).astype("int32") - register(sequence_np, "sequence_lens") - - if layout == 1: - initial_h_np = np.random.uniform(size=(batch_size, directions, hidden_size)).astype( - "float32" - ) - else: - initial_h_np = np.random.uniform(size=(directions, batch_size, hidden_size)).astype( - "float32" - ) - register(initial_h_np, "initial_h") - - if rnn_type == "LSTM": - if layout == 1: - initial_c_np = np.random.uniform( - size=(batch_size, directions, hidden_size) - ).astype("float32") - else: - initial_c_np = np.random.uniform( - size=(directions, batch_size, hidden_size) - ).astype("float32") - register(initial_c_np, "initial_c") - - if use_peep and rnn_type == "LSTM": - assert use_initial_state is True, "Peepholes require initial state to be specified." - p_np = np.random.uniform(size=(directions, 3 * hidden_size)).astype("float32") - register(p_np, "P") - - return input_names, input_tensors, input_values - - input_names, input_tensors, input_values = get_inputs() - - def get_outputs(): - output_names = [] - graph_outputs = [] - output_shapes = [] - - def register(name, shape, proto_type): - output_names.append(name) - graph_outputs.append(helper.make_tensor_value_info(name, proto_type, list(shape))) - output_shapes.append(list(shape)) - - if layout == 1: - register("Y", [directions, seq_length, batch_size, hidden_size], TensorProto.FLOAT) - register("Y_h", [batch_size, directions, hidden_size], TensorProto.FLOAT) - else: - register("Y", [seq_length, directions, batch_size, hidden_size], TensorProto.FLOAT) - register("Y_h", [directions, batch_size, hidden_size], TensorProto.FLOAT) - - if rnn_type == "LSTM": - if layout == 1: - register("Y_c", [batch_size, directions, hidden_size], TensorProto.FLOAT) - else: - register("Y_c", [directions, batch_size, hidden_size], TensorProto.FLOAT) - - return output_names, graph_outputs, output_shapes - - output_names, graph_outputs, output_shapes = get_outputs() - - rnn_node = helper.make_node( - rnn_type, inputs=input_names, outputs=output_names, hidden_size=hidden_size - ) - if activations is not None: - activations_attr = helper.make_attribute("activations", activations) - rnn_node.attribute.append(activations_attr) - if directions == 2: - direction_attr = helper.make_attribute("direction", "bidirectional") - rnn_node.attribute.append(direction_attr) - if alphas is not None: - alphas_attr = helper.make_attribute("activation_alpha", alphas) - rnn_node.attribute.append(alphas_attr) - if betas is not None: - betas_attr = helper.make_attribute("activation_beta", betas) - rnn_node.attribute.append(betas_attr) - if linear_before_reset and rnn_type == "GRU": - lbr_attr = helper.make_attribute("linear_before_reset", 1) - rnn_node.attribute.append(lbr_attr) - if layout == 1: - layout_attr = helper.make_attribute("layout", 1) - rnn_node.attribute.append(layout_attr) - - graph = helper.make_graph([rnn_node], "rnn_test", inputs=input_tensors, outputs=graph_outputs) - - model = helper.make_model(graph, producer_name="rnn_test") - - verify_with_ort_with_inputs( - model, input_values, output_shapes, atol=atol, rtol=rtol, target=target, dev=dev - ) - - -def verify_rnn_helper(target, dev, rnn_type): - num_activations = 1 - if rnn_type == "GRU": - num_activations = 2 - elif rnn_type == "LSTM": - num_activations = 3 - - for directions in [1, 2]: - # No bias. - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=False, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # large batch. - verify_rnn( - seq_length=4, - batch_size=8, - input_size=16, - hidden_size=32, - use_bias=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # Non power of two. - verify_rnn( - seq_length=3, - batch_size=3, - input_size=16, - hidden_size=40, - use_bias=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # Long sequence. - verify_rnn( - seq_length=8, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # Large hidden. - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=128, - use_bias=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # Large input. - verify_rnn( - seq_length=2, - batch_size=1, - input_size=64, - hidden_size=32, - use_bias=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - - # Different activation testing. - # Default value hardsigmoid. - # TODO: onnxruntime <= v1.12.0 has wrong default value of all activation functions - if rnn_type != "RNN": - activations = ["HardSigmoid", "Tanh", "Tanh"][0:num_activations] * directions - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=False, - activations=activations, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # Multiple parametrized activations. - activations = ["HardSigmoid", "LeakyRelu", "Tanh"][0:num_activations] * directions - alphas = [2.0, 0.5, 0.0][0:num_activations] * directions - betas = [0.3, 0.0, 0.0][0:num_activations] * directions - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=False, - activations=activations, - alphas=alphas, - betas=betas, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - # All parametrized with new Affine activation. - activations = ["Affine", "LeakyRelu", "HardSigmoid"][0:num_activations] * directions - alphas = [0.8, 2.0, 0.5][0:num_activations] * directions - betas = [0.0, 0.3, 0.0][0:num_activations] * directions - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=False, - activations=activations, - alphas=alphas, - betas=betas, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - - # Testing with initial state - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=True, - use_initial_state=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - ) - - # Testing layout - # TODO: onnxruntime <= 1.12.0 doesn't support layout == 1 - # verify_rnn( - # seq_length=2, - # batch_size=1, - # input_size=16, - # hidden_size=32, - # use_bias=True, - # rnn_type="RNN", - # directions=directions, - # layout=1, - # target=target, - # dev=dev, - # ) - - # Testing with initial state - if rnn_type == "GRU": - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=True, - use_initial_state=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - use_sequence_lens=True, - ) - verify_rnn( - seq_length=8, - batch_size=8, - input_size=16, - hidden_size=32, - use_bias=True, - use_initial_state=True, - rnn_type=rnn_type, - directions=directions, - target=target, - dev=dev, - use_sequence_lens=True, - ) - - # Testing with peepholes - if rnn_type == "LSTM": - verify_rnn( - seq_length=2, - batch_size=1, - input_size=16, - hidden_size=32, - use_bias=True, - use_initial_state=True, - use_peep=True, - rnn_type="LSTM", - directions=directions, - target=target, - dev=dev, - ) - - -@tvm.testing.parametrize_targets -def test_rnn(target, dev): - verify_rnn_helper(target, dev, "RNN") - - -@tvm.testing.parametrize_targets -def test_lstm(target, dev): - verify_rnn_helper(target, dev, "LSTM") - - -@tvm.testing.parametrize_targets -def test_gru(target, dev): - verify_rnn_helper(target, dev, "GRU") - - -@tvm.testing.parametrize_targets -def test_resize(target, dev): - """test_resize""" - - def verify(ishape, oshape, scales, mode, coord_trans="asymmetric", alpha=0.5, exclude=False): - nodes = [ - make_constant_node("roi", onnx.TensorProto.FLOAT, (0,), []), - make_constant_node("scales", onnx.TensorProto.FLOAT, (len(scales),), scales), - ] - input_names = ["X", "roi", "scales"] - - if oshape != []: - nodes.append( - make_constant_node("sizes", onnx.TensorProto.INT64, (len(oshape),), oshape) - ) - input_names.append("sizes") - nodes.append( - helper.make_node( - "Resize", - inputs=input_names, - outputs=["Y"], - mode=mode, - coordinate_transformation_mode=coord_trans, - cubic_coeff_a=alpha, - exclude_outside=exclude, - ) - ) - - if oshape == []: - oshape = [round(dim * scale) for (dim, scale) in zip(ishape, scales)] - graph = helper.make_graph( - nodes, - "resize_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, ishape)], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, oshape)], - ) - - model = helper.make_model(graph, producer_name="resize_test") - - verify_with_ort( - model, - [ishape], - [oshape], - use_vm=True, - opset=11, - freeze_params=True, - target=target, - dev=dev, - ) - - for ndim in [1, 2, 3]: - method = "nearest" - for coord_trans in ["asymmetric", "align_corners", "half_pixel"]: - # upsampling - verify([1, 16] + [32] * ndim, [1, 16] + [64] * ndim, [], method, coord_trans) - # downsampling - verify([1, 16] + [32] * ndim, [1, 16] + [16] * ndim, [], method, coord_trans) - # scales are specified instead of sizes - verify([1, 16] + [32] * ndim, [], [1, 1] + [0.5] * ndim, method, coord_trans) - verify([1, 16] + [32] * ndim, [], [1, 1] + [2] * ndim, method, coord_trans) - verify([1, 16] + [32] * ndim, [], [1, 1] + [2] * ndim, None, coord_trans) - - method = "linear" - # upsampling - verify([1, 16] + [32] * ndim, [1, 16] + [64] * ndim, [], method) - # downsampling - verify([1, 16] + [32] * ndim, [1, 16] + [16] * ndim, [], method) - # scales are specified instead of sizes - verify([1, 16] + [32] * ndim, [], [1, 1] + [0.5] * ndim, method) - verify([1, 16] + [32] * ndim, [], [1, 1] + [2] * ndim, method) - - if ndim == 2: - # ONNX Runtime only supports cubic interpolation for 2D images - method = "cubic" - for alpha in [0.5, 0.75]: - for exclude in [True, False]: - # upsampling - verify( - [1, 16] + [32] * ndim, - [1, 16] + [64] * ndim, - [], - method, - alpha=alpha, - exclude=exclude, - ) - # downsampling - verify( - [1, 16] + [32] * ndim, - [1, 16] + [16] * ndim, - [], - method, - alpha=alpha, - exclude=exclude, - ) - # scales are specified instead of sizes - verify( - [1, 16] + [32] * ndim, - [], - [1, 1] + [0.5] * ndim, - method, - alpha=alpha, - exclude=exclude, - ) - verify( - [1, 16] + [32] * ndim, - [], - [1, 1] + [2] * ndim, - method, - alpha=alpha, - exclude=exclude, - ) - - def verify_opset_10(ishape, scales, mode): - nodes = [ - make_constant_node("scales", onnx.TensorProto.FLOAT, (len(scales),), scales), - ] - input_names = ["X", "scales"] - nodes.append( - helper.make_node( - "Resize", - inputs=input_names, - outputs=["Y"], - mode=mode, - ) - ) - - oshape = [round(dim * scale) for (dim, scale) in zip(ishape, scales)] - graph = helper.make_graph( - nodes, - "resize_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, ishape)], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, oshape)], - ) - - model = helper.make_model(graph, producer_name="resize_test") - verify_with_ort( - model, - [ishape], - [oshape], - use_vm=True, - freeze_params=True, - opset=10, - target=target, - dev=dev, - ) - - verify_opset_10([1, 16, 32, 32], [1, 1, 2, 2], "nearest") - verify_opset_10([1, 16, 32, 32], [1, 1, 0.5, 0.5], "linear") - - -@tvm.testing.parametrize_targets -def test_nonzero(target, dev): - """test_nonzero""" - - def verify_nonzero(indata, outdata, dtype): - node = helper.make_node( - "NonZero", - inputs=["X"], - outputs=["Y"], - ) - - graph = helper.make_graph( - [node], - "nonzero_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.INT64, list(indata.shape))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.INT64, list(outdata.shape))], - ) - - model = helper.make_model(graph, producer_name="nonzero_test") - - verify_with_ort_with_inputs( - model, [indata], dtype="int64", use_vm=True, opset=9, target=target, dev=dev - ) - - input_data = np.array([[1, 0], [1, 1]], dtype=np.int64) - result = np.array((np.nonzero(input_data))) # expected output [[0, 1, 1], [0, 0, 1]] - verify_nonzero(input_data, result, dtype=np.int64) - - input_data = np.array([[3, 0, 0], [0, 4, 0], [5, 6, 0]], dtype=np.int64) - result = np.array((np.nonzero(input_data))) # expected output [[0, 1, 2, 2], [0, 1, 0, 1]] - verify_nonzero(input_data, result, dtype=np.int64) - - -@tvm.testing.parametrize_targets -def test_topk(target, dev): - """test_topk""" - - def verify_topk(input_dims, k, axis=-1): - output_dims = list(input_dims) - output_dims[axis] = k - - node = helper.make_node("TopK", inputs=["X", "K"], outputs=["Values", "Indices"], axis=axis) - - graph = helper.make_graph( - [node], - "topk_test", - inputs=[ - helper.make_tensor_value_info("X", TensorProto.FLOAT, list(input_dims)), - helper.make_tensor_value_info( - "K", - TensorProto.INT64, - [ - 1, - ], - ), - ], - outputs=[ - helper.make_tensor_value_info("Values", TensorProto.FLOAT, output_dims), - helper.make_tensor_value_info("Indices", TensorProto.INT64, output_dims), - ], - ) - - model = helper.make_model(graph, producer_name="topk_test") - - indata = np.random.uniform(-10, 10, input_dims).astype(np.float32) - verify_with_ort_with_inputs( - model, [indata, np.array([k])], use_vm=True, target=target, dev=dev - ) - - for n in [12, 32]: - for shape in [[n], [n, n], [n, n, n]]: - for k in [1, 5, 10]: - verify_topk(shape, k) - - verify_topk([n, n, n], 5, 0) - verify_topk([n, n, n], 5, 1) - verify_topk([n, n, n], 5, 2) - - -@tvm.testing.parametrize_targets -def test_roi_align(target, dev): - """test_roi_align""" - - def verify_roi_align( - input_dims, - num_roi, - output_height, - output_width, - sampling_ratio=0, - spatial_scale=1.0, - mode="avg", - ): - output_dims = [num_roi, input_dims[1], output_height, output_width] - - node = helper.make_node( - "RoiAlign", - coordinate_transformation_mode="output_half_pixel", - inputs=["X", "rois", "batch_indices"], - outputs=["Y"], - mode=mode, - output_height=output_height, - output_width=output_width, - sampling_ratio=sampling_ratio, - spatial_scale=spatial_scale, - ) - - graph = helper.make_graph( - [node], - "roialign_test", - inputs=[ - helper.make_tensor_value_info("X", TensorProto.FLOAT, list(input_dims)), - helper.make_tensor_value_info("rois", TensorProto.FLOAT, [num_roi, 4]), - helper.make_tensor_value_info( - "batch_indices", - TensorProto.INT64, - [ - num_roi, - ], - ), - ], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, output_dims)], - ) - - model = helper.make_model(graph, producer_name="roialign_test") - - np_data = np.random.uniform(size=input_dims).astype("float32") - np_rois = np.random.uniform(size=[num_roi, 4]).astype("float32") * input_dims[2] - np_batch_indices = np.random.randint(low=0, high=input_dims[0], size=num_roi) - - verify_with_ort_with_inputs( - model, - [np_data, np_rois, np_batch_indices], - out_shape=[output_dims], - target=target, - dev=dev, - ) - - verify_roi_align((1, 4, 16, 16), 32, 7, 7, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((4, 4, 16, 32), 32, 7, 7, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((1, 8, 16, 16), 32, 7, 7, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((1, 4, 8, 8), 32, 7, 7, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((1, 4, 16, 16), 16, 5, 7, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((1, 4, 16, 12), 8, 7, 3, sampling_ratio=0, spatial_scale=1.0) - verify_roi_align((1, 4, 16, 16), 32, 7, 7, sampling_ratio=0, spatial_scale=0.5) - verify_roi_align((3, 4, 12, 16), 32, 7, 7, sampling_ratio=0, spatial_scale=1.5) - verify_roi_align((5, 4, 16, 14), 32, 7, 7, sampling_ratio=1, spatial_scale=1.0) - verify_roi_align((1, 4, 16, 16), 32, 7, 7, sampling_ratio=2, spatial_scale=1.0) - - # ONNX implementation of roi_align with max mode is incorrect, so we don't compare outputs here. - - -@tvm.testing.parametrize_targets -def test_non_max_suppression(target, dev): - """test_non_max_suppression""" - - def verify_nms( - boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold, output_dims - ): - input_names = ["boxes", "scores", "max_output_boxes_per_class", "iou_threshold"] - input_nodes = [ - helper.make_tensor_value_info("boxes", TensorProto.FLOAT, boxes.shape), - helper.make_tensor_value_info("scores", TensorProto.FLOAT, scores.shape), - helper.make_tensor_value_info( - "max_output_boxes_per_class", TensorProto.INT64, max_output_boxes_per_class.shape - ), - helper.make_tensor_value_info("iou_threshold", TensorProto.FLOAT, iou_threshold.shape), - ] - inputs = [boxes, scores, max_output_boxes_per_class, iou_threshold] - if score_threshold is not None: - input_names.append("score_threshold") - input_nodes.append( - helper.make_tensor_value_info( - "score_threshold", TensorProto.FLOAT, score_threshold.shape - ) - ) - inputs.append(score_threshold) - node = helper.make_node( - "NonMaxSuppression", - inputs=input_names, - outputs=["Y"], - center_point_box=0, - ) - - graph = helper.make_graph( - [node], - "nms_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("Y", TensorProto.INT64, output_dims)], - ) - - model = helper.make_model(graph, producer_name="nms_test") - - verify_with_ort_with_inputs(model, inputs, use_vm=True, target=target, dev=dev) - - boxes = np.array( - [ - [ - [0.0, 0.0, 0.3, 0.3], - [0.0, 0.0, 0.4, 0.4], - [0.0, 0.0, 0.5, 0.5], - [0.5, 0.5, 0.9, 0.9], - [0.5, 0.5, 1.0, 1.0], - ], - [ - [0.0, 0.0, 0.3, 0.3], - [0.0, 0.0, 0.4, 0.4], - [0.5, 0.5, 0.95, 0.95], - [0.5, 0.5, 0.96, 0.96], - [0.5, 0.5, 1.0, 1.0], - ], - ] - ).astype("float32") - - scores = np.array( - [ - [[0.1, 0.2, 0.6, 0.3, 0.9], [0.1, 0.2, 0.6, 0.3, 0.9]], - [[0.1, 0.2, 0.6, 0.3, 0.9], [0.1, 0.2, 0.6, 0.3, 0.9]], - ] - ).astype("float32") - max_output_boxes_per_class = np.array(2).astype("int64") - iou_threshold = np.array(0.8).astype("float32") - output_dims = [8, 3] - verify_nms(boxes, scores, max_output_boxes_per_class, iou_threshold, None, output_dims) - - boxes = np.array( - [ - [ - [0.0, 0.0, 1.0, 1.0], - [0.0, 0.1, 1.0, 1.1], - [0.0, -0.1, 1.0, 0.9], - [0.0, 10.0, 1.0, 11.0], - [0.0, 10.1, 1.0, 11.1], - [0.0, 100.0, 1.0, 101.0], - ] - ] - ).astype(np.float32) - scores = np.array([[[0.9, 0.75, 0.6, 0.95, 0.5, 0.3]]]).astype(np.float32) - max_output_boxes_per_class = np.array([3]).astype(np.int64) - iou_threshold = np.array([0.5]).astype(np.float32) - score_threshold = np.array([0.4]).astype(np.float32) - output_dims = [2, 3] - verify_nms( - boxes, scores, max_output_boxes_per_class, iou_threshold, score_threshold, output_dims - ) - - -@tvm.testing.parametrize_targets -def test_loop(target, dev): - """test_loop""" - - def verify_cond_loop(): - y_in = helper.make_tensor_value_info("y_in", TensorProto.FLOAT, [1]) - y_out = helper.make_tensor_value_info("y_out", TensorProto.FLOAT, [1]) - scan_out = helper.make_tensor_value_info("scan_out", TensorProto.FLOAT, [1]) - cond_in = helper.make_tensor_value_info("cond_in", TensorProto.BOOL, []) - cond_out = helper.make_tensor_value_info("cond_out", TensorProto.BOOL, []) - iter_count = helper.make_tensor_value_info("iter_count", TensorProto.INT64, []) - - y = np.array([-2]).astype(np.float32) - - five_const_node = helper.make_node( - "Constant", - inputs=[], - outputs=["five"], - value=helper.make_tensor( - name="const_tensor_five", data_type=TensorProto.FLOAT, dims=(), vals=[5] - ), - ) - - iter_cast_node = helper.make_node( - "Cast", inputs=["iter_count"], outputs=["iter_cast"], to=onnx.TensorProto.FLOAT - ) - - y_add_node = helper.make_node("Add", inputs=["y_in", "iter_cast"], outputs=["y_out"]) - - less_node = helper.make_node("Less", inputs=["y_out", "five"], outputs=["cond_less"]) - - squeeze_node = helper.make_node("Squeeze", inputs=["cond_less"], outputs=["cond_squeeze"]) - - cond_cast_node = helper.make_node( - "Cast", inputs=["cond_squeeze"], outputs=["cond_out"], to=onnx.TensorProto.BOOL - ) - - scan_identity_node = helper.make_node("Identity", inputs=["y_out"], outputs=["scan_out"]) - - loop_body = helper.make_graph( - [ - five_const_node, - iter_cast_node, - y_add_node, - less_node, - squeeze_node, - cond_cast_node, - scan_identity_node, - ], - "loop_body", - [iter_count, cond_in, y_in], - [cond_out, y_out, scan_out], - ) - - loop_node = helper.make_node( - "Loop", - inputs=["trip_count", "cond", "y"], - outputs=["res_y", "res_scan"], - body=loop_body, - ) - - trip_count = np.array(5).astype(np.int64) - _ = np.array([13]).astype(np.float32) - cond = np.array(1).astype(bool) - loop_graph = onnx.helper.make_graph( - [loop_node], - "loop_outer", - inputs=[ - onnx.helper.make_tensor_value_info("trip_count", onnx.TensorProto.INT64, []), - onnx.helper.make_tensor_value_info("cond", onnx.TensorProto.BOOL, []), - onnx.helper.make_tensor_value_info("y", onnx.TensorProto.FLOAT, [1]), - ], - outputs=[ - onnx.helper.make_tensor_value_info("res_y", onnx.TensorProto.FLOAT, [1]), - onnx.helper.make_tensor_value_info("res_scan", onnx.TensorProto.FLOAT, [5, 1]), - ], - ) - loop_model = onnx.helper.make_model(loop_graph) - - # Set a high trip count so that condition trips first. - trip_count = np.array(40).astype(np.int64) - cond = np.array(1).astype(bool) - input_vals = [trip_count, cond, y] - verify_with_ort_with_inputs( - loop_model, - input_vals, - use_vm=True, - freeze_params=True, - opset=11, - target=target, - dev=dev, - ) - - def verify_count_loop(): - y_in = helper.make_tensor_value_info("y_in", TensorProto.FLOAT, []) - y_out = helper.make_tensor_value_info("y_out", TensorProto.FLOAT, []) - scan_out = helper.make_tensor_value_info("scan_out", TensorProto.FLOAT, []) - cond_in = helper.make_tensor_value_info("cond_in", TensorProto.BOOL, []) - cond_out = helper.make_tensor_value_info("cond_out", TensorProto.BOOL, []) - iter_count = helper.make_tensor_value_info("iter_count", TensorProto.INT64, []) - - y = np.array(-2).astype(np.float32) - - iter_cast_node = helper.make_node( - "Cast", inputs=["iter_count"], outputs=["iter_cast"], to=onnx.TensorProto.FLOAT - ) - - y_add_node = helper.make_node("Add", inputs=["y_in", "iter_cast"], outputs=["y_out"]) - - identity_node = helper.make_node("Identity", inputs=["cond_in"], outputs=["cond_out"]) - - scan_identity_node = helper.make_node("Identity", inputs=["y_out"], outputs=["scan_out"]) - - loop_body = helper.make_graph( - [identity_node, iter_cast_node, y_add_node, scan_identity_node], - "loop_body", - [iter_count, cond_in, y_in], - [cond_out, y_out, scan_out], - ) - - loop_node = helper.make_node( - "Loop", - inputs=["trip_count", "cond", "y"], - outputs=["res_y", "res_scan"], - body=loop_body, - ) - - trip_count = np.array(5).astype(np.int64) - _ = np.array([13]).astype(np.float32) - cond = np.array(1).astype(bool) - loop_graph = onnx.helper.make_graph( - [loop_node], - "loop_outer", - inputs=[ - onnx.helper.make_tensor_value_info("trip_count", onnx.TensorProto.INT64, []), - onnx.helper.make_tensor_value_info("cond", onnx.TensorProto.BOOL, []), - onnx.helper.make_tensor_value_info("y", onnx.TensorProto.FLOAT, []), - ], - outputs=[ - onnx.helper.make_tensor_value_info("res_y", onnx.TensorProto.FLOAT, []), - onnx.helper.make_tensor_value_info("res_scan", onnx.TensorProto.FLOAT, [5]), - ], - ) - loop_model = onnx.helper.make_model(loop_graph) - - trip_count = np.array(5).astype(np.int64) - cond = np.array(1).astype(bool) - input_vals = [trip_count, cond, y] - verify_with_ort_with_inputs( - loop_model, - input_vals, - use_vm=True, - freeze_params=True, - opset=11, - target=target, - dev=dev, - ) - - def verify_tensor_loop(shapeless_output=False): - y_in = helper.make_tensor_value_info("y_in", TensorProto.FLOAT, [3, 3, 3, 3]) - y_out = helper.make_tensor_value_info("y_out", TensorProto.FLOAT, [3, 3, 3, 3]) - scan_out = helper.make_tensor_value_info("scan_out", TensorProto.FLOAT, [3, 3, 3, 3]) - cond_in = helper.make_tensor_value_info("cond_in", TensorProto.BOOL, []) - cond_out = helper.make_tensor_value_info("cond_out", TensorProto.BOOL, []) - iter_count = helper.make_tensor_value_info("iter_count", TensorProto.INT64, []) - - y = np.random.normal(size=[3, 3, 3, 3]).astype(np.float32) - - iter_cast_node = helper.make_node( - "Cast", inputs=["iter_count"], outputs=["iter_cast"], to=onnx.TensorProto.FLOAT - ) - - y_add_node = helper.make_node("Add", inputs=["y_in", "iter_cast"], outputs=["y_out"]) - - identity_node = helper.make_node("Identity", inputs=["cond_in"], outputs=["cond_out"]) - - scan_identity_node = helper.make_node("Identity", inputs=["y_out"], outputs=["scan_out"]) - - loop_body = helper.make_graph( - [identity_node, iter_cast_node, y_add_node, scan_identity_node], - "loop_body", - [iter_count, cond_in, y_in], - [cond_out, y_out, scan_out], - ) - - loop_node = helper.make_node( - "Loop", - inputs=["trip_count", "cond", "y"], - outputs=["res_y", "res_scan"], - body=loop_body, - ) - - trip_count = np.array(5).astype(np.int64) - cond = np.array(1).astype(bool) - - # Allow testing of malformed nodes since pytorch likes to create these. - if shapeless_output: - scan_shape = None - else: - scan_shape = [5, 3, 3, 3, 3] - - loop_graph = onnx.helper.make_graph( - [loop_node], - "loop_outer", - inputs=[ - onnx.helper.make_tensor_value_info("trip_count", onnx.TensorProto.INT64, []), - onnx.helper.make_tensor_value_info("cond", onnx.TensorProto.BOOL, []), - onnx.helper.make_tensor_value_info("y", onnx.TensorProto.FLOAT, [3, 3, 3, 3]), - ], - outputs=[ - onnx.helper.make_tensor_value_info("res_y", onnx.TensorProto.FLOAT, [3, 3, 3, 3]), - onnx.helper.make_tensor_value_info("res_scan", onnx.TensorProto.FLOAT, scan_shape), - ], - ) - loop_model = onnx.helper.make_model(loop_graph) - - trip_count = np.array(5).astype(np.int64) - cond = np.array(1).astype(bool) - input_vals = [trip_count, cond, y] - verify_with_ort_with_inputs( - loop_model, - input_vals, - use_vm=True, - freeze_params=True, - opset=11, - target=target, - dev=dev, - ) - - # Test a loop that exits once a condition is met. - verify_cond_loop() - # Test a loop that exits after a fixed number of iterations with scalar outputs. - verify_count_loop() - # Test a loop that uses an array output. - verify_tensor_loop() - # Test a loop that is malformed and has no output shape defined. - verify_tensor_loop(shapeless_output=True) - - -@tvm.testing.parametrize_targets -def test_if(target, dev): - """test_if""" - - def verify_if(cond_array, num_outputs): - # Given a bool scalar input cond. - # return constant tensor x if cond is True, otherwise return constant tensor y. - - def append_constant_nodes(nodes, outputs, expected, name): - outputs.append(onnx.helper.make_tensor_value_info(name, onnx.TensorProto.FLOAT, [5])) - - expected.append(np.random.randn(5).astype("float32")) - - nodes.append( - onnx.helper.make_node( - "Constant", - inputs=[], - outputs=[name], - value=numpy_helper.from_array(expected[-1]), - ) - ) - - if_outputs = [] - graph_outputs = [] - - then_nodes, then_outs, then_expected = [], [], [] - else_nodes, else_outs, else_expected = [], [], [] - - for i in range(num_outputs): - append_constant_nodes(then_nodes, then_outs, then_expected, f"then_out{i}") - append_constant_nodes(else_nodes, else_outs, else_expected, f"else_out{i}") - - if_outputs.append(f"res{i}") - graph_outputs.append( - onnx.helper.make_tensor_value_info(f"res{i}", onnx.TensorProto.FLOAT, [5]), - ) - - then_body = onnx.helper.make_graph(then_nodes, "then_body", [], then_outs) - else_body = onnx.helper.make_graph(else_nodes, "else_body", [], else_outs) - - if_node = onnx.helper.make_node( - "If", inputs=["cond"], outputs=if_outputs, then_branch=then_body, else_branch=else_body - ) - - if_graph = onnx.helper.make_graph( - [if_node], - "if_outer", - inputs=[ - onnx.helper.make_tensor_value_info("cond", onnx.TensorProto.BOOL, []), - ], - outputs=graph_outputs, - ) - - if_model = onnx.helper.make_model(if_graph) - if cond_array: - cond = np.array([1]).astype("bool") - else: - cond = np.array(1).astype("bool") - correct_out = then_expected if cond else else_expected - - # TODO(jwfromm): Onnxruntime 1.0.0 is buggy with If statements. Replace this with - # verify_with_ort once we update versions. - tvm_out = get_tvm_output_with_vm(if_model, [cond], target, dev, freeze_params=True) - if not isinstance(tvm_out, list): - tvm_out = [tvm_out] - for i, _ in enumerate(tvm_out): - tvm.testing.assert_allclose( - correct_out[i], - tvm_out[i], # pylint: disable=unnecessary-list-index-lookup - rtol=1e-05, - atol=1e-05, - ) - - # Confirm that if works with cond as an array or scalar. - verify_if(cond_array=False, num_outputs=1) - verify_if(cond_array=False, num_outputs=2) - verify_if(cond_array=True, num_outputs=1) - verify_if(cond_array=True, num_outputs=2) - - -@tvm.testing.parametrize_targets -def test_graph_input_use_in_if(target, dev): - """test_graph_input_use_in_if""" - - def verify_if(num_nested, cond): - # return "graph input" if cond is True, else return constant(-1). - - input_tensor = helper.make_tensor_value_info("graph_input", TensorProto.FLOAT, [1]) - output_tensor = helper.make_tensor_value_info("graph_output", TensorProto.FLOAT, [1]) - constant_node = make_constant_node("const_val", TensorProto.FLOAT, [1], [-1]) - cond_tensor = helper.make_tensor_value_info("cond", TensorProto.BOOL, [1]) - inner_if_node = None - for i in range(num_nested): - identity_node = helper.make_node( - "Identity", - inputs=["const_val"], - outputs=[f"const{i}"], - name=f"depth{i}'th else identity", - ) - else_branch = helper.make_graph( - [identity_node], - f"else{i}_body", - inputs=[], - outputs=[helper.make_tensor_value_info(f"const{i}", TensorProto.FLOAT, [1])], - ) - out_name = f"if_output{i}" if i != (num_nested - 1) else "graph_output" - - if i == 0: - identity_node = helper.make_node( - "Identity", - inputs=["graph_input"], - outputs=[f"input_identity{i}"], - name=f"depth{i}'th then identity", - ) - then_branch = helper.make_graph( - [identity_node], - f"then{i}_body", - inputs=[], - outputs=[ - helper.make_tensor_value_info(f"input_identity{i}", TensorProto.FLOAT, [1]) - ], - ) - if_node = helper.make_node( - "If", - inputs=["cond"], - outputs=[out_name], - then_branch=then_branch, - else_branch=else_branch, - name=f"depth{i}'s If node", - ) - inner_if_node = if_node - else: - then_branch = helper.make_graph( - [inner_if_node], - f"then{i}_body", - inputs=[], - outputs=[ - helper.make_tensor_value_info(f"if_output{i-1}", TensorProto.FLOAT, [1]) - ], - ) - if_node = helper.make_node( - "If", - inputs=["cond"], - outputs=[out_name], - then_branch=then_branch, - else_branch=else_branch, - name=f"depth{i}'s If node", - ) - inner_if_node = if_node - graph_nodes = [constant_node, inner_if_node] - graph = helper.make_graph( - graph_nodes, - "input_use_in_if_test", - inputs=[input_tensor, cond_tensor], - outputs=[output_tensor], - ) - model = helper.make_model(graph, producer_name="input_use_in_if_test") - - verify_with_ort_with_inputs( - model, - [np.array([3.0], dtype="float32"), np.array([cond])], - dtype="float32", - use_vm=True, - opset=14, - target=target, - dev=dev, - ) - - # Confirm that if works with cond as an array or scalar. - verify_if(num_nested=1, cond=True) - verify_if(num_nested=1, cond=False) - verify_if(num_nested=2, cond=True) - verify_if(num_nested=2, cond=False) - - -@tvm.testing.parametrize_targets -def test_size(target, dev): - """test_size""" - - def verify_size(indata): - node = helper.make_node( - "Size", - inputs=["X"], - outputs=["Y"], - ) - - graph = helper.make_graph( - [node], - "size_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.INT64, list(indata.shape))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.INT64, [])], - ) - - model = helper.make_model(graph, producer_name="size_test") - - verify_with_ort_with_inputs( - model, [indata], dtype="int64", use_vm=True, opset=11, target=target, dev=dev - ) - - input_data = np.array([[1, 0], [1, 1]], dtype=np.int64) - verify_size(input_data) - - input_data = np.array([[3, 0, 0], [0, 4, 0], [5, 6, 0]], dtype=np.int64) - verify_size(input_data) - - -@tvm.testing.parametrize_targets -def test_maxunpool(target, dev): - """test_maxunpool""" - - def verify_maxunpool(data, indices, kernel_shape, strides, output_shape=None, pads=None): - input_names = ["xT", "xI"] - input_info = [ - helper.make_tensor_value_info("xT", TensorProto.FLOAT, list(data.shape)), - helper.make_tensor_value_info("xI", TensorProto.INT64, list(indices.shape)), - ] - input_values = [data, indices] - if output_shape is not None: - input_names.append("output_shape") - input_info.append( - helper.make_tensor_value_info( - "output_shape", TensorProto.INT64, list(output_shape.shape) - ) - ) - input_values.append(output_shape) - else: - # Compute expected output shape - output_shape = np.asarray(([1, 1] + list(strides))) * np.asarray(list(data.shape)) - output_shape += np.asarray(([0, 0] + list(kernel_shape))) - np.asarray( - ([0, 0] + list(strides)) - ) - if pads is not None: - output_shape -= np.asarray( - [0, 0] + list(np.sum(np.reshape(list(pads), [-1, 2]), axis=-1)) - ) - output_shape = [int(i) for i in output_shape] - - node = helper.make_node( - "MaxUnpool", inputs=input_names, outputs=["y"], kernel_shape=kernel_shape - ) - - if pads is not None: - pad_attr = helper.make_attribute("pads", pads) - node.attribute.append(pad_attr) - - if strides is not None: - strides_attr = helper.make_attribute("strides", strides) - node.attribute.append(strides_attr) - - graph = helper.make_graph( - [node], - "maxunpool_test", - inputs=input_info, - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, output_shape)], - ) - - model = helper.make_model(graph, producer_name="size_test") - - verify_with_ort_with_inputs( - model, input_values, use_vm=True, opset=11, target=target, dev=dev - ) - - # Basic test - x_t = np.array([[[[5, 6], [7, 8]]]], dtype=np.float32) - x_i = np.array([[[[0, 7], [13, 15]]]], dtype=np.int64) - verify_maxunpool(x_t, x_i, [2, 2], strides=[2, 2]) - # Small stride - verify_maxunpool(x_t, x_i, [2, 2], strides=[1, 1]) - # Big kernel - verify_maxunpool(x_t, x_i, [3, 3], strides=[2, 2]) - # With output shape - output_shape = np.array((1, 1, 5, 5), dtype=np.int64) - verify_maxunpool(x_t, x_i, [2, 2], strides=[2, 2], output_shape=output_shape) - # With explicit reverse padding - pads = np.asarray([1, 1, 1, 1]).astype(np.int64) - verify_maxunpool(x_t, x_i, [2, 2], strides=[2, 2], pads=pads) - - -@tvm.testing.parametrize_targets -def test_softplus(target, dev): - """test_softplus""" - - def verify_softplus(indata): - node = helper.make_node( - "Softplus", - inputs=["X"], - outputs=["Y"], - ) - - graph = helper.make_graph( - [node], - "softplus_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, list(indata.shape))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(indata.shape))], - ) - - model = helper.make_model(graph, producer_name="softplus_test") - - verify_with_ort_with_inputs( - model, [indata], dtype="float32", use_vm=True, opset=11, target=target, dev=dev - ) - - # Simple case with all signs. - input_data = np.array([[-1, 0, 1]], dtype=np.float32) - verify_softplus(input_data) - # More fancy case. - input_data = np.random.randn(1, 32, 32, 3).astype("float32") - verify_softplus(input_data) - - -@tvm.testing.parametrize_targets -def test_cumsum(target, dev): - """test_cumsum""" - - def verify_cumsum(indata, axis, exclusive=0, reverse=0, dtype="float32"): - cumsum_node = onnx.helper.make_node( - "CumSum", - inputs=["X", "axis"], - outputs=["Y"], - ) - if exclusive != 0: - exclusive_attr = helper.make_attribute("exclusive", exclusive) - cumsum_node.attribute.append(exclusive_attr) - if reverse != 0: - reverse_attr = helper.make_attribute("reverse", reverse) - cumsum_node.attribute.append(reverse_attr) - nodes = [ - make_constant_node("axis", onnx.TensorProto.INT32, [1], [axis]), - cumsum_node, - ] - if dtype == "float32": - tensor_type = TensorProto.FLOAT - else: - tensor_type = TensorProto.INT32 - dtype = "int32" - - graph = helper.make_graph( - nodes, - "cumsum_test", - inputs=[ - helper.make_tensor_value_info("X", tensor_type, list(indata.shape)), - ], - outputs=[helper.make_tensor_value_info("Y", tensor_type, list(indata.shape))], - ) - - model = helper.make_model(graph, producer_name="cumsum_test") - - verify_with_ort_with_inputs( - model, [indata], dtype=dtype, use_vm=True, opset=11, target=target, dev=dev - ) - - data = ( - np.array( - [ - 1.0, - 2.0, - 3.0, - 4.0, - 5.0, - 6.0, - 7.0, - 8.0, - 9.0, - 10.0, - 11.0, - 12.0, - ] - ) - .astype(np.float32) - .reshape((3, 4)) - ) - - verify_cumsum(data, 0) - verify_cumsum(data, 1) - verify_cumsum(data, 0, 1, 0) - verify_cumsum(data, 1, 1, 0) - verify_cumsum(data, 0, 0, 1) - verify_cumsum(data, 1, 0, 1) - verify_cumsum(data, 1, 1, 1) - data = np.random.randn(1, 32, 32, 3).astype("float32") - verify_cumsum(data, 1) - data = np.random.randn(1, 32, 32, 3).astype("int32") - verify_cumsum(data, 0, dtype="int32") - verify_cumsum(data, 1, dtype="int32") - verify_cumsum(data, 0, 1, 0, dtype="int32") - verify_cumsum(data, 1, 1, 0, dtype="int32") - verify_cumsum(data, 0, 0, 1, dtype="int32") - verify_cumsum(data, 1, 0, 1, dtype="int32") - verify_cumsum(data, 1, 1, 1, dtype="int32") - - -@tvm.testing.parametrize_targets -def test_eyelike(target, dev): - """test_eyelike""" - - def verify_eyelike(indata, dynamic=False): - node_list = [] - eyelike_inputs = ["X"] - input_node_list = [ - helper.make_tensor_value_info("X", TensorProto.FLOAT, list(indata.shape)) - ] - input_list = [indata] - - if dynamic: - input_node_list.append( - helper.make_tensor_value_info("shape", TensorProto.INT64, [len(indata.shape)]) - ) - input_list.append(np.asarray(indata.shape)) - reshape_node = helper.make_node("Reshape", ["X", "shape"], ["X_dyn"]) - eyelike_inputs[0] = "X_dyn" - node_list += [reshape_node] - - node = helper.make_node( - "EyeLike", - inputs=eyelike_inputs, - outputs=["Y"], - ) - node_list.append(node) - - graph = helper.make_graph( - node_list, - "eyelike_test", - inputs=input_node_list, - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(indata.shape))], - ) - - model = helper.make_model(graph, producer_name="eyelike_test") - verify_with_ort_with_inputs( - model, input_list, dtype="float32", opset=9, target=target, dev=dev, use_vm=True - ) - - input_data = np.zeros((5, 5), dtype=np.float32) - verify_eyelike(input_data) - verify_eyelike(input_data, True) - - -# The following parametrized tests loads the tests that ONNX ships as -# serialized ONNX files, inputs, and outputs. The goal of this test -# is to ensure the ONNX importer is in line with the ONNX specification. -# To allow these tests to run in CI before all pass, a number of tests -# that are not yet supported are skipped. - -onnx_test_node_dir = os.path.join(os.path.dirname(onnx.__file__), "backend", "test", "data", "node") - -onnx_test_folders = sorted( - dirname - for dirname in os.listdir(onnx_test_node_dir) - if dirname.startswith("test") and os.path.isdir(os.path.join(onnx_test_node_dir, dirname)) -) - -unsupported_onnx_tests = [ - "test_batchnorm_epsilon_training_mode", - "test_batchnorm_example_training_mode", - "test_bernoulli", - "test_bernoulli_expanded", - "test_bernoulli_double", - "test_bernoulli_double_expanded", - "test_bernoulli_seed", - "test_bernoulli_seed_expanded", - "test_blackmanwindow", - "test_blackmanwindow_expanded", - "test_blackmanwindow_symmetric", - "test_blackmanwindow_symmetric_expanded", - # the follow cast and castlike cases have lowering issues - "test_cast_FLOAT_to_STRING", - "test_cast_STRING_to_FLOAT", - "test_castlike_FLOAT_to_STRING", - "test_castlike_FLOAT_to_STRING_expanded", - "test_castlike_STRING_to_FLOAT", - "test_castlike_STRING_to_FLOAT_expanded", - # the following cast and castlike cases segfault - "test_cast_DOUBLE_to_FLOAT16", - "test_castlike_DOUBLE_to_FLOAT16", - "test_castlike_DOUBLE_to_FLOAT16_expanded", - "test_convtranspose_dilations", - "test_cumsum_1d", - "test_cumsum_1d_exclusive", - "test_cumsum_1d_reverse", - "test_cumsum_1d_reverse_exclusive", - "test_cumsum_2d_axis_0", - "test_cumsum_2d_axis_1", - "test_cumsum_2d_negative_axis", - "test_det_2d", - "test_det_nd", - "test_dropout_default", - "test_dropout_default_mask", - "test_dropout_default_mask_ratio", - "test_dropout_default_ratio", - "test_gru_batchwise", - "test_hammingwindow", - "test_hammingwindow_expanded", - "test_hammingwindow_symmetric", - "test_hammingwindow_symmetric_expanded", - "test_hannwindow", - "test_hannwindow_expanded", - "test_hannwindow_symmetric", - "test_hannwindow_symmetric_expanded", - "test_identity_opt", - "test_identity_sequence", - "test_if_opt", - "test_if_seq", - "test_loop13_seq", - "test_loop16_seq_none", - "test_lstm_batchwise", - "test_maxpool_with_argmax_2d_precomputed_pads", - "test_maxpool_with_argmax_2d_precomputed_strides", - "test_maxunpool_export_with_output_shape", - "test_melweightmatrix", - # This test fails llvm with a lowering error: - "test_nllloss_NCd1d2d3_none_no_weight_negative_ii_expanded", - "test_qlinearmatmul_3D", - "test_range_float_type_positive_delta_expanded", - "test_range_int32_type_negative_delta_expanded", - "test_reduce_sum_do_not_keepdims_example", - "test_reduce_sum_do_not_keepdims_random", - "test_reduce_sum_keepdims_example", - "test_reduce_sum_keepdims_random", - "test_reduce_sum_negative_axes_keepdims_example", - "test_reduce_sum_negative_axes_keepdims_random", - "test_roialign_aligned_true", - "test_sequence_insert_at_back", - "test_sequence_insert_at_front", - "test_sequence_map_add_1_sequence_1_tensor", - "test_sequence_map_add_1_sequence_1_tensor_expanded", - "test_sequence_map_add_2_sequences", - "test_sequence_map_add_2_sequences_expanded", - "test_sequence_map_extract_shapes", - "test_sequence_map_extract_shapes_expanded", - "test_sequence_map_identity_1_sequence", - "test_sequence_map_identity_1_sequence_1_tensor", - "test_sequence_map_identity_1_sequence_1_tensor_expanded", - "test_sequence_map_identity_1_sequence_expanded", - "test_sequence_map_identity_2_sequences", - "test_sequence_map_identity_2_sequences_expanded", - "test_simple_rnn_batchwise", - "test_simple_rnn_defaults", - "test_simple_rnn_with_initial_bias", - "test_split_variable_parts_1d", - "test_split_variable_parts_2d", - "test_split_variable_parts_default_axis", - "test_split_zero_size_splits", - "test_stft", - "test_stft_with_window", - "test_strnormalizer_export_monday_casesensintive_lower", - "test_strnormalizer_export_monday_casesensintive_nochangecase", - "test_strnormalizer_export_monday_casesensintive_upper", - "test_strnormalizer_export_monday_empty_output", - "test_strnormalizer_export_monday_insensintive_upper_twodim", - "test_strnormalizer_nostopwords_nochangecase", - "test_tfidfvectorizer_tf_batch_onlybigrams_skip0", - "test_tfidfvectorizer_tf_batch_onlybigrams_skip5", - "test_tfidfvectorizer_tf_batch_uniandbigrams_skip5", - "test_tfidfvectorizer_tf_only_bigrams_skip0", - "test_tfidfvectorizer_tf_onlybigrams_levelempty", - "test_tfidfvectorizer_tf_onlybigrams_skip5", - "test_tfidfvectorizer_tf_uniandbigrams_skip5", - "test_training_dropout", - "test_training_dropout_default", - "test_training_dropout_default_mask", - "test_training_dropout_mask", - "test_training_dropout_zero_ratio", - "test_training_dropout_zero_ratio_mask", - "test_tril_zero", - "test_triu_zero", - "test_unique_sorted_with_axis", - "test_unique_sorted_with_axis_3d", - "test_unique_sorted_with_negative_axis", - "test_upsample_nearest", - "test_upsample_nearest_default", -] - - -target_skips = { - "cuda": [ - "test_range_float_type_positive_delta_expanded", - "test_range_int32_type_positive_delta_expanded", - "test_mod_mixed_sign_float16", - "test_qlinearconv", - "test_qlinearmatmul", - "test_resize_upsample_sizes_nearest", - ] -} - - -def _load_proto(proto_filename, target_list, model_type_proto): - with open(proto_filename, "rb") as fin: - protobuf_content = fin.read() - if model_type_proto.HasField("sequence_type"): - sequence = onnx.SequenceProto() - sequence.ParseFromString(protobuf_content) - target_list.append(numpy_helper.to_list(sequence)) - elif model_type_proto.HasField("tensor_type"): - tensor = onnx.TensorProto() - tensor.ParseFromString(protobuf_content) - target_list.append(numpy_helper.to_array(tensor)) - elif model_type_proto.HasField("optional_type"): - optional = onnx.OptionalProto() - optional.ParseFromString(protobuf_content) - target_list.append(numpy_helper.to_optional(optional)) - else: - raise ValueError( - "Loading proto of that specific type (Map/Sparse Tensor) is currently not supported" - ) - - -def is_ort_version_lower_than(ver): - import onnxruntime as ort - - v11, v12, v13 = tuple(int(v) for v in ort.__version__.split(".")) - v21, v22, v23 = tuple(int(v) for v in ver.split(".")) - - return (v11 < v21) or (v11 == v21 and v12 < v22) or ((v11, v12) == (v21, v22) and v13 < v23) - - -@pytest.mark.parametrize("onnx_test", onnx_test_folders) -@tvm.testing.parametrize_targets -def test_onnx_nodes(target, dev, onnx_test): - """test_onnx_nodes""" - if platform.machine() == "aarch64" and onnx_test == "test_resize_upsample_sizes_nearest": - pytest.skip("Currently failing on AArch64") - - target_kind = tvm.target.Target(target).kind.name - - if onnx_test in unsupported_onnx_tests: - pytest.skip(f"Onnx test '{onnx_test}' not yet supported by TVM") - - target_specific_skips = target_skips.get(target_kind, []) - if onnx_test in target_specific_skips: - pytest.skip(f"Onnx test '{onnx_test}' not yet supported by TVM on {target_kind} targets") - - if is_ort_version_lower_than("1.13.1") and onnx_test == "test_convtranspose_autopad_same": - pytest.skip( - f"Onnx test '{onnx_test}' expected to fail for onnxruntime version lower than 1.13.1 " - "due to different interpretation of auto_pad parameters SAME_UPPER and SAME_LOWER." - ) - - test_dir = os.path.join(onnx_test_node_dir, onnx_test) - - atol = 1e-5 - rtol = 1e-5 - if "roialign" in test_dir: - # for some reason the ONNX test crops the - # roialign results to 4 decimal places - atol = 1e-4 - - if "to_BFLOAT16" in test_dir: - # the tolerance here is for the comparison in uint16 space, but is not as significant - # of a delta in bfloat16 space because it's representing the mantissa being off by 1 - atol = 1 - - if "_sce_" in test_dir: - # complicated loss functions like SoftmaxCrossEntropy can have minor variations - # in accuracy depending on implementation - atol = 1e-4 - - if "bicubic" in test_dir: - # satisfies onnx precision for bicubic interpolation - atol = 1e-4 - - if "dft" in test_dir: - atol = 1e-3 - - model = onnx.load(os.path.join(test_dir, "model.onnx")) - for test_data_dir in glob.glob(os.path.join(test_dir, "test_data_set*")): - inputs = [] - n_inputs = len(glob.glob(os.path.join(test_data_dir, "input_*.pb"))) - for i in range(n_inputs): - input_file = os.path.join(test_data_dir, f"input_{i}.pb") - _load_proto(input_file, inputs, model.graph.input[i].type) - - outputs = [] - n_outputs = len(glob.glob(os.path.join(test_data_dir, "output_*.pb"))) - for i in range(n_outputs): - output_file = os.path.join(test_data_dir, f"output_{i}.pb") - _load_proto(output_file, outputs, model.graph.output[i].type) - - tvm_val = get_tvm_output_with_vm(model, inputs, target, dev) - if len(outputs) == 1: - tvm.testing.assert_allclose(outputs[0], tvm_val, rtol=rtol, atol=atol) - else: - for output, val in zip(outputs, tvm_val): - tvm.testing.assert_allclose(output, val, rtol=rtol, atol=atol) - - -def test_wrong_input(): - """test_wrong_input""" - node = helper.make_node( - "Softplus", - inputs=["X"], - outputs=["Y"], - ) - - graph = helper.make_graph( - [node], - "softplus_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, list([5]))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list([5]))], - ) - model = helper.make_model(graph, producer_name="softplus_test") - - # Check that the graph can import correctly with proper shape definitions. - correct_shape_dict = {"X": [5]} - relay.frontend.from_onnx(model, shape=correct_shape_dict) - - # Check that an assertion is triggered when an input not in the graph is provided. - wrong_shape_dict = {"Z": [5]} - with pytest.raises(AssertionError): - relay.frontend.from_onnx(model, shape=wrong_shape_dict) - - -@pytest.mark.skip(reason="unsupported op numel") -@tvm.testing.parametrize_targets -def test_aten(target, dev): - """test_aten""" - torch.set_grad_enabled(False) - - def _convert_to_onnx(model, inputs): - file_name = "aten_model.onnx" - torch.onnx.export( - model, - inputs, - file_name, - export_params=True, - verbose=False, - opset_version=10, - operator_export_type=torch.onnx.OperatorExportTypes.ONNX_ATEN, - ) - onnx_model = onnx.load(file_name) - return onnx_model - - def verify_embedding_bag(num_embedding, embedding_dim, data_shape, num_bags=None): - dummy_data = torch.randint(0, num_embedding - 1, data_shape) - tvm_inputs = [dummy_data.numpy()] - model = torch.nn.EmbeddingBag(num_embedding, embedding_dim) - onnx_model = _convert_to_onnx(model, dummy_data) - torch_out = model(dummy_data) - tvm_out = get_tvm_output_with_vm( - onnx_model, - tvm_inputs, - freeze_params=True, - target=target, - dev=dev, - ) - tvm.testing.assert_allclose(torch_out.numpy(), tvm_out, atol=5e-7) - - verify_embedding_bag(10, 3, [2, 10]) - verify_embedding_bag(32, 2, [3, 3]) - - -@tvm.testing.parametrize_targets -def test_index_put(target, dev): - """test_index_put""" - - class IndexPutModel(torch.nn.Module): - def __init__(self, indices, values, accumulate): - super().__init__() - self.indices = indices - self.values = values - self.accumulate = accumulate - - def forward(self, x): - return x.index_put(self.indices, self.values, self.accumulate) - - def _convert_to_onnx(model, dummy_data): - file_name = "aten_model.onnx" - torch.onnx.export( - model, - dummy_data, - file_name, - export_params=True, - verbose=False, - opset_version=11, - operator_export_type=torch.onnx.OperatorExportTypes.ONNX_ATEN_FALLBACK, - ) - onnx_model = onnx.load(file_name) - return onnx_model - - def verify_index_put(data_shape, indices, accumulate): - dummy_data = torch.ones(data_shape) - tvm_inputs = [dummy_data.numpy()] - values = torch.rand(indices[0].size()) - model = IndexPutModel(indices, values, accumulate) - onnx_model = _convert_to_onnx(model, dummy_data) - torch_out = model(dummy_data) - - tvm_out = get_tvm_output_with_vm(onnx_model, tvm_inputs, target, dev, freeze_params=True) - tvm.testing.assert_allclose(torch_out.numpy(), tvm_out) - - shape = (3, 5) - xidx = torch.tensor([0, 1, 2, 2]) - yidx = torch.tensor([0, 1, 3, 4]) - verify_index_put(shape, [xidx, yidx], True) - - shape = (3, 5, 3) - xidx = torch.tensor([0, 1, 2, 2, 0]) - yidx = torch.tensor([0, 1, 3, 4, 0]) - zidx = torch.tensor([0, 1, 1, 2, 0]) - verify_index_put(shape, [xidx, yidx, zidx], False) - - def verify_index_put_slice(data_shape, value_shape, accumulate): - dummy_data = torch.ones(data_shape) - tvm_inputs = [dummy_data.numpy()] - indices = [] - index_shape = [1] * len(value_shape) - index_shape[0] = -1 - for _, v_shape in enumerate(value_shape): - indices.append(torch.arange(0, v_shape).reshape(tuple(index_shape))) - index_shape.pop() - values = torch.rand(value_shape) - - model = IndexPutModel(indices, values, accumulate) - onnx_model = _convert_to_onnx(model, dummy_data) - torch_out = model(dummy_data) - - tvm_out = get_tvm_output_with_vm(onnx_model, tvm_inputs, target, dev, freeze_params=True) - tvm.testing.assert_allclose(torch_out.numpy(), tvm_out) - - verify_index_put_slice((3, 3), (2, 2), False) - verify_index_put_slice((2, 3, 4), (1, 2, 3), True) - verify_index_put_slice((2, 3, 4, 5), (1, 2, 3, 1), False) - - -@tvm.testing.parametrize_targets -def test_reverse_sequence(target, dev): - """test_reverse_sequence""" - - def verify_reverse_sequence(x, sequence_lens, batch_axis, time_axis): - node = onnx.helper.make_node( - "ReverseSequence", - inputs=["x", "sequence_lens"], - outputs=["y"], - time_axis=time_axis, - batch_axis=batch_axis, - ) - - graph = helper.make_graph( - [node], - "reverse_sequence_test", - inputs=[ - helper.make_tensor_value_info("x", TensorProto.FLOAT, list(x.shape)), - helper.make_tensor_value_info( - "sequence_lens", TensorProto.INT64, list(sequence_lens.shape) - ), - ], - outputs=[helper.make_tensor_value_info("y", TensorProto.FLOAT, list(x.shape))], - ) - - model = helper.make_model(graph, producer_name="reverse_sequence_test") - verify_with_ort_with_inputs(model, [x, sequence_lens], [x.shape], target=target, dev=dev) - - x = np.array( - [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]], - dtype=np.float32, - ) - sequence_lens = np.array([1, 2, 3, 4], dtype=np.int64) - verify_reverse_sequence(x, sequence_lens, 0, 1) - - sequence_lens = np.array([4, 3, 2, 1], dtype=np.int64) - verify_reverse_sequence(x, sequence_lens, 1, 0) - - -@pytest.mark.parametrize("op_name", ["Gelu", "FastGelu"], scope="session") -@pytest.mark.parametrize("data_type", ["float16", "float32"], scope="session") -@tvm.testing.parametrize_targets -def test_gelu(target, dev, data_type, op_name): - """test_gelu""" - dtype = np.dtype(data_type) - tensor_type = mapping.NP_TYPE_TO_TENSOR_TYPE[dtype] - absolute_tolerance = 1e-3 if data_type == "float16" else 1e-5 - - def verify_gelu(x): - node = onnx.helper.make_node( - op_name, - inputs=["x"], - outputs=["y"], - domain="com.microsoft", - ) - - graph = helper.make_graph( - [node], - f"{op_name}_test", - inputs=[helper.make_tensor_value_info("x", tensor_type, list(x.shape))], - outputs=[helper.make_tensor_value_info("y", tensor_type, list(x.shape))], - ) - - model = helper.make_model(graph, producer_name=f"{op_name}_test") - verify_with_ort_with_inputs( - model, [x], [x.shape], atol=absolute_tolerance, dtype=data_type, target=target, dev=dev - ) - - x = np.array([-1.0, 0, 1.0, 100.0, -100.0, 1000.0, -1000.0], dtype=dtype) - verify_gelu(x) - x = np.array([[1, 2], [3, 4]], dtype=dtype) - verify_gelu(x) - - -@pytest.mark.parametrize("op_name", ["BiasGelu", "FastGelu"], scope="session") -@pytest.mark.parametrize("data_type", ["float16", "float32"], scope="session") -@tvm.testing.parametrize_targets -def test_biasgelu(target, dev, data_type, op_name): - """test_biasgelu""" - dtype = np.dtype(data_type) - tensor_type = mapping.NP_TYPE_TO_TENSOR_TYPE[dtype] - absolute_tolerance = 1e-2 if data_type == "float16" else 1e-5 - - def verify_biasgelu(x, bias): - node = onnx.helper.make_node( - op_name, - inputs=["x", "bias"], - outputs=["y"], - domain="com.microsoft", - ) - - graph = helper.make_graph( - [node], - f"{op_name}_test", - inputs=[ - helper.make_tensor_value_info("x", tensor_type, list(x.shape)), - helper.make_tensor_value_info("bias", tensor_type, list(bias.shape)), - ], - outputs=[helper.make_tensor_value_info("y", tensor_type, list(x.shape))], - ) - - model = helper.make_model(graph, producer_name=f"{op_name}_test") - verify_with_ort_with_inputs( - model, - [x, bias], - [x.shape], - atol=absolute_tolerance, - dtype=data_type, - target=target, - dev=dev, - ) - - x = np.array([-1.0, 0, 1.0, 100.0, -100.0, 1000.0, -1000.0], dtype=dtype) - bias = np.repeat(2.0, 7).astype(dtype) - verify_biasgelu(x, bias) - - x = np.array([[1, 2], [3, 4]], dtype=dtype) - bias = np.array([0.3, 4.0], dtype=dtype) - verify_biasgelu(x, bias) - - -@tvm.testing.parametrize_targets -def test_embedlayernormalization(target, dev): - """test_embedlayernormalization""" - - def verify_embedlayernormalization( - input_ids, - segment_ids, - word_embedding, - position_embedding, - segment_embedding, - gamma, - beta, - ): - node = onnx.helper.make_node( - "EmbedLayerNormalization", - inputs=[ - "input_ids", - "" if segment_ids is None else "segment_ids", - "word_embedding", - "position_embedding", - "" if segment_embedding is None else "segment_embedding", - "gamma", - "beta", - ], - outputs=["output", "mask_index"], - domain="com.microsoft", - ) - - node.attribute.append(onnx.helper.make_attribute("epsilon", 1e-4)) - - segment_ids_shape = [] if segment_ids is None else segment_ids.shape - segment_embedding_shape = [] if segment_embedding is None else segment_embedding.shape - - graph = helper.make_graph( - [node], - "embedlayernormalization_test", - inputs=[ - helper.make_tensor_value_info( - "input_ids", TensorProto.INT32, list(input_ids.shape) - ), - helper.make_tensor_value_info("segment_ids", TensorProto.INT32, segment_ids_shape), - helper.make_tensor_value_info( - "word_embedding", TensorProto.FLOAT, list(word_embedding.shape) - ), - helper.make_tensor_value_info( - "position_embedding", TensorProto.FLOAT, list(position_embedding.shape) - ), - helper.make_tensor_value_info( - "segment_embedding", TensorProto.FLOAT, segment_embedding_shape - ), - helper.make_tensor_value_info("gamma", TensorProto.FLOAT, list(gamma.shape)), - helper.make_tensor_value_info("beta", TensorProto.FLOAT, list(beta.shape)), - ], - outputs=[ - helper.make_tensor_value_info( - "output", TensorProto.FLOAT, list((batch_size, sequence_length, hidden_size)) - ), - helper.make_tensor_value_info("mask_index", TensorProto.INT32, [batch_size]), - ], - ) - - model = helper.make_model(graph, producer_name="embedlayernormalization_test") - - # TODO(@anwang2009): onnxruntime v1.9.0 requires empty list for optional argument, - # but v1.10.0+ requires None instead. - verify_with_ort_with_inputs( - model, - [ - input_ids, - np.empty(0, dtype="int32") if segment_ids is None else segment_ids, - word_embedding, - position_embedding, - np.empty(0, dtype="float32") if segment_embedding is None else segment_embedding, - gamma, - beta, - ], - [ - (batch_size, sequence_length, hidden_size), - batch_size, - ], - target=target, - dev=dev, - rtol=1e-4, - atol=1e-4, - ) - - hidden_size = 384 - batch_size = 4 - sequence_length = 3 - vocab_size = 5 - - input_ids = np.full((batch_size, sequence_length), 3).astype("int32") - segment_ids = np.zeros((batch_size, sequence_length)).astype("int32") - word_embedding = np.full((vocab_size, hidden_size), 1).astype("float32") - position_embedding = np.full((sequence_length, hidden_size), 2).astype("float32") - segment_embedding = np.full((vocab_size, hidden_size), 3).astype("float32") - - gamma = np.random.uniform(0.5, 0.7, hidden_size).astype("float32") - beta = np.random.randn(hidden_size).astype("float32") * 0.1 - - verify_embedlayernormalization( - input_ids, segment_ids, word_embedding, position_embedding, segment_embedding, gamma, beta - ) - - # Test with undefined segment embedding - verify_embedlayernormalization( - input_ids, None, word_embedding, position_embedding, None, gamma, beta - ) - - -@tvm.testing.parametrize_targets -def test_attention(target, dev): - """test_attention""" - - def verify_attention(_unidirectional, _input, _weight, _bias, _mask_index=None, _past=None): - input_names = ["input", "weight", "bias"] - if _mask_index is not None: - input_names.append("mask_index") - if _past is not None: - input_names.append("past") - - node = onnx.helper.make_node( - "Attention", - inputs=input_names, - outputs=["output", "present"], - domain="com.microsoft", - num_heads=num_heads, - unidirectional=_unidirectional, - ) - - past_shape = (2, batch_size, num_heads, past_sequence_length, head_size) - present_output_shape = (2, batch_size, num_heads, sequence_length, head_size) - - inputs_info = [ - helper.make_tensor_value_info("input", TensorProto.FLOAT, list(_input.shape)), - helper.make_tensor_value_info("weight", TensorProto.FLOAT, list(_weight.shape)), - helper.make_tensor_value_info("bias", TensorProto.FLOAT, list(_bias.shape)), - ] - if _mask_index is not None: - inputs_info.append( - helper.make_tensor_value_info( - "mask_index", TensorProto.INT32, list(_mask_index.shape) - ), - ) - if _past is not None: - inputs_info.append( - helper.make_tensor_value_info("past", TensorProto.FLOAT, list(past_shape)) - ) - - graph = helper.make_graph( - [node], - "attention_test", - inputs=inputs_info, - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(_input.shape)), - helper.make_tensor_value_info( - "present", TensorProto.FLOAT, list(present_output_shape) - ), - ], - ) - - model = helper.make_model(graph, producer_name="attention_test") - - inputs = [_input, _weight, _bias] - if _mask_index is not None: - inputs.append(_mask_index) - if _past is not None: - inputs.append(_past) - - # "present" output should be nullptr when the "past" input isn't included, - # but ort requires an output shape to be specified? - verify_with_ort_with_inputs( - model, - inputs, - [_input.shape, present_output_shape], - target=target, - dev=dev, - rtol=1e-4, - atol=1e-4, - ) - - batch_size = 11 - num_heads = 13 - head_size = 37 - sequence_length = 7 - input_hidden_size = 147 - weight_hidden_size = num_heads * head_size - past_sequence_length = 17 - - total_sequence_length = past_sequence_length + sequence_length - - # Required inputs - input_array = np.random.normal(size=(batch_size, sequence_length, input_hidden_size)).astype( - "float32" - ) - weight = ( - np.random.normal(size=(input_hidden_size, 3 * weight_hidden_size)).astype("float32") * 0.1 - ) - bias = np.random.randn(3 * weight_hidden_size).astype("float32") - - # Optional inputs - past = np.random.random((2, batch_size, num_heads, past_sequence_length, head_size)).astype( - "float32" - ) - - for unidirectional in [0, 1]: - for have_past in [False, True]: - if not have_past: - mask_index = np.random.randint(0, 2, (batch_size, sequence_length)).astype("int32") - verify_attention(unidirectional, input_array, weight, bias, mask_index) - else: - mask_index = np.random.randint(0, 2, (batch_size, total_sequence_length)).astype( - "int32" - ) - verify_attention(unidirectional, input_array, weight, bias, mask_index, past) - - -@tvm.testing.parametrize_targets -def test_qattention(target, dev): - """test_qattention""" - - def verify_attention( - _unidirectional, - _input, - _weight, - _bias, - _input_scale, - _weight_scale, - _mask_index=None, - _input_zero_point=None, - _weight_zero_point=None, - _past=None, - ): - input_names = ["input", "weight", "bias", "input_scale", "weight_scale"] - if _mask_index is not None: - input_names.append("mask_index") - if _input_zero_point is not None: - input_names.append("input_zero_point") - if _weight_zero_point is not None: - input_names.append("weight_zero_point") - if _past is not None: - input_names.append("past") - - node = onnx.helper.make_node( - "QAttention", - inputs=input_names, - outputs=["output", "present"], - domain="com.microsoft", - num_heads=num_heads, - unidirectional=_unidirectional, - ) - - past_shape = (2, batch_size, num_heads, past_sequence_length, head_size) - present_output_shape = ( - 2, - batch_size, - num_heads, - past_sequence_length + sequence_length, - head_size, - ) - - inputs_info = [ - helper.make_tensor_value_info("input", TensorProto.UINT8, list(_input.shape)), - helper.make_tensor_value_info("weight", TensorProto.UINT8, list(_weight.shape)), - helper.make_tensor_value_info("bias", TensorProto.FLOAT, list(_bias.shape)), - helper.make_tensor_value_info("input_scale", TensorProto.FLOAT, ()), - helper.make_tensor_value_info("weight_scale", TensorProto.FLOAT, ()), - ] - if _mask_index is not None: - inputs_info.append( - helper.make_tensor_value_info( - "mask_index", TensorProto.INT32, list(_mask_index.shape) - ) - ) - if _input_zero_point is not None: - inputs_info.append( - helper.make_tensor_value_info("input_zero_point", TensorProto.UINT8, ()) - ) - if _weight_zero_point is not None: - inputs_info.append( - helper.make_tensor_value_info("weight_zero_point", TensorProto.UINT8, ()) - ) - if _past is not None: - inputs_info.append( - helper.make_tensor_value_info("past", TensorProto.FLOAT, list(past_shape)) - ) - - graph = helper.make_graph( - [node], - "qattention_test", - inputs=inputs_info, - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(_input.shape)), - helper.make_tensor_value_info( - "present", TensorProto.FLOAT, list(present_output_shape) - ), - ], - ) - - model = helper.make_model(graph, producer_name="qattention_test") - - inputs = [_input, _weight, _bias, _input_scale, _weight_scale] - if _mask_index is not None: - inputs.append(_mask_index) - if _input_zero_point is not None: - inputs.append(_input_zero_point) - if _weight_zero_point is not None: - inputs.append(_weight_zero_point) - if _past is not None: - inputs.append(_past) - - verify_with_ort_with_inputs( - model, - inputs, - [_input.shape, present_output_shape], - target=target, - dev=dev, - rtol=1e-3, - atol=1e-3, - ) - - batch_size = 11 - num_heads = 13 - head_size = 37 - sequence_length = 7 - input_hidden_size = 147 - weight_hidden_size = num_heads * head_size - past_sequence_length = 17 - - total_sequence_length = past_sequence_length + sequence_length - - # Required inputs - input_array = np.random.randint( - 0, 255, (batch_size, sequence_length, input_hidden_size) - ).astype("uint8") - weight = np.random.randint(0, 255, (input_hidden_size, 3 * weight_hidden_size)).astype("uint8") - bias = np.random.randn(3 * weight_hidden_size).astype("float32") - input_scale = np.random.random(1).astype("float32") - weight_scale = np.random.random(1).astype("float32") - - # Optional inputs - input_zero_point = np.random.randint(0, 255, 1).astype("uint8") - weight_zero_point = np.random.randint(0, 255, 1).astype("uint8") - past = np.random.random((2, batch_size, num_heads, past_sequence_length, head_size)).astype( - "float32" - ) - - for unidirectional in [0, 1]: - for have_past in [False, True]: - if not have_past: - mask_index = np.random.randint(0, 2, (batch_size, sequence_length)).astype("int32") - - verify_attention( - unidirectional, - input_array, - weight, - bias, - input_scale, - weight_scale, - mask_index, - ) - verify_attention( - unidirectional, - input_array, - weight, - bias, - input_scale, - weight_scale, - mask_index, - input_zero_point, - ) - verify_attention( - unidirectional, - input_array, - weight, - bias, - input_scale, - weight_scale, - mask_index, - input_zero_point, - weight_zero_point, - ) - else: - mask_index = np.random.randint(0, 2, (batch_size, total_sequence_length)).astype( - "int32" - ) - - verify_attention( - unidirectional, - input_array, - weight, - bias, - input_scale, - weight_scale, - mask_index, - input_zero_point, - weight_zero_point, - past, - ) - - -@tvm.testing.parametrize_targets -def test_skiplayernormalization(target, dev): - """test_skiplayernormalization""" - - def verify_skiplayernormalization(input_, skip, gamma, beta, bias): - node = onnx.helper.make_node( - "SkipLayerNormalization", - inputs=["input", "skip", "gamma", "beta", "bias"], - outputs=["output"], - domain="com.microsoft", - ) - - node.attribute.append(onnx.helper.make_attribute("epsilon", 1e-4)) - - graph = helper.make_graph( - [node], - "skiplayernormalization_test", - inputs=[ - helper.make_tensor_value_info("input", TensorProto.FLOAT, list(input_.shape)), - helper.make_tensor_value_info("skip", TensorProto.FLOAT, list(skip.shape)), - helper.make_tensor_value_info("gamma", TensorProto.FLOAT, list(gamma.shape)), - helper.make_tensor_value_info("beta", TensorProto.FLOAT, list(beta.shape)), - helper.make_tensor_value_info("bias", TensorProto.FLOAT, list(bias.shape)), - ], - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, list(input_.shape)), - ], - ) - - model = helper.make_model(graph, producer_name="skiplayernormalization_test") - verify_with_ort_with_inputs( - model, [input_, skip, gamma, beta, bias], [input_.shape], target=target, dev=dev - ) - - hidden_size = 384 - batch_size = 4 - sequence_length = 4 - - dtype = "float32" - input_array = np.random.random((batch_size, sequence_length, hidden_size)).astype(dtype) - skip = np.random.random((batch_size, sequence_length, hidden_size)).astype(dtype) - gamma = np.random.uniform(0.5, 0.7, hidden_size).astype(dtype) - beta = np.random.randn(hidden_size).astype(dtype) * 0.1 - bias = np.random.randn(hidden_size).astype(dtype) - - verify_skiplayernormalization(input_array, skip, gamma, beta, bias) - - -@tvm.testing.known_failing_targets("cuda") -@tvm.testing.parametrize_targets -def test_qgemm(target, dev): - """test_qgemm""" - - def verify_qgemm( - a_shape, - b_shape, - y_shape, - C=False, - y_zp=False, - b_per_tensor_quantization=False, - alpha=1.0, - transA=0, - transB=1, - ): - a_array = np.random.randint(low=0, high=255, size=a_shape).astype("uint8") - b_array = np.random.uniform(low=0, high=255, size=b_shape).astype("uint8") - - input_nodes = [ - helper.make_tensor_value_info("a", TensorProto.UINT8, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.UINT8, list(b_shape)), - ] - - initializer = [ - helper.make_tensor("a_scale", TensorProto.FLOAT, (), [np.random.rand()]), - helper.make_tensor("a_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)]), - ] - - input_names = [ - "a", - "a_scale", - "a_zero_point", - "b", - "b_scale", - "b_zero_point", - ] - input_values = [a_array, b_array] - - if b_per_tensor_quantization: - initializer.append( - helper.make_tensor("b_scale", TensorProto.FLOAT, (), [np.random.rand()]) - ) - initializer.append( - helper.make_tensor( - "b_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)] - ) - ) - else: # per_colume_quantization - shape_value = b_shape[0] if transB else b_shape[1] - b_scale_array = np.random.random(shape_value).astype("float32") - w_zero_point_array = np.random.randint(0, 255, size=shape_value).astype("uint8") - initializer.append( - helper.make_tensor( - "b_scale", TensorProto.FLOAT, list(b_scale_array.shape), b_scale_array - ) - ) - initializer.append( - helper.make_tensor( - "b_zero_point", - TensorProto.UINT8, - list(w_zero_point_array.shape), - w_zero_point_array, - ) - ) - - output_tensor = helper.make_tensor_value_info("output", TensorProto.FLOAT, list(y_shape)) - - if C is True: - C_shape = (b_shape[0] if transB else b_shape[1],) - C_array = np.random.randint(low=0, high=65536, size=C_shape).astype("int32") - input_nodes.append(helper.make_tensor_value_info("C", TensorProto.INT32, list(C_shape))) - input_names.append("C") - input_values.append(C_array) - - if y_zp is True: - input_names.append("y_scale") - initializer.append( - helper.make_tensor("y_scale", TensorProto.FLOAT, (), [np.random.rand()]) - ) - - input_names.append("y_zero_point") - initializer.append( - helper.make_tensor( - "y_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)] - ) - ) - - output_tensor = helper.make_tensor_value_info( - "output", TensorProto.UINT8, list(y_shape) - ) - - kwargs = {} - kwargs["alpha"] = alpha - kwargs["transA"] = transA - kwargs["transB"] = transB - - node = helper.make_node( - "QGemm", - inputs=input_names, - outputs=["output"], - domain="com.microsoft", - # Default values for other attributes: - **kwargs, - ) - - graph = helper.make_graph( - [node], - "QGemm", - inputs=input_nodes, - outputs=[output_tensor], - initializer=initializer, - ) - model = helper.make_model( - graph, - producer_name="QGemm", - opset_imports=[ - onnx.helper.make_opsetid("com.microsoft", 1), - ], - ) - - verify_with_ort_with_inputs(model, input_values, target=target, dev=dev) - - # B per tensor quantization - verify_qgemm( - (20, 30), - (50, 30), - (20, 50), - True, - True, - True, - ) - - # B per column quantization - verify_qgemm( - (20, 30), - (50, 30), - (20, 50), - True, - True, - False, - ) - - # test alpha - verify_qgemm( - (20, 30), - (50, 30), - (20, 50), - True, - True, - True, - 0.5, - ) - - # test transpose A - verify_qgemm( - (20, 50), - (20, 80), - (50, 80), - True, - True, - True, - 0.5, - 1, - 0, - ) - - -@tvm.testing.known_failing_targets("cuda") -@tvm.testing.parametrize_targets -def test_qlinearconv(target, dev): - """test_qlinearconv""" - - def verify_qlinearconv( - x_shape, - w_shape, - y_shape, - padding, - kernel_shape, - strides, - dilations, - auto_pad="NOTSET", - bias=False, - per_channel_quantization=False, - ): - - x_array = np.random.randint(low=0, high=255, size=x_shape).astype("uint8") - w_array = np.random.uniform(low=0, high=255, size=w_shape).astype("uint8") - - initializer = [ - helper.make_tensor("x_scale", TensorProto.FLOAT, (), [np.random.rand()]), - helper.make_tensor("x_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)]), - helper.make_tensor("y_scale", TensorProto.FLOAT, (), [np.random.rand()]), - helper.make_tensor("y_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)]), - ] - - input_nodes = [ - helper.make_tensor_value_info("x", TensorProto.UINT8, list(x_shape)), - helper.make_tensor_value_info("w", TensorProto.UINT8, list(w_shape)), - ] - input_names = [ - "x", - "x_scale", - "x_zero_point", - "w", - "w_scale", - "w_zero_point", - "y_scale", - "y_zero_point", - ] - input_values = [x_array, w_array] - - if per_channel_quantization: - w_scale_array = np.random.random(w_shape[0]).astype("float32") - w_zero_point_array = np.random.randint(0, 255, size=w_shape[0]).astype("uint8") - - initializer.append( - helper.make_tensor("w_scale", TensorProto.FLOAT, [w_shape[0]], w_scale_array) - ) - initializer.append( - helper.make_tensor( - "w_zero_point", TensorProto.UINT8, [w_shape[0]], w_zero_point_array - ) - ) - else: - initializer.append( - helper.make_tensor("w_scale", TensorProto.FLOAT, (), [np.random.rand()]) - ) - initializer.append( - helper.make_tensor( - "w_zero_point", TensorProto.UINT8, (), [np.random.randint(0, 255)] - ) - ) - - if bias is True: - b_shape = w_shape[0:1] - b_array = np.random.randint(low=0, high=65536, size=b_shape).astype("int32") - input_nodes.append(helper.make_tensor_value_info("B", TensorProto.INT32, list(b_shape))) - input_names.append("B") - input_values.append(b_array) - - if padding is None: - ## autopadding with unset default attributes - kwargs = {} - if not all(list(s == 1 for s in strides)): - kwargs["strides"] = strides - if not all(list(d == 1 for d in dilations)): - kwargs["dilations"] = dilations - - node = helper.make_node( - "QLinearConv", - inputs=input_names, - outputs=["y"], - # Default values for other attributes: - auto_pad=auto_pad, - **kwargs, - ) - else: - node = helper.make_node( - "QLinearConv", - inputs=input_names, - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - # groups=1 - pads=padding, - ) - - graph = helper.make_graph( - [node], - "conv_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("y", TensorProto.UINT8, list(y_shape))], - initializer=initializer, - ) - model = helper.make_model(graph, producer_name="qlinearconv_test") - # opt_level=1 will cause error - verify_with_ort_with_inputs(model, input_values, opt_level=2, target=target, dev=dev) - - def repeat(num, dims): - return tuple(num for _ in range(dims)) - - # only support QLinearConv2d because only support qnn.conv2d - dims = 2 - - # Convolution with padding - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - - # Convolution with bias - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - bias=True, - ) - - # Convolution with asymmetric padding - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(4, dims), - repeat(0, dims) + repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution without padding - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution with autopadding - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with valid autopadding - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="VALID", - ) - # Convolution with non uniform stride - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with dilation - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(2, dims), - repeat(3, dims), - repeat(1, dims), - repeat(2, dims), - ) - # Convolution with per channel quantization - verify_qlinearconv( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - per_channel_quantization=True, - ) - - -# TODO(vvchernov): fix problem with quantization on cuda -@tvm.testing.known_failing_targets("cuda") -@tvm.testing.parametrize_targets -def test_qlinearmatmul(target, dev): - """test_qlinearmatmul""" - - def verify_qlinearmatmul( - x_shape, - w_shape, - y_shape, - x_dtype="uint8", - w_dtype="uint8", - ): - def get_randint_numpy_scalar(dtype="uint8"): - if dtype == "uint8": - return np.random.randint(0, 255) - else: # "int8" - return np.random.randint(-128, 127) - - if x_dtype == "uint8": - x_array = np.random.randint(low=0, high=255, size=x_shape).astype("uint8") - else: # "int8" - x_array = np.random.randint(low=-128, high=127, size=x_shape).astype("int8") - if w_dtype == "uint8": - w_array = np.random.uniform(low=0, high=255, size=w_shape).astype("uint8") - else: # "int8" - w_array = np.random.uniform(low=-128, high=127, size=w_shape).astype("int8") - - x_proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(x_dtype)] - w_proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(w_dtype)] - - y_dtype = "int8" - if x_dtype == "uint8" and w_dtype == "uint8": - y_dtype = "uint8" - y_proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(y_dtype)] - - initializer = [ - helper.make_tensor("x_scale", TensorProto.FLOAT, (), [np.random.rand()]), - # TODO: 0 value for int8? - helper.make_tensor( - "x_zero_point", x_proto_type, (), [get_randint_numpy_scalar(x_dtype)] - ), - helper.make_tensor("w_scale", TensorProto.FLOAT, (), [np.random.rand()]), - # TODO: 0 value for int8? - helper.make_tensor( - "w_zero_point", w_proto_type, (), [get_randint_numpy_scalar(w_dtype)] - ), - helper.make_tensor("y_scale", TensorProto.FLOAT, (), [np.random.rand()]), - helper.make_tensor( - "y_zero_point", y_proto_type, (), [get_randint_numpy_scalar(y_dtype)] - ), - ] - - input_nodes = [ - helper.make_tensor_value_info("x", x_proto_type, list(x_shape)), - helper.make_tensor_value_info("w", w_proto_type, list(w_shape)), - ] - input_names = [ - "x", - "x_scale", - "x_zero_point", - "w", - "w_scale", - "w_zero_point", - "y_scale", - "y_zero_point", - ] - input_values = [x_array, w_array] - - node = helper.make_node( - "QLinearMatMul", - inputs=input_names, - outputs=["y"], - ) - - y_proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype("int8")] - if x_dtype == "uint8" and w_dtype == "uint8": - y_proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype("uint8")] - - graph = helper.make_graph( - [node], - "qmatmul_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("y", y_proto_type, list(y_shape))], - initializer=initializer, - ) - model = helper.make_model(graph, producer_name="qlinearmatmul_test") - # opt_level=1 will cause error - verify_with_ort_with_inputs(model, input_values, opt_level=2, target=target, dev=dev) - - # Default matmul both ranks = 2 (x_dtype = "uint8", w_dtype = "uint8") - verify_qlinearmatmul((2, 3), (3, 2), (2, 2)) - - # Default matmul both ranks = 2 (x_dtype = "int8", w_dtype = "int8") - verify_qlinearmatmul((2, 3), (3, 2), (2, 2), "int8", "int8") - - # TODO(vvchernov): problems on ONNX Runtime side and type check (onnx.py:L4763) on TVM side - # Default matmul both ranks = 2 (x_dtype = "uint8", w_dtype = "int8") - # verify_qlinearmatmul((2, 3), (3, 2), (2, 2), "uint8", "int8") - - # TODO(vvchernov): problems on ONNX Runtime side and type check (onnx.py:L4763) on TVM side - # Default matmul both ranks = 2 (x_dtype = "int8", w_dtype = "uint8") - # verify_qlinearmatmul((2, 3), (3, 2), (2, 2), "int8", "uint8") - - # Reduced matmul: x_ranks = 1, w_rank = 2 (x_dtype = "uint8", w_dtype = "uint8") - verify_qlinearmatmul((3,), (3, 2), (2,)) - - # Special case matmul: x_ranks = 3, w_rank = 2 (x_dtype = "uint8", w_dtype = "uint8") - verify_qlinearmatmul((2, 3, 4), (4, 3), (2, 3, 3)) - - # GPT2-style matmul both ranks = 4 (x_dtype = "uint8", w_dtype = "uint8") - verify_qlinearmatmul((2, 4, 3, 3), (2, 4, 3, 3), (2, 4, 3, 3)) - - # Asymetric matmul: x_ranks = 4, w_rank = 3 (x_dtype = "uint8", w_dtype = "uint8") - verify_qlinearmatmul((2, 4, 3, 3), (4, 3, 3), (2, 4, 3, 3)) - - # Asymetric matmul: x_ranks = 2, w_rank = 3 (x_dtype = "uint8", w_dtype = "uint8") - # verify_qlinearmatmul((3, 3), (4, 3, 3), (4, 3, 3)) - - -@tvm.testing.parametrize_targets -def test_qlinearconcat(target, dev): - """test_qlinearconcat""" - - def verify_qlinearconcat(shapes, out_shape, axis=None): - input_names = [] - input_values = [] - input_nodes = [] - for i, shape in enumerate(shapes): - tensor_name = chr(ord("a") + i) - node = helper.make_tensor_value_info(tensor_name, TensorProto.FLOAT, list(shape)) - - input_names.append(tensor_name) - input_values.append(np.random.random(shape).astype("float32")) - input_nodes.append(node) - - node = helper.make_node("Concat", input_names, ["C"]) - if axis is not None: - axis_attr = helper.make_attribute("axis", axis) - node.attribute.append(axis_attr) - graph = helper.make_graph( - [node], - "qlinearconcat_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("C", TensorProto.FLOAT, list(out_shape))], - ) - model = helper.make_model(graph, producer_name="qlinearconcat_test") - quantize_and_verify_with_ort(model, input_names, shapes, target, dev) - - verify_qlinearconcat([[2, 1], [2, 1]], [4, 1], 0) - verify_qlinearconcat([[2, 1], [2, 1]], [2, 2], 1) - verify_qlinearconcat([[1, 2], [2, 2], [3, 2]], [6, 2], 0) - - -@tvm.testing.parametrize_targets -def test_qlinearadd(target, dev): - """test_qlinearadd""" - - def verify_qlinearadd(a_shape, b_shape, c_shape): - - _ = np.random.random(a_shape).astype("float32") - _ = np.random.random(b_shape).astype("float32") - - input_nodes = [ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ] - input_names = [ - "a", - "b", - ] - - node = helper.make_node("Add", ["a", "b"], ["C"]) - graph = helper.make_graph( - [node], - "qlinearadd_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("C", TensorProto.FLOAT, list(c_shape))], - ) - model = helper.make_model(graph, producer_name="qlinearadd_test") - quantize_and_verify_with_ort(model, input_names, [a_shape, b_shape], target, dev) - - verify_qlinearadd([4, 2], [4, 2], [4, 2]) - verify_qlinearadd([4, 2], [2], [4, 2]) - verify_qlinearadd([5, 1, 7], [2, 7], [5, 2, 7]) - - -@tvm.testing.parametrize_targets -def test_qlinearmul(target, dev): - """test_qlinearmul""" - - def verify_qlinearmul(a_shape, b_shape, c_shape): - - _ = np.random.random(a_shape).astype("float32") - _ = np.random.random(b_shape).astype("float32") - - input_nodes = [ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - helper.make_tensor_value_info("b", TensorProto.FLOAT, list(b_shape)), - ] - input_names = [ - "a", - "b", - ] - - node = helper.make_node("Mul", input_names, ["C"]) - graph = helper.make_graph( - [node], - "qlinearmul_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("C", TensorProto.FLOAT, list(c_shape))], - ) - model = helper.make_model(graph, producer_name="qlinearmul_test") - quantize_and_verify_with_ort(model, input_names, [a_shape, b_shape], target, dev) - - verify_qlinearmul([7], [7], [7]) - verify_qlinearmul([4, 2], [4, 2], [4, 2]) - verify_qlinearmul([4, 2], [2], [4, 2]) - verify_qlinearmul([5, 1, 7], [2, 7], [5, 2, 7]) - - -@pytest.mark.skip(reason="See https://github.com/apache/tvm/issues/11375") -@tvm.testing.parametrize_targets -def test_qlinearleakyrelu(target, dev): - """test_qlinearleakyrelu""" - - def verify_qlinearleakyrelu(inshape, kwargs): - - in_array = np.random.random(inshape).astype("float32") - node = helper.make_node("LeakyRelu", ["X"], ["Y"], **kwargs) - - graph = helper.make_graph( - [node], - "qlinearRelu_test", - inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, list(in_array.shape))], - outputs=[helper.make_tensor_value_info("Y", TensorProto.FLOAT, list(in_array.shape))], - ) - model = helper.make_model(graph, producer_name="qlinearRelu_test") - args = (model, ["X"], [in_array.shape], target, dev) - if dev == "cuda": - quantize_and_verify_with_ort(*args, rtol=1e-2, atol=1e-2) - else: - quantize_and_verify_with_ort(*args) - - verify_qlinearleakyrelu([2, 4, 5, 6], {"alpha": 0.25}) - verify_qlinearleakyrelu([6, 5, 6, 7], {"alpha": 0.35}) - verify_qlinearleakyrelu([5, 1, 4, 6], {"alpha": 0.65}) - - -@pytest.mark.skip(reason="See https://github.com/apache/tvm/issues/11375") -@tvm.testing.parametrize_targets -def test_qlinearsigmoid(target, dev): - """test_qlinearsigmoid""" - - def verify_qlinearsigmoid(a_shape): - - _ = np.random.random(a_shape).astype("float32") - - input_nodes = [helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape))] - - node = helper.make_node("Sigmoid", ["a"], ["B"]) - graph = helper.make_graph( - [node], - "qlinearsigmoid_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("B", TensorProto.FLOAT, list(a_shape))], - ) - model = helper.make_model(graph, producer_name="qlinearsigmoid_test") - quantize_and_verify_with_ort(model, ["a"], [a_shape], target, dev) - - verify_qlinearsigmoid([4, 2]) - verify_qlinearsigmoid([5]) - verify_qlinearsigmoid([3, 4, 5]) - verify_qlinearsigmoid([]) - - -@tvm.testing.parametrize_targets -def test_qlinearsoftmax(target, dev): - """test_qlinearsoftmax""" - - def verify_qlinearsoftmax(a_shape): - - _ = np.random.random(a_shape).astype("float32") - - input_nodes = [helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape))] - - node = helper.make_node("Softmax", ["a"], ["B"]) - graph = helper.make_graph( - [node], - "qlinearsoftmax_test", - inputs=input_nodes, - outputs=[helper.make_tensor_value_info("B", TensorProto.FLOAT, list(a_shape))], - ) - model = helper.make_model(graph, producer_name="qlinearsoftmax_test") - quantize_and_verify_with_ort(model, ["a"], [a_shape], target, dev) - - verify_qlinearsoftmax([4, 2]) - verify_qlinearsoftmax([5]) - verify_qlinearsoftmax([3, 4, 5]) - - -@tvm.testing.parametrize_targets("llvm") -def test_random_bernoulli(target, dev): - """test_random_bernoulli""" - - def _get_tvm_output( - inputs, - out_dtype="int32", - seed=None, - target=target, - dev=dev, - use_vm=False, - freeze_params=False, - ): - def get_bernoulli_model(shape, in_dtype="float32", out_dtype="int32", seed=None): - onnx_itype = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(in_dtype)] - onnx_otype = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(out_dtype)] - node = helper.make_node( - "Bernoulli", - ["input"], - ["output"], - ) - dtype_attr = helper.make_attribute("dtype", onnx_otype) - node.attribute.append(dtype_attr) - if seed is not None: - seed_attr = helper.make_attribute("seed", float(seed)) - node.attribute.append(seed_attr) - - graph = helper.make_graph( - [node], - "random_bernoulli_test", - inputs=[helper.make_tensor_value_info("input", onnx_itype, list(shape))], - outputs=[helper.make_tensor_value_info("output", onnx_otype, list(shape))], - ) - return helper.make_model(graph, producer_name="random_bernoulli_test") - - shape = inputs.shape - in_dtype = inputs.dtype - model = get_bernoulli_model(shape, in_dtype, out_dtype, seed) - - if use_vm: - return get_tvm_output_with_vm( - model, - inputs, - target, - dev, - freeze_params=freeze_params, - ) - else: - return get_tvm_output( - model, - inputs, - target, - dev, - ) - - def binom_test(input, ideal_mean, threshold=0.05): - # This test is strictly appropriate when input probabilities are all identical. - # In that case, it should lead to flaky failures in only one run in a million (p>=1e-6). - # The test should be over-conservative when input probabilities are not identical. - # (i.e., It should have a rate of flaky failures lower than one run in a million.) - # If this test starts repeatedly throwing flaky failures, consult a statistician - # in addition to your regular debugging. - bnm_test_res = scipy.stats.binomtest( - k=np.sum(input, dtype="int32"), n=len(input), p=ideal_mean - ) - return bnm_test_res.pvalue > threshold - - def verify_bernoulli( - inputs=None, - shape=[], - in_dtype="float32", - out_dtype="int32", - seed=None, - target=target, - dev=dev, - use_vm=False, - freeze_params=False, - in_out_equal=False, - ): - if inputs is None: - assert len(shape) != 0 - inputs = np.random.uniform(size=shape).astype(in_dtype) - - tvm_out = _get_tvm_output( - inputs, - out_dtype, - seed, - target, - dev, - use_vm, - freeze_params, - ) - - if isinstance(tvm_out, list): - tvm_out = tvm_out[0] - # check that values are 0 or 1 - tvm_flat = tvm_out.flatten() - assert np.array_equal(tvm_flat, tvm_flat.astype("bool")) - if in_out_equal: - tvm.testing.assert_allclose(inputs, tvm_out) - else: - # check that mean value is close to the theoretical one by binomial test - ideal_mean = np.mean(inputs) - repeats = 3 - check = False - for i in range(repeats): - if binom_test(tvm_flat, ideal_mean): - check = True - break - else: - # repeat with new seed - seed = np.random.randint(1e6) - tvm_flat = _get_tvm_output( - inputs, - out_dtype, - seed, - target, - dev, - use_vm, - freeze_params, - ).flatten() - assert check, "Binomial test failed" - - # Test input sequence of 0 and 1 - inputs = np.random.randint(2, size=[10000]).astype("float32") - verify_bernoulli(inputs, in_out_equal=True) - - # Binomial test input with 0.5 values - val_num = 10000 - inputs = np.ones([val_num], dtype="float32") * 0.5 - verify_bernoulli(inputs) - - # Binomial test input with 0.1 values - inputs = np.ones([val_num], dtype="float32") * 0.1 - verify_bernoulli(inputs) - - # Simple test - verify_bernoulli(shape=[val_num]) - - # Floating output type - verify_bernoulli(shape=[val_num], out_dtype="float32") - - # Double input type - verify_bernoulli(shape=[val_num], in_dtype="float64") - - # Test N-D tensor generation - verify_bernoulli(shape=[2, 4, 100, 100]) - - # Test with seed - verify_bernoulli(shape=[val_num], seed=np.random.randint(1e6)) - - # Test result determinism with the same seeds - inputs = np.random.uniform(size=[val_num]) - fixed_seed = np.random.randint(1e6) - tvm_out_1 = _get_tvm_output(inputs, seed=fixed_seed) - tvm_out_2 = _get_tvm_output(inputs, seed=fixed_seed) - tvm.testing.assert_allclose(tvm_out_1, tvm_out_2) - - -@tvm.testing.parametrize_targets("llvm") -def test_random_uniform(target, dev): - """test_random_uniform""" - - def get_random_uniform(shape, dtype="float32", high=1.0, low=0.0, seed=None): - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - node = helper.make_node( - "RandomUniform", [], ["out"], shape=shape, dtype=ONNX_DTYPE, high=high, low=low - ) - if seed is not None: - seed_attr = helper.make_attribute("seed", seed) - node.attribute.append(seed_attr) - - graph = helper.make_graph( - [node], - "random_uniform_test", - inputs=[], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, shape)], - ) - model = helper.make_model(graph, producer_name="random_uniform_test") - return get_tvm_output_with_vm( - model, - [], - target=target, - dev=dev, - validate_structural_equal=(seed is not None), - ) - - # Check that function runs and produces proper shape. - vals = get_random_uniform([10], dtype="float32") - assert list(vals.shape) == [10] - assert vals.dtype == "float32" - - # Test N-D tensor generation. - vals = get_random_uniform([1, 3, 100, 100], dtype="float32") - assert list(vals.shape) == [1, 3, 100, 100] - - # Check that bounds aren't exceeded. - vals = get_random_uniform(shape=[100], high=100.0, low=-100.0) - assert list(vals.shape) == [100] - assert all(vals >= -100) and all(vals <= 100) - - # Check that a fixed seed produces the same values when run twice. - vals_1 = get_random_uniform(shape=[10], seed=1) - vals_2 = get_random_uniform(shape=[10], seed=1) - assert all(vals_1 == vals_2) - - # Test against an expected output with a fixed seed. - real = get_random_uniform(shape=[10], seed=5.0) - expected = np.asarray( - [ - 0.043976, - 0.96656, - 0.292199, - 0.904297, - 0.25167, - 0.521778, - 0.778985, - 0.085463, - 0.939846, - 0.194201, - ] - ) - tvm.testing.assert_allclose(real, expected, rtol=1e-5) - - -@tvm.testing.parametrize_targets("llvm") -def test_random_uniform_like(target, dev): - """test_random_uniform_like""" - - def get_random_uniform_like(input_, shape, dtype=None, high=1.0, low=0.0, seed=None): - node = helper.make_node("RandomUniformLike", ["in"], ["out"], high=high, low=low) - if seed is not None: - seed_attr = helper.make_attribute("seed", seed) - node.attribute.append(seed_attr) - - ONNX_DTYPE = None - if dtype is not None: - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - dtype_attr = helper.make_attribute("dtype", ONNX_DTYPE) - node.attribute.append(dtype_attr) - else: - dtype = input_.dtype - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - - graph = helper.make_graph( - [node], - "random_uniform_test", - inputs=[helper.make_tensor_value_info("in", ONNX_DTYPE, shape)], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, shape)], - ) - model = helper.make_model(graph, producer_name="random_uniform_like_test") - return get_tvm_output_with_vm( - model, - [input_], - target=target, - dev=dev, - validate_structural_equal=(seed is not None), - ) - - # Check that function runs and produces proper shape and dtype. - shape = [10] - input_array = np.random.random(shape).astype("float32") - vals = get_random_uniform_like(input_array, shape, dtype="float32") - assert list(vals.shape) == [10] - assert vals.dtype == "float32" - - # Test N-D tensor generation. - shape = [1, 3, 100, 100] - input_array = np.random.random(shape).astype("float32") - vals = get_random_uniform_like(input_array, shape, dtype="float64") - assert list(vals.shape) == shape - assert vals.dtype == "float64" - - # Check that bounds aren't exceeded. - shape = [100] - input_array = np.random.random(shape).astype("float64") - vals = get_random_uniform_like(input_array, shape, high=100.0, low=-100.0) - assert list(vals.shape) == shape - assert all(vals >= -100) and all(vals <= 100) - - # Test against an expected output with a fixed seed. - shape = [10] - input_array = np.random.random(shape).astype("float32") - real = get_random_uniform_like(input_array, shape=[10], seed=5.0) - expected = np.asarray( - [ - 0.043976, - 0.96656, - 0.292199, - 0.904297, - 0.25167, - 0.521778, - 0.778985, - 0.085463, - 0.939846, - 0.194201, - ] - ) - tvm.testing.assert_allclose(real, expected, rtol=1e-5) - - -@tvm.testing.parametrize_targets("llvm") -def test_random_normal(target, dev): - """test_random_normal""" - - def get_random_normal(shape, dtype="float32", scale=1.0, mean=0.0, seed=None): - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - node = helper.make_node( - "RandomNormal", [], ["out"], shape=shape, dtype=ONNX_DTYPE, scale=scale, mean=mean - ) - if seed is not None: - seed_attr = helper.make_attribute("seed", seed) - node.attribute.append(seed_attr) - - graph = helper.make_graph( - [node], - "random_normal_test", - inputs=[], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, shape)], - ) - model = helper.make_model(graph, producer_name="random_normal_test") - return get_tvm_output_with_vm( - model, - [], - target=target, - dev=dev, - validate_structural_equal=(seed is not None), - ) - - # Test N-D tensor generation. - vals = get_random_normal([1, 3, 100, 100], dtype="float32") - assert list(vals.shape) == [1, 3, 100, 100] - tvm.testing.assert_allclose(vals.mean(), 0.0, rtol=0.1, atol=0.1) - tvm.testing.assert_allclose(np.std(vals), 1.0, rtol=0.1, atol=0.1) - - # Test mean=2.0 scale=10.0 - vals = get_random_normal([1, 3, 100, 100], mean=2.0, scale=10.0, dtype="float32") - assert list(vals.shape) == [1, 3, 100, 100] - tvm.testing.assert_allclose(vals.mean(), 2.0, rtol=0.1, atol=0.1) - tvm.testing.assert_allclose(np.std(vals), 10.0, rtol=0.1, atol=0.1) - - # Check that a fixed seed produces the same values when run twice. - vals_1 = get_random_normal(shape=[10], seed=1.0) - vals_2 = get_random_normal(shape=[10], seed=1.0) - assert all(vals_1 == vals_2) - - -@tvm.testing.parametrize_targets("llvm") -def test_random_normal_like(target, dev): - """test_random_normal_like""" - - def get_random_normal_like(input_, shape, dtype="float32", scale=1.0, mean=0.0, seed=None): - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - node = helper.make_node( - "RandomNormalLike", ["in"], ["out"], dtype=ONNX_DTYPE, scale=scale, mean=mean - ) - if seed is not None: - seed_attr = helper.make_attribute("seed", seed) - node.attribute.append(seed_attr) - - graph = helper.make_graph( - [node], - "random_normal_like_test", - inputs=[helper.make_tensor_value_info("in", ONNX_DTYPE, shape)], - outputs=[helper.make_tensor_value_info("out", ONNX_DTYPE, shape)], - ) - model = helper.make_model(graph, producer_name="random_normal_like_test") - return get_tvm_output_with_vm( - model, - [input_], - target=target, - dev=dev, - validate_structural_equal=(seed is not None), - ) - - # Test N-D tensor generation. - shape = [1, 3, 100, 100] - input_array = np.random.random(shape).astype("float32") - vals = get_random_normal_like(input_array, [1, 3, 100, 100], dtype="float32") - assert list(vals.shape) == [1, 3, 100, 100] - tvm.testing.assert_allclose(vals.mean(), 0.0, rtol=0.1, atol=0.1) - tvm.testing.assert_allclose(np.std(vals), 1.0, rtol=0.1, atol=0.1) - - # Test mean=2.0 scale=10.0 - shape = [1, 3, 100, 100] - input_array = np.random.random(shape).astype("float32") - vals = get_random_normal_like( - input_array, [1, 3, 100, 100], mean=2.0, scale=10.0, dtype="float32" - ) - assert list(vals.shape) == [1, 3, 100, 100] - tvm.testing.assert_allclose(vals.mean(), 2.0, rtol=0.1, atol=0.1) - tvm.testing.assert_allclose(np.std(vals), 10.0, rtol=0.1, atol=0.1) - - -@tvm.testing.parametrize_targets("llvm") -def test_multinomial(target, dev): - def get_multinomial(input, shape, sample_size, seed=None): - IN_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype("float32")] - OUT_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype("int32")] - node = helper.make_node("Multinomial", ["in"], ["out"], sample_size=sample_size) - if seed is not None: - seed_attr = helper.make_attribute("seed", seed) - node.attribute.append(seed_attr) - - graph = helper.make_graph( - [node], - "multinomial_test", - inputs=[helper.make_tensor_value_info("in", IN_DTYPE, shape)], - outputs=[helper.make_tensor_value_info("out", OUT_DTYPE, shape)], - ) - model = helper.make_model(graph, producer_name="multinomial_test") - return get_tvm_output_with_vm( - model, - [input], - target=target, - dev=dev, - validate_structural_equal=(seed is not None), - ) - - # Test N-D tensor generation. - shape = [3] - sample_size = 2 - probs = np.random.random(shape).astype("float32") - indices = get_multinomial(probs, shape, sample_size) - # Since specific values are random, we'll check that the output shape is - # correct and the values chosen are all valid indices. - assert list(indices.shape) == [sample_size] - assert np.max(indices) < shape[-1] - - # Test 2d multinomial - shape = [10, 5] - sample_size = 4 - probs = np.random.random(shape).astype("float32") - indices = get_multinomial(probs, shape, sample_size) - assert list(indices.shape) == [10, sample_size] - assert np.max(indices) < shape[-1] - - -@tvm.testing.parametrize_targets -def test_convinteger(target, dev): - """test_convinteger""" - - def verify_convinteger( - x_shape, - w_shape, - y_shape, - padding, - kernel_shape, - strides, - dilations, - auto_pad="NOTSET", - dtype="uint8", - ): - x_array = np.random.randint(low=0, high=255, size=x_shape).astype(dtype) - w_array = np.random.uniform(low=0, high=255, size=w_shape).astype(dtype) - x_zero_point_array = np.random.randint(0, 255, size=[1]).astype(dtype) - w_zero_point_array = np.random.randint(0, 255, size=[1]).astype(dtype) - - ONNX_DTYPE = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)] - input_nodes = [ - helper.make_tensor_value_info("x", ONNX_DTYPE, list(x_shape)), - helper.make_tensor_value_info("w", ONNX_DTYPE, list(w_shape)), - ] - initializer = [ - helper.make_tensor("x_zero_point", ONNX_DTYPE, [], x_zero_point_array), - helper.make_tensor("w_zero_point", ONNX_DTYPE, [], w_zero_point_array), - ] - input_names = ["x", "w", "x_zero_point", "w_zero_point"] - input_values = [x_array, w_array] - - if padding is None: - ## autopadding with unset default attributes - kwargs = {} - if not all(list(s == 1 for s in strides)): - kwargs["strides"] = strides - if not all(list(d == 1 for d in dilations)): - kwargs["dilations"] = dilations - - node = helper.make_node( - "ConvInteger", - inputs=input_names, - outputs=["y"], - # Default values for other attributes: - auto_pad=auto_pad, - **kwargs, - ) - else: - node = helper.make_node( - "ConvInteger", - inputs=input_names, - outputs=["y"], - kernel_shape=kernel_shape, - # Default values for other attributes: - strides=strides, - dilations=dilations, - # groups=1 - pads=padding, - ) - - graph = helper.make_graph( - [node], - "convinteger_test", - inputs=input_nodes, - initializer=initializer, - outputs=[helper.make_tensor_value_info("y", TensorProto.INT32, list(y_shape))], - ) - model = helper.make_model(graph, producer_name="convinteger_test") - # opt_level=1 will cause error - verify_with_ort_with_inputs(model, input_values, target=target, dev=dev, opt_level=2) - - def repeat(num, dims): - return tuple(num for _ in range(dims)) - - # only support 2D ConvInteger because we only support qnn.conv2d for now. - dims = 2 - - # Convolution with padding - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - - # Convolution with asymmetric padding - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(4, dims), - repeat(0, dims) + repeat(1, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution without padding - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - 2 * repeat(0, dims), - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - ) - # Convolution with autopadding - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with valid autopadding - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(1, dims), - repeat(1, dims), - auto_pad="VALID", - ) - # Convolution with non uniform stride - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(3, dims), - None, - repeat(3, dims), - repeat(2, dims), - repeat(1, dims), - auto_pad="SAME_UPPER", - ) - # Convolution with dilation - verify_convinteger( - (1, 1) + repeat(5, dims), - (1, 1) + repeat(3, dims), - (1, 1) + repeat(5, dims), - 2 * repeat(2, dims), - repeat(3, dims), - repeat(1, dims), - repeat(2, dims), - ) - - -@tvm.testing.parametrize_targets -def test_bitshift(target, dev): - """test_bitshift""" - - def verify_bitshift(in_shape, shift_shape, high=1000000000, in_dtype="uint64"): - in_shape = list(in_shape) - shift_shape = list(shift_shape) - - # Create an input for each tensor. - tensor_values = [ - np.random.randint(high, size=in_shape).astype(in_dtype), - np.random.randint(16, size=shift_shape).astype(in_dtype), - np.random.randint(16, size=shift_shape).astype(in_dtype), - ] - - bitshift_left_node = helper.make_node( - "BitShift", - inputs=["input", "shift_left"], - outputs=["shifted"], - direction="LEFT", - ) - - bitshift_right_node = helper.make_node( - "BitShift", - inputs=["shifted", "shift_right"], - outputs=["output"], - direction="RIGHT", - ) - - # Create input and output tensors. - proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(in_dtype)] - graph_inputs = [ - helper.make_tensor_value_info("input", proto_type, in_shape), - helper.make_tensor_value_info("shift_left", proto_type, shift_shape), - helper.make_tensor_value_info("shift_right", proto_type, shift_shape), - ] - - graph_outputs = [helper.make_tensor_value_info("output", proto_type, in_shape)] - - graph_nodes = [bitshift_left_node, bitshift_right_node] - - graph = helper.make_graph( - graph_nodes, - "BitShift_test", - inputs=graph_inputs, - outputs=graph_outputs, - ) - model = helper.make_model( - graph, - producer_name="BitShift_test", - ) - - verify_with_ort_with_inputs(model, tensor_values, target=target, dev=dev) - - shape = (100, 4, 2) - broadcast_shape = (100, 1, 1) - # Common bitwise test - verify_bitshift(shape, shape) - # Bitwise test with broadcasting - verify_bitshift(shape, broadcast_shape) - - -# TODO(vvchernov): return test back than ONNX Runtime in CI will support domain version of 18 -@pytest.mark.skip("Currently ONNX Runtime in CI does not support domain version of 18") -@tvm.testing.parametrize_targets -def test_bitwise(target, dev): - """test_bitwise""" - - def verify_bitwise_ops(A_shape, B_shape, C_shape, D_shape, high=128, in_dtype="int32"): - A_shape = list(A_shape) - B_shape = list(B_shape) - C_shape = list(C_shape) - D_shape = list(D_shape) - - # Create an input for each tensor. - tensor_values = [ - np.random.randint(high, size=A_shape).astype(in_dtype), - np.random.randint(high, size=B_shape).astype(in_dtype), - np.random.randint(high, size=C_shape).astype(in_dtype), - np.random.randint(high, size=D_shape).astype(in_dtype), - ] - - or_node = helper.make_node( - "BitwiseOr", - inputs=["A", "B"], - outputs=["OR"], - ) - - and_node = helper.make_node( - "BitwiseAnd", - inputs=["OR", "C"], - outputs=["AND"], - ) - - xor_node = helper.make_node( - "BitwiseXor", - inputs=["AND", "D"], - outputs=["XOR"], - ) - - not_node = helper.make_node( - "BitwiseNot", - inputs=["XOR"], - outputs=["output"], - ) - - # Create input and output tensors. - proto_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(in_dtype)] - graph_inputs = [ - helper.make_tensor_value_info("A", proto_type, A_shape), - helper.make_tensor_value_info("B", proto_type, B_shape), - helper.make_tensor_value_info("C", proto_type, C_shape), - helper.make_tensor_value_info("D", proto_type, D_shape), - ] - - graph_outputs = [ - helper.make_tensor_value_info("output", proto_type, A_shape), - ] - - graph_nodes = [ - or_node, - and_node, - xor_node, - not_node, - ] - - graph = helper.make_graph( - graph_nodes, - "Bitwise_test", - inputs=graph_inputs, - outputs=graph_outputs, - ) - model = helper.make_model( - graph, - producer_name="Bitwise_test", - ) - - verify_with_ort_with_inputs(model, tensor_values, target=target, dev=dev) - - shape = (100, 4, 2) - broadcast_shape = (100, 1, 1) - dtypes = ["int8", "uint8", "int32", "uint32"] - high_vals = [128, 128, 2147483648, 2147483648] - for high, dtype in zip(high_vals, dtypes): - # Common bitwise test - verify_bitwise_ops(shape, shape, shape, shape, high, dtype) - # Bitwise test with broadcasting - verify_bitwise_ops(shape, broadcast_shape, broadcast_shape, broadcast_shape, high, dtype) - - -@tvm.testing.parametrize_targets -def test_scan(target, dev): - """test_scan""" - - def verify_scan( - input_shapes, - output_shapes, - num_scan_inputs, - scan_input_axes, - scan_input_directions, - scan_output_axes, - scan_output_directions, - opset, - ): - - body_input_shapes = copy.deepcopy(input_shapes) - num_state_inputs = len(input_shapes) - num_scan_inputs - - if opset == 8: - for i in range(len(input_shapes)): - body_input_shapes[i].pop(0) - for i in range(num_state_inputs, len(input_shapes)): - body_input_shapes[i].pop(0) - else: - for i in range(num_state_inputs, len(input_shapes)): - body_input_shapes[i].pop(scan_input_axes[i - num_state_inputs]) - - initial0 = onnx.helper.make_tensor_value_info( - "initial0", onnx.TensorProto.FLOAT, body_input_shapes[0] - ) - initial1 = onnx.helper.make_tensor_value_info( - "initial1", onnx.TensorProto.FLOAT, body_input_shapes[1] - ) - input0 = onnx.helper.make_tensor_value_info( - "input0", onnx.TensorProto.FLOAT, body_input_shapes[2] - ) - input1 = onnx.helper.make_tensor_value_info( - "input1", onnx.TensorProto.FLOAT, body_input_shapes[3] - ) - input2 = onnx.helper.make_tensor_value_info( - "input2", onnx.TensorProto.FLOAT, body_input_shapes[4] - ) - state0 = onnx.helper.make_tensor_value_info( - "state0", onnx.TensorProto.FLOAT, body_input_shapes[0] - ) - scan_out0 = onnx.helper.make_tensor_value_info( - "scan_out0", onnx.TensorProto.FLOAT, body_input_shapes[0] - ) - state1 = onnx.helper.make_tensor_value_info( - "state1", onnx.TensorProto.FLOAT, body_input_shapes[1] - ) - scan_out1 = onnx.helper.make_tensor_value_info( - "scan_out1", onnx.TensorProto.FLOAT, body_input_shapes[1] - ) - add_node = onnx.helper.make_node( - "Add", - inputs=["initial0", "input0"], - outputs=["state0"], - ) - id_node_0 = onnx.helper.make_node( - "Identity", - inputs=["state0"], - outputs=["scan_out0"], - ) - matmul_node = onnx.helper.make_node( - "MatMul", - inputs=["input1", "input2"], - outputs=["matmul_out"], - ) - sub_node = onnx.helper.make_node( - "Sub", - inputs=["initial1", "matmul_out"], - outputs=["state1"], - ) - id_node_1 = onnx.helper.make_node( - "Identity", - inputs=["state1"], - outputs=["scan_out1"], - ) - scan_body = onnx.helper.make_graph( - [add_node, id_node_0, matmul_node, sub_node, id_node_1], - "scan_body", - [initial0, initial1, input0, input1, input2], - [state0, state1, scan_out0, scan_out1], - ) - # create scan op node - scan_node = None - if opset == 8: - scan_node = onnx.helper.make_node( - "Scan", - inputs=["", "init0", "init1", "in0", "in1", "in2"], - outputs=["s0", "s1", "scan0", "scan1"], - num_scan_inputs=num_scan_inputs, - body=scan_body, - ) - else: - scan_node = onnx.helper.make_node( - "Scan", - inputs=["init0", "init1", "in0", "in1", "in2"], - outputs=["s0", "s1", "scan0", "scan1"], - num_scan_inputs=num_scan_inputs, - body=scan_body, - scan_input_axes=scan_input_axes, - scan_input_directions=scan_input_directions, - scan_output_axes=scan_output_axes, - scan_output_directions=scan_output_directions, - ) - input_info = [ - helper.make_tensor_value_info("init0", TensorProto.FLOAT, input_shapes[0]), - helper.make_tensor_value_info("init1", TensorProto.FLOAT, input_shapes[1]), - helper.make_tensor_value_info("in0", TensorProto.FLOAT, input_shapes[2]), - helper.make_tensor_value_info("in1", TensorProto.FLOAT, input_shapes[3]), - helper.make_tensor_value_info("in2", TensorProto.FLOAT, input_shapes[4]), - ] - out_info = [ - helper.make_tensor_value_info("s0", TensorProto.FLOAT, output_shapes[0]), - helper.make_tensor_value_info("s1", TensorProto.FLOAT, output_shapes[1]), - helper.make_tensor_value_info("scan0", TensorProto.FLOAT, output_shapes[2]), - helper.make_tensor_value_info("scan1", TensorProto.FLOAT, output_shapes[3]), - ] - graph = helper.make_graph( - nodes=[scan_node], - name="scan_test", - inputs=input_info, - outputs=out_info, - ) - model = onnx.helper.make_model(graph, producer_name="scan-test") - init0 = np.random.uniform(low=0, high=255, size=input_shapes[0]).astype(np.float32) - init1 = np.random.uniform(low=0, high=255, size=input_shapes[1]).astype(np.float32) - in0 = np.random.uniform(low=0, high=255, size=input_shapes[2]).astype(np.float32) - in1 = np.random.uniform(low=0, high=255, size=input_shapes[3]).astype(np.float32) - in2 = np.random.uniform(low=0, high=255, size=input_shapes[4]).astype(np.float32) - input_values = [init0, init1, in0, in1, in2] - - verify_with_ort_with_inputs( - model, - input_values, - target=target, - dev=dev, - opt_level=2, - use_vm=True, - opset=opset, - ) - - # opset 8 - input_shapes = [[2, 6, 7, 8], [2, 3, 3], [2, 5, 6, 7, 8], [2, 5, 3, 4], [2, 5, 4, 3]] - output_shapes = [[2, 6, 7, 8], [2, 3, 3], [2, 5, 6, 7, 8], [2, 5, 3, 3]] - # input_shapes, output_shapes, num_scan_inputs, scan_input_axes, scan_input_directions, - # scan_output_axes, scan_output_directions, opset - verify_scan(input_shapes, output_shapes, 3, [0] * 3, [0] * 3, [0] * 2, [0] * 2, 8) - # opset 9 - input_shapes = [[6, 7, 8], [3, 3], [5, 6, 7, 8], [5, 3, 4], [5, 4, 3]] - output_shapes = [[6, 7, 8], [3, 3], [5, 6, 7, 8], [5, 3, 3]] - verify_scan(input_shapes, output_shapes, 3, [0] * 3, [0] * 3, [0] * 2, [0] * 2, 9) - - input_shapes = [[6, 7, 8], [3, 3], [5, 6, 7, 8], [3, 4, 5], [4, 5, 3]] - output_shapes = [[6, 7, 8], [3, 3], [6, 5, 7, 8], [3, 5, 3]] - verify_scan(input_shapes, output_shapes, 3, [0, 2, 1], [1] * 3, [1] * 2, [1] * 2, 9) - # Negative axes - input_shapes = [[6, 7, 8], [3, 3], [5, 6, 7, 8], [3, 4, 5], [4, 5, 3]] - output_shapes = [[6, 7, 8], [3, 3], [6, 5, 7, 8], [3, 5, 3]] - verify_scan(input_shapes, output_shapes, 3, [-4, -1, -2], [1] * 3, [-3, -2], [1] * 2, 9) - - -@tvm.testing.parametrize_targets -def test_linear_regressor(target, dev): - """test_linear_regressor""" - - def verify_linear_regressor(a_shape, c_shape, i_shape, targets=1, batch=1): - a_array = np.random.uniform(size=a_shape).astype("float32") - out_shape = (batch, targets) - - coefficients = np.random.uniform(size=c_shape).astype("float32") - intercepts = np.random.uniform(size=i_shape).astype("float32") - - mul_node = helper.make_node( - "LinearRegressor", - ["a"], - ["out"], - coefficients=coefficients, - intercepts=intercepts, - targets=targets, - domain="ai.onnx.ml", - ) - - graph = helper.make_graph( - [mul_node], - "LinearRegressor_test", - inputs=[ - helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape)), - ], - outputs=[helper.make_tensor_value_info("out", TensorProto.FLOAT, out_shape)], - ) - model = helper.make_model( - graph, - producer_name="LinearRegressor_test", - opset_imports=[ - onnx.helper.make_opsetid("ai.onnx.ml", 1), - ], - ) - verify_with_ort_with_inputs(model, [a_array], target=target, dev=dev) - - verify_linear_regressor((1, 3), (3), (1)) - verify_linear_regressor((2, 10), (10), (1), batch=2) - verify_linear_regressor((1, 3), (30), (10), targets=10) - verify_linear_regressor((10, 3), (30), (10), targets=10, batch=10) - verify_linear_regressor((1, 4), (3), (1)) - - -@tvm.testing.parametrize_targets -def test_dft(target, dev): - """test_dft""" - - def verify_dft( - _axis, - _inverse, - _onesided, - _dft_length, - _input_shape, - _output_shape, - ): - input_names = ["input"] - if _dft_length is not None: - input_names.append("dft_length") - - node = onnx.helper.make_node( - "DFT", - inputs=input_names, - outputs=["output"], - axis=_axis, - inverse=_inverse, - onesided=_onesided, - ) - - nodes = [] - if _dft_length is not None: - nodes.append( - make_constant_node("dft_length", TensorProto.INT32, [], [_dft_length]), - ) - nodes.append(node) - - graph = helper.make_graph( - nodes, - "dft_test", - inputs=[ - helper.make_tensor_value_info("input", TensorProto.FLOAT, _input_shape), - ], - outputs=[ - helper.make_tensor_value_info("output", TensorProto.FLOAT, _output_shape), - ], - ) - - model = helper.make_model(graph, producer_name="dft_test") - - _input = np.random.normal(size=_input_shape).astype("float32") - verify_with_ort_with_inputs( - model, - [_input], - [_input_shape], - target=target, - dev=dev, - rtol=1e-4, - atol=1e-4, - use_vm=False, - ) - - batch_size = 5 - n = 2 - D = 7 - - for axis in list(range(1, n)) + [-2]: - for inverse, onesided in [(0, 0), (0, 1), (1, 0), (None, None)]: - for n_fft in [D, D - 1, D + 1]: - for c in [1, 2]: - input_shape = [batch_size] + n * [D] + [c] - output_shape = [batch_size] + n * [D] + [2] - if onesided == 1: - output_shape[axis] = output_shape[axis] // 2 + 1 - verify_dft(axis, inverse, onesided, n_fft, input_shape, output_shape) - - -@tvm.testing.parametrize_targets -def test_sequence(target, dev): - """test_sequence""" - - def verify_sequence_ops(tensor_shape, num_tensors, axis=0, position=0, new_axis=None): - tensor_shape = list(tensor_shape) - tensor_values = [] - for i in range(num_tensors): - tensor_values.append(np.random.uniform(size=tensor_shape).astype("float32")) - - # Create an input for each tensor. - input_tensor_names = [] - for i in range(num_tensors): - name = f"input_tensor_{i}" - input_tensor_names.append(name) - - # Test creating a tensor sequence. - construct_node = helper.make_node( - "SequenceConstruct", - inputs=input_tensor_names, - outputs=["sequence"], - ) - - position_node = make_constant_node("position", TensorProto.INT32, (), [position]) - - # Test sequence insertion. - insert_node = helper.make_node( - "SequenceInsert", - inputs=["sequence", input_tensor_names[0], "position"], - outputs=["inserted_sequence"], - ) - - # Test sequence erase. - erase_node = helper.make_node( - "SequenceErase", - inputs=["inserted_sequence", "position"], - outputs=["erased_sequence"], - ) - - # Test sequence concatenation. - concat_node = helper.make_node( - "ConcatFromSequence", - inputs=["erased_sequence"], - outputs=["concat_sequence"], - axis=axis, - ) - - # Test splitting a tensor into a sequence. - split_node = helper.make_node( - "SplitToSequence", inputs=["concat_sequence"], outputs=["split_sequence"], axis=axis - ) - - # Test tensor extraction from sequence - at_node = helper.make_node( - "SequenceAt", inputs=["split_sequence", "position"], outputs=["output"] - ) - - # Test sequence length - length_node = helper.make_node( - "SequenceLength", inputs=["split_sequence"], outputs=["output_2"] - ) - - if new_axis is not None: - new_axis_attr = helper.make_attribute("new_axis", new_axis) - concat_node.attribute.append(new_axis_attr) - - # Create input and output tensors. - graph_inputs = [] - for name in input_tensor_names: - input_tensor = helper.make_tensor_value_info(name, TensorProto.FLOAT, tensor_shape) - graph_inputs.append(input_tensor) - - # Construct output tensor. - output_shape = tensor_shape - if new_axis is not None: - output_shape.insert(axis, 1) - output_shape[axis] = num_tensors + 1 - else: - output_shape[axis] = (num_tensors + 1) * output_shape[axis] - graph_outputs = [ - helper.make_tensor_value_info("output", TensorProto.FLOAT, output_shape), - helper.make_tensor_value_info("output_2", TensorProto.INT64, []), - ] - - graph_nodes = [ - position_node, - construct_node, - insert_node, - erase_node, - concat_node, - split_node, - at_node, - length_node, - ] - - graph = helper.make_graph( - graph_nodes, - "Sequence_test", - inputs=graph_inputs, - outputs=graph_outputs, - ) - model = helper.make_model( - graph, - producer_name="Sequence_test", - ) - - verify_with_ort_with_inputs(model, tensor_values, target=target, dev=dev) - - verify_sequence_ops((10, 3), 2) - verify_sequence_ops((3, 3, 3, 3), 4, position=3) - verify_sequence_ops((3, 3, 3, 3), 4, axis=2) - verify_sequence_ops((3, 3, 3, 3), 4, axis=2, new_axis=1) - - -@tvm.testing.parametrize_targets -def test_empty_sequence(target, dev): - """test_empty_sequence""" - - # Test creating an empty tensor sequence. - empty_node = helper.make_node( - "SequenceEmpty", - inputs=[], - outputs=["empty_sequence"], - ) - - length_node = helper.make_node("SequenceLength", inputs=["empty_sequence"], outputs=["output"]) - - graph_outputs = [helper.make_tensor_value_info("output", TensorProto.INT64, [])] - - graph_nodes = [empty_node, length_node] - - graph = helper.make_graph( - graph_nodes, - "Sequence_empty_test", - inputs=[], - outputs=graph_outputs, - ) - - model = helper.make_model( - graph, - producer_name="Sequence_empty_test", - ) - - verify_with_ort_with_inputs(model, [], target=target, dev=dev) - - -def test_exporting_node_renamed_model(): - """test exproting model when export_node_renamed_model is set""" - - a_name, a_shape = "a", (4, 3) - b_name, b_shape = "b", (3, 4) - out_name, out_shape = "out", [a_shape[0], b_shape[1]] - temp_dir = utils.tempdir().path - - # model definition - mul_node = helper.make_node("MatMul", [a_name, b_name], [out_name]) - graph = helper.make_graph( - [mul_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info(a_name, TensorProto.FLOAT, a_shape), - helper.make_tensor_value_info(b_name, TensorProto.FLOAT, b_shape), - ], - outputs=[helper.make_tensor_value_info(out_name, TensorProto.FLOAT, out_shape)], - ) - model = helper.make_model(graph, producer_name="matmul_test") - - # get frontend model - shape_dict = {a_name: a_shape, b_name: b_shape} - _, _ = relay.frontend.from_onnx(model, shape_dict, export_node_renamed_model_path=temp_dir) - - exported_model_name = os.listdir(temp_dir)[0] - assert "tvm_exported_model_" in exported_model_name - - exported_model = onnx.load(os.path.join(temp_dir, exported_model_name)) - assert exported_model.graph.node[0].name == "MatMul_0" - - -class TestSetSpan: - """test structural equal between translated / hand-crafted relay IR with span tagged.""" - - def _verify(self, res_fptr, golden_fptr): - with tvm.testing.enable_span_filling(): - with_span = res_fptr() - with tvm.testing.disable_span_filling(): - without_span = res_fptr() - tvm.ir.assert_structural_equal(with_span, without_span) - _verify_structural_equal_with_span(with_span, golden_fptr()) - - def test_conv2d_bias_add_span(self): - padding = [0, 0, 0, 0] - k_shape = [7, 7] - y_shape, y_name = [1, 6, 10, 10], "y" - x_shape, x_name = [1, 3, 10, 10], "x" - b_shape, b_name = [6], "b" - b_val = np.random.random(b_shape).astype(np.float32) - w_shape, w_name = [6, 3, 7, 7], "w" - w_val = np.random.random(w_shape).astype(np.float32) - group, strides, dilations = 1, [1, 1], [1, 1] - conv_name = "conv2d" - - def _res(): - # model definition - node = helper.make_node( - "Conv", - inputs=[x_name, w_name, b_name], - outputs=[y_name], - kernel_shape=k_shape, - strides=strides, - dilations=dilations, - group=group, - pads=padding, - name=conv_name, - ) - graph = helper.make_graph( - [node], - "conv_test", - inputs=[helper.make_tensor_value_info(x_name, TensorProto.FLOAT, x_shape)], - outputs=[helper.make_tensor_value_info(y_name, TensorProto.FLOAT, y_shape)], - initializer=[ - helper.make_tensor( - w_name, - TensorProto.FLOAT, - dims=w_shape, - vals=w_val.flatten(), - ), - helper.make_tensor( - b_name, - TensorProto.FLOAT, - dims=b_shape, - vals=b_val.flatten(), - ), - ], - ) - model = helper.make_model(graph, producer_name="conv_test") - - # get frontend model - shape_dict = {x_name: x_shape} - mod, _ = relay.frontend.from_onnx(model, shape_dict) - return mod["main"] - - def _golden(): - conv_si = conv_name - x = relay.var( - x_name, - shape=tuple(x_shape), - span=_create_span(f"{conv_si}.{x_name}"), - ) - conv_weight = relay.const( - w_val, - span=_create_span(f"{conv_si}.{w_name}"), - ) - conv_bias = relay.const( - b_val, - span=_create_span(f"{conv_si}.{b_name}"), - ) - conv_out = _set_span( - relay.nn.conv2d( - x, - conv_weight, - padding=[0] * 4, - channels=y_shape[1], - kernel_size=k_shape, - ), - conv_si, - ) - bias_out = _set_span(relay.nn.bias_add(conv_out, conv_bias), conv_si) - return infer_type(relay.Function([x], bias_out)) - - self._verify(_res, _golden) - - def test_batchnorm_span(self): - input_name, in_shape = "x", [1, 16, 10, 10] - bn_name = "bn" - output_name = "y" - scale_name = "scale" - bias_name = "b" - mean_name = "mean" - var_name = "var" - - def _res(): - # model definition - batchnorm = onnx.helper.make_node( - "BatchNormalization", - inputs=[input_name, scale_name, bias_name, mean_name, var_name], - outputs=[output_name], - name=bn_name, - ) - graph = helper.make_graph( - [batchnorm], - "batchnorm_test", - inputs=[ - helper.make_tensor_value_info(input_name, TensorProto.FLOAT, in_shape), - helper.make_tensor_value_info(scale_name, TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info(bias_name, TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info(mean_name, TensorProto.FLOAT, [in_shape[1]]), - helper.make_tensor_value_info(var_name, TensorProto.FLOAT, [in_shape[1]]), - ], - outputs=[helper.make_tensor_value_info(output_name, TensorProto.FLOAT, in_shape)], - ) - model = helper.make_model(graph, producer_name="batchnorm_test") - - # get frontend model - shape_dict = {input_name: in_shape} - mod, _ = relay.frontend.from_onnx(model, shape_dict) - return mod["main"] - - def _golden(): - bn_si = bn_name - x = relay.var( - input_name, - shape=tuple(in_shape), - span=_create_span(f"{bn_si}.{input_name}"), - ) - bn_scale = relay.var( - scale_name, - shape=(in_shape[1],), - span=_create_span(f"{bn_si}.{scale_name}"), - ) - bn_bias = relay.var( - bias_name, - shape=(in_shape[1],), - span=_create_span(f"{bn_si}.{bias_name}"), - ) - bn_rm = relay.var( - mean_name, - shape=(in_shape[1],), - span=_create_span(f"{bn_si}.{mean_name}"), - ) - bn_rv = relay.var( - var_name, - shape=(in_shape[1],), - span=_create_span(f"{bn_si}.{var_name}"), - ) - bn_out = _set_span( - relay.nn.batch_norm(x, bn_scale, bn_bias, bn_rm, bn_rv), - bn_si, - ) - bn_tuple_get_item = _set_span(relay.TupleGetItem(bn_out.tuple_value, 0), bn_si) - return infer_type( - relay.Function([x, bn_scale, bn_bias, bn_rm, bn_rv], bn_tuple_get_item) - ) - - self._verify(_res, _golden) - - def test_reshape_span(self): - input_shape = [2, 1, 10, 1, 10] - new_shape = [2, 1, 10, 10] - input_name = "in" - output_name = "out" - ref_name = "ref_in" - const_name = "const" - reshape_name = "reshape" - - def _res(): - # model definition - ref_array = np.array(new_shape) - ref_node = helper.make_node( - "Constant", - inputs=[], - outputs=[ref_name], - value=helper.make_tensor( - name="const_tensor", - data_type=TensorProto.INT32, - dims=ref_array.shape, - vals=ref_array.flatten().astype(int), - ), - name=const_name, - ) - reshape_node = helper.make_node( - "Reshape", - [input_name, ref_name], - [output_name], - name=reshape_name, - ) - graph = helper.make_graph( - [ref_node, reshape_node], - "reshape_test", - inputs=[helper.make_tensor_value_info(input_name, TensorProto.FLOAT, input_shape)], - outputs=[helper.make_tensor_value_info(output_name, TensorProto.FLOAT, new_shape)], - ) - model = helper.make_model(graph, producer_name="reshape_test") - - # get frontend model - shape_dict = {input_name: input_shape} - mod, _ = relay.frontend.from_onnx(model, shape_dict) - return mod["main"] - - def _golden(): - reshape_si = reshape_name - x = relay.var( - input_name, - shape=tuple(input_shape), - span=_create_span(f"{reshape_si}.{input_name}"), - ) - reshape_out = _set_span( - relay.reshape(x, newshape=new_shape), - reshape_si, - ) - return infer_type(relay.Function([x], reshape_out)) - - self._verify(_res, _golden) - - def test_matmul_span(self): - a_name, a_shape = "a", (4, 3) - b_name, b_shape = "b", (3, 4) - out_name, out_shape = "out", [a_shape[0], b_shape[1]] - matmul_name = "matmul" - - def _res(): - # model definition - mul_node = helper.make_node("MatMul", [a_name, b_name], [out_name], name=matmul_name) - graph = helper.make_graph( - [mul_node], - "matmul_test", - inputs=[ - helper.make_tensor_value_info(a_name, TensorProto.FLOAT, a_shape), - helper.make_tensor_value_info(b_name, TensorProto.FLOAT, b_shape), - ], - outputs=[helper.make_tensor_value_info(out_name, TensorProto.FLOAT, out_shape)], - ) - model = helper.make_model(graph, producer_name="matmul_test") - - # get frontend model - shape_dict = {a_name: a_shape, b_name: b_shape} - mod, _ = relay.frontend.from_onnx(model, shape_dict) - return mod["main"] - - def _golden(): - matmul_si = matmul_name - a = relay.var( - a_name, - shape=tuple(a_shape), - span=_create_span(f"{matmul_si}.{a_name}"), - ) - b = relay.var( - b_name, - shape=tuple(b_shape), - span=_create_span(f"{matmul_si}.{b_name}"), - ) - b_t = _set_span(relay.transpose(b, axes=[1, 0]), matmul_si) - matmul_out = _set_span( - relay.nn.dense(a, b_t, out_dtype="float32"), - matmul_si, - ) - return infer_type(relay.Function([a, b], matmul_out)) - - self._verify(_res, _golden) - - -@tvm.testing.parametrize_targets -def test_pad_constant_value(target, dev): - """test_pad_constant_value""" - - def verify_pad_constant_value(constant_value): - tensor_shape = [1, 2, 257, 126] - tensor_values = [np.random.uniform(size=tensor_shape).astype("float32")] - graph_inputs = [helper.make_tensor_value_info("input", TensorProto.FLOAT, tensor_shape)] - graph_outputs = [helper.make_tensor_value_info("output", TensorProto.FLOAT, None)] - pads = helper.make_tensor("pads", TensorProto.INT64, [8], [0, 0, 0, 2, 0, 0, 0, 0]) - pad_node = helper.make_node( - "Pad", ["input", "pads", constant_value], ["output"], mode="constant" - ) - graph_nodes = [pad_node] - graph = helper.make_graph( - graph_nodes, - "test_pad_constant_value", - inputs=graph_inputs, - outputs=graph_outputs, - initializer=[pads], - ) - model = helper.make_model( - graph, - producer_name="test_pad_constant_value", - ) - verify_with_ort_with_inputs(model, tensor_values, target=target, dev=dev) - - verify_pad_constant_value("") - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/paddlepaddle/test_forward.py b/tests/python/frontend/paddlepaddle/test_forward.py deleted file mode 100755 index 6b8e90545c83..000000000000 --- a/tests/python/frontend/paddlepaddle/test_forward.py +++ /dev/null @@ -1,2566 +0,0 @@ -# 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 os -from pathlib import Path -import shutil - -import numpy as np -import tvm -import tvm.testing -import tvm.topi.testing -from tvm import relay -from tvm.contrib import graph_executor -import pytest - -import paddle - -paddle.disable_signal_handler() -import paddle.nn as nn - -PADDLE_TEST_DATA_ROOT_PATH = Path(Path("~").expanduser(), ".tvm_test_data", "paddle") -PADDLE_TEST_DATA_ROOT_PATH.mkdir(parents=True, exist_ok=True) -cached_program = list() - - -def assert_shapes_match(tru, est): - if tru.shape != est.shape: - msg = "Output shapes {} and {} don't match" - raise AssertionError(msg.format(tru.shape, est.shape)) - - -def get_paddle_model(func, input_spec): - global PADDLE_TEST_DATA_ROOT_PATH - global cached_program - model_path = Path(PADDLE_TEST_DATA_ROOT_PATH, "model") - - paddle.jit.save(func, str(model_path), input_spec=input_spec) - baseline_model = paddle.jit.load(str(model_path)) - if len(cached_program) >= 4: - cached_program = list() - cached_program.append(baseline_model._get_program_holder()) - - shutil.rmtree(str(PADDLE_TEST_DATA_ROOT_PATH)) - return baseline_model - - -def verify_model(func, input_data, use_vm=False, rtol=1e-5, atol=1e-5): - if not (isinstance(input_data, (tuple, list))): - input_data = [input_data] - - input_spec = [] - input_names = [] - input_shape_dict = {} - compiled_input = {} - for idx, data in enumerate(input_data): - input_name = "input{}".format(idx) - input_spec.append( - paddle.static.InputSpec(dtype=data.dtype, shape=data.shape, name=input_name) - ) - input_names.append(input_name) - input_shape_dict[input_name] = data.shape - if isinstance(data, np.ndarray): - compiled_input[input_name] = data - else: - compiled_input[input_name] = data.numpy() - - baseline_model = get_paddle_model(func, input_spec) - baseline_outputs = baseline_model(*[input[:] for input in input_data]) - - # get paddle outputs - if isinstance(baseline_outputs, (tuple, list)): - baseline_outputs = tuple(out.numpy() for out in baseline_outputs) - else: - baseline_outputs = (baseline_outputs.numpy(),) - - mod, params = relay.frontend.from_paddle(baseline_model, input_shape_dict) - compiled_names = [] - for arg in mod["main"].params: - assert arg.name_hint in input_names or arg.name_hint in params - if arg.name_hint in input_names: - compiled_names.append(arg.name_hint) - - if use_vm: - tvm_vm_input = [] - for idx, data in enumerate(input_data): - if isinstance(data, np.ndarray): - tvm_vm_input.append(data) - else: - tvm_vm_input.append(data.numpy()) - for target, dev in tvm.testing.enabled_targets(): - result = relay.create_executor("vm", mod=mod, device=dev, target=target).evaluate()( - *tvm_vm_input, **params - ) - tvm_vm_output = [] - if isinstance(result, tvm.runtime.NDArray): - tvm_vm_output = result.numpy() - else: - tvm_vm_output = [r.numpy() for r in result] - if not isinstance(tvm_vm_output, list): - tvm_vm_output = [tvm_vm_output] - - for i, baseline_output in enumerate(baseline_outputs): - assert_shapes_match(baseline_output, tvm_vm_output[i]) - tvm.testing.assert_allclose(baseline_output, tvm_vm_output[i], rtol=rtol, atol=atol) - else: - with tvm.transform.PassContext(opt_level=3): - for target, dev in tvm.testing.enabled_targets(): - lib = relay.build(mod, target=target, params=params) - gmod = graph_executor.GraphModule(lib["default"](dev)) - for name in compiled_names: - gmod.set_input(name, compiled_input[name]) - gmod.run() - - for i, baseline_output in enumerate(baseline_outputs): - compiled_output = gmod.get_output(i).numpy() - - assert_shapes_match(baseline_output, compiled_output) - tvm.testing.assert_allclose( - baseline_output, compiled_output, rtol=rtol, atol=atol - ) - - -@tvm.testing.uses_gpu -def test_forward_add_subtract(): - input_shape = [10] - - @paddle.jit.to_static - def add_subtract(inputs): - return paddle.subtract(paddle.add(inputs, inputs), inputs) - - @paddle.jit.to_static - def add_subtract2(inputs): - return inputs + 1 - 2 - - @paddle.jit.to_static - def add_subtract3(inputs1, inputs2): - ones = paddle.ones([10], dtype="float32") - return inputs1 + ones - inputs2 - - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(add_subtract, input_data) - verify_model(add_subtract2, input_data) - input_data2 = paddle.rand(input_shape, dtype="float32") - verify_model(add_subtract3, [input_data, input_data2]) - - -@tvm.testing.uses_gpu -def test_forward_addmm(): - class Addmm(nn.Layer): - def __init__(self, alpha=1.0, beta=1.0): - super(Addmm, self).__init__() - self.alpha = alpha - self.beta = beta - - @paddle.jit.to_static - def forward(self, inputs, x, y): - return paddle.addmm(inputs, x, y, self.alpha, self.beta) - - input_shapes = [[10, 10], [1, 1], [7, 1]] - x_shapes = [[10, 3], [5, 6], [7, 7]] - y_shapes = [[3, 10], [6, 2], [7, 3]] - input_shapes = [[10, 10]] - x_shapes = [[10, 3]] - y_shapes = [[3, 10]] - - for i in range(len(input_shapes)): - input_data = paddle.rand(input_shapes[i], dtype="float32") - x_data = paddle.rand(x_shapes[i], dtype="float32") - y_data = paddle.rand(y_shapes[i], dtype="float32") - verify_model(Addmm(), input_data=[input_data, x_data, y_data]) - verify_model(Addmm(0.5, 0.3), input_data=[input_data, x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_arg_max_min(): - class ArgMax(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.argmax(inputs) - - class ArgMax1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmax(axis=1) - - class ArgMax2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmax(axis=1, keepdim=False) - - class ArgMax3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmax(axis=2, keepdim=True) - - class ArgMin(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.argmin(inputs) - - class ArgMin1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmin(axis=1) - - class ArgMin2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmax(axis=1, keepdim=False) - - class ArgMin3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return inputs.argmin(axis=2, keepdim=True) - - input_shapes = [[256], [5, 28], [10, 5, 4], [1, 3, 8, 8]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(ArgMax(), input_data=input_data) - verify_model(ArgMin(), input_data=input_data) - for input_shape in input_shapes[1:]: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(ArgMax1(), input_data=input_data) - verify_model(ArgMax2(), input_data=input_data) - verify_model(ArgMin1(), input_data=input_data) - verify_model(ArgMin2(), input_data=input_data) - for input_shape in input_shapes[2:]: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(ArgMax3(), input_data=input_data) - verify_model(ArgMin3(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_argsort(): - class ArgSort1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.argsort(inputs) - - class ArgSort2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.argsort(inputs, axis=0, descending=True) - - class ArgSort3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.argsort(inputs, axis=-1, descending=True) - - input_shapes = [[256], [10, 20], [10, 5, 3], [1, 3, 5, 5]] - for input_shape in input_shapes: - # Avoid duplicate elements in the array which will bring - # different results with different sort algorithms - np.random.seed(13) - np_data = np.random.choice(range(-5000, 5000), np.prod(input_shape), replace=False) - input_data = paddle.to_tensor(np_data.reshape(input_shape).astype("int64")) - verify_model(ArgSort1(), [input_data]) - verify_model(ArgSort2(), [input_data]) - verify_model(ArgSort3(), [input_data]) - - -@tvm.testing.uses_gpu -def test_forward_assign(): - @paddle.jit.to_static - def assign(inputs): - return paddle.assign(inputs) - - @paddle.jit.to_static - def assign_value(inputs): - x = paddle.to_tensor(np.array([3]).astype("float32")) - return inputs + x - - input_shape = [2, 3] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model( - assign, - [ - input_data, - ], - ) - input_data2 = np.random.randint(100, size=input_shape) - verify_model( - assign, - [ - input_data2, - ], - ) - verify_model(assign_value, [input_data]) - - -@tvm.testing.uses_gpu -def test_forward_batch_norm(): - class BatchNorm1D(nn.Layer): - def __init__(self): - super(BatchNorm1D, self).__init__() - self.batch_norm = nn.BatchNorm1D(2) - - @paddle.jit.to_static - def forward(self, input_data): - return self.batch_norm(input_data) - - class BatchNorm2D(nn.Layer): - def __init__(self): - super(BatchNorm2D, self).__init__() - self.batch_norm = nn.BatchNorm2D(2) - - @paddle.jit.to_static - def forward(self, input_data): - return self.batch_norm(input_data) - - class BatchNorm3D(nn.Layer): - def __init__(self): - super(BatchNorm3D, self).__init__() - self.batch_norm = nn.BatchNorm3D(2) - - @paddle.jit.to_static - def forward(self, input_data): - return self.batch_norm(input_data) - - input_data = paddle.rand((2, 2, 3), dtype="float32") - verify_model(BatchNorm1D(), input_data=input_data) - input_data = paddle.rand((2, 2, 2, 3), dtype="float32") - verify_model(BatchNorm2D(), input_data=input_data) - input_data = paddle.rand((2, 2, 2, 2, 3), dtype="float32") - verify_model(BatchNorm3D(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_bmm(): - class Bmm(nn.Layer): - def __init__(self): - super(Bmm, self).__init__() - - @paddle.jit.to_static - def forward(self, x, y): - return paddle.bmm(x, y) - - x_shapes = [[10, 3, 4], [5, 6, 2], [1, 7, 7]] - y_shapes = [[10, 4, 5], [5, 2, 7], [1, 7, 3]] - for i in range(len(x_shapes)): - x_data = paddle.rand(x_shapes[i], dtype="float32") - y_data = paddle.rand(y_shapes[i], dtype="float32") - verify_model(Bmm(), input_data=[x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_cast(): - @paddle.jit.to_static - def cast1(inputs, dtype="uint8"): - return paddle.cast(inputs, dtype) - - @paddle.jit.to_static - def cast2(inputs, dtype="int64"): - return inputs.cast(dtype) - - input_shape = [2, 3] - input_data = paddle.rand(input_shape, dtype="float32") * 100 - verify_model( - cast1, - [ - input_data, - ], - ) - verify_model( - cast2, - [ - input_data, - ], - ) - - -@tvm.testing.uses_gpu -def test_forward_check_tensor(): - class IsFinite(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.cast(paddle.isfinite(inputs), "int32") - - class IsNan(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.cast(paddle.isnan(inputs), "int32") - - class IsInf(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.cast(paddle.isinf(inputs), "int32") - - input_shapes = [[32], [8, 32], [2, 5, 20], [2, 3, 8, 8], [2, 2, 3, 6, 6]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(IsFinite(), input_data=input_data) - verify_model(IsNan(), input_data=input_data) - verify_model(IsInf(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_clip(): - class Clip1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.clip(inputs, min=0.3, max=0.55) - - class Clip2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs, max_value): - return paddle.clip(inputs, max=max_value) - - class Clip3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs, min_value): - return paddle.clip(inputs, min=min_value) - - class Clip4(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs, min_value, max_value): - return paddle.clip(inputs, min=min_value, max=max_value) - - input_data = paddle.rand((2, 2, 2, 3), dtype="float32") - max_value = paddle.to_tensor([0.55]) - min_value = paddle.to_tensor([0.3]) - verify_model(Clip1(), input_data) - verify_model(Clip2(), [input_data, max_value]) - verify_model(Clip3(), [input_data, min_value]) - verify_model(Clip4(), [input_data, min_value, max_value]) - - -@tvm.testing.uses_gpu -def test_forward_concat_unsqueeze(): - @paddle.jit.to_static - def concat_unsqueeze1(inputs): - return paddle.concat([inputs[:, 0].unsqueeze(1), inputs[:, 1].unsqueeze(1)], axis=1) - - @paddle.jit.to_static - def concat_unsqueeze2(inputs): - a = (inputs[:, :, 0] + 2) * 7 - b = (inputs[:, :, 1] + 3) * 11 - c = (inputs[:, :, 2] + 5) * 13 - return paddle.concat([paddle.unsqueeze(t, axis=2) for t in [a, b, c]], axis=2) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(concat_unsqueeze1, input_data=input_data) - verify_model(concat_unsqueeze2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_cumsum(): - @paddle.jit.to_static - def cusum1(inputs): - return paddle.cumsum(inputs) - - @paddle.jit.to_static - def cusum2(inputs): - return paddle.cumsum(inputs, axis=0) - - @paddle.jit.to_static - def cusum3(inputs): - return paddle.cumsum(inputs, axis=1) - - input_data = paddle.randint(0, 100, (10, 10), dtype=paddle.int32) - verify_model(cusum1, [input_data]) - verify_model(cusum1, [input_data.astype(paddle.int64)]) - verify_model( - cusum2, - [ - input_data, - ], - ) - verify_model( - cusum3, - [ - input_data, - ], - ) - - -@tvm.testing.uses_gpu -def test_forward_conv(): - class Conv2D1(nn.Layer): - def __init__(self, stride=1, padding=0, dilation=1, groups=1, padding_mode="zeros"): - super(Conv2D1, self).__init__() - self.conv = nn.Conv2D( - 3, - 6, - 3, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups, - padding_mode=padding_mode, - ) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - class Conv2D2(nn.Layer): - def __init__( - self, - stride=1, - padding=0, - dilation=1, - groups=1, - padding_mode="zeros", - data_format="NCHW", - ): - super(Conv2D2, self).__init__() - self.conv = nn.Conv2D( - 3, - 6, - 3, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups, - padding_mode=padding_mode, - data_format=data_format, - ) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - input_shapes = [[1, 3, 10, 10], [1, 3, 12, 12]] - - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Conv2D1(), input_data=input_data) - verify_model(Conv2D1(stride=2, padding="VALID", dilation=3), input_data=input_data) - verify_model(Conv2D1(stride=2, padding="SAME", dilation=3), input_data=input_data) - verify_model( - Conv2D1(stride=2, padding=3, dilation=3, padding_mode="replicate"), - input_data=input_data, - ) - verify_model(Conv2D1(stride=2, padding="SAME", dilation=2, groups=3), input_data=input_data) - verify_model( - Conv2D2(stride=2, padding="SAME", dilation=2, groups=3, data_format="NCHW"), - input_data=input_data, - ) - - -@tvm.testing.uses_gpu -def test_forward_conv_transpose(): - class Conv2DTranspose(nn.Layer): - def __init__(self, stride=1, padding=0, dilation=1, groups=1, padding_mode="zeros"): - super(Conv2DTranspose, self).__init__() - self.conv = nn.Conv2DTranspose( - 6, - 3, - 3, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups, - ) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - input_shapes = [[1, 6, 10, 10], [2, 6, 8, 8]] - - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Conv2DTranspose(), input_data=input_data) - verify_model(Conv2DTranspose(stride=2, padding="VALID"), input_data=input_data) - verify_model(Conv2DTranspose(stride=2, padding="SAME", dilation=1), input_data=input_data) - verify_model(Conv2DTranspose(stride=2, padding=3), input_data=input_data) - verify_model(Conv2DTranspose(stride=3, padding="SAME", groups=1), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_conv3d(): - class Conv3D(nn.Layer): - def __init__(self, stride=1, padding=0, dilation=1, groups=1, padding_mode="zeros"): - super(Conv3D, self).__init__() - self.conv = nn.Conv3D( - 3, - 6, - 3, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups, - padding_mode=padding_mode, - ) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - class Conv3D2(nn.Layer): - def __init__( - self, - stride=1, - padding=0, - dilation=1, - groups=1, - padding_mode="zeros", - data_format="NCDHW", - ): - super(Conv3D2, self).__init__() - self.conv = nn.Conv3D( - 3, - 6, - 3, - stride=stride, - padding=padding, - dilation=dilation, - groups=groups, - padding_mode=padding_mode, - data_format=data_format, - ) - self.softmax = nn.Softmax() - - @paddle.jit.to_static - def forward(self, inputs): - return self.softmax(self.conv(inputs)) - - input_shapes = [[1, 3, 10, 10, 10], [1, 3, 12, 12, 12]] - - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Conv3D(), input_data=input_data) - verify_model(Conv3D(stride=2, padding="VALID", dilation=3), input_data=input_data) - verify_model(Conv3D(stride=2, padding="SAME", dilation=3), input_data=input_data) - verify_model( - Conv3D(stride=2, padding=(3, 3, 4, 4, 2, 2), dilation=3), - input_data=input_data, - ) - verify_model( - Conv3D(stride=2, padding=3, dilation=3, padding_mode="reflect"), - input_data=input_data, - ) - verify_model( - Conv3D(stride=2, padding=3, dilation=3, padding_mode="replicate"), - input_data=input_data, - ) - verify_model(Conv3D(stride=2, padding="SAME", dilation=2, groups=3), input_data=input_data) - verify_model( - Conv3D2(stride=2, padding="SAME", dilation=2, groups=3, data_format="NCDHW"), - input_data=input_data, - ) - - -@tvm.testing.uses_gpu -def test_forward_dot(): - class Dot(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - return paddle.dot(x, y) - - input_shapes = [[128], [8, 24]] - for input_shape in input_shapes: - x_data = paddle.rand(input_shape, dtype="float32") - y_data = paddle.rand(input_shape, dtype="float32") - verify_model(Dot(), input_data=[x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_dropout(): - @paddle.jit.to_static - def dropout(inputs): - return nn.functional.dropout(inputs) - - @paddle.jit.to_static - def dropout1(inputs): - return nn.functional.dropout(inputs, 0.1) - - @paddle.jit.to_static - def dropout2(inputs): - return nn.functional.dropout(inputs, 0.1, mode="downscale_in_infer") - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(dropout, input_data=input_data[0, 0]) - verify_model(dropout, input_data=input_data) - verify_model(dropout1, input_data=input_data[0, 0]) - verify_model(dropout1, input_data=input_data) - verify_model(dropout2, input_data=input_data[0, 0]) - verify_model(dropout2, input_data=input_data) - - -def test_forward_elemwise(): - class ElemwiseAPI(nn.Layer): - def __init__(self, api_name): - super(ElemwiseAPI, self).__init__() - self.api_name_ = api_name - for candidate in (paddle, paddle.nn.functional): - self.func = getattr(candidate, api_name, None) - if self.func: - break - - @paddle.jit.to_static - def forward(self, input1, input2): - y = self.func(input1, input2) - if "equal" in self.api_name_ or "than" in self.api_name_: - # for compare operation, cast boolean result to int32 - y = paddle.cast(y, "int32") - return y - - api_list = [ - "equal", - "floor_divide", - "greater_equal", - "greater_than", - "less_equal", - "less_than", - "maximum", - "minimum", - "pow", - ] - x_shapes = [[128], [8, 20], [4, 20, 3], [2, 3, 8, 8], [2, 3, 3, 9, 9]] - y_shapes = [[1], [8, 20], [4, 1, 1], [2, 3, 8, 8], [2, 3, 3, 9, 1]] - for x_shape, y_shape in zip(x_shapes, y_shapes): - x_data = paddle.randint(1, 10, x_shape, dtype="int32") - y_data = paddle.randint(1, 10, y_shape, dtype="int32") - for api_name in api_list: - if api_name == "pow": - # only support float for pow - x_data = x_data.astype("float32") - y_data = y_data.astype("float32") - verify_model(ElemwiseAPI(api_name), [x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_expand(): - @paddle.jit.to_static - def expand1(inputs): - return paddle.expand(inputs, shape=[2, 128]) - - @paddle.jit.to_static - def expand2(inputs): - return paddle.expand(inputs, shape=[2, 1, 4, 16]) - - @paddle.jit.to_static - def expand3(inputs): - return paddle.expand(inputs, shape=[2, 1, 3, 7, 7]) - - @paddle.jit.to_static - def expand4(inputs): - shape = paddle.to_tensor(np.array([2, 128]).astype("int32")) - return paddle.expand(inputs, shape=shape) - - @paddle.jit.to_static - def expand5(inputs): - shape = paddle.to_tensor(np.array([2, 1, 4, 16]).astype("int32")) - return paddle.expand(inputs, shape=shape) - - @paddle.jit.to_static - def expand6(inputs): - shape = paddle.to_tensor(np.array([2, 1, 3, 7, 7]).astype("int32")) - return paddle.expand(inputs, shape=shape) - - data = paddle.rand([128], dtype="float32") - verify_model(expand1, input_data=[data]) - verify_model(expand4, input_data=[data]) - data = paddle.rand([4, 16], dtype="float32") - verify_model(expand2, input_data=[data]) - verify_model(expand5, input_data=[data]) - data = paddle.rand([1, 3, 7, 7], dtype="float32") - verify_model(expand3, input_data=[data]) - verify_model(expand6, input_data=[data]) - - -@tvm.testing.uses_gpu -def test_forward_expand_as(): - class ExpandAs(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - z = paddle.expand_as(x, y) - z += y - return z - - x_shapes = [[1], [8, 128], [8, 1, 1], [2, 3, 229, 229], [2, 3, 3, 224, 1]] - y_shapes = [[128], [8, 128], [8, 200, 300], [2, 3, 229, 229], [2, 3, 3, 224, 224]] - for x_shape, y_shape in zip(x_shapes, y_shapes): - x_data = paddle.rand(x_shape, dtype="float32") - y_data = paddle.rand(y_shape, dtype="float32") - verify_model(ExpandAs(), [x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_fill_zeros_like(): - class FilZeroLike(nn.Layer): - def __init__(self, dtype=None): - super(FilZeroLike, self).__init__() - self.dtype = dtype - - @paddle.jit.to_static - def forward(self, x): - return paddle.zeros_like(x, dtype=self.dtype) - - input_shape = [2, 3, 5] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(FilZeroLike("float32"), input_data=input_data) - verify_model(FilZeroLike("int32"), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_flatten(): - class Flatten(nn.Layer): - def __init__(self, start_axis=0, stop_axis=-1): - super(Flatten, self).__init__() - self.start_axis = start_axis - self.stop_axis = stop_axis - - @paddle.jit.to_static - def forward(self, x): - return paddle.flatten(x, start_axis=self.start_axis, stop_axis=self.stop_axis) - - input_data = paddle.rand([2, 3, 4, 5, 2], dtype="float32") - verify_model(Flatten(), input_data=input_data) - verify_model(Flatten(2), input_data=input_data) - verify_model(Flatten(2, -2), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_flip(): - class Flip(nn.Layer): - def __init__(self, axis): - super(Flip, self).__init__() - self.axis = axis - - @paddle.jit.to_static - def forward(self, x): - return paddle.flip(x, axis=self.axis) - - input_data = paddle.rand([2, 3, 4], dtype="float32") - verify_model(Flip(0), input_data) - verify_model(Flip(-1), input_data) - verify_model(Flip([0, 1]), input_data) - - -@tvm.testing.uses_gpu -def test_forward_gather(): - class Gather(nn.Layer): - def __init__(self, axis=None): - super(Gather, self).__init__() - self.axis = axis - - @paddle.jit.to_static - def forward(self, x, index): - return paddle.gather(x, index, axis=self.axis) - - x_shapes = [[20, 10], [10, 10, 8]] - index = paddle.to_tensor(np.array([1, 3, 5]).astype("int64")) - for x_shape in x_shapes: - x_data = paddle.rand(x_shape, dtype="float32") - verify_model(Gather(), [x_data, index]) - verify_model(Gather(axis=0), [x_data, index]) - verify_model(Gather(axis=1), [x_data, index]) - - -@tvm.testing.uses_gpu -def test_forward_gather_nd(): - class GatherNd(nn.Layer): - @paddle.jit.to_static - def forward(self, x, index): - return paddle.gather_nd(x, index) - - x_shapes = [[20], [8, 8], [4, 5, 6], [3, 4, 3, 5]] - y_shapes = [[2, 1], [2], [1, 2, 3], [3]] - for x_shape, y_shape in zip(x_shapes, y_shapes): - x_data = paddle.rand(x_shape, dtype="float32") - y_data = paddle.randint(low=0, high=3, shape=y_shape, dtype="int64") - verify_model(GatherNd(), [x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_group_norm(): - class GroupNorm(nn.Layer): - def __init__(self, channels, groups): - super(GroupNorm, self).__init__() - self.group_norm = paddle.nn.GroupNorm(num_channels=channels, num_groups=groups) - - def forward(self, inputs): - return self.group_norm(inputs) - - input_shapes = [[1, 4, 6, 6], [2, 2, 4, 7], [2, 8, 1, 1]] - for input_shape in input_shapes: - num_channels = input_shape[1] - input_data = paddle.uniform(input_shape) - verify_model(GroupNorm(num_channels, 1), input_data, rtol=1e-4, atol=1e-4) - verify_model(GroupNorm(num_channels, 2), input_data, rtol=1e-4, atol=1e-4) - - -@tvm.testing.uses_gpu -def test_forward_grid_sampler(): - class GridSampler(nn.Layer): - def __init__(self, mode="bilinear", padding_mode="zeros", align_corners=True): - super(GridSampler, self).__init__() - self.mode = mode - self.padding_mode = padding_mode - self.align_corners = align_corners - - def forward(self, x, grid): - return paddle.nn.functional.grid_sample( - x, - grid, - mode=self.mode, - padding_mode=self.padding_mode, - align_corners=self.align_corners, - ) - - x_2D = paddle.rand(shape=[4, 4, 8, 8], dtype="float32") - grid_2D = paddle.rand(shape=[4, 8, 8, 2], dtype="float32") - verify_model(GridSampler(mode="nearest"), input_data=[x_2D, grid_2D]) - verify_model(GridSampler(padding_mode="reflection"), input_data=[x_2D, grid_2D]) - verify_model(GridSampler(padding_mode="border"), input_data=[x_2D, grid_2D]) - verify_model(GridSampler(align_corners=False), input_data=[x_2D, grid_2D]) - - x_3D = paddle.rand(shape=[4, 4, 4, 4, 4], dtype="float32") - grid_3D = paddle.rand(shape=[4, 8, 8, 8, 3], dtype="float32") - verify_model(GridSampler(mode="nearest"), input_data=[x_3D, grid_3D]) - verify_model(GridSampler(padding_mode="reflection"), input_data=[x_3D, grid_3D]) - verify_model(GridSampler(padding_mode="border"), input_data=[x_3D, grid_3D]) - verify_model(GridSampler(align_corners=False), input_data=[x_3D, grid_3D]) - - -@tvm.testing.uses_gpu -def test_forward_scatter(): - class Scatter(nn.Layer): - def __init__(self, overwrite=True): - super(Scatter, self).__init__() - self.overwrite = overwrite - - @paddle.jit.to_static - def forward(self, x, index, updates): - return paddle.scatter(x, index, updates, overwrite=self.overwrite) - - x_shapes = [[10], [4, 5], [6, 4, 5], [4, 5, 6, 4]] - index_shapes = [[10], [4], [6], [4]] - for x_shape, index_shape in zip(x_shapes, index_shapes): - x_data = paddle.rand(x_shape, dtype="float32") - updates = paddle.rand(x_shape, dtype="float32") + 1.0 - index = paddle.randint(low=0, high=3, shape=index_shape) - verify_model(Scatter(), [x_data, index, updates]) - verify_model(Scatter(False), [x_data, index, updates]) - - -def test_forward_scatter_nd(): - @paddle.jit.to_static - def scatter_nd(index, updates): - shape = [3, 5, 9, 10] - return paddle.scatter_nd(index, updates, shape) - - @paddle.jit.to_static - def scatter_nd_add(x, index, updates): - return paddle.scatter_nd_add(x, index, updates) - - index_data = np.array([[1, 1], [0, 1], [1, 3]]).astype(np.int64) - index = paddle.to_tensor(index_data) - updates = paddle.rand(shape=[3, 9, 10], dtype="float32") - verify_model(scatter_nd, [index, updates]) - x = paddle.rand(shape=[3, 5, 4, 9, 10], dtype="float32") - updates = paddle.rand(shape=[3, 2, 9, 10], dtype="float32") - index = paddle.randint(0, 3, shape=[3, 2, 3]) - verify_model(scatter_nd_add, [x, index, updates]) - - -@tvm.testing.uses_gpu -def test_forward_shape_full(): - @paddle.jit.to_static - def full1(inputs): - return paddle.full(paddle.shape(inputs), 3.14) - - @paddle.jit.to_static - def full2(inputs): - return paddle.full(paddle.shape(inputs), 1.0, dtype=inputs.dtype) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(full1, input_data=[input_data]) - verify_model(full2, input_data=[input_data]) - - -@tvm.testing.uses_gpu -def test_forward_split(): - class Split(nn.Layer): - def __init__( - self, axis=None, num_or_sections=None, axis_is_tensor=False, num_is_tensor=False - ): - super(Split, self).__init__() - self.axis = axis - self.num_or_sections = num_or_sections - self.axis_is_tensor = axis_is_tensor - self.num_is_tensor = num_is_tensor - - @paddle.jit.to_static - def forward(self, inputs): - axis = self.axis - if self.axis_is_tensor: - axis = paddle.to_tensor(axis, dtype="int32") - num_or_sections = self.num_or_sections - if self.num_is_tensor: - new_num_or_sections = [] - for i in num_or_sections: - if isinstance(i, list): - i = paddle.to_tensor(i, dtype="int32") - new_num_or_sections.append(i) - num_or_sections = new_num_or_sections - return paddle.split(inputs, num_or_sections=num_or_sections, axis=axis) - - input_shape = [3, 6, 2] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Split(axis=1, num_or_sections=3), input_data=input_data) - verify_model( - Split(axis=[1], num_or_sections=[2, 3, 1], axis_is_tensor=True), input_data=input_data - ) - verify_model( - Split(axis=1, num_or_sections=[2, -1, [3]], num_is_tensor=True), input_data=input_data - ) - - -@tvm.testing.uses_gpu -def test_forward_squeeze(): - class Squeeze(nn.Layer): - def __init__(self, axis=None): - super(Squeeze, self).__init__() - self.axis = axis - - @paddle.jit.to_static - def forward(self, inputs): - return paddle.squeeze(inputs, axis=self.axis) - - input_shapes = [[1, 1, 3, 1, 5], [5, 1, 6]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Squeeze(axis=None), input_data=input_data) - verify_model(Squeeze(axis=1), input_data=input_data) - input_data = paddle.rand([1], dtype="float32") - verify_model(Squeeze(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_ones_like(): - @paddle.jit.to_static - def ones_like1(inputs): - return paddle.ones_like(inputs) - - @paddle.jit.to_static - def ones_like2(inputs): - return paddle.ones_like(inputs, dtype="int32") - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(ones_like1, input_data=input_data) - verify_model(ones_like2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_gelu(): - @paddle.jit.to_static - def gelu(inputs): - return nn.functional.gelu(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(gelu, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_hard_sigmoid(): - @paddle.jit.to_static - def hard_sigmoid(inputs): - return nn.functional.hardsigmoid(inputs) - - def hard_sigmoid1(inputs): - return nn.functional.hardsigmoid(inputs, offset=0.6) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(hard_sigmoid, input_data=input_data) - verify_model(hard_sigmoid1, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_hard_swish(): - @paddle.jit.to_static - def hard_swish(inputs): - return nn.functional.hardswish(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(hard_swish, input_data=input_data) - - -def test_forward_instance_norm(): - class InstanceNorm(nn.Layer): - def __init__(self, num_features, epsilon=1e-05): - super(InstanceNorm, self).__init__() - self.instance_norm = paddle.nn.InstanceNorm2D( - num_features=num_features, epsilon=epsilon - ) - - def forward(self, inputs): - return self.instance_norm(inputs) - - input_shapes = [[2, 2, 2, 3], [1, 3, 5, 5]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(InstanceNorm(input_shape[1]), input_data) - verify_model(InstanceNorm(input_shape[1], 1e-03), input_data) - - -@tvm.testing.uses_gpu -def test_forward_interpolate(): - class Interpolate(nn.Layer): - def __init__( - self, - mode="nearest", - align_corners=False, - align_mode=0, - data_format="NCHW", - use_scale=False, - use_list=False, - use_const=False, - use_scaler=False, - ): - super(Interpolate, self).__init__() - self.mode = mode - self.align_corners = align_corners - self.align_mode = align_mode - self.data_format = data_format - self.use_scale = use_scale - self.use_list = use_list - self.use_const = use_const - self.use_scaler = use_scaler - - @paddle.jit.to_static - def forward(self, x): - size = np.array([15, 19]).astype("int32") - scale = np.array([2.0, 1.0]).astype("float32") - if not self.use_list and not self.use_const: - size = paddle.to_tensor(size) - scale = paddle.to_tensor(scale) - elif not self.use_const: - size0 = paddle.to_tensor(size[0:1]) - size = [size0, int(size[1])] - elif not self.use_scaler: - size = size.tolist() - scale = scale.tolist() - else: - size = list(size) - h, w = paddle.rand(size).shape # add decrease_axis - size = [h, w] - if not self.use_scale: - return paddle.nn.functional.interpolate( - x, - size=size, - mode=self.mode, - align_corners=self.align_corners, - align_mode=self.align_mode, - data_format=self.data_format, - ) - else: - return paddle.nn.functional.interpolate( - x, - scale_factor=scale, - mode=self.mode, - align_corners=self.align_corners, - align_mode=self.align_mode, - data_format=self.data_format, - ) - - input_data = paddle.rand([1, 2, 8, 12]).astype("float32") - verify_model(Interpolate(), input_data) - verify_model(Interpolate(use_list=True), input_data) - verify_model(Interpolate(use_scale=True, use_const=True), input_data) - verify_model(Interpolate(use_const=True, use_scaler=True), input_data) - verify_model(Interpolate("bilinear", use_scale=True), input_data) - verify_model(Interpolate("bilinear", use_scale=True, align_corners=True), input_data) - verify_model( - Interpolate( - "bilinear", - use_scale=True, - align_corners=True, - align_mode=1, - data_format="NHWC", - use_const=True, - ), - input_data, - ) - verify_model( - Interpolate("bicubic", use_scale=True, align_corners=True, align_mode=1), input_data - ) - - -@tvm.testing.uses_gpu -def test_forward_layer_norm(): - @paddle.jit.to_static - def layer_norm(inputs, weight, bias): - return nn.functional.layer_norm(inputs, inputs.shape[-1], weight=weight, bias=bias) - - class LayerNorm(nn.Layer): - def __init__(self): - super(LayerNorm, self).__init__() - data_shape = [10] - self.layer_norm = nn.LayerNorm(data_shape) - - @paddle.jit.to_static - def forward(self, inputs): - return self.layer_norm(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - weight = paddle.rand([10], dtype="float32") - bias = paddle.rand([10], dtype="float32") - verify_model(layer_norm, input_data=[input_data, weight, bias]) - verify_model(LayerNorm(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_leaky_relu(): - @paddle.jit.to_static - def leaky_relu(inputs): - return nn.functional.leaky_relu(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(leaky_relu, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_logical_api(): - class LogicalAPI(nn.Layer): - def __init__(self, api_name): - super(LogicalAPI, self).__init__() - for candidate in (paddle, paddle.nn.functional): - self.func = getattr(candidate, api_name, None) - if self.func: - break - - @paddle.jit.to_static - def forward(self, x, y): - z = self.func(x, y) - return paddle.cast(z, "int32") - - x_shapes = [[128], [8, 20], [4, 20, 3], [2, 3, 8, 8], [2, 3, 3, 9, 9]] - y_shapes = [[1], [8, 20], [4, 1, 1], [2, 3, 8, 8], [2, 3, 3, 9, 1]] - for x_shape, y_shape in zip(x_shapes, y_shapes): - x_data = paddle.randint(0, 2, x_shape).astype("bool") - y_data = paddle.randint(0, 2, y_shape).astype("bool") - verify_model(LogicalAPI("logical_and"), [x_data, y_data]) - verify_model(LogicalAPI("logical_or"), [x_data, y_data]) - verify_model(LogicalAPI("logical_xor"), [x_data, y_data]) - - -@tvm.testing.uses_gpu -def test_forward_logical_not(): - class LogicalNot(nn.Layer): - def __init__(self): - super(LogicalNot, self).__init__() - - @paddle.jit.to_static - def forward(self, x): - return paddle.logical_not(x).astype("int32") - - input_shapes = [[128], [8, 20], [4, 20, 3], [2, 3, 8, 8], [2, 3, 3, 9, 9]] - for input_shape in input_shapes: - input_data = paddle.randint(-2, 2, input_shape).astype("bool") - verify_model(LogicalNot(), input_data) - - -@tvm.testing.uses_gpu -def test_forward_look_up(): - @paddle.jit.to_static - def look_up(inputs, weight): - return nn.functional.embedding(inputs, weight) - - class LookUp(nn.Layer): - def __init__(self): - super(LookUp, self).__init__() - self.embedding = paddle.nn.Embedding(10, 4, sparse=True) - - @paddle.jit.to_static - def forward(self, inputs): - return self.embedding(inputs) - - input_shape = [1, 3, 10, 10] - input_data = paddle.randint(0, 10, input_shape, dtype="int32") - weight = paddle.rand([10, 4], dtype="float32") - verify_model(look_up, input_data=[input_data, weight]) - verify_model(LookUp(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_multiply(): - @paddle.jit.to_static - def multiply1(inputs): - return inputs * inputs - - @paddle.jit.to_static - def multiply2(inputs): - return inputs * 1.0 / 2.0 - - @paddle.jit.to_static - def multiply3(inputs, inputs2): - ones = paddle.ones([10], dtype="float32") - return inputs * ones / inputs2 - - input_shape = [10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(multiply1, input_data=input_data) - verify_model(multiply2, input_data=input_data) - input_data2 = paddle.rand(input_shape, dtype="float32") - verify_model(multiply3, input_data=[input_data, input_data2]) - - -@tvm.testing.uses_gpu -def test_forward_matmul(): - class MatMul1(nn.Layer): - def forward(self, input1, input2): - return paddle.matmul(input1, input2) - - # matrix x vector - input_data1 = paddle.randn((3, 4), dtype="float32") - input_data2 = paddle.randn((4,), dtype="float32") - verify_model(MatMul1(), input_data=[input_data1, input_data2]) - - # matrix x matrix - input_data1 = paddle.randn((5, 4), dtype="float32") - input_data2 = paddle.randn((4, 5), dtype="float32") - verify_model(MatMul1(), input_data=[input_data1, input_data2]) - - # batched matrix x batched matrix - input_data1 = paddle.randn((10, 3, 4), dtype="float32") - input_data2 = paddle.randn((10, 4, 5), dtype="float32") - verify_model(MatMul1(), input_data=[input_data1, input_data2]) - - # batched matrix x broadcasted matrix - input_data1 = paddle.randn((10, 3, 4), dtype="float32") - input_data2 = paddle.randn((4, 5), dtype="float32") - verify_model(MatMul1(), input_data=[input_data1, input_data2]) - - -@tvm.testing.uses_gpu -def test_forward_pool2d(): - class Pool2D1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool2d(inputs, kernel_size=2, stride=2, padding=0) - - class Pool2D2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.adaptive_avg_pool2d(inputs, output_size=[3, 3]) - - class Pool2D3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool2d( - inputs, - kernel_size=3, - stride=1, - padding=[1, 1], - exclusive=False, - divisor_override=2.5, - ) - - input_shapes = [[1, 2, 8, 8], [1, 3, 10, 10]] - for input_shape in input_shapes: - input_data = paddle.uniform(shape=input_shape, dtype="float32", min=-1, max=1) - verify_model(Pool2D1(), input_data=input_data) - verify_model(Pool2D2(), input_data=input_data) - verify_model(Pool2D3(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_pad1d(): - class Pad1D(nn.Layer): - def __init__(self, padding=0, mode="constant", value=0.0, data_format="NCL"): - super(Pad1D, self).__init__() - self.pad1d = paddle.nn.Pad1D(padding, mode=mode, value=value, data_format=data_format) - - @paddle.jit.to_static - def forward(self, inputs): - return self.pad1d(inputs) - - input_shapes = [[1, 2, 5], [2, 5, 9]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Pad1D(padding=2), input_data=input_data) - verify_model(Pad1D(padding=[1, 2], data_format="NLC"), input_data=input_data) - verify_model(Pad1D(padding=[0, 2], value=0.3), input_data=input_data) - verify_model(Pad1D(padding=[2, 2], mode="reflect"), input_data=input_data) - verify_model(Pad1D(padding=3, mode="replicate"), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_pad2d(): - class Pad2D(nn.Layer): - def __init__(self, padding=0, mode="constant", value=0.0, data_format="NCHW"): - super(Pad2D, self).__init__() - self.pad2d = paddle.nn.Pad2D(padding, mode=mode, value=value, data_format=data_format) - - @paddle.jit.to_static - def forward(self, inputs): - return self.pad2d(inputs) - - input_shapes = [[1, 2, 5, 5], [2, 2, 5, 9]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Pad2D(padding=2), input_data=input_data) - verify_model(Pad2D(padding=[1, 2, 0, 2], data_format="NHWC"), input_data=input_data) - verify_model(Pad2D(padding=[1, 2, 0, 2], value=0.3), input_data=input_data) - verify_model(Pad2D(padding=[1, 2, 0, 2], mode="reflect"), input_data=input_data) - verify_model(Pad2D(padding=3, mode="replicate"), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_pad3d(): - class Pad3D(nn.Layer): - def __init__(self, padding=0, mode="constant", value=0.0, data_format="NCDHW"): - super(Pad3D, self).__init__() - self.pad3d = paddle.nn.Pad3D(padding, mode=mode, value=value, data_format=data_format) - - @paddle.jit.to_static - def forward(self, inputs): - return self.pad3d(inputs) - - input_shapes = [[1, 2, 2, 5, 5], [1, 2, 2, 5, 9]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(Pad3D(padding=2), input_data=input_data) - verify_model(Pad3D(padding=[1, 2, 0, 2, 1, 1], data_format="NDHWC"), input_data=input_data) - verify_model(Pad3D(padding=[1, 2, 0, 2, 1, 1], value=0.3), input_data=input_data) - verify_model(Pad3D(padding=[1, 2, 0, 2, 1, 1], mode="reflect"), input_data=input_data) - verify_model(Pad3D(padding=3, mode="replicate"), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_transpose(): - class Transpose(nn.Layer): - def __init__(self, perm): - super(Transpose, self).__init__() - self.perm = perm - - @paddle.jit.to_static - def forward(self, inputs): - inputs = inputs * 2 - return paddle.transpose(inputs, perm=self.perm) - - input_data = paddle.rand([1, 3, 5, 4, 3], dtype="float32") - verify_model(Transpose([0, 1, 2, 3, 4]), input_data=input_data) - verify_model(Transpose([4, 3, 2, 0, 1]), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_reduce(): - class Reduce(nn.Layer): - def __init__(self, op_name, axis=None, keepdim=False): - super(Reduce, self).__init__() - self.op_name = op_name - self.axis = axis - self.keepdim = keepdim - - @paddle.jit.to_static - def forward(self, inputs): - result = getattr(paddle, self.op_name)(inputs, axis=self.axis, keepdim=self.keepdim) - result = result.astype("float32") - return result - - input_shapes = [[1, 2, 2, 5, 5], [2, 3, 4], [4, 20], [2, 3, 30, 30]] - for input_shape in input_shapes: - input_data = paddle.uniform(min=-3, max=3, shape=input_shape, dtype="float32") - verify_model(Reduce("all"), input_data=input_data.astype("bool")) - verify_model(Reduce("any", 1), input_data=input_data.astype("bool")) - verify_model(Reduce("max", 0, True), input_data=input_data) - verify_model(Reduce("min", 1, True), input_data=input_data) - verify_model(Reduce("prod", 0), input_data=input_data) - verify_model(Reduce("sum", 0, True), input_data=input_data) - verify_model(Reduce("mean", -1, True), input_data=input_data) - # logsumexp only supports tensor with rank less than 5 - if len(input_shape) < 5: - verify_model(Reduce("logsumexp", -1, True), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_reshape(): - @paddle.jit.to_static - def reshape1(inputs, x): - new_shape = paddle.shape(x) - return paddle.reshape(inputs, new_shape) - - @paddle.jit.to_static - def reshape2(inputs): - return inputs.reshape([-1]) - - @paddle.jit.to_static - def reshape3(inputs): - data_shape = inputs.shape - return inputs.reshape([data_shape[0] * data_shape[1], data_shape[2]]) - - @paddle.jit.to_static - def reshape4(inputs, x): - new_shape = paddle.shape(x) - return paddle.reshape(inputs, [new_shape[2], 2, -1]) - - input_shape = [2, 1, 10, 1, 10] - input_data = paddle.rand(input_shape, dtype="float32") - input_data2 = paddle.randn([2, 1, 10, 10]) - verify_model(reshape1, input_data=[input_data, input_data2]) - verify_model(reshape2, input_data=input_data) - verify_model(reshape3, input_data=paddle.randn((2, 3, 4))) - verify_model(reshape4, input_data=[input_data, input_data2]) - - -@tvm.testing.uses_gpu -def test_forward_scale(): - @paddle.jit.to_static - def scale1(inputs): - return paddle.scale(inputs, scale=2.0, bias=1.0) - - @paddle.jit.to_static - def scale2(inputs): - return paddle.scale(inputs, scale=3, bias=2.1, act="gelu") - - input_data = paddle.randn(shape=[2, 3], dtype="float32") - verify_model( - scale1, - input_data=[ - input_data, - ], - ) - verify_model(scale2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_slice(): - @paddle.jit.to_static - def slice1(inputs): - return inputs[:, :, :, :3] - - @paddle.jit.to_static - def slice2(inputs): - return inputs[0, :, :-3, :] - - @paddle.jit.to_static - def slice3(inputs): - return inputs[0::2, 0::2] + inputs[1::2, 1::2] - - @paddle.jit.to_static - def slice4(inputs): - x0 = paddle.to_tensor([2]) - paddle.to_tensor([1]) - x1 = paddle.to_tensor([3]) + paddle.to_tensor([1]) - return inputs[:, x0:, 1:x1, :] - - @paddle.jit.to_static - def slice5(inputs): - b, c, h, w = inputs # add decrease_axis - return h - - input_shape = [1, 3, 10, 10] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model( - slice1, - input_data=[ - input_data, - ], - ) - verify_model(slice2, input_data=input_data) - verify_model(slice3, input_data=paddle.randn((4, 4))) - verify_model(slice4, input_data=input_data) - # verify_model(slice5, input_data=paddle.randn((4,))) - - -@tvm.testing.uses_gpu -def test_forward_unique(): - class Unique(nn.Layer): - def __init__( - self, - return_index=False, - return_inverse=False, - return_counts=False, - axis=None, - dtype="int64", - ): - super(Unique, self).__init__() - self.return_index = return_index - self.return_inverse = return_inverse - self.return_counts = return_counts - self.axis = None - self.dtype = dtype - - @paddle.jit.to_static - def forward(self, inputs): - result = paddle.unique( - inputs, - return_inverse=self.return_inverse, - return_counts=self.return_counts, - axis=self.axis, - dtype=self.dtype, - ) - return result - - input_shape = [2, 3, 5] - input_data = paddle.rand(input_shape) - verify_model(Unique(), input_data=input_data) - verify_model(Unique(return_index=True), input_data=input_data) - verify_model(Unique(return_index=True, return_inverse=True), input_data=input_data) - verify_model( - Unique(return_index=True, return_inverse=True, return_counts=True), input_data=input_data - ) - - -@tvm.testing.uses_gpu -def run_math_api(func): - api_name = func.__name__.split("_")[-1] - print("func_name:", api_name) - - class MathAPI(nn.Layer): - def __init__(self, api_name): - super(MathAPI, self).__init__() - for candidate in (paddle, paddle.nn.functional): - self.func = getattr(candidate, api_name, None) - if self.func: - break - - @paddle.jit.to_static - def forward(self, inputs): - return self.func(inputs) - - input_shapes = [[128], [2, 100], [10, 2, 5], [7, 3, 4, 1]] - for input_shape in input_shapes: - input_data = paddle.rand(input_shape, dtype="float32") - if api_name in ["log", "log2", "log10", "reciprocal", "sqrt", "rsqrt"]: - # avoid illegal input, all elements should be positive - input_data = paddle.uniform(input_shape, min=0.01, max=0.99) - verify_model(MathAPI(api_name), input_data=input_data) - - -@run_math_api -def test_forward_abs(): - pass - - -@run_math_api -def test_forward_acos(): - pass - - -@run_math_api -def test_forward_abs(): - pass - - -@run_math_api -def test_forward_atan(): - pass - - -@run_math_api -def test_forward_ceil(): - pass - - -@run_math_api -def test_forward_cos(): - pass - - -@run_math_api -def test_forward_cosh(): - pass - - -@run_math_api -def test_forward_elu(): - pass - - -@run_math_api -def test_forward_erf(): - pass - - -@run_math_api -def test_forward_exp(): - pass - - -@run_math_api -def test_forward_floor(): - pass - - -@run_math_api -def test_forward_hardshrink(): - pass - - -@run_math_api -def test_forward_hardtanh(): - pass - - -@run_math_api -def test_forward_log_sigmoid(): - pass - - -@run_math_api -def test_forward_log_softmax(): - pass - - -@run_math_api -def test_forward_log(): - pass - - -@run_math_api -def test_forward_log2(): - pass - - -@run_math_api -def test_forward_log10(): - pass - - -@run_math_api -def test_forward_log1p(): - pass - - -@run_math_api -def test_forward_reciprocal(): - pass - - -@run_math_api -def test_forward_relu(): - pass - - -@run_math_api -def test_forward_round(): - pass - - -@run_math_api -def test_forward_rsqrt(): - pass - - -@run_math_api -def test_forward_selu(): - pass - - -@run_math_api -def test_forward_sigmoid(): - pass - - -@run_math_api -def test_forward_sign(): - pass - - -@run_math_api -def test_forward_sin(): - pass - - -@tvm.testing.uses_gpu -def test_forward_softplus(): - @paddle.jit.to_static - def Softplus1(input): - return paddle.nn.functional.softplus(input, beta=1.0, threshold=20.0) - - @paddle.jit.to_static - def Softplus2(input): - return paddle.nn.functional.softplus(input, beta=6.0, threshold=20.0) - - @paddle.jit.to_static - def Softplus3(input): - return paddle.nn.functional.softplus(input, beta=1.0, threshold=10.0) - - x = paddle.to_tensor([-8.0, -12.0, 1.0, 18.0, 25.0]) - verify_model(Softplus1, x) - verify_model(Softplus2, x) - verify_model(Softplus3, x) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Softplus1, input_data=input_data) - verify_model(Softplus2, input_data=input_data) - verify_model(Softplus3, input_data=input_data) - - -@run_math_api -def test_forward_sqrt(): - pass - - -@run_math_api -def test_forward_square(): - pass - - -@run_math_api -def test_forward_sin(): - pass - - -@run_math_api -def test_forward_softsign(): - pass - - -@run_math_api -def test_forward_sqrt(): - pass - - -@run_math_api -def test_forward_square(): - pass - - -@run_math_api -def test_forward_swish(): - pass - - -@run_math_api -def test_forward_tan(): - pass - - -@run_math_api -def test_forward_tanh(): - pass - - -@tvm.testing.uses_gpu -def test_forward_meshgrid(): - @paddle.jit.to_static - def t(x, y, z): - return paddle.meshgrid(x, y, z) - - x = paddle.randint(low=0, high=100, shape=[2]) - y = paddle.randint(low=0, high=100, shape=[3]) - z = paddle.randint(low=0, high=100, shape=[5]) - verify_model(t, [x, y, z]) - - -@tvm.testing.uses_gpu -def test_forward_mv(): - class Mv(nn.Layer): - def forward(self, input1, input2): - return paddle.mv(input1, input2) - - # matrix x vector - input_data1 = paddle.randn((3, 4), dtype="float32") - input_data2 = paddle.randn((4,), dtype="float32") - verify_model(Mv(), input_data=[input_data1, input_data2]) - - -@tvm.testing.uses_gpu -def test_forward_pixel_shuffle(): - class PixelShuffle(nn.Layer): - def __init__(self, upscale_factor, data_format="NCHW"): - super(PixelShuffle, self).__init__() - self.pixel_shuffle = paddle.nn.PixelShuffle(upscale_factor, data_format) - - @paddle.jit.to_static - def forward(self, x): - return self.pixel_shuffle(x) - - input_shapes = [[1, 4, 3, 3], [2, 8, 2, 5]] - for input_shape in input_shapes: - x = paddle.rand(input_shape, dtype="float32") - verify_model(PixelShuffle(2), x) - - input_shapes = [[1, 3, 3, 4], [2, 2, 5, 8]] - for input_shape in input_shapes: - x = paddle.rand(input_shape, dtype="float32") - verify_model(PixelShuffle(2, data_format="NHWC"), x) - - -@tvm.testing.uses_gpu -def test_forward_prelu(): - class PRelu(nn.Layer): - @paddle.jit.to_static - def forward(self, x, w): - return paddle.nn.functional.prelu(x, w) - - x = paddle.normal(shape=[4, 3, 5, 5]) - w = paddle.to_tensor( - np.array( - [ - 0.25, - ] - ).astype("float32") - ) - verify_model(PRelu(), [x, w]) - w2 = paddle.to_tensor(np.array([0.25, 0.5, 0.8]).astype("float32")) - verify_model(PRelu(), [x, w2]) - - -@tvm.testing.uses_gpu -def test_forward_arange(): - @paddle.jit.to_static - def arange(inputs): - return paddle.arange(paddle.shape(inputs)[0], 9, 2.0) - - @paddle.jit.to_static - def arange1(inputs): - return inputs + paddle.arange(0, 10.0, 8, dtype="float32") - - input_shape = [2, 2] - input_data = paddle.rand(input_shape, dtype="float32") - verify_model(arange, input_data) - verify_model(arange1, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_rnn(): - class RNN(nn.Layer): - def __init__(self, api_name, input_size, hidden_size, num_layers, direction="forward"): - super(RNN, self).__init__() - rnn_func = getattr(paddle.nn, api_name, None) - self.rnn = rnn_func(input_size, hidden_size, num_layers, direction=direction) - - @paddle.jit.to_static - def forward(self, inputs, prev_h): - y, h = self.rnn(inputs, prev_h) - return y - - input_size, hidden_size, num_layers = 8, 16, 2 - input_shape = [4, 5, 8] - input_data = paddle.rand(input_shape, dtype="float32") - - for api_name in ("SimpleRNN", "GRU"): - prev_h = paddle.rand([4, 4, 16], dtype="float32") - verify_model( - RNN(api_name, input_size, hidden_size, num_layers, direction="bidirectional"), - input_data=[input_data, prev_h], - ) - prev_h = paddle.rand([2, 4, 16], dtype="float32") - verify_model( - RNN(api_name, input_size, hidden_size, num_layers), input_data=[input_data, prev_h] - ) - - -@tvm.testing.uses_gpu -def test_forward_topk(): - @paddle.jit.to_static - def topk1(inputs): - return paddle.topk(inputs, k=1) - - @paddle.jit.to_static - def topk2(inputs): - k = paddle.to_tensor([1], dtype=paddle.int32) - return paddle.topk(inputs, k=k) - - @paddle.jit.to_static - def topk3(inputs): - return paddle.topk(inputs, k=1, largest=False) - - @paddle.jit.to_static - def topk4(inputs): - return paddle.topk(inputs, k=2, sorted=True) - - @paddle.jit.to_static - def topk5(inputs): - return paddle.topk(inputs, k=2, sorted=False) - - @paddle.jit.to_static - def topk6(inputs): - return paddle.topk(inputs, k=1, axis=0) - - # paddle.fluid.layers.topk - @paddle.jit.to_static - def topk7(inputs): - return paddle.fluid.layers.topk(inputs, k=1) - - @paddle.jit.to_static - def topk8(inputs): - return paddle.fluid.layers.topk(inputs, k=2) - - input_data = paddle.to_tensor([[1, 4, 5, 7], [3, 6, 2, 5]], dtype=paddle.int32) - input_data_fp32 = paddle.to_tensor([[1, 4, 5, 7], [3, 6, 2, 5]], dtype=paddle.float32) - verify_model(topk1, input_data=input_data) - # verify_model(topk2, input_data=input_data) - verify_model(topk3, input_data=input_data) - verify_model(topk4, input_data=input_data) - verify_model(topk5, input_data=input_data) - verify_model(topk6, input_data=input_data) - verify_model(topk7, input_data=input_data_fp32) - verify_model(topk8, input_data=input_data_fp32) - - -@tvm.testing.uses_gpu -def test_forward_tanhshrink(): - @paddle.jit.to_static - def tanhshrink(inputs): - return paddle.nn.functional.tanhshrink(inputs) - - input_data = paddle.randn(shape=[2, 3], dtype="float32") - verify_model(tanhshrink, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_one_hot_v2(): - @paddle.jit.to_static - def one_hot_v2_1(inputs): - return nn.functional.one_hot(inputs, num_classes=4) - - input_data = paddle.to_tensor([1, 1, 3, 0], dtype=paddle.int32) - verify_model(one_hot_v2_1, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_norm(): - @paddle.jit.to_static - def norm_1(inputs): - return paddle.fluid.layers.l2_normalize(inputs, -1, 1e-12) - - def norm_2(inputs): - return paddle.fluid.layers.l2_normalize(inputs, 1, 1e-12) - - input_data = paddle.to_tensor( - [[[1, 2], [3, 1], [4, 5]], [[3, 1], [3, 5], [2, 4]]], dtype=paddle.float32 - ) - verify_model(norm_1, input_data=input_data) - verify_model(norm_2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_where_index(): - @paddle.jit.to_static - def where_index_1(inputs): - return paddle.nonzero(inputs) - - input_data = paddle.to_tensor([[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 3.0]]) - verify_model(where_index_1, input_data=input_data, use_vm=True) - - -@tvm.testing.uses_gpu -def test_forward_take_along_axis(): - @paddle.jit.to_static - def take_along_axis_1(inputs, index): - return paddle.take_along_axis(inputs, index, 0) - - input_data = paddle.to_tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - index = paddle.to_tensor([[0]]) - verify_model(take_along_axis_1, input_data=[input_data, index]) - - -@tvm.testing.uses_gpu -def test_forward_stack(): - class Stack1(nn.Layer): - @paddle.jit.to_static - def forward(self, input0, input1, input2): - return paddle.stack([input0, input1, input2], axis=-1) - - class Stack2(nn.Layer): - @paddle.jit.to_static - def forward(self, input0, input1, input2): - return paddle.stack([input0, input1, input2], axis=1) - - class Stack3(nn.Layer): - @paddle.jit.to_static - def forward(self, input0, input1, input2): - return paddle.stack([input0, input1, input2], axis=2) - - input_shapes = [[2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data_0 = paddle.randn(shape=input_shape, dtype="float32") - input_data_1 = paddle.randn(shape=input_shape, dtype="float32") - input_data_2 = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Stack1(), [input_data_0, input_data_1, input_data_2]) - verify_model(Stack2(), [input_data_0, input_data_1, input_data_2]) - verify_model(Stack3(), [input_data_0, input_data_1, input_data_2]) - - -@tvm.testing.uses_gpu -def test_forward_unstack(): - class UnStack1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.unstack(inputs, axis=-1) - - class UnStack2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.unstack(inputs, axis=1) - - class UnStack3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.unstack(inputs, axis=0) - - input_shapes = [[2, 3], [5, 10, 11], [3, 4, 5, 6], [1, 3, 4, 1, 1]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(UnStack1(), input_data) - verify_model(UnStack2(), input_data) - verify_model(UnStack3(), input_data) - - -@tvm.testing.uses_gpu -def test_forward_silu(): - class Silu(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.silu(inputs) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Silu(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_softshrink(): - @paddle.jit.to_static - def Softshrink1(input): - return nn.functional.softshrink(input, threshold=0.0) - - @paddle.jit.to_static - def Softshrink2(input): - return nn.functional.softshrink(input, threshold=0.5) - - @paddle.jit.to_static - def Softshrink3(input): - return nn.functional.softshrink(input, threshold=1.0) - - x = paddle.to_tensor([-0.9, -0.2, 0.1, 0.8]) - verify_model(Softshrink2, x) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Softshrink1, input_data=input_data) - verify_model(Softshrink2, input_data=input_data) - verify_model(Softshrink3, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_where(): - @paddle.jit.to_static - def where1(x, y): - return paddle.where(x > 1, x, y) - - @paddle.jit.to_static - def where2(x, y): - return paddle.where(x > y, x, y) - - x = paddle.to_tensor([0.9383, 0.1983, 3.2, 1.2]) - y = paddle.to_tensor([1.0, 1.0, 1.0, 1.0]) - verify_model(where1, [x, y]) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - x = paddle.randn(shape=input_shape, dtype="float32") - y = paddle.randn(shape=input_shape, dtype="float32") - verify_model(where1, [x, y]) - verify_model(where2, [x, y]) - - -@tvm.testing.uses_gpu -def test_forward_tile(): - class Tile1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.tile(inputs, repeat_times=[10]) - - class Tile2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.tile(inputs, repeat_times=[2, 3]) - - class Tile3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.tile(inputs, repeat_times=[1, 2, 3]) - - class Tile4(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.tile(inputs, repeat_times=[2, 3, 4, 1, 5]) - - class Tile5(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - reps = paddle.to_tensor([3, 2]) - reps = paddle.cast(reps, "int32") - return paddle.tile(inputs, repeat_times=reps) - - class Tile6(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - rep_0 = paddle.to_tensor([3]) - rep_1 = paddle.to_tensor([2]) - rep_0 = paddle.cast(rep_0, "int32") - rep_1 = paddle.cast(rep_1, "int32") - return paddle.tile(inputs, repeat_times=[rep_0, rep_1]) - - input_shapes = [ - [10], - [2, 3], - [3, 4, 5], - [5, 3, 1, 4], - [1, 3, 1, 6, 7], - ] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Tile1(), input_data=input_data) - verify_model(Tile2(), input_data=input_data) - verify_model(Tile3(), input_data=input_data) - verify_model(Tile4(), input_data=input_data) - verify_model(Tile5(), input_data=input_data) - verify_model(Tile6(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_mish(): - class Mish(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.mish(inputs) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - if paddle.version.full_version >= "2.4.2": - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(Mish(), input_data=input_data) - input_data += 20.0 - verify_model(Mish(), input_data=input_data) - - input_data = paddle.to_tensor([-5.0, 0.0, 5.0, 23.1, 20.0]) - verify_model(Mish(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_thresholded_relu(): - class ThresholdedRelu1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.thresholded_relu(inputs) - - class ThresholdedRelu2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.thresholded_relu(inputs, threshold=0.5) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - verify_model(ThresholdedRelu1(), input_data=input_data) - verify_model(ThresholdedRelu2(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_index_select(): - class IndexSelect1(nn.Layer): - @paddle.jit.to_static - def forward(self, x, index): - return paddle.index_select(x, index, axis=0) - - class IndexSelect2(nn.Layer): - @paddle.jit.to_static - def forward(self, x, index): - return paddle.index_select(x, index, axis=-1) - - input_shapes = [[10], [2, 3], [5, 10, 11], [3, 4, 5, 6]] - for input_shape in input_shapes: - input_data = paddle.randn(shape=input_shape, dtype="float32") - index = paddle.to_tensor([0, 1, 1], dtype="int32") - verify_model(IndexSelect1(), input_data=[input_data, index]) - verify_model(IndexSelect2(), input_data=[input_data, index]) - - -@tvm.testing.uses_gpu -def test_forward_eye(): - class Eye1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.eye(3, 5, dtype="int32"), paddle.eye(3, 5, dtype="float32"), inputs - - class Eye2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.eye(5, 3, dtype="int64"), paddle.eye(5, 3, dtype="float64"), inputs - - class Eye3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.eye(0, 3, dtype="int64"), paddle.eye(0, 0, dtype="float64"), inputs - - class Eye4(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return paddle.eye(4, None, dtype="int64"), paddle.eye(4, None, dtype="float64"), inputs - - x = paddle.to_tensor([1], dtype="float32") - verify_model(Eye1(), input_data=[x]) - verify_model(Eye2(), input_data=[x]) - verify_model(Eye3(), input_data=[x]) - verify_model(Eye4(), input_data=[x]) - - -@tvm.testing.uses_gpu -def test_forward_linspace(): - class Linspace1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - out1 = paddle.linspace(0.5, 7, 1, "int32") - out2 = paddle.linspace(1.3, 7.1, 5, "float32") - out3 = paddle.linspace(1, 1000000000, 10, "int64") - out4 = paddle.linspace(1, 7.1, 5, "float64") - return out1, out2, out3, out4, inputs - - class Linspace2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - start = paddle.to_tensor([-2.5]) - stop = paddle.to_tensor([31.6]) - num = paddle.to_tensor([13]) - start = paddle.cast(start, "float32") - stop = paddle.cast(stop, "float32") - num = paddle.cast(num, "int32") - out1 = paddle.linspace(start, stop, num, "int32") - out2 = paddle.linspace(start, stop, num, "float32") - out3 = paddle.linspace(start, stop, num, "int64") - out4 = paddle.linspace(start, stop, num, "float64") - return out1, out2, out3, out4, inputs - - class Linspace3(nn.Layer): - @paddle.jit.to_static - def forward(self, start, stop, num): - out1 = paddle.linspace(start, stop, num, "int32") - out2 = paddle.linspace(start, stop, num, "float32") - out3 = paddle.linspace(start, stop, num, "int64") - out4 = paddle.linspace(start, stop, num, "float32") - return out1 - - start = paddle.to_tensor([1.3]) - stop = paddle.to_tensor([5.1]) - num = paddle.to_tensor([3]) - start = paddle.cast(start, "float32") - stop = paddle.cast(stop, "float32") - num = paddle.cast(num, "int32") - x = paddle.to_tensor([1], dtype="float32") - verify_model(Linspace1(), input_data=[x]) - verify_model(Linspace2(), input_data=[x]) - verify_model(Linspace3(), input_data=[start, stop, num], use_vm=True) - num = paddle.to_tensor([1]) - num = paddle.cast(num, "int32") - verify_model(Linspace3(), input_data=[start, stop, num], use_vm=True) - - -@tvm.testing.uses_gpu -def test_forward_dist(): - class Dist(nn.Layer): - @paddle.jit.to_static - def forward(self, x, y): - l0_norm = paddle.dist(x, y, 0) - l2_norm = paddle.dist(x, y, 2) - float_norm = paddle.dist(x, y, 1.3) - inf_norm = paddle.dist(x, y, float("inf")) - ninf_norm = paddle.dist(x, y, float("-inf")) - return l0_norm, l2_norm, float_norm, inf_norm, ninf_norm - - x = paddle.to_tensor([[3, 3], [3, 3]], dtype="float32") - y = paddle.to_tensor([[1, 2], [3, 4]], dtype="float32") - w = paddle.to_tensor([[1, 2]], dtype="float32") - v = paddle.to_tensor([[2.1]], dtype="float32") - verify_model(Dist(), input_data=[x, y]) - verify_model(Dist(), input_data=[x, w]) - verify_model(Dist(), input_data=[w, v]) - verify_model(Dist(), input_data=[y, v]) - - -@tvm.testing.uses_gpu -def test_forward_p_norm(): - class PNorm(nn.Layer): - def __init__(self, axis, keepdim, p=1): - super(PNorm, self).__init__() - self.p = p - self.axis = axis - self.keepdim = keepdim - - @paddle.jit.to_static - def forward(self, input_data): - return paddle.norm(input_data, p=self.p, axis=self.axis, keepdim=self.keepdim) - - input_data = paddle.rand((2, 2, 3), dtype="float32") - verify_model(PNorm(axis=0, keepdim=True), input_data=input_data) - verify_model(PNorm(axis=0, keepdim=False), input_data=input_data) - verify_model(PNorm(axis=1, keepdim=True, p=1.5), input_data=input_data) - verify_model(PNorm(axis=-1, keepdim=True, p=3.4), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_roi_align(): - class RoiAlign(nn.Layer): - def __init__(self, spatial_scale=1.0, sampling_ratio=-1, aligned=False): - super(RoiAlign, self).__init__() - self.spatial_scale = spatial_scale - self.sampling_ratio = sampling_ratio - self.aligned = aligned - - @paddle.jit.to_static - def forward(self, input_data, rois, rois_num): - return paddle.vision.ops.roi_align( - input_data, rois, rois_num, 3, self.spatial_scale, self.sampling_ratio, self.aligned - ) - - input_data = paddle.rand((1, 128, 32, 32), dtype="float32") - boxes = paddle.rand([3, 4]) - boxes[:, 2] += boxes[:, 0] + 3 - boxes[:, 3] += boxes[:, 1] + 4 - boxes_num = paddle.to_tensor([3]).astype("int32") - verify_model(RoiAlign(), input_data=[input_data, boxes, boxes_num]) - verify_model(RoiAlign(aligned=True), input_data=[input_data, boxes, boxes_num]) - verify_model( - RoiAlign(spatial_scale=2.0, aligned=True), input_data=[input_data, boxes, boxes_num] - ) - - -@tvm.testing.uses_gpu -def test_forward_softmax_with_cross_entropy(): - class SoftmaxWithCrossEntropy(nn.Layer): - def __init__(self, soft_label=False, ignore_index=-100, return_softmax=False, axis=-1): - super(SoftmaxWithCrossEntropy, self).__init__() - self.soft_label = soft_label - self.ignore_index = ignore_index - self.return_softmax = return_softmax - self.axis = axis - - @paddle.jit.to_static - def forward(self, input_data, label): - return paddle.nn.functional.softmax_with_cross_entropy( - input_data, - label, - soft_label=self.soft_label, - ignore_index=self.ignore_index, - return_softmax=self.return_softmax, - axis=self.axis, - ) - - input_data = paddle.rand([5, 3], dtype="float32") - label = paddle.randint(0, 2, [5, 1]) - verify_model(SoftmaxWithCrossEntropy(), input_data=[input_data, label]) - verify_model(SoftmaxWithCrossEntropy(return_softmax=True), input_data=[input_data, label]) - verify_model( - SoftmaxWithCrossEntropy(return_softmax=True, ignore_index=1), input_data=[input_data, label] - ) - input_data = paddle.rand([5, 4, 3], dtype="float32") - label = paddle.randint(0, 2, [5, 1, 3]) - verify_model(SoftmaxWithCrossEntropy(axis=1), input_data=[input_data, label]) - label = paddle.randint(0, 2, [5, 4, 3]).astype("float32") - verify_model(SoftmaxWithCrossEntropy(soft_label=True), input_data=[input_data, label]) - verify_model(SoftmaxWithCrossEntropy(soft_label=True, axis=0), input_data=[input_data, label]) - - -@tvm.testing.uses_gpu -def test_forward_pool3d(): - class Pool3D1(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool3d(inputs, kernel_size=2, stride=2, padding=0) - - class Pool3D2(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.adaptive_avg_pool3d(inputs, output_size=[3, 3, 3]) - - class Pool3D3(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool3d( - inputs, - kernel_size=3, - stride=1, - padding=[1, 1, 1], - exclusive=False, - divisor_override=2.5, - ) - - class Pool3D4(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool3d( - inputs, - kernel_size=2, - stride=1, - padding=[[0, 0], [0, 0], [1, 1], [1, 1], [1, 1]], - ceil_mode=True, - data_format="NCDHW", - ) - - class Pool3D5(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs): - return nn.functional.avg_pool3d( - inputs, - kernel_size=2, - stride=1, - padding=[[0, 0], [1, 1], [1, 1], [1, 1], [0, 0]], - ceil_mode=True, - data_format="NDHWC", - ) - - input_shapes = [[1, 2, 2, 8, 8], [1, 2, 3, 10, 10]] # [N, C, D, H, W] - for input_shape in input_shapes: - input_data = paddle.uniform(shape=input_shape, dtype="float32", min=-1, max=1) - verify_model(Pool3D1(), input_data=input_data) - verify_model(Pool3D2(), input_data=input_data) - verify_model(Pool3D3(), input_data=input_data) - verify_model(Pool3D4(), input_data=input_data) - verify_model(Pool3D5(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_set_value(): - class SetValue(nn.Layer): - @paddle.jit.to_static - def forward(self, inputs, update_input): - x = inputs + 1 - x[3:] = 3 - x[1:] = 3.0 - x[2:] = update_input - x[0] = 1 - x[-3:-2] = 1 - x[0][0] = 5 - return x - - input_shapes = [[5, 2], [10, 3], [10, 3, 3]] - for input_shape in input_shapes: - input_data = paddle.uniform(shape=input_shape, dtype="float32", min=-1, max=1) - update_shape = input_shape.copy() - update_shape[0] = input_shape[0] - 2 - update_input = paddle.uniform(shape=update_shape, dtype="float32", min=-1, max=1) - verify_model(SetValue(), input_data=[input_data, update_input]) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/pytorch/qnn_test.py b/tests/python/frontend/pytorch/qnn_test.py deleted file mode 100644 index 1cc1a46cea6b..000000000000 --- a/tests/python/frontend/pytorch/qnn_test.py +++ /dev/null @@ -1,803 +0,0 @@ -# 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. -""" Tests on quantized torch model conversion """ -import os - -import numpy as np -import torch -import tvm -import tvm.testing -from PIL import Image -from torch import nn -from torch.quantization import ( - DeQuantStub, - QuantStub, - QuantWrapper, - fuse_modules, - get_default_qat_qconfig, - prepare_qat, -) -from tvm import relay -from tvm.contrib.download import download_testdata -from tvm.relay.frontend.pytorch_utils import is_version_greater_than -from tvm.relay.op.contrib.register import get_pattern_table, register_pattern_table - - -def torch_version_check(): - from packaging import version - - return version.parse(torch.__version__) > version.parse("1.4.0") - - -def get_tvm_runtime(script_module, input_name, ishape, keep_quantized_weight=False, target="llvm"): - input_shapes = [(input_name, ishape)] - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch( - script_module, input_shapes, keep_quantized_weight=keep_quantized_weight - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch( - script_module, input_shapes, keep_quantized_weight=keep_quantized_weight - ) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - if keep_quantized_weight: - for p in params.values(): - assert p.dtype in ["int8", "int32"] - - with tvm.transform.PassContext(opt_level=3): - # test on only cpu for now, torch cannot run quant models on cuda - # also not to make CI too slow - lib = relay.build(mod, target=target, params=params) - - runtime = tvm.contrib.graph_executor.GraphModule(lib["default"](tvm.device(target, 0))) - return runtime - - -def get_qconfig(per_channel): - from torch.quantization.observer import ( - MovingAverageMinMaxObserver, - default_weight_observer, - ) - - if per_channel: - return torch.quantization.get_default_qconfig("fbgemm") - else: - act = MovingAverageMinMaxObserver.with_args(reduce_range=False) - return torch.quantization.QConfig(activation=act, weight=default_weight_observer) - - -def quantize_model(model, inp, per_channel=False): - model.fuse_model() - model.qconfig = get_qconfig(per_channel) - torch.quantization.prepare(model, inplace=True) - model(inp) - torch.quantization.convert(model, inplace=True) - - -class ConvBn(nn.Module): - def __init__(self, with_relu=False): - super().__init__() - layers = [nn.Conv2d(3, 32, 3, bias=True), nn.BatchNorm2d(32)] - if with_relu: - layers.append(nn.ReLU()) - self.conv = nn.Sequential(*layers) - self.quant_wrap = QuantWrapper(self.conv) - self.with_relu = with_relu - - def forward(self, x): - return self.quant_wrap(x) - - def fuse_model(self): - indices = ["0", "1"] - if self.with_relu: - indices.append("2") - fuse_modules(self.conv, indices, inplace=True) - - -class ConvTranspose(nn.Module): - def __init__(self): - super().__init__() - layers = [nn.ConvTranspose2d(3, 32, 3, bias=True)] - self.conv = nn.Sequential(*layers) - self.quant_wrap = QuantWrapper(self.conv) - - def forward(self, x): - return self.quant_wrap(x) - - def fuse_model(self): - pass - - -class Linear(nn.Module): - def __init__(self, with_relu=False): - super().__init__() - layers = [nn.Linear(16, 32)] - if with_relu: - layers.append(nn.ReLU()) - self.fc = nn.Sequential(*layers) - self.quant_wrap = QuantWrapper(self.fc) - self.with_relu = with_relu - - def forward(self, x): - return self.quant_wrap(x) - - def fuse_model(self): - if self.with_relu: - fuse_modules(self.fc, ["0", "1"], inplace=True) - - -class ReLU(nn.Module): - def __init__(self): - super().__init__() - self.relu = QuantWrapper(nn.ReLU()) - - def forward(self, x): - return self.relu(x) - - def fuse_model(self): - pass - - -class LeakyReLU(nn.Module): - def __init__(self): - super().__init__() - self.leaky_relu = QuantWrapper(nn.LeakyReLU()) - - def forward(self, x): - return self.leaky_relu(x) - - def fuse_model(self): - pass - - -# Mobilenet V3 related modules -class Hsigmoid(nn.Module): - def __init__(self, add_stub=False): - super().__init__() - self.quant = QuantStub() - self.dequant = DeQuantStub() - self.add_stub = add_stub - self.hsigmoid = nn.Hardsigmoid() - - def forward(self, x): - if self.add_stub: - x = self.quant(x) - x = self.hsigmoid(x) - if self.add_stub: - x = self.dequant(x) - return x - - def fuse_model(self): - pass - - -class Hswish(nn.Module): - def __init__(self, add_stub=False): - super().__init__() - self.hswish = QuantWrapper(nn.Hardswish()) - - def forward(self, x): - return self.hswish(x) - - def fuse_model(self): - pass - - -class SqueezeExcite(nn.Module): - def __init__(self, channel, reduction=4, add_stub=False): - super(SqueezeExcite, self).__init__() - self.avg_pool = nn.AdaptiveAvgPool2d(1) - self.fc = nn.Sequential( - nn.Linear(channel, channel // reduction, bias=False), - nn.ReLU(inplace=True), - nn.Linear(channel // reduction, channel, bias=False), - Hsigmoid(add_stub=False), - ) - self.fmul = nn.quantized.FloatFunctional() - self.quant = QuantStub() - self.dequant = DeQuantStub() - self.add_stub = add_stub - - def forward(self, x): - b, c, _, _ = x.size() - if self.add_stub: - x = self.quant(x) - y = self.avg_pool(x).view(b, c) - y = self.fc(y).view(b, c, 1, 1) - out = self.fmul.mul(x, y.expand_as(x)) - if self.add_stub: - return self.dequant(out) - else: - return out - - def fuse_model(self): - fuse_modules(self.fc, ["0", "1"], inplace=True) - - -# test on quantized::mul_scalar with negative scale -class MulScalarNegative(nn.Module): - def __init__(self): - super().__init__() - self.float_op = nn.quantized.FloatFunctional() - self.quant = QuantStub() - self.dequant = DeQuantStub() - - def forward(self, x): - x = self.quant(x) - mul = self.float_op.mul_scalar(x, -0.3) - return self.dequant(mul) - - def fuse_model(self): - pass - - -class UpsamplingBilinear(nn.Module): - def __init__(self): - super().__init__() - self.quant = QuantStub() - self.dequant = DeQuantStub() - - def forward(self, x): - x = self.quant(x) - upsample = nn.functional.interpolate(x, scale_factor=2, mode="bilinear", align_corners=True) - return self.dequant(upsample) - - def fuse_model(self): - pass - - -class AvgPool2d(nn.Module): - def __init__(self): - super().__init__() - self.pool = QuantWrapper(nn.AvgPool2d(kernel_size=2)) - - def forward(self, x): - return self.pool(x) - - def fuse_model(self): - pass - - -class AdaptiveAvgPool2d(nn.Module): - def __init__(self): - super().__init__() - self.pool = QuantWrapper(nn.AdaptiveAvgPool2d((1, 1))) - - def forward(self, x): - return self.pool(x) - - def fuse_model(self): - pass - - -def test_quantized_modules(): - imagenet_ishape = (1, 3, 224, 224) - - qmodules = [ - ("relu", imagenet_ishape, ReLU(), False), - ("upsample bilinear", (1, 3, 64, 64), UpsamplingBilinear(), False), - ("avgpool", imagenet_ishape, AvgPool2d(), False), - ] - - for per_channel in [False, True]: - if per_channel: - postfix = ", per_channel" - else: - postfix = "" - - qmodules += [ - ("conv_bn" + postfix, imagenet_ishape, ConvBn(), per_channel), - ("conv_bn_relu" + postfix, imagenet_ishape, ConvBn(with_relu=True), per_channel), - ("linear" + postfix, (16, 16), Linear(), per_channel), - ("linear_relu" + postfix, (16, 16), Linear(with_relu=True), per_channel), - ("conv_transpose", imagenet_ishape, ConvTranspose(), False), - ("hsigmoid", imagenet_ishape, Hsigmoid(add_stub=True), False), - ("hswish", imagenet_ishape, Hswish(), False), - ("semodule", (1, 16, 64, 64), SqueezeExcite(16, add_stub=True), False), - ("semodule, per_channel", (1, 16, 64, 64), SqueezeExcite(16, add_stub=True), True), - ("mul_scalar negative", imagenet_ishape, MulScalarNegative(), False), - ("leaky_relu", imagenet_ishape, LeakyReLU(), False), - ] - - for (module_name, ishape, raw_module, per_channel) in qmodules: - raw_module.eval() - inp = torch.rand(ishape) - - # quantized conv_transpose2d is supported only with qnnpack engine before torch v1.8.0. - if module_name == "conv_transpose" and not is_version_greater_than("1.7.1"): - prev_engine = torch.backends.quantized.engine - torch.backends.quantized.engine = "qnnpack" - quantize_model(raw_module, inp, per_channel=per_channel) - torch.backends.quantized.engine = prev_engine - else: - quantize_model(raw_module, inp, per_channel=per_channel) - - script_module = torch.jit.trace(raw_module, inp).eval() - - with torch.no_grad(): - pt_result = script_module(inp.clone()).numpy() - - input_name = "input" - runtime = get_tvm_runtime(script_module, input_name, ishape) - runtime.set_input(input_name, inp.numpy().copy()) - runtime.run() - tvm_result = runtime.get_output(0).numpy() - - max_abs_diff = np.max(np.abs(tvm_result - pt_result)) - mean_abs_diff = np.mean(np.abs(tvm_result - pt_result)) - num_identical = np.sum(tvm_result == pt_result) - match_ratio = num_identical / float(np.prod(tvm_result.shape)) - - print(module_name, max_abs_diff, mean_abs_diff, match_ratio) - - if "linear" in module_name and tvm.get_global_func("tvm.contrib.cublas.matmul", True): - runtime = get_tvm_runtime(script_module, input_name, ishape, target="cuda -libs=cublas") - runtime.set_input(input_name, inp.numpy().copy()) - runtime.run() - cublas_result = runtime.get_output(0).numpy() - # It is generally safe to enable this assertion, but disabled for CI - # tvm.testing.assert_allclose(cublas_result, pt_result, atol=1e-5, rtol=1e-5) - print(np.max(np.abs(cublas_result - pt_result))) - - # sample outputs - """ - relu 0.0039215684 2.6052087e-08 0.9999933567176871 - leaky_relu 0.0 0.0 1.0 - upsample bilinear 0.0 0.0 1.0 - conv_bn 0.22062653 0.011478779 0.6909348115006899 - conv_bn_relu 0.3700896 0.010921672 0.7489366477964451 - linear 0.15987062 0.009231662 0.794921875 - linear_relu 0.14180502 0.0053220326 0.8828125 - conv_transpose 0.0033792555 4.4658788e-07 0.9998678439971806 - conv_bn, per_channel 0.01654929 2.9486866e-06 0.9998218235127019 - conv_bn_relu, per_channel 0.009089053 1.4926576e-06 0.9998357732732732 - linear, per_channel 0.0 0.0 1.0 - linear_relu, per_channel 0.0 0.0 1.0 - hsigmoid 0.002614379 0.00020525524 0.9214896896258503 - hswish 0.0026143193 1.7367661e-08 0.9999933567176871 - hswish, per_channel 0.0 0.0 1.0 - semodule, per_channel 0.0039885044 0.0008620687 0.7838592529296875 - mul_scalar negative 0.0011764616 7.815566e-09 0.9999933567176871 - """ - - # we cannot make any guarantee on how close the raw output is to torch - # tvm.testing.assert_allclose(tvm_result, pt_result, rtol=1e-1, atol=1e-1) - - -def test_quantized_imagenet(): - def get_transform(): - import torchvision.transforms as transforms - - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) - return transforms.Compose( - [transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), normalize] - ) - - def get_real_image(im_height, im_width): - repo_base = "https://github.com/dmlc/web-data/raw/main/tensorflow/models/InceptionV1/" - img_name = "elephant-299.jpg" - image_url = os.path.join(repo_base, img_name) - img_path = download_testdata(image_url, img_name, module="data") - return Image.open(img_path).resize((im_height, im_width)) - - def get_imagenet_input(): - im = get_real_image(224, 224) - preprocess = get_transform() - pt_tensor = preprocess(im) - return np.expand_dims(pt_tensor.numpy(), 0) - - from torchvision.models.quantization import googlenet as qgooglenet - from torchvision.models.quantization import inception as qinception - from torchvision.models.quantization import mobilenet as qmobilenet - from torchvision.models.quantization import ( - mobilenet_v3_large as qmobilenet_v3_large, - ) - from torchvision.models.quantization import resnet as qresnet - - per_channel = True - qmodels = [ - ("resnet18", qresnet.resnet18(pretrained=True), per_channel), - ("mobilenet_v2", qmobilenet.mobilenet_v2(pretrained=True), per_channel), - ("inception_v3", qinception.inception_v3(pretrained=True), per_channel), - # tracing quantized googlenet broken as of v1.6 - # ("googlenet", qgooglenet(pretrained=True), per_channel), - # As of v1.10, quantized mobilenet v3 has a weird segfault issue - # during make_conv_packed_param - # See https://ci.tlcpack.ai/blue/organizations/jenkins/tvm/detail/ci-docker-staging/192 - # ("mobilenet_v3_large", qmobilenet_v3_large(pretrained=True, quantize=True).eval(), True) - ] - - results = [] - - for (model_name, raw_model, per_channel) in qmodels: - raw_model.eval() - - if per_channel: - model_name += ", per channel quantization" - else: - model_name += ", per tensor quantization" - - inp = get_imagenet_input() - pt_inp = torch.from_numpy(inp) - - if "mobilenet_v3_large" not in model_name: - # mv3 was qat-ed, quantize=True option above makes it already quantized - quantize_model(raw_model, pt_inp, per_channel=per_channel) - - script_module = torch.jit.trace(raw_model, pt_inp).eval() - - with torch.no_grad(): - pt_result = script_module(pt_inp).numpy() - - input_name = "image" - runtime = get_tvm_runtime(script_module, input_name, (1, 3, 224, 224)) - runtime.set_input(input_name, inp) - runtime.run() - - tvm_result = runtime.get_output(0).numpy() - - results.append((model_name, pt_result[0], tvm_result[0])) - - for (model_name, pt_result, tvm_result) in results: - max_abs_diff = np.max(np.abs(tvm_result - pt_result)) - mean_abs_diff = np.mean(np.abs(tvm_result - pt_result)) - num_identical = np.sum(tvm_result == pt_result) - pt_top3_labels = np.argsort(pt_result)[::-1][:3] - tvm_top3_labels = np.argsort(tvm_result)[::-1][:3] - - print("\nModel name: %s" % model_name) - print("PyTorch top3 label:", pt_top3_labels) - print("TVM top3 label:", tvm_top3_labels) - print("max abs diff:", max_abs_diff) - print("mean abs_diff:", mean_abs_diff) - print("%d in 1000 raw outputs identical." % num_identical) - - assert set(pt_top3_labels) == set(tvm_top3_labels) - - # sample outputs - """ - Model name: resnet18, per tensor quantization - PyTorch top3 label: [386 101 385] - TVM top3 label: [386 101 385] - max abs diff: 0.65681696 - mean abs_diff: 0.14055882 - 236 in 1000 raw outputs identical. - - Model name: mobilenet_v2, per tensor quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 2.1262953 - mean abs_diff: 0.41025686 - 101 in 1000 raw outputs identical. - - Model name: inception_v3, per tensor quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 0.9994669 - mean abs_diff: 0.098697364 - 272 in 1000 raw outputs identical. - - Model name: googlenet, per tensor quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 0.28248847 - mean abs_diff: 0.0634469 - 274 in 1000 raw outputs identical. - - Model name: resnet18, per channel quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 0.65908074 - mean abs_diff: 0.1274223 - 469 in 1000 raw outputs identical. - - Model name: mobilenet_v2, per channel quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 0.71120834 - mean abs_diff: 0.15883648 - 423 in 1000 raw outputs identical. - - Model name: inception_v3, per channel quantization - PyTorch top3 label: [386 101 385] - TVM top3 label: [386 101 385] - max abs diff: 1.3372154 - mean abs_diff: 0.1225224 - 401 in 1000 raw outputs identical. - - Model name: googlenet, per channel quantization - PyTorch top3 label: [101 386 385] - TVM top3 label: [101 386 385] - max abs diff: 0.34015465 - mean abs_diff: 0.054197952 - 558 in 1000 raw outputs identical. - """ - - -def test_serialized_modules(): - ishape = (1, 16, 64, 64) - raw_module = AdaptiveAvgPool2d().eval() - inp = torch.rand(ishape) - - quantize_model(raw_module, inp) - script_module = torch.jit.trace(raw_module, inp).eval() - - fname = "tmp.pt" - torch.jit.save(script_module, fname) - loaded = torch.jit.load(fname) - os.remove(fname) - - with torch.no_grad(): - pt_result = loaded(inp.clone()).numpy() - - input_name = "input" - runtime = get_tvm_runtime(loaded, input_name, ishape) - runtime.set_input(input_name, inp.numpy().copy()) - runtime.run() - tvm_result = runtime.get_output(0).numpy() - - # with 0.5ish results, 1e-2 is relative accuracy close to 2**-6. - # for simple layers like here this should be achievable - # with 8 bit quantization - # we only require 90% match just to be sure - num_identical = np.sum(np.abs(tvm_result - pt_result) < 1e-2) - match_ratio = num_identical / float(np.prod(tvm_result.shape)) - assert match_ratio > 0.90 - - -def test_quantize_dynamic(): - # A wrapper is required for quantize_dynamic to work correctly - class LinearWrapper(nn.Module): - def __init__(self, in_dim, hidden_dim): - super().__init__() - self.linear = nn.Linear(in_dim, hidden_dim) - - def forward(self, inp): - return self.linear(inp) - - torch.manual_seed(0) - mod = LinearWrapper(16, 32) - - for qconfig in [ - torch.quantization.per_channel_dynamic_qconfig, - torch.quantization.default_dynamic_qconfig, - ]: - for ishape in [(16, 16), (10, 16, 16)]: - qspec = {nn.Linear: qconfig} - qmod = torch.quantization.quantize_dynamic(mod, qconfig_spec=qspec, dtype=torch.qint8) - - inp = torch.randn(*ishape) - script_module = torch.jit.trace(qmod, inp).eval() - - with torch.no_grad(): - pt_result = script_module(inp.clone()).numpy() - - input_name = "input" - runtime = get_tvm_runtime(script_module, "input", inp.shape) - runtime.set_input(input_name, inp.numpy().copy()) - runtime.run() - tvm_result = runtime.get_output(0).numpy() - - # Only compare with the PyTorch result for version v1.6 or newer - # Have seen a strange accuracy problem from PyTorch 1.4 and 1.5 - # Even with the manual random seed set, the same PyTorch - # version can outputs slightly different results depending on an environment. - # Outputs from v1.6 seem reliable. TVM's outputs are always the same - if is_version_greater_than("1.5.1"): - tvm.testing.assert_allclose(tvm_result, pt_result, rtol=1e-4, atol=1e-4) - - -def make_qnn_add_pattern(): - from tvm.relay.dataflow_pattern import is_op, wildcard - - lhs = wildcard() - rhs = wildcard() - lhs_scale = wildcard() - lhs_zero_point = wildcard() - rhs_scale = wildcard() - rhs_zero_point = wildcard() - output_scale = wildcard() - output_zero_point = wildcard() - qadd = is_op("qnn.add")( - lhs, - rhs, - lhs_scale, - lhs_zero_point, - rhs_scale, - rhs_zero_point, - output_scale, - output_zero_point, - ) - return qadd.optional(is_op("clip")) - - -@register_pattern_table("test_table") -def pattern_table(): - return [ - ("qnn_add", make_qnn_add_pattern()), - ] - - -def run_qnn_mergecomposite(script_module, input_name, ishape): - input_shapes = [(input_name, ishape)] - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch(script_module, input_shapes) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(script_module, input_shapes) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - pattern_table = get_pattern_table("test_table") - with tvm.transform.PassContext(opt_level=3): - pass_list = [ - tvm.relay.transform.SimplifyInference(), - tvm.relay.transform.MergeComposite(pattern_table), - ] - composite_partition = tvm.transform.Sequential(pass_list) - partitioned = composite_partition(mod) - - -def test_qnn_mergecomposite(): - from torchvision.models.quantization import resnet as qresnet - - model = qresnet.resnet18(pretrained=True) - model.eval() - - inp = torch.zeros((1, 3, 224, 224)) - model.fuse_model() - model.qconfig = torch.quantization.get_default_qconfig("fbgemm") - torch.quantization.prepare(model, inplace=True) - model(inp) - torch.quantization.convert(model, inplace=True) - script_module = torch.jit.trace(model, inp).eval() - - input_name = "image" - run_qnn_mergecomposite(script_module, input_name, inp.shape) - - -def test_keep_quantized_weight(): - qmodules = [] - - for per_channel in [False, True]: - qmodules += [ - ((1, 3, 224, 224), ConvBn(), per_channel), - ((16, 16), Linear(), per_channel), - ] - - for (ishape, raw_module, per_channel) in qmodules: - raw_module.eval() - inp = torch.rand(ishape) - - quantize_model(raw_module, inp, per_channel=per_channel) - script_module = torch.jit.trace(raw_module, inp).eval() - - input_name = "input" - - runtime = get_tvm_runtime(script_module, input_name, ishape, keep_quantized_weight=False) - runtime.set_input(input_name, inp.numpy().copy()) - runtime.run() - tvm_result = runtime.get_output(0).numpy() - - runtime_int8_weight = get_tvm_runtime( - script_module, input_name, ishape, keep_quantized_weight=True - ) - runtime_int8_weight.set_input(input_name, inp.numpy().copy()) - runtime_int8_weight.run() - tvm_result_int8_weight = runtime_int8_weight.get_output(0).numpy() - - tvm.testing.assert_allclose(tvm_result, tvm_result_int8_weight) - - -def test_tuple_lowered(): - # See the following discuss thread for details - # https://discuss.tvm.apache.org/t/bug-frontend-pytorch-relay-ir-is-inconsistent-with-that-of-the-original-model/12010 - - class ConvBnRelu(nn.Module): - def __init__(self, inp, oup, kernel_size=3, stride=1, padding=1, bias=True, groups=1): - super(ConvBnRelu, self).__init__() - if groups > 1: - self.conv = nn.Conv2d( - inp, inp, kernel_size, stride, padding, bias=bias, groups=groups - ) - self.bn = nn.BatchNorm2d(inp) - else: - self.conv = nn.Conv2d( - inp, oup, kernel_size, stride, padding, bias=bias, groups=groups - ) - self.bn = nn.BatchNorm2d(oup) - self.relu = nn.ReLU(inplace=True) - - def forward(self, inputs): - x = self.conv(inputs) - x = self.bn(x) - x = self.relu(x) - return x - - def conv_bn(inp, oup, stride=1, width_multiplier=1): - return ConvBnRelu(inp, oup, kernel_size=3, stride=stride, padding=1, bias=False) - - def conv_dw(inp, oup, stride, width_multiplier=1, padding=1): - dw_block = nn.Sequential() - depth_wise = ConvBnRelu( - inp, oup, kernel_size=3, stride=stride, padding=padding, bias=False, groups=inp - ) - point_wise = ConvBnRelu(inp, oup, kernel_size=1, stride=1, padding=0, bias=False) - - dw_block.add_module("depth_wise", depth_wise) - dw_block.add_module("point_wise", point_wise) - - return dw_block - - class Backbone(nn.Module): - def __init__(self, width_multiplier=1): - super(Backbone, self).__init__() - self.width_multiplier = width_multiplier - self.conv1 = conv_bn(3, 16, 2, self.width_multiplier) - self.conv2 = conv_dw(16, 32, 1, self.width_multiplier) - - def forward(self, inputs): - x1 = self.conv1(inputs) - x2 = self.conv2(x1) - return [x1, x2] - - class QuantizableBackbone(nn.Module): - def __init__(self, inputsize=(128, 128)): - super(QuantizableBackbone, self).__init__() - self.quant = QuantStub() - self.dequant = DeQuantStub() - self.backbone = Backbone() - - def fuse_model(self): - fuse_modules_qat = getattr(torch.ao.quantization, "fuse_modules_qat", fuse_modules) - for idx, m in enumerate(self.modules()): - if type(m) == ConvBnRelu: - fuse_modules_qat(m, ["conv", "bn", "relu"], inplace=True) - - def forward(self, input): - input = self.quant(input) - y0, y1 = self.backbone(input) - y0 = self.dequant(y0) - y1 = self.dequant(y1) - return y0, y1 - - fp32_input = torch.randn(1, 3, 128, 128) - model = QuantizableBackbone() - model.train() - model.fuse_model() - model.qconfig = get_default_qat_qconfig("qnnpack") - - prepare_qat(model, inplace=True) - - model.eval() - model(fp32_input) - - model_int8 = torch.quantization.convert(model, inplace=True) - script_module = torch.jit.trace(model_int8, fp32_input).eval() - - input_infos = [("input", (fp32_input.shape, "float32"))] - with tvm.testing.disable_span_filling(): - mod, _ = relay.frontend.from_pytorch(script_module, input_infos) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(script_module, input_infos) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - output = mod["main"].body - - assert isinstance(output, relay.Tuple) and len(output) == 2 - dq1, dq2 = output - assert dq1.op.name == "qnn.dequantize" and dq2.op.name == "qnn.dequantize" - scale1 = dq1.args[1].data.numpy().item() - scale2 = dq2.args[1].data.numpy().item() - assert scale1 != scale2 diff --git a/tests/python/frontend/pytorch/test_forward.py b/tests/python/frontend/pytorch/test_forward.py deleted file mode 100644 index 9f8fac93061c..000000000000 --- a/tests/python/frontend/pytorch/test_forward.py +++ /dev/null @@ -1,5884 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, missing-function-docstring -"""Unit tests for various models and operators""" -import os -import platform -import sys - -from packaging import version as package_version - -import pytest -import numpy as np - -import torch -from torch.nn import Module -from torch.nn import functional as F -import torchvision - -import tvm -import tvm.testing -from tvm import relay -from tvm.contrib import graph_executor -from tvm.contrib.nvcc import have_fp16 -from tvm.contrib import cudnn, utils -from relay.utils.tag_span import _create_span, _set_span, _verify_structural_equal_with_span - -sys.setrecursionlimit(10000) -if torch.cuda.is_available(): - torch.backends.cuda.matmul.allow_tf32 = False - torch.backends.cudnn.allow_tf32 = False - - -def list_ops(expr): - """list_ops""" - - class OpLister(tvm.relay.ExprVisitor): - """OpLister inherits from ExprVisitor""" - - def visit_op(self, op): - if op not in self.node_set: - self.node_list.append(op) - return super().visit_op(op) - - def list_nodes(self, expr): - self.node_set = {} - self.node_list = [] - self.visit(expr) - return self.node_list - - return OpLister().list_nodes(expr) - - -def assert_shapes_match(tru, est): - """Verfiy whether the shapes are equal""" - if tru.shape != est.shape: - msg = "Output shapes {} and {} don't match" - raise AssertionError(msg.format(tru.shape, est.shape)) - - -def load_torchvision(model_name): - """Given a model name, returns a Torchvision model in eval mode as well - as an example input.""" - with torch.no_grad(): - if model_name.startswith("inception"): - height = width = 299 - mean = [0.5, 0.5, 0.5] - std = [0.5, 0.5, 0.5] - else: - height = width = 224 - mean = [0.485, 0.456, 0.406] - std = [0.229, 0.224, 0.225] - input_shape = [1, 3, height, width] - input_data = torch.randn(input_shape).float() - for channel in range(3): - input_data[:, channel] -= mean[channel] - input_data[:, channel] /= std[channel] - - if model_name.startswith("googlenet"): - model = getattr(torchvision.models, model_name)(pretrained=True, aux_logits=True) - else: - model = getattr(torchvision.models, model_name)(pretrained=True) - model = model.float().eval() - return model, [input_data] - - -def load_pretrainedmodels(model_name): - """Given a model name, returns a pretrainedmodels.pytorch model in eval - mode as well as an example input.""" - # pylint: disable=import-outside-toplevel - import pretrainedmodels # https://github.com/Cadene/pretrained-models.pytorch - - model = getattr(pretrainedmodels, model_name)().float().eval() - input_shape = [1, *model.input_size] - input_data = torch.rand(input_shape).float() * 256 - for channel in range(3): - input_data[:, channel] -= model.mean[channel] - input_data[:, channel] /= model.std[channel] - return model, [input_data] - - -def load_model(model_name): - """Given a model name, returns a model as well as an example input.""" - if hasattr(torchvision.models, model_name): - return load_torchvision(model_name) - # pylint: disable=import-outside-toplevel - try: - import pretrainedmodels - - if hasattr(pretrainedmodels, model_name): - return load_pretrainedmodels(model_name) - except ModuleNotFoundError as e: - raise ModuleNotFoundError("Please install pretrainedmodels.pytorch") from e - raise RuntimeError("Model not supported") - - -def verify_model( - model_name, - input_data=None, - custom_convert_map=None, - rtol=1e-5, - atol=1e-5, - expected_ops=None, - kind="graph", - check_correctness=True, - cpu_only=False, - validate_structural_equal=True, -): - """Assert that the output of a compiled model matches with that of its - baseline.""" - input_data = [] if input_data is None else input_data - custom_convert_map = custom_convert_map or {} - expected_ops = expected_ops or [] - if isinstance(model_name, str): - baseline_model, baseline_input = load_model(model_name) - elif isinstance(input_data, list): - baseline_model = model_name - baseline_input = input_data - elif isinstance(input_data, torch.Tensor) or not input_data.shape: - baseline_model = model_name - baseline_input = [input_data] - else: - assert False, "Unexpected input format" - if torch.cuda.is_available(): - if isinstance(baseline_model, torch.nn.Module): - baseline_model = baseline_model.cuda() - baseline_input = [inp.cuda() for inp in baseline_input] - - with torch.no_grad(): - baseline_outputs = baseline_model(*[input.clone() for input in baseline_input]) - - if isinstance(baseline_outputs, tuple): - baseline_outputs = tuple(out.cpu().numpy() for out in baseline_outputs) - else: - baseline_outputs = (baseline_outputs.cpu().numpy(),) - - trace = torch.jit.trace(baseline_model, [input.clone() for input in baseline_input]) - if isinstance(baseline_model, torch.nn.Module): - trace = trace.float().eval() - - if torch.cuda.is_available(): - trace = trace.cuda() - else: - trace = trace.cpu() - - input_names = [f"input{idx}" for idx, _ in enumerate(baseline_input)] - input_shapes = list(zip(input_names, [inp.shape for inp in baseline_input])) - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch(trace, input_shapes, custom_convert_map) - if validate_structural_equal: - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(trace, input_shapes, custom_convert_map) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - for arg in mod["main"].params[: len(input_names)]: - assert arg.name_hint in input_names - compiled_input = dict(zip(input_names, [inp.clone().cpu().numpy() for inp in baseline_input])) - - targets = ["llvm"] - if not cpu_only: - targets.append("cuda") - - with tvm.transform.PassContext(opt_level=3): - for target in targets: - if not tvm.runtime.enabled(target): - continue - dev = tvm.device(target, 0) - exe = relay.create_executor( - kind, mod=mod, params=params, device=dev, target=target - ).evaluate() - result = exe(**compiled_input) - if not isinstance(result, list): - result = [result] - - for i, baseline_output in enumerate(baseline_outputs): - output = result[i].numpy() - - assert_shapes_match(baseline_output, output) - if check_correctness: - tvm.testing.assert_allclose(baseline_output, output, rtol=rtol, atol=atol) - - if expected_ops: - - def visit(op): - if isinstance(op, tvm.ir.op.Op): - if op.name in expected_ops: - expected_ops.remove(op.name) - - tvm.relay.analysis.post_order_visit(mod["main"].body, visit) - - if expected_ops: - msg = "TVM Relay do not contain expected ops {}" - raise AssertionError(msg.format(expected_ops)) - - del model_name - del baseline_model - if torch.cuda.is_available(): - torch.cuda.empty_cache() - - -def verify_model_with_input( - test_func, - input_data, - *, - input_dict=None, - custom_convert_map=None, - rtol=1e-5, - atol=1e-5, - assert_shape_only=False, - validate_structural_equal=True, -): - """Generic function to generate and compare Pytorch and TVM output""" - input_dict = input_dict or {} - custom_convert_map = custom_convert_map or {} - baseline_outputs = test_func(*input_data) - trace = torch.jit.trace(test_func, [input.clone() for input in input_data]) - input_names = [f"input{idx}" for idx, _ in enumerate(input_data)] - input_shapes = list(zip(input_names, [inp.shape for inp in input_data])) - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch(trace, input_shapes, custom_convert_map) - if validate_structural_equal: - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(trace, input_shapes, custom_convert_map) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - with tvm.transform.PassContext(opt_level=3): - for target in ["llvm", "cuda"]: - if not tvm.runtime.enabled(target): - continue - dev = tvm.device(target, 0) - lib = relay.build(mod, target=target, params=params) - relay_model = graph_executor.GraphModule(lib["default"](dev)) - for name, value in input_dict.items(): - relay_model.set_input(name, value) - relay_model.run() - - compiled_output = relay_model.get_output(0).numpy() - assert_shapes_match(baseline_outputs, compiled_output) - if assert_shape_only is False: - tvm.testing.assert_allclose(baseline_outputs, compiled_output, rtol=rtol, atol=atol) - - -def gen_ir_module(model, inputs, use_parser_friendly_name=False): - """Helper function to generate IRModule with meaningful source information""" - - trace = torch.jit.trace(model, inputs) - input_names = ["input{}".format(idx) for idx, _ in enumerate(inputs)] - input_shapes = list(zip(input_names, [inp.shape for inp in inputs])) - mod, _ = relay.frontend.from_pytorch( - trace, - input_shapes, - use_parser_friendly_name=use_parser_friendly_name, - ) - return mod - - -# Single operator tests -@tvm.testing.uses_gpu -def test_forward_pixel_shuffle(): - """test_forward_pixel_shuffle""" - torch.set_grad_enabled(False) - input_shape = [1, 144, 16, 16] - - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.PixelShuffle(2).float().eval(), input_data=input_data) - verify_model(torch.nn.PixelShuffle(3).float().eval(), input_data=input_data) - verify_model(torch.nn.PixelShuffle(4).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_add(): - """test_forward_add""" - torch.set_grad_enabled(False) - input_shape = [10] - - class Add1(Module): - def forward(self, *args): - return args[0] + args[0] - - class Add2(Module): - def forward(self, *args): - return args[0] + 1 - - class Add3(Module): - def forward(self, *args): - ones = torch.ones(input_shape, dtype=torch.float) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] + ones - - class Add4(Module): - def forward(self, *args): - ones = torch.ones([], dtype=torch.float) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] + ones - - input_data = torch.rand(input_shape).float() - verify_model(Add1().float().eval(), input_data=input_data) - verify_model(Add2().float().eval(), input_data=input_data) - verify_model(Add3().float().eval(), input_data=input_data) - verify_model(Add4().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_subtract(): - """test_forward_subtract""" - torch.set_grad_enabled(False) - input_shape = [10] - - class Subtract1(Module): - def forward(self, *args): - return args[0] - args[0] - - class Subtract2(Module): - def forward(self, *args): - return args[0] - 1 - - class Subtract3(Module): - def forward(self, *args): - ones = torch.ones(input_shape) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] - ones - - class Subtract4(Module): - def forward(self, *args): - ones = torch.ones([]) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] - ones - - input_data = torch.rand(input_shape).float() - verify_model(Subtract1().float().eval(), input_data=input_data) - verify_model(Subtract2().float().eval(), input_data=input_data) - verify_model(Subtract3().float().eval(), input_data=input_data) - verify_model(Subtract4().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_multiply(): - """test_forward_multiply""" - torch.set_grad_enabled(False) - input_shape = [10] - - class Multiply1(Module): - def forward(self, *args): - return args[0] * args[0] - - class Multiply2(Module): - def forward(self, *args): - return args[0] * 1.0 - - class Multiply3(Module): - def forward(self, *args): - ones = torch.ones(input_shape) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] * ones - - class Multiply4(Module): - def forward(self, *args): - ones = torch.ones([]) - if torch.cuda.is_available(): - ones = ones.cuda() - return args[0] * ones - - input_data = torch.rand(input_shape).float() - verify_model(Multiply1().float().eval(), input_data=input_data) - verify_model(Multiply2().float().eval(), input_data=input_data) - verify_model(Multiply3().float().eval(), input_data=input_data) - verify_model(Multiply4().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_min_max(): - """test_min_max""" - - class Max(Module): - def forward(self, inp): - return torch.max(inp) - - class Min(Module): - def forward(self, inp): - return torch.min(inp) - - class Max2(Module): - def forward(self, inp): - out, _ = torch.max(inp, 1, keepdim=True) - return out - - class Min2(Module): - def forward(self, inp): - out, _ = torch.min(inp, 0, keepdim=False) - return out - - class Max3(Module): - def forward(self, lhs, rhs): - return torch.max(lhs, rhs) - - class Min3(Module): - def forward(self, lhs, rhs): - return torch.min(lhs, rhs) - - class Max4(Module): - def forward(self, inp): - out = torch.amax(inp, (1, 2), keepdim=True) - return out - - class Min4(Module): - def forward(self, inp): - out = torch.amin(inp, (0, 3), keepdim=False) - return out - - input_data = [torch.rand((10, 10, 10, 10)), torch.rand((10, 10, 10, 10))] - - verify_model(Max(), input_data=input_data[0]) - verify_model(Min(), input_data=input_data[0]) - verify_model(Max2(), input_data=input_data[0]) - verify_model(Min2(), input_data=input_data[0]) - verify_model(Max3(), input_data=input_data) - verify_model(Min3(), input_data=input_data) - verify_model(Max4(), input_data=input_data[0]) - verify_model(Min4(), input_data=input_data[0]) - - -@tvm.testing.uses_gpu -def test_minimum_maximum(): - """test_minimum_maximum""" - - class Maximum(Module): - def forward(self, lhs, rhs): - return torch.maximum(lhs, rhs) - - class Minimum(Module): - def forward(self, lhs, rhs): - return torch.minimum(lhs, rhs) - - input_data = [torch.rand((10, 10, 10, 10)), torch.rand((10, 10, 10, 10))] - - verify_model(Maximum(), input_data=input_data) - verify_model(Minimum(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_reciprocal(): - """test_forward_reciprocal""" - torch.set_grad_enabled(False) - input_shape = [2, 1, 10, 1, 10] - - class Reciprocal1(Module): - def forward(self, *args): - return args[0].reciprocal() - - input_data = torch.rand(input_shape).float() - verify_model(Reciprocal1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_repeat(): - """test_forward_repeat""" - torch.set_grad_enabled(False) - input_shape = [1, 3] - - class Repeat1(Module): - def forward(self, *args): - return args[0].repeat(1, 1) - - class Repeat2(Module): - def forward(self, *args): - return args[0].repeat(4, 2) - - class Repeat3(Module): - def forward(self, *args): - return args[0].repeat(4, 2, 1) - - input_data = torch.rand(input_shape).float() - verify_model(Repeat1().float().eval(), input_data=input_data) - verify_model(Repeat2().float().eval(), input_data=input_data) - verify_model(Repeat3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_repeat_interleave(): - """test_forward_repeat_interleave""" - torch.set_grad_enabled(False) - input_shape = [2, 2, 3] - - class RepeatInterleave1(Module): - def forward(self, *args): - return args[0].repeat_interleave(2) - - class RepeatInterleave2(Module): - def forward(self, *args): - return args[0].repeat_interleave(3, dim=0) - - class RepeatInterleave3(Module): - def forward(self, *args): - return args[0].repeat_interleave(2, dim=1) - - class RepeatInterleave4(Module): - def forward(self, *args): - return args[0].repeat_interleave(4, dim=2) - - input_data = torch.rand(input_shape).float() - verify_model(RepeatInterleave1().float().eval(), input_data=input_data) - verify_model(RepeatInterleave2().float().eval(), input_data=input_data) - verify_model(RepeatInterleave3().float().eval(), input_data=input_data) - verify_model(RepeatInterleave4().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_unsqueeze(): - """test_forward_unsqueeze""" - torch.set_grad_enabled(False) - input_shape = [10, 10] - - class Unsqueeze1(Module): - def forward(self, *args): - return args[0].unsqueeze(2) - - class Unsqueeze2(Module): - def forward(self, *args): - _ = args[0].unsqueeze_(2) - # Check whether operations after inplace unsqueeze works as expected - y = args[0].squeeze(2) - return torch.add(y, y) - - input_data = torch.rand(input_shape).float() - verify_model(Unsqueeze1().float().eval(), input_data=input_data) - verify_model(Unsqueeze2().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_squeeze(): - """test_forward_squeeze""" - torch.set_grad_enabled(False) - input_shape = [2, 1, 10, 1, 10] - - class Squeeze1(Module): - def forward(self, *args): - return args[0].squeeze() - - class Squeeze2(Module): - def forward(self, *args): - return args[0].squeeze(1) - - class Squeeze3(Module): - def forward(self, *args): - return args[0].squeeze((1, 3)) - - input_data = torch.rand(input_shape).float() - verify_model(Squeeze1().float().eval(), input_data=input_data) - verify_model(Squeeze2().float().eval(), input_data=input_data) - if package_version.parse(torch.__version__) >= package_version.parse("2.0.0"): - verify_model(Squeeze3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_arange(): - """test_forward_arange""" - torch.set_grad_enabled(False) - - class Arange1(Module): - def forward(self, *args): - return torch.arange(5) - - class Arange2(Module): - def forward(self, *args): - return torch.arange(2.5) - - class Arange3(Module): - def forward(self, *args): - return torch.arange(1, 4) - - class Arange4(Module): - def forward(self, *args): - return torch.arange(1, 2.5, 0.5) - - class Arange5(Module): - def forward(self, *args): - return torch.arange(1, 2, 1, dtype=torch.int32) - - class Arange6(Module): - def forward(self, *args): - return torch.arange(start=1, end=6, step=2) - - class Arange7(Module): - def forward(self, *args): - return torch.arange(1, 4, dtype=torch.float32) - - class Arange8(Module): - def forward(self, *args): - return torch.arange(1, 2, 1, dtype=torch.int16) - - class Arange9(Module): - def forward(self, *args): - end = torch.add(torch.tensor(4), 1) - return torch.arange(end) + torch.ones((5,), dtype=torch.int64) - - class Arange10(Module): - def forward(self, *args): - end = torch.add(torch.tensor(4.0), torch.tensor(1.0)) - return torch.arange(end) + torch.ones((5,), dtype=torch.float) - - class Arange11(Module): - def forward(self, *args): - start = torch.add(torch.tensor(1), 1) - end = torch.add(torch.tensor(4), 1) - step = torch.add(torch.tensor(2), 1) - out = torch.arange(start, end, step) - return out + torch.ones((3,), dtype=torch.int64) - - class Arange12(Module): - def forward(self, *args): - start = torch.add(torch.tensor(1), 1) - end = torch.add(torch.tensor(4), 1) - step = torch.add(torch.tensor(2.5), torch.tensor(4.1)) - out = torch.arange(start, end, step) - return out + torch.ones((3,), dtype=torch.float) - - verify_model(Arange1().float().eval()) - verify_model(Arange2().float().eval()) - verify_model(Arange3().float().eval()) - verify_model(Arange4().float().eval()) - verify_model(Arange5().float().eval()) - verify_model(Arange6().float().eval()) - verify_model(Arange7().float().eval()) - verify_model(Arange8().float().eval()) - verify_model(Arange9().float().eval()) - verify_model(Arange10().float().eval()) - verify_model(Arange11().float().eval()) - verify_model(Arange12().float().eval()) - - -@tvm.testing.uses_gpu -def test_forward_mesh_grid(): - """test_forward_mesh_grid""" - torch.set_grad_enabled(False) - - class MeshGrid1(Module): - def forward(self, *args): - x = torch.tensor([1, 2, 3]) - y = torch.tensor([4, 5, 6]) - grid_x, grid_y = torch.meshgrid([x, y]) - return grid_x, grid_y - - class MeshGrid2(Module): - def forward(self, *args): - x = torch.tensor([1, 2, 3], dtype=torch.float32) - y = torch.add(torch.tensor(5, dtype=torch.float32), 1) - grid_x, grid_y = torch.meshgrid([x, y]) - return grid_x, grid_y - - verify_model(MeshGrid1().float().eval()) - verify_model(MeshGrid2().float().eval()) - - -@tvm.testing.uses_gpu -def test_forward_abs(): - """test_forward_abs""" - torch.set_grad_enabled(False) - input_shape = [2, 1, 10, 1, 10] - - class Abs1(Module): - def forward(self, *args): - return args[0].abs() - - input_data = torch.rand(input_shape).float() - verify_model(Abs1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_concatenate(): - """test_forward_concatenate""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Concatenate1(Module): - def forward(self, *args): - return torch.cat([args[0][:, 0].unsqueeze(1), args[0][:, 1].unsqueeze(1)], 1) - - class Concatenate2(Module): - def forward(self, *args): - a = (args[0][:, :, 0] + 2) * 7 - b = (args[0][:, :, 1] + 3) * 11 - c = (args[0][:, :, 2] + 5) * 13 - return torch.cat([t.unsqueeze(2) for t in [a, b, c]], 2) - - class Concatenate3(Module): - """ - torch.concat is preserved as aten::concat only when in a nested module. - (In the most cases, It is converted to aten::cat instead of aten::concat.) - """ - - def __init__(self): - super().__init__() - - class _Concatenate(Module): - def forward(self, *args): - a = (args[0][:, :, 0] + 2) * 7 - b = (args[0][:, :, 1] + 3) * 11 - c = (args[0][:, :, 2] + 5) * 13 - return torch.concat([t.unsqueeze(2) for t in [a, b, c]], 2) - - self.mod = _Concatenate() - - def forward(self, *args): - return self.mod(*args) - - input_data = torch.rand(input_shape).float() - verify_model(Concatenate1().float().eval(), input_data=input_data) - verify_model(Concatenate2().float().eval(), input_data=input_data) - verify_model(Concatenate3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_relu(): - """test_forward_relu""" - torch.set_grad_enabled(False) - input_shape = [10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.ReLU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_relu6(): - """test_forward_relu6""" - torch.set_grad_enabled(False) - input_shape = [10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.ReLU6().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_prelu(): - """test_forward_prelu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.PReLU(num_parameters=3).eval(), input_data=input_data) - # Test when input channel > 1 and num parameters = 1 - verify_model(torch.nn.PReLU(num_parameters=1).eval(), input_data=input_data) - # Test when input dims < 2 - verify_model(torch.nn.PReLU(num_parameters=1).eval(), input_data=torch.randn(2)) - - -@tvm.testing.uses_gpu -def test_forward_leakyrelu(): - """test_forward_leakyrelu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.LeakyReLU().eval(), input_data=input_data) - verify_model(torch.nn.LeakyReLU(negative_slope=0.05).eval(), input_data=input_data) - verify_model(torch.nn.LeakyReLU(negative_slope=1.0, inplace=True).eval(), input_data=input_data) - verify_model( - torch.nn.LeakyReLU(negative_slope=1.25, inplace=True).eval(), input_data=input_data - ) - - -@tvm.testing.uses_gpu -def test_forward_elu(): - """test_forward_elu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.randn(input_shape).float() - verify_model(torch.nn.ELU().eval(), input_data=input_data) - verify_model(torch.nn.ELU(alpha=0.3).eval(), input_data=input_data) - verify_model(torch.nn.ELU(alpha=1.0).eval(), input_data=input_data) - verify_model(torch.nn.ELU(alpha=1.3).eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_celu(): - """test_forward_celu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.CELU().eval(), input_data=input_data) - verify_model(torch.nn.CELU(alpha=0.3).eval(), input_data=input_data) - verify_model(torch.nn.CELU(alpha=1.0).eval(), input_data=input_data) - verify_model(torch.nn.CELU(alpha=1.3).eval(), input_data=input_data) - input_data = torch.tensor([-1.0, 2.0], dtype=torch.float32) - verify_model(torch.nn.CELU().eval(), input_data=input_data) - - input_shape = [2, 0, 1] - input_data = torch.rand(input_shape).float() - with pytest.raises(RuntimeError): - verify_model(torch.nn.CELU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_gelu(): - """test_forward_gelu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.GELU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_selu(): - """test_forward_selu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.SELU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_silu(): - """test_forward_silu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.SiLU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_glu(): - """test_forward_glu""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.GLU().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_softplus(): - """test_forward_softplus""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Softplus().eval(), input_data=input_data) - verify_model(torch.nn.Softplus(beta=1.5, threshold=20).eval(), input_data=input_data) - verify_model(torch.nn.Softplus(beta=5, threshold=10).eval(), input_data=input_data) - verify_model(torch.nn.Softplus(beta=5, threshold=1).eval(), input_data=input_data) - verify_model(torch.nn.Softplus(beta=1, threshold=2).eval(), input_data=input_data) - verify_model(torch.nn.Softplus(beta=1, threshold=-1).eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_softsign(): - """test_forward_softsign""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Softsign().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_log_sigmoid(): - """test_forward_log_sigmoid""" - torch.set_grad_enabled(False) - input_shape = [10, 10] - input_data = torch.rand(input_shape).float() - input_data_overflow = torch.tensor([-300.0, -100.0]).float() - verify_model(torch.nn.LogSigmoid().eval(), input_data=input_data) - verify_model(torch.nn.LogSigmoid().eval(), input_data=input_data_overflow) - - -@tvm.testing.uses_gpu -def test_forward_adaptive_avgpool(): - """test_forward_adaptive_avgpool""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.AdaptiveAvgPool2d([1, 1]).eval(), input_data=input_data) - verify_model(torch.nn.AdaptiveAvgPool2d([10, 10]).eval(), input_data=input_data) - - input_data = torch.rand([1, 3, 10]).float() - verify_model(torch.nn.AdaptiveAvgPool1d([1]).eval(), input_data=input_data) - verify_model(torch.nn.AdaptiveAvgPool1d([5]).eval(), input_data=input_data) - - input_data = torch.rand([1, 3, 5, 6]).float() - verify_model(torch.nn.AdaptiveAvgPool2d([3, None]).eval(), input_data=input_data) - input_data = torch.rand([1, 1, 3, 5, 6]).float() - verify_model(torch.nn.AdaptiveAvgPool3d([3, None, None]).eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_adaptive_maxpool(): - """test_forward_adaptive_maxpool""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.AdaptiveMaxPool2d([1, 1]).eval(), input_data=input_data) - verify_model(torch.nn.AdaptiveMaxPool2d([10, 10]).eval(), input_data=input_data) - - input_data = torch.rand([1, 3, 10]).float() - verify_model(torch.nn.AdaptiveMaxPool1d([1]).eval(), input_data=input_data) - verify_model(torch.nn.AdaptiveMaxPool1d([5]).eval(), input_data=input_data) - - input_data = torch.rand([1, 3, 5, 6]).float() - verify_model(torch.nn.AdaptiveMaxPool2d([3, None]).eval(), input_data=input_data) - input_data = torch.rand([1, 1, 3, 5, 6]).float() - verify_model(torch.nn.AdaptiveMaxPool3d([3, None, None]).eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_maxpool2d(): - """test_forward_maxpool2d""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - - verify_model(torch.nn.MaxPool2d(kernel_size=[1, 1]).eval(), input_data) - verify_model(torch.nn.MaxPool2d(kernel_size=[2, 2], dilation=[2, 3]).eval(), input_data) - verify_model(torch.nn.MaxPool2d(kernel_size=[10, 10]).eval(), input_data) - verify_model(torch.nn.MaxPool2d(kernel_size=[4, 4], padding=2, stride=2).eval(), input_data) - - # A functional variant (default strides = None case) - class MaxPool2D(Module): - def forward(self, *args): - return torch.nn.functional.max_pool2d(args[0], kernel_size=[10, 10]) - - verify_model(MaxPool2D(), input_data=input_data) - - class MaxPool2DWithIndices(Module): - def __init__(self): - super().__init__() - self.pool = torch.nn.MaxPool2d(kernel_size=[1, 1], return_indices=True) - - def forward(self, *args): - output, _ = self.pool(args[0]) - return output - - class MaxPool2DWithIntStrides(Module): - def forward(self, *args): - # Makes kernel_size and strides a Relay expr to test converting back to int - x_shape = args[0].shape - # kernel_size = [torch.tensor(x_shape[1]).int(), torch.tensor(x_shape[1]).int()] - strides = [torch.tensor(x_shape[0]).int(), torch.tensor(x_shape[0]).int()] - return torch.nn.functional.max_pool2d(args[0], kernel_size=[4, 4], stride=strides) - - verify_model(MaxPool2DWithIndices().float().eval(), input_data=input_data) - verify_model(MaxPool2DWithIntStrides().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_maxpool1d(): - """test_forward_maxpool1d""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10] - input_data = torch.rand(input_shape).float() - - verify_model(torch.nn.MaxPool1d(kernel_size=1).eval(), input_data) - verify_model(torch.nn.MaxPool1d(kernel_size=2, dilation=[1]).eval(), input_data) - verify_model(torch.nn.MaxPool1d(kernel_size=10).eval(), input_data) - verify_model(torch.nn.MaxPool1d(kernel_size=4, padding=2, stride=2).eval(), input_data) - - # A functional variant (default strides = None case) - class MaxPool1D(Module): - def forward(self, *args): - return torch.nn.functional.max_pool1d(args[0], kernel_size=10) - - verify_model(MaxPool1D(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_maxpool3d(): - """test_forward_maxpool3d""" - torch.set_grad_enabled(False) - for input_shape in [(1, 3, 10, 10, 10), (3, 10, 10, 10)]: - input_data = torch.rand(input_shape).float() - - verify_model(torch.nn.MaxPool3d(kernel_size=[1, 1, 1]).eval(), input_data) - verify_model( - torch.nn.MaxPool3d(kernel_size=[2, 2, 2], dilation=[1, 2, 3]).eval(), input_data - ) - verify_model(torch.nn.MaxPool3d(kernel_size=[10, 10, 10]).eval(), input_data) - verify_model( - torch.nn.MaxPool3d(kernel_size=[4, 4, 4], padding=2, stride=2).eval(), input_data - ) - - # A functional variant (default strides = None case) - class MaxPool3D(Module): - def forward(self, *args): - return torch.nn.functional.max_pool3d(args[0], kernel_size=[10, 10, 10]) - - verify_model(MaxPool3D(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_split(): - """test_forward_split""" - torch.set_grad_enabled(False) - input_shape = [4, 10] - - class Split(Module): - def __init__(self, split_size_or_sections, dim): - super().__init__() - self.split_size_or_sections = split_size_or_sections - self.dim = dim - - def forward(self, *args): - return torch.split(args[0], self.split_size_or_sections, self.dim) - - input_data = torch.rand(input_shape).float() - verify_model(Split(2, 0).float().eval(), input_data=input_data) - verify_model(Split(3, 1).float().eval(), input_data=input_data) - verify_model(Split(4, 1).float().eval(), input_data=input_data) - verify_model(Split([2, 3, 5], 1).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_tensor_split(): - """test_forward_tensor_split""" - torch.set_grad_enabled(False) - input_shape = [4, 10] - - class Tensor_Split(Module): - def __init__(self, split_size_or_sections, dim): - super().__init__() - self.split_size_or_sections = split_size_or_sections - self.dim = dim - - def forward(self, *args): - return torch.tensor_split(args[0], self.split_size_or_sections, self.dim) - - # tensor_split was introduced when torch > 1.7.1 - if package_version.parse(torch.__version__) > package_version.parse("1.7.1"): - input_data = torch.rand(input_shape).float() - verify_model(Tensor_Split(2, 0).float().eval(), input_data=input_data) - verify_model(Tensor_Split(torch.tensor(3), 1).float().eval(), input_data=input_data) - verify_model(Tensor_Split([2, 3, 5], 1).float().eval(), input_data=input_data) - verify_model(Tensor_Split((2, 3, 5), 1).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_avgpool1d(): - """test_forward_avgpool1d""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10] - - class AvgPool1D2(Module): - def forward(self, *args): - return torch.nn.functional.avg_pool1d(args[0], kernel_size=[10]) - - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.AvgPool1d(kernel_size=[10]).eval(), input_data=input_data) - verify_model(AvgPool1D2().float().eval(), input_data=input_data) - verify_model( - torch.nn.AvgPool1d(kernel_size=[5], stride=2, padding=2).eval(), input_data=input_data - ) - - -@tvm.testing.uses_gpu -def test_forward_avgpool2d(): - """test_forward_avgpool2d""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class AvgPool2D2(Module): - def forward(self, *args): - return torch.nn.functional.avg_pool2d(args[0], kernel_size=[10, 10]) - - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.AvgPool2d(kernel_size=[10, 10]).eval(), input_data=input_data) - verify_model(AvgPool2D2().float().eval(), input_data=input_data) - verify_model( - torch.nn.AvgPool2d(kernel_size=5, stride=2, padding=2).eval(), input_data=input_data - ) - - input_shape = [1, 1, 1, 9] - input_data = torch.rand(input_shape).float() - verify_model( - torch.nn.AvgPool2d( - kernel_size=[1, 2], stride=[1, 2], ceil_mode=True, count_include_pad=True - ).eval(), - input_data=input_data, - ) - - -@tvm.testing.uses_gpu -def test_forward_avgpool3d(): - """test_forward_avgpool3d""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10, 10] - - class AvgPool3D1(Module): - def forward(self, *args): - return torch.nn.functional.avg_pool3d(args[0], kernel_size=[10, 10, 10]) - - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.AvgPool3d(kernel_size=[10, 10, 10]).eval(), input_data=input_data) - verify_model(AvgPool3D1().float().eval(), input_data=input_data) - verify_model( - torch.nn.AvgPool3d(kernel_size=5, stride=2, padding=2).eval(), input_data=input_data - ) - - -@tvm.testing.uses_gpu -def test_forward_hardtanh(): - """test_forward_hardtanh""" - torch.set_grad_enabled(False) - input_shape = [10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Hardtanh().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_conv(): - """test_forward_conv""" - torch.set_grad_enabled(False) - conv1d_input_shape = [1, 3, 10] - conv2d_input_shape = [1, 3, 10, 10] - - class Conv2D1(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv2d(3, 6, 7, bias=True) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - class Conv2D2(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv2d(3, 6, 7, bias=False) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - class Conv2D3(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv2d(3, 6, 7, groups=3, bias=False) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - class Conv1D1(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv1d(3, 6, 7) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - class Conv1D2(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv1d(3, 6, 7, bias=False) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - class Conv1D3(Module): - def __init__(self): - super().__init__() - self.conv = torch.nn.Conv1d(3, 6, 7, groups=3, bias=False) - self.softmax = torch.nn.Softmax() - - def forward(self, *args): - return self.softmax(self.conv(args[0])) - - conv2d_input_data = torch.rand(conv2d_input_shape).float() - verify_model(Conv2D1().float().eval(), input_data=conv2d_input_data) - verify_model(Conv2D2().float().eval(), input_data=conv2d_input_data) - # depth wise conv with channel mult 2 - verify_model(Conv2D3().float().eval(), input_data=conv2d_input_data) - # group conv - verify_model( - torch.nn.Conv2d(8, 8, kernel_size=(3, 3), stride=(1, 1), groups=2).eval(), - input_data=torch.randn((1, 8, 16, 16)), - ) - - conv1d_input_data = torch.rand(conv1d_input_shape).float() - verify_model(Conv1D1().float().eval(), input_data=conv1d_input_data) - verify_model(Conv1D2().float().eval(), input_data=conv1d_input_data) - verify_model(Conv1D3().float().eval(), input_data=conv1d_input_data) - - -@tvm.testing.uses_gpu -@pytest.mark.parametrize("in_channels", [3], ids=lambda x: "in_channels=" + str(x)) -@pytest.mark.parametrize("out_channels", [5], ids=lambda x: "out_channels=" + str(x)) -@pytest.mark.parametrize("kernel_size", [3], ids=lambda x: "kernel_size=" + str(x)) -@pytest.mark.parametrize("output_padding", [0, 1, 2], ids=lambda x: "output_padding=" + str(x)) -@pytest.mark.parametrize("groups", [1], ids=lambda x: "groups=" + str(x)) -@pytest.mark.parametrize("bias", [True, False], ids=lambda x: "bias=" + str(x)) -def test_forward_conv_transpose( - in_channels, out_channels, kernel_size, output_padding, bias, groups -): - """test_forward_conv_transpose""" - # Note we do not test with groups > 1 because that is not supported - # in tvm for conv transpose operations - - # Output padding must be smaller than either stride or dilation so we - # opt to make the stride 1 + output padding - stride = output_padding + 1 - - # Conv 3D Transpose Tests - conv3d_input_shape = [1, in_channels, 16, 16, 16] - conv3d_input_data = torch.rand(conv3d_input_shape).float() - conv3d_transpose = torch.nn.ConvTranspose3d( - in_channels=in_channels, - out_channels=out_channels, - kernel_size=kernel_size, - stride=stride, - output_padding=output_padding, - groups=groups, - bias=bias, - ).eval() - verify_model(conv3d_transpose, conv3d_input_data) - - # Conv 2D Transpose Tests - conv2d_input_shape = [1, in_channels, 128, 256] - conv2d_input_data = torch.rand(conv2d_input_shape).float() - conv2d_transpose = torch.nn.ConvTranspose2d( - in_channels=in_channels, - out_channels=out_channels, - kernel_size=kernel_size, - stride=stride, - output_padding=output_padding, - groups=groups, - bias=bias, - ).eval() - verify_model(conv2d_transpose, conv2d_input_data) - - # # Conv 1D Transpose Tests - conv1d_input_shape = [1, in_channels, 10] - conv1d_input_data = torch.rand(conv1d_input_shape).float() - conv1d_transpose = torch.nn.ConvTranspose1d( - in_channels=in_channels, - out_channels=out_channels, - kernel_size=kernel_size, - stride=stride, - output_padding=output_padding, - groups=groups, - bias=bias, - ).eval() - verify_model(conv1d_transpose, conv1d_input_data) - - -@tvm.testing.uses_gpu -def test_forward_conv2d_transpose_group(): - """test_forward_conv2d_transpose_group""" - # https://github.com/apache/tvm/issues/10223 - - class ModulatedConvTranspose2D(torch.nn.Module): - """ModulatedConvTranspose2D module""" - - def forward(self, x, w, s): - """forward""" - B, C, H, W = x.shape - I, O, KH, KW = w.shape - - # weight is different for each input in batch (this is why we want grouped conv - # transpose) - w = w.unsqueeze(0) * s.reshape(B, 1, 1, 1, 1) - w = w.reshape(B * I, O, KH, KW) - x = x.reshape(1, B * C, H, W) - x = torch.nn.functional.conv_transpose2d( - x, w, stride=(2, 2), padding=(1, 1), output_padding=(1, 1), groups=B - ) - return x.reshape(B, O, H * 2, W * 2) - - b, c, h, w, k = 4, 512, 8, 16, 3 - inputs = torch.rand(b, c, h, w) - weights = torch.rand(c, c // 2, k, k) - styles = torch.rand(b) - - # cuda not supported for group > 1 conv2d_transpose - targets = ["llvm"] - - if cudnn.exists(): - targets.append("cuda -libs=cudnn") - - verify_trace_model(ModulatedConvTranspose2D().eval(), [inputs, weights, styles], targets) - - -def test_forward_deform_conv(): - """test_forward_deform_conv""" - torch.set_grad_enabled(False) - - def test_run( - batch_size, - in_channels, - out_channels, - in_height, - in_width, - out_height, - out_width, - offset_groups, - kh, - kw, - groups, - ): - input_shape = [batch_size, in_channels, in_height, in_width] - offset_shape = [batch_size, 2 * offset_groups * kh * kw, out_height, out_width] - weight_shape = [out_channels, in_channels // groups, kh, kw] - input_data = torch.rand(input_shape) - offset_data = torch.rand(offset_shape) - weight_data = torch.rand(weight_shape) - - class DeformConv2D(Module): - def forward(self, *args): - return torchvision.ops.deform_conv2d(args[0], args[1], args[2]) - - verify_model( - DeformConv2D().float().eval(), - input_data=[input_data, offset_data, weight_data], - rtol=1e-4, - atol=1e-4, - ) - - batch_size = 4 - in_channels, out_channels = 4, 6 - in_height, in_width = 10, 10 - out_height, out_width = 8, 8 - offset_groups = 2 - kh, kw = 3, 3 - groups = 1 - - test_run( - batch_size, - in_channels, - out_channels, - in_height, - in_width, - out_height, - out_width, - offset_groups, - kh, - kw, - groups, - ) - - batch_size = 5 - in_channels, out_channels = 4, 6 - in_height, in_width = 10, 10 - out_height, out_width = 8, 8 - offset_groups = 1 - kh, kw = 3, 3 - groups = 1 - - test_run( - batch_size, - in_channels, - out_channels, - in_height, - in_width, - out_height, - out_width, - offset_groups, - kh, - kw, - groups, - ) - - -@tvm.testing.uses_gpu -def test_forward_threshold(): - """test_forward_threshold""" - torch.set_grad_enabled(False) - input_shape = [1, 3] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Threshold(0, 0).float().eval(), input_data=input_data) - input_data = torch.tensor([[-1.0, 2.0]], dtype=torch.float32) - verify_model(torch.nn.Threshold(1, 1).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_contiguous(): - """test_forward_contiguous""" - torch.set_grad_enabled(False) - input_shape = [10] - - class Contiguous1(Module): - def forward(self, *args): - return args[0].contiguous() - - input_data = torch.rand(input_shape).float() - verify_model(Contiguous1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_batchnorm(): - """test_forward_batchnorm""" - - def init_weight(m): - torch.nn.init.normal_(m.weight, 0, 0.01) - torch.nn.init.normal_(m.bias) - - inp_2d = torch.rand((1, 16, 10, 10)) - inp_3d = torch.rand((1, 16, 10, 10, 10)) - - class BatchNorm(Module): - def __init__(self, weight, bias): - super().__init__() - self.weight = weight - self.bias = bias - - def forward(self, *args): - return torch.nn.functional.batch_norm( - args[0], - running_mean=torch.zeros(args[0].shape[1]), - running_var=torch.ones(args[0].shape[1]), - weight=self.weight, - bias=self.bias, - ) - - for bn, inp in [(torch.nn.BatchNorm2d(16), inp_2d), (torch.nn.BatchNorm3d(16), inp_3d)]: - init_weight(bn.eval()) - verify_model(bn.eval(), input_data=inp) - verify_model(BatchNorm(bn.weight, None).eval(), input_data=inp) - verify_model(BatchNorm(bn.weight, bn.bias).eval(), input_data=inp) - - -@tvm.testing.uses_gpu -def test_forward_instancenorm(): - """test_forward_instancenorm""" - inp_2d = torch.rand((1, 16, 10, 10)) - inp_3d = torch.rand((1, 16, 10, 10, 10)) - - for ins_norm, inp in [ - (torch.nn.InstanceNorm2d(16), inp_2d), - (torch.nn.InstanceNorm3d(16), inp_3d), - (torch.nn.InstanceNorm2d(16, track_running_stats=True), inp_2d), - (torch.nn.InstanceNorm3d(16, track_running_stats=True), inp_3d), - ]: - verify_model(ins_norm.eval(), input_data=inp) - - -@tvm.testing.uses_gpu -def test_forward_layernorm(): - """test_forward_layernorm""" - - def init_weight(m): - torch.nn.init.normal_(m.weight, 0, 0.01) - torch.nn.init.normal_(m.bias, 0.02) - - inp_2d = torch.rand((1, 16, 10, 10)) - inp_3d = torch.rand((1, 16, 10, 10, 10)) - for ln, inp in [(torch.nn.LayerNorm(10), inp_2d), (torch.nn.LayerNorm(10), inp_3d)]: - init_weight(ln.eval()) - verify_model(ln.eval(), input_data=inp) - - -@tvm.testing.uses_gpu -def test_forward_groupnorm(): - """test_forward_groupnorm""" - input_shape = [10, 6, 5, 5] - input_data = torch.rand(input_shape).float() - - # Separate 6 channels into 3 groups - verify_model(torch.nn.GroupNorm(3, 6).eval(), input_data=input_data) - - # Put all 6 channels into a single group (equivalent with LayerNorm) - verify_model(torch.nn.GroupNorm(1, 6).eval(), input_data=input_data) - - # Separate 6 channels into 6 groups (equivalent with InstanceNorm) - verify_model(torch.nn.GroupNorm(6, 6).eval(), input_data=input_data) - - input_shape = [1, 10, 4, 7] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.GroupNorm(1, 10).eval(), input_data=input_data) - verify_model(torch.nn.GroupNorm(2, 10).eval(), input_data=input_data) - verify_model(torch.nn.GroupNorm(5, 10).eval(), input_data=input_data) - verify_model(torch.nn.GroupNorm(10, 10).eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_reshape(): - """test_forward_reshape""" - torch.set_grad_enabled(False) - input_shape = [2, 1, 10, 1, 10] - new_shape = [2, 1, 10, 10] - - class Reshape1(Module): - def forward(self, *args): - return args[0].reshape(new_shape) - - class Reshape2(Module): - def forward(self, *args): - return args[0].reshape([-1]) - - class Reshape3(torch.nn.Module): - def forward(self, x): - x_shape = x.shape - return x.reshape((x_shape[0] * x_shape[1], x_shape[2])) - - input_data = torch.rand(input_shape).float() - verify_model(Reshape1(), input_data=input_data) - verify_model(Reshape2(), input_data=input_data) - verify_model(Reshape3(), input_data=torch.randn(2, 3, 4)) - - -@tvm.testing.uses_gpu -def test_forward_reshape_as(): - """test_forward_reshape_as""" - - def test_func(input_tensor, other_tensor): - return input_tensor.reshape_as(other_tensor) - - input_data = [torch.rand([2, 1, 10, 1, 10]), torch.rand([2, 1, 10, 10])] - - verify_model_with_input(test_func, input_data, input_dict={"input0": input_data[0]}) - - -@tvm.testing.uses_gpu -def test_flatten(): - """test_flatten""" - - def _test_flatten(start_dim, end_dim): - return lambda inp: torch.flatten(inp, start_dim, end_dim) - - inp = torch.rand((3, 5, 2, 2)) - - # [3, 5, 2, 2] -> [60] - verify_model(_test_flatten(0, -1), inp) - verify_model(_test_flatten(0, 3), inp) - verify_model(_test_flatten(-4, 3), inp) - verify_model(_test_flatten(-4, -1), inp) - - # [3, 5, 2, 2] -> [3, 5, 2, 2] - verify_model(_test_flatten(3, -1), inp) - verify_model(_test_flatten(-1, -1), inp) - verify_model(_test_flatten(0, -4), inp) - verify_model(_test_flatten(-4, -4), inp) - - # [3, 5, 2, 2] -> [3, 10, 2] - verify_model(_test_flatten(1, 2), inp) - verify_model(_test_flatten(1, -2), inp) - verify_model(_test_flatten(-3, 2), inp) - verify_model(_test_flatten(-3, -2), inp) - - -@tvm.testing.uses_gpu -def test_unflatten(): - """test_unflatten""" - - def _test_unflatten(dim, unflattened_size): - return lambda inp: torch.unflatten(inp, dim, unflattened_size) - - inp = torch.rand(60) - - # [60] -> [3, 5, 2, 2] - verify_model(_test_unflatten(0, (3, 5, 2, 2)), inp) - verify_model(_test_unflatten(0, (-1, 5, 2, 2)), inp) - verify_model(_test_unflatten(0, (3, -1, 2, 2)), inp) - verify_model(_test_unflatten(0, (3, 5, -1, 2)), inp) - verify_model(_test_unflatten(0, (3, 5, 2, -1)), inp) - verify_model(_test_unflatten(-1, (3, 5, 2, 2)), inp) - verify_model(_test_unflatten(-1, (-1, 5, 2, 2)), inp) - verify_model(_test_unflatten(-1, (3, -1, 2, 2)), inp) - verify_model(_test_unflatten(-1, (3, 5, -1, 2)), inp) - verify_model(_test_unflatten(-1, (3, 5, 2, -1)), inp) - - inp = torch.rand(3, 4, 1) - - # [3, 4, 1] -> [3, 2, 2, 1] - verify_model(_test_unflatten(1, (2, 2)), inp) - verify_model(_test_unflatten(1, (-1, 2)), inp) - - inp = torch.rand(5, 12, 3) - - # [5, 12, 3] -> [5, 2, 2, 3, 1, 1, 3] - verify_model(_test_unflatten(1, (2, 2, 3, 1, 1)), inp) - verify_model(_test_unflatten(-2, (2, 2, 3, 1, 1)), inp) - - -@tvm.testing.uses_gpu -def test_forward_transpose(): - """test_forward_transpose""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Transpose1(Module): - def forward(self, *args): - return args[0].transpose(2, 3) - - class Transpose2(Module): - def forward(self, *args): - return args[0].transpose(-2, -1) - - class Transpose3(Module): - def forward(self, *args): - return args[0].permute(0, 2, 3, 1) - - input_data = torch.rand(input_shape).float() - verify_model(Transpose1().float().eval(), input_data=input_data) - verify_model(Transpose2().float().eval(), input_data=input_data) - verify_model(Transpose3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_numpy_T(): - """test_forward_numpy_T""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - def test_fn(x): - return x.T - - input_data = torch.rand(input_shape).float() - verify_model(test_fn, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_size(): - """test_forward_size""" - torch.set_grad_enabled(False) - input_shape = [1, 3] - - class Size1(Module): - def forward(self, *args): - return float(args[0].size(0)) * args[0] - - input_data = torch.rand(input_shape).float() - verify_model(Size1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_type_as(): - """test_type_as""" - torch.set_grad_enabled(False) - input_shape = [1, 3] - - def _create_module(dtype): - class TypeAs(Module): - def forward(self, *args): - expected_type_tensor = torch.zeros(1, 3, dtype=dtype) - return args[0].type_as(expected_type_tensor) - - return TypeAs() - - input_data = torch.randn(input_shape).float() - verify_model(_create_module(torch.float64), input_data=input_data) - verify_model(_create_module(torch.float32), input_data=input_data) - verify_model(_create_module(torch.int64), input_data=input_data) - verify_model(_create_module(torch.int32), input_data=input_data) - verify_model(_create_module(torch.int16), input_data=input_data) - verify_model(_create_module(torch.int8), input_data=input_data) - - if torch.cuda.is_available(): - check_fp16 = False - try: - # Only check half precision on supported hardwares. - if have_fp16(tvm.cuda(0).compute_version): - check_fp16 = True - # pylint: disable=broad-except - except Exception: - # If GPU is not enabled in TVM, skip the fp16 test. - pass - - # Temporary disable fp16 test - check_fp16 = False - - if check_fp16: - verify_model(_create_module(torch.float16), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_view(): - """test_forward_view""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class View1(Module): - def forward(self, *args): - return args[0].view((1, 3 * 10 * 10)) - - class View2(Module): - def forward(self, *args): - return args[0].view(args[0].shape[0], -1) - - class View3(Module): - def forward(self, *args): - d1 = torch.tensor(3) * torch.tensor(10) * torch.tensor(10) - return args[0].view(args[0].shape[0], d1) - - input_data = torch.rand(input_shape).float() - verify_model(View1().float().eval(), input_data=input_data) - verify_model(View2().float().eval(), input_data=input_data) - verify_model(View3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_view_as(): - """test_forward_view_as""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10] - - class ViewAs1(Module): - def forward(self, *args): - t1 = torch.ones((1 * 3 * 10)) - return args[0].view_as(t1) - - input_data = torch.rand(input_shape).float() - verify_model(ViewAs1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_select(): - """test_forward_select""" - torch.set_grad_enabled(False) - input_shape = [5, 3, 10, 10] - - class Select1(Module): - def forward(self, *args): - return args[0].select(1, 1) - - class IndexedSelect(Module): - def __init__(self, inp, dim): - super().__init__() - self.inp = inp - self.dim = dim - if torch.cuda.is_available(): - self.inp = self.inp.cuda() - - def forward(self, index): - return torch.index_select(self.inp, self.dim, index) - - input_data = torch.rand(input_shape).float() - verify_model(Select1().float().eval(), input_data=input_data) - - # test negative indexing - verify_model(lambda x: x[-1], input_data=input_data) - - x = torch.randn(3, 4) - indices = torch.tensor([0, 2]) - verify_model(IndexedSelect(x, 0).eval(), input_data=indices) - verify_model(IndexedSelect(x, 1).eval(), input_data=indices) - - -@tvm.testing.uses_gpu -def test_forward_clone(): - """test_forward_clone""" - torch.set_grad_enabled(False) - input_shape = [10] - - class Clone1(Module): - def forward(self, *args): - return args[0].clone() - - input_data = torch.rand(input_shape).float() - verify_model(Clone1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_gather(): - """test_forward_gather""" - torch.set_grad_enabled(False) - - class Gather1(Module): - def forward(self, *args): - return torch.gather(args[0], 0, args[1]) - - class Gather2(Module): - def forward(self, *args): - return torch.gather(args[0], 1, args[1]) - - class Gather3(Module): - def forward(self, *args): - return torch.gather(args[0], 2, args[1]) - - input_data = torch.rand((4,)).float() - index = torch.tensor([1]) - verify_model(Gather1().float().eval(), input_data=[input_data, index]) - - input_data = torch.rand((2, 2)).float() - index = torch.tensor([[1, 0], [0, 1]]) - verify_model(Gather1().float().eval(), input_data=[input_data, index]) - - input_data = torch.tensor([[1, 2], [3, 4]]) - index = torch.tensor([[0, 0], [1, 0]]) - verify_model(Gather2().float().eval(), input_data=[input_data, index]) - - input_data = torch.rand((2, 2)).float() - index = torch.tensor([[1, 0], [0, 1]]) - verify_model(Gather2().float().eval(), input_data=[input_data, index]) - - input_data = torch.rand((3, 3, 3)).float() - index = torch.tensor( - [ - [[1, 0, 0], [1, 0, 1], [0, 1, 1]], - [[1, 1, 1], [1, 2, 1], [1, 0, 1]], - [[1, 2, 1], [1, 2, 1], [1, 2, 1]], - ] - ) - verify_model(Gather3().float().eval(), input_data=[input_data, index]) - - -@tvm.testing.uses_gpu -def test_forward_logsoftmax(): - """test_forward_logsoftmax""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class LogSoftmax1(Module): - def forward(self, *args): - return torch.nn.LogSoftmax(dim=1)(args[0][0, 0]) - - input_data = torch.rand(input_shape).float() - verify_model(LogSoftmax1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_norm(): - """test_forward_norm""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Norm1(Module): - def forward(self, *args): - return torch.norm(args[0], p=float("inf"), dim=None, keepdim=False) - - class Norm2(Module): - def forward(self, *args): - return torch.norm(args[0], p=float("-inf"), dim=None, keepdim=False) - - class Norm3(Module): - def forward(self, *args): - return torch.norm(args[0], p=float("-inf"), dim=None, keepdim=True) - - class Norm4(Module): - def forward(self, *args): - return torch.norm(args[0], p=float("inf"), dim=(1, 2), keepdim=False) - - class Norm5(Module): - def forward(self, *args): - return torch.norm(args[0], p=float("inf"), dim=(1), keepdim=True) - - class Norm6(Module): - def forward(self, *args): - return torch.norm(args[0], p=float(0.5), dim=(1), keepdim=True) - - class Norm7(Module): - def forward(self, *args): - return torch.norm(args[0], p=float(1), dim=None, keepdim=False) - - class Norm8(Module): - def forward(self, *args): - return torch.norm(args[0], p=float(2.0), dim=(1), keepdim=True) - - class Norm9(Module): - def forward(self, *args): - return torch.norm(args[0], p=float(-0.5), dim=(1, 2), keepdim=True) - - class Norm10(Module): - def forward(self, *args): - return torch.norm(args[0], p=float(-2), dim=(1), keepdim=False) - - input_data = torch.rand(input_shape).float() - verify_model(Norm1().float().eval(), input_data=input_data) - verify_model(Norm2().float().eval(), input_data=input_data) - verify_model(Norm3().float().eval(), input_data=input_data) - verify_model(Norm4().float().eval(), input_data=input_data) - verify_model(Norm5().float().eval(), input_data=input_data) - verify_model(Norm6().float().eval(), input_data=input_data) - verify_model(Norm7().float().eval(), input_data=input_data) - verify_model(Norm8().float().eval(), input_data=input_data) - verify_model(Norm9().float().eval(), input_data=input_data) - verify_model(Norm10().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_frobenius_norm(): - """test_forward_frobenius_norm""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class FroNorm1(Module): - def forward(self, *args): - return torch.norm(args[0]) - - class FroNorm2(Module): - def forward(self, *args): - return torch.norm(args[0], p="fro", dim=None, keepdim=True) - - class FroNorm3(Module): - def forward(self, *args): - return torch.norm(args[0], p="fro", dim=(1), keepdim=True) - - class FroNorm4(Module): - def forward(self, *args): - return torch.norm(args[0], dim=None, keepdim=False) - - input_data = torch.rand(input_shape).float() - verify_model(FroNorm1().float().eval(), input_data=input_data) - verify_model(FroNorm2().float().eval(), input_data=input_data) - verify_model(FroNorm3().float().eval(), input_data=input_data) - verify_model(FroNorm4().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_sigmoid(): - """test_forward_sigmoid""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Sigmoid().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_dense(): - """test_forward_dense""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Dense1(Module): - def __init__(self): - super().__init__() - self.linear = torch.nn.Linear(10, 7, bias=True) - - def forward(self, *args): - return self.linear(args[0][0, 0]) - - class Dense2(Module): - def __init__(self): - super().__init__() - self.linear = torch.nn.Linear(10, 7, bias=False) - - def forward(self, *args): - return self.linear(args[0][0, 0]) - - input_data = torch.rand(input_shape).float() - verify_model(Dense1().float().eval(), input_data=input_data) - verify_model(Dense2().float().eval(), input_data=input_data) - - trace = torch.jit.trace(Dense1(), [input_data]) - mod, _ = relay.frontend.from_pytorch( - trace, - [("input", input_shape)], - ) - assert not any(list(op.name == "multiply" for op in list_ops(mod["main"]))) - - -@tvm.testing.uses_gpu -def test_forward_linear(): - """test_forward_linear""" - torch.set_grad_enabled(False) - - class Linear(Module): - def forward(self, inputs, weight, bias): - return F.linear(inputs, weight, bias) - - class LinearNoBias(Module): - def forward(self, inputs, weight): - return F.linear(inputs, weight) - - class LinearNested(Module): - def forward(self, x, y, z): - return F.linear(x, F.linear(y, z)) - - input1d = torch.rand([2]).float() - input2d = torch.rand([2, 2]).float() - input3d = torch.rand([4, 3, 2]).float() - weight1d = torch.rand([2]).float() - weight2d = torch.rand([2, 2]).float() - weight3x2 = torch.rand([3, 2]).float() - bias0d = torch.rand([]).float() - bias1d = torch.rand([2]).float() - bias2d = torch.rand([2, 2]).float() - # 2D input, 2D weight, 1D bias - verify_model(Linear(), input_data=[input2d, weight2d, bias1d]) - # 2D input, 2D weight, 2D bias - verify_model(Linear(), input_data=[input2d, weight2d, bias2d]) - # 2D input, 2D weight, no bias - verify_model(LinearNoBias(), input_data=[input2d, weight2d]) - verify_model(LinearNoBias(), input_data=[input2d, weight3x2]) - # 2D input, 1D weight, 1D bias is not supported by torch.linear() - # 2D input, 1D weight, no bias - verify_model(LinearNoBias(), input_data=[input2d, weight1d]) - # 3D input, 2D weight, no bias - verify_model(LinearNoBias(), input_data=[input3d, weight3x2]) - # 3D input, 2D weight, 1D bias - verify_model(Linear(), input_data=[input3d, weight2d, bias1d]) - - verify_model(LinearNested(), input_data=[torch.randn(10, 10) for _ in range(3)]) - - # 1D input, 2D weight, 1D bias - verify_model(Linear(), input_data=[input1d, weight2d, bias1d]) - # 1D input, 2D weight, no bias - verify_model(LinearNoBias(), input_data=[input1d, weight2d]) - # 1D input, 1D weight, scalar bias - verify_model(Linear(), input_data=[input1d, weight1d, bias0d]) - # 1D input, 1D weight, no bias - verify_model(LinearNoBias(), input_data=[input1d, weight1d]) - - -@tvm.testing.uses_gpu -def test_forward_dropout(): - """test_forward_dropout""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(torch.nn.Dropout(p=0.5).eval(), input_data=input_data[0, 0]) - verify_model(torch.nn.Dropout2d(p=0.5).eval(), input_data=input_data[0]) - verify_model(torch.nn.Dropout3d(p=0.5).eval(), input_data=input_data) - verify_model(torch.nn.AlphaDropout(p=0.5).eval(), input_data=input_data[0, 0]) - - -@tvm.testing.uses_gpu -def test_forward_slice(): - """test_forward_slice""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Slice1(Module): - def forward(self, *args): - return args[0][:, :, :, :3] - - class Slice2(Module): - def forward(self, *args): - return args[0][0, :, :-3, :] - - class Slice3(Module): - def forward(self, *args): - x0 = torch.tensor(2) - torch.tensor(1) - x1 = torch.tensor(3) + torch.tensor(1) - return args[0][:, x0:, 1:x1, :] - - class SliceWithStride(torch.nn.Module): - def forward(self, x): - return x[..., 0::2] + x[..., 1::2] - - class SliceWithStride2(torch.nn.Module): - def forward(self, x): - return x[0::2, 0::2] + x[1::2, 1::2] - - class DynamicLengthSlice(torch.nn.Module): - def forward(self, values, length): - return values[0:length] - - input_data = torch.rand(input_shape).float() - verify_model(Slice1(), input_data=input_data) - verify_model(Slice2(), input_data=input_data) - verify_model(Slice3(), input_data=input_data) - verify_model(SliceWithStride(), input_data=torch.randn(1, 4)) - verify_model(SliceWithStride2(), input_data=torch.randn(4, 4)) - - inp = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - slice_len = torch.tensor(2) - targets = ["llvm", "cuda"] - verify_trace_model(DynamicLengthSlice(), [inp, slice_len], targets) - - -@tvm.testing.uses_gpu -def test_forward_narrow(): - """test_forward_narrow""" - torch.set_grad_enabled(False) - input_shape = [3, 3] - - class Narrow1(Module): - def forward(self, *args): - return torch.narrow(args[0], 0, 0, 2) - - class Narrow2(Module): - def forward(self, *args): - return torch.narrow(args[0], 1, 1, 2) - - class Narrow3(Module): - def forward(self, *args): - begin = torch.tensor(2) - torch.tensor(1) - length = torch.tensor(1) * torch.tensor(2) - return torch.narrow(args[0], 1, begin, length) - - input_data = torch.rand(input_shape).float() - verify_model(Narrow1(), input_data=input_data) - verify_model(Narrow2(), input_data=input_data) - verify_model(Narrow3(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_mean(): - """test_forward_mean""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Mean1(Module): - def forward(self, *args): - return args[0].mean(2) - - input_data = torch.rand(input_shape).float() - verify_model(Mean1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_expand(): - """test_forward_expand""" - torch.set_grad_enabled(False) - - class Expand1(Module): - def forward(self, *args): - return args[0].expand((3, -1, -1, -1)) - - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(Expand1().float().eval(), input_data=input_data) - - class Expand2(Module): - def forward(self, *args): - return args[0].expand((3, 3, 3, 1)) - - input_shape = [3, 1] - input_data = torch.rand(input_shape).float() - verify_model(Expand2().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_tensors(): - """test_forward_broadcast_tensors""" - torch.set_grad_enabled(False) - - class BroadCastTensors1(Module): - def forward(self, x, y): - return torch.broadcast_tensors(x, y) - - x = torch.arange(3).view(1, 1, 3) - y = torch.arange(2).view(1, 2, 1) - verify_model(BroadCastTensors1().float().eval(), input_data=[x, y]) - - class BroadCastTensors2(Module): - def forward(self, x, y, z): - return torch.broadcast_tensors(x, y, z) - - x = torch.arange(3).view(1, 1, 3) - y = torch.arange(2).view(1, 2, 1) - z = torch.arange(4).view(4, 1, 1) - verify_model(BroadCastTensors2().float().eval(), input_data=[x, y, z]) - - -@tvm.testing.uses_gpu -def test_forward_broadcast_to(): - """test_forward_broadcast_to""" - torch.set_grad_enabled(False) - - class BroadCastTo1(Module): - def forward(self, x): - return torch.broadcast_to(x, (3, 3)) - - x = torch.tensor([1, 2, 3]) - verify_model(BroadCastTo1().float().eval(), input_data=[x]) - - class BroadCastTo2(Module): - def __init__(self): - super().__init__() - self.y = torch.tensor(1) - self.z = torch.tensor(2) - - def forward(self, x): - return torch.broadcast_to(x, (self.y + self.z, 3)) - - x = torch.tensor([1, 2, 3]) - verify_model(BroadCastTo2().float().eval(), input_data=[x]) - - -@tvm.testing.uses_gpu -def test_forward_pow(): - """test_forward_pow""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Pow1(Module): - def forward(self, *args): - return args[0] ** 2 - - input_data = torch.rand(input_shape).float() - verify_model(Pow1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_chunk(): - """test_forward_chunk""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 14, 14] - - class Chunk1(Module): - def forward(self, *args): - chunks = args[0].chunk(7, 2) - return torch.cat(chunks, 2) - - input_data = torch.rand(input_shape).float() - verify_model(Chunk1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_upsample(): - """test_upsample""" - - class Upsample(Module): - def __init__(self, size=None, scale=None, mode="nearest", align_corners=None): - super().__init__() - self.size = size - self.scale = scale - self.mode = mode - self.align_corners = align_corners - - def forward(self, x): - return torch.nn.functional.interpolate( - x, - size=self.size, - scale_factor=self.scale, - mode=self.mode, - align_corners=self.align_corners, - ) - - inp = torch.rand((1, 3, 32, 32)) - verify_model(Upsample(size=(64, 64), mode="nearest"), inp) - verify_model(Upsample(scale=2, mode="nearest"), inp) - verify_model(Upsample(size=(50, 50), mode="nearest"), inp) - verify_model(Upsample(size=(64, 64), mode="bilinear", align_corners=True), inp) - verify_model(Upsample(scale=2, mode="bilinear", align_corners=True), inp) - verify_model(Upsample(size=(50, 50), mode="bilinear", align_corners=True), inp) - verify_model(Upsample(size=(64, 64), mode="bicubic", align_corners=True), inp) - verify_model(Upsample(scale=2, mode="bicubic", align_corners=True), inp) - verify_model(Upsample(size=(50, 50), mode="bicubic", align_corners=True), inp) - - -@tvm.testing.uses_gpu -def test_to(): - """test for aten::to(...)""" - - class ToCPU(Module): - def forward(self, x): - return x.to("cpu") - - class ToFloat(Module): - def forward(self, x): - return x.float() - - class ToInt(Module): - def forward(self, x): - return x.int() - - class ToLong(Module): - def forward(self, x): - return x.long() - - class ToDouble(Module): - def forward(self, x): - return x.double() - - class ToFloat16(Module): - def forward(self, x): - return x.to(torch.float16) - - verify_model(ToCPU().eval(), torch.rand((1, 3, 32, 32))) - verify_model(ToFloat().eval(), torch.zeros((1, 3, 32, 32), dtype=torch.int)) - verify_model(ToFloat().eval(), torch.tensor(2, dtype=torch.int)) - verify_model(ToInt().eval(), torch.zeros((1, 3, 32, 32))) - verify_model(ToInt().eval(), torch.tensor(0.8)) - verify_model(ToLong().eval(), torch.tensor(0.8)) - verify_model(ToDouble().eval(), torch.tensor(0.8)) - verify_model(ToFloat16().eval(), torch.tensor(2, dtype=torch.float32)) - verify_model(ToFloat16().eval(), torch.zeros((1, 3, 32, 32), dtype=torch.int)) - - -@tvm.testing.uses_gpu -def test_adaptive_pool3d(): - """test_adaptive_pool3d""" - for ishape in [(1, 32, 16, 16, 16), (1, 32, 9, 15, 15), (1, 32, 13, 7, 7)]: - inp = torch.rand(ishape) - verify_model(torch.nn.AdaptiveMaxPool3d((1, 1, 1)).eval(), inp) - verify_model(torch.nn.AdaptiveMaxPool3d((2, 2, 2)).eval(), inp) - verify_model(torch.nn.AdaptiveAvgPool3d((1, 1, 1)).eval(), inp) - verify_model(torch.nn.AdaptiveAvgPool3d((2, 2, 2)).eval(), inp) - verify_model(torch.nn.AdaptiveAvgPool3d((4, 8, 8)).eval(), inp) - verify_model(torch.nn.AdaptiveMaxPool3d((7, 8, 9)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_functional_pad(): - """test_forward_functional_pad""" - torch.set_grad_enabled(False) - pad = (0, 0) - - class Pad1(Module): - def forward(self, *args): - return torch.nn.functional.pad(args[0], pad, "constant", 0) - - input_data = torch.rand((3, 3, 4, 2)) - pad = (1, 1) - verify_model(Pad1().float().eval(), input_data=input_data) - - pad = (1, 1, 2, 2) - verify_model(Pad1().float().eval(), input_data=input_data) - - pad = (0, 1, 2, 1, 3, 3) - verify_model(Pad1().float().eval(), input_data=input_data) - - class Pad2(Module): - def forward(self, *args): - return torch.nn.functional.pad(args[0], pad, "constant", 1) - - input_data = torch.rand((3, 3, 4, 2)) - pad = (1, 1) - verify_model(Pad2().float().eval(), input_data=input_data) - - pad = (1, 1, 2, 2) - verify_model(Pad2().float().eval(), input_data=input_data) - - pad = (0, 1, 2, 1, 3, 3) - verify_model(Pad2().float().eval(), input_data=input_data) - - class Pad3(Module): - def forward(self, *args): - return torch.nn.functional.pad(args[0], pad, "constant", 1.0) - - input_data = torch.rand((3, 3, 4, 2)) - pad = (1, 1) - verify_model(Pad3().float().eval(), input_data=input_data) - - pad = (1, 1, 2, 2) - verify_model(Pad3().float().eval(), input_data=input_data) - - pad = (0, 1, 2, 1, 3, 3) - verify_model(Pad3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_zero_pad2d(): - """test_forward_zero_pad2d""" - inp = torch.rand((1, 1, 3, 3)) - verify_model(torch.nn.ZeroPad2d(2).eval(), inp) - verify_model(torch.nn.ZeroPad2d((1, 1, 2, 0)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_constant_pad1d(): - """test_forward_constant_pad1d""" - inp = torch.rand((1, 2, 4)) - verify_model(torch.nn.ConstantPad1d(2, 3.5).eval(), inp) - - inp = torch.rand((1, 2, 3)) - verify_model(torch.nn.ConstantPad1d((3, 1), 3.5).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_constant_pad2d(): - """test_forward_constant_pad2d""" - inp = torch.rand((1, 2, 2, 2)) - verify_model(torch.nn.ConstantPad2d(2, 3.5).eval(), inp) - verify_model(torch.nn.ConstantPad2d((3, 0, 2, 1), 3.5).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_constant_pad3d(): - """test_forward_constant_pad3d""" - inp = torch.rand((1, 3, 2, 2, 2)) - verify_model(torch.nn.ConstantPad3d(3, 3.5).eval(), inp) - verify_model(torch.nn.ConstantPad3d((3, 4, 5, 6, 0, 1), 3.5).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_reflection_pad1d(): - """test_forward_reflection_pad1d""" - inp = torch.rand((1, 2, 4)) - verify_model(torch.nn.ReflectionPad1d(2).eval(), inp) - verify_model(torch.nn.ReflectionPad1d((3, 1)).eval(), inp) - - inp = torch.rand((2, 4, 5)) - verify_model(torch.nn.ReflectionPad1d((2, 3)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_reflection_pad2d(): - """test_forward_reflection_pad2d""" - inp = torch.rand((1, 1, 3, 3)) - verify_model(torch.nn.ReflectionPad2d(2).eval(), inp) - verify_model(torch.nn.ReflectionPad2d((1, 1, 2, 0)).eval(), inp) - - inp = torch.rand((2, 4, 5, 6)) - verify_model(torch.nn.ReflectionPad2d((1, 3, 2, 4)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_replication_pad1d(): - """test_forward_replication_pad1d""" - inp = torch.rand((1, 2, 4)) - verify_model(torch.nn.ReplicationPad1d(2).eval(), inp) - verify_model(torch.nn.ReplicationPad1d((3, 1)).eval(), inp) - - inp = torch.rand((2, 4, 5)) - verify_model(torch.nn.ReplicationPad1d((2, 3)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_replication_pad2d(): - """test_forward_replication_pad2d""" - inp = torch.rand((1, 1, 3, 3)) - verify_model(torch.nn.ReplicationPad2d(2).eval(), inp) - verify_model(torch.nn.ReplicationPad2d((1, 1, 2, 0)).eval(), inp) - - inp = torch.rand((2, 4, 5, 6)) - verify_model(torch.nn.ReplicationPad2d((1, 3, 2, 4)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_replication_pad3d(): - """test_forward_replication_pad3d""" - inp = torch.rand((1, 1, 3, 3, 3)) - verify_model(torch.nn.ReplicationPad3d(3).eval(), inp) - verify_model(torch.nn.ReplicationPad3d((1, 1, 2, 2, 1, 1)).eval(), inp) - - inp = torch.rand((7, 5, 4, 5, 6)) - verify_model(torch.nn.ReplicationPad3d((2, 3, 2, 5, 1, 4)).eval(), inp) - - -@tvm.testing.uses_gpu -def test_forward_upsample3d(): - """test_forward_upsample3d""" - inp = torch.arange(1, 9, dtype=torch.float32).view(1, 1, 2, 2, 2) - verify_model(torch.nn.Upsample(scale_factor=2, mode="nearest").eval(), inp) - verify_model(torch.nn.Upsample(scale_factor=2, mode="trilinear").eval(), inp) - verify_model( - torch.nn.Upsample(scale_factor=2, mode="trilinear", align_corners=True).eval(), inp - ) - - -def test_forward_nms(): - """dynamic Non-Maximum Suppression""" - torch.set_grad_enabled(False) - - class NonMaxSupression(Module): - def __init__(self, iou_thres): - super().__init__() - self.iou_threshold = iou_thres - - def forward(self, *args): - return torchvision.ops.nms(args[0], args[1], self.iou_threshold) - - # Generate random input data - def _gen_rand_inputs(num_boxes): - box_len = 4 - boxes = torch.rand(num_boxes, box_len, dtype=torch.float) * 0.5 - boxes[:, 2] += boxes[:, 0] - boxes[:, 3] += boxes[:, 1] - scores = np.linspace(0, 1, num=num_boxes).astype("float32") - np.random.shuffle(scores) - return boxes, torch.from_numpy(scores) - - targets = ["llvm", "cuda"] - - for num_boxes, iou_thres in [(10, 0.3), (100, 0.5), (500, 0.9)]: - in_boxes, in_scores = _gen_rand_inputs(num_boxes) - verify_trace_model(NonMaxSupression(iou_thres), [in_boxes, in_scores], targets) - - -def test_forward_roi_align(): - """ROI align""" - torch.set_grad_enabled(False) - - class ROIAlign(Module): - def __init__(self, output_sizes, spatial_scale=1.0, sampling_ratio=-1): - super().__init__() - self.spatial_scale = spatial_scale - self.sampling_ratio = sampling_ratio - self.output_sizes = output_sizes - - def forward(self, *args): - return torchvision.ops.roi_align( - args[0], - args[1], - self.output_sizes, - self.spatial_scale, - self.sampling_ratio, - ) - - in_data = torch.Tensor(np.random.uniform(size=(1, 8, 100, 100))) - in_boxes = torch.Tensor(np.random.uniform(0.0, 100.0, size=(35, 4))) - in_batch = torch.zeros((35, 1), dtype=torch.float) - in_boxes = torch.cat([in_batch, in_boxes], dim=1) - - verify_model(ROIAlign(7), [in_data, in_boxes]) - verify_model(ROIAlign((10, 10), 0.7, 5), [in_data, in_boxes]) - verify_model(ROIAlign(15, 0.9, 3), [in_data, in_boxes]) - - -@tvm.testing.uses_gpu -def test_conv3d(): - """test_conv3d""" - for ishape in [(1, 32, 16, 16, 16), (1, 32, 9, 15, 15), (1, 32, 13, 7, 7)]: - inp = torch.rand(ishape) - verify_model(torch.nn.Conv3d(32, 16, (3, 3, 3), padding=(1, 1, 1)).eval(), inp) - verify_model(torch.nn.Conv3d(32, 16, (5, 5, 5), padding=(2, 2, 2)).eval(), inp) - verify_model(torch.nn.Conv3d(32, 16, kernel_size=1).eval(), inp) - # downsample - verify_model(torch.nn.Conv3d(32, 16, kernel_size=1, stride=2).eval(), inp) - - -@tvm.testing.uses_gpu -def test_conv3d_transpose(): - """test_conv3d_transpose""" - for ishape in [(1, 8, 10, 5, 10), (1, 8, 5, 8, 8), (1, 8, 13, 7, 7)]: - inp = torch.rand(ishape) - verify_model( - torch.nn.ConvTranspose3d( - in_channels=8, out_channels=33, kernel_size=3, stride=2 - ).eval(), - inp, - ) - verify_model( - torch.nn.ConvTranspose3d( - in_channels=8, - out_channels=20, - kernel_size=(3, 5, 2), - stride=(2, 1, 1), - padding=(0, 4, 2), - ).eval(), - inp, - ) - verify_model( - torch.nn.ConvTranspose3d(in_channels=8, out_channels=20, kernel_size=1).eval(), inp - ) - verify_model( - torch.nn.ConvTranspose3d(in_channels=8, out_channels=5, kernel_size=1, stride=2).eval(), - inp, - ) - - -# Model tests -@tvm.testing.uses_gpu -def test_resnet18(): - """test_resnet18""" - torch.set_grad_enabled(False) - verify_model("resnet18", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_squeezenet1_0(): - """test_squeezenet1_0""" - torch.set_grad_enabled(False) - verify_model("squeezenet1_0", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_squeezenet1_1(): - """test_squeezenet1_1""" - torch.set_grad_enabled(False) - verify_model("squeezenet1_1", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_densenet121(): - """test_densenet121""" - torch.set_grad_enabled(False) - verify_model("densenet121", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_inception_v3(): - """test_inception_v3""" - torch.set_grad_enabled(False) - verify_model("inception_v3", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_googlenet(): - """test_googlenet""" - torch.set_grad_enabled(False) - verify_model("googlenet", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_mnasnet0_5(): - """test_mnasnet0_5""" - torch.set_grad_enabled(False) - verify_model("mnasnet0_5", atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_mobilenet_v2(): - """test_mobilenet_v2""" - torch.set_grad_enabled(False) - verify_model("mobilenet_v2", atol=1e-4, rtol=1e-4) - - -# pylint: disable=pointless-string-statement -""" -#TODO: Fix VGG and AlexNet issues (probably due to pooling) -@tvm.testing.uses_gpu -def test_alexnet(): - torch.set_grad_enabled(False) - verify_model("alexnet") - -@tvm.testing.uses_gpu -def test_vgg11(): - torch.set_grad_enabled(False) - verify_model("vgg11") - -@tvm.testing.uses_gpu -def test_vgg11_bn(): - torch.set_grad_enabled(False) - verify_model("vgg11_bn") -""" - - -@tvm.testing.uses_gpu -def test_custom_conversion_map(): - """test_custom_conversion_map""" - - def get_roi_align(): - pool_size = 5 - n_channels = 2 * (pool_size**2) - x = torch.rand(2, n_channels, 10, 10) - rois = torch.tensor( - [ - [0, 0, 0, 9, 9], # format is (xyxy) - [0, 0, 5, 4, 9], - [0, 5, 5, 9, 9], - [1, 0, 0, 9, 9], - ], - dtype=torch.float, - ) - roi_align = torchvision.ops.RoIAlign(pool_size, spatial_scale=1, sampling_ratio=-1) - return roi_align.eval(), [x, rois] - - def convert_roi_align(): - def _impl(inputs, input_types): - spatial_scale = inputs[2] - pooled_size = (inputs[3], inputs[4]) - sampling_ratio = inputs[5] - return relay.op.vision.roi_align( - inputs[0], inputs[1], pooled_size, spatial_scale, sampling_ratio - ) - - return _impl - - custom_map = {"torchvision::roi_align": convert_roi_align()} - model, inputs = get_roi_align() - - verify_model(model, inputs, custom_map) - - -@tvm.testing.uses_gpu -def test_segmentation_models(): - """test_segmentation_models""" - - class SegmentationModelWrapper(Module): - def __init__(self, model): - super().__init__() - self.model = model - - def forward(self, inp): - out = self.model(inp) - return out["out"] - - fcn = torchvision.models.segmentation.fcn_resnet101(pretrained=True) - deeplab = torchvision.models.segmentation.deeplabv3_resnet101(pretrained=True) - - inp = [torch.rand((1, 3, 300, 300), dtype=torch.float)] - - verify_model(SegmentationModelWrapper(fcn.eval()), inp, atol=1e-4, rtol=1e-4) - verify_model(SegmentationModelWrapper(deeplab.eval()), inp, atol=1e-4, rtol=1e-4) - - -@tvm.testing.uses_gpu -def test_3d_models(): - """test_3d_models""" - input_shape = (1, 3, 4, 56, 56) - resnet3d = torchvision.models.video.r3d_18(pretrained=True).eval() - verify_model(resnet3d, [torch.rand(input_shape)], atol=1e-4, rtol=1e-4) - - -def _get_default_vm_targets(): - """Get default vm targets""" - return ["llvm", "cuda"] - - -def verify_script_model(pt_model, ishapes, targets, idtype=None): - """verify_script_model""" - script_module = torch.jit.script(pt_model) - - verify_model_vm(script_module, ishapes, idtype=idtype, targets=targets) - - -def verify_trace_model(pt_model, idata, targets): - """verify_trace_model""" - traced_model = torch.jit.trace(pt_model, idata) - ishapes = [data.shape for data in idata] - verify_model_vm(traced_model, ishapes, idata=idata, targets=targets) - - -def convert_pt_to_tvm_type(idtype): - """Accepts a pytorch dtype and returns string TVM dtype.""" - # TVM does not support PyTorch complex dtypes - if idtype == torch.float64: - curr_dtype = "float64" - elif idtype == torch.float32: - curr_dtype = "float32" - elif idtype == torch.float16: - curr_dtype = "float16" - elif idtype == torch.bfloat16: - curr_dtype = "bfloat16" - elif idtype == torch.int64: - curr_dtype = "int64" - elif idtype == torch.int32: - curr_dtype = "int32" - elif idtype == torch.int16: - curr_dtype = "int16" - elif idtype == torch.int8: - curr_dtype = "int8" - elif idtype == torch.uint8: - curr_dtype = "uint8" - elif idtype == torch.bool: - curr_dtype = "bool" - else: - raise NotImplementedError(f"Unsupported dtype: {idtype}") - return curr_dtype - - -def verify_model_vm(input_model, ishapes, idtype=None, idata=None, targets=None): - """verify_model_vm""" - targets = targets or ["llvm"] - if not idtype: - idtype = torch.float - - input_names = [f"i{idx}" for idx, _ in enumerate(ishapes)] - tvm_dtype = convert_pt_to_tvm_type(idtype) - input_dtypes = [tvm_dtype] * len(input_names) - input_shapes = list(zip(input_names, list(zip(ishapes, input_dtypes)))) - - if idata: - input_data = idata - # If no input_data provided, generate random data of specified dtype - else: - if idtype == torch.bool: - input_data = [ - torch.Tensor.bool(torch.randint(low=0, high=2, size=shape)) for shape in ishapes - ] - # Torch dtype can be float, complex, int, or Bool. Complex not supported, - # so if not float or Bool, dtype must be int! - elif not idtype.is_floating_point: - input_data = [ - torch.randint(low=0, high=10, size=shape, dtype=idtype) for shape in ishapes - ] - else: - input_data = [torch.randn(shape, dtype=idtype) for shape in ishapes] - - # Compile via VM - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch(input_model, input_shapes) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(input_model, input_shapes) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - for tgt in targets: - if not tvm.testing.device_enabled(tgt): - continue - print("Running on target", tgt) - - dev = tvm.device(tgt, 0) - - evaluator = relay.create_executor("vm", mod=mod, device=dev, target=tgt).evaluate() - - # Inference - for name, inp in zip(input_names, input_data): - params[name] = inp.numpy() - vm_res = evaluator(**params) - - # Baseline result - with torch.no_grad(): - pt_result = input_model(*input_data) - - # Verify the accuracy - if isinstance(pt_result, tuple): - # handle multiple outputs - for i, pt_result in enumerate(pt_result): - tvm_res = vm_res[i].numpy() - tvm.testing.assert_allclose(tvm_res, pt_result.numpy(), rtol=1e-5, atol=1e-5) - elif not isinstance(pt_result, torch.Tensor): - tvm_res = vm_res.numpy().item() - assert pt_result == tvm_res - else: - tvm.testing.assert_allclose(vm_res.numpy(), pt_result.numpy(), rtol=1e-5, atol=1e-5) - - -@tvm.testing.uses_gpu -def test_control_flow(): - """test_control_flow""" - - class SimpleIf(torch.nn.Module): - """SimpleIf module""" - - def __init__(self, N, M): - super().__init__() - self.weight = torch.nn.Parameter(torch.rand(N, M)) - - def forward(self, inp): - if inp.sum() > 0.0: - output = self.weight + inp - else: - output = self.weight - inp - return output - - class NestedIf(torch.nn.Module): - """NestedIf module""" - - def __init__(self, N, M): - super().__init__() - self.weight = torch.nn.Parameter(torch.rand(N, M)) - - def forward(self, inp): - """forward""" - if inp.sum() > 0.0: - if inp.mean() > 0.0: - output = self.weight + inp - else: - output = self.weight - inp - else: - if inp.mean() >= 0.0: - output = self.weight * inp - else: - output = self.weight / inp - - return output - - class ScalarLoop(torch.nn.Module): - """ScalarLoop module""" - - def forward(self, inp): - """forward""" - a = 0 - for i in range(inp.size(0)): - b = i * i - b = b + 1 - a += b - if a != 0: - a += 1 - else: - a += 2 - return a - - class SimpleLoop(torch.nn.Module): - def forward(self, inp): - a = inp - for _ in range(inp.size(0)): - b = a * 2.0 - c = a + b - a += c - return a - - class LoopWithIf(torch.nn.Module): - """LoopWithIf module""" - - def forward(self, inp): - a = inp - for _ in range(inp.size(0)): - b = a * 2.0 - b = a + b - if b.sum() > 0.0: - a += b - else: - a -= b - return a - - class NestedLoop(torch.nn.Module): - def forward(self, inp): - a = inp - for i in range(inp.size(0)): - b = a * float(i) - for j in range(inp.size(1)): - a += b * float(j) - return a - - class SimpleScalarWhileLoop(torch.nn.Module): - """SimpleScalarWhileLoop module""" - - def forward(self, inp): - """forward""" - a = 1 - i = 0 - while i <= inp.size(0): - a += i - i += 2 - i = 0 - # also test constant init cond - while i < 10: - a += i - i += 3 - return a - - class SimpleWhileLoop(torch.nn.Module): - def forward(self, inp): - a = inp - i = 0 - while i < inp.size(0): - a += a * float(i) * 2.0 - i += 1 - return a - - models = [ - SimpleIf(10, 20), - NestedIf(10, 20), - ScalarLoop(), - SimpleLoop(), - LoopWithIf(), - SimpleScalarWhileLoop(), - SimpleWhileLoop(), - NestedLoop(), - ] - - for pt_model in models: - verify_script_model(pt_model.eval(), [(10, 20)], _get_default_vm_targets()) - - -@tvm.testing.uses_gpu -def test_simple_rnn(): - """test_simple_rnn""" - # The mixed tracing and scripting example from - # https://pytorch.org/tutorials/beginner/Intro_to_TorchScript_tutorial.html#mixing-scripting-and-tracing - class DecisionGate(torch.nn.Module): - def forward(self, x): - if x.sum() > 0: - return x - else: - return -x - - class Cell(torch.nn.Module): - def __init__(self, dg): - super().__init__() - self.dg = dg - self.linear = torch.nn.Linear(4, 4) - - def forward(self, x, h): - new_h = torch.tanh(self.dg(self.linear(x)) + h) - return new_h, new_h - - class RNNLoop(torch.nn.Module): - """Pytorch RNNLoop module""" - - def __init__(self): - super().__init__() - x = torch.rand(10, 4, dtype=torch.float) - h = torch.rand(10, 4, dtype=torch.float) - self.cell = torch.jit.trace(Cell(DecisionGate()), (x, h)) - - def forward(self, xs): - h = torch.zeros(10, 4, dtype=torch.float) - y = torch.zeros(10, 4, dtype=torch.float) - for i in range(xs.size(0)): - y, h = self.cell(xs[i], h) - return y - - verify_script_model(RNNLoop().eval(), [(10, 10, 4)], _get_default_vm_targets()) - - -@tvm.testing.uses_gpu -def test_forward_reduce_sum(): - """test_forward_reduce_sum""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class ReduceSum1(Module): - def forward(self, *args): - return args[0].sum(1) - - class ReduceSum2(Module): - def forward(self, *args): - return args[0].sum(dim=1, keepdim=False) - - class ReduceSum3(Module): - def forward(self, *args): - return args[0].sum(dim=2, keepdim=True) - - class ReduceSum4(Module): - def forward(self, *args): - return args[0].sum(dim=(2, 3), keepdim=True) - - class ReduceSum5(Module): - def forward(self, *args): - return args[0].sum(dim=(2, 3), keepdim=False) - - input_data = torch.rand(input_shape).float() - verify_model(ReduceSum1().float().eval(), input_data=input_data) - verify_model(ReduceSum2().float().eval(), input_data=input_data) - verify_model(ReduceSum3().float().eval(), input_data=input_data) - verify_model(ReduceSum4().float().eval(), input_data=input_data) - verify_model(ReduceSum5().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_reduce_prod(): - """test_forward_reduce_prod""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class ReduceProd1(Module): - def forward(self, *args): - return args[0].prod(1) - - class ReduceProd2(Module): - def forward(self, *args): - return args[0].prod(dim=1, keepdim=False) - - class ReduceProd3(Module): - def forward(self, *args): - return args[0].prod(dim=2, keepdim=True) - - input_data = torch.rand(input_shape).float() - verify_model(ReduceProd1().float().eval(), input_data=input_data) - verify_model(ReduceProd2().float().eval(), input_data=input_data) - verify_model(ReduceProd3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_argmin(): - """test_forward_argmin""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class ArgMin1(Module): - def forward(self, *args): - return args[0].argmin(1) - - class ArgMin2(Module): - def forward(self, *args): - return args[0].argmin(dim=1, keepdim=False) - - class ArgMin3(Module): - def forward(self, *args): - return args[0].argmin(dim=2, keepdim=True) - - input_data = torch.rand(input_shape).float() - verify_model(ArgMin1().float().eval(), input_data=input_data) - verify_model(ArgMin2().float().eval(), input_data=input_data) - verify_model(ArgMin3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_argmax(): - """test_forward_argmax""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class ArgMax1(Module): - def forward(self, *args): - return args[0].argmax(1) - - class ArgMax2(Module): - def forward(self, *args): - return args[0].argmax(dim=1, keepdim=False) - - class ArgMax3(Module): - def forward(self, *args): - return args[0].argmax(dim=2, keepdim=True) - - input_data = torch.rand(input_shape).float() - verify_model(ArgMax1().float().eval(), input_data=input_data) - verify_model(ArgMax2().float().eval(), input_data=input_data) - verify_model(ArgMax3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_std(): - """test_forward_std""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Std1(Module): - def forward(self, *args): - return args[0].std(1, unbiased=False) - - class Std2(Module): - def forward(self, *args): - return args[0].std(dim=1, keepdim=False, unbiased=False) - - class Std3(Module): - def forward(self, *args): - return args[0].std(dim=2, keepdim=True, unbiased=False) - - class Std4(Module): - def forward(self, *args): - return args[0].std(dim=(2, 3), keepdim=True, unbiased=False) - - class Std5(Module): - def forward(self, *args): - return args[0].std(dim=(2, 3), keepdim=False, unbiased=False) - - class Std6(Module): - def forward(self, *args): - return args[0].std(unbiased=False) - - class Std7(Module): - def forward(self, *args): - return args[0].std(dim=1, keepdim=False, unbiased=True) - - class Std8(Module): - def forward(self, *args): - return args[0].std(dim=(2, 3), keepdim=True, unbiased=True) - - class Std9(Module): - def forward(self, *args): - return args[0].std(unbiased=True) - - input_data = torch.rand(input_shape).float() - verify_model(Std1().float().eval(), input_data=input_data) - verify_model(Std2().float().eval(), input_data=input_data) - verify_model(Std3().float().eval(), input_data=input_data) - verify_model(Std4().float().eval(), input_data=input_data) - verify_model(Std5().float().eval(), input_data=input_data) - verify_model(Std6().float().eval(), input_data=input_data) - verify_model(Std7().float().eval(), input_data=input_data) - verify_model(Std8().float().eval(), input_data=input_data) - verify_model(Std9().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_var_mean(): - """test_forward_var_mean""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class VarMean1(Module): - def forward(self, *args): - return torch.var_mean(args[0], 1, unbiased=False) - - class VarMean2(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=1, keepdim=False, unbiased=False) - - class VarMean3(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=2, keepdim=True, unbiased=False) - - class VarMean4(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=(2, 3), keepdim=True, unbiased=False) - - class VarMean5(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=(2, 3), keepdim=False, unbiased=False) - - class VarMean6(Module): - def forward(self, *args): - return torch.var_mean(args[0], unbiased=False) - - class VarMean7(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=1, keepdim=False, unbiased=True) - - class VarMean8(Module): - def forward(self, *args): - return torch.var_mean(args[0], dim=(2, 3), keepdim=True, unbiased=True) - - class VarMean9(Module): - def forward(self, *args): - return torch.var_mean(args[0], unbiased=True) - - input_data = torch.rand(input_shape).float() - verify_model(VarMean1().float().eval(), input_data=input_data) - verify_model(VarMean2().float().eval(), input_data=input_data) - verify_model(VarMean3().float().eval(), input_data=input_data) - verify_model(VarMean4().float().eval(), input_data=input_data) - verify_model(VarMean5().float().eval(), input_data=input_data) - verify_model(VarMean6().float().eval(), input_data=input_data) - verify_model(VarMean7().float().eval(), input_data=input_data) - verify_model(VarMean8().float().eval(), input_data=input_data) - verify_model(VarMean9().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_variance(): - """test_forward_variance""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Variance1(Module): - def forward(self, *args): - return args[0].var(1, unbiased=False) - - class Variance2(Module): - def forward(self, *args): - return args[0].var(dim=1, keepdim=False, unbiased=False) - - class Variance3(Module): - def forward(self, *args): - return args[0].var(dim=2, keepdim=True, unbiased=False) - - class Variance4(Module): - def forward(self, *args): - return args[0].var(dim=(2, 3), keepdim=True, unbiased=False) - - class Variance5(Module): - def forward(self, *args): - return args[0].var(dim=(2, 3), keepdim=False, unbiased=False) - - class Variance6(Module): - def forward(self, *args): - return args[0].var(unbiased=False) - - class Variance7(Module): - def forward(self, *args): - return args[0].var(dim=1, keepdim=False, unbiased=True) - - class Variance8(Module): - def forward(self, *args): - return args[0].var(dim=(2, 3), keepdim=True, unbiased=True) - - class Variance9(Module): - def forward(self, *args): - return args[0].var(unbiased=True) - - input_data = torch.rand(input_shape).float() - verify_model(Variance1().float().eval(), input_data=input_data) - verify_model(Variance2().float().eval(), input_data=input_data) - verify_model(Variance3().float().eval(), input_data=input_data) - verify_model(Variance4().float().eval(), input_data=input_data) - verify_model(Variance5().float().eval(), input_data=input_data) - verify_model(Variance6().float().eval(), input_data=input_data) - verify_model(Variance7().float().eval(), input_data=input_data) - verify_model(Variance8().float().eval(), input_data=input_data) - verify_model(Variance9().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_rsub(): - """test_forward_rsub""" - torch.set_grad_enabled(False) - - class Rsub1(Module): - def forward(self, *args): - return torch.rsub(args[0], args[1]) - - class Rsub2(Module): - def forward(self, *args): - return torch.rsub(args[0], args[1], alpha=0.5) - - d1 = torch.rand([1, 3]).float() - d2 = torch.rand([1, 3]).float() - d3 = torch.rand([1, 3]).int() - verify_model(Rsub1().float().eval(), input_data=[d1, d2]) - verify_model(Rsub1().float().eval(), input_data=[d1, d3]) - verify_model(Rsub2().float().eval(), input_data=[d1, d2]) - verify_model(Rsub2().float().eval(), input_data=[d1, d3]) - - d1 = torch.rand([1, 3]).half() - d2 = torch.rand([1, 3]).half() - verify_model(Rsub1().half().eval(), input_data=[d1, d2]) - verify_model(Rsub1().half().eval(), input_data=[d1, d3]) - verify_model(Rsub2().half().eval(), input_data=[d1, d2]) - verify_model(Rsub2().half().eval(), input_data=[d1, d3]) - - -@tvm.testing.uses_gpu -def test_forward_embedding(): - """test_forward_embedding""" - torch.set_grad_enabled(False) - - input_data = torch.randint(0, 10, [2, 4]).long() - verify_model(torch.nn.Embedding(10, 3).float().eval(), input_data=input_data) - - input_data = torch.randint(0, 4, [2, 3, 4]).long() - verify_model(torch.nn.Embedding(4, 5, sparse=False).float().eval(), input_data=input_data) - - input_data = torch.randint(0, 4, [2, 3, 4]).long() - verify_model(torch.nn.Embedding(4, 5, sparse=True).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_onehot(): - """test_forward_onehot""" - torch.set_grad_enabled(False) - - class OneHot1(Module): - def forward(self, *args): - return torch.nn.functional.one_hot(args[0], num_classes=3) - - class OneHot2(Module): - def forward(self, *args): - return torch.nn.functional.one_hot(args[0], num_classes=5) - - input_data = torch.arange(0, 5) % 3 - verify_model(OneHot1().float().eval(), input_data=input_data) - - input_data = torch.arange(0, 5) % 4 - verify_model(OneHot2().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_isfinite(): - """test_forward_isfinite""" - torch.set_grad_enabled(False) - - class IsFinite1(Module): - def forward(self, *args): - return torch.isfinite(args[0]) - - input_data = torch.tensor([1, float("inf"), 2, float("-inf"), float("nan")]).float() - verify_model(IsFinite1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_isnan(): - """test_forward_isnan""" - torch.set_grad_enabled(False) - - class IsNan1(Module): - def forward(self, *args): - return torch.isnan(args[0]) - - input_data = torch.tensor([1, float("inf"), 2, float("-inf"), float("nan")]).float() - verify_model(IsNan1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_isinf(): - """test_forward_isinf""" - torch.set_grad_enabled(False) - - class IsInf1(Module): - def forward(self, *args): - return torch.isinf(args[0]) - - input_data = torch.tensor([1, float("inf"), 2, float("-inf"), float("nan")]).float() - verify_model(IsInf1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_clamp(): - """test_forward_clamp""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class Clamp1(Module): - def forward(self, *args): - return torch.clamp(args[0], min=-0.5, max=0.5) - - class Clamp2(Module): - def forward(self, *args): - return torch.clamp(args[0], min=-0.3) - - class Clamp3(Module): - def forward(self, *args): - return torch.clamp(args[0], max=1.0) - - class Clamp_MinExpr_MaxConstant(Module): - def forward(self, *args): - h, w = args[0].shape[2:] - amin = h / 100.0 - return torch.clamp(args[0], min=amin, max=w) - - input_data = torch.rand(input_shape).float() - verify_model(Clamp1().float().eval(), input_data=input_data) - verify_model(Clamp2().float().eval(), input_data=input_data) - verify_model(Clamp3().float().eval(), input_data=input_data) - verify_model(Clamp_MinExpr_MaxConstant().float().eval(), input_data=input_data) - - verify_model(lambda inp: torch.clamp_min(inp, 0.5), input_data) - inp_uint8 = torch.randint(low=0, high=256, size=(100, 100), dtype=torch.uint8) - verify_model(lambda inp: torch.clamp_max(inp, 125), inp_uint8) - - -@tvm.testing.uses_gpu -def test_forward_clamp_(): - """test_forward_clamp_""" - torch.set_grad_enabled(False) - - class ClampInPlace(Module): - def __init__(self, i_min, i_max): - super().__init__() - self.min = i_min - self.max = i_max - - def forward(self, *args): - return torch.clamp_(args[0], self.min, self.max) - - for ishape, i_min, i_max in (([4, 8], 0.1, 0.9), ([7, 6], 0.2, 0.5)): - input_data = torch.rand(ishape).float() - verify_model(ClampInPlace(i_min, i_max).float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_ones(): - """test_forward_ones""" - torch.set_grad_enabled(False) - - class Ones1(Module): - def forward(self, *args): - return torch.ones(2, 3) - - verify_model(Ones1().float().eval(), input_data=[]) - - -@tvm.testing.uses_gpu -def test_forward_ones_like(): - """test_forward_ones_like""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class OnesLike1(Module): - def forward(self, *args): - return torch.ones_like(args[0]) - - class OnesLike2(Module): - def forward(self, *args): - return torch.ones_like(args[0], dtype=torch.int8) - - class OnesLike3(Module): - def forward(self, *args): - return torch.ones_like(args[0], dtype=torch.float) - - input_data = torch.rand(input_shape).float() - verify_model(OnesLike1().float().eval(), input_data=input_data) - verify_model(OnesLike2().float().eval(), input_data=input_data) - verify_model(OnesLike3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_new_ones(): - """test_forward_new_ones""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - def test_func(input_tensor): - return input_tensor.new_ones([3, 10, 10]) - - verify_model_with_input(test_func, [torch.rand(input_shape).float()]) - - -@tvm.testing.uses_gpu -def test_forward_zeros(): - """test_forward_zeros""" - torch.set_grad_enabled(False) - - class Zeros1(Module): - def forward(self, *args): - return torch.zeros(2, 3) - - verify_model(Zeros1().float().eval(), input_data=[]) - - -def test_forward_zero_(): - def test_func(x): - return x.zero_() - - verify_model_with_input(test_func, [torch.rand([1, 3, 10, 10]).float()]) - - -@tvm.testing.uses_gpu -def test_forward_zeros_like(): - """test_forward_zeros_like""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class ZerosLike1(Module): - def forward(self, *args): - return torch.zeros_like(args[0]) - - class ZerosLike2(Module): - def forward(self, *args): - return torch.zeros_like(args[0], dtype=torch.int32) - - class ZerosLike3(Module): - def forward(self, *args): - return torch.zeros_like(args[0], dtype=torch.float) - - input_data = torch.rand(input_shape).float() - verify_model(ZerosLike1().float().eval(), input_data=input_data) - verify_model(ZerosLike2().float().eval(), input_data=input_data) - verify_model(ZerosLike3().float().eval(), input_data=input_data) - - -def test_forward_new_zeros(): - def test_func(x): - return x.new_zeros((2, 3)) - - verify_model_with_input(test_func, [torch.rand([1, 3, 10, 10]).float()]) - - -@tvm.testing.uses_gpu -def test_forward_full(): - """test_forward_full""" - torch.set_grad_enabled(False) - - class Full1(Module): - def forward(self, *args): - return torch.full((2, 3), 3.14) - - class Full2(Module): - def forward(self, *args): - return torch.full((1, 2, 3), 1.0, dtype=torch.int32) - - verify_model(Full1().float().eval(), input_data=[]) - verify_model(Full2().float().eval(), input_data=[]) - - -@tvm.testing.uses_gpu -def test_forward_adaptive_max_pool1d(): - """test_forward_adaptive_max_pool1d""" - torch.set_grad_enabled(False) - input_data = [torch.randn([2, 2, 4], dtype=torch.float32)] - m = torch.nn.AdaptiveMaxPool1d(3) - - verify_model(m.float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_instance_norm(): - """test_forward_instance_norm""" - - class instance_norm(Module): - def forward(self, *args): - return torch.nn.functional.instance_norm(args[0], use_input_stats=True) - - m = instance_norm().float().eval() - input_data = torch.randn([1, 1, 1, 2], dtype=torch.float64) - - verify_model(m.float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_full_like(): - """test_forward_full_like""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - class FullLike1(Module): - def forward(self, *args): - return torch.full_like(args[0], 3.14) - - class FullLike2(Module): - def forward(self, *args): - return torch.full_like(args[0], 22.22, dtype=torch.int32) - - class FullLike3(Module): - def forward(self, *args): - return torch.full_like(args[0], 1.4, dtype=torch.float) - - input_data = torch.rand(input_shape).float() - verify_model(FullLike1().float().eval(), input_data=input_data) - verify_model(FullLike2().float().eval(), input_data=input_data) - verify_model(FullLike3().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_new_full(): - """test_forward_new_full""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - def test_func(input_tensor): - return input_tensor.new_full([2, 3], 1) - - verify_model_with_input(test_func, [torch.rand(input_shape).float()]) - - -def test_forward_fill_(): - def test_func(x): - return x.fill_(3) - - verify_model_with_input(test_func, [torch.rand([1, 3, 10, 10]).float()]) - - -def test_forward_fill_with_div(): - """test_forward_fill_with_div""" - - def test_func(x): - y = torch.div(torch.tensor(6.0), torch.tensor(2.0)) - return x.fill_(y) - - verify_model_with_input(test_func, [torch.rand([1, 3, 10, 10]).float()]) - - -@tvm.testing.uses_gpu -def test_forward_linspace(): - """test_forward_linspace""" - torch.set_grad_enabled(False) - - class Linspace1(Module): - def forward(self, *args): - return torch.linspace(5, 10, steps=100) - - class Linspace2(Module): - def forward(self, *args): - return torch.linspace(-10, 10, steps=5) - - class Linspace3(Module): - def forward(self, *args): - return torch.linspace(start=-10, end=10, steps=5) - - class Linspace4(Module): - def forward(self, *args): - return torch.linspace(start=-10, end=10, steps=1) - - class Linspace5(Module): - def forward(self, *args): - return torch.linspace(1, 2, 1, dtype=torch.int32) - - class Linspace6(Module): - def forward(self, *args): - return torch.linspace(start=1, end=6, steps=2) - - class Linspace7(Module): - def forward(self, *args): - return torch.linspace(1, 4, steps=100, dtype=torch.float32) - - class Linspace8(Module): - def forward(self, *args): - return torch.linspace(1, 2, 1, dtype=torch.int16) - - class Linspace9(Module): - def forward(self, *args): - return torch.linspace(0, 8, 10) - - verify_model(Linspace1().float().eval()) - verify_model(Linspace2().float().eval()) - verify_model(Linspace3().float().eval()) - verify_model(Linspace4().float().eval()) - verify_model(Linspace5().float().eval()) - verify_model(Linspace6().float().eval()) - verify_model(Linspace7().float().eval()) - verify_model(Linspace8().float().eval()) - verify_model(Linspace9().float().eval()) - - -@tvm.testing.uses_gpu -def test_forward_take(): - """test_forward_take""" - torch.set_grad_enabled(False) - - class Take1(Module): - def forward(self, *args): - indices = torch.tensor([[0, 0], [1, 0]]) - if torch.cuda.is_available(): - indices = indices.cuda() - return torch.take(args[0], indices) - - class Take2(Module): - def forward(self, *args): - return torch.take(args[0], args[1]) - - input_data = torch.tensor([[1, 2], [3, 4]]) - verify_model(Take1().float().eval(), input_data=input_data) - indices = torch.tensor([[0, 0], [1, 0]]) - verify_model(Take2().float().eval(), input_data=[input_data, indices]) - indices = torch.tensor([0, -1]) - verify_model(Take2().float().eval(), input_data=[input_data, indices]) - - -@tvm.testing.uses_gpu -def test_forward_topk(): - """test_forward_topk""" - torch.set_grad_enabled(False) - - class Topk1(Module): - def forward(self, *args): - return torch.topk(args[0], k=3) - - class Topk2(Module): - def forward(self, *args): - return torch.topk(args[0], k=3, dim=-2) - - class Topk3(Module): - def forward(self, *args): - return torch.topk(args[0], k=3, dim=3) - - class Topk4(Module): - def forward(self, *args): - return torch.topk(args[0], k=3, largest=True) - - class Topk5(Module): - def forward(self, *args): - return torch.topk(args[0], k=3, largest=False) - - class Topk6(Module): - def forward(self, *args): - return torch.topk(args[0], k=3, sorted=True) - - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(Topk1().float().eval(), input_data=input_data) - verify_model(Topk2().float().eval(), input_data=input_data) - verify_model(Topk3().float().eval(), input_data=input_data) - verify_model(Topk4().float().eval(), input_data=input_data) - verify_model(Topk5().float().eval(), input_data=input_data) - verify_model(Topk6().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_logical_not(): - """test_forward_logical_not""" - torch.set_grad_enabled(False) - - class LogicalNot1(Module): - def forward(self, *args): - return torch.logical_not(args[0]) - - input_data = torch.tensor([True, False]) - verify_model(LogicalNot1().float().eval(), input_data=input_data) - - input_data = torch.tensor([0, 1, -10], dtype=torch.int8) - verify_model(LogicalNot1().float().eval(), input_data=input_data) - - input_data = torch.tensor([0.0, 1.5, -10.0], dtype=torch.double) - verify_model(LogicalNot1().float().eval(), input_data=input_data) - - input_data = torch.tensor([0.0, 1.0, -10.0], dtype=torch.int32) - verify_model(LogicalNot1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_bitwise_not(): - """test_forward_bitwise_not""" - torch.set_grad_enabled(False) - - class BitwiseNot1(Module): - def forward(self, *args): - return torch.bitwise_not(args[0]) - - input_data = torch.tensor([0, 1, -10], dtype=torch.int8) - verify_model(BitwiseNot1().float().eval(), input_data=input_data) - - input_data = torch.tensor([0.0, 1.0, -10.0], dtype=torch.int32) - verify_model(BitwiseNot1().float().eval(), input_data=input_data) - - input_data = torch.tensor([True, False]) - verify_model(BitwiseNot1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_bitwise_xor(): - """test_forward_bitwise_xor""" - torch.set_grad_enabled(False) - - class BitwiseXor1(Module): - def forward(self, *args): - return torch.bitwise_xor(args[0], args[1]) - - class BitwiseXor2(Module): - def forward(self, *args): - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - if torch.cuda.is_available(): - rhs = rhs.cuda() - return torch.bitwise_xor(args[0], rhs) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - verify_model(BitwiseXor1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([True, True, False]) - rhs = torch.tensor([False, True, False]) - verify_model(BitwiseXor1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - verify_model(BitwiseXor2().float().eval(), input_data=[lhs]) - - -def test_forward_bitwise_and(): - """test_forward_bitwise_and""" - torch.set_grad_enabled(False) - - class BitwiseAnd1(Module): - def forward(self, *args): - return torch.bitwise_and(args[0], args[1]) - - class BitwiseAnd2(Module): - def forward(self, *args): - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - if torch.cuda.is_available(): - rhs = rhs.cuda() - return torch.bitwise_and(args[0], rhs) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - verify_model(BitwiseAnd1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([True, True, False]) - rhs = torch.tensor([False, True, False]) - verify_model(BitwiseAnd1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - verify_model(BitwiseAnd2().float().eval(), input_data=[lhs]) - - -@tvm.testing.uses_gpu -def test_forward_logical_xor(): - """test_forward_logical_xor""" - torch.set_grad_enabled(False) - - class LogicalXor1(Module): - def forward(self, *args): - return torch.logical_xor(args[0], args[1]) - - class LogicalXor2(Module): - def forward(self, *args): - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - if torch.cuda.is_available(): - rhs = rhs.cuda() - return torch.logical_xor(args[0], rhs) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - rhs = torch.tensor([1, 0, 3], dtype=torch.int8) - verify_model(LogicalXor1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([True, True, False]) - rhs = torch.tensor([False, True, False]) - verify_model(LogicalXor1().float().eval(), input_data=[lhs, rhs]) - - lhs = torch.tensor([-1, -2, 3], dtype=torch.int8) - verify_model(LogicalXor2().float().eval(), input_data=[lhs]) - - -@tvm.testing.uses_gpu -def test_forward_unary(): - """test_forward_unary""" - torch.set_grad_enabled(False) - - class Sqrt1(Module): - def forward(self, *args): - return torch.sqrt(args[0]) - - class RSqrt1(Module): - def forward(self, *args): - return torch.rsqrt(args[0]) - - class Ceil1(Module): - def forward(self, *args): - return torch.ceil(args[0]) - - class Floor1(Module): - def forward(self, *args): - return torch.floor(args[0]) - - class Round1(Module): - def forward(self, *args): - return torch.round(args[0]) - - class Cos1(Module): - def forward(self, *args): - return torch.cos(args[0]) - - class Sin1(Module): - def forward(self, *args): - return torch.sin(args[0]) - - class Tan1(Module): - def forward(self, *args): - return torch.tan(args[0]) - - class Tanh1(Module): - def forward(self, *args): - return torch.tanh(args[0]) - - class Acos1(Module): - def forward(self, *args): - return torch.acos(args[0]) - - class Asin1(Module): - def forward(self, *args): - return torch.asin(args[0]) - - class Atan1(Module): - def forward(self, *args): - return torch.atan(args[0]) - - class Log1(Module): - def forward(self, *args): - return torch.log(args[0]) - - class Exp1(Module): - def forward(self, *args): - return torch.exp(args[0]) - - class Erf1(Module): - def forward(self, *args): - return torch.erf(args[0]) - - class Trunc1(Module): - def forward(self, *args): - return torch.trunc(args[0]) - - class Sign1(Module): - def forward(self, *args): - return torch.sign(args[0]) - - class Neg1(Module): - def forward(self, *args): - return torch.neg(args[0]) - - class Sinh1(Module): - def forward(self, *args): - return torch.sinh(args[0]) - - class Cosh1(Module): - def forward(self, *args): - return torch.cosh(args[0]) - - class Log2_1(Module): - def forward(self, *args): - return torch.log2(args[0]) - - class Log10_1(Module): - def forward(self, *args): - return torch.log10(args[0]) - - class Log1p_1(Module): - def forward(self, *args): - return torch.log1p(args[0]) - - class Square(Module): - def forward(self, *args): - return torch.square(args[0]) - - input_shape = [1, 3, 10, 10] - input_data = torch.rand(input_shape).float() - verify_model(Square().float().eval(), input_data=input_data) - verify_model(Sqrt1().float().eval(), input_data=input_data) - verify_model(RSqrt1().float().eval(), input_data=input_data) - verify_model(Ceil1().float().eval(), input_data=input_data) - verify_model(Floor1().float().eval(), input_data=input_data) - verify_model(Round1().float().eval(), input_data=input_data) - verify_model(Cos1().float().eval(), input_data=input_data) - verify_model(Cosh1().float().eval(), input_data=input_data) - verify_model(Sin1().float().eval(), input_data=input_data) - verify_model(Sinh1().float().eval(), input_data=input_data) - verify_model(Tan1().float().eval(), input_data=input_data) - verify_model(Tanh1().float().eval(), input_data=input_data) - verify_model(Acos1().float().eval(), input_data=input_data) - verify_model(Asin1().float().eval(), input_data=input_data) - verify_model(Atan1().float().eval(), input_data=input_data) - verify_model(Log1().float().eval(), input_data=input_data) - verify_model(Log2_1().float().eval(), input_data=input_data) - verify_model(Log10_1().float().eval(), input_data=input_data) - verify_model(Log1p_1().float().eval(), input_data=input_data) - verify_model(Exp1().float().eval(), input_data=input_data) - verify_model(Erf1().float().eval(), input_data=input_data) - verify_model(Trunc1().float().eval(), input_data=input_data) - verify_model(Sign1().float().eval(), input_data=input_data) - verify_model(Neg1().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_tril(): - """test_forward_tril""" - torch.set_grad_enabled(False) - - def test_func(input_data): - return torch.tril(input_data) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func, input_data=input_data) - - def test_func1(input_data): - return torch.tril(input_data, 1) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func1, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func1, input_data=input_data) - - def test_func2(input_data): - return torch.tril(input_data, -1) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func2, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_triu(): - """test_forward_triu""" - torch.set_grad_enabled(False) - - def test_func(input_data): - return torch.triu(input_data) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func, input_data=input_data) - - def test_func1(input_data): - return torch.triu(input_data, 1) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func1, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func1, input_data=input_data) - - def test_func2(input_data): - return torch.triu(input_data, -1) - - input_data = torch.rand([3, 3]).float() - verify_model(test_func2, input_data=input_data) - input_data = torch.rand([1, 3, 10, 10]).float() - verify_model(test_func2, input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_where(): - """test_forward_where""" - torch.set_grad_enabled(False) - - class Where1(Module): - def forward(self, *args): - y = torch.ones([3, 2]) - if torch.cuda.is_available(): - y = y.cuda() - return torch.where(args[0] > 0, args[0], y) - - class Where2(Module): - def forward(self, *args): - return torch.where(args[0] > 0, args[0], args[1]) - - class Where3(Module): - def forward(self, *args): - return torch.where(args[0])[0] - - x = torch.rand([3, 2]).float() - verify_model(Where1(), input_data=[x]) - y = torch.rand([3, 2]) - verify_model(Where2(), input_data=[x, y]) - - # a single argument variant, equivalent to torch.nonzero(..., as_tuple=True) - inp = torch.rand([10]) - inp[3:8] = 0 - verify_trace_model(Where3(), [inp], ["llvm"]) - - -@tvm.testing.uses_gpu -def test_forward_addcdiv(): - """test_forward_addcdiv""" - torch.set_grad_enabled(False) - - class Addcdiv1(Module): - def forward(self, *args): - t1 = torch.ones([3, 1]) - t2 = torch.ones([1, 3]) - if torch.cuda.is_available(): - t1 = t1.cuda() - t2 = t2.cuda() - return torch.addcdiv(args[0], 0.1, t1, t2) - - class Addcdiv2(Module): - def forward(self, *args): - return torch.addcdiv(args[0], 0.5, args[1], args[2]) - - input_data = torch.rand([1, 3]).float() - verify_model(Addcdiv1().float().eval(), input_data=input_data) - t1 = torch.rand([3, 1]).float() - t2 = torch.rand([1, 3]).float() - verify_model(Addcdiv2().float().eval(), input_data=[input_data, t1, t2]) - - -@tvm.testing.uses_gpu -def test_forward_addcmul(): - """test_forward_addcmul""" - torch.set_grad_enabled(False) - - class Addcmul1(Module): - def forward(self, *args): - t1 = torch.ones([3, 1]) - t2 = torch.ones([1, 3]) - if torch.cuda.is_available(): - t1 = t1.cuda() - t2 = t2.cuda() - return torch.addcmul(args[0], 0.1, t1, t2) - - class Addcmul2(Module): - def forward(self, *args): - return torch.addcmul(args[0], 0.5, args[1], args[2]) - - input_data = torch.rand([1, 3]).float() - verify_model(Addcmul1().float().eval(), input_data=input_data) - t1 = torch.rand([3, 1]).float() - t2 = torch.rand([1, 3]).float() - verify_model(Addcmul2().float().eval(), input_data=[input_data, t1, t2]) - - -@tvm.testing.uses_gpu -def test_forward_true_divide(): - """test_forward_true_divide""" - if package_version.parse(torch.__version__) < package_version.parse("1.5.0"): - return - torch.set_grad_enabled(False) - - class TrueDivide(Module): - def forward(self, *args): - return torch.true_divide(args[0], args[1]) - - dividend = torch.rand([5, 3]).float() - # divisor could be either tensor or scalar - divisor_tensor = torch.rand([5, 3]).float() + 0.5 - divisor_scalar = torch.tensor(1.0, dtype=torch.float32) - verify_model( - TrueDivide().float().eval(), input_data=[dividend, divisor_tensor], atol=1e-4, rtol=1e-4 - ) - verify_model( - TrueDivide().float().eval(), input_data=[dividend, divisor_scalar], atol=1e-4, rtol=1e-4 - ) - - -@tvm.testing.uses_gpu -def test_forward_is_floating_point(): - """test_forward_is_floating_point""" - torch.set_grad_enabled(False) - - class IsFloatingPoint(Module): - def forward(self, arg): - # `torch.jit.trace` cannot accept something that outputs - # a Bool, so `torch.jit.script` will be used instead - return torch.is_floating_point(arg) - - targets = _get_default_vm_targets() - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.float64) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.float32) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.float16) - # todo(dvisnty): Run the test for bfloat16 when full bfloat16 support is implemented - # verify_script_model(IsFloatingPoint(), [(1,1)], targets, idtype=torch.bfloat16) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.int64) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.int32) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.int16) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.int8) - verify_script_model(IsFloatingPoint(), [(1, 1)], targets, idtype=torch.uint8) - - -@tvm.testing.uses_gpu -def test_forward_traced_function(): - """test_forward_traced_function""" - - def fn(t1, t2): - return t1 + t2 - - tensor1 = torch.randn(3, 4) - tensor2 = torch.randn(3, 4) - verify_model(fn, input_data=[tensor1, tensor2]) - - -@tvm.testing.uses_gpu -def test_forward_dtypes(): - """test_forward_dtypes""" - - def fn(t1, t2): - return 2.5 * t1 + t2 - - for dt in [torch.int32, torch.int64, torch.double]: - tensor1 = torch.randn(3, 4).to(dtype=dt) - tensor2 = torch.randn(3, 4).to(dtype=dt) - verify_model(fn, input_data=[tensor1, tensor2]) - - class ModuleWithIntParameters(Module): - def __init__(self, arr): - super().__init__() - self.param = torch.nn.Parameter(torch.LongTensor(arr), requires_grad=False) - - def forward(self, x): - return x.long() + self.param - - shape = (10, 10) - param = torch.ones(shape, dtype=torch.long) - inp = torch.ones(shape, dtype=torch.int) - verify_model(ModuleWithIntParameters(param), input_data=inp) - - -@tvm.testing.uses_gpu -def test_weight_names(): - tm = torch.jit.trace(torch.nn.Linear(3, 4), [torch.randn(2, 3)]) - _, params = relay.frontend.from_pytorch(tm, [("input", (2, 3))]) - keys = [key.split(".")[-1] for key in params.keys()] - assert set(keys) == set(n for n, p in tm.named_parameters()) - - -@tvm.testing.uses_gpu -def test_duplicate_weight_use(): - """test_duplicate_weight_use""" - # The test cases doesn't make any sense as a neural network, - # the issue popped up in shared input/output embeddings of bert, - # but this is quicker - class Test(Module): - def __init__(self): - super().__init__() - self.lin = torch.nn.Linear(5, 3) - - def forward(self, x): - x = self.lin(x) - x = x @ self.lin.weight - return x - - verify_model(Test(), input_data=[torch.randn(5, 5)]) - - -@tvm.testing.uses_gpu -def test_forward_matmul(): - """test_forward_matmul""" - torch.set_grad_enabled(False) - - class MatMul1(Module): - def forward(self, *args): - return torch.matmul(args[0], args[1]) - - # vector x vector - 1D x 1D - tensor1 = torch.randn(4) - tensor2 = torch.randn(4) - verify_model(MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.dense"]) - - # vector x matrix - 1D x 2D - tensor1 = torch.randn(4) - tensor2 = torch.randn(4, 3) - verify_model(MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.dense"]) - - # vector x batched_matrix - 1D x ND - tensor1 = torch.randn(5) - tensor2 = torch.randn(2, 3, 5, 4) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # matrix x vector - 2D - 1D - tensor1 = torch.randn(3, 4) - tensor2 = torch.randn(4) - verify_model(MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.dense"]) - - # matrix x matrix - 2D x 2D - tensor1 = torch.randn(10, 4) - tensor2 = torch.randn(4, 10) - verify_model(MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.dense"]) - - # broadcasted matrix x batched matrix - 2D x ND - tensor1 = torch.randn(10, 4) - tensor2 = torch.randn(2, 3, 4, 5) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # batched matrix x vector - ND x 1D - tensor1 = torch.randn(2, 3, 4, 5) - tensor2 = torch.randn(5) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # batched matrix x broadcasted matrix - ND x 2D - tensor1 = torch.randn(10, 3, 4) - tensor2 = torch.randn(4, 5) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # batched matrix x batched matrix - ND x ND - tensor1 = torch.randn(2, 10, 3, 4) - tensor2 = torch.randn(2, 10, 4, 5) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # batched matrix x broadcasted matrix - ND x ND - tensor1 = torch.randn(2, 5, 3, 4) - tensor2 = torch.randn(2, 1, 4, 5) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # broadcasted matrix x batched matrix - ND x ND - tensor1 = torch.randn(2, 1, 5, 4) - tensor2 = torch.randn(2, 5, 4, 3) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - # broadcasted matrix x broadcasted matrix - ND x ND - tensor1 = torch.randn(3, 2, 3, 1, 5, 4) - tensor2 = torch.randn(2, 1, 5, 4, 3) - verify_model( - MatMul1().float().eval(), input_data=[tensor1, tensor2], expected_ops=["nn.batch_matmul"] - ) - - -@pytest.mark.skip(reason="unsupported op aten::lift_fresh") -def test_forward_index(): - """test_forward_index""" - torch.set_grad_enabled(False) - input_shape = [3, 4, 5, 6] - - class Index0(Module): - def forward(self, x): - return x[[0, 1], [0, 2], :2, 4] - - input_data = torch.rand(input_shape).float() - verify_model(Index0().eval(), input_data=input_data) - - class Index1(Module): - def forward(self, x): - return x[[0], [1, 2, 3, 0], [3, 1, 2, 2], [4, 2, 1, 0]] - - input_data = torch.rand(input_shape).float() - verify_model(Index1().eval(), input_data=input_data) - - class Index2(Module): - def forward(self, x): - return x[None, [2, 2]] - - input_data = torch.rand(input_shape).float() - verify_model(Index2().eval(), input_data=input_data) - - class Index3(Module): - def forward(self, x): - return x[None, [0, 1, 2], 1, [2, 3, 4]] - - input_data = torch.rand(input_shape).float() - verify_model(Index3().eval(), input_data=input_data) - - class Index4(Module): - def forward(self, x): - return x[None, [0, 0], None, np.array([[0], [1], [2]]), None] - - input_data = torch.rand(input_shape).float() - verify_model(Index4().eval(), input_data=input_data) - - class Index5(Module): - def forward(self, x): - return x[None, None, [0, 0], np.array([[0], [1], [2]]), None] - - input_data = torch.rand(input_shape).float() - verify_model(Index5().eval(), input_data=input_data) - - class Index6(Module): - def forward(self, x): - return x[None, 1, None, [1, 2, 3]] - - input_data = torch.rand(input_shape).float() - verify_model(Index6().eval(), input_data=input_data) - - def test_fn_bool_mask(): - return lambda data, mask: data[0, mask] - - data = torch.tensor([[1, 2, 3], [4, 5, 6]]) - mask = torch.tensor([True, True, False]) - - verify_trace_model(test_fn_bool_mask(), [data, mask], ["llvm", "cuda"]) - - -def test_logsumexp(): - """test_logsumexp""" - - class Logsumexp(Module): - def __init__(self, dim, keepdim=False): - super().__init__() - self.dim = dim - self.keepdim = keepdim - - def forward(self, x): - return torch.logsumexp(x, self.dim, self.keepdim) - - input_shape = (100, 100) - input_data = torch.rand(input_shape) - - verify_model(Logsumexp(0), input_data=input_data) - verify_model(Logsumexp(0, keepdim=True), input_data=input_data) - # Also test on double - verify_model(Logsumexp(1, keepdim=True), input_data=input_data.double()) - - -def test_stack(): - """test_stack""" - - class Stack(torch.nn.Module): - def __init__(self, axis=0): - super().__init__() - self.axis = axis - - def forward(self, x): - return torch.stack((x, x), dim=self.axis) - - inp = torch.randn(8, 8, 8) - verify_model(Stack(), input_data=inp) - verify_model(Stack(axis=-1), input_data=inp) - verify_model(Stack(axis=3), input_data=inp) - verify_model(Stack(axis=-4), input_data=inp) - - -def test_stack_dynamic(): - """test_stack_dynamic""" - - class Stack(torch.nn.Module): - def forward(self, x): - tensor_list = [] - for i in range(x.size(0)): - # this is a workaround to avoid generating impure aten::append op - tensor_list += [x[i]] - # relay tensor array only supports stacking on the first axis - return torch.stack(tensor_list, dim=0) - - verify_script_model(Stack(), [(8, 8, 8)], _get_default_vm_targets()) - - -def test_forward_unbind(): - """test_forward_unbind""" - - class Unbind(torch.nn.Module): - def __init__(self, axis=0): - super().__init__() - self.axis = axis - - def forward(self, x): - return torch.unbind(x, self.axis) - - inp = torch.randn(8, 8, 8) - verify_model(Unbind(0), input_data=inp) - verify_model(Unbind(1), input_data=inp) - verify_model(Unbind(2), input_data=inp) - - -def test_forward_nonzero(): - """test_forward_nonzero""" - - class Nonzero(Module): - def __init__(self, as_tuple=False): - super().__init__() - self.as_tuple = as_tuple - - def forward(self, data): - return torch.nonzero(data, as_tuple=self.as_tuple) - - inp = torch.Tensor(np.array([[0, 1, 0], [2, 0, 9], [-1, -1, 0]]).astype("float32")) - verify_trace_model(Nonzero(), [inp], ["llvm"]) - verify_trace_model(Nonzero(as_tuple=True), [inp], ["llvm"]) - - -def test_forward_scatter(): - """test_forward_scatter""" - # integer cannot be traced - def test_fn_scatter(dim): - return lambda data, index, src: torch.scatter(data, dim=dim, index=index, src=src) - - def test_fn_scatter_add(dim): - return lambda data, index, src: torch.scatter_add(data, dim=dim, index=index, src=src) - - in_data = torch.zeros(3, 5) - in_index = torch.tensor([[0, 1, 2, 0, 0], [2, 0, 0, 1, 2]]) - in_src = torch.rand(2, 5) - - targets = ["llvm", "cuda"] - verify_trace_model(test_fn_scatter(0), [in_data, in_index, in_src], targets) - verify_trace_model(test_fn_scatter_add(0), [in_data, in_index, in_src], targets) - - in_data = torch.zeros(2, 4) - in_index = torch.tensor([[2], [3]]) - in_src = torch.rand(2, 1) - - verify_trace_model(test_fn_scatter(1), [in_data, in_index, in_src], targets) - verify_trace_model(test_fn_scatter_add(1), [in_data, in_index, in_src], targets) - - # Check empty indices - in_data = torch.zeros(2, 4) - in_index = torch.empty((0,)) - in_src = torch.rand(2, 1) - verify_trace_model(test_fn_scatter(0), [in_data, in_index, in_src], targets) - verify_trace_model(test_fn_scatter_add(0), [in_data, in_index, in_src], targets) - - # Check scalar source - # TODO(vvchernov): Scalar source is supported on TVM side, but torch failes with - # input Tuple(Tensor, Tensor, float). What does scalar mean for torch in this case? - - -def test_forward_scatter_reduce(): - """test_forward_scatter_reduce""" - # integer cannot be traced - def test_fn_scatter_reduce(dim, reduce): - return lambda data, index, src: torch.scatter_reduce( - data, dim=dim, index=index, src=src, reduce=reduce - ) - - in_data = torch.rand(3, 5) - 1 - in_index = torch.tensor([[0, 1, 2, 0, 0], [2, 0, 0, 1, 2]]) - in_src = torch.rand(2, 5) - 1 - - targets = ["llvm", "cuda"] - for reduce in ["sum", "prod", "amin", "amax", "mean"]: - verify_trace_model(test_fn_scatter_reduce(0, reduce), [in_data, in_index, in_src], targets) - - in_data = torch.rand(2, 4) - 1 - in_index = torch.tensor([[2], [3]]) - in_src = torch.rand(2, 1) - 1 - - for reduce in ["sum", "prod", "amin", "amax", "mean"]: - verify_trace_model(test_fn_scatter_reduce(1, reduce), [in_data, in_index, in_src], targets) - - -def test_forward_index_put(): - """test_forward_index_put""" - # torch.index_put for 2D tensor and default accumulate (False) - def test_fn_index_put2(): - return lambda data, xidx, yidx, values: torch.index_put( - data, indices=[xidx, yidx], values=values - ) - - # torch.index_put for 3D tensor and accumulate=True - def test_fn_index_put3a(): - return lambda data, xidx, yidx, zidx, values: torch.index_put( - data, indices=[xidx, yidx, zidx], values=values, accumulate=True - ) - - shape = (3, 5) - in_data = torch.zeros(shape) - xidx = torch.tensor([0, 1, 2, 2]) - yidx = torch.tensor([0, 1, 3, 4]) - values = torch.tensor([2.0, 4.0, 7.0, 9.0]) - - targets = ["llvm", "cuda"] - verify_trace_model(test_fn_index_put2(), [in_data, xidx, yidx, values], targets) - - shape = (3, 5, 3) - in_data = torch.zeros(shape) - xidx = torch.tensor([0, 1, 2, 2, 0]) - yidx = torch.tensor([0, 1, 3, 4, 0]) - zidx = torch.tensor([0, 1, 1, 2, 0]) - values = torch.tensor([2.0, 4.0, 7.0, 9.0, 1.0]) - - verify_trace_model(test_fn_index_put3a(), [in_data, xidx, yidx, zidx, values], targets) - - -def test_numel(): - """test_numel""" - - class Numel(Module): - def forward(self, data): - return torch.tensor(torch.numel(data)) - - targets = _get_default_vm_targets() - verify_script_model(Numel(), [(1,)], targets) - verify_script_model(Numel(), [(3, 5)], targets) - verify_script_model(Numel(), [(3, 5, 8)], targets) - - -def test_empty(): - """Test for aten::empty""" - - def test_func(): - return torch.empty([1, 3, 10, 10]) - - verify_model_with_input(test_func, [], assert_shape_only=True) - - -def test_empty_like(): - """Test for aten::empty_like""" - - def test_func(data): - return torch.empty_like(data) - - verify_model_with_input(test_func, [torch.rand([1, 3, 10, 10]).float()], assert_shape_only=True) - - -@tvm.testing.uses_gpu -def test_new_empty(): - """test_forward_new_ones""" - torch.set_grad_enabled(False) - input_shape = [1, 3, 10, 10] - - def test_func(input_tensor): - return input_tensor.new_empty([3, 10, 10]) - - verify_model_with_input(test_func, [torch.rand(input_shape).float()], assert_shape_only=True) - - def test_func1(input_tensor): - return input_tensor.new_empty([3, 10, 10], dtype=torch.int32) - - verify_model_with_input(test_func1, [torch.rand(input_shape).float()], assert_shape_only=True) - - -def test_randn(): - """Test for aten::randn""" - - def test_func(): - return torch.randn([1, 3, 10, 10]) - - verify_model_with_input(test_func, [], assert_shape_only=True, validate_structural_equal=False) - - def test_func1(): - return torch.randn(1, 3, 10, 10) - - verify_model_with_input(test_func1, [], assert_shape_only=True, validate_structural_equal=False) - - -def test_forward_pretrained_bert_base_uncased(): - ###################################################################### - # This is an example how to run BERT models using TVM - # --------------------------------------------------- - """ - Refer the bert example given in https://pypi.org/project/pytorch-pretrained-bert - - # To get started, pretrained bert package needs to be installed as prerequisite. - - .. code-block:: bash - - # install bert package - pip install pytorch_pretrained_bert==0.6.2 --user - """ - # pylint: disable=import-outside-toplevel - try: - from pytorch_pretrained_bert import BertForMaskedLM, BertTokenizer - except ImportError: - print("Torch pretrained bert package must be installed to run this script.") - return - - ###################################################################### - # Load the tokenizer and tokenize the input - # ----------------------------------------- - - # Load pre-trained model tokenizer (vocabulary) - tokenizer = BertTokenizer.from_pretrained("bert-base-uncased") - - # Tokenized input - text = "[CLS] Who was Jim Henson ? [SEP] Jim Henson was a puppeteer [SEP]" - tokenized_text = tokenizer.tokenize(text) - - # Mask a token that we will try to predict back with `BertForMaskedLM` - masked_index = 8 - tokenized_text[masked_index] = "[MASK]" - assert tokenized_text == [ - "[CLS]", - "who", - "was", - "jim", - "henson", - "?", - "[SEP]", - "jim", - "[MASK]", - "was", - "a", - "puppet", - "##eer", - "[SEP]", - ] - - # Convert token to vocabulary indices - indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) - # Define sentence A and B indices associated to 1st and 2nd sentences (see paper) - segments_ids = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] - - # Convert inputs to PyTorch tensors - tokens_tensor = torch.tensor([indexed_tokens]) - segments_tensors = torch.tensor([segments_ids]) - - ###################################################################### - # Load a pretrained PyTorch model bert-base-uncased - # ------------------------------------------------- - - # Bert Model with a language modeling - model = BertForMaskedLM.from_pretrained("bert-base-uncased") - model.eval() - - ###################################################################### - # Predict all tokens with pytorch - # ------------------------------- - - with torch.no_grad(): - torch_preds = model(tokens_tensor, segments_tensors) - - ###################################################################### - # Make TorchScripted model via jit trace - # -------------------------------------- - - scripted_model = torch.jit.trace(model, (tokens_tensor, segments_tensors)).eval() - - ###################################################################### - # Import the graph to Relay - # ------------------------- - # Convert PyTorch graph to Relay graph. The input name can be arbitrary. - - input_1 = "input_ids" - input_2 = "input.2" - shape_list = [(input_1, list(tokens_tensor.shape)), (input_2, list(segments_tensors.shape))] - - mod, params = relay.frontend.from_pytorch(scripted_model, shape_list) - - ###################################################################### - # Compile the model with relay - # ---------------------------- - - target = "llvm" - with tvm.transform.PassContext(opt_level=3): - relay_graph, relay_lib, relay_params = relay.build(mod, target=target, params=params) - - ###################################################################### - # Execute on TVM - # -------------- - - dev = tvm.device(target, 0) - relay_model = graph_executor.create(relay_graph, relay_lib, dev) - relay_model.set_input(**relay_params) - relay_model.set_input(input_1, tokens_tensor) - relay_model.set_input(input_2, segments_tensors) - relay_model.run() - compiled_output = relay_model.get_output(0).numpy() - - ###################################################################### - # Validate the outputs - # -------------------- - # Compare the torch and tvm outputs - - tvm.testing.assert_allclose(torch_preds, compiled_output, rtol=1e-3, atol=1e-3) - - ###################################################################### - # Process the output - # ------------------ - # Process the model output to token. - - # Torch output to token - torch_pred_idx = torch.argmax(torch_preds[0, masked_index]).item() - torch_pred_token = tokenizer.convert_ids_to_tokens([torch_pred_idx])[0] - - # TVM output to token - tvm_pred_idx = compiled_output[0, masked_index].argmax() - tvm_pred_token = tokenizer.convert_ids_to_tokens([tvm_pred_idx])[0] - - assert torch_pred_idx == tvm_pred_idx - assert torch_pred_token == tvm_pred_token - - # Print the outputs - print(f"Torch top-1 id: {torch_pred_idx}, token: {torch_pred_idx}") - print(f"TVM top-1 id: {tvm_pred_idx}, token: {tvm_pred_token}") - - -@pytest.mark.skipif( - platform.machine() == "aarch64", - reason="Currently failing on AArch64", -) -def test_convert_torch_script_with_input_types(): - """test_convert_torch_script_with_input_types""" - - def model_fn(x, y): - x = x.to(dtype=torch.int32) - y = x + y - return y - - ishape = (4, 5) - input_x = torch.rand(ishape, dtype=torch.float32) - input_y = torch.randint(low=0, high=100, size=ishape, dtype=torch.int32) - inputs = [input_x, input_y] - - verify_model(model_fn, input_data=inputs) - - -def test_bincount(): - """test_bincount""" - - def test_fn(x, weights=None): - return torch.bincount(x, weights=weights) - - inp = torch.randint(0, 100, (10000,), dtype=torch.int64) - weights = torch.linspace(0, 100, steps=10000) - - targets = ["llvm", "cuda"] - verify_trace_model(test_fn, [inp], targets) - verify_trace_model(test_fn, [inp, weights], targets) - - -def test_hard_swish(): - """test_hard_swish""" - examples = [torch.rand(8).float(), torch.rand(8, 10).float(), torch.rand(1, 1, 10).float()] - for input_data in examples: - verify_model(torch.nn.Hardswish().eval(), input_data=input_data) - verify_model(torch.nn.Hardswish(inplace=True).eval(), input_data=input_data) - - -def test_hard_sigmoid(): - """test_hard_sigmoid""" - examples = [torch.rand(8).float(), torch.rand(8, 10).float(), torch.rand(1, 1, 10).float()] - for input_data in examples: - verify_model(torch.nn.Hardsigmoid().eval(), input_data=input_data) - verify_model(torch.nn.Hardsigmoid(inplace=True).eval(), input_data=input_data) - - -def test_cumsum(): - """test_cumsum""" - - def test_fn(dim, dtype=None): - return lambda x: torch.cumsum(x, dim=dim, dtype=dtype) - - inp = torch.randint(0, 100, (10000,), dtype=torch.int32) - verify_model(test_fn(0), [inp]) - verify_model(test_fn(0), [inp.to(torch.int64)]) - verify_model(test_fn(0, dtype=torch.int64), [inp.to(torch.int64)]) - - inp = torch.randn((100, 100), dtype=torch.float32) - verify_model(test_fn(dim=0, dtype=torch.float64), [inp]) - verify_model(test_fn(dim=1), [inp]) - - inp = torch.randn((100, 100), dtype=torch.float32) > 0.5 - verify_model(test_fn(dim=0, dtype=torch.int32), [inp]) - - -def test_masked_fill(): - """test_transformer""" - - def test_fn(x, mask): - return torch.masked_fill(x, mask, 0.0) - - inp = torch.randn(100, 100) - verify_model(test_fn, [inp, inp > 0.5]) - verify_model(test_fn, [inp.to(torch.float64), inp > 0.5]) - - -def test_transformer(): - """test_transformer""" - model = torch.nn.Transformer(d_model=256, nhead=8, num_encoder_layers=6, num_decoder_layers=6) - model = model.eval() - src = torch.rand((10, 32, 256)) - tgt = torch.rand((20, 32, 256)) - verify_model(model.eval(), input_data=[src, tgt]) - - -def test_argsort(): - """test_argsort""" - - def test_fn(dim, descending): - return lambda x: torch.argsort(x, dim=dim, descending=descending) - - inp = torch.randn(100) - verify_model(test_fn(0, True), [inp]) - verify_model(test_fn(0, False), [inp]) - - inp = torch.randn(100, 100) - verify_model(test_fn(0, True), [inp]) - verify_model(test_fn(0, False), [inp]) - verify_model(test_fn(1, True), [inp]) - verify_model(test_fn(1, False), [inp]) - - -def test_sort(): - """test_sort""" - - def test_fn(dim, descending): - return lambda x: torch.sort(x, dim=dim, descending=descending) - - inp = torch.randn(100) - verify_model(test_fn(0, True), [inp]) - verify_model(test_fn(-1, False), [inp]) - - inp = torch.randn(100, 100) - verify_model(test_fn(0, True), [inp]) - verify_model(test_fn(-2, False), [inp]) - verify_model(test_fn(1, True), [inp]) - verify_model(test_fn(-1, False), [inp]) - - -def test_logical_and(): - """test_logical_and""" - - def test_fn(x, y): - return torch.logical_and(x, y) - - a = torch.tensor([0, 1, 10, 0], dtype=torch.int8) - b = torch.tensor([4, 0, 1, 0], dtype=torch.int8) - verify_model(test_fn, [a, b]) - - a = torch.tensor([True, False, True]) - b = torch.tensor([True, False, False]) - verify_model(test_fn, [a, b]) - - -def test_logical_or(): - """test_logical_or""" - - def test_fn(x, y): - return torch.logical_or(x, y) - - a = torch.tensor([0, 1, 10, 0], dtype=torch.int8) - b = torch.tensor([4, 0, 1, 0], dtype=torch.int8) - verify_model(test_fn, [a, b]) - - a = torch.tensor([True, False, True]) - b = torch.tensor([True, False, False]) - verify_model(test_fn, [a, b]) - - -def test_masked_select(): - """test_masked_select""" - - def test_fn(x, mask): - return torch.masked_select(x, mask) - - for shape in [(10,), (3, 4), (16, 32, 64)]: - x = torch.randn(*shape) - mask = x.ge(0.5) - verify_trace_model(test_fn, [x, mask], ["llvm", "cuda"]) - - -def test_unique(): - """test_unique""" - - def test_fn(is_sorted, return_inverse, return_counts): - return lambda x: torch.unique(x, is_sorted, return_inverse, return_counts) - - in_data = torch.randint(0, 20, (10,), dtype=torch.int32) - targets = ["llvm", "cuda"] - verify_trace_model(test_fn(True, True, True), [in_data], targets) - verify_trace_model(test_fn(True, False, True), [in_data], targets) - verify_trace_model(test_fn(True, True, False), [in_data], targets) - verify_trace_model(test_fn(True, False, True), [in_data], targets) - in_data = torch.randint(0, 20, (20,), dtype=torch.int64) - verify_trace_model(test_fn(True, True, True), [in_data], targets) - verify_trace_model(test_fn(True, False, True), [in_data], targets) - verify_trace_model(test_fn(True, True, False), [in_data], targets) - verify_trace_model(test_fn(True, False, True), [in_data], targets) - - -def test_forward_nll_loss(): - """test_forward_nll_loss""" - torch.set_grad_enabled(False) - N, C = 10, 3 - predictions = torch.rand((N, C)).float() - targets = torch.randint(0, 3, (N,)) - weights = torch.tensor([1, 2, 3]).float() - verify_model(torch.nn.NLLLoss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(weight=weights).eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(ignore_index=1).eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(reduction="none").eval(), input_data=[predictions, targets]) - - # multidimension nll loss (aten::nll_loss2d) - d1, d2 = 2, 3 - predictions = torch.rand((N, C, d1, d2)).float() - targets = torch.randint(0, 3, (N, d1, d2)) - verify_model(torch.nn.NLLLoss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(weight=weights).eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(ignore_index=1).eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.NLLLoss(reduction="none").eval(), input_data=[predictions, targets]) - - -def test_cross_entropy_loss(): - """test_cross_entropy_loss""" - torch.set_grad_enabled(False) - N, C = 10, 3 - # class indices - predictions = torch.rand((N, C)).float() - targets = torch.randint(0, 3, (N,)) - weights = torch.tensor([1, 2, 3]).float() - verify_model(torch.nn.CrossEntropyLoss().eval(), input_data=[predictions, targets]) - verify_model( - torch.nn.CrossEntropyLoss(weight=weights).eval(), input_data=[predictions, targets] - ) - - # class probabilities - predictions = torch.randn(N, C).float() - targets = torch.randn(N, C) - verify_model(torch.nn.CrossEntropyLoss().eval(), input_data=[predictions, targets]) - - -def test_forward_l1_loss(): - """test_forward_l1_loss""" - torch.set_grad_enabled(False) - N, C = 10, 3 - predictions = torch.rand((N, C)).float() - targets = torch.rand((N, C)).float() - verify_model(torch.nn.L1Loss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.L1Loss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.L1Loss(reduction="none").eval(), input_data=[predictions, targets]) - - # multidimension l1 loss - d1, d2 = 2, 3 - predictions = torch.rand((N, C, d1, d2)).float() - targets = torch.rand((N, C, d1, d2)).float() - verify_model(torch.nn.L1Loss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.L1Loss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.L1Loss(reduction="none").eval(), input_data=[predictions, targets]) - - -def test_forward_mse_loss(): - """test_forward_mse_loss""" - torch.set_grad_enabled(False) - N, C = 10, 3 - predictions = torch.rand((N, C)).float() - targets = torch.rand((N, C)).float() - verify_model(torch.nn.MSELoss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.MSELoss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.MSELoss(reduction="none").eval(), input_data=[predictions, targets]) - - # multidimension mse loss - d1, d2 = 2, 3 - predictions = torch.rand((N, C, d1, d2)).float() - targets = torch.rand((N, C, d1, d2)).float() - verify_model(torch.nn.MSELoss().eval(), input_data=[predictions, targets]) - verify_model(torch.nn.MSELoss(reduction="sum").eval(), input_data=[predictions, targets]) - verify_model(torch.nn.MSELoss(reduction="none").eval(), input_data=[predictions, targets]) - - -@tvm.testing.uses_gpu -def test_forward_flip(): - """Test for aten::flip""" - torch.set_grad_enabled(False) - - class Flip(Module): - def __init__(self, axis=0): - super().__init__() - self.axis = axis - - def forward(self, x): - return x.flip(self.axis) - - input_t = torch.randn(2, 3, 4) - verify_model(Flip(axis=[0]), input_data=input_t) - verify_model(Flip(axis=[1]), input_data=input_t) - verify_model(Flip(axis=[2]), input_data=input_t) - verify_model(Flip(axis=[-1]), input_data=input_t) - verify_model(Flip(axis=[0, 1]), input_data=input_t) - - -def test_annotate_span(): - """test_annotate_span""" - model = torchvision.models.resnet18().eval() - inp = torch.randn([1, 3, 224, 224]) - trace = torch.jit.trace(model, inp).eval() - mod, _ = relay.frontend.from_pytorch( - trace, [("input", inp.shape)], use_parser_friendly_name=True - ) - relay.transform.AnnotateSpans()(mod) - - -@tvm.testing.uses_gpu -def test_all_any(): - """test_all_any""" - - def test_fn(f, dim=None, keepdim=False): - return lambda x: f(x, dim=dim, keepdim=keepdim) - - def test_fn_no_arg(f): - return lambda x: f(x) # pylint: disable=unnecessary-lambda - - for f in [torch.all, torch.any]: - verify_model(test_fn(f, 0), [torch.rand(1, 2).bool()]) - verify_model(test_fn(f, 0), [torch.arange(0, 3).to(torch.uint8)]) - verify_model(test_fn(f, 1), [torch.rand(4, 2).bool()]) - verify_model(test_fn(f, 0, keepdim=True), [torch.rand(4, 2).bool()]) - verify_model(test_fn_no_arg(f), [torch.rand(1, 2).bool()]) - verify_model(test_fn_no_arg(f), [torch.arange(0, 3).to(torch.uint8)]) - - -@tvm.testing.uses_gpu -def test_searchsorted(): - """test_searchsorted""" - - def test_fn(out_int32=False, right=False): - return lambda x, y: torch.searchsorted(x, y, out_int32=out_int32, right=right) - - sorted_sequence = torch.tensor([[1, 3, 5, 7, 9], [2, 4, 6, 8, 10]]) - values = torch.tensor([[3, 6, 9], [3, 6, 9]]) - verify_model(test_fn(), [sorted_sequence, values]) - verify_model(test_fn(out_int32=True), [sorted_sequence[0], values[0]]) - verify_model(test_fn(right=True), [sorted_sequence, values]) - - sorted_sequence_1d = torch.tensor([1, 3, 5, 7, 9]) - values = torch.tensor([[3, 6, 9], [4, 2, 7]]) - verify_model(test_fn(), [sorted_sequence_1d, values]) - - verify_model(test_fn(), [sorted_sequence_1d, torch.tensor(6)]) - - -@tvm.testing.uses_gpu -def test_bucketize(): - """test_bucketize""" - - def test_fn(out_int32=False, right=False): - return lambda x, y: torch.bucketize(x, y, out_int32=out_int32, right=right) - - boundaries = torch.tensor([1, 3, 5, 7, 9]) - values = torch.tensor([3, 6, 9]) - - verify_model(test_fn(), [values, boundaries]) - verify_model(test_fn(out_int32=True, right=True), [values, boundaries]) - - -@tvm.testing.uses_gpu -def test_roll(): - """Test for aten::roll""" - - def test_fn(shifts, dims): - return lambda x: torch.roll(x, shifts, dims) - - x = torch.tensor([1, 2, 3, 4, 5, 6, 7, 8]).view(4, 2) - verify_model(test_fn(1, 0), [x]) - verify_model(test_fn(-1, 0), [x]) - verify_model(test_fn(shifts=(2, 1), dims=(0, 1)), [x]) - - -@tvm.testing.uses_gpu -def test_einsum(): - """test_einsum""" - - def test_fn(equation): - return lambda *x: torch.einsum(equation, *x) - - x = torch.ones([2, 3]) - y = torch.ones([3, 4]) - z = torch.ones([4, 5]) - verify_model(test_fn("ij,jk"), [x, y]) - verify_model(test_fn("ij,jk,km->im"), [x, y, z]) - - -def test_stft(): - """test_stft""" - - def test_fn(n_fft, hop_length, win_length, center, pad_mode, normalized, onesided): - return lambda input, window=None: torch.stft( - input=input, - n_fft=n_fft, - hop_length=hop_length, - win_length=win_length, - window=window, - center=center, - pad_mode=pad_mode, - normalized=normalized, - onesided=onesided, - return_complex=False, - ) - - input_t = torch.rand([1, 12]).float() - window = torch.tensor([2, 3, 4], dtype=torch.int32) - targets = ["llvm", "cuda"] - verify_trace_model(test_fn(3, 3, 3, False, "constant", False, True), [input_t, window], targets) - verify_trace_model(test_fn(3, 3, 3, True, "constant", False, True), [input_t, window], targets) - verify_trace_model(test_fn(3, 3, 3, False, "reflect", False, True), [input_t, window], targets) - verify_trace_model(test_fn(3, 3, 3, True, "reflect", False, True), [input_t, window], targets) - verify_trace_model(test_fn(3, 3, 3, True, "reflect", True, True), [input_t, window], targets) - verify_trace_model(test_fn(3, 3, 3, True, "reflect", False, False), [input_t, window], targets) - input_t = torch.rand([2, 12]).float() - window = torch.tensor([2, 3, 4], dtype=torch.int32) - verify_trace_model(test_fn(3, 3, 3, False, "reflect", False, True), [input_t, window], targets) - window = torch.tensor([1, 3], dtype=torch.int32) - verify_trace_model(test_fn(2, 1, 2, False, "reflect", False, True), [input_t, window], targets) - verify_trace_model(test_fn(2, 1, 2, False, "reflect", False, True), [input_t], targets) - - -@tvm.testing.uses_gpu -def test_dot(): - """Test for aten::dot""" - - def test_fn(x): - return x.dot(x) - - x = torch.randn([4]) - verify_model(test_fn, [x]) - - -@tvm.testing.uses_gpu -def test_mv(): - """Test for aten::mv""" - - def test_fn(m, v): - return m.mv(v) - - verify_model(test_fn, [torch.randn(4, 4), torch.randn(4)]) - verify_model(test_fn, [torch.randn(2, 2), torch.randn(2)]) - verify_model(test_fn, [torch.randn(3, 8), torch.randn(8)]) - - -def test_grid_sample(): - """test_grid_sample""" - - class Grid_sample(Module): - def __init__(self, method, padding_mode, align_corners): - super().__init__() - self._method = method - self._padding_mode = padding_mode - self._align_corners = align_corners - - def forward(self, x, y): - return torch.nn.functional.grid_sample( - input=x, - grid=y, - mode=self._method, - padding_mode=self._padding_mode, - align_corners=self._align_corners, - ) - - methods = ["nearest", "bilinear", "bicubic"] - padding_modes = ["zeros", "border", "reflection"] - align_corners = [True, False] - - data_2D = torch.rand([4, 4, 8, 8]).float() - grid_2D = torch.rand([4, 16, 16, 2]).float() - # choosing smaller sizes to be testable on weaker GPUs - data_3D = torch.rand([4, 4, 4, 4, 4]).float() - grid_3D = torch.rand([4, 8, 8, 8, 3]).float() - - for _method in methods: - # bicubic was introduced when pytorch > 1.7.1 - torch_version = package_version.parse(torch.__version__) - if _method == "bicubic" and torch_version <= package_version.parse("1.7.1"): - continue - for _padding in padding_modes: - for _align in align_corners: - # ATTENTION: - # "nearest" + "reflection" result may be different with pytorch on cpu device, - # because pytorch's cpu result is different with gpu result, - # and gpu result used here as baseline in tvm topi.image.grid_sample. - model = Grid_sample(_method, _padding, _align) - verify_model(model, input_data=[data_2D, grid_2D]) - - # 3D "bicubic"(tricubic) is not supported in pytorch - if _method != "bicubic": - verify_model(model, input_data=[data_3D, grid_3D]) - - -def test_list_tuple(): - """test compilation error for a Python list followed by a prim::TupleConstruct.""" - - class List_tuple(Module): - """List_tuple""" - - def forward(self, x): - """forward""" - merged = [] - mask_list = [] - for i in range(3): - w0 = torch.sigmoid(x) - merged.append((w0, w0)) - mask_list.append(x) - - for i in range(3): - merged[i] = merged[i][0] + merged[i][1] - return mask_list[2], merged - - x = torch.rand([4, 4, 16, 32]).float() - script_module = torch.jit.trace(List_tuple(), x, strict=False).eval() - relay.frontend.from_pytorch(script_module, [("x", x.shape)]) - - -# pylint: disable=unnecessary-dunder-call -@tvm.testing.uses_gpu -def test_binary_bitwise(): - """Test for binary bitwise""" - - def test_ior(x, y): - return x.__ior__(y) - - def test_iand(x, y): - return x.__iand__(y) - - def test_ixor(x, y): - return x.__ixor__(y) - - x = torch.tensor([7, 49, 16, 1, 2, 3], dtype=torch.uint8) - y = torch.tensor([39, 128, 99, 228, 63, 17], dtype=torch.uint8) - - for test_fn in [test_ior, test_iand, test_ixor]: - verify_model(test_fn, [x, y]) - - -@tvm.testing.uses_gpu -def test_shift(): - """Test for aten::__lshift__, aten::__rshift__""" - - def test_lshift(x, y): - return x << y - - def test_rshift(x, y): - return x >> y - - x = torch.tensor([39, 128, 99, 228, 63, 17], dtype=torch.int32) - y = torch.tensor([3, 2, 7, 4, 5, 9], dtype=torch.int32) - - for test_fn in [test_lshift, test_rshift]: - verify_model(test_fn, [x, y]) - - -@tvm.testing.uses_gpu -def test_mod(): - """Test for aten::fmod""" - - def test_fmod(x, y): - return torch.fmod(x, y) - - def test_remainder(x, y): - return torch.remainder(x, y) - - for test_fn in [test_fmod, test_remainder]: - verify_model(test_fn, [torch.tensor([-3.0, -2, -1, 1, 2, 3]), torch.tensor(2)]) - verify_model(test_fn, [torch.tensor([1, 2, 3, 4, 5]), torch.tensor(-1.5)]) - - -def test_softmax_fuse(): - """test_softmax_fuse""" - # https://github.com/apache/tvm/issues/12001 - class Model(torch.nn.Module): - """Pytorch model module""" - - def __init__(self, nchwc_post_op=False) -> None: - super().__init__() - self.conv = torch.nn.Conv2d(3, 3, (1, 1), 1) - self.nchwc_post_op = nchwc_post_op - - @torch.no_grad() - def forward(self, x): - """forward""" - t0a = self.conv(x) - t0b = torch.floor(x) - t2b = torch.softmax(t0a, dim=2) - - if self.nchwc_post_op: - t3a = t0a - t0b - t4a = t2b - t0b - t6a = t3a + t4a - return t6a - - return t2b + 1 - - sh = [3, 3, 10, 1] - inp = torch.ones(*sh, dtype=torch.float32) - - for model in [Model(nchwc_post_op=False).eval(), Model(nchwc_post_op=True).eval()]: - output_torch = model(inp).numpy() - - mod, params = relay.frontend.from_pytorch(torch.jit.trace(model, inp), [("inp0", sh)]) - - with tvm.transform.PassContext(opt_level=4): - out = ( - relay.create_executor("graph", mod, params=params) - .evaluate()(inp0=inp.numpy()) - .numpy() - ) - - tvm.testing.assert_allclose(out, output_torch, rtol=1e-5, atol=1e-5) - - -@tvm.testing.uses_gpu -def test_lerp(): - """test_lerp""" - - def test_fn(x, y, w): - return torch.lerp(x, y, w) - - input_shape = [16] - x = torch.rand(input_shape).float() - y = torch.rand(input_shape).float() - w = torch.rand(input_shape).float() - - # weight can be tensor or scalar - verify_model(test_fn, [x, y, w]) - verify_model(test_fn, [x, y, w[0]]) - - -def test_trilu(): - def _test_trilu(op, diagonal): - return lambda inp: op(inp, diagonal) - - for op in [torch.triu, torch.tril]: - verify_model(_test_trilu(op, 0), [torch.rand(size=[3, 3])]) - verify_model(_test_trilu(op, 1), [torch.rand(size=[6, 6])]) - verify_model(_test_trilu(op, -2), [torch.rand(size=[6, 6])]) - - -def test_multinomial(): - """test_multinomial""" - - def _test_multinomial(num_samples): - return lambda inp: torch.multinomial(inp, num_samples=num_samples, replacement=True) - - # Dont check output since it's random. Instead we'll just make sure shapes are right. - verify_model( - _test_multinomial(2), - [torch.rand(size=[3]).float()], - cpu_only=True, - check_correctness=False, - validate_structural_equal=False, - ) - verify_model( - _test_multinomial(1), - [torch.rand(size=[4, 5]).float()], - cpu_only=True, - check_correctness=False, - validate_structural_equal=False, - ) - - -def test_weight_norm(): - """Test for atten::_weight_norm""" - in_channels = 32 - out_channels = 64 - input_data_conv = torch.rand((1, in_channels, 32, 32)).float() - - conv_wn = torch.nn.utils.weight_norm(torch.nn.Conv2d(in_channels, out_channels, kernel_size=3)) - verify_model(conv_wn.eval().float(), input_data_conv) - - conv_wn_groups = torch.nn.utils.weight_norm( - torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, groups=2) - ) - verify_model(conv_wn_groups.eval().float(), input_data_conv) - - conv_wn = torch.nn.utils.weight_norm( - torch.nn.Conv2d(in_channels, out_channels, kernel_size=3), dim=1 - ) - verify_model(conv_wn.eval().float(), input_data_conv) - - linear_wn = torch.nn.utils.weight_norm(torch.nn.Linear(in_channels, out_channels)) - input_data_linear = torch.rand((128, in_channels)).float() - verify_model(linear_wn.eval().float(), input_data_linear) - - -@tvm.testing.uses_gpu -def test_addmm(): - def test_fn(alpha, beta): - return lambda inp, batch1, batch2: torch.addmm(inp, batch1, batch2, beta=beta, alpha=alpha) - - M = torch.randn(3, 5) - batch1 = torch.randn(3, 4) - batch2 = torch.randn(4, 5) - - verify_model(test_fn(0.4, 0.8), [M, batch1, batch2]) - - -@tvm.testing.uses_gpu -def test_baddbmm(): - def test_fn(alpha, beta): - return lambda inp, batch1, batch2: torch.baddbmm( - inp, batch1, batch2, beta=beta, alpha=alpha - ) - - M = torch.randn(10, 3, 5) - batch1 = torch.randn(10, 3, 4) - batch2 = torch.randn(10, 4, 5) - - verify_model(test_fn(0.5, 1.0), [M, batch1, batch2]) - - -def test_exporting_renamed_c_graph(): - """test exproting model when export_renamed_model is set""" - - # model definition - class Conv2D(Module): - def __init__(self): - super(Conv2D, self).__init__() - self.conv = torch.nn.Conv2d(3, 6, 3, bias=True) - - def forward(self, *args): - return self.conv(args[0]) - - input_name, input_shape = "input", [1, 3, 10, 10] - shape_list = [(input_name, input_shape)] - temp_dir = utils.tempdir().path - script_module = torch.jit.trace(Conv2D(), [torch.rand(input_shape)]) - _, _ = relay.frontend.from_pytorch( - script_module, shape_list, export_renamed_c_graph_path=temp_dir - ) - - exported_c_graph_name = os.listdir(temp_dir)[0] - assert "tvm_exported_c_graph_" in exported_c_graph_name - - # make sure the renamed output variable presents in the restored _C.Graph - with open(f"{temp_dir}/{exported_c_graph_name}", "r") as f: - graph = f.read() - assert "%aten::_convolution_0" in graph - - -def test_inplace_copy(): - class SimpleInplaceCopy(torch.nn.Module): - def forward(self, x): - x[:5, 0, 5:] = x[:5, 0, 5:] + 1 - return x - - class NegativeSliceInplaceCopy(torch.nn.Module): - def forward(self, x): - x[5:-1, -1, :] = x[5:-1, -1, :] + 1 - return x - - class PartialDimensionInplaceCopy(torch.nn.Module): - def forward(self, x): - x[:5] = x[:5] + 1 - x[0:5, ...] = x[0:5, ...] + 1 - x[0:5, ..., -1] = x[0:5, ..., -1] + 1 - return x - - inputs = torch.randn(10, 10, 10) - verify_model(SimpleInplaceCopy(), [inputs]) - inputs = torch.randn(10, 10, 10) - verify_model(NegativeSliceInplaceCopy(), [inputs]) - inputs = torch.randn(10, 10, 10) - verify_model(PartialDimensionInplaceCopy(), [inputs]) - - -@tvm.testing.uses_gpu -def test_swapaxes(): - """test_swapaxes""" - torch.set_grad_enabled(False) - input_shape = [2, 3, 10, 5] - - class Swapaxes1(Module): - def forward(self, *args): - return args[0].swapaxes(2, 3) - - class Swapaxes2(Module): - def forward(self, *args): - return args[0].swapaxes(-2, -1) - - class Swapaxes3(Module): - def forward(self, *args): - return args[0].swapaxes(1, 1) - - input_data = torch.rand(input_shape).float() - verify_model(Swapaxes1().float().eval(), input_data=input_data) - verify_model(Swapaxes2().float().eval(), input_data=input_data) - verify_model(Swapaxes3().float().eval(), input_data=input_data) - - -def test_linalg_vector_norm(): - """test_linalg_vector_norm""" - torch.set_grad_enabled(False) - - def test_fn(order): - return lambda x: torch.linalg.vector_norm(x, ord=order) - - input_shape = [3, 3] - - input_data = torch.rand(input_shape).float() - verify_model(test_fn(order=2), input_data=input_data) - verify_model(test_fn(order=3.5), input_data=input_data) - verify_model(test_fn(order=np.inf), input_data=input_data) - verify_model(test_fn(order=-np.inf), input_data=input_data) - verify_model(test_fn(order=0), input_data=input_data) - - # Also test on double - input_data = torch.rand(input_shape).double() - verify_model(test_fn(order=2), input_data=input_data) - verify_model(test_fn(order=3.5), input_data=input_data) - verify_model(test_fn(order=np.inf), input_data=input_data) - verify_model(test_fn(order=-np.inf), input_data=input_data) - verify_model(test_fn(order=0), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_scaled_dot_product_attention(): - """test_scaled_dot_product_attention""" - torch.set_grad_enabled(False) - - def test_fn(attn_mask=None, is_causal=False): - return lambda query, key, value: torch.nn.functional.scaled_dot_product_attention( - query, key, value, attn_mask=attn_mask, is_causal=is_causal - ) - - L, S, E, Ev = 5, 7, 11, 13 - query_4d = torch.randn(2, 3, L, E) - query_3d = torch.randn(3, L, E) - key_4d = torch.randn(2, 3, S, E) - key_3d = torch.randn(3, S, E) - value_4d = torch.randn(2, 3, S, Ev) - value_3d = torch.randn(3, S, Ev) - - verify_model(test_fn(), [query_4d, key_4d, value_4d]) - verify_model(test_fn(), [query_4d, key_4d, value_3d]) - verify_model(test_fn(), [query_4d, key_3d, value_4d]) - verify_model(test_fn(), [query_4d, key_3d, value_3d]) - verify_model(test_fn(), [query_3d, key_4d, value_4d]) - verify_model(test_fn(), [query_3d, key_4d, value_3d]) - verify_model(test_fn(), [query_3d, key_3d, value_4d]) - verify_model(test_fn(), [query_3d, key_3d, value_3d]) - - verify_model(test_fn(is_causal=True), [query_4d, key_4d, value_4d]) - verify_model(test_fn(is_causal=True), [query_4d, key_4d, value_3d]) - verify_model(test_fn(is_causal=True), [query_4d, key_3d, value_4d]) - verify_model(test_fn(is_causal=True), [query_4d, key_3d, value_3d]) - verify_model(test_fn(is_causal=True), [query_3d, key_4d, value_4d]) - verify_model(test_fn(is_causal=True), [query_3d, key_4d, value_3d]) - verify_model(test_fn(is_causal=True), [query_3d, key_3d, value_4d]) - verify_model(test_fn(is_causal=True), [query_3d, key_3d, value_3d]) - - # Test with explicit attn_mask - attn_mask = torch.ones((L, S), dtype=torch.bool).tril(diagonal=0) - if torch.cuda.is_available(): - attn_mask = attn_mask.cuda() - verify_model(test_fn(attn_mask=attn_mask), [query_4d, key_4d, value_4d]) - verify_model(test_fn(attn_mask=attn_mask), [query_4d, key_4d, value_3d]) - verify_model(test_fn(attn_mask=attn_mask), [query_4d, key_3d, value_4d]) - verify_model(test_fn(attn_mask=attn_mask), [query_4d, key_3d, value_3d]) - verify_model(test_fn(attn_mask=attn_mask), [query_3d, key_4d, value_4d]) - verify_model(test_fn(attn_mask=attn_mask), [query_3d, key_4d, value_3d]) - verify_model(test_fn(attn_mask=attn_mask), [query_3d, key_3d, value_4d]) - verify_model(test_fn(attn_mask=attn_mask), [query_3d, key_3d, value_3d]) - - # Test with float64 - query_4d = torch.randn(2, 3, L, E, dtype=torch.float64) - query_3d = torch.randn(3, L, E, dtype=torch.float64) - key_4d = torch.randn(2, 3, S, E, dtype=torch.float64) - key_3d = torch.randn(3, S, E, dtype=torch.float64) - value_4d = torch.randn(2, 3, S, Ev, dtype=torch.float64) - value_3d = torch.randn(3, S, Ev, dtype=torch.float64) - verify_model(test_fn(), [query_4d, key_4d, value_4d]) - verify_model(test_fn(), [query_4d, key_4d, value_3d]) - verify_model(test_fn(), [query_4d, key_3d, value_4d]) - verify_model(test_fn(), [query_4d, key_3d, value_3d]) - verify_model(test_fn(), [query_3d, key_4d, value_4d]) - verify_model(test_fn(), [query_3d, key_4d, value_3d]) - verify_model(test_fn(), [query_3d, key_3d, value_4d]) - verify_model(test_fn(), [query_3d, key_3d, value_3d]) - - # Test with larger tensors - L, S, E, Ev = 128, 128, 64, 64 - query_4d = torch.randn(32, 8, L, E) - query_3d = torch.randn(8, L, E) - key_4d = torch.randn(32, 8, S, E) - key_3d = torch.randn(8, S, E) - value_4d = torch.randn(32, 8, S, Ev) - value_3d = torch.randn(8, S, Ev) - verify_model(test_fn(), [query_4d, key_4d, value_4d]) - verify_model(test_fn(), [query_4d, key_4d, value_3d]) - verify_model(test_fn(), [query_4d, key_3d, value_4d]) - verify_model(test_fn(), [query_4d, key_3d, value_3d]) - verify_model(test_fn(), [query_3d, key_4d, value_4d]) - verify_model(test_fn(), [query_3d, key_4d, value_3d]) - verify_model(test_fn(), [query_3d, key_3d, value_4d]) - verify_model(test_fn(), [query_3d, key_3d, value_3d]) - - -def test_parameterlist(): - """test_parameterlist""" - torch.set_grad_enabled(False) - - class ParamListModel(torch.nn.Module): - def __init__(self, num_layer=2): - super().__init__() - self.biases = torch.nn.ParameterList([torch.randn(10)] * num_layer) - self.weights = torch.nn.ParameterList([torch.randn(10, 10)] * num_layer) - - def forward(self, x): - for i in range(len(self.weights) - 1): - x = torch.addmm(self.biases[i], x, self.weights[i]) - return torch.addmm(self.biases[-1], x, self.weights[-1]) - - input_data = torch.randn(20, 10) - verify_model(ParamListModel().float().eval(), input_data=input_data) - - -@tvm.testing.uses_gpu -def test_forward_tile(): - """test_forward_repeat""" - torch.set_grad_enabled(False) - input_shape = [1, 3] - - class Tile1(Module): - def forward(self, *args): - return args[0].tile(1, 1) - - class Tile2(Module): - def forward(self, *args): - return args[0].tile(4, 2) - - class Tile3(Module): - def forward(self, *args): - return args[0].tile(4, 2, 1) - - input_data = torch.rand(input_shape).float() - verify_model(Tile1().float().eval(), input_data=input_data) - verify_model(Tile2().float().eval(), input_data=input_data) - verify_model(Tile3().float().eval(), input_data=input_data) - - -class TestSetSpan: - """test structural equal between translated / hand-crafted relay IR with span tagged.""" - - def _verify(self, res_fptr, golden_fptr): - with tvm.testing.enable_span_filling(): - with_span = res_fptr() - with tvm.testing.disable_span_filling(): - without_span = res_fptr() - tvm.ir.assert_structural_equal(with_span, without_span) - _verify_structural_equal_with_span(with_span, golden_fptr()) - - def test_conv2d_bias_add(self): - ker_sz, in_chs, out_chs = 7, 3, 6 - input_shape = [1, 3, 10, 10] - - def _res(): - # model definition - class Conv2D(Module): - def __init__(self): - super(Conv2D, self).__init__() - self.conv = torch.nn.Conv2d(in_chs, out_chs, ker_sz, bias=True) - - def forward(self, *args): - return self.conv(args[0]) - - # get frontend model - mod = gen_ir_module(Conv2D(), [torch.rand(input_shape)]) - return mod["main"] - - def _golden(): - conv_si = "aten::_convolution_0" - input_name = "input0" - input_0 = relay.var( - input_name, - shape=tuple(input_shape), - span=_create_span(f"{conv_si}.{input_name}"), - ) - weight_name = f"{conv_si}.weight" - conv_weight = relay.var( - weight_name, - shape=(out_chs, in_chs, ker_sz, ker_sz), - span=_create_span(weight_name), - ) - bias_name = f"{conv_si}.bias" - conv_bias = relay.var( - bias_name, - shape=(out_chs,), - span=_create_span(bias_name), - ) - conv_out = _set_span( - relay.nn.conv2d( - input_0, - conv_weight, - padding=[0] * 4, - channels=out_chs, - kernel_size=[ker_sz] * 2, - ), - conv_si, - ) - bias_out = _set_span(relay.nn.bias_add(conv_out, conv_bias), conv_si) - return relay.Function([input_0, conv_weight, conv_bias], bias_out) - - self._verify(_res, _golden) - - def test_batchnorm_span(self): - features = 16 - input_shape = [1, 16, 10, 10] - - def _res(): - # model definition - bn_2d = torch.nn.BatchNorm2d(features) - - # get frontend model - mod = gen_ir_module(bn_2d, [torch.rand(input_shape)]) - return mod["main"] - - def _golden(): - bn_si = "aten::batch_norm_0" - input_name = "input0" - input_0 = relay.var( - input_name, - shape=tuple(input_shape), - span=_create_span(f"{bn_si}.{input_name}"), - ) - weight_name = f"{bn_si}.weight" - bn_weight = relay.var( - weight_name, - shape=(features,), - span=_create_span(weight_name), - ) - bias_name = f"{bn_si}.bias" - bn_bias = relay.var( - bias_name, - shape=(features,), - span=_create_span(bias_name), - ) - rm_name = f"{bn_si}.running_mean" - bn_rm = relay.var( - rm_name, - shape=(features,), - span=_create_span(rm_name), - ) - rv_name = f"{bn_si}.running_var" - bn_rv = relay.var( - rv_name, - shape=(features,), - span=_create_span(rv_name), - ) - bn_out = _set_span( - relay.nn.batch_norm(input_0, bn_weight, bn_bias, bn_rm, bn_rv), - bn_si, - ) - bn_tuple_get_item = _set_span(relay.TupleGetItem(bn_out.tuple_value, 0), bn_si) - return relay.Function([input_0, bn_weight, bn_bias, bn_rm, bn_rv], bn_tuple_get_item) - - self._verify(_res, _golden) - - def test_reshape_span(self): - input_shape = [2, 1, 10, 1, 10] - new_shape = [2, 1, 10, 10] - - def _res(): - # model definition - class Reshape(Module): - def forward(self, *args): - return args[0].reshape(new_shape) - - # get frontend model - mod = gen_ir_module(Reshape(), [torch.rand(input_shape)]) - return mod["main"] - - def _golden(): - reshape_si = "aten::reshape_0" - input_name = "input0" - input_0 = relay.var( - input_name, - shape=tuple(input_shape), - span=_create_span(f"{reshape_si}.{input_name}"), - ) - reshape_out = _set_span( - relay.reshape(input_0, newshape=new_shape), - reshape_si, - ) - return relay.Function([input_0], reshape_out) - - self._verify(_res, _golden) - - def test_dense_bias_add(self): - in_f, out_f = 10, 7 - input_shape = [in_f, in_f] - - def _res(): - # model definition - class Dense(Module): - def __init__(self): - super(Dense, self).__init__() - self.linear = torch.nn.Linear(in_f, out_f, bias=True) - - def forward(self, *args): - return self.linear(args[0]) - - # get frontend model - mod = gen_ir_module(Dense(), [torch.rand(input_shape)]) - return mod["main"] - - def _golden(): - dense_si = "aten::linear_0" - input_name = "input0" - input_0 = relay.var( - input_name, - shape=tuple(input_shape), - span=_create_span(f"{dense_si}.{input_name}"), - ) - weight_name = f"{dense_si}.weight" - dense_weight = relay.var( - weight_name, - shape=(out_f, in_f), - span=_create_span(weight_name), - ) - bias_name = f"{dense_si}.bias" - dense_bias = relay.var( - bias_name, - shape=(out_f,), - span=_create_span(bias_name), - ) - dense_out = _set_span( - relay.nn.dense(input_0, dense_weight), - dense_si, - ) - bias_out = _set_span( - relay.nn.bias_add(dense_out, dense_bias, axis=-1), - dense_si, - ) - return relay.Function([input_0, dense_weight, dense_bias], bias_out) - - self._verify(_res, _golden) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/pytorch/test_fx_quant.py b/tests/python/frontend/pytorch/test_fx_quant.py deleted file mode 100644 index 8ed6e1a74797..000000000000 --- a/tests/python/frontend/pytorch/test_fx_quant.py +++ /dev/null @@ -1,95 +0,0 @@ -# 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. -""" Tests on fx-quantized torch model conversion """ -import torch -import torchvision -import pytest -import numpy as np -from torch.quantization import get_default_qconfig -from torch.quantization.quantize_fx import prepare_fx, convert_fx -from torchvision.models.efficientnet import efficientnet_b4 -from torchvision.models.resnet import resnet50 -from tvm import relay -import tvm.testing - - -def quantize(model, example_inputs): - qconfig = get_default_qconfig("fbgemm") - qconfig_dict = {"": qconfig} - return convert_fx(prepare_fx(model, qconfig_dict, example_inputs)) - - -def quantize_and_build(model, in_size): - inp = torch.rand(1, 3, in_size, in_size) - input_name = "inp" - qmodel = quantize(model, inp) - - with torch.no_grad(): - script_module = torch.jit.trace(qmodel, inp) - with tvm.testing.disable_span_filling(): - mod, _ = relay.frontend.from_pytorch(script_module, [(input_name, inp.shape)]) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(script_module, [(input_name, inp.shape)]) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - mod = relay.transform.InferType()(mod) - - # Make sure that the model is quantized - assert "qnn.conv2d" in mod.astext(show_meta_data=False) - - # Skip building since it is slow on CI - # relay.build(mod, params=params, target="llvm") - - -@pytest.mark.skip(reason="unsupported op aten::linalg_vector_norm") -def test_ssd_vgg(): - class TraceWrapper(torch.nn.Module): - def __init__(self, model): - super().__init__() - self.model = model - - def forward(self, inp): - features = self.model.backbone(inp) - features = list(features.values()) - out = self.model.head(features) - return out["bbox_regression"], out["cls_logits"] - - model_func = torchvision.models.detection.ssd300_vgg16 - model = TraceWrapper(model_func(num_classes=50, pretrained_backbone=True)).eval() - quantize_and_build(model, 300) - - -def test_deeplab_v3(): - class TraceWrapper(torch.nn.Module): - def __init__(self, model): - super().__init__() - self.model = model - - def forward(self, inp): - out = self.model(inp) - return out["out"] - - deeplabv3 = torchvision.models.segmentation.deeplabv3_mobilenet_v3_large(pretrained=True) - model = TraceWrapper(deeplabv3.eval()).eval() - quantize_and_build(model, 300) - - -@pytest.mark.skip( - reason="Model binary isn't uploaded to S3. See https://github.com/apache/tvm/pull/17397" -) -def test_imagenet(): - for model_func in [resnet50, efficientnet_b4]: - quantize_and_build(model_func(pretrained=True).eval(), 224) diff --git a/tests/python/frontend/pytorch/test_lstm.py b/tests/python/frontend/pytorch/test_lstm.py deleted file mode 100644 index da4e1ae96e03..000000000000 --- a/tests/python/frontend/pytorch/test_lstm.py +++ /dev/null @@ -1,372 +0,0 @@ -# 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. -""" Tests on torch lstm model conversion """ -# originally from https://github.com/pytorch/pytorch/blob/master/benchmarks/fastrnns/custom_lstms.py -# described in https://pytorch.org/blog/optimizing-cuda-rnn-with-torchscript/ -import numpy as np -import torch -import torch.nn as nn -from torch.nn import Parameter -import torch.jit as jit -from typing import List, Tuple -from torch import Tensor - -import tvm -import tvm.testing -from tvm import relay -from tvm.relay.frontend.pytorch import from_pytorch -from tvm.relay.prelude import Prelude -from tvm.runtime.container import ADT, tuple_object - - -class LayerNormLSTMCell(jit.ScriptModule): - def __init__(self, input_size, hidden_size): - super().__init__() - self.input_size = input_size - self.hidden_size = hidden_size - self.weight_ih = Parameter(torch.randn(4 * hidden_size, input_size)) - self.weight_hh = Parameter(torch.randn(4 * hidden_size, hidden_size)) - - ln = nn.LayerNorm - - self.layernorm_i = ln(4 * hidden_size) - self.layernorm_h = ln(4 * hidden_size) - self.layernorm_c = ln(hidden_size) - - @jit.script_method - def forward(self, input, state): - # type: (Tensor, Tuple[Tensor, Tensor]) -> Tuple[Tensor, Tuple[Tensor, Tensor]] - hx, cx = state - igates = self.layernorm_i(torch.mm(input, self.weight_ih.t())) - hgates = self.layernorm_h(torch.mm(hx, self.weight_hh.t())) - gates = igates + hgates - ingate, forgetgate, cellgate, outgate = gates.chunk(4, 1) - - ingate = torch.sigmoid(ingate) - forgetgate = torch.sigmoid(forgetgate) - cellgate = torch.tanh(cellgate) - outgate = torch.sigmoid(outgate) - - cy = self.layernorm_c((forgetgate * cx) + (ingate * cellgate)) - hy = outgate * torch.tanh(cy) - - return hy, (hy, cy) - - -class LSTMLayer(jit.ScriptModule): - def __init__(self, cell, *cell_args): - super().__init__() - self.cell = cell(*cell_args) - - @jit.script_method - def forward(self, input, state): - # type: (Tensor, Tuple[Tensor, Tensor]) -> Tuple[Tensor, Tuple[Tensor, Tensor]] - outputs = [] - for i in range(input.size(0)): - out, state = self.cell(input[i], state) - outputs += [out] - return torch.stack(outputs), state - - -class ReverseLSTMLayer(jit.ScriptModule): - def __init__(self, cell, *cell_args): - super(ReverseLSTMLayer, self).__init__() - self.cell = cell(*cell_args) - - @jit.script_method - def forward(self, inputs, state): - # type: (Tensor, Tuple[Tensor, Tensor]) -> Tuple[Tensor, Tuple[Tensor, Tensor]] - outputs = jit.annotate(List[Tensor], []) - seq_len = inputs.size(0) - for i in range(seq_len): - out, state = self.cell(inputs[seq_len - i - 1], state) - # workaround for the lack of list rev support - outputs = [out] + outputs - return torch.stack(outputs), state - - -class BidirLSTMLayer(jit.ScriptModule): - __constants__ = ["directions"] - - def __init__(self, cell, *cell_args): - super(BidirLSTMLayer, self).__init__() - self.directions = nn.ModuleList( - [ - LSTMLayer(cell, *cell_args), - ReverseLSTMLayer(cell, *cell_args), - ] - ) - - @jit.script_method - def forward(self, input, states): - # type: (Tensor, List[Tuple[Tensor, Tensor]]) -> Tuple[Tensor, List[Tuple[Tensor, Tensor]]] - # List[LSTMState]: [forward LSTMState, backward LSTMState] - outputs = jit.annotate(List[Tensor], []) - output_states = jit.annotate(List[Tuple[Tensor, Tensor]], []) - for (i, direction) in enumerate(self.directions): - state = states[i] - out, out_state = direction(input, state) - outputs += [out] - output_states += [out_state] - # tensor array concat assumes axis == 0 for now - # return torch.cat(outputs, -1), output_states - return torch.cat(outputs, 0), output_states - - -def init_stacked_lstm(num_layers, layer, first_layer_args, other_layer_args): - layers = [layer(*first_layer_args)] + [layer(*other_layer_args) for _ in range(num_layers - 1)] - return nn.ModuleList(layers) - - -class StackedLSTM(jit.ScriptModule): - __constants__ = ["layers"] # Necessary for iterating through self.layers - - def __init__(self, num_layers, layer, first_layer_args, other_layer_args): - super().__init__() - self.layers = init_stacked_lstm(num_layers, layer, first_layer_args, other_layer_args) - - @jit.script_method - def forward(self, input, states): - # type: (Tensor, List[Tuple[Tensor, Tensor]]) -> Tuple[Tensor, List[Tuple[Tensor, Tensor]]] - # List[LSTMState]: One state per layer - output_states = jit.annotate(List[Tuple[Tensor, Tensor]], []) - output = input - for (i, rnn_layer) in enumerate(self.layers): - state = states[i] - output, out_state = rnn_layer(output, state) - output_states += [out_state] - return output, output_states - - -class StackedBidirLSTM(jit.ScriptModule): - __constants__ = ["layers"] # Necessary for iterating through self.layers - - def __init__(self, num_layers, layer, first_layer_args, other_layer_args): - super(StackedBidirLSTM, self).__init__() - self.layers = init_stacked_lstm(num_layers, layer, first_layer_args, other_layer_args) - - @jit.script_method - def forward(self, input, states): - # type: (Tensor, List[List[Tuple[Tensor, Tensor]]]) -> Tuple[Tensor, List[List[Tuple[Tensor, Tensor]]]] - # List[List[LSTMState]]: The outer list is for layers, - # inner list is for directions. - output_states = jit.annotate(List[List[Tuple[Tensor, Tensor]]], []) - output = input - for (i, rnn_layer) in enumerate(self.layers): - state = states[i] - output, out_state = rnn_layer(output, state) - output_states += [out_state] - return output, output_states - - -def lstm(input_size, hidden_size): - return LSTMLayer(LayerNormLSTMCell, input_size, hidden_size) - - -def stacked_lstm(input_size, hidden_size, num_layers): - return StackedLSTM( - num_layers, - LSTMLayer, - first_layer_args=[LayerNormLSTMCell, input_size, hidden_size], - other_layer_args=[LayerNormLSTMCell, hidden_size, hidden_size], - ) - - -def bidir_lstm(input_size, hidden_size): - return BidirLSTMLayer(LayerNormLSTMCell, input_size, hidden_size) - - -def stacked_bidir_lstm(input_size, hidden_size, num_layers): - return StackedBidirLSTM( - num_layers, - BidirLSTMLayer, - first_layer_args=[LayerNormLSTMCell, input_size, hidden_size], - other_layer_args=[LayerNormLSTMCell, hidden_size, hidden_size], - ) - - -def vmobj_to_list(o, dtype="float32"): - if isinstance(o, tvm.nd.NDArray): - return [o] - elif isinstance(o, tvm.runtime.container.ADT): - result = [] - for f in o: - result.extend(vmobj_to_list(f, dtype)) - return result - else: - raise RuntimeError("Unknown object type: %s" % type(o)) - - -def assert_equal(tvm_result, torch_result): - if isinstance(torch_result, (tuple, list)): - assert isinstance(tvm_result, list) - for tvm_res, pt_res in zip(tvm_result, torch_result): - assert_equal(tvm_res, pt_res) - elif isinstance(torch_result, torch.Tensor): - tvm.testing.assert_allclose(tvm_result.numpy(), torch_result.numpy(), rtol=1e-4, atol=1e-4) - - -def run_and_compare(mod, params, pt_result, target, device): - exec_res = relay.create_executor("vm", mod=mod, device=device, target=target).evaluate()( - **params - ) - - def flatten(nested): - res = [] - for r in nested: - if isinstance(r, torch.Tensor): - res.append(r) - else: - res.extend(flatten(r)) - return res - - if isinstance(exec_res, tvm.runtime.container.ADT): - assert not isinstance(pt_result, torch.Tensor) - tvm_res = vmobj_to_list(exec_res) - torch_res = flatten(pt_result) - else: - tvm_res = exec_res - torch_res = pt_result - - assert_equal(tvm_res, torch_res) - - -def convert_list_to_vmobj(py_lst): - def wrap_nd_array(arr): - return tvm.nd.array(arr, device=tvm.cpu(0)) - - mod = tvm.IRModule() - prelude = Prelude(mod) - list, cons, nil = mod.get_type("List") - adt_lst = ADT(nil.tag, []) - for elem in reversed(py_lst): - if isinstance(elem, np.ndarray): - vmobj = wrap_nd_array(elem) - elif isinstance(elem, tuple): - vmobj = tuple_object([wrap_nd_array(e) for e in elem]) - elif isinstance(elem, list): - vmobj = convert_list_to_vmobj(elem) - adt_lst = ADT(cons.tag, [vmobj, adt_lst]) - return adt_lst - - -@tvm.testing.uses_gpu -def test_custom_lstm(): - input_name = "input" - states_name = "states" - seq_len = 5 - batch = 2 - input_size = 3 - hidden_size = 4 - num_layers = 3 - state_tensor_shape = (batch, hidden_size) - - torch.manual_seed(1) - - inp = torch.randn(seq_len, batch, input_size) - - input_shapes = [ - (input_name, (seq_len, batch, input_size)), - (states_name, (state_tensor_shape, state_tensor_shape)), - ] - - input_shapes_stacked = [ - (input_name, (seq_len, batch, input_size)), - ( - states_name, - [(state_tensor_shape, state_tensor_shape), (state_tensor_shape, state_tensor_shape)], - ), - ] - - input_shapes_stacked_bidir = [ - (input_name, (seq_len, batch, input_size)), - ( - states_name, - [ - [(state_tensor_shape, state_tensor_shape) for _ in range(2)] - for _ in range(num_layers) - ], - ), - ] - - states = [ - (torch.randn(state_tensor_shape), torch.randn(state_tensor_shape)) - for _ in range(num_layers) - ] - - bidir_states = [ - (torch.randn(state_tensor_shape), torch.randn(state_tensor_shape)) for _ in range(2) - ] - - stacked_bidir_states = [ - [(torch.randn(state_tensor_shape), torch.randn(state_tensor_shape)) for _ in range(2)] - for _ in range(num_layers) - ] - - models = [ - ("lstm", lstm(input_size, hidden_size).eval(), states[0], input_shapes), - ( - "stacked", - stacked_lstm(input_size, hidden_size, num_layers).eval(), - states, - input_shapes_stacked, - ), - ("bidir", bidir_lstm(input_size, hidden_size).eval(), bidir_states, input_shapes_stacked), - # TODO(masahi): stacked bidir seems to have a rare accuracy issue - # ( - # "stacked_bidir", - # stacked_bidir_lstm(input_size, hidden_size, num_layers).eval(), - # stacked_bidir_states, - # input_shapes_stacked_bidir, - # ), - ] - - for (name, raw_model, states, input_shapes) in models: - script_module = torch.jit.script(raw_model) - with tvm.testing.disable_span_filling(): - mod, params = from_pytorch(script_module, input_shapes) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = from_pytorch(script_module, input_shapes) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - with torch.no_grad(): - pt_result = raw_model(inp.clone(), states) - - params[input_name] = inp.numpy() - - if isinstance(states, tuple): - states_np = tuple(st.numpy() for st in states) - elif isinstance(states, list) and isinstance(states[0], torch.Tensor): - states_np = [st.numpy() for st in states] - elif isinstance(states, list) and isinstance(states[0], tuple): - states_np = [tuple(st.numpy() for st in states[i]) for i in range(len(states))] - elif isinstance(states, list) and isinstance(states[0], list): - states_np = [ - [tuple(st.numpy() for st in states) for states in states[layer]] - for layer in range(num_layers) - ] - else: - assert False - - if isinstance(states_np, list): - params[states_name] = convert_list_to_vmobj(states_np) - else: - params[states_name] = states_np - - for tgt, dev in tvm.testing.enabled_targets(): - print("Running %s on target %s" % (name, tgt)) - run_and_compare(mod, params, pt_result, target=tgt, device=dev) diff --git a/tests/python/frontend/pytorch/test_object_detection.py b/tests/python/frontend/pytorch/test_object_detection.py deleted file mode 100644 index 9dd336f7e9d2..000000000000 --- a/tests/python/frontend/pytorch/test_object_detection.py +++ /dev/null @@ -1,167 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument -"""Test torch vision fasterrcnn and maskrcnn models""" -import numpy as np -import cv2 - -import torch -import torchvision - -import tvm - -import tvm.testing -from tvm import relay -from tvm.runtime.vm import VirtualMachine -from tvm.relay.frontend.pytorch_utils import ( - rewrite_nms_to_batched_nms, - rewrite_batched_nms_with_max_out_size, - rewrite_scatter_to_gather, -) -from tvm.contrib.download import download - -in_size = 300 - - -def process_image(img): - img = cv2.imread(img).astype("float32") - img = cv2.resize(img, (in_size, in_size)) - img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) - img = torch.from_numpy(img / 255.0).permute(2, 0, 1).float() - img = torch.unsqueeze(img, axis=0) - - return img - - -def do_trace(model, inp, in_size=in_size): - model_trace = torch.jit.trace(model, inp) - model_trace.eval() - return model_trace - - -def dict_to_tuple(out_dict): - if "masks" in out_dict.keys(): - return out_dict["boxes"], out_dict["scores"], out_dict["labels"], out_dict["masks"] - return out_dict["boxes"], out_dict["scores"], out_dict["labels"] - - -class TraceWrapper(torch.nn.Module): - def __init__(self, model): - super().__init__() - self.model = model - - def forward(self, inp): - out = self.model(inp) - return dict_to_tuple(out[0]) - - -def generate_jit_model(index): - model_funcs = [ - torchvision.models.detection.fasterrcnn_resnet50_fpn, - torchvision.models.detection.maskrcnn_resnet50_fpn, - ] - - model_func = model_funcs[index] - model = TraceWrapper(model_func(pretrained=True, rpn_pre_nms_top_n_test=1000)) - - model.eval() - inp = torch.Tensor(np.random.uniform(0.0, 250.0, size=(1, 3, in_size, in_size))) - - with torch.no_grad(): - out = model(inp) - - script_module = do_trace(model, inp) - script_out = script_module(inp) - - assert len(out[0]) > 0 and len(script_out[0]) > 0 - return script_module - - -def test_detection_models(): - img = "test_street_small.jpg" - img_url = ( - "https://raw.githubusercontent.com/dmlc/web-data/master/gluoncv/detection/street_small.jpg" - ) - download(img_url, img) - - input_shape = (1, 3, in_size, in_size) - - input_name = "input0" - shape_list = [(input_name, input_shape)] - - scripted_model = generate_jit_model(1) - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch(scripted_model, shape_list) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch(scripted_model, shape_list) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - data = process_image(img) - data_np = data.detach().numpy() - - with torch.no_grad(): - pt_res = scripted_model(data) - - def compile_and_run_vm(mod, params, data_np, target): - with tvm.transform.PassContext(opt_level=3): - vm_exec = relay.vm.compile(mod, target=target, params=params) - - dev = tvm.device(target, 0) - vm = VirtualMachine(vm_exec, dev) - vm.set_input("main", **{input_name: data_np}) - return vm.run() - - for target in ["llvm"]: - tvm_res = compile_and_run_vm(mod, params, data_np, target) - - # Bounding boxes - tvm.testing.assert_allclose( - pt_res[0].cpu().numpy(), tvm_res[0].numpy(), rtol=1e-5, atol=1e-5 - ) - # Scores - tvm.testing.assert_allclose( - pt_res[1].cpu().numpy(), tvm_res[1].numpy(), rtol=1e-5, atol=1e-5 - ) - # Class ids - np.testing.assert_equal(pt_res[2].cpu().numpy(), tvm_res[2].numpy()) - - score_threshold = 0.9 - print("Num boxes:", pt_res[0].cpu().numpy().shape[0]) - print("Num valid boxes:", np.sum(pt_res[1].cpu().numpy() >= score_threshold)) - - before = mod["main"] - mod = rewrite_nms_to_batched_nms(mod) - after = mod["main"] - assert not tvm.ir.structural_equal(after, before) - - # TODO(masahi): It seems this rewrite causes flaky segfaults on CI - # See https://github.com/apache/tvm/issues/7363 - # before = mod["main"] - # mod = rewrite_batched_nms_with_max_out_size(mod) - # after = mod["main"] - # assert not tvm.ir.structural_equal(after, before) - - before = mod["main"] - mod = rewrite_scatter_to_gather(mod, 4) # num_scales is 4 for maskrcnn_resnet50_fpn - after = mod["main"] - assert not tvm.ir.structural_equal(after, before) - - tvm_res_after_rewrite = compile_and_run_vm(mod, params, data_np, "llvm") - - # Results should be equivalent after rewriting - for res1, res2 in zip(tvm_res, tvm_res_after_rewrite): - tvm.testing.assert_allclose(res1.numpy(), res2.numpy()) diff --git a/tests/python/frontend/pytorch/test_rnns.py b/tests/python/frontend/pytorch/test_rnns.py deleted file mode 100644 index b43af58d69a3..000000000000 --- a/tests/python/frontend/pytorch/test_rnns.py +++ /dev/null @@ -1,521 +0,0 @@ -# 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 torch -import tvm -import tvm.testing -import onnx -import io -import sys - -from tvm import relay -from tvm.contrib import graph_executor - -from torch import nn - -## LSTM parameters -lstm_feature_size = 16 -lstm_hidden_size = 32 -lstm_projection_size = 20 - -## GRU parameters -gru_feature_size = 8 -gru_hidden_size = 16 - -num_layers = 2 -seqs_length = 2 -batch_size = 2 - -##RNN parameters -rnn_feature_size = 8 -rnn_hidden_size = 16 - - -class RNN_Model(nn.Module): - """ - It is base class for RNN layer classes. - It contains some common fields and methods for child classes. - """ - - def __init__( - self, - ): - super().__init__() - - # model is defined in child class - self.model = None - - def forward(self, input, hidden_init=None): - """ - Computes the output tensor after input inference along RNN layer. - - :param input: batch of data as a tensor of shape (seqs_length, batch_size, feature_size) or (batch_size, seqs_length, feature_size) if self.batch_first = True - :param hidden_init: initial hidden state(s) of the RNN as a tensor(s) of shape (num_layers, batch_size, hidden_size). Will default to a tensor of zeros if None. - :return: the output tensor of shape (batch_size, hidden_size) - """ - if self.model is None: - raise NotImplementedError("self.model must be defined in subclasses!") - out, _ = self.model(input, hidden_init) - - return out - - def gen_rnd_weights(self): - """ - Generate random weigths for the model - """ - if self.model is None: - raise NotImplementedError("self.model must be defined in subclasses!") - with torch.no_grad(): - for weight_group in self.model.all_weights: - for weight in weight_group: - weight.data = torch.rand(weight.shape) - - def get_dummy_inputs(self): - raise NotImplementedError("subclasses must override get_dummy_inputs()!") - - def get_input_names(self): - raise NotImplementedError("subclasses must override get_input_names()!") - - def get_shape_desc(self, frontend_type): - raise NotImplementedError("subclasses must override get_shape_desc(frontend_type)!") - - def get_tvm_inputs(self, dtype): - raise NotImplementedError("subclasses must override get_tvm_inputs(dtype)!") - - -class RNN_Model_Impl(RNN_Model): - def __init__( - self, - seq_len=seqs_length, - batch_size=batch_size, - feature_size=rnn_feature_size, - hidden_size=rnn_hidden_size, - batch_first=False, - layer_num=1, - bidirectional=False, - use_bias=True, - rnd_weights_init=False, - nonlinearity="tanh", - dropout=0.0, - ): - super().__init__() - # Shapes - self.shape = [seq_len, batch_size, feature_size] - if batch_first: - self.shape = [batch_size, seq_len, feature_size] - layers_num = 2 * layer_num if bidirectional else layer_num - self.h0_shape = [layers_num, batch_size, hidden_size] - # Dummy inputs - self.dummy_inputs = (torch.rand(self.shape), torch.zeros(self.h0_shape)) - - self.model = nn.RNN( - input_size=feature_size, - hidden_size=hidden_size, - num_layers=layer_num, - nonlinearity=nonlinearity, - bias=use_bias, - batch_first=batch_first, - dropout=dropout, - bidirectional=bidirectional, - ) - - if rnd_weights_init: - self.gen_rnd_weights() - - def gen_rnd_weights(self): - super().gen_rnd_weights() - - def get_dummy_inputs(self): - return self.dummy_inputs - - def get_input_names(self): - return ["input", "h0"] - - def get_shape_desc(self, frontend_type): - shape_desc = None - if frontend_type == "pt": # PyTorch - shape_desc = [("input", self.shape)] - elif frontend_type == "onnx": # ONNX - shape_desc = { - "input": self.shape, - "h0": self.h0_shape, - } - return shape_desc - - def get_tvm_inputs(self, dtype): - return { - "input": tvm.nd.array(self.dummy_inputs[0].numpy().astype(dtype)), - "h0": tvm.nd.array(self.dummy_inputs[1].numpy().astype(dtype)), - } - - -class GRU_Model(RNN_Model): - def __init__( - self, - seq_len=seqs_length, - batch_size=batch_size, - feature_size=gru_feature_size, - hidden_size=gru_hidden_size, - batch_first=False, - layer_num=1, - bidirectional=False, - use_bias=True, - rnd_weights_init=False, - ): - super().__init__() - - # Shapes - self.shape = [seq_len, batch_size, feature_size] - if batch_first: - self.shape = [batch_size, seq_len, feature_size] - layers_num = 2 * layer_num if bidirectional else layer_num - self.h0_shape = [layers_num, batch_size, hidden_size] - # Dummy inputs - self.dummy_inputs = (torch.rand(self.shape), torch.zeros(self.h0_shape)) - - self.model = nn.GRU( - input_size=feature_size, - hidden_size=hidden_size, - num_layers=layer_num, - bidirectional=bidirectional, - batch_first=batch_first, - bias=use_bias, - ) - - if rnd_weights_init: - self.gen_rnd_weights() - - def gen_rnd_weights(self): - """ - Generate random weigths for the model with biases - For first uni- and bidirectional weights group: - Wi (3*hidden_size, feature_size) - Wh (3*hidden_size, hidden_size) - Bi (3*hidden_size) - Bh (3*hidden_size) - For other weights group: - Wi (3*hidden_size, hidden_size) - Wh (3*hidden_size, hidden_size) - Bi (3*hidden_size) - Bh (3*hidden_size) - For generation of random weigths for the model without biases the Bi and Bh weights are skipped - """ - super().gen_rnd_weights() - - def get_dummy_inputs(self): - return self.dummy_inputs - - def get_input_names(self): - return ["input", "h0"] - - def get_shape_desc(self, frontend_type): - shape_desc = None - if frontend_type == "pt": # PyTorch - shape_desc = [("input", self.shape)] - elif frontend_type == "onnx": # ONNX - shape_desc = { - "input": self.shape, - "h0": self.h0_shape, - } - return shape_desc - - def get_tvm_inputs(self, dtype): - return { - "input": tvm.nd.array(self.dummy_inputs[0].numpy().astype(dtype)), - "h0": tvm.nd.array(self.dummy_inputs[1].numpy().astype(dtype)), - } - - -def check_torch_version_for_proj_in_lstm(): - """ - proj_size parameter is supported in torch.nn.LSTM layer started from 1.8.0 torch version - """ - me = False - - version = torch.__version__ - major, minor, micro = version.split(".") - - if int(major) > 1: - me = True - elif int(major) == 1: - if int(minor) >= 8: - me = True - - return me - - -class LSTM_Model(RNN_Model): - def __init__( - self, - seq_len=seqs_length, - batch_size=batch_size, - feature_size=lstm_feature_size, - hidden_size=lstm_hidden_size, - batch_first=False, - layer_num=1, - bidirectional=False, - proj_size=0, - use_bias=True, - rnd_weights_init=False, - ): - super().__init__() - - # Shapes - self.shape = [seq_len, batch_size, feature_size] - if batch_first: - self.shape = [batch_size, seq_len, feature_size] - layers_num = 2 * layer_num if bidirectional else layer_num - self.h0_shape = [layers_num, batch_size, hidden_size] - if proj_size > 0: - self.h0_shape = [layers_num, batch_size, proj_size] - self.c0_shape = [layers_num, batch_size, hidden_size] - # Dummy inputs - self.dummy_inputs = ( - torch.rand(self.shape), - (torch.zeros(self.h0_shape), torch.zeros(self.c0_shape)), - ) - - if check_torch_version_for_proj_in_lstm(): - self.model = nn.LSTM( - input_size=lstm_feature_size, - hidden_size=lstm_hidden_size, - num_layers=layer_num, - bidirectional=bidirectional, - proj_size=proj_size, - batch_first=batch_first, - bias=use_bias, - ) - else: - if proj_size > 0: - print( - "WARNING: projection is not supported for torch version less than 1.8.0! ", - "LSTM was constructed without projection!", - ) - # sys.exit() - self.model = nn.LSTM( - input_size=lstm_feature_size, - hidden_size=lstm_hidden_size, - num_layers=layer_num, - bidirectional=bidirectional, - batch_first=batch_first, - bias=use_bias, - ) - - if rnd_weights_init: - self.gen_rnd_weights() - - def gen_rnd_weights(self): - """ - Generate random weigths for the model with biases - Without projection: - For first weights group: - Wi (4*lstm_hidden_size, lstm_feature_size) - Wh (4*lstm_hidden_size, lstm_hidden_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - For first bidirectional weights group: - Wi (4*lstm_hidden_size, lstm_feature_size) - Wh (4*lstm_hidden_size, lstm_hidden_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - For other weights group: - Wi (4*lstm_hidden_size, lstm_hidden_size) - Wh (4*lstm_hidden_size, lstm_hidden_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - With projection: - For first weights group: - Wi (4*lstm_hidden_size, lstm_feature_size) - Wh (4*lstm_hidden_size, proj_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - P (proj_size, lstm_hidden_size) - For first bidirectional weights group: - Wi (4*lstm_hidden_size, lstm_feature_size) - Wh (4*lstm_hidden_size, proj_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - P (proj_size, lstm_hidden_size) - For other weights group: - Wi (4*lstm_hidden_size, proj_size * num_directions) - Wh (4*lstm_hidden_size, proj_size) - Bi (4*lstm_hidden_size) - Bh (4*lstm_hidden_size) - P (proj_size, lstm_hidden_size) - For generation of random weigths for the model without biases Bi and Bh are skipped - """ - super().gen_rnd_weights() - - def get_dummy_inputs(self): - return self.dummy_inputs - - def get_input_names(self): - return ["input", "h0", "c0"] - - def get_shape_desc(self, frontend_type): - shape_desc = None - if frontend_type == "pt": # PyTorch - shape_desc = [("input", self.shape)] - elif frontend_type == "onnx": # ONNX - shape_desc = { - "input": self.shape, - "h0": self.h0_shape, - "c0": self.c0_shape, - } - return shape_desc - - def get_tvm_inputs(self, dtype): - return { - "input": tvm.nd.array(self.dummy_inputs[0].numpy().astype(dtype)), - "h0": tvm.nd.array(self.dummy_inputs[1][0].numpy().astype(dtype)), - "c0": tvm.nd.array(self.dummy_inputs[1][1].numpy().astype(dtype)), - } - - -def compare(input, gold_data, rtol=1e-5, atol=1e-5): - tvm.testing.assert_allclose(input, gold_data, rtol=rtol, atol=atol) - - -def check_rnn(rnn_type, rnn_mod, target=tvm.target.Target("llvm -mcpu=core-avx2"), dev=tvm.cpu(0)): - def get_model( - rnn_type, - rnn_mod, - args, - ): - # Fill args - if "b" in rnn_mod: - args["bidirectional"] = True - if "s" in rnn_mod: - args["layer_num"] = num_layers - if "tanh" in rnn_mod: - args["nonlinearity"] = "tanh" - if "relu" in rnn_mod: - args["nonlinearity"] = "relu" - - if rnn_type == "GRU": - RNN_Model_selector = GRU_Model - elif rnn_type == "LSTM": - RNN_Model_selector = LSTM_Model - if "p" in rnn_mod: - args["proj_size"] = lstm_projection_size - elif rnn_type == "RNN": - RNN_Model_selector = RNN_Model_Impl - - return RNN_Model_selector(**args) - - def get_onnx_model(model): - onnx_io = io.BytesIO() - with torch.no_grad(): - input_names = model.get_input_names() - inputs = model.get_dummy_inputs() - - # default export (without dynamic input) - torch.onnx.export(model, inputs, onnx_io, input_names=input_names) - - onnx_io.seek(0, 0) - return onnx.load_model(onnx_io) - - model = None - dtype = "float32" - device = torch.device("cpu") - for batch_first in (True, False): - for use_bias in (True, False): - for rnd_weights in [True]: # (True, False): - model_inputs = { - "batch_first": batch_first, - "use_bias": use_bias, - "rnd_weights_init": rnd_weights, - } - model = get_model(rnn_type, rnn_mod, model_inputs) - model.to(device) - model.eval() - - # Get golden output from original model - dummy_inputs = model.get_dummy_inputs() - golden_output = model.forward(dummy_inputs[0].to(device)).detach().cpu().numpy() - - tvm_output = None - for format in ["pt"]: # ["pt", "onnx"]: - shape_desc = model.get_shape_desc(format) - if format == "pt": - # Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing. - traced_script_module = torch.jit.trace(model, dummy_inputs[0]).eval() - - # Import model to Relay - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_pytorch( - traced_script_module, shape_desc - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_pytorch( - traced_script_module, shape_desc - ) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - elif format == "onnx": - try: - onnx_model = get_onnx_model(model) - except: - print( - "WARNING: torch.onnx.export does not support conversion LSTM with projection " - "from pytorch! TODO: waiting for the support and correct test after that." - ) - continue - - # Import model to Relay - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_onnx(onnx_model, shape_desc) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_onnx(onnx_model, shape_desc) - tvm.ir.assert_structural_equal(mod, mod_with_span, map_free_vars=True) - - # Model compilation by tvm - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target=target, params=params) - - # Inference of the model with given input data - m = graph_executor.GraphModule(lib["default"](dev)) - - # Set inputs - tvm_inputs = model.get_tvm_inputs(dtype) - m.set_input(**tvm_inputs) - # Execute - m.run() - # Get outputs (converted to numpy array) - tvm_output = m.get_output(0).numpy() - - compare(tvm_output, golden_output) - - -@tvm.testing.uses_gpu -def test_rnns(): - for target, dev in tvm.testing.enabled_targets(): - # RNN types: GRU, LSTM - # GRU modifications: unidirectional, stacked, bidirectional, stacked bidirectional - for mod_type in ["uni", "s", "b", "sb"]: - check_rnn("GRU", mod_type, target, dev) - # LSTM modifications: unidirectional, stacked, bidirectional, stacked bidirectional, - # and all these types with projection ("p", "sp", "bp", "sbp") - # The latter are skiped for test acceleration - for mod_type in ["uni", "s", "b", "sb"]: - check_rnn("LSTM", mod_type, target, dev) - - for mod_type in ["uni", "s", "b", "sb", "tanh", "relu"]: - check_rnn("RNN", mod_type, target, dev) - - -if __name__ == "__main__": - test_rnns() diff --git a/tests/python/frontend/pytorch/test_span_naming.py b/tests/python/frontend/pytorch/test_span_naming.py deleted file mode 100644 index fb39ddf4f061..000000000000 --- a/tests/python/frontend/pytorch/test_span_naming.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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. -# pylint: disable=import-self, too-many-lines, len-as-condition, no-else-return, unused-variable, too-many-nested-blocks -# pylint: disable=consider-iterating-dictionary, invalid-name, unused-argument, unused-variable, broad-except -# pylint: disable=import-outside-toplevel, simplifiable-if-expression, cell-var-from-loop, unnecessary-lambda -# pylint: disable=missing-function-docstring, redefined-builtin, use-implicit-booleaness-not-comparison -"""Tests to ensure span names are correctly populated when importing Pytorch""" -from torch import nn -import torch -import tvm - - -class NestedConvModule(nn.Module): - """Module that performs Conv2d and relu activation""" - - def __init__(self, in_channels, out_channels): - super().__init__() - self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) - self.relu = nn.ReLU() - - def forward(self, x): - x = self.relu(self.conv(x)) - return x - - -class NestedFinalModule(nn.Module): - """Simple module that adds 2 inputs""" - - def forward(self, x, y): - return x + y - - -class SimpleTwoConvModule(nn.Module): - """ - ML model that performs 2 convolutions and adds them together. - All operations are inside nested modules to make scope names interesting. - """ - - def __init__(self): - super().__init__() - # First convolutional module - self.image_block1 = NestedConvModule(in_channels=3, out_channels=64) - # Second convolutional module - self.image_block2 = NestedConvModule(in_channels=64, out_channels=64) - self.final_block = NestedFinalModule() - - def forward(self, x): - # Forward pass through the first convolutional module - x1 = self.image_block1(x) - # Forward pass through the second convolutional module - x2 = self.image_block2(x1) - # Add the outputs of the two convolutional modules - return self.final_block(x1, x2) - - -def test_pytorch_scope_based_span_names(): - model = SimpleTwoConvModule() - sample_input = torch.zeros((1, 3, 64, 64), dtype=torch.float32) - with torch.no_grad(): - traced_torch_model = torch.jit.trace(model, sample_input) - import_input = [("model_input", (1, 3, 64, 64))] - relay_model_ir, relay_model_params = tvm.relay.frontend.from_pytorch( - traced_torch_model, import_input, preserve_pytorch_scopes=True - ) - # If specified, we are preserving the pytorch named spans - for block in [1, 2]: - for key in ["weight", "bias"]: - assert f"image_block{block}.conv.{key}" in relay_model_params.keys() - # Manually check all span names since asserting structural equality is not sufficient - current_call = relay_model_ir["main"].body - assert current_call.op.name == "add" - assert current_call.span is not None and current_call.span.source_name.name == "final_block" - current_call = current_call.args[1] - for block in [2, 1]: - assert current_call.op.name == "nn.relu" - assert ( - current_call.span is not None - and current_call.span.source_name.name == f"image_block{block}.relu" - ) - current_call = current_call.args[0] - assert current_call.op.name == "nn.bias_add" - assert ( - current_call.span is not None - and current_call.span.source_name.name == f"image_block{block}.conv" - ) - current_call = current_call.args[0] - assert current_call.op.name == "nn.conv2d" - assert ( - current_call.span is not None - and current_call.span.source_name.name == f"image_block{block}.conv" - ) - current_call = current_call.args[0] diff --git a/tests/python/frontend/tensorflow/test_bn_dynamic.py b/tests/python/frontend/tensorflow/test_bn_dynamic.py deleted file mode 100644 index 99d8f790028c..000000000000 --- a/tests/python/frontend/tensorflow/test_bn_dynamic.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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. -""" -BatchNorm without given mean and variance given testcases -==================== -This is a test script to test fused_batch_norm operators -in TensorFlow frontend when mean and variance are not given. -""" -import tvm -import tvm.testing -import numpy as np - -try: - import tensorflow.compat.v1 as tf - - tf.disable_v2_behavior() -except ImportError: - import tensorflow as tf -from tvm import relay -from tensorflow.python.framework import graph_util - - -def verify_fused_batch_norm(shape): - g = tf.Graph() - with g.as_default(): - input_tensor = tf.placeholder(tf.float32, shape=shape, name="input") - alpha = tf.constant( - np.random.rand( - shape[-1], - ), - dtype=tf.float32, - name="alpha", - ) - beta = tf.constant( - np.random.rand( - shape[-1], - ), - dtype=tf.float32, - name="beta", - ) - bn = tf.nn.fused_batch_norm(x=input_tensor, offset=beta, scale=alpha, name="bn") - out = tf.identity(bn[0], name="output") - data = np.random.rand(*shape) - with tf.Session(graph=out.graph) as sess: - sess.run([tf.global_variables_initializer()]) - tf_out = sess.run(out, feed_dict={input_tensor: data}) - constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, ["output"]) - - for device in ["llvm"]: - dev = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print("Skip because %s is not enabled" % device) - continue - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_tensorflow(constant_graph, outputs=["output"]) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow(constant_graph, outputs=["output"]) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"]) - with tvm.transform.PassContext(opt_level=3): - graph, lib, params = relay.build(mod, target=device, params=params) - from tvm.contrib import graph_executor - - m = graph_executor.create(graph, lib, dev) - m.set_input(**params) - m.set_input("input", data) - m.run() - tvm_out = m.get_output(0) - tvm.testing.assert_allclose( - tvm_out.numpy(), tf_out.astype(tvm_out.dtype), atol=1e-3, rtol=1e-3 - ) - - -def test_fused_batch_norm(): - verify_fused_batch_norm(shape=(1, 12, 12, 32)) - verify_fused_batch_norm(shape=(1, 24, 24, 64)) - verify_fused_batch_norm(shape=(1, 64, 64, 128)) - verify_fused_batch_norm(shape=(8, 12, 12, 32)) - verify_fused_batch_norm(shape=(16, 12, 12, 32)) - verify_fused_batch_norm(shape=(32, 12, 12, 32)) - - -if __name__ == "__main__": - test_fused_batch_norm() diff --git a/tests/python/frontend/tensorflow/test_control_flow.py b/tests/python/frontend/tensorflow/test_control_flow.py deleted file mode 100644 index 494deb46835f..000000000000 --- a/tests/python/frontend/tensorflow/test_control_flow.py +++ /dev/null @@ -1,473 +0,0 @@ -# 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. -"""Unit tests for converting TensorFlow control flow op to Relay.""" -import pytest - -try: - import tensorflow.compat.v1 as tf - - tf.disable_v2_behavior() -except ImportError: - import tensorflow as tf -from tensorflow.python.ops import control_flow_ops -import numpy as np -from tvm import nd, relay, ir, testing -from tvm.relay.frontend.tensorflow import from_tensorflow - - -def check_equal(graph, tf_out, input_map=None): - with testing.disable_span_filling(): - mod, params = from_tensorflow(graph.as_graph_def(add_shapes=True)) - with testing.enable_span_filling(): - mod_with_span, _ = from_tensorflow(graph.as_graph_def(add_shapes=True)) - assert ir.structural_equal(mod["main"], mod_with_span["main"]) - - if input_map is not None: - params.update(input_map) - relay_out = relay.create_executor("vm", mod=mod).evaluate()(**params) - if isinstance(relay_out, nd.NDArray): - np.testing.assert_allclose(tf_out, relay_out.numpy()) - else: - if not isinstance(tf_out, (list, tuple)): - tf_out = [tf_out] - for x, y in zip(tf_out, [r.numpy() for r in relay_out]): - np.testing.assert_allclose(x, y) - - -def test_vanilla_loop(): - graph = tf.Graph() - with graph.as_default(): - i = tf.constant(0, name="while/constant") - - def c(i): - return tf.less(i, 10) - - def b(i): - return tf.add(i, 1) - - r = tf.while_loop(c, b, [i]) - - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_callnode_loop_vars(): - graph = tf.Graph() - with graph.as_default(): - i = tf.add(tf.constant(0), 1) - - def c(i): - return tf.less(i, 10) - - def b(i): - return tf.add(i, 1) - - r = tf.while_loop(c, b, [i]) - - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_loop_2_vars(): - graph = tf.Graph() - with graph.as_default(): - i0 = tf.constant(0) - j0 = tf.ones([2, 2]) - - def c(i, j): - return i < 10 - - def b(i, j): - return [tf.add(i, 1), j] - - i1, i2 = tf.while_loop(c, b, loop_vars=[i0, j0]) - i1 += tf.constant(1337) - - with tf.Session() as sess: - tf_out = sess.run(i1) - - check_equal(graph, tf_out) - - -def test_loop_3_vars(): - graph = tf.Graph() - with graph.as_default(): - i0 = tf.constant(1) - j0 = tf.constant(2) - k0 = tf.constant(4) - - def c(i, j, k): - return i < 10 - - def b(i, j, k): - return [i + 1, j * k, k + i] - - r = tf.while_loop(c, b, loop_vars=[i0, j0, k0]) - - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_loop_conditions(): - graph = tf.Graph() - with graph.as_default(): - i = tf.constant(1) - j = tf.constant(1) - k = tf.constant(5) - - def c(i, j, k): - return tf.equal( - tf.not_equal(tf.less(i + j, 10), tf.less(j * k, 100)), tf.greater_equal(k, i + j) - ) - - def b(i, j, k): - return [i + j, j + k, k + 1] - - r = tf.while_loop(c, b, loop_vars=[i, j, k]) - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -@pytest.mark.skip -def test_loop_bodies(): - graph = tf.Graph() - with graph.as_default(): - - def body(x): - a = tf.constant(np.array([[5, 6], [7, 8]]), dtype=tf.int32) - b = tf.constant(np.array([[1, 2], [3, 4]]), dtype=tf.int32) - c = a + b - return tf.nn.relu(x + c) - - def condition(x): - return tf.reduce_sum(x) < 100 - - x = tf.constant(0, shape=[2, 2]) - r = tf.while_loop(condition, body, [x]) - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_nested_loop(): - graph = tf.Graph() - with graph.as_default(): - - def body(x): - def nest_body(c): - return tf.multiply(c, 2) - - def cd(c): - return tf.less(c, 10) - - c = tf.constant(2) - res = tf.while_loop(cd, nest_body, loop_vars=[c]) - return tf.nn.relu(x + res) - - def condition(x): - return tf.greater(x, 100) - - x = tf.constant(3) - r = tf.while_loop(condition, body, loop_vars=[x]) - - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_vanilla_cond(): - graph = tf.Graph() - with graph.as_default(): - i = tf.constant(1) - j = tf.constant(4) - - def f1(): - return tf.multiply(1, 17) - - def f2(): - return tf.add(4, 23) - - r = tf.cond(tf.less(i, j), f1, f2) - - with tf.Session(graph=graph) as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_multiple_cond_vars(): - graph = tf.Graph() - with graph.as_default(): - x1 = tf.constant(7) - x2 = tf.constant(12) - z = tf.constant(20) - r = tf.cond(tf.less(tf.add(x1, x2), 10), lambda: tf.add(10, 2), lambda: tf.square(5)) - - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_cond_fn_parameters(): - graph = tf.Graph() - with graph.as_default(): - - def fn1(x, y): - return tf.multiply(5, 6) - - def fn2(x, y): - return tf.add(3, 4) - - i = tf.constant(1) - j = tf.constant(2) - k = tf.constant(3) - r = tf.cond(tf.less(i, j), lambda: fn1(i, k), lambda: fn2(j, k)) - - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={i: 1, j: 2, k: 3}) - - check_equal(graph, tf_out) - - -def test_nested_cond(): - graph = tf.Graph() - with graph.as_default(): - - def fn1(a, b): - def nest_fn1(): - return tf.add(1, 2) - - def nest_fn2(): - return tf.subtract(10, 5) - - res = tf.cond(tf.less(1, 2), nest_fn1, nest_fn2) - return tf.multiply(tf.add(87, res), 10) - - def fn2(a, b): - return tf.add(10, 10) - - x = tf.constant(5) - y = tf.constant(6) - z = tf.constant(7) - pred = tf.less(x, y) - r = tf.cond(pred, lambda: fn1(x, y), lambda: fn2(y, z)) - - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={x: 1, y: 2, z: 3, pred: True}) - - check_equal(graph, tf_out) - - -def test_loop_in_cond(): - graph = tf.Graph() - with graph.as_default(): - - def fn1(a, b): - i = tf.constant(0) - - def cd(i): - return tf.less(i, 10) - - def bd(i): - return tf.add(i, 1) - - res = tf.while_loop(cd, bd, [i]) - return tf.multiply(tf.add(20, res), 10) - - def fn2(a, b): - return tf.add(10, 20) - - x = tf.constant(7) - y = tf.constant(20) - z = tf.constant(10) - pred = tf.less(x, y) - r = tf.cond(pred, lambda: fn1(x, y), lambda: fn2(y, z)) - - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={x: 1, y: 2, z: 3, pred: True}) - - check_equal(graph, tf_out) - - -def test_cond_in_loop(): - graph = tf.Graph() - with graph.as_default(): - - def body(x): - x = tf.constant(7) - z = tf.constant(20) - res = tf.cond(tf.less(x, 10), lambda: tf.add(10, 20), lambda: tf.square(10)) - return tf.multiply(res, x) - - x = tf.constant(21) - - def condition(x): - return tf.less(x, 100) - - r = tf.while_loop(condition, body, loop_vars=[x]) - with tf.Session() as sess: - tf_out = sess.run(r) - - check_equal(graph, tf_out) - - -def test_vanilla_loop_bound(): - graph = tf.Graph() - with graph.as_default(): - dshape = (2, 10) - dtype = "float32" - dname = "data" - np_data = np.random.uniform(size=dshape).astype(dtype) - data = tf.placeholder(shape=dshape, dtype=dtype, name=dname) - x = tf.slice(data, [1, 4], [1, 4]) - outer = x + 5.0 - - def body(x, y): - res = tf.cond(tf.less(y, 10), lambda: tf.add(10.0, 20.0), lambda: tf.square(10.0)) - z = tf.constant(7) - res = tf.cond(tf.less(z, 10), lambda: res * 5, lambda: res + 10) - return tf.multiply(res, x * outer), y + 1 - - y = tf.constant(0) - - def condition(x, y): - return tf.less(y, 20) - - r = tf.while_loop(condition, body, loop_vars=[x, y]) - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={"%s:0" % dname: np_data}) - - check_equal(graph, tf_out, {dname: np_data}) - - -def test_nested_loop_bound(): - graph = tf.Graph() - with graph.as_default(): - dshape = (2, 10) - dtype = "float32" - dname = "data" - np_data = np.random.uniform(size=dshape).astype(dtype) - data = tf.placeholder(shape=dshape, dtype=dtype, name=dname) - x = tf.slice(data, [1, 4], [1, 4]) - outer = x + 5.0 - - def body(x, y): - res = tf.cond(tf.less(y, 10), lambda: tf.add(10.0, 20.0), lambda: tf.square(10.0)) - - def nested_body(nx, ny): - return nx + 1, res + 2.0 - - def nested_cond(nx, ny): - return tf.less(nx, 15) - - nx = tf.constant(0) - ny = tf.constant(0.0) - nested_res = tf.while_loop(nested_cond, nested_body, loop_vars=[nx, ny]) - res = res + nested_res[1] - z = tf.constant(7) - res = tf.cond(tf.less(z, 10), lambda: res * 5, lambda: res + 10) - return tf.multiply(res, x * outer), y + 1 - - y = tf.constant(0) - - def condition(x, y): - return tf.less(y, 20) - - r = tf.while_loop(condition, body, loop_vars=[x, y]) - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={"%s:0" % dname: np_data}) - - check_equal(graph, tf_out, {dname: np_data}) - - -def test_switch(): - graph = tf.Graph() - - with graph.as_default(): - data_np = np.random.uniform(0, 5, size=(2, 4, 5, 1)).astype("float32") - dname = "data" - flag_name = "flag" - data = tf.placeholder(shape=data_np.shape, dtype=data_np.dtype, name=dname) - split = tf.split(data, 2, axis=0) - flag = tf.placeholder(shape={}, dtype=tf.bool, name=flag_name) - output_false, output_true = control_flow_ops.switch(split[1], flag) - with tf.Session() as sess: - tf_out = sess.run(output_false, feed_dict={data.name: data_np, flag.name: False}) - - check_equal(graph, tf_out, {dname: data_np, flag_name: False}) - - -def test_loop_tuple_input(): - graph = tf.Graph() - - with graph.as_default(): - data_np = np.random.uniform(0, 5, size=(2, 4, 5, 1)).astype("float32") - dname = "data" - data = tf.placeholder(shape=data_np.shape, dtype=data_np.dtype, name=dname) - split = tf.split(data, 2, axis=0) - - def body(x, y): - return x + 2, y + 1 - - start = tf.constant(0) - - def condition(x, y): - return tf.less(y, 20) - - r = tf.while_loop(condition, body, loop_vars=[split[1], start]) - with tf.Session() as sess: - tf_out = sess.run(r, feed_dict={data.name: data_np}) - - check_equal(graph, tf_out, {dname: data_np}) - - -if __name__ == "__main__": - # tf.while_loop - test_vanilla_loop() - test_loop_2_vars() - test_loop_3_vars() - test_loop_conditions() - # TODO(@jroesch): Need to fix memory alloc to support closure - # test_loop_bodies() - test_callnode_loop_vars() - - # tf.cond - test_vanilla_cond() - test_multiple_cond_vars() - test_cond_fn_parameters() - - # nested cases - test_nested_loop() - test_nested_cond() - test_loop_in_cond() - test_cond_in_loop() - test_vanilla_loop_bound() - test_nested_loop_bound() - - test_switch() - test_loop_tuple_input() diff --git a/tests/python/frontend/tensorflow/test_debugging.py b/tests/python/frontend/tensorflow/test_debugging.py deleted file mode 100644 index 0f7c4dd7d65a..000000000000 --- a/tests/python/frontend/tensorflow/test_debugging.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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. -"""Unit tests for converting TensorFlow debugging ops to Relay.""" -try: - import tensorflow.compat.v1 as tf - - tf.disable_v2_behavior() -except ImportError: - import tensorflow as tf -import numpy as np -from tvm import relay, ir, testing -from tvm.relay.frontend.tensorflow import from_tensorflow - - -def run_relay(graph, shape_dict=None, *vars): - with testing.disable_span_filling(): - mod, params = from_tensorflow(graph.as_graph_def(add_shapes=True), shape=shape_dict) - with testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow( - graph.as_graph_def(add_shapes=True), shape=shape_dict - ) - assert ir.structural_equal(mod["main"], mod_with_span["main"]) - - return relay.create_executor("debug", mod=mod).evaluate()(*vars) - - -def test_assert_true(): - g = tf.Graph() - shape = (1, 2) - with g.as_default(): - x = tf.placeholder(tf.float32, shape=shape, name="input") - assert_op = tf.Assert(tf.reduce_all(tf.less_equal(x, x)), ["it failed"]) - - with tf.Session() as sess: - x_value = np.random.rand(*shape) - assert sess.run(assert_op, feed_dict={x: x_value}) is None - - # In TVM, tf.assert is converted to a no-op which is actually a 0, - # though it should probably be none or an empty tuple. - # - # ToDo: It appears that the frontend converter gets confused here and - # entirely eliminates all operands from main(). Likely because x <= x - # is always true, so the placeholder can be eliminated. But TF doesn't - # do that, it's happening in Relay, and that optimization shouldn't - # affect the arity of the main function. We should have to pass in - # x_value here. - np.testing.assert_allclose(0, run_relay(g, {"input": shape}).numpy()) - - -def test_assert_true_var_capture(): - g = tf.Graph() - with g.as_default(): - x = tf.placeholder(tf.float32, shape=()) - - # It turns out that tf.assert() creates a large and complex subgraph if - # you capture a variable as part of the error message. So we need to - # test that, too. - assert_op = tf.Assert(tf.less_equal(x, x), ["it failed", x]) - - with tf.Session() as sess: - x_value = np.random.rand() - assert sess.run(assert_op, feed_dict={x: x_value}) is None - - # TODO: The frontend converter notes the output of - # the graph as a boolean, which is not correct - as you can see above, - # TF believes that the value of this graph is None. - np.testing.assert_allclose(True, run_relay(g, None, x_value).numpy()) - - -def test_assert_false(): - g = tf.Graph() - with g.as_default(): - assert_op = tf.Assert(tf.constant(False), ["it failed"]) - - with tf.Session() as sess: - try: - print(sess.run(assert_op)) - assert False # TF should have thrown an exception - except tf.errors.InvalidArgumentError as e: - assert "it failed" in e.message - - # In TVM, tf.assert is converted to a no-op which is actually a 0, - # though it should probably be none or an empty tuple. For the same - # reason, there should not be an error here, even though the assertion - # argument is false. - np.testing.assert_allclose(0, run_relay(g).numpy()) - - -if __name__ == "__main__": - test_assert_true() - test_assert_true_var_capture() - test_assert_false() diff --git a/tests/python/frontend/tensorflow/test_forward.py b/tests/python/frontend/tensorflow/test_forward.py deleted file mode 100644 index 354ed38a62ce..000000000000 --- a/tests/python/frontend/tensorflow/test_forward.py +++ /dev/null @@ -1,6100 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, ungrouped-imports, wrong-import-order -""" -Tensorflow testcases -==================== -This article is a test script to test tensorflow operator with Relay. -""" -from __future__ import print_function - -import threading -import platform -import os.path -from packaging import version as package_version -import numpy as np -import pytest - -from PIL import Image - -from tensorflow.python.framework import constant_op -from tensorflow.python.framework import graph_util -from tensorflow.python.ops import nn_ops -from tensorflow.python.ops import nn -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import math_ops -from tensorflow.python.ops import variable_scope -from tensorflow.python.ops import variables -from tensorflow.python.ops import init_ops -from tensorflow.python.framework import function -from tensorflow.python.framework import ops -from tensorflow.python.framework import dtypes -from tensorflow.python.ops import gen_functional_ops -from tensorflow.python.client import device_lib - -try: - import tensorflow.compat.v1 as tf - - tf.disable_v2_behavior() -except ImportError: - import tensorflow as tf - -import tvm -from tvm import relay, ir -from tvm.runtime.vm import VirtualMachine -from tvm.relay.frontend.tensorflow import from_tensorflow -from tvm.contrib import graph_executor -from tvm.contrib import utils -import tvm.testing -import tvm.relay.testing.tf as tf_testing -from relay.utils.tag_span import _set_span, _create_span, _verify_structural_equal_with_span - - -# Only allow TF to run on half the GPU RAM to save the other half -# For TVM -gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5) -gpu_sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) -gpu_sess.close() - - -####################################################################### -# Generic run functions for TVM & tensorflow -# ------------------------------------------ - - -def convert_to_list(x): - if not isinstance(x, list): - x = [x] - return x - - -tf_dtypes = { - "float32": tf.float32, - "float16": tf.float16, - "float64": tf.float64, - "int32": tf.int32, - "uint8": tf.uint8, - "int8": tf.int8, - "int16": tf.int16, - "uint16": tf.uint16, - "int64": tf.int64, -} - - -def vmobj_to_list(o): - """Converts TVM objects returned by VM execution to Python List.""" - if isinstance(o, tvm.nd.NDArray): - return [o.numpy()] - elif isinstance(o, tvm.runtime.container.ADT): - result = [] - for f in o: - result.extend(vmobj_to_list(f)) - return result - elif isinstance(o, tvm.relay.backend.interpreter.ConstructorValue): - if o.constructor.name_hint == "Cons": - tl = vmobj_to_list(o.fields[1]) - hd = vmobj_to_list(o.fields[0]) - hd.extend(tl) - return hd - elif o.constructor.name_hint == "Nil": - return [] - elif "tensor_nil" in o.constructor.name_hint: - return [0] - elif "tensor" in o.constructor.name_hint: - return [o.fields[0].numpy()] - else: - raise RuntimeError(f"Unknown object type: {o.constructor.name_hint}") - else: - raise RuntimeError(f"Unknown object type: {type(o)}") - - -def run_tvm_graph( - graph_def, - input_data, - input_node, - num_output=1, - target="llvm", - out_names=None, - opt_level=3, - mode="graph_executor", - cuda_layout="NCHW", - layout=None, - disabled_pass=None, - ignore_in_shape=False, - serialize=False, - convert_config=None, -): - """Generic function to compile on relay and execute on tvm""" - input_data = convert_to_list(input_data) - input_node = convert_to_list(input_node) - if target == "cuda": - layout = cuda_layout - target_host = None - if ignore_in_shape: - shape_dict = None - else: - shape_dict = { - e: i.shape if hasattr(i, "shape") else () for e, i in zip(input_node, input_data) - } - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_tensorflow( - graph_def, - layout=layout, - shape=shape_dict, - outputs=out_names, - convert_config=convert_config, - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow( - graph_def, - layout=layout, - shape=shape_dict, - outputs=out_names, - convert_config=convert_config, - ) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"], map_free_vars=True) - - dev = tvm.device(target, 0) - if mode == "debug": - inputs = [] - for param in mod["main"].params: - found = False - for i, n in enumerate(input_node): - if n == param.name_hint: - found = True - inputs.append(tvm.nd.array(input_data[i])) - break - # Interpreter doesn't bind constants, so still need to find in params - if not found: - inputs.append(tvm.nd.array(params[param.name_hint])) - result = relay.create_executor(mode, mod=mod, device=tvm.cpu(), target="llvm").evaluate()( - *inputs - ) - return vmobj_to_list(result) - elif mode == "vm": - with tvm.transform.PassContext(opt_level=opt_level, disabled_pass=disabled_pass): - mod = relay.transform.InferType()(mod) - vm_exec = relay.vm.compile(mod, target="llvm", params=params) - if serialize: - code, lib = vm_exec.save() - vm_exec = tvm.runtime.vm.Executable.load_exec(code, lib) - vm = VirtualMachine(vm_exec, tvm.cpu()) - inputs = {} - for e, i in zip(input_node, input_data): - inputs[e] = tvm.nd.array(i) - result = vm.invoke("main", **inputs) - return vmobj_to_list(result) - else: - with tvm.transform.PassContext(opt_level=opt_level, disabled_pass=disabled_pass): - target = tvm.target.Target(target, target_host) - graph, lib, params = relay.build(mod, target=target, params=params) - - m = graph_executor.create(graph, lib, dev) - # set inputs - for e, i in zip(input_node, input_data): - if e != "": - m.set_input(e, tvm.nd.array(i)) - - m.set_input(**params) - # execute - m.run() - # get outputs - assert out_names is None or num_output == len( - out_names - ), f"out_names: {out_names} num_output: {num_output}" - tvm_output_list = [m.get_output(i).numpy() for i in range(num_output)] - return tvm_output_list - - -def run_tf_graph(sess, input_data, input_node, output_node): - """Generic function to execute tensorflow""" - input_data = convert_to_list(input_data) - input_node = convert_to_list(input_node) - output_node = convert_to_list(output_node) - - tensor = [sess.graph.get_tensor_by_name(output_name) for output_name in output_node] - - input_dict = {e: input_data[i] for i, e in enumerate(input_node)} - if len(input_node) == 1 and input_node[0] == "": - output_data = sess.run(tensor) - else: - output_data = sess.run(tensor, input_dict) - return output_data - - -def compare_tf_with_tvm( - in_data, - in_name, - out_name, - init_global_variables=False, - no_gpu=False, - opt_level=3, - mode="graph_executor", - cuda_layout="NCHW", - add_shapes_to_graph_def=True, - targets=None, - ignore_in_shape=False, - convert_config=None, - atol=1e-5, - rtol=1e-5, -): - """Generic function to generate and compare tensorflow and TVM output""" - - def name_without_num(name): - return name.split(":")[0] if ":" in name else name - - out_name = convert_to_list(out_name) - out_node = [name_without_num(name) for name in out_name] - - in_data = convert_to_list(in_data) - in_name = convert_to_list(in_name) - in_node = [name_without_num(name) for name in in_name] - with tf.Session() as sess: - if init_global_variables: - sess.run(variables.global_variables_initializer()) - final_graph_def = ( - tf_testing.AddShapesToGraphDef(sess, out_node) - if add_shapes_to_graph_def - else tf.get_default_graph().as_graph_def() - ) - - tf_output = run_tf_graph(sess, in_data, in_name, out_name) - - devices = targets if targets else ["llvm", "cuda"] - - for device in devices: - _ = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print(f"Skip because {device} is not enabled") - continue - if no_gpu and device == "cuda": - continue - if "cublas" in device and not tvm.get_global_func("tvm.contrib.cublas.matmul", True): - print(f"Skip because cublas is not enabled: {device}") - continue - - tvm_output = run_tvm_graph( - final_graph_def, - in_data, - in_node, - target=device, - out_names=out_name, - num_output=len(out_name), - opt_level=opt_level, - mode=mode, - cuda_layout=cuda_layout, - ignore_in_shape=ignore_in_shape, - convert_config=convert_config, - ) - # since the names from tensorflow and relay runs are not exactly same, - # first len(tf_output) will be compared - for i, tf_out in enumerate(tf_output): - if not isinstance(tf_out, np.ndarray): - assert len(tvm_output[i].shape) == 0 # pylint: disable=len-as-condition - tvm.testing.assert_allclose(tf_out, tvm_output[i], atol=atol, rtol=rtol) - - sess.close() - - -def is_gpu_available(): - """Verify gpu is available""" - local_device_protos = device_lib.list_local_devices() - gpu_list = [x.name for x in local_device_protos if x.device_type == "GPU"] - if gpu_list: - print("Tensorflow GPU:", gpu_list) - return True - else: - return False - - -####################################################################### -# Pooling -# ------- - - -def _test_pooling_iteration(input_shape, **kwargs): - """One iteration of pool operation with given shapes and attributes""" - - x = -np.arange(np.prod(input_shape), dtype=np.float32).reshape(input_shape) - 1 - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype="float32") - nn_ops.pool(in_data, **kwargs) - - if kwargs["pooling_type"] == "MAX": - out_name = "max_pool:0" - else: - out_name = "avg_pool:0" - - compare_tf_with_tvm(x, "Placeholder:0", out_name) - - -def _test_pooling(input_shape, **kwargs): - _test_pooling_iteration(input_shape, **kwargs) - - if is_gpu_available(): - if len(input_shape) == 4: - input_shape = [input_shape[ii] for ii in (0, 3, 1, 2)] - if isinstance(kwargs["padding"], list): - kwargs["padding"] = [kwargs["padding"][ii] for ii in (0, 3, 1, 2)] - kwargs["data_format"] = "NCHW" - _test_pooling_iteration(input_shape, **kwargs) - - -def _test_pooling_dynamic(input_shape, np_shape, **kwargs): - """Pooling with dynamic height and width dimensions.""" - x = -np.arange(np.prod(np_shape), dtype=np.float32).reshape(np_shape) - 1 - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype="float32") - nn_ops.pool(in_data, **kwargs) - - if kwargs["pooling_type"] == "MAX": - out_name = "max_pool:0" - else: - out_name = "avg_pool:0" - - compare_tf_with_tvm(x, "Placeholder:0", out_name, mode="vm", ignore_in_shape=True) - - -@tvm.testing.uses_gpu -def test_forward_pooling(): - """Pooling""" - # TensorFlow only supports NDHWC for max_pool3d on CPU - for pool_type in ["AVG", "MAX"]: - # NDHWC is the default layout for max_pool3d and avg_pool3d in TensorFlow - _test_pooling( - input_shape=[1, 3, 32, 32, 32], - window_shape=[2, 2, 2], - padding="VALID", - pooling_type=pool_type, - dilation_rate=[1, 1, 1], - strides=[2, 2, 2], - ) - - _test_pooling( - input_shape=[1, 3, 32, 32, 32], - window_shape=[1, 1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1, 1], - strides=[1, 1, 1], - ) - - _test_pooling( - input_shape=[1, 3, 32, 32, 32], - window_shape=[2, 2, 2], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1, 1], - strides=[2, 2, 2], - ) - - _test_pooling_dynamic( - input_shape=[1, None, None, 3], - np_shape=[1, 32, 32, 3], - window_shape=[2, 2], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - # test cases for max_pool3d & avg_pool3d with layout NCDHW - # TensorFlow pool3d doesn't support NCDHW on cpu - if is_gpu_available(): - _test_pooling( - input_shape=[1, 3, 32, 32, 32], - window_shape=[1, 1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1, 1], - strides=[1, 1, 1], - data_format="NCDHW", - ) - - _test_pooling( - input_shape=[1, 3, 32, 32, 32], - window_shape=[2, 2, 2], - padding="VALID", - pooling_type=pool_type, - dilation_rate=[1, 1, 1], - strides=[2, 2, 2], - data_format="NCDHW", - ) - - _test_pooling( - input_shape=[2, 9, 10, 2], - window_shape=[1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 10, 9, 2], - window_shape=[1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 9, 10, 2], - window_shape=[2, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 10, 9, 2], - window_shape=[2, 3], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[2, 1], - ) - - # Tests involving SpaceToBatchND - _test_pooling( - input_shape=[1, 1, 2, 1], - window_shape=[1, 1], - padding="VALID", - pooling_type=pool_type, - dilation_rate=[1, 2], - ) - - _test_pooling( - input_shape=[1, 2, 1], - window_shape=[1], - padding="VALID", - pooling_type=pool_type, - dilation_rate=[2], - ) - # Explicit padding - if package_version.parse(tf.VERSION) >= package_version.parse("2.4.1"): - _test_pooling( - input_shape=[2, 9, 10, 2], - window_shape=[4, 4], - padding=[[0, 0], [0, 1], [2, 3], [0, 0]], - pooling_type="MAX", - dilation_rate=[1, 1], - strides=[1, 1], - ) - - -####################################################################### -# Convolution -# ----------- - - -def _test_convolution( - opname, - tensor_in_sizes, - filter_in_sizes, - dilations, - strides, - padding, - data_format, - deconv_output_shape=None, - add_shapes_to_graph_def=True, -): - """One iteration of convolution with given shapes and attributes""" - deconv_output_shape = deconv_output_shape or [] - total_size_1 = np.prod(tensor_in_sizes) - total_size_2 = np.prod(filter_in_sizes) - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - filter_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32") - in_filter = constant_op.constant(filter_array, shape=filter_in_sizes, dtype="float32") - if data_format == "NHWC": - strides = [1] + strides + [1] - dilations = [1] + dilations + [1] - else: - strides = [1, 1] + strides - dilations = [1, 1] + dilations - - if opname == "conv": - nn_ops.conv2d( - in_data, - in_filter, - strides=strides, - dilations=dilations, - padding=padding, - data_format=data_format, - ) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), - "Placeholder:0", - "Conv2D:0", - add_shapes_to_graph_def=add_shapes_to_graph_def, - ) - elif opname == "conv_transpose": - nn_ops.conv2d_transpose( - in_data, - in_filter, - output_shape=deconv_output_shape, - strides=strides, - padding=padding, - data_format=data_format, - ) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), - "Placeholder:0", - "conv2d_transpose:0", - add_shapes_to_graph_def=add_shapes_to_graph_def, - ) - else: - nn_ops.depthwise_conv2d_native( - in_data, - in_filter, - strides=strides, - dilations=dilations, - padding=padding, - data_format=data_format, - ) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), - "Placeholder:0", - "DepthwiseConv2dNative:0", - add_shapes_to_graph_def=add_shapes_to_graph_def, - ) - - -@pytest.mark.skip(reason="See https://github.com/apache/tvm/issues/10275") -@tvm.testing.uses_gpu -def test_forward_convolution(): - """Convolution""" - if is_gpu_available(): - _test_convolution("conv", [4, 176, 8, 8], [1, 1, 176, 32], [1, 1], [1, 1], "SAME", "NCHW") - _test_convolution("conv", [4, 19, 17, 17], [3, 3, 19, 19], [1, 1], [2, 2], "VALID", "NCHW") - _test_convolution("conv", [4, 124, 17, 17], [1, 1, 124, 19], [1, 1], [1, 1], "SAME", "NCHW") - _test_convolution("conv", [4, 12, 17, 17], [3, 3, 12, 32], [1, 1], [2, 2], "VALID", "NCHW") - _test_convolution( - "depthwise", [4, 176, 8, 8], [1, 1, 176, 1], [1, 1], [1, 1], "SAME", "NCHW" - ) - _test_convolution( - "depthwise", [4, 19, 17, 17], [3, 3, 19, 1], [1, 1], [2, 2], "VALID", "NCHW" - ) - _test_convolution( - "depthwise", [4, 124, 17, 17], [1, 1, 124, 1], [1, 1], [1, 1], "SAME", "NCHW" - ) - _test_convolution( - "depthwise", [4, 12, 17, 17], [3, 3, 12, 1], [1, 1], [2, 2], "VALID", "NCHW" - ) - _test_convolution( - "depthwise", [4, 12, 17, 17], [3, 3, 12, 2], [1, 1], [2, 2], "VALID", "NCHW" - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [1, 1, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NCHW", - [4, 176, 8, 8], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [2, 2, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NCHW", - [4, 176, 8, 8], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [2, 2, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NCHW", - [4, 176, 15, 15], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [3, 3, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NCHW", - [4, 176, 8, 8], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [3, 3, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NCHW", - [4, 176, 15, 15], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [3, 3, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NCHW", - [4, 176, 16, 16], - ) - _test_convolution( - "conv_transpose", - [4, 19, 8, 8], - [3, 3, 19, 19], - [1, 1], - [2, 2], - "VALID", - "NCHW", - [4, 19, 17, 17], - ) - _test_convolution( - "conv_transpose", - [4, 19, 17, 17], - [1, 1, 124, 19], - [1, 1], - [1, 1], - "SAME", - "NCHW", - [4, 124, 17, 17], - ) - _test_convolution( - "conv_transpose", - [4, 19, 17, 17], - [3, 3, 124, 19], - [1, 1], - [1, 1], - "SAME", - "NCHW", - [4, 124, 17, 17], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [3, 3, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NCHW", - [4, 12, 17, 17], - ) - # kernel 2x2, strides (2,2) - _test_convolution( - "conv_transpose", - [4, 19, 8, 8], - [2, 2, 19, 19], - [1, 1], - [2, 2], - "VALID", - "NCHW", - [4, 19, 16, 16], - ) - _test_convolution( - "conv_transpose", - [4, 32, 8, 8], - [2, 2, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NCHW", - [4, 12, 16, 16], - ) - # output channel is 1 - _test_convolution( - "conv_transpose", - [1, 19, 8, 8], - [1, 1, 1, 19], - [1, 1], - [1, 1], - "VALID", - "NCHW", - [1, 1, 8, 8], - ) - _test_convolution( - "conv_transpose", - [4, 19, 8, 8], - [2, 2, 66, 19], - [1, 1], - [2, 2], - "VALID", - "NCHW", - [4, 66, 16, 16], - ) - _test_convolution("conv", [4, 8, 8, 176], [1, 1, 176, 32], [1, 1], [1, 1], "SAME", "NHWC") - _test_convolution("conv", [4, 17, 17, 19], [3, 3, 19, 19], [1, 1], [2, 2], "VALID", "NHWC") - _test_convolution("conv", [4, 17, 17, 124], [1, 1, 124, 19], [1, 1], [1, 1], "SAME", "NHWC") - _test_convolution("conv", [4, 17, 17, 12], [3, 3, 12, 32], [1, 1], [2, 2], "VALID", "NHWC") - _test_convolution( - "conv", - [4, 17, 17, 12], - [3, 3, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NHWC", - add_shapes_to_graph_def=False, - ) - _test_convolution("depthwise", [4, 8, 8, 176], [1, 1, 176, 1], [1, 1], [1, 1], "SAME", "NHWC") - _test_convolution("depthwise", [4, 17, 17, 19], [3, 3, 19, 1], [1, 1], [2, 2], "VALID", "NHWC") - _test_convolution("depthwise", [4, 17, 17, 124], [1, 1, 124, 1], [1, 1], [1, 1], "SAME", "NHWC") - _test_convolution("depthwise", [4, 17, 17, 12], [3, 3, 12, 1], [1, 1], [2, 2], "VALID", "NHWC") - _test_convolution("depthwise", [4, 17, 17, 12], [3, 3, 12, 2], [1, 1], [2, 2], "VALID", "NHWC") - _test_convolution( - "depthwise", - [4, 17, 17, 12], - [3, 3, 12, 2], - [1, 1], - [2, 2], - "VALID", - "NHWC", - add_shapes_to_graph_def=False, - ) - - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [1, 1, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 8, 8, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [2, 2, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 8, 8, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [2, 2, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NHWC", - [4, 15, 15, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [3, 3, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 8, 8, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [3, 3, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NHWC", - [4, 15, 15, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [3, 3, 176, 32], - [1, 1], - [2, 2], - "SAME", - "NHWC", - [4, 16, 16, 176], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 19], - [3, 3, 19, 19], - [1, 1], - [2, 2], - "VALID", - "NHWC", - [4, 17, 17, 19], - ) - _test_convolution( - "conv_transpose", - [4, 17, 17, 19], - [1, 1, 124, 19], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 17, 17, 124], - ) - _test_convolution( - "conv_transpose", - [4, 17, 17, 19], - [3, 3, 124, 19], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 17, 17, 124], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [3, 3, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NHWC", - [4, 17, 17, 12], - ) - # kernel 2x2, strides (2,2) - _test_convolution( - "conv_transpose", - [4, 8, 8, 19], - [2, 2, 19, 19], - [1, 1], - [2, 2], - "VALID", - "NHWC", - [4, 16, 16, 19], - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [2, 2, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NHWC", - [4, 16, 16, 12], - ) - # output channel is 1 - _test_convolution( - "conv_transpose", - [1, 8, 8, 19], - [1, 1, 1, 19], - [1, 1], - [1, 1], - "VALID", - "NHWC", - [1, 8, 8, 1], - ) - # Test without adding shapes to graph def - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [1, 1, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NHWC", - [4, 8, 8, 176], - add_shapes_to_graph_def=False, - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 19], - [2, 2, 66, 19], - [1, 1], - [2, 2], - "VALID", - "NHWC", - [4, 16, 16, 66], - ) - # Explicit padding - if package_version.parse(tf.VERSION) >= package_version.parse("2.4.1"): - _test_convolution( - "conv", - [4, 8, 8, 16], - [1, 1, 16, 32], - [1, 1], - [1, 1], - [[0, 0], [2, 3], [0, 1], [0, 0]], - "NHWC", - ) - _test_convolution( - "depthwise", - [4, 8, 8, 16], - [1, 1, 16, 1], - [1, 1], - [1, 1], - [[0, 0], [2, 3], [0, 1], [0, 0]], - "NHWC", - ) - _test_convolution( - "conv_transpose", - [4, 8, 8, 32], - [3, 3, 176, 32], - [1, 1], - [2, 2], - [[0, 0], [1, 0], [1, 0], [0, 0]], - "NHWC", - [4, 16, 16, 176], - ) - - -####################################################################### -# Convolution3D -# ------------- - - -def _test_convolution3d( - opname, - tensor_in_sizes, - filter_in_sizes, - dilations, - strides, - padding, - data_format, - deconv_output_shape=None, - add_shapes_to_graph_def=True, -): - """One iteration of 3D convolution with given shapes and attributes""" - deconv_output_shape = deconv_output_shape or [] - total_size_1 = np.prod(tensor_in_sizes) - total_size_2 = np.prod(filter_in_sizes) - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - filter_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32") - in_filter = constant_op.constant(filter_array, shape=filter_in_sizes, dtype="float32") - if data_format == "NDHWC": - strides = [1] + strides + [1] - dilations = [1] + dilations + [1] - else: - strides = [1, 1] + strides - dilations = [1, 1] + dilations - - if opname == "conv": - nn_ops.conv3d( - in_data, - in_filter, - strides=strides, - dilations=dilations, - padding=padding, - data_format=data_format, - ) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), - "Placeholder:0", - "Conv3D:0", - cuda_layout="NCDHW", - add_shapes_to_graph_def=add_shapes_to_graph_def, - ) - - -@tvm.testing.uses_gpu -def test_forward_convolution3d(): - """Convolution3d""" - if is_gpu_available(): - _test_convolution3d( - "conv", [4, 176, 8, 8, 8], [1, 1, 1, 176, 32], [1, 1, 1], [1, 1, 1], "SAME", "NCDHW" - ) - _test_convolution3d( - "conv", [4, 19, 17, 17, 17], [3, 3, 3, 19, 19], [1, 1, 1], [2, 2, 2], "VALID", "NCDHW" - ) - _test_convolution3d( - "conv", [4, 124, 17, 17, 17], [1, 1, 1, 124, 19], [1, 1, 1], [1, 1, 1], "SAME", "NCDHW" - ) - _test_convolution3d( - "conv", [4, 12, 17, 17, 17], [3, 3, 3, 12, 32], [1, 1, 1], [2, 2, 2], "VALID", "NCDHW" - ) - _test_convolution3d( - "conv", [4, 8, 8, 8, 176], [1, 1, 1, 176, 32], [1, 1, 1], [1, 1, 1], "SAME", "NDHWC" - ) - _test_convolution3d( - "conv", [4, 17, 17, 17, 19], [3, 3, 3, 19, 19], [1, 1, 1], [2, 2, 2], "VALID", "NDHWC" - ) - _test_convolution3d( - "conv", [4, 17, 17, 17, 124], [1, 1, 1, 124, 19], [1, 1, 1], [1, 1, 1], "SAME", "NDHWC" - ) - _test_convolution3d( - "conv", [4, 17, 17, 17, 12], [3, 3, 3, 12, 32], [1, 1, 1], [2, 2, 2], "VALID", "NDHWC" - ) - # Test without adding shapes to graph def - _test_convolution3d( - "conv", - [4, 17, 17, 17, 12], - [3, 3, 3, 12, 32], - [1, 1, 1], - [2, 2, 2], - "VALID", - "NDHWC", - add_shapes_to_graph_def=False, - ) - - -####################################################################### -# Convolution3D Transpose -# ----------------------- - - -def _test_convolution3d_transpose( - data_shape, - filter_shape, - strides, - padding, - output_shape, - data_format="NCDHW", - add_shapes_to_graph_def=True, -): - """One iteration of 3D convolution transpose with given shapes and attributes""" - - dtype = "float32" - data_array = np.random.uniform(size=data_shape).astype(dtype) - filter_array = np.random.uniform(size=filter_shape).astype(dtype) - if data_format == "NDHWC": - strides = [1] + strides + [1] - else: - strides = [1, 1] + strides - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data_shape, dtype=dtype) - in_filter = constant_op.constant(filter_array, shape=filter_shape, dtype=dtype) - - nn_ops.conv3d_transpose( - in_data, - in_filter, - output_shape=output_shape, - strides=strides, - padding=padding, - data_format=data_format, - ) - - compare_tf_with_tvm( - data_array, - "Placeholder:0", - "conv3d_transpose:0", - cuda_layout="NDHWC", - add_shapes_to_graph_def=add_shapes_to_graph_def, - ) - - -@tvm.testing.uses_gpu -def test_forward_convolution3d_transpose(): - """Convolution3d transpose""" - if is_gpu_available(): - _test_convolution3d_transpose( - data_shape=[1, 10, 8, 8, 8], - filter_shape=[1, 1, 1, 6, 10], - strides=[1, 1, 1], - padding="VALID", - output_shape=[1, 6, 8, 8, 8], - ) - - _test_convolution3d_transpose( - data_shape=[4, 9, 8, 8, 8], - filter_shape=[1, 1, 1, 6, 9], - strides=[1, 1, 1], - padding="VALID", - output_shape=[4, 6, 8, 8, 8], - ) - - _test_convolution3d_transpose( - data_shape=[1, 3, 8, 8, 8], - filter_shape=[1, 1, 1, 6, 3], - strides=[2, 2, 2], - padding="SAME", - output_shape=[1, 6, 15, 15, 15], - ) - - _test_convolution3d_transpose( - data_shape=[1, 16, 8, 8, 8], - filter_shape=[3, 3, 3, 6, 16], - strides=[3, 3, 3], - padding="VALID", - output_shape=[1, 6, 24, 24, 24], - ) - - _test_convolution3d_transpose( - data_shape=[1, 8, 8, 8, 10], - filter_shape=[1, 1, 1, 6, 10], - strides=[1, 1, 1], - padding="VALID", - output_shape=[1, 8, 8, 8, 6], - data_format="NDHWC", - ) - - _test_convolution3d_transpose( - data_shape=[4, 8, 8, 8, 9], - filter_shape=[1, 1, 1, 6, 9], - strides=[1, 1, 1], - padding="VALID", - output_shape=[4, 8, 8, 8, 6], - data_format="NDHWC", - ) - - _test_convolution3d_transpose( - data_shape=[1, 8, 8, 8, 3], - filter_shape=[1, 1, 1, 6, 3], - strides=[2, 2, 2], - padding="SAME", - output_shape=[1, 15, 15, 15, 6], - data_format="NDHWC", - ) - - _test_convolution3d_transpose( - data_shape=[1, 8, 8, 8, 16], - filter_shape=[3, 3, 3, 6, 16], - strides=[3, 3, 3], - padding="VALID", - output_shape=[1, 24, 24, 24, 6], - data_format="NDHWC", - ) - - # Test without adding shapes to graph def - _test_convolution3d_transpose( - data_shape=[1, 8, 8, 8, 16], - filter_shape=[3, 3, 3, 6, 16], - strides=[3, 3, 3], - padding="VALID", - output_shape=[1, 24, 24, 24, 6], - data_format="NDHWC", - add_shapes_to_graph_def=False, - ) - - -####################################################################### -# BiasAdd -# ----------- - - -def _test_biasadd(tensor_in_sizes, data_format): - """One iteration of biasadd with given shapes and attributes""" - - total_size_1 = 1 - for s in tensor_in_sizes: - total_size_1 *= s - tensor_bias_sizes = [tensor_in_sizes[1]] if data_format == "NCHW" else [tensor_in_sizes[3]] - total_size_2 = tensor_bias_sizes[0] - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - bias_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32") - in_bias = constant_op.constant(bias_array, shape=tensor_bias_sizes, dtype="float32") - nn_ops.bias_add(in_data, in_bias, data_format=data_format) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), "Placeholder:0", "BiasAdd:0" - ) - - -@tvm.testing.uses_gpu -def test_forward_biasadd(): - """Bias add""" - if is_gpu_available(): - _test_biasadd([4, 176, 8, 8], "NCHW") - _test_biasadd([1, 100, 1, 1], "NCHW") - _test_biasadd([4, 19, 17, 17], "NCHW") - _test_biasadd([4, 124, 3, 3], "NCHW") - - _test_biasadd([4, 8, 8, 176], "NHWC") - _test_biasadd([1, 1, 1, 100], "NHWC") - _test_biasadd([4, 17, 17, 19], "NHWC") - _test_biasadd([4, 3, 3, 124], "NHWC") - - -def _test_forward_where(input_shape): - with tf.Graph().as_default(): - dtype = tf.float32 - t = tf.constant( - np.random.choice([0, 1, -2, 3, -1, 0.1, -0.2], size=input_shape).astype(dtype.name) - ) - out = tf.where(t) - compare_tf_with_tvm([], [], out.name, mode="debug") - compare_tf_with_tvm([], [], out.name, mode="vm") - - -def test_forward_argwhere(): - _test_forward_where((5,)) - _test_forward_where((5, 5)) - _test_forward_where((5, 5, 5)) - _test_forward_where((5, 5, 5, 5)) - _test_forward_where((5, 5, 5, 5, 5)) - - -def _test_forward_where_with_broadcast(in_shape, cond_shape): - choice_list = list(np.arange(10).astype("float32")) - t1 = np.random.choice(choice_list, size=cond_shape) - t2 = np.random.choice(choice_list, size=cond_shape) - x = np.random.choice(choice_list, size=in_shape) - y = np.random.choice(choice_list, size=in_shape) - - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=cond_shape, dtype="float32", name="in1") - in2 = tf.placeholder(shape=cond_shape, dtype="float32", name="in2") - condition = math_ops.less(in1, in2, name="less") - lhs = tf.placeholder(shape=in_shape, dtype="float32", name="x") - rhs = tf.placeholder(shape=in_shape, dtype="float32", name="y") - out = tf.where(condition, lhs, rhs) - compare_tf_with_tvm([t1, t2, x, y], ["in1:0", "in2:0", "x:0", "y:0"], out.name) - - -def test_forward_where_with_broadcast(): - _test_forward_where_with_broadcast((5, 2), (5,)) - _test_forward_where_with_broadcast((5, 7), (5,)) - _test_forward_where_with_broadcast((3, 2, 5), (3,)) - - -####################################################################### -# SpaceToBatchND -# -------------- - - -def _test_space_to_batch_nd(input_shape, block_shape, paddings, dtype="int32"): - data = np.random.uniform(0, 5, size=input_shape).astype(dtype) - - with tf.Graph().as_default(): - in_data = tf.placeholder(shape=input_shape, dtype=dtype) - out = tf.space_to_batch_nd(in_data, block_shape, paddings) - - compare_tf_with_tvm(data, in_data.name, out.name) - - -def _test_space_to_batch_nd_infer_paddings(input_shape, block_shape, dtype="int32"): - data = np.random.uniform(0, 5, size=input_shape).astype(dtype) - padding_np = np.array([0, 1]).astype(np.int32).reshape((1, 2)) - with tf.Graph().as_default(): - in_data = tf.placeholder(shape=input_shape, dtype=dtype) - const1 = tf.constant(padding_np, dtype=tf.int32) - # make paddings an input to tf.transpose, but not an input to the graph, - # so it can be extracted with infer_value_simulated - paddings = tf.reverse(const1, axis=[-1]) - out = tf.space_to_batch_nd(in_data, block_shape, paddings) - compare_tf_with_tvm(data, in_data.name, out.name) - - -def test_forward_space_to_batch_nd(): - """SpaceToBatchNd""" - # test cases: https://www.tensorflow.org/api_docs/cc/class/tensorflow/ops/space-to-batch-n-d - _test_space_to_batch_nd(input_shape=[1, 2, 2, 1], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd(input_shape=[1, 2, 2, 3], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd(input_shape=[1, 4, 4, 1], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd( - input_shape=[2, 2, 4, 1], block_shape=[2, 2], paddings=[[0, 0], [2, 0]], dtype="int64" - ) - - # pylint: disable=line-too-long - # https://github.com/tensorflow/tensorflow/blob/24f578/tensorflow/python/kernel_tests/spacetobatch_op_test.py - _test_space_to_batch_nd(input_shape=[2, 3], block_shape=[2], paddings=[[1, 0]], dtype="float32") - - _test_space_to_batch_nd( - input_shape=[2, 3, 2], block_shape=[2], paddings=[[1, 0]], dtype="float64" - ) - - _test_space_to_batch_nd_infer_paddings(input_shape=[2, 3, 2], block_shape=[2]) - - -####################################################################### -# BatchToSpaceND -# -------------- - - -def _test_batch_to_space_nd(input_shape, block_shape, crops, dtype="int32"): - data = np.random.uniform(0, 5, size=input_shape).astype(dtype) - - with tf.Graph().as_default(): - in_data = tf.placeholder(shape=input_shape, dtype=dtype) - out = tf.batch_to_space_nd(in_data, block_shape, crops) - - compare_tf_with_tvm(data, in_data.name, out.name) - - -def test_forward_batch_to_space_nd(): - """BatchToSpaceNd""" - # test cases: https://www.tensorflow.org/api_docs/cc/class/tensorflow/ops/batch-to-space-n-d - _test_batch_to_space_nd(input_shape=[4, 1, 1, 1], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd(input_shape=[4, 1, 1, 3], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd(input_shape=[4, 2, 2, 1], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd( - input_shape=[8, 1, 3, 1], block_shape=[2, 2], crops=[[0, 0], [2, 0]], dtype="int64" - ) - - # pylint: disable=line-too-long - # https://github.com/tensorflow/tensorflow/blob/24f578/tensorflow/python/kernel_tests/batchtospace_op_test.py - _test_batch_to_space_nd( - input_shape=[18, 2, 1, 2], block_shape=[2, 3], crops=[[1, 1], [0, 0]], dtype="float32" - ) - - _test_batch_to_space_nd( - input_shape=[20, 5, 8, 7], block_shape=[2, 2], crops=[[1, 1], [1, 1]], dtype="float64" - ) - - -####################################################################### -# Reshape -# ------- - - -def _test_reshape(data, out_shape): - """One iteration of reshape operation with given data and out shape""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - array_ops.reshape(in_data, out_shape) - - compare_tf_with_tvm(data, "Placeholder:0", "Reshape:0") - - -def _test_reshape_with_call(): - """relay.expr.Call as shape""" - data = np.zeros((6, 4, 2)) - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out_shape = tf.constant([1, 2, 3], dtype="int32") - out_shape = tf.multiply(out_shape, 2) - array_ops.reshape(in_data, out_shape) - - compare_tf_with_tvm(data, "Placeholder:0", "Reshape:0") - - -def _test_reshape_like(data, shape_like): - """A special case for reshape.""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - in_shape_like = array_ops.placeholder(shape=shape_like.shape, dtype=data.dtype) - out_shape = array_ops.shape(in_shape_like) - array_ops.reshape(in_data, out_shape) - - compare_tf_with_tvm(data, "Placeholder:0", "Reshape:0") - - -def _test_reshape_symbolic(data, a_data, b_data): - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - a = array_ops.placeholder(shape=a_data.shape, dtype=a_data.dtype) - b = array_ops.placeholder(shape=b_data.shape, dtype=b_data.dtype) - newshape = tf.add(a, b) - out = array_ops.reshape(in_data, newshape) - - for mode in ["debug", "vm"]: - compare_tf_with_tvm( - [data, a_data, b_data], [in_data.name, a.name, b.name], out.name, mode=mode - ) - - -def test_forward_reshape(): - """Reshape""" - _test_reshape(np.arange(6.0), [2, 3]) - _test_reshape(np.arange(6), [-1, 2]) - _test_reshape(np.arange(6), [3, -1]) - _test_reshape(np.arange(6), [-1]) - _test_reshape_with_call() - _test_reshape_like(np.zeros((3, 6)), np.zeros((9, 2))) - _test_reshape_symbolic(np.arange(6.0), np.array([2, 0]), np.array([0, 3])) - _test_reshape_symbolic(np.arange(6), np.array([-1, 0]), np.array([0, 2])) - _test_reshape_symbolic(np.arange(6), np.array([3, 0]), np.array([3, -1])) - _test_reshape_symbolic(np.arange(6), np.array([0]), np.array([-1])) - - -####################################################################### -# DepthToSpace -# ------------ - - -def _test_depthtospace(data, block_size): - """One iteration of depth_to_space operation with given data and block size""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - array_ops.depth_to_space(in_data, block_size) - - compare_tf_with_tvm(data, "Placeholder:0", "DepthToSpace:0") - - -def test_forward_depthtospace(): - _test_depthtospace(np.random.normal(size=[1, 32, 32, 4]), 2) - _test_depthtospace(np.random.normal(size=[1, 16, 8, 32]), 4) - - -####################################################################### -# SpaceToDepth -# ------------ - - -def _test_spacetodepth(data, block_size): - """One iteration of space_to_depth operation with given data and block size""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - array_ops.space_to_depth(in_data, block_size) - - compare_tf_with_tvm(data, "Placeholder:0", "SpaceToDepth:0") - - -def test_forward_spacetodepth(): - _test_spacetodepth(np.random.normal(size=[1, 32, 32, 4]), 2) - _test_spacetodepth(np.random.normal(size=[1, 16, 8, 32]), 4) - - -####################################################################### -# Squeeze -# ------- - - -def _test_squeeze(data, squeeze_dims=None): - """One iteration of squeeze""" - - if squeeze_dims is None: - squeeze_dims = [] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - if squeeze_dims: - array_ops.squeeze(in_data, squeeze_dims) - else: - array_ops.squeeze(in_data) - - compare_tf_with_tvm(data, "Placeholder:0", "Squeeze:0") - - -def test_forward_squeeze(): - """Squeeze""" - - # Nothing to squeeze. - _test_squeeze(np.arange(2).reshape((2))) - _test_squeeze(np.arange(6).reshape((2, 3))) - - # Squeeze the middle element away. - _test_squeeze(np.arange(4).reshape((2, 1, 2))) - - # Squeeze on both ends. - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1))) - - # Positive squeeze dim index. - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [0]) - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [2, 4]) - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [0, 4, 2]) - - # Negative squeeze dim index. - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [-1]) - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [-3, -5]) - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3, 1)), [-3, -5, -1]) - - -####################################################################### -# TensorArray -# ----------- -def test_tensor_array_write_read(): - """Tensor array write read""" - - def run(dtype_str, infer_shape, element_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - np_data = np.array([[1.0, 2.0], [3.0, 4.0]]).astype(dtype_str) - _ = [np_data, np_data] - t1 = tf.constant(np_data, dtype=dtype) - t2 = tf.constant(np_data, dtype=dtype) - ta1 = tf.TensorArray( - dtype=dtype, size=2, infer_shape=infer_shape, element_shape=element_shape - ) - ta2 = ta1.write(0, t1) - ta3 = ta2.write(1, t2) - _ = ta3.read(0) - _ = tf.get_default_graph() - compare_tf_with_tvm([], [], "TensorArrayReadV3:0", mode="vm") - - for dtype in ["float32", "int8"]: - run(dtype, False, None) - run(dtype, False, tf.TensorShape([None, 2])) - run(dtype, True, None) - - -def test_tensor_array_scatter(): - """Tensor array scatter""" - - def run(dtype_str, infer_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - if infer_shape: - element_shape = tf.TensorShape([tf.Dimension(None)]) - else: - element_shape = None - ta0 = _construct_scatter(dtype, dtype_str, element_shape, infer_shape, 3) - _ = ta0.read(0) - _ = ta0.read(1) - _ = ta0.read(2) - ta1 = _construct_scatter(dtype, dtype_str, element_shape, infer_shape, 4) - out4 = ta1.read(0) - _ = tf.get_default_graph() - compare_tf_with_tvm([], [], ["TensorArrayReadV3:0"], mode="vm") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_1:0"], mode="vm") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_2:0"], mode="vm") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_2:0", out4.name], mode="vm") - - def _construct_scatter(dtype, dtype_str, element_shape, infer_shape, size): - arr = [[float(i)] for i in range(size)] # pylint: disable=unnecessary-comprehension - indices_arr = list(range(size - 1, -1, -1)) - - t = tf.constant(np.array(arr).astype(dtype_str), dtype=dtype) - indices = tf.constant(indices_arr) - ta1 = tf.TensorArray( - dtype=dtype, size=size, infer_shape=infer_shape, element_shape=element_shape - ) - ta2 = ta1.scatter(indices, t) - return ta2 - - for dtype in ["float32", "int8"]: - run(dtype, False) - run(dtype, True) - - -def test_tensor_array_gather(): - """tensor array gather""" - - def run(dtype_str, infer_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - t = tf.constant(np.array([[1.0], [2.0], [3.0]]).astype(dtype_str)) - scatter_indices = tf.constant([2, 1, 0]) - gather_indices = tf.constant([1, 2]) - ta1 = tf.TensorArray(dtype=dtype, size=3, infer_shape=infer_shape) - ta2 = ta1.scatter(scatter_indices, t) - _ = ta2.gather(gather_indices) - _ = tf.get_default_graph() - compare_tf_with_tvm([], [], ["TensorArrayGatherV3:0"], mode="vm") - - for dtype in ["float32", "int8"]: - run(dtype, True) - - -def test_tensor_array_split(): - """tensor array split""" - - def run(dtype_str, infer_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - t = tf.constant( - np.array([[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0]]).astype( - dtype_str - ), - dtype=dtype, - ) - split_length = tf.constant([2, 2, 2, 2], dtype=tf.int32) - ta1 = tf.TensorArray(dtype=dtype, size=4, infer_shape=infer_shape) - ta2 = ta1.split(t, split_length) - _ = ta2.read(0) - _ = ta2.read(1) - _ = ta2.read(2) - _ = ta2.read(3) - _ = tf.get_default_graph() - compare_tf_with_tvm([], [], ["TensorArrayReadV3:0"], mode="debug") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_1:0"], mode="debug") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_2:0"], mode="debug") - compare_tf_with_tvm([], [], ["TensorArrayReadV3_3:0"], mode="debug") - - for dtype in ["float32", "int8"]: - run(dtype, False) - run(dtype, True) - - -def test_tensor_array_concat(): - """Tensor array concat""" - - def run(dtype_str, infer_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - t = tf.constant( - np.array([[1.0], [2.0], [3.0], [4.0], [5.0], [6.0], [7.0], [8.0]]).astype( - dtype_str - ), - dtype=dtype, - ) - split_length = tf.constant([2, 2, 2, 2], dtype=tf.int32) - ta1 = tf.TensorArray(dtype=dtype, size=4, infer_shape=infer_shape) - ta2 = ta1.split(t, split_length) - t = ta2.concat() - _ = tf.identity(t) - compare_tf_with_tvm([], [], ["Identity:0"], mode="debug") - - for dtype in ["float32", "int8"]: - run(dtype, False) - run(dtype, True) - - -def test_tensor_array_size(): - """Tensor array size""" - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - pytest.skip("Needs fixing for tflite >= 1.15.0") - - def run(dtype_str, infer_shape): - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - np_data = np.array([[1.0, 2.0], [3.0, 4.0]]).astype(dtype_str) - _ = [np_data, np_data] - t1 = tf.constant(np_data, dtype=dtype) - t2 = tf.constant(np_data, dtype=dtype) - ta1 = tf.TensorArray(dtype=dtype, size=2, infer_shape=infer_shape) - ta2 = ta1.write(0, t1) - ta3 = ta2.write(1, t2) - _ = ta3.size() - _ = tf.get_default_graph() - compare_tf_with_tvm([], [], "TensorArraySizeV3:0", mode="debug") - - for dtype in ["float32", "int8"]: - run(dtype, False) - run(dtype, True) - - -def test_tensor_array_stack(): - """Tensor array stack""" - - def run(dtype_str, infer_shape): - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - pytest.skip("Needs fixing for tflite >= 1.15.0") - - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - t = tf.constant(np.array([[1.0], [2.0], [3.0]]).astype(dtype_str)) - scatter_indices = tf.constant([2, 1, 0]) - ta1 = tf.TensorArray(dtype=dtype, size=3, infer_shape=infer_shape) - ta2 = ta1.scatter(scatter_indices, t) - t1 = ta2.stack() - print(t1) - _ = tf.get_default_graph() - - compare_tf_with_tvm([], [], ["TensorArrayStack/TensorArrayGatherV3:0"], mode="vm") - - for dtype in ["float32", "int8"]: - run(dtype, True) - - -def test_tensor_array_unstack(): - """Tensor array unstack""" - - def run(dtype_str, input_shape, infer_shape): - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - pytest.skip("Needs fixing for tflite >= 1.15.0") - - with tf.Graph().as_default(): - dtype = tf_dtypes[dtype_str] - t = tf.constant(np.random.choice([0, 1, 2, 3], size=input_shape).astype(dtype.name)) - ta1 = tf.TensorArray(dtype=dtype, infer_shape=infer_shape, size=input_shape[0]) - ta2 = ta1.unstack(t) - _ = ta2.size() - _ = ta2.read(0) - compare_tf_with_tvm([], [], "TensorArraySizeV3:0", mode="debug") - compare_tf_with_tvm([], [], "TensorArrayReadV3:0", mode="debug") - - for dtype in ["float32", "int8"]: - run(dtype, (5,), False) - run(dtype, (5, 5), True) - run(dtype, (5, 5, 5), False) - run(dtype, (5, 5, 5, 5), True) - - -####################################################################### -# ConcatV2 -# -------- - - -def _test_concat_v2(shape1, shape2, dim): - """One iteration of ConcatV2""" - - with tf.Graph().as_default(): - dtype = "float32" - in1 = tf.placeholder(shape=shape1, dtype=dtype, name="in1") - in2 = tf.placeholder(shape=shape2, dtype=dtype, name="in2") - array_ops.concat_v2([in1, in2], dim) - - np_data1 = np.random.uniform(size=shape1).astype(dtype) - np_data2 = np.random.uniform(size=shape2).astype(dtype) - - compare_tf_with_tvm([np_data1, np_data2], ["in1:0", "in2:0"], "ConcatV2:0") - - -def test_forward_concat_v2(): - if package_version.parse(tf.__version__) < package_version.parse("1.4.1"): - return - - _test_concat_v2([2, 3], [2, 3], 0) - _test_concat_v2([10, 3, 5], [2, 3, 5], 0) - _test_concat_v2([2, 3], [2, 3], 1) - _test_concat_v2([5, 8], [5, 4], 1) - _test_concat_v2([2, 8, 5], [2, 8, 6], -1) - - -####################################################################### -# Sigmoid -# ------- - - -def _test_sigmoid(data): - """One iteration of sigmoid""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - _ = math_ops.sigmoid(in_data) - - compare_tf_with_tvm(data, "Placeholder:0", "Sigmoid:0") - - -def test_forward_sigmoid(): - """Sigmoid""" - - _test_sigmoid(np.random.uniform(size=(3, 4, 4, 3)).astype("float32")) - - -####################################################################### -# Argmin/Argmax -# ------------- - - -def _test_argx(func, data, **kwargs): - - with tf.Graph().as_default(): - inp = array_ops.placeholder(shape=data.shape, dtype=data.dtype, name="c0") - func(inp, name="argx0", **kwargs) - compare_tf_with_tvm(data, "c0:0", "argx0:0") - - -def test_forward_argminmax(): - for output_type in [tf.int64, tf.int32]: - for axis in [None, 0, 1, 2]: - data = np.random.uniform(size=(8, 4, 9)).astype("float32") - _test_argx(tf.argmax, data=data, axis=axis, output_type=output_type) - _test_argx(tf.argmin, data=data, axis=axis, output_type=output_type) - - -####################################################################### -# Variable -# -------- - - -def _test_variable(data): - """One iteration of a variable""" - - tf.reset_default_graph() - with tf.Graph().as_default(): - input_op = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - input_tensor = array_ops.reshape(input_op, data.shape) - - size = input_tensor.shape.dims[1] - with variable_scope.variable_scope("linear", reuse=None): - w = variable_scope.get_variable("w", shape=[size, size], dtype=input_tensor.dtype) - math_ops.matmul(input_tensor, w) - - compare_tf_with_tvm(data, "Placeholder:0", "MatMul:0", init_global_variables=True) - - -def test_forward_variable(): - """Variable type op test""" - _test_variable(np.random.uniform(size=(32, 100)).astype("float32")) - - -@tvm.testing.parametrize_targets("llvm", "cuda") -def test_read_variable_op(target, dev): - """Read Variable op test""" - - tf.reset_default_graph() - data = np.random.uniform(size=(32, 100)).astype("float32") - input_tensor = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - size = input_tensor.shape.dims[1] - var_data = np.random.uniform(-5, 5, size=[size, size]).astype(np.float32) - input_var = tf.Variable(var_data, name="var1", use_resource=True) - math_ops.matmul(input_tensor, input_var) - - out_name = ["MatMul:0"] - out_node = ["MatMul"] - in_name = ["Placeholder:0"] - in_node = ["Placeholder"] - in_data = [data] - - with tf.Session() as sess: - sess.run(variables.global_variables_initializer()) - - final_graph_def = sess.graph.as_graph_def(add_shapes=True) - tf_output = run_tf_graph(sess, in_data, in_name, out_name) - - shape_dict = {e: i.shape for e, i in zip(in_name, in_data)} - with pytest.raises(Exception) as execinfo: - with tvm.testing.disable_span_filling(): - mod, _ = relay.frontend.from_tensorflow( - final_graph_def, layout=None, shape=shape_dict, outputs=None - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow( - final_graph_def, layout=None, shape=shape_dict, outputs=None - ) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"]) - - assert execinfo.value.args[0].startswith("Graph is not frozen. Provide a frozen graph") - - # Now convert the variables to constant and run inference on the converted graph - final_graph_def = tf.graph_util.convert_variables_to_constants( - sess, - sess.graph.as_graph_def(add_shapes=True), - out_node, - ) - - tvm_output = run_tvm_graph( - final_graph_def, - in_data, - in_node, - target=target, - out_names=out_name, - num_output=len(out_name), - ) - for i, tf_out in enumerate(tf_output): - tvm.testing.assert_allclose(tf_out, tvm_output[i], atol=1e-4, rtol=1e-5) - - sess.close() - - -####################################################################### -# MatMul, BatchMatMul, BatchMatMulV2 -# ---------------------------------- - - -def _test_matmul(i, j, k, dtype, outer=None): - """One iteration of matmul""" - - A_shape_init = [i, j] - B_shape_init = [j, k] - - for transpose_a in [False, True]: - for transpose_b in [False, True]: - outer = outer or [] - A_shape = outer + (A_shape_init[::-1] if transpose_a else A_shape_init) - B_shape = outer + (B_shape_init[::-1] if transpose_b else B_shape_init) - - with tf.Graph().as_default(): - A = tf.placeholder(shape=A_shape, dtype=dtype, name="A") - B = tf.placeholder(shape=B_shape, dtype=dtype, name="B") - result = tf.matmul(A, B, transpose_a=transpose_a, transpose_b=transpose_b) - - A_np = np.random.uniform(high=5.0, size=A_shape).astype(dtype) - B_np = np.random.uniform(high=5.0, size=B_shape).astype(dtype) - compare_tf_with_tvm( - [A_np, B_np], [A.name, B.name], result.name, convert_config={"use_dense": True} - ) - compare_tf_with_tvm( - [A_np, B_np], [A.name, B.name], result.name, convert_config={"use_dense": False} - ) - - -def test_forward_matmul(): - """MatMul op test""" - _test_matmul(1, 3, 6, "int32") - _test_matmul(5, 3, 1, "float64") - - -def _test_batch_matmul(A_shape, B_shape, dtype, adjoint_a=False, adjoint_b=False): - - with tf.Graph().as_default(): - A = tf.placeholder(shape=A_shape, dtype=dtype, name="A") - B = tf.placeholder(shape=B_shape, dtype=dtype, name="B") - result = tf.matmul(A, B, adjoint_a=adjoint_a, adjoint_b=adjoint_b, name="batchmatmul") - - A_np = np.random.uniform(high=5.0, size=A_shape).astype(dtype) - B_np = np.random.uniform(high=5.0, size=B_shape).astype(dtype) - compare_tf_with_tvm( - [A_np, B_np], - [A.name, B.name], - result.name, - convert_config={"use_nt_batch_matmul": True}, - ) - compare_tf_with_tvm( - [A_np, B_np], - [A.name, B.name], - result.name, - convert_config={"use_nt_batch_matmul": False}, - ) - - -def _test_batch_matmul_dynamic( - A_shape, B_shape, A_np_shape, B_np_shape, dtype, adjoint_a=False, adjoint_b=False -): - with tf.Graph().as_default(): - A = tf.placeholder(shape=A_shape, dtype=dtype, name="A") - B = tf.placeholder(shape=B_shape, dtype=dtype, name="B") - result = tf.matmul(A, B, adjoint_a=adjoint_a, adjoint_b=adjoint_b, name="batchmatmul") - - A_np = np.random.uniform(high=5.0, size=A_np_shape).astype(dtype) - B_np = np.random.uniform(high=5.0, size=B_np_shape).astype(dtype) - # for now, in TOPI, only llvm & cublas's implementation support dynamic shape - # TODO add more backends support in TOPI - compare_tf_with_tvm( - [A_np, B_np], - [A.name, B.name], - result.name, - mode="vm", - targets=["llvm", "cuda -libs=cublas"], - convert_config={"use_nt_batch_matmul": True}, - ) - compare_tf_with_tvm( - [A_np, B_np], - [A.name, B.name], - result.name, - mode="vm", - targets=["llvm", "cuda -libs=cublas"], - convert_config={"use_nt_batch_matmul": False}, - ) - - -def test_forward_batch_matmul(): - """TF op BatchMatMul, BatchMatMulV2 test""" - _test_batch_matmul((3, 5, 4), (3, 4, 5), "int32") - _test_batch_matmul((3, 5, 4), (3, 4, 5), "float32", True, True) - _test_batch_matmul((3, 5, 4), (3, 5, 4), "int32", True, False) - _test_batch_matmul((3, 5, 4), (3, 5, 4), "float32", False, True) - _test_batch_matmul((2, 3, 4, 5, 6), (2, 3, 4, 6, 5), "int32") - _test_batch_matmul((1, 2, 3, 4, 5, 6), (1, 2, 3, 4, 6, 5), "float32", True, True) - _test_batch_matmul((3, 4, 5, 6), (3, 4, 5, 6), "int32", True, False) - _test_batch_matmul((2, 3, 4, 2, 3, 4, 5, 6), (2, 3, 4, 2, 3, 4, 5, 6), "float32", False, True) - _test_batch_matmul((1, 8, 64, 2), (2, 1), "float32", False, False) - _test_batch_matmul((1, 8, 8, 64), (64, 1), "float32", False, False) - _test_batch_matmul((1, 8, 64), (64, 1), "float32", False, False) - - -def test_forward_batch_matmul_dynamic(): - """Dynamic batch matmul""" - _test_batch_matmul_dynamic((None, 5, 4), (None, 4, 5), (3, 5, 4), (3, 4, 5), "int32") - _test_batch_matmul_dynamic( - (None, 5, 4), (None, 4, 5), (3, 5, 4), (3, 4, 5), "float32", True, True - ) - _test_batch_matmul_dynamic( - (None, 5, 4), (None, 5, 4), (3, 5, 4), (3, 5, 4), "int32", True, False - ) - _test_batch_matmul_dynamic( - (None, 5, 4), (None, 5, 4), (3, 5, 4), (3, 5, 4), "float32", False, True - ) - _test_batch_matmul_dynamic( - (None, 4, 5, 6), (None, 4, 6, 5), (3, 4, 5, 6), (3, 4, 6, 5), "float32" - ) - _test_batch_matmul_dynamic( - (None, None, 5, 6), (None, None, 6, 5), (3, 4, 5, 6), (3, 4, 6, 5), "float32" - ) - _test_batch_matmul_dynamic( - (None, None, None, 5, 6), - (None, None, None, 6, 5), - (2, 3, 4, 5, 6), - (2, 3, 4, 6, 5), - "float32", - ) - _test_batch_matmul_dynamic( - (None, None, None, 5, 6), - (6, None), - (2, 3, 4, 5, 6), - (6, 1), - "float32", - ) - _test_batch_matmul_dynamic( - (None, 5, 6), - (6, None), - (24, 5, 6), - (6, 1), - "float32", - ) - - -####################################################################### -# SparseTensorDenseMatMul -# ---------------------------------- - - -def _test_sparse_dense_matmul(indices, values, A_inp_shape, B_inp_shape, dtype, flip=False): - """One iteration of sparse_dense_matmul""" - - for adjoint_a in [False, True]: - for adjoint_b in [False, True]: - A_shape = A_inp_shape[::-1] if adjoint_a else A_inp_shape - B_shape = B_inp_shape[::-1] if adjoint_b else B_inp_shape - - with tf.Graph().as_default(): - A_sp = tf.sparse.SparseTensor(indices=indices, values=values, dense_shape=A_shape) - B = tf.placeholder(shape=B_shape, dtype=dtype, name="B") - - if flip: - result = tf.sparse.sparse_dense_matmul( - B, A_sp, adjoint_a=adjoint_b, adjoint_b=adjoint_a - ) - else: - result = tf.sparse.sparse_dense_matmul( - A_sp, B, adjoint_a=adjoint_a, adjoint_b=adjoint_b - ) - - B_np = np.random.uniform(high=5.0, size=B_shape).astype(dtype) - - compare_tf_with_tvm([B_np], [B.name], result.name) - - -def test_forward_sparse_dense_matmul(): - """sparse_dense_matmul op test""" - ################################################################### - # - # In order to create a SparseTensor, it requires 3 input as below: - # SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]) - # - # Above Sparse can be represented in Dense as below : - # [[1, 0, 0, 0] - # [0, 0, 2, 0] - # [0, 0, 0, 0]] - # - # ------------------------------------------------------------------ - - _test_sparse_dense_matmul([[0, 0], [1, 2]], [4.0, 8.0], [3, 4], [4, 3], "float32") - _test_sparse_dense_matmul([[0, 0], [1, 2]], [4.0, 8.0], [3, 3], [3, 3], "float32") - _test_sparse_dense_matmul([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], [5, 5], "float32") - _test_sparse_dense_matmul([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [7, 9], [9, 5], "float32") - _test_sparse_dense_matmul([[0, 0], [1, 2]], [4.0, 8.0], [4, 3], [3, 4], "float32", True) - _test_sparse_dense_matmul([[0, 0], [1, 2]], [4.0, 8.0], [3, 3], [3, 3], "float32", True) - _test_sparse_dense_matmul( - [[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], [5, 5], "float32", True - ) - _test_sparse_dense_matmul( - [[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [9, 5], [7, 9], "float32", True - ) - - -####################################################################### -# SparseFillEmptyRows -# ------------ - - -def _test_sparse_fill_empty_rows(indices_np, values_np, dense_shape_np, default_value_int, use_dyn): - with tf.Graph().as_default(): - if use_dyn: - indices = tf.placeholder(shape=(None, None), dtype=indices_np.dtype, name="indices") - values = tf.placeholder(shape=(None), dtype=values_np.dtype, name="values") - dense_shape = tf.placeholder( - shape=(None), dtype=dense_shape_np.dtype, name="dense_shape" - ) - else: - indices = tf.placeholder(shape=indices_np.shape, dtype=indices_np.dtype, name="indices") - values = tf.placeholder(shape=values_np.shape, dtype=values_np.dtype, name="values") - dense_shape = tf.placeholder( - shape=dense_shape_np.shape, dtype=dense_shape_np.dtype, name="dense_shape" - ) - - default_value = tf.placeholder(shape=(), dtype=values_np.dtype, name="default_value") - sp_input = tf.sparse.SparseTensor(indices=indices, values=values, dense_shape=dense_shape) - _ = tf.sparse.fill_empty_rows(sp_input, default_value, name="sparse_fill_empty_rows") - compare_tf_with_tvm( - [indices_np, values_np, dense_shape_np, default_value_int], - [indices.name, values.name, dense_shape.name, default_value.name], - [ - "sparse_fill_empty_rows/SparseFillEmptyRows:0", - "sparse_fill_empty_rows/SparseFillEmptyRows:1", - "sparse_fill_empty_rows/SparseFillEmptyRows:2", - ], - mode="vm", - ) - - -@pytest.mark.parametrize( - "sparse_indices_np, sparse_values_np, dense_shape_np, default_value_int", - [ - ( - np.array([[1, 1], [0, 3], [0, 1], [2, 0], [3, 1]], dtype=np.int64), - np.array([1, 2, 3, 4, 5], dtype=np.int64), - np.array([5, 6], dtype=np.int64), - 10, - ), - ( - np.array([[1, 1], [0, 3], [2, 0], [3, 1]], dtype=np.int64), - np.array([1, 2, 3, 4], dtype=np.int64), - np.array([5, 6], dtype=np.int64), - 10, - ), - ( - np.array([[0, 1], [0, 3], [2, 0], [3, 1]], dtype=np.int64), - np.array([1, 2, 3, 4], dtype=np.int64), - np.array([5, 6], dtype=np.int64), - 10, - ), - ( - np.array([[1, 1, 1], [1, 3, 1], [2, 0, 5], [3, 1, 6]], dtype=np.int64), - np.array([1, 2, 3, 4], dtype=np.int64), - np.array([7, 7, 7], dtype=np.int64), - 5, - ), - ( - np.array([[1], [2]], dtype=np.int64), - np.array([7, 8], dtype=np.int64), - np.array([5], dtype=np.int64), - 4, - ), - ( - np.ones((0, 1), dtype=np.int64), - np.array([], dtype=np.int64), - np.array([5], dtype=np.int64), - 4, - ), - ( - np.ones((0, 3), dtype=np.int64), - np.array([], dtype=np.int64), - np.array([9, 3, 7], dtype=np.int64), - 100, - ), - ], -) -@pytest.mark.parametrize("use_dyn", [True, False]) -def test_forward_sparse_fill_empty_rows( - sparse_indices_np, sparse_values_np, dense_shape_np, default_value_int, use_dyn -): - """sparse_fill_empty_rows op test""" - ################################################################### - # - # In order to create a SparseTensor, it requires 3 input as below: - # SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]) - # - # Above Sparse can be represented in Dense as below : - # [[1, 0, 0, 0] - # [0, 0, 2, 0] - # [0, 0, 0, 0]] - # - # ------------------------------------------------------------------ - _test_sparse_fill_empty_rows( - sparse_indices_np, sparse_values_np, dense_shape_np, default_value_int, use_dyn - ) - - -####################################################################### -# SparseReshape -# ------------ - - -def _test_sparse_reshape(indices_np, values_np, prev_shape_np, new_shape_np, use_dyn=False): - with tf.Graph().as_default(): - if use_dyn: - indices = tf.placeholder(shape=(None, None), dtype=indices_np.dtype, name="indices") - values = tf.placeholder(shape=(None), dtype=values_np.dtype, name="values") - prev_shape = tf.placeholder(shape=(None), dtype=prev_shape_np.dtype, name="prev_shape") - new_shape = tf.placeholder(shape=(None), dtype=new_shape_np.dtype, name="new_shape") - else: - indices = tf.placeholder(shape=indices_np.shape, dtype=indices_np.dtype, name="indices") - values = tf.placeholder(shape=values_np.shape, dtype=values_np.dtype, name="values") - prev_shape = tf.placeholder( - shape=prev_shape_np.shape, dtype=prev_shape_np.dtype, name="prev_shape" - ) - new_shape = tf.placeholder( - shape=new_shape_np.shape, dtype=new_shape_np.dtype, name="new_shape" - ) - sp_input = tf.sparse.SparseTensor(indices=indices, values=values, dense_shape=prev_shape) - - _ = tf.sparse.reshape(sp_input, new_shape, name="sparse_reshape") - compare_tf_with_tvm( - [indices_np, values_np, prev_shape_np, new_shape_np], - [indices.name, values.name, prev_shape.name, new_shape.name], - ["sparse_reshape:0", "sparse_reshape:1", "sparse_reshape/Identity:0"], - mode="vm", - ) - - -@pytest.mark.parametrize( - "sparse_indices_np, sparse_values_np, prev_shape_np, new_shape_np", - [ - ( - np.ones((0, 1), dtype=np.int64), - np.array([], dtype=np.int64), - np.array([4], dtype=np.int64), - np.array([2, -1], dtype=np.int64), - ), - ( - np.ones((0, 1), dtype=np.int64), - np.array([], dtype=np.int64), - np.array([4], dtype=np.int64), - np.array([2, 2], dtype=np.int64), - ), - ( - np.ones((0, 2), dtype=np.int64), - np.array([], dtype=np.int64), - np.array([3, 6], dtype=np.int64), - np.array([-1, 2], dtype=np.int64), - ), - ( - np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 2, 3]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([2, 3, 6], dtype=np.int64), - np.array([-1, 9], dtype=np.int64), - ), - ( - np.array( - [ - [0, 0, 0, 0, 0], - [0, 0, 1, 2, 3], - [0, 1, 0, 3, 5], - [1, 0, 0, 4, 6], - [1, 2, 3, 6, 8], - ], - dtype=np.int64, - ), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([2, 3, 6, 7, 9], dtype=np.int64), - np.array([9, -1, 7], dtype=np.int64), - ), - ( - np.array([[0, 0], [0, 1], [3, 4], [4, 3], [7, 3]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([9, 4], dtype=np.int64), - np.array([-1], dtype=np.int64), - ), - ( - np.array([[0], [5], [10], [20], [24]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([25], dtype=np.int64), - np.array([5, 5], dtype=np.int64), - ), - ( - np.array([[0, 100], [200, 100], [300, 400], [50, 20], [400, 50]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([500, 20], dtype=np.int64), - np.array([500, 20], dtype=np.int64), - ), - ( - np.array([[0, 100], [200, 100], [300, 400], [50, 20], [400, 50]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([500, 20], dtype=np.int64), - np.array([500, -1], dtype=np.int64), - ), - ( - np.array([[0, 100], [200, 100], [300, 400], [50, 20], [400, 50]], dtype=np.int64), - np.array([7, 5, 6, 3, 9], dtype=np.int64), - np.array([500, 20], dtype=np.int64), - np.array([250, 40], dtype=np.int64), - ), - ], -) -@pytest.mark.parametrize("use_dyn", [True, False]) -def test_forward_sparse_reshape( - sparse_indices_np, sparse_values_np, prev_shape_np, new_shape_np, use_dyn -): - """sparse_reshape op test""" - ################################################################### - # - # In order to create a SparseTensor, it requires 3 input as below: - # SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]) - # - # Above Sparse can be represented in Dense as below : - # [[1, 0, 0, 0] - # [0, 0, 2, 0] - # [0, 0, 0, 0]] - # - # ------------------------------------------------------------------ - _test_sparse_reshape(sparse_indices_np, sparse_values_np, prev_shape_np, new_shape_np, use_dyn) - - -####################################################################### -# Sparse Segment Variants -# ------------ - - -def _test_sparse_segment_variant( - tf_op, data_np, indices_np, segment_ids_np, num_segments, use_dyn=False -): - with tf.Graph().as_default(): - if use_dyn: - data = tf.placeholder( - shape=[None for _ in data_np.shape], dtype=data_np.dtype, name="data" - ) - indices = tf.placeholder(shape=[None], dtype=indices_np.dtype, name="indices") - segment_ids = tf.placeholder( - shape=(None), dtype=segment_ids_np.dtype, name="segment_ids" - ) - else: - data = tf.placeholder(shape=data_np.shape, dtype=data_np.dtype, name="data") - indices = tf.placeholder(shape=indices_np.shape, dtype=indices_np.dtype, name="indices") - segment_ids = tf.placeholder( - shape=segment_ids_np.shape, dtype=segment_ids_np.dtype, name="segment_ids" - ) - - _ = tf_op( - data, indices, segment_ids, num_segments=num_segments, name="sparse_segment_variant" - ) - compare_tf_with_tvm( - [data_np, indices_np, segment_ids_np], - [data.name, indices.name, segment_ids.name], - ["sparse_segment_variant:0"], - mode="vm", - ) - - -@pytest.mark.parametrize( - "data_np, indices_np, segment_ids_np, num_segments", - [ - ( - np.array([5, 1, 7, 2, 3, 4], dtype=np.float32), - np.array([0, 3, 4], dtype=np.int32), - np.array([0, 1, 1], dtype=np.int32), - None, - ), - ( - np.array([[1, 2, 3, 4], [-1, -2, -3, -4], [5, 6, 7, 8]], dtype=np.float64), - np.array([0, 1], dtype=np.int32), - np.array([0, 2], dtype=np.int32), - 4, - ), - ( - np.random.random((6, 4, 5)), - np.array([0, 2, 4, 3, 1], dtype=np.int32), - np.array([0, 0, 1, 5, 5], dtype=np.int32), - 100, - ), - ( - np.random.random((6, 4, 5)), - np.array([0, 2, 4, 3, 1], dtype=np.int32), - np.array([0, 0, 1, 5, 5], dtype=np.int32), - None, - ), - ( - np.array([[[1, 7]], [[3, 8]], [[2, 9]]], dtype=np.float64), - np.array([0, 1, 2], dtype=np.int32), - np.array([0, 0, 1], dtype=np.int32), - None, - ), - ( - np.random.random((9, 4, 5, 7)), - np.array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=np.int32), - np.array([0, 0, 1, 3, 5, 6, 7, 7, 8], dtype=np.int32), - 9, - ), - ( - np.random.random((9, 4, 5, 7)), - np.array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=np.int32), - np.array([0, 0, 1, 3, 5, 6, 7, 7, 8], dtype=np.int32), - None, - ), - ( - np.array([[1, 2, 3, 4], [-1, -2, -3, -4], [5, 6, 7, 8]], dtype=np.float64), - np.array([0, 1], dtype=np.int32), - np.array([0, 2], dtype=np.int32), - None, - ), - ( - np.random.random((9, 4, 5, 7)), - np.array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=np.int32), - np.array([0, 0, 1, 3, 5, 5, 5, 5, 5], dtype=np.int32), - 6, - ), - ], -) -@pytest.mark.parametrize("use_dyn", [True, False]) -@pytest.mark.parametrize( - "tf_op", - [ - tf.sparse.segment_sum, - tf.sparse.segment_sqrt_n, - tf.sparse.segment_mean, - ], -) -def test_forward_sparse_segment_sum_variants( - tf_op, - data_np, - indices_np, - segment_ids_np, - num_segments, - use_dyn, -): - """sparse segment sum variants tests""" - _test_sparse_segment_variant(tf_op, data_np, indices_np, segment_ids_np, num_segments, use_dyn) - - -####################################################################### -# Math SegmentSum -# ------------ - - -def _test_math_segment_sum(data_np, segment_ids_np, use_dyn=False): - with tf.Graph().as_default(): - if use_dyn: - data = tf.placeholder( - shape=[None for _ in data_np.shape], dtype=data_np.dtype, name="data" - ) - segment_ids = tf.placeholder( - shape=(None), dtype=segment_ids_np.dtype, name="segment_ids" - ) - else: - data = tf.placeholder(shape=data_np.shape, dtype=data_np.dtype, name="data") - segment_ids = tf.placeholder( - shape=segment_ids_np.shape, dtype=segment_ids_np.dtype, name="segment_ids" - ) - - _ = tf.math.segment_sum(data, segment_ids, name="segment_sum") - compare_tf_with_tvm( - [data_np, segment_ids_np], - [data.name, segment_ids.name], - ["segment_sum:0"], - mode="vm", - ) - - -@pytest.mark.parametrize( - "data_np, segment_ids_np", - [ - ( - np.array([5, 1, 7, 2, 3, 4], dtype=np.float32), - np.array([0, 0, 0, 1, 1, 1], dtype=np.int32), - ), - ( - np.array([[1, 2, 3, 4], [-1, -2, -3, -4], [5, 6, 7, 8]], dtype=np.float64), - np.array([0, 0, 1], dtype=np.int32), - ), - ( - np.random.random((6, 4, 5)), - np.array([0, 0, 1, 2, 2, 3], dtype=np.int64), - ), - ( - np.array([[[1, 7]], [[3, 8]], [[2, 9]]], dtype=np.float32), - np.array([0, 0, 1], dtype=np.int32), - ), - ( - np.random.random((9, 4, 5, 7)), - np.array([0, 0, 0, 1, 2, 3, 4, 4, 5], dtype=np.int64), - ), - ], -) -@pytest.mark.parametrize("use_dyn", [True, False]) -def test_forward_math_segment_sum(data_np, segment_ids_np, use_dyn): - """math segment sum test""" - _test_math_segment_sum(data_np, segment_ids_np, use_dyn) - - -# tensorflow.compat.v1.sparse_to_dense -# --------------- -def _test_sparse_to_dense(sparse_indices, sparse_values, default_value, output_shape): - with tf.Graph().as_default(): - indices = tf.placeholder( - shape=sparse_indices.shape, dtype=str(sparse_indices.dtype), name="indices" - ) - values = tf.placeholder( - shape=sparse_values.shape, dtype=str(sparse_values.dtype), name="values" - ) - oshape = tf.constant(output_shape, shape=output_shape.shape, dtype=str(output_shape.dtype)) - - # Output shape depends on a dynamic input, use VM. - if default_value is None: - output = tf.sparse_to_dense(indices, oshape, values) - compare_tf_with_tvm( - [sparse_indices, sparse_values], ["indices:0", "values:0"], output.name, mode="vm" - ) - else: - dv = tf.placeholder(shape=(), dtype=str(default_value.dtype), name="default_value") - output = tf.sparse_to_dense(indices, oshape, values, dv) - compare_tf_with_tvm( - [sparse_indices, sparse_values, default_value], - ["indices:0", "values:0", "default_value:0"], - output.name, - mode="vm", - ) - - -def test_forward_sparse_to_dense(): - """Sparse to dense""" - # scalar - _test_sparse_to_dense( - sparse_indices=np.int32(1), - sparse_values=np.int32(3), - default_value=np.int32(0), - output_shape=np.array([5]).astype("int32"), - ) - - # vector - _test_sparse_to_dense( - sparse_indices=np.array([0, 1, 4]).astype("int32"), - sparse_values=np.array([3, 3, 3]).astype("int32"), - default_value=np.int32(0), - output_shape=np.array([5]).astype("int32"), - ) - - # vector nXd - _test_sparse_to_dense( - sparse_indices=np.array([[0, 0], [1, 2]]).astype("int32"), - sparse_values=np.array([1, 2]).astype("int32"), - default_value=np.int32(0), - output_shape=np.array([3, 4]).astype("int32"), - ) - - _test_sparse_to_dense( - sparse_indices=np.array([[0, 0, 0], [1, 2, 3]]).astype("int32"), - sparse_values=np.array([1, 2]).astype("int32"), - default_value=np.int32(4), - output_shape=np.array([2, 3, 4]).astype("int32"), - ) - - # floats - _test_sparse_to_dense( - sparse_indices=np.array([0, 1, 4]).astype("int32"), - sparse_values=np.array([3.1, 3.1, 3.1]).astype("float32"), - default_value=np.float32(3.5), - output_shape=np.array([5]).astype("int32"), - ) - - # default value not specified - _test_sparse_to_dense( - sparse_indices=np.array([0, 1, 4]).astype("int32"), - sparse_values=np.array([3.1, 3.1, 3.1]).astype("float32"), - default_value=None, - output_shape=np.array([5]).astype("int32"), - ) - - -####################################################################### -# tensorflow.sparse.to_dense -# --------------- -def _test_sparse_to_dense_v2(indices, values, A_shape, dtype, default_value=None): - with tf.Graph().as_default(): - A_sp = tf.sparse.SparseTensor(indices=indices, values=values, dense_shape=A_shape) - - result = tf.sparse.to_dense(A_sp, default_value=default_value) - - # The output shape depends on a dynamic input, use VM. - compare_tf_with_tvm([], [], result.name, mode="vm") - - -def test_forward_sparse_to_dense_v2(): - _test_sparse_to_dense_v2([[1]], [3.0], [5], "float32") - _test_sparse_to_dense_v2([[1]], [3.0], [5], "float32", 0.3) - _test_sparse_to_dense_v2([[0, 0], [1, 2]], [4.0, 8.0], [3, 4], "float32") - _test_sparse_to_dense_v2([[0, 0], [1, 2]], [4.0, 8.0], [3, 4], "float32", 1.3) - _test_sparse_to_dense_v2([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], "float32") - _test_sparse_to_dense_v2([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], "float32", 1.9) - - -####################################################################### -# tensorflow.sparse.add -# ---------------------------------- - - -def _test_sparse_add(indices, values, A_shape, B_shape, dtype, flip=False): - """One iteration of tf.sparse.add""" - - # TODO(ANSHUMAN87): support cuda - # TODO(ANSHUMAN87): support both sparse input case - - with tf.Graph().as_default(): - A_sp = tf.sparse.SparseTensor( - indices=indices, values=np.array(values).astype(dtype), dense_shape=A_shape - ) - B = tf.placeholder(shape=B_shape, dtype=dtype, name="B") - - # TODO(ANSHUMAN87): support user input threashold values - if flip: - if package_version.parse(tf.VERSION) < package_version.parse("1.13.0"): - result = tf.sparse.add(B, A_sp, thresh=0) - else: - result = tf.sparse.add(B, A_sp, threshold=0) - else: - if package_version.parse(tf.VERSION) < package_version.parse("1.13.0"): - result = tf.sparse.add(A_sp, B, thresh=0) - else: - result = tf.sparse.add(A_sp, B, threshold=0) - - B_np = np.random.uniform(high=5.0, size=B_shape).astype(dtype) - - compare_tf_with_tvm([B_np], [B.name], result.name, no_gpu=True) - - -def test_sparse_add(): - """sparse.add op test""" - ################################################################### - # - # In order to create a SparseTensor, it requires 3 input as below: - # SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]) - # - # Above Sparse can be represented in Dense as below : - # [[1, 0, 0, 0] - # [0, 0, 2, 0] - # [0, 0, 0, 0]] - # - # ------------------------------------------------------------------ - for dtype_inp in ["float32", "float64", "int32"]: - _test_sparse_add([[0, 0], [1, 2]], [4.0, 8.0], [3, 4], [3, 4], dtype_inp) - _test_sparse_add([[0, 0], [1, 2]], [4.0, 8.0], [3, 4], [3, 4], dtype_inp, True) - _test_sparse_add([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], [5, 5], dtype_inp) - _test_sparse_add([[0, 0], [1, 3], [4, 3]], [3.0, 6.0, 9.0], [5, 5], [5, 5], dtype_inp, True) - - -####################################################################### -# StridedSlice -# ------------ - - -def _test_stridedslice( - ip_shape, - begin, - end, - stride, - dtype, - begin_mask=0, - end_mask=0, - new_axis_mask=0, - shrink_axis_mask=0, - ellipsis_mask=0, -): - """One iteration of a Stridedslice""" - - tf.reset_default_graph() - np_data = np.random.uniform(size=ip_shape).astype(dtype) - with tf.Graph().as_default(): - if len(ip_shape) == 0: # pylint: disable=len-as-condition - in_data = tf.constant(np_data, dtype) - else: - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - tf.strided_slice( - in_data, - begin, - end, - stride, - begin_mask=begin_mask, - end_mask=end_mask, - new_axis_mask=new_axis_mask, - shrink_axis_mask=shrink_axis_mask, - ellipsis_mask=ellipsis_mask, - name="strided_slice", - ) - if len(ip_shape) == 0: # pylint: disable=len-as-condition - compare_tf_with_tvm(None, "", "strided_slice:0") - else: - compare_tf_with_tvm(np_data, "in_data:0", "strided_slice:0") - - -def test_forward_stridedslice(): - """test StridedSlice""" - - _test_stridedslice([], [0], [0], [1], "float32", new_axis_mask=1) - _test_stridedslice([2], [1], [1], [1], "float32", shrink_axis_mask=1) - _test_stridedslice([4], [-1], [0], [1], "float32", shrink_axis_mask=1) - _test_stridedslice([2, 1], [0], [1], [1], "float32", shrink_axis_mask=1) - _test_stridedslice([2, 3, 4], [-2], [0], [1], "float32", shrink_axis_mask=8) - _test_stridedslice([2, 3, 4], [0], [1], [1], "float32", shrink_axis_mask=8) - _test_stridedslice([3, 4, 3], [1, -1, 0], [4, -5, 3], [2, -1, 1], "float32") - _test_stridedslice([3, 4, 3], [1, 0], [4, 3], [2, 1], "float32", ellipsis_mask=8) - _test_stridedslice([3, 4, 3], [1, 0], [4, 2], [2, 1], "float32", ellipsis_mask=2) - _test_stridedslice([3, 4, 5, 3], [1, 0], [4, 2], [2, 1], "float32", ellipsis_mask=2) - _test_stridedslice([3, 4, 5, 3], [1, 0, 1], [4, 2, 2], [2, 1, 1], "float32", ellipsis_mask=2) - _test_stridedslice([3, 4, 3], [1, 1, 0], [4, 4, 2], [2, 1, 1], "float32", new_axis_mask=5) - _test_stridedslice( - [3, 4, 3], [1, 1, 1], [4, 4, 1], [2, 1, 1], "float32", ellipsis_mask=2, new_axis_mask=4 - ) - _test_stridedslice( - [6, 4, 5], [1, 1, 1], [6, 3, 4], [2, 1, 1], "float32", ellipsis_mask=2, new_axis_mask=5 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 2], [4, 4, 3], [2, 1, 1], "float32", ellipsis_mask=4, new_axis_mask=2 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 2], [4, 4, 3], [2, 1, 1], "float32", ellipsis_mask=2, new_axis_mask=3 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 0], [4, 4, 1], [2, 1, 1], "float32", ellipsis_mask=2, new_axis_mask=3 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 2], [4, 4, 3], [2, 1, 1], "float32", ellipsis_mask=2, new_axis_mask=2 - ) - _test_stridedslice((3, 4), [1, 0], [4, 4], [1, 1], "float32", shrink_axis_mask=2) - _test_stridedslice( - [3, 4, 3], [1, 1, 0], [4, 4, 3], [2, 1, 1], "float32", shrink_axis_mask=2, new_axis_mask=2 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 0], [4, 4, 3], [2, 1, 1], "float32", shrink_axis_mask=1, new_axis_mask=2 - ) - _test_stridedslice( - [3, 4, 3], [1, 1, 0], [4, 4, 3], [2, 1, 1], "float32", shrink_axis_mask=2, new_axis_mask=1 - ) - _test_stridedslice( - [3, 4, 5, 4, 5, 6], [0, 0], [2, 3], [1, 1], "float32", shrink_axis_mask=5, new_axis_mask=1 - ) - _test_stridedslice( - [3, 4, 5, 4, 5, 6], - [0, 0, 1, 2, 1], - [2, 3, 4, 5, 3], - [1, 1, 2, 2, 1], - "float32", - shrink_axis_mask=5, - new_axis_mask=1, - ellipsis_mask=2, - begin_mask=8, - end_mask=8, - ) - _test_stridedslice( - [3, 4, 5, 4, 5, 6], - [0, 0, 1, 2, 1], - [2, 3, 4, 5, 3], - [1, 1, 2, 2, 1], - "float32", - shrink_axis_mask=8, - new_axis_mask=1, - ellipsis_mask=2, - begin_mask=5, - end_mask=5, - ) - _test_stridedslice( - [3, 4, 5, 4, 5, 6], - [0, 0, 1, 2, 1], - [2, 3, 4, 5, 3], - [1, 1, 2, 2, 1], - "float32", - shrink_axis_mask=16, - new_axis_mask=1, - ellipsis_mask=2, - begin_mask=5, - end_mask=5, - ) - _test_stridedslice( - [3, 4, 5, 4, 5, 6], - [1, 2, 0, -3], - [4, 5, 3, 3], - [2, 2, 1, 1], - "float32", - shrink_axis_mask=8, - new_axis_mask=1, - ellipsis_mask=2, - begin_mask=5, - end_mask=8, - ) - _test_stridedslice( - [1, 13, 13, 3, 2], - [0, 0], - [1, 1], - [1, -1], - "float32", - ellipsis_mask=1, - begin_mask=2, - end_mask=2, - ) - - -####################################################################### -# FloorDiv, RealDiv -# ----------------- -def _test_forward_divide(ip_shape, dtype): - np_numer = np.random.uniform(-100, 100, size=ip_shape).astype(dtype) - np_denomin = np.random.uniform(1, 100, size=ip_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - numerator = tf.placeholder(dtype, ip_shape, name="numer") - denominator = tf.placeholder(dtype, ip_shape, name="denomin") - tf.math.divide(numerator, denominator, name="RealDiv") - compare_tf_with_tvm([np_numer, np_denomin], ["numer:0", "denomin:0"], "RealDiv:0") - - -def _test_forward_floordiv(ip_shape, dtype): - np_numer = np.random.uniform(1, 100, size=ip_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - numerator = tf.placeholder(dtype, ip_shape, name="numer") - tf.math.floordiv(numerator, tf.constant(5, dtype=dtype), name="FloorDiv") - compare_tf_with_tvm([np_numer], ["numer:0"], "FloorDiv:0") - - -def test_forward_divide(): - """test FloorDiv, RealDiv""" - _test_forward_divide((4,), "int32") - _test_forward_divide((4, 3, 7), "float32") - _test_forward_floordiv((4, 3, 7), "float32") - _test_forward_floordiv((4, 3, 7), "int32") - - -####################################################################### -# FloorMod -# -------- -def _test_forward_floormod(in_shape, if_shape, dtype): - np_numer = np.random.uniform(1, 100, size=in_shape).astype(dtype) - np_factor = np.random.uniform(1, 100, size=if_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - numerator = tf.placeholder(dtype, in_shape, name="numer") - factor = tf.placeholder(dtype, if_shape, name="factor") - tf.floormod(numerator, factor, name="FloorMod") - compare_tf_with_tvm([np_numer, np_factor], ["numer:0", "factor:0"], "FloorMod:0") - - -def test_forward_floormod(): - """test FloorMod""" - _test_forward_floormod((10,), (10,), "float32") - _test_forward_floormod((8, 2), (1,), "float32") - _test_forward_floormod((4, 3, 7), (4, 3, 7), "float32") - _test_forward_floormod((4, 3, 7), (4, 3, 7), "int32") - - -####################################################################### -# TruncateMod -# ----------- -def _test_forward_truncatemod(ip_shape, dtype): - np_data_1 = np.random.uniform(-100, 100, size=ip_shape).astype(dtype) - np_data_2 = np.random.uniform(1, 10, size=ip_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data_1 = tf.placeholder(dtype, ip_shape, name="in_data_1") - in_data_2 = tf.placeholder(dtype, ip_shape, name="in_data_2") - tf.truncatemod(in_data_1, in_data_2, name="truncatemod") - compare_tf_with_tvm([np_data_1, np_data_2], ["in_data_1:0", "in_data_2:0"], "truncatemod:0") - - -def test_forward_truncatemod(): - """test TruncateMod""" - _test_forward_truncatemod((4, 3, 7), "int32") - - -####################################################################### -# Gather, GatherV2 -# -------------------------- - - -def _test_gather(ip_shape, indice_shape, indice_value, axis, batch_dims, dtype): - """One iteration of a GatherV2""" - - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - indices = tf.placeholder("int32", indice_shape, name="indices") - out = tf.gather(in_data, indices, axis=axis, batch_dims=batch_dims) - np_data = np.random.uniform(1, 10, size=ip_shape).astype(dtype) - - def _fill_indices(indice_value): - indices = np.array(ip_shape, dtype=dtype) - if isinstance(indice_value, int): - indices = np.array([indice_value], dtype="int32") - else: - indices = np.asarray(indice_value, dtype="int32") - return indices - - np_indices = _fill_indices(indice_value) - compare_tf_with_tvm([np_data, np_indices], ["in_data:0", "indices:0"], out.name) - - -def test_forward_gather(): - """test Gather/GatherV2 layer""" - _test_gather((4,), (1,), 1, 0, 1, "int32") - _test_gather((4,), (1,), 1, 0, 0, "float32") - _test_gather((1, 4), (1,), [0], 0, 0, "int32") - _test_gather((4,), (1, 2, 2), [[[1, 0], [0, 1]]], 0, 0, "float32") - _test_gather((2, 2), (1, 2, 2), [[[1, 0], [0, 1]]], 0, 0, "int32") - _test_gather((2, 2), (1, 2, 2), [[[1, 0], [0, 1]]], 1, 0, "int32") - _test_gather((2, 2), (1, 2, 2), [[[1, 0], [0, 1]]], 0, 0, "float32") - _test_gather((3, 3, 3), (1, 1, 2), [[[1, 0]]], 0, 0, "int32") - _test_gather((3, 3, 3), (1, 1, 2), [[[1, 0]]], 2, 0, "int32") - _test_gather((4, 3, 5, 6), (1, 4), [[2, 1, 0, 0]], 0, 0, "float32") - _test_gather((2, 2), (2, 2), [[0, 0], [0, 0]], 1, 1, "float32") - _test_gather( - (2, 2, 3, 6), (2, 2, 3), [[[1, 1, 0], [0, 0, 1]], [[0, 1, 0], [1, 0, 1]]], 2, 2, "float32" - ) - _test_gather( - (2, 2, 3, 6), (2, 2, 3), [[[1, 1, 0], [0, 0, 1]], [[0, 1, 0], [1, 0, 1]]], 3, 1, "float32" - ) - _test_gather( - (2, 2, 3, 6), (2, 2, 3), [[[1, 1, 0], [0, 0, 1]], [[0, 1, 0], [1, 0, 1]]], 3, 2, "float32" - ) - _test_gather( - (2, 2, 3, 6), (2, 2, 3), [[[1, 1, 0], [0, 0, 1]], [[0, 1, 0], [1, 0, 1]]], 3, 0, "float32" - ) - - -####################################################################### -# GatherND -# -------------------------- - - -def _test_gather_nd(ip_shape, indice_value, dtype): - """test operator GatherNd""" - np_data = np.random.uniform(1, 100, size=ip_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - tf.gather_nd(in_data, indices=indice_value, name="gather_nd") - compare_tf_with_tvm([np_data], ["in_data:0"], "gather_nd:0") - - -def test_forward_gather_nd(): - """test operator GatherNd""" - _test_gather_nd((2, 2), [[0, 0], [1, 1]], "float32") - _test_gather_nd((2, 2, 2), [[1, 0, 0], [0, 0, 0]], "float32") - _test_gather_nd((4,), [1], "float32") - _test_gather_nd((4,), [1], "int32") - _test_gather_nd((1, 4), [0, 3], "int32") - _test_gather_nd((2, 2), [[[1, 0], [0, 1]]], "int32") - _test_gather_nd((2, 2), [[[1, 0], [0, 1]]], "float32") - _test_gather_nd((3, 3, 3), [[[1, 0]]], "int32") - _test_gather_nd((3, 3, 3), [[[1, 0]]], "int32") - _test_gather_nd((4, 3, 5, 6), [[2, 1, 0, 0]], "float32") - _test_gather_nd((3, 3, 3), [[[2, 1]]], "int32") - - -####################################################################### -# BiasAdd -# ------- -def test_forward_bias_add(): - """test Op BiasAdd""" - - def check_bias_add(lh_shpae, rh_shape, dtype): - tf.reset_default_graph() - lh_data = np.random.uniform(size=lh_shpae).astype(dtype) - rh_data = np.random.uniform(size=rh_shape).astype(dtype) - with tf.Graph().as_default(): - lft_data = tf.placeholder(dtype, name="lft_data") - rgt_data = tf.placeholder(dtype, name="rgt_data") - tf.nn.bias_add(lft_data, rgt_data, name="BiasAdd") - compare_tf_with_tvm([lh_data, rh_data], ["lft_data:0", "rgt_data:0"], "BiasAdd:0") - - check_bias_add((10, 8, 16, 32), (32,), dtype="int32") - check_bias_add((10, 20), (20,), dtype="float32") - - -####################################################################### -# Split -# ----- - - -def _test_split(in_shape, axis, num_or_size_splits, dtype): - """One iteration of a Split""" - np_data = np.random.uniform(-5, 5, size=in_shape).astype(dtype) - - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - _ = len(num_or_size_splits) if isinstance(num_or_size_splits, list) else num_or_size_splits - split = tf.split(in_data, num_or_size_splits, axis=axis) - relu = [tf.nn.relu(i) for i in split] - - compare_tf_with_tvm([np_data], ["in_data:0"], [n.name for n in relu]) - - # and now test together with concat - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - splitted = tf.split(in_data, num_or_size_splits, axis=axis) - concat = tf.concat(splitted, axis) - compare_tf_with_tvm([np_data], "in_data:0", concat.name) - - -def test_forward_split(): - """test split layer""" - # rank 1 - _test_split((3,), 0, 1, "float32") - _test_split((3,), 0, 3, "float32") - _test_split((6,), 0, 3, "float32") - # rank 2 - _test_split((6, 2), 0, 3, "float32") - _test_split((2, 6), 1, 6, "float32") - # rank 3 - _test_split((6, 2, 4), 0, 2, "int32") - _test_split((2, 6, 4), 1, 3, "float32") - _test_split((2, 4, 6), 2, 1, "float32") - # rank 4 - _test_split((6, 1, 3, 5), 0, 3, "float32") - _test_split((1, 6, 3, 5), 1, 3, "float32") - _test_split((1, 3, 6, 5), 2, 3, "float32") - _test_split((1, 3, 5, 6), 3, 3, "float32") - # split along negative axis - _test_split((6, 1, 3, 5), -4, 3, "float32") - _test_split((1, 6, 3, 5), -3, 3, "float32") - _test_split((1, 3, 6, 5), -2, 3, "float32") - _test_split((1, 3, 5, 6), -1, 3, "float32") - # size_splits list - _test_split((6,), 0, [1, 2, 3], "int32") - _test_split((3, 6, 4), -2, [1, 4, 1], "float32") - - -###################################################################### -# TopKV2 -# ------ - - -def _test_forward_top_k_v2(in_shape, k): - np_data = np.random.uniform(-100, 100, size=in_shape).astype("float32") - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder("float32", in_shape, name="in_data") - tf.math.top_k(in_data, k, name="TopK") - compare_tf_with_tvm([np_data], ["in_data:0"], "TopK:0") - - -def test_forward_top_k_v2(): - _test_forward_top_k_v2((3,), 1) - _test_forward_top_k_v2((3,), 3) - _test_forward_top_k_v2((3, 5, 7), 3) - _test_forward_top_k_v2((3, 5, 7), 3) - - -####################################################################### -# Unstack -# ------- - - -def _test_unstack(ip_shape, axis, dtype): - np_data = np.random.uniform(-5, 5, size=ip_shape).astype(dtype) - - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - unstack = tf.unstack(in_data, axis=axis) - - compare_tf_with_tvm([np_data], ["in_data:0"], [n.name for n in unstack]) - - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - tf.stack(tf.unstack(in_data, axis=axis), axis=axis) - - compare_tf_with_tvm([np_data], ["in_data:0"], "stack:0") - - -def test_forward_unstack(): - """test unstack layer""" - _test_unstack((6,), 0, "int32") - _test_unstack((2, 6), 1, "float64") - # negative axis - _test_unstack((1, 4), -1, "int32") - _test_unstack((3, 6, 4), -2, "float32") - - -####################################################################### -# Tile -# ---- - - -def _test_tile(in_shape, multiples, dtype): - np_data = np.random.uniform(-5, 5, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - tf.tile(in_data, multiples=multiples, name="tile") - compare_tf_with_tvm([np_data], ["in_data:0"], "tile:0") - - -def test_forward_tile(): - """test Tile""" - _test_tile((2,), (3,), "int32") - _test_tile((2, 2), (2, 3), "float32") - _test_tile((2, 4, 6), (6, 7, 8), "float64") - - -####################################################################### -# ClipByValue -# ----------- - - -def _test_forward_clip_by_value(ip_shape, clip_value_min, clip_value_max, dtype): - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - tf.clip_by_value(in_data, clip_value_min, clip_value_max, name="ClipByValue") - np_data = np.random.uniform(-100, 100, size=ip_shape).astype(dtype) - compare_tf_with_tvm([np_data], ["in_data:0"], "ClipByValue:0") - - -def test_forward_clip_by_value(): - """test ClipByValue op""" - if package_version.parse(tf.__version__) < package_version.parse("1.9"): - _test_forward_clip_by_value((4,), 0.1, 5.0, "float32") - _test_forward_clip_by_value((4, 4), 1, 5, "int32") - - -####################################################################### -# Multi Input to graph -# -------------------- - - -def test_forward_multi_input(): - """Multi Input""" - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.int32, shape=[3, 3], name="in1") - in2 = tf.placeholder(tf.int32, shape=[3, 3], name="in2") - in3 = tf.placeholder(tf.int32, shape=[3, 3], name="in3") - in4 = tf.placeholder(tf.int32, shape=[3, 3], name="in4") - - out1 = tf.add(in1, in2, name="out1") - out2 = tf.subtract(in3, in4, name="out2") - _ = tf.multiply(out1, out2, name="out") - in_data = np.arange(9, dtype="int32").reshape([3, 3]) - - compare_tf_with_tvm( - [in_data, in_data, in_data, in_data], ["in1:0", "in2:0", "in3:0", "in4:0"], "out:0" - ) - - -####################################################################### -# Multi Output to Graph -# --------------------- - - -def test_forward_multi_output(): - """Multi Output""" - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.int32, shape=[3, 3], name="in1") - in2 = tf.placeholder(tf.int32, shape=[3, 3], name="in2") - in3 = tf.placeholder(tf.int32, shape=[3, 3], name="in3") - in4 = tf.placeholder(tf.int32, shape=[3, 3], name="in4") - - _ = tf.add(in1, in2, name="out1") - _ = tf.subtract(in3, in4, name="out2") - in_data = np.arange(9, dtype="int32").reshape([3, 3]) - in_data = [in_data] * 4 - in_name = ["in1:0", "in2:0", "in3:0", "in4:0"] - out_name = ["out1:0", "out2:0"] - out_node = [out.strip(":0") for out in out_name] - in_node = [inp.strip(":0") for inp in in_name] - - with tf.Session() as sess: - final_graph_def = tf.graph_util.convert_variables_to_constants( - sess, - sess.graph.as_graph_def(add_shapes=True), - out_node, - ) - tf_output = run_tf_graph(sess, in_data, in_name, out_name) - tvm_output = run_tvm_graph( - final_graph_def, in_data, in_node, target="llvm", out_names=out_node, num_output=2 - ) - for i, tf_out in enumerate(tf_output): - tvm.testing.assert_allclose(tf_out, tvm_output[i], atol=1e-5, rtol=1e-5) - - -####################################################################### -# Resize Bilinear, Nearest_Neighbor -# --------------------------------- - - -def _test_resize_bilinear(in_shape, to_shape, align_corners): - """One iteration of resize bilinear""" - - data = np.random.uniform(size=in_shape).astype("float32") - shape_data = np.array(to_shape).astype("int32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - shape_data = constant_op.constant( - shape_data, shape=shape_data.shape, dtype=shape_data.dtype - ) - tf.image.resize_bilinear(in_data, shape_data, align_corners=align_corners) - - compare_tf_with_tvm(data, "Placeholder:0", "ResizeBilinear:0") - - -def _test_resize_bilinear_from_tensor(in_shape, align_corners): - """One iteration of resize bilinear with non-constant output shape, requires - value inference to get proper output shape.""" - - data = np.random.uniform(size=in_shape).astype("float32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder( - shape=[in_shape[0], None, None, in_shape[3]], dtype=data.dtype - ) - to_shape = tf.shape(in_data)[1:3] - tf.image.resize_bilinear(in_data, to_shape, align_corners=align_corners) - - compare_tf_with_tvm(data, "Placeholder:0", "ResizeBilinear:0") - - -def _test_resize_nearest_neighbor(in_shape, to_shape): - """One iteration of resize nearest neighbor""" - - data = np.random.uniform(size=in_shape).astype("float32") - shape_data = np.array(to_shape).astype("int32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - shape_data = constant_op.constant( - shape_data, shape=shape_data.shape, dtype=shape_data.dtype - ) - tf.image.resize_nearest_neighbor(in_data, shape_data, name="resize_nearest_neighbor") - - compare_tf_with_tvm(data, "Placeholder:0", "resize_nearest_neighbor:0") - - -def _test_resize_nearest_neighbor_dynamic_shape(in_shape, scale): - """One iteration of resize nearest neighbor for graph with dynamic input shape""" - - data = np.random.uniform(size=in_shape).astype("float32") - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=None, dtype=data.dtype) - # multiply input shape by scale factor - new_shape = tf.shape(in_data)[1:3] * tf.constant(scale, dtype=tf.int32) - tf.image.resize_nearest_neighbor(in_data, new_shape, name="resize_nearest_neighbor") - - compare_tf_with_tvm(data, "Placeholder:0", "resize_nearest_neighbor:0") - - -def test_forward_resize(): - """Resize Bilinear, Nearest_Neighbor""" - # TF default layout is NHWC - _test_resize_bilinear((4, 32, 32, 3), [50, 50], False) - _test_resize_bilinear((6, 32, 32, 3), [20, 20], True) - _test_resize_bilinear_from_tensor((4, 32, 32, 3), False) - _test_resize_bilinear_from_tensor((6, 50, 50, 3), True) - _test_resize_nearest_neighbor((6, 32, 32, 3), [20, 20]) - _test_resize_nearest_neighbor_dynamic_shape((1, 16, 16, 3), scale=[2, 2]) - - -####################################################################### -# BroadcastArgs -# ----------- - - -def _test_broadcast_args(in_shape_1, in_shape_2): - """One iteration of broadcast_args""" - - shape_1 = np.array(in_shape_1).astype("int32") - shape_2 = np.array(in_shape_2).astype("int32") - - with tf.Graph().as_default(): - shape_1 = constant_op.constant(shape_1, shape=shape_1.shape, dtype=shape_1.dtype) - shape_2 = constant_op.constant(shape_2, shape=shape_2.shape, dtype=shape_2.dtype) - tf.raw_ops.BroadcastArgs(s0=shape_1, s1=shape_2) - - compare_tf_with_tvm(None, "", "BroadcastArgs:0", opt_level=0) - - -def test_forward_broadcast_args(): - """Resize Bilinear""" - - _test_broadcast_args((4, 1, 32, 32), [4, 8, 32, 32]) - _test_broadcast_args((6, 32, 32, 1), [6, 32, 32, 16]) - _test_broadcast_args((32, 32, 16), [6, 32, 32, 16]) - - -####################################################################### -# BroadcastTo -# ----------- - - -def _test_broadcast_to(in_shape, to_shape): - """One iteration of broadcast_to""" - - data = np.random.uniform(size=in_shape).astype("float32") - shape_data = np.array(to_shape).astype("int32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - shape_data = constant_op.constant( - shape_data, shape=shape_data.shape, dtype=shape_data.dtype - ) - tf.broadcast_to(in_data, shape_data) - - compare_tf_with_tvm(data, "Placeholder:0", "BroadcastTo:0", opt_level=0) - - -def _test_broadcast_to_from_tensor(in_shape): - """One iteration of broadcast_to with unknown shape at graph build""" - - data = np.random.uniform(size=in_shape).astype("float32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=[None], dtype=data.dtype) - - shape_data = tf.multiply(tf.shape(in_data), 32) - tf.broadcast_to(in_data, shape_data) - - compare_tf_with_tvm(data, "Placeholder:0", "BroadcastTo:0") - - -def test_forward_broadcast_to(): - """Resize Bilinear""" - - _test_broadcast_to((4, 1, 32, 32), [4, 8, 32, 32]) - _test_broadcast_to((6, 32, 32, 1), [6, 32, 32, 16]) - _test_broadcast_to_from_tensor((1)) - - -####################################################################### -# Fill -# ---- - - -def _test_fill(in_shape): - """Use the fill op to create a tensor of ones with non-constant shape.""" - - with tf.Graph().as_default(): - tf.ones(shape=in_shape, dtype="float32") - compare_tf_with_tvm(in_shape, [], "ones:0", opt_level=1) - - -def _test_fill_from_tensor(in_shape): - """Use the fill op to create a tensor of ones with non-constant shape. - Some extra ops need to be added here to prevent the graph from - being fully constant and folded away.""" - - data = np.random.uniform(size=in_shape).astype("float32") - - with tf.Graph().as_default(): - in_data = array_ops.placeholder( - shape=[in_shape[0], in_shape[1], None, None], dtype=data.dtype - ) - - x = tf.ones(shape=2 * tf.shape(in_data), dtype=data.dtype) - _ = tf.math.add(in_data, tf.reduce_mean(x), name="out1") - compare_tf_with_tvm(data, "Placeholder:0", "out1:0") - - -def _test_fill_symbolic_inputs(in_shape_data, in_value_data, dtype): - with tf.Graph().as_default(): - in_shape = tf.placeholder(shape=[in_shape_data.shape[0]], dtype=in_shape_data.dtype) - in_value = tf.placeholder(shape=(), dtype=dtype) - out = tf.fill(in_shape, in_value) - for mode in ["debug", "vm"]: - compare_tf_with_tvm( - [in_shape_data, in_value_data], [in_shape.name, in_value.name], out.name, mode=mode - ) - - -def test_forward_fill(): - """Resize Bilinear""" - - _test_fill((32)) - _test_fill((6, 32, 64, 64)) - _test_fill_from_tensor((6, 32, 64, 64)) - _test_fill_symbolic_inputs(np.array((2,)), np.int32(9), tf.int32) - _test_fill_symbolic_inputs(np.array((2, 3)), 9, tf.int64) - _test_fill_symbolic_inputs(np.array((2, 3, 4)), np.float32(9.0), tf.float32) - - -####################################################################### -# Crop to bounding box -# -------------------- - - -def _test_crop(in_shape, off_h, off_w, tar_h, tar_w): - """Crop to bounding box""" - data = np.random.uniform(size=in_shape).astype("float32") - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - tf.image.crop_to_bounding_box(in_data, off_h, off_w, tar_h, tar_w) - compare_tf_with_tvm(data, "Placeholder:0", "crop_to_bounding_box/Slice:0") - - -def test_forward_crop(): - """Crop to bounding box""" - _test_crop((1, 224, 224, 3), 20, 20, 120, 120) - - -####################################################################### -# CropAndResize -# ------------- - - -def _test_forward_crop_and_resize( - img_shape, - boxes, - box_idx, - crop_size, - extrapolation_value=0.0, - method="bilinear", - dtype="float32", - atol=1e-4, - rtol=1e-4, -): - image = np.random.uniform(0, 10, size=img_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = array_ops.placeholder(dtype, image.shape, name="in_data") - tf.image.crop_and_resize( - in_data, - boxes=boxes, - box_ind=box_idx, - crop_size=crop_size, - method=method, - extrapolation_value=extrapolation_value, - name="crop_and_resize", - ) - compare_tf_with_tvm([image], ["in_data:0"], "crop_and_resize:0", atol=atol, rtol=rtol) - - -def test_forward_crop_and_resize(): - """CropAndResize""" - _test_forward_crop_and_resize([1, 6, 6, 3], [[0, 0, 1, 1]], [0], [3, 3]) - _test_forward_crop_and_resize([1, 6, 6, 3], [[0, 0, 1, 1]], [0], [3, 3], 0.2) - _test_forward_crop_and_resize([1, 6, 6, 3], [[0, 0, 1, 1]], [0], [3, 3], 0.2, "nearest") - _test_forward_crop_and_resize([1, 11, 11, 3], [[0.3, 0.3, 1, 1]], [0], [21, 21]) - _test_forward_crop_and_resize([1, 41, 41, 3], [[0.2, 0.4, 0.8, 0.8]], [0], [21, 11]) - _test_forward_crop_and_resize([1, 100, 100, 3], [[0, 0, 0.9, 0.9]], [0], [30, 30]) - _test_forward_crop_and_resize([1, 249, 249, 3], [[0, 0, 1, 1]], [0], [9, 9]) - _test_forward_crop_and_resize([1, 201, 301, 3], [[0.2, 0.3, 0.7, 0.8]], [0], [51, 51]) - _test_forward_crop_and_resize( - img_shape=[10, 11, 11, 3], - boxes=[[0, 0, 0.9, 0.9], [0.2, 0.2, 0.8, 0.8]], - box_idx=[0, 1], - crop_size=[5, 5], - ) - - if platform.machine() == "aarch64": - pytest.skip("Currently failing on AArch64") - _test_forward_crop_and_resize([1, 224, 224, 3], [[0.1, 0.2, 1, 1]], [0], [9, 9]) - _test_forward_crop_and_resize( - img_shape=[20, 576, 576, 3], - boxes=[[0, 0, 1, 1], [0, 0, 0.8, 0.8], [0.1, 0.2, 0.9, 1], [0.2, 0, 1, 1]], - box_idx=[1, 0, 2, 3], - crop_size=[24, 24], - extrapolation_value=0.3, - atol=1e-3, - rtol=1e-3, - ) - _test_forward_crop_and_resize( - img_shape=[20, 229, 229, 3], - boxes=[[0, 0, 0.9, 0.9], [0.3, 0.3, 1, 1], [0.2, 0.1, 0.7, 0.8], [0, 0, 1, 1]], - box_idx=[3, 0, 2, 1], - crop_size=[58, 58], - extrapolation_value=0.2, - method="nearest", - atol=1e-3, - rtol=1e-3, - ) - - -####################################################################### -# Non Max Suppression -# ------------------- -def _test_forward_nms_v3( - bx_shape, score_shape, iou_threshold, score_threshold, out_size, dtype="float32" -): - boxes = np.random.uniform(0, 10, size=bx_shape).astype(dtype) - scores = np.random.uniform(size=score_shape).astype(dtype) - max_output_size = np.int32(out_size) - tf.reset_default_graph() - in_data_1 = tf.placeholder(dtype, boxes.shape, name="in_data_1") - in_data_2 = tf.placeholder(dtype, scores.shape, name="in_data_2") - in_data_3 = tf.placeholder(tf.int32, name="in_data_3") - tf.image.non_max_suppression( - boxes=in_data_1, - scores=in_data_2, - max_output_size=in_data_3, - iou_threshold=iou_threshold, - score_threshold=score_threshold, - name="nms", - ) - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - "nms/NonMaxSuppressionV3:0", - mode="vm", - ) - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - "nms/NonMaxSuppressionV3:0", - mode="debug", - ) - - -def _test_forward_nms_v4( - bx_shape, score_shape, iou_threshold, score_threshold, out_size, dtype="float32" -): - boxes = np.random.uniform(0, 10, size=bx_shape).astype(dtype) - scores = np.random.uniform(size=score_shape).astype(dtype) - max_output_size = np.int32(out_size) - tf.reset_default_graph() - in_data_1 = tf.placeholder(dtype, boxes.shape, name="in_data_1") - in_data_2 = tf.placeholder(dtype, scores.shape, name="in_data_2") - in_data_3 = tf.placeholder(tf.int32, name="in_data_3") - indices_padded, num_valid = tf.image.non_max_suppression_padded( - boxes=in_data_1, - scores=in_data_2, - max_output_size=in_data_3, - iou_threshold=iou_threshold, - score_threshold=score_threshold, - name="nms", - pad_to_max_output_size=True, - ) - num_valid = tf.reshape(num_valid, shape=(-1,)) - indices_padded = tf.reshape(indices_padded, shape=(-1,)) - tf.slice(indices_padded, tf.constant([0]), num_valid, name="SlicedIndices") - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - ["nms/NonMaxSuppressionV4:1", "SlicedIndices:0"], - mode="vm", - ) - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - ["nms/NonMaxSuppressionV4:1", "SlicedIndices:0"], - mode="debug", - ) - - -def _test_forward_nms_v5( - bx_shape, score_shape, iou_threshold, score_threshold, out_size, dtype="float32" -): - boxes = np.random.uniform(0, 10, size=bx_shape).astype(dtype) - scores = np.random.uniform(size=score_shape).astype(dtype) - max_output_size = np.int32(out_size) - tf.reset_default_graph() - in_data_1 = tf.placeholder(dtype, boxes.shape, name="in_data_1") - in_data_2 = tf.placeholder(dtype, scores.shape, name="in_data_2") - in_data_3 = tf.placeholder(tf.int32, name="in_data_3") - tf.image.non_max_suppression_with_scores( - boxes=in_data_1, - scores=in_data_2, - max_output_size=in_data_3, - iou_threshold=iou_threshold, - score_threshold=score_threshold, - name="nms", - ) - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - ["nms/NonMaxSuppressionV5:0", "nms/NonMaxSuppressionV5:1"], - mode="vm", - ) - - -def test_forward_nms(): - """NonMaxSuppressionV3,5""" - for _test_forward_nms in [_test_forward_nms_v3, _test_forward_nms_v5]: - _test_forward_nms((5, 4), (5,), 0.7, 0.5, 5) - _test_forward_nms((20, 4), (20,), 0.5, 0.6, 10) - _test_forward_nms((1000, 4), (1000,), 0.3, 0.7, 1000) - _test_forward_nms((2000, 4), (2000,), 0.4, 0.6, 7) - - -def _test_forward_combined_nms( - bx_shape, - score_shape, - iou_threshold, - score_threshold, - out_size, - total_size, - clip_boxes=False, - dtype="float32", -): - def get_random_scores(size, dtype): - size1d = np.prod(size) - scores = np.linspace(0, 1, num=size1d) - np.random.shuffle(scores) - return scores.reshape(size).astype(dtype) - - boxes = np.random.uniform(-1, 2, size=bx_shape).astype(dtype) - scores = get_random_scores(score_shape, dtype) - max_output_size = np.int32(out_size) - tf.reset_default_graph() - in_data_1 = tf.placeholder(dtype, boxes.shape, name="in_data_1") - in_data_2 = tf.placeholder(dtype, scores.shape, name="in_data_2") - in_data_3 = tf.placeholder(tf.int32, name="in_data_3") - tf.image.combined_non_max_suppression( - boxes=in_data_1, - scores=in_data_2, - max_output_size_per_class=in_data_3, - max_total_size=total_size, - iou_threshold=iou_threshold, - score_threshold=score_threshold, - pad_per_class=False, - clip_boxes=clip_boxes, - name="nms", - ) - compare_tf_with_tvm( - [boxes, scores, max_output_size], - ["in_data_1:0", "in_data_2:0", "in_data_3:0"], - [ - "nms/CombinedNonMaxSuppression:0", - "nms/CombinedNonMaxSuppression:1", - "nms/CombinedNonMaxSuppression:2", - "nms/CombinedNonMaxSuppression:3", - ], - ) - - -def test_forward_combined_nms(): - """CombinedNonMaxSuppression""" - _test_forward_combined_nms((1, 64, 1, 4), (1, 64, 1), 0.7, 0.5, 64, 64) - _test_forward_combined_nms((1, 32, 1, 4), (1, 32, 1), 0.7, 0.5, 10, 64) - _test_forward_combined_nms((1, 32, 1, 4), (1, 32, 2), 0.7, 0.5, 32, 64) - _test_forward_combined_nms((1, 64, 1, 4), (1, 64, 20), 0.7, 0.5, 64, 10) - # This workload seems flaky on CI. - # See https://github.com/apache/tvm/issues/8140 - # _test_forward_combined_nms((1, 64, 20, 4), (1, 64, 20), 0.7, 0.5, 64, 64, clip_boxes=True) - _test_forward_combined_nms((2, 200, 1, 4), (2, 200, 1), 0.4, 0.6, 100, 100) - _test_forward_combined_nms((2, 200, 1, 4), (2, 200, 10), 0.4, 0.2, 150, 1000) - - -####################################################################### -# LSTM -# ---- - - -def _test_lstm_cell(batch_size, num_hidden, num_layers, forget_bias, dtype): - """One iteration of a LSTM cell""" - - tf.reset_default_graph() - input_size = num_hidden - input_data = np.full((batch_size, input_size), 1.0, dtype=dtype) - in_state_c = np.full((batch_size, num_hidden), 0.1, dtype=dtype) - in_state_h = np.full((batch_size, num_hidden), 0.1, dtype=dtype) - - def _get_tensorflow_output(): - with tf.Session() as sess: - with variable_scope.variable_scope( - "root", initializer=init_ops.constant_initializer(0.5) - ): - m0 = tf.placeholder(dtype, [batch_size, num_hidden], name="m0") - m1 = tf.placeholder(dtype, [batch_size, num_hidden], name="m1") - x = tf.placeholder(shape=(batch_size, input_size), dtype=dtype, name="input") - g, ((out_m0, out_m1)) = tensorflow.contrib.rnn.LSTMBlockCell( - num_hidden, forget_bias=forget_bias - )(x, (m0, m1)) - sess.run([variables.global_variables_initializer()]) - res = sess.run( - [g, out_m0, out_m1], - { - x.name: np.array([[1.0, 1.0]]), - m0.name: in_state_c, - m1.name: in_state_h, - }, - ) - graph_def = sess.graph.as_graph_def(add_shapes=True) - final_graph_def = graph_util.convert_variables_to_constants( - sess, graph_def, ["root/lstm_cell/LSTMBlockCell"] - ) - - return final_graph_def, res - - graph_def, tf_out = _get_tensorflow_output() - tvm_output = run_tvm_graph( - graph_def, - [input_data, in_state_c, in_state_h], - ["root/input", "root/m0", "root/m1"], - num_output=7, - ) - assert isinstance(tvm_output, list) - - tvm.testing.assert_allclose(tf_out[0], tvm_output[6], rtol=1e-3, atol=1e-3) - tvm.testing.assert_allclose(tf_out[1], tvm_output[1], rtol=1e-3, atol=1e-3) - - -def test_forward_lstm(): - """test LSTM block cell""" - if package_version.parse(tf.VERSION) < package_version.parse("2.0.0"): - # in 2.0, tf.contrib.rnn.LSTMBlockCell is removed - _test_lstm_cell(1, 2, 1, 0.5, "float32") - - -####################################################################### -# Pack -# --- -def _test_pack(axis, shape, **kwargs): - - a = np.arange(np.prod(shape), dtype=np.float32).reshape(shape) - b = np.arange(np.prod(shape), dtype=np.float32).reshape(shape) - - with tf.Graph().as_default(): - tf_a = array_ops.placeholder(shape=shape, dtype="float32", name="pl_a") - tf_b = array_ops.placeholder(shape=shape, dtype="float32", name="pl_b") - tf_c = tf.stack([tf_a, tf_b], axis=axis, **kwargs) - assert tf_c.op.op_def.name == "Pack", "tf.stack() is expected to produce 'Pack' operation" - - compare_tf_with_tvm([a, b], ["pl_a:0", "pl_b:0"], "stack:0") - - -def test_forward_pack(): - for axis in range(-3, 3): - _test_pack(axis, [3, 2, 1]) - for axis in range(-1, 1): - _test_pack(axis, [3]) - _test_pack(0, []) - - -####################################################################### -# Unpack -# ------ -def _test_forward_unpack(in_shape, axis, dtype): - """test operator Unpack""" - np_data = np.random.uniform(-100, 100, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - tf.unstack(in_data, axis=axis, name="Unpack") - compare_tf_with_tvm([np_data], ["in_data:0"], "Unpack:0") - - -def test_forward_unpack(): - _test_forward_unpack((3,), 0, "int32") - _test_forward_unpack((3,), -1, "int16") - _test_forward_unpack((21, 23, 3), 2, "float32") - - -####################################################################### -# Range -# ----- - - -def test_forward_range(): - """test operator Range""" - for dtype in [tf.int32, tf.int64]: - tf.reset_default_graph() - with tf.Graph().as_default(): - tf.range(1, 18, 3, name="range", dtype=dtype) - compare_tf_with_tvm([], [], "range:0") - - # test type assignment for operator Range - tf.reset_default_graph() - with tf.Graph().as_default(): - tf.range(1, 256 + 1, 1, dtype=tf.float32) - compare_tf_with_tvm([], [], "range:0") - - -####################################################################### -# Einsum -# ----- - - -def _test_einsum(equation, dtype, *shape_of_input_tensors): - """Test Einsum Op""" - - with tf.Graph().as_default(): - inputs_placeholders = [] - input_data = [] - for idx, shape in enumerate(shape_of_input_tensors): - input_name = f"input_{idx}" - inputs_placeholders.append(tf.placeholder(shape=shape, dtype=dtype, name=input_name)) - input_data.append(np.random.normal(size=shape).astype(dtype)) - - result = tf.einsum(equation, *inputs_placeholders) - - compare_tf_with_tvm(input_data, [ph.name for ph in inputs_placeholders], result.name) - - -def test_forward_einsum(): - for dtype in ["float32"]: - _test_einsum("ij,jk->ik", dtype, [2, 3], [3, 5]) # Matmul - _test_einsum("ij,jk", dtype, [2, 3], [3, 5]) # Matmul - _test_einsum("i,i->", dtype, [2], [2]) # Dot product - _test_einsum("i,j->ij", dtype, [3], [5]) # Outer produce - _test_einsum("ij->ji", dtype, [2, 3]) # Transpose - _test_einsum("ii->i", dtype, [3, 3]) # Diag - _test_einsum("ii", dtype, [3, 3]) # Trace of a square matrix - _test_einsum("bij,bjk->bik", dtype, [7, 5, 3], [7, 3, 2]) # Batch matmul - - -####################################################################### -# Pad -# --- - - -def _test_pad(input_shape, paddings, mode, **kwargs): - """One iteration of pad operation with given shape""" - - x = np.arange(np.prod(input_shape), dtype=np.float32).reshape(input_shape) - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype="float32") - pad_values = constant_op.constant(paddings) - _ = tf.pad(in_data, paddings=pad_values, mode=mode, **kwargs) - - if mode == "CONSTANT": - if "constant_values" in kwargs: - out_name = "PadV2:0" - else: - out_name = "Pad:0" - else: - out_name = "MirrorPad:0" - - compare_tf_with_tvm(x, "Placeholder:0", out_name) - - -def test_forward_pad(): - """Pad""" - _test_pad((2, 3), [[1, 1], [2, 2]], mode="CONSTANT") - _test_pad((2, 3), [[1, 1], [2, 2]], mode="CONSTANT", constant_values=1.0) - _test_pad((2, 3), [[1, 1], [2, 2]], mode="SYMMETRIC") - _test_pad((2, 3), [[1, 1], [2, 2]], mode="REFLECT") - - -####################################################################### -# Logical operators -# -------------------- - - -def test_logical_and(): - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in1") - in2 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in2") - _ = tf.logical_and(in1, in2, name="out") - in_data1 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - in_data2 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - compare_tf_with_tvm([in_data1, in_data2], ["in1:0", "in2:0"], "out:0") - - -def test_logical_or(): - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in1") - in2 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in2") - _ = tf.logical_or(in1, in2, name="out") - in_data1 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - in_data2 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - compare_tf_with_tvm([in_data1, in_data2], ["in1:0", "in2:0"], "out:0") - - -def test_logical_xor(): - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in1") - in2 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in2") - _ = tf.logical_xor(in1, in2, name="out") - in_data1 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - in_data2 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - compare_tf_with_tvm([in_data1, in_data2], ["in1:0", "in2:0"], "out:0") - - -def test_logical_not(): - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.bool, shape=[1, 4, 4, 3], name="in1") - _ = tf.logical_not(in1, name="out") - in_data1 = np.random.choice(a=[False, True], size=(1, 4, 4, 3)).astype("bool") - compare_tf_with_tvm(in_data1, "in1:0", "out:0") - - -def test_forward_logical(): - test_logical_and() - test_logical_or() - test_logical_xor() - test_logical_not() - - -####################################################################### -# Where, Select, SelectV2 -# ------------- -def test_forward_where(): - """Where: return elements depending on conditions""" - with tf.Graph().as_default(): - with tf.Session() as _: - input1 = tf.placeholder(tf.int32, shape=[1, 4, 4, 3], name="input1") - input2 = tf.placeholder(tf.int32, shape=[1, 4, 4, 3], name="input2") - mask = input1 > input2 - tf.where(mask, input1 + 1, input2 * 2) - in_data1 = np.random.uniform(0, 10, size=(1, 4, 4, 3)).astype("uint32") - in_data2 = np.random.uniform(0, 10, size=(1, 4, 4, 3)).astype("uint32") - compare_tf_with_tvm([in_data1, in_data2], ["input1:0", "input2:0"], "Select:0") - - -####################################################################### -# Inception V3 -# ------------ -@pytest.mark.skip(reason="See https://github.com/apache/tvm/issues/10275") -def test_forward_inception_v3(): - """test inception V3 model""" - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload( - "InceptionV3/inception_v3_2016_08_28_frozen-with_shapes.pb" - ) - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - data = np.random.uniform(size=(1, 299, 299, 3)).astype("float32") - - with tf.Session() as sess: - tf_output = run_tf_graph(sess, data, "input:0", "InceptionV3/Predictions/Reshape_1:0") - tvm_output = run_tvm_graph(graph_def, data, "input") - tvm.testing.assert_allclose(tf_output[0], tvm_output[0], rtol=1e-5, atol=1e-5) - - -####################################################################### -# Inception V1 -# ------------ - - -def test_forward_inception_v1(): - """test inception V1 model""" - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload("InceptionV1/classify_image_graph_def-with_shapes.pb") - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - # Build an image from random data. - img_array = np.random.uniform(size=(1, 600, 600, 3)).astype("uint8") - img = Image.frombuffer("RGB", (600, 600), img_array.tostring(), "raw", "RGB", 0, 1) - temp = utils.tempdir() - img_path = temp.relpath("tf-test.jpg") - img.save(img_path) - - if not tf.gfile.Exists(os.path.join(img_path)): - tf.logging.fatal("File does not exist %s", img_path) - data = tf.gfile.FastGFile(os.path.join(img_path), "rb").read() - - temp.remove() - - # Extract tensorflow decoded image frame for tvm input - with tf.Session() as sess: - tvm_data = run_tf_graph(sess, data, "DecodeJpeg/contents:0", "DecodeJpeg:0") - - with tf.Session() as sess: - tf_output = run_tf_graph(sess, data, "DecodeJpeg/contents:0", "softmax:0") - tvm_output = run_tvm_graph(graph_def, tvm_data, "DecodeJpeg/contents") - tvm.testing.assert_allclose(tf_output[0], tvm_output[0], rtol=1e-5, atol=1e-5) - - -####################################################################### -# Mobilenet -# --------- - - -def test_forward_mobilenet(): - """test mobilenet model""" - # MobilenetV2 - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload( - "https://storage.googleapis.com/mobilenet_v2/checkpoints/mobilenet_v2_1.4_224.tgz", - "mobilenet_v2_1.4_224_frozen.pb", - ) - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - out_node = "MobilenetV2/Predictions/Reshape_1" - - with tf.Session() as sess: - # Add shapes to the graph. - graph_def = tf_testing.AddShapesToGraphDef(sess, out_node) - tf_output = run_tf_graph(sess, data, "input:0", out_node + ":0") - tvm_output = run_tvm_graph(graph_def, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tf_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# ResnetV2 -# -------- - - -@tvm.testing.requires_gpu -def test_forward_resnetv2(): - """test resnet model""" - if is_gpu_available(): - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload( - "ResnetV2/resnet-20180601_resnet_v2_imagenet-shapes.pb" - ) - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - data = np.random.uniform(size=(128, 224, 224, 3)).astype("float32") - out_node = "ArgMax" - - with tf.Session() as sess: - tf_output = run_tf_graph(sess, data, "input_tensor:0", out_node + ":0") - for device in ["llvm", "cuda"]: - _ = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print(f"Skip because {device} is not enabled") - continue - tvm_output = run_tvm_graph( - graph_def, data, "input_tensor", len(tf_output), target=device - ) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tf_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# SSD -# --- - - -def _test_ssd_impl(): - """Test SSD with backbone MobileNet V1""" - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload( - "object_detection/ssd_mobilenet_v1_ppn_shared_" - "box_predictor_300x300_coco14_sync_2018_07_03.pb" - ) - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - data = np.random.uniform(0.0, 255.0, size=(1, 512, 512, 3)).astype("uint8") - in_node = "image_tensor" - out_node = ["detection_boxes", "detection_scores", "detection_classes"] - - with tf.Session() as sess: - tf_output = run_tf_graph( - sess, data, f"{in_node}:0", [f"{oname}:0" for oname in out_node] - ) - # TODO(kevinthesun): enable gpu test when VM heterogeneous execution is ready. - for device in ["llvm"]: - _ = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print(f"Skip because {device} is not enabled") - continue - tvm_output = run_tvm_graph( - graph_def, - data, - in_node, - len(out_node), - target=device, - layout="NCHW", - out_names=out_node, - mode="vm", - disabled_pass=["FoldScaleAxis"], - serialize=True, - ) - for i in range(len(out_node)): - tvm.testing.assert_allclose(tvm_output[i], tf_output[i], rtol=1e-3, atol=1e-3) - - -@pytest.mark.skip( - reason="Use of threading module here hides errors, see https://github.com/apache/tvm/pull/10231" -) -def test_forward_ssd(): - run_thread = threading.Thread(target=_test_ssd_impl, args=()) - old_stack_size = threading.stack_size(100 * 1024 * 1024) - run_thread.start() - run_thread.join() - threading.stack_size(old_stack_size) - - -####################################################################### -# Placeholder -# ----------- - - -def test_forward_placeholder(): - """test a simple pb with Placeholder node in the end of GraphDef""" - with tf.Graph().as_default(): - graph_def = tf_testing.get_workload("Custom/placeholder.pb") - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - out_node = "mul" - - with tf.Session() as sess: - # Add shapes to the graph. - graph_def = tf_testing.AddShapesToGraphDef(sess, out_node) - tf_output = run_tf_graph(sess, data, "Placeholder:0", out_node + ":0") - tvm_output = run_tvm_graph(graph_def, data, "Placeholder") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tf_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# PTB -# --- -try: - # Load contrib for running ptb model in tf version before 2.0 - import tensorflow.contrib -except ImportError: - pass - - -def test_forward_ptb(): - """test ptb model""" - config = tf_testing.get_config() - num_steps = config.num_steps - num_hidden = config.hidden_size - num_layers = config.num_layers - batch_size = config.batch_size - vocab_size = config.vocab_size - out_sample_shape = (batch_size, vocab_size) - out_state_shape = (batch_size, num_hidden) - # Sample input - inpt = "we have no useful information on" - cnt_sample = 20 - - def _pretty_print(items, is_char_model, id2word): - if not is_char_model: - return " ".join([id2word[x] for x in items]) - else: - return "".join([id2word[x] for x in items]).replace("_", " ") - - def _get_tvm_graph_module(graph_def): - # Cell inputs 'c and 'h' consist of all layers values - shape_dict = {"Model/Placeholder": (batch_size, num_steps)} - - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_tensorflow( - graph_def, - shape=shape_dict, - outputs=[ - "Model/Softmax:0", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell:1", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell:6", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell_1:1", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell_1:6", - ], - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow( - graph_def, - shape=shape_dict, - outputs=[ - "Model/Softmax:0", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell:1", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell:6", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell_1:1", - "Model/RNN/RNN/multi_rnn_cell/cell_0/lstm_cell/LSTMBlockCell_1:6", - ], - ) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"]) - - target = "llvm" - with tvm.transform.PassContext(opt_level=0): - graph, lib, params = relay.build(mod, target, params=params) - - dev = tvm.cpu(0) - return params, graph_executor.create(graph, lib, dev) - - def _do_tvm_sample(model, data, in_states, params, num_samples): - """Sampled from the model""" - samples = [] - state = in_states - sample = None - - def _get_sample(data, state): - input_data = np.full((batch_size, num_steps), data, dtype="int32") - - model.set_input("Model/Placeholder", tvm.nd.array(input_data.astype("int32"))) - model.set_input( - "Model/MultiRNNCellZeroState/LSTMBlockCellZeroState/zeros", - tvm.nd.array(state[0].astype("float32")), - ) - model.set_input( - "Model/MultiRNNCellZeroState/LSTMBlockCellZeroState/zeros_1", - tvm.nd.array(state[1].astype("float32")), - ) - model.set_input( - "Model/MultiRNNCellZeroState/LSTMBlockCellZeroState_1/zeros", - tvm.nd.array(state[2].astype("float32")), - ) - model.set_input( - "Model/MultiRNNCellZeroState/LSTMBlockCellZeroState_1/zeros_1", - tvm.nd.array(state[3].astype("float32")), - ) - model.set_input(**params) - model.run() - tvm_output = model.get_output(0, tvm.nd.empty(out_sample_shape, "float32")).numpy() - - state_output = [] - for i in range(4): - state_output.append( - model.get_output(i + 1, tvm.nd.empty(out_state_shape, "float32")).numpy() - ) - sample = tf_testing.pick_from_weight(tvm_output[0]) - - return sample, state_output - - for x in data: - sample, state = _get_sample(x, state) - - if sample is not None: - samples.append(sample) - else: - samples.append(0) - - k = 1 - while k < num_samples: - sample, state = _get_sample(samples[-1], state) - samples.append(sample) - k += 1 - return samples, state - - with tf.Graph().as_default(): - word_to_id, id_to_word, graph_def = tf_testing.get_workload_ptb() - vocab_size = len(word_to_id) - # Call the utility to import the graph definition into default graph. - graph_def = tf_testing.ProcessGraphDefParam(graph_def) - sess = tf.Session() - - # TVM graph module creation - params, m = _get_tvm_graph_module(graph_def) - - # Create 10 predicted statments of 20 words - cnt_stm = 0 - while cnt_stm < 10: - cnt_stm += 1 - in_state = [np.full((batch_size, num_hidden), 0, dtype="float32")] * 2 * num_layers - seed_for_sample = inpt.split() - tvm_samples, _ = _do_tvm_sample( - m, [word_to_id[word] for word in seed_for_sample], in_state, params, cnt_sample - ) - tvm_sample_str = _pretty_print(tvm_samples, False, id_to_word) - tf_samples, _ = tf_testing.do_tf_sample( - sess, [word_to_id[word] for word in seed_for_sample], in_state, cnt_sample - ) - tf_sample_str = _pretty_print(tf_samples, False, id_to_word) - inpt = tvm_sample_str - tvm.testing.assert_allclose(tf_samples, tvm_samples, rtol=1e-5, atol=1e-5) - assert tvm_sample_str == tf_sample_str - - -####################################################################### -# LRN (Local Response Normalization) -# ---------------------------------- - - -def _test_lrn(ishape, size, axis, bias, alpha, beta): - """testing local response normalization""" - lrn_depth_radius = size / 2 - - inp_array = np.random.uniform(size=ishape).astype(np.float32) - - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype, name="lrn0_data") - nn_ops.local_response_normalization( - in1, name="lrn", depth_radius=lrn_depth_radius, bias=bias, alpha=alpha, beta=beta - ) - - compare_tf_with_tvm(inp_array, "lrn0_data:0", "lrn:0") - - -def test_forward_lrn(): - _test_lrn((1, 3, 20, 20), 3, 1, 1.0, 1.0, 0.5) - - -####################################################################### -# l2_normalize -# ------------ - - -def _test_l2_normalize(ishape, eps, axis): - """testing l2 normalize (uses max, sum, square, sqrt frontend operators)""" - - inp_array = np.random.uniform(size=ishape).astype(np.float32) - - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - nn.l2_normalize(in1, axis=axis, epsilon=eps, name=None, dim=None) - - compare_tf_with_tvm(inp_array, "Placeholder:0", "l2_normalize:0") - - -def test_forward_l2_normalize(): - _test_l2_normalize((1, 3, 20, 20), 0.001, (0,)) - - -####################################################################### -# transpose -# --------- - - -def _test_forward_transpose(ishape, axes=None): - data = np.random.uniform(size=ishape).astype(np.float32) - - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=data.shape, dtype=data.dtype, name="transpose_data") - - if axes is None: - tf.transpose(in1) - else: - tf.transpose(in1, perm=axes) - - compare_tf_with_tvm(data, "transpose_data:0", "transpose:0") - - -def _test_forward_tranapose_axes_input(ishape, axes): - data = np.random.uniform(size=ishape).astype(np.float32) - axes_np = np.array(axes).astype(np.int32) - - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=data.shape, dtype=data.dtype, name="transpose_data") - - const1 = tf.constant(axes_np, dtype=tf.int32) - - # make axes an input to tf.transpose, but not an input to the graph, - # so it can be extracted with infer_value_simulated - axes = tf.reverse(const1, axis=[-1]) - tf.transpose(in1, axes) - - compare_tf_with_tvm([data], ["transpose_data:0"], "transpose:0") - - -def test_forward_transpose(): - _test_forward_transpose((2, 3, 4), (1, 2, 0)) - _test_forward_transpose((2, 3, 4)) - _test_forward_transpose((7, 8, 8, 10)) - _test_forward_transpose((2, 3, 4), (1, 2, 0)) - _test_forward_transpose((2, 3, 4), (0, 1, 2)) - _test_forward_transpose((2, 3, 4, 5), (3, 0, 1, 2)) - _test_forward_tranapose_axes_input((2, 3, 4), (1, 2, 0)) - _test_forward_tranapose_axes_input((2, 3, 4, 5), (3, 0, 1, 2)) - - -def _test_forward_slice_operation_input(input_value, begin_value, size_value): - input_data = np.array(input_value, dtype=np.float32) - with tf.Graph().as_default(): - input_tensor = tf.placeholder(shape=input_data.shape, dtype=input_data.dtype, name="input") - tf.slice(input_tensor, begin_value, size_value, name="slice_output") - compare_tf_with_tvm([input_data], ["input:0"], "slice_output:0") - - -def test_forward_slice(): - _test_forward_slice_operation_input([1, 1], [0], [2]) - _test_forward_slice_operation_input([0, 1, 2, 3], [3], [-1]) - _test_forward_slice_operation_input( - [[0, 1, 2, 3], [4, 5, 6, 7]], begin_value=[0, 1], size_value=[-1, -1] - ) - - -def test_forward_ceil(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.ceil(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Ceil:0") - - -def test_forward_floor(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.floor(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Floor:0") - - -def test_forward_relu(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - for mode in ["graph_executor", "vm"]: - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.nn.relu(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Relu:0", mode=mode) - - -def test_forward_leaky_relu(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - for mode in ["graph_executor", "vm"]: - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.nn.leaky_relu(in1, alpha=0.4) - compare_tf_with_tvm(inp_array, "Placeholder:0", "LeakyRelu:0", mode=mode) - - -def test_forward_elu(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.nn.elu(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Elu:0") - - -def test_forward_selu(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.nn.selu(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Selu:0") - - -def test_forward_tanh(): - ishape = (1, 3, 10, 10) - inp_array = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.nn.tanh(in1) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Tanh:0") - - -####################################################################### -# Softmax -# ------- -def test_forward_softmax(): - """test operator Softmax""" - - def check_softmax(in_shape, axis, dtype): - np_data = np.random.uniform(-100, 100, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - tf.nn.softmax(in_data, axis=axis, name="Softmax") - compare_tf_with_tvm([np_data], ["in_data:0"], "Softmax:0") - - check_softmax((2, 3, 5), 2, "float32") - check_softmax((2, 3, 5), -1, "float32") - - -####################################################################### -# Tensor -# ------ - - -def test_forward_round(): - """test Round""" - np_data = np.random.uniform(-10, 10, size=(5, 7)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (5, 7), name="in_data") - tf.round(in_data, name="round") - compare_tf_with_tvm([np_data], ["in_data:0"], "round:0") - - -def test_forward_abs(): - """test operator Abs""" - np_data = np.random.uniform(1, 100, size=(9, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (9, 11), name="in_data") - tf.math.abs(in_data, name="abs") - compare_tf_with_tvm([np_data], ["in_data:0"], "abs:0") - - -def _test_forward_zeros_like(in_shape, dtype): - np_data = np.random.uniform(-10, 10, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - tf.zeros_like(in_data, name="zeros_like") - compare_tf_with_tvm([np_data], ["in_data:0"], "zeros_like:0") - - -def test_forward_zeros_like(): - if package_version.parse(tf.__version__) < package_version.parse("1.2"): - _test_forward_zeros_like((2, 3), "int32") - _test_forward_zeros_like((2, 3, 5), "int8") - _test_forward_zeros_like((2, 3, 5, 7), "uint16") - _test_forward_zeros_like((2, 3, 11), "float32") - _test_forward_zeros_like((2, 3, 11), "float64") - - -def test_forward_squared_difference(): - ishape = (1, 3, 10, 14) - inp_array_a = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - inp_array_b = np.random.uniform(-5, 5, size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array_a.shape, dtype=inp_array_a.dtype, name="in1") - in2 = tf.placeholder(shape=inp_array_b.shape, dtype=inp_array_b.dtype, name="in2") - out = tf.math.squared_difference(in1, in2) - compare_tf_with_tvm([inp_array_a, inp_array_b], [in1.name, in2.name], out.name) - - -def _test_forward_reverse_v2(in_shape, axis, dtype): - np_data = np.random.uniform(-10, 10, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, in_shape, name="in_data") - tf.reverse(in_data, axis=[axis], name="reverse") - compare_tf_with_tvm([np_data], ["in_data:0"], "reverse:0") - - -def test_forward_reverse_v2(): - """test ReverseV2""" - _test_forward_reverse_v2((2, 3), 0, "int32") - _test_forward_reverse_v2((2, 3, 5), 2, "float32") - _test_forward_reverse_v2((2, 3, 5, 7), 1, "float32") - _test_forward_reverse_v2((2, 3, 5), -1, "float64") - _test_forward_reverse_v2((2, 3, 5), -3, "float64") - - -def test_forward_sign(): - """test Sign""" - np_data = np.random.uniform(-10, 10, size=(5, 7, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (5, 7, 11), name="in_data") - tf.sign(in_data, name="sign") - compare_tf_with_tvm([np_data], ["in_data:0"], "sign:0") - - -def test_forward_square(): - """test operator Square""" - np_data = np.random.uniform(1, 100, size=(2, 3, 5)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (2, 3, 5), name="in_data") - tf.square(in_data, name="square") - compare_tf_with_tvm([np_data], ["in_data:0"], "square:0") - - -def test_forward_pow_exp(): - """test Pow and Exp""" - np_in1 = np.random.uniform(-2, 2, size=(5, 7, 11)).astype(np.float32) - np_in2 = np.random.uniform(-2, 2, size=(5, 7, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in1 = tf.placeholder(tf.float32, (5, 7, 11), name="in1") - in2 = tf.placeholder(tf.float32, (5, 7, 11), name="in2") - _ = tf.pow(in1, in2, name="pow") - _ = tf.exp(in1, name="exp") - compare_tf_with_tvm([np_in1, np_in2], ["in1:0", "in2:0"], "pow:0") - compare_tf_with_tvm([np_in1], ["in1:0"], "exp:0") - - -def test_forward_unary(): - """Unary""" - - def _test_forward_unary(op, a_min=1, a_max=5, dtype=np.float32): - """test unary operators""" - np_data = np.random.uniform(a_min, a_max, size=(2, 3, 5)).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, (2, 3, 5), name="in_data") - out = op(in_data) - compare_tf_with_tvm([np_data], ["in_data:0"], out.name) - - _test_forward_unary(tf.acos, -1, 1) - _test_forward_unary(tf.asin, -1, 1) - _test_forward_unary(tf.atanh, -1, 1) - _test_forward_unary(tf.sinh) - _test_forward_unary(tf.cosh) - _test_forward_unary(tf.acosh) - _test_forward_unary(tf.asinh) - _test_forward_unary(tf.atan) - _test_forward_unary(tf.sin) - _test_forward_unary(tf.cos) - _test_forward_unary(tf.tan) - _test_forward_unary(tf.tanh) - _test_forward_unary(tf.erf) - _test_forward_unary(tf.log) - _test_forward_unary(tf.log1p) - - -def test_forward_atan2(): - """test operator tan""" - tf.disable_eager_execution() - np_data_1 = np.random.uniform(1, 100, size=(2, 3, 5)).astype(np.float32) - np_data_2 = np.random.uniform(1, 100, size=(2, 3, 5)).astype(np.float32) - tf.reset_default_graph() - in_data_1 = tf.placeholder(tf.float32, (2, 3, 5), name="in_data_1") - in_data_2 = tf.placeholder(tf.float32, (2, 3, 5), name="in_data_2") - tf.atan2(in_data_1, in_data_2, name="atan2") - compare_tf_with_tvm([np_data_1, np_data_2], ["in_data_1:0", "in_data_2:0"], "atan2:0") - - -def test_forward_expm1(): - """test operator expm1""" - - def _test_forward_expm1(shape): - tf.disable_eager_execution() - np_data = np.random.uniform(1, 10, size=shape).astype(np.float32) - tf.reset_default_graph() - in_data = tf.placeholder(tf.float32, shape, name="in_data") - tf.expm1(in_data, name="expm1") - compare_tf_with_tvm([np_data], ["in_data:0"], "expm1:0") - - _test_forward_expm1([1, 100]) - _test_forward_expm1([1, 10, 10]) - _test_forward_expm1([2, 5, 2, 5]) - - -def test_forward_softsign(): - """test operator softsign""" - - def _test_forward_softsign(shape): - tf.disable_eager_execution() - np_data = np.random.uniform(1, 100, size=shape).astype(np.float32) - tf.reset_default_graph() - in_data = tf.placeholder(tf.float32, shape, name="in_data") - tf.nn.softsign(in_data, name="softsign") - compare_tf_with_tvm([np_data], ["in_data:0"], "softsign:0") - - _test_forward_softsign([1, 100]) - _test_forward_softsign([1, 10, 10]) - _test_forward_softsign([2, 5, 2, 5]) - - -def test_forward_rint(): - """test operator rint""" - - def _test_forward_rint(shape): - tf.disable_eager_execution() - np_data = np.random.uniform(-100, 100, size=shape).astype(np.float32) - tf.reset_default_graph() - in_data = tf.placeholder(tf.float32, shape, name="in_data") - tf.math.rint(in_data, name="rint") - compare_tf_with_tvm([np_data], ["in_data:0"], "rint:0") - - _test_forward_rint([100]) - _test_forward_rint([1, 100]) - _test_forward_rint([1, 10, 10]) - _test_forward_rint([2, 5, 2, 5]) - - -def test_forward_negative(): - """test tf operator Neg""" - np_data = np.random.uniform(-100, 255, size=(224, 224, 3)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (224, 224, 3), name="in_data") - tf.negative(in_data, name="negative") - compare_tf_with_tvm([np_data], ["in_data:0"], "negative:0") - - -def test_forward_log_softmax(): - """test operator LogSoftmax""" - np_data = np.random.uniform(1, 100, size=(9, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (9, 11), name="in_data") - tf.math.log_softmax(in_data, name="LogSoftmax") - compare_tf_with_tvm([np_data], ["in_data:0"], "LogSoftmax:0") - - -def test_forward_softplus(): - """test operator Softplus""" - np_data = np.random.uniform(1, 10, size=(2, 3, 5)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (2, 3, 5), name="in_data") - tf.nn.softplus(in_data, name="softplus") - compare_tf_with_tvm([np_data], ["in_data:0"], "softplus:0") - - -def test_forward_rsqrt(): - """test Rsqrt""" - np_data = np.random.uniform(1, 100, size=(5, 7, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (5, 7, 11), name="in_data") - tf.rsqrt(in_data, name="rsqrt") - compare_tf_with_tvm([np_data], ["in_data:0"], "rsqrt:0") - - -def test_forward_sqrt(): - """test Sqrt""" - np_data = np.random.uniform(1, 100, size=(5, 7, 11)).astype(np.float32) - tf.reset_default_graph() - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, (5, 7, 11), name="in_data") - tf.sqrt(in_data, name="sqrt") - compare_tf_with_tvm([np_data], ["in_data:0"], "sqrt:0") - - -def _test_forward_right_shift(in_shape, dtype): - """test operator RightShift""" - lh_data = np.random.randint(1, 3, size=in_shape).astype(dtype) - rh_data = np.random.randint(1, 8, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - lft_data = tf.placeholder(dtype, in_shape, name="lft_data") - rgt_data = tf.placeholder(dtype, in_shape, name="rgt_data") - tf.bitwise.right_shift(lft_data, rgt_data, name="RightShift") - compare_tf_with_tvm([lh_data, rh_data], ["lft_data:0", "rgt_data:0"], "RightShift:0") - - -def test_forward_right_shift(): - _test_forward_right_shift((7,), "int32") - _test_forward_right_shift((3, 11), "int16") - - -def _test_forward_left_shift(in_shape, dtype): - """test operator LeftShift""" - lh_data = np.random.randint(100, 1000000, size=in_shape).astype(dtype) - rh_data = np.random.randint(1, 3, size=in_shape).astype(dtype) - tf.reset_default_graph() - with tf.Graph().as_default(): - lft_data = tf.placeholder(dtype, in_shape, name="lft_data") - rgt_data = tf.placeholder(dtype, in_shape, name="rgt_data") - tf.bitwise.left_shift(lft_data, rgt_data, name="LeftShift") - compare_tf_with_tvm([lh_data, rh_data], ["lft_data:0", "rgt_data:0"], "LeftShift:0") - - -def test_forward_left_shift(): - _test_forward_left_shift((10,), "int32") - _test_forward_left_shift((224, 224, 3), "int16") - - -####################################################################### -# Mean -# ---- - - -def test_forward_mean(): - """Mean""" - - def check_mean(ishape, **kwargs): - inp_array = np.random.uniform(size=ishape).astype(np.float32) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array.shape, dtype=inp_array.dtype) - tf.keras.backend.mean(in1, **kwargs) - compare_tf_with_tvm(inp_array, "Placeholder:0", "Mean:0", no_gpu=True) - - check_mean((10, 8, 16, 32)) - check_mean((10, 8, 16, 32), axis=(2, 3)) - check_mean((10, 8, 16, 32), axis=(1, 2), keepdims=True) - - -####################################################################### -# Size -# ---- - - -def test_forward_size(): - """Size""" - - def check_size(ishape): - np_input = np.random.uniform(size=ishape).astype(np.float32) - - # if all dimensions are constant, TF will optimize away size operator into constant - tf_input_shape = list(np_input.shape) - tf_input_shape[0] = None - - with tf.Graph().as_default(): - tf_input = tf.placeholder(shape=tf_input_shape, dtype=np_input.dtype, name="input") - tf.size(tf_input, name="size") - compare_tf_with_tvm([np_input], ["input:0"], "size:0") - - check_size((10, 8, 16, 32)) - check_size((10,)) - - -####################################################################### -# All, Any, Max, Min, Prod, variance, std, logsumexp, euclidean_norm -# ------------------------------------------------------------------ - - -def test_forward_reduce(): - """Reduce""" - - def _check_op(tf_op, ishape, axis, keepdims, dtype="float32"): - tf.reset_default_graph() - if dtype == "bool": - np_data = np.random.choice([True, False], size=ishape) - else: - np_data = np.random.uniform(size=ishape).astype(dtype) - if tf_op == tf.math.reduce_prod: - axis = 1 - np_data = np_data.reshape(1, -1) - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, name="in_data") - reduce_op = tf_op(in_data, axis=axis, keepdims=keepdims, name="reduce_std") - compare_tf_with_tvm([np_data], ["in_data:0"], reduce_op.name) - - def _test_math_op(op, d_types=None): - d_types = d_types or ["int32", "float32"] - for dtype in d_types: - _check_op(op, (3, 10), axis=(-1), keepdims=False, dtype=dtype) - _check_op(op, (8, 16, 32), axis=(-1), keepdims=False, dtype=dtype) - _check_op(op, (1, 8, 8, 3), axis=(2, 3), keepdims=True, dtype=dtype) - _check_op(op, (2, 3, 10, 10), axis=(1, 2), keepdims=True, dtype=dtype) - - _test_math_op(tf.math.reduce_all, d_types=["bool"]) - _test_math_op(tf.math.reduce_any, d_types=["bool"]) - _test_math_op(tf.math.reduce_max) - _test_math_op(tf.math.reduce_min) - _test_math_op(tf.math.reduce_prod) - _test_math_op(tf.math.reduce_variance, d_types=["float32"]) - _test_math_op(tf.math.reduce_std, d_types=["float32"]) - _test_math_op(tf.math.reduce_logsumexp, d_types=["float32"]) - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - _test_math_op(tf.math.reduce_euclidean_norm) - - -####################################################################### -# All, Max, Min -# ------------------------------------------------------------------ - - -def test_forward_raw_reduce(): - """Raw reduce""" - - def _check_op(tf_op, ishape, axis, keepdims, range_axis=False, dtype="float32"): - tf.reset_default_graph() - if dtype == "bool": - np_data = np.random.choice([True, False], size=ishape) - else: - np_data = np.random.uniform(size=ishape).astype(dtype) - if tf_op == tf.math.reduce_prod: - axis = 1 - np_data = np_data.reshape(1, -1) - with tf.Graph().as_default(): - if range_axis: - axis = tf.range(axis[0], axis[1], axis[2], name="range", dtype="int32") - in_data = tf.placeholder(dtype, name="in_data") - reduce_op = tf_op(input=in_data, axis=axis, keep_dims=keepdims, name="reduce_std") - compare_tf_with_tvm([np_data], ["in_data:0"], reduce_op.name) - - def _test_raw_reduce_op(op, d_types=None): - d_types = d_types or ["int32", "float32"] - for dtype in d_types: - _check_op(op, (3, 10), axis=(-1), keepdims=False, dtype=dtype) - _check_op(op, (8, 16, 32), axis=(-1), keepdims=False, dtype=dtype) - _check_op(op, (1, 8, 8, 3), axis=(2, 3), keepdims=True, dtype=dtype) - _check_op(op, (2, 3, 10, 10), axis=(1, 2), keepdims=True, dtype=dtype) - _check_op(op, (1, 8, 8, 3), axis=(2, 4, 1), keepdims=True, range_axis=True, dtype=dtype) - _check_op( - op, (2, 3, 10, 10), axis=(1, 3, 1), keepdims=True, range_axis=True, dtype=dtype - ) - - if package_version.parse(tf.VERSION) >= package_version.parse("2.4.1"): - _test_raw_reduce_op(tf.raw_ops.All, d_types=["bool"]) - _test_raw_reduce_op(tf.raw_ops.Max) - _test_raw_reduce_op(tf.raw_ops.Min) - - -####################################################################### -# Relational operators -# -------------------- - - -def _test_forward_rel_op(data, func): - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=data[0].shape, dtype=data[0].dtype, name="in1") - in2 = tf.placeholder(shape=data[1].shape, dtype=data[1].dtype, name="in2") - op = func(in1, in2, name="op") - _ = tf.cast(op, tf.int32, name="out1") - compare_tf_with_tvm([data[0], data[1]], ["in1:0", "in2:0"], "out1:0") - - -def test_forward_rel_ops(): - t1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - t2 = np.array([[9, 8, 7], [6, 5, 4], [3, 2, 1]]) - _test_forward_rel_op([t1, t2], math_ops.less) - _test_forward_rel_op([t1, t2], math_ops.greater) - _test_forward_rel_op([t1, t2], math_ops.less_equal) - _test_forward_rel_op([t1, t2], math_ops.greater_equal) - _test_forward_rel_op([t1, t2], math_ops.equal) - _test_forward_rel_op([t1, t2], math_ops.not_equal) - - -####################################################################### -# ExpandDims -# ---------- - - -def _test_forward_expand_dims(data, axis): - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=data.shape, dtype=data.dtype, name="in1") - out = tf.expand_dims(in1, axis) - compare_tf_with_tvm([data], [in1.name], out.name) - - -def test_forward_expand_dims(): - _test_forward_expand_dims(np.int32(1), 0) - _test_forward_expand_dims(np.array([1]), 0) - _test_forward_expand_dims(np.array([1]), -1) - _test_forward_expand_dims(np.array([[1], [2]]), 0) - _test_forward_expand_dims(np.array([[1], [2]]), 1) - _test_forward_expand_dims(np.array([[1], [2]]), -1) - - -####################################################################### -# Maximum, Minimum -# ---------------- -def test_forward_maximum(): - """test Op Maximum""" - - def check_maximum(lh_shape, rh_shape, dtype): - tf.reset_default_graph() - lh_data = np.random.uniform(size=lh_shape).astype(dtype) - rh_data = np.random.uniform(size=rh_shape).astype(dtype) - with tf.Graph().as_default(): - lft_data = tf.placeholder(dtype, name="lft_data") - rgt_data = tf.placeholder(dtype, name="rgt_data") - tf.math.maximum(lft_data, rgt_data, name="maximum") - compare_tf_with_tvm([lh_data, rh_data], ["lft_data:0", "rgt_data:0"], "maximum:0") - - check_maximum((10, 8, 16, 32), (1,), dtype="int32") - check_maximum((10, 8, 16, 32), (10, 8, 16, 32), dtype="float32") - - -def test_forward_minimum(): - """test Op Minimum""" - - def check_minimum(lh_shape, rh_shape, dtype): - tf.reset_default_graph() - lh_data = np.random.uniform(size=lh_shape).astype(dtype) - rh_data = np.random.uniform(size=rh_shape).astype(dtype) - with tf.Graph().as_default(): - lft_data = tf.placeholder(dtype, name="lft_data") - rgt_data = tf.placeholder(dtype, name="rgt_data") - tf.math.minimum(lft_data, rgt_data, name="minimum") - compare_tf_with_tvm([lh_data, rh_data], ["lft_data:0", "rgt_data:0"], "minimum:0") - - check_minimum((10, 8, 16, 32), (1,), dtype="int32") - check_minimum((10, 8, 16, 32), (10, 8, 16, 32), dtype="float32") - - -####################################################################### -# PlaceholderWithDefault -# ---------------------- -def test_placeholder(): - """Placeholder""" - with tf.Graph().as_default(): - in_data1 = np.random.uniform(-5, 5, size=(3, 4, 5)).astype(np.float32) - var1 = tf.Variable(in_data1, name="in1") - var2 = array_ops.placeholder_with_default(var1, None, name="place1") - - in_data2 = np.random.uniform(-5, 5, size=(3, 4, 5)).astype(np.float32) - place1 = array_ops.placeholder(shape=in_data1.shape, dtype=in_data1.dtype, name="in2") - - out1 = tf.math.add(var1, var2, name="out1") - _ = tf.math.add(out1, place1, name="out2") - - compare_tf_with_tvm( - [in_data1, in_data2], ["place1:0", "in2:0"], "out2:0", init_global_variables=True - ) - - -####################################################################### -# OneHot -# ---------------------- - - -def _test_forward_one_hot(indices_shape, depth, on_value, off_value, axis, out_dtype): - inp_array1 = np.random.randint(0, 5, size=indices_shape) - with tf.Graph().as_default(): - in1 = tf.placeholder(shape=inp_array1.shape, dtype=inp_array1.dtype) - out = tf.one_hot(in1, depth, on_value, off_value, axis, dtype=out_dtype) - compare_tf_with_tvm(inp_array1, in1.name, out.name) - - -def test_forward_one_hot(): - _test_forward_one_hot((3,), 3, 1, 0, -1, "int32") - _test_forward_one_hot((3,), 3, 1.0, 0.0, -1, "float32") - _test_forward_one_hot((2, 2), 5, 2, -2, 0, "int32") - _test_forward_one_hot((2, 2), 5, 0.5, -0.5, 1, "float32") - _test_forward_one_hot((3, 2, 4, 5), 6, 1, 0, 1, "int32") - _test_forward_one_hot((3, 2, 4, 5), 6, 1.0, 0.0, 0, "float32") - - -####################################################################### -# AddN -# ---------------------- - - -def _test_forward_add_n(inputs): - tf.reset_default_graph() - with tf.Graph().as_default(): - temp = [] - for each in inputs: - temp.append(tf.placeholder(shape=each.shape, dtype=each.dtype)) - output = tf.add_n(temp) - compare_tf_with_tvm(list(inputs), [each.name for each in temp], output.name) - - -def test_forward_add_n(): - """Add n""" - x = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - y = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - z = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - m, n, o = x.astype(np.float32), y.astype(np.float32), z.astype(np.float32) - in0 = x - in1 = [x, y] - in2 = (x, y, z) - in3 = m - in4 = [m, n] - in5 = (m, n, o) - _test_forward_add_n(in0) - _test_forward_add_n(in1) - _test_forward_add_n(in2) - _test_forward_add_n(in3) - _test_forward_add_n(in4) - _test_forward_add_n(in5) - - -####################################################################### -# Sharing params case -# ---------------------- - - -def test_sharing_node(): - """Test the sharing params case.""" - np_data = np.random.uniform(size=(2, 2, 2)).astype("float32") - with tf.Graph().as_default(): - in_data = tf.placeholder(tf.float32, shape=(2, 2, 2), name="in_data") - axis = tf.constant([-1], dtype=tf.int32, name="axis") - mean0 = tf.reduce_mean(in_data, axis=axis, keepdims=False, name="mean0") - mean1 = tf.reduce_mean(in_data, axis=axis, keepdims=False, name="mean1") - _ = tf.add(mean0, mean1, name="out") - compare_tf_with_tvm([np_data], ["in_data:0"], "out:0") - - -####################################################################### -# Unravel Index -# ---------------------- -def _test_forward_unravel_index(inputs): - tf.reset_default_graph() - with tf.Graph().as_default(): - temp = [] - for each in inputs: - temp.append(tf.placeholder(shape=each.shape, dtype=each.dtype)) - output = tf.unravel_index(temp[0], temp[1]) - compare_tf_with_tvm(list(inputs), [each.name for each in temp], output.name) - - -def _test_forward_unravel_index_scalar(x, y, dtype="int32"): - tf.reset_default_graph() - with tf.Graph().as_default(): - indices_1 = constant_op.constant(x, dtype=dtype) - dims_1 = constant_op.constant(y, dtype=dtype) - out_1 = array_ops.unravel_index(indices_1, dims_1) - compare_tf_with_tvm([], [], out_1.name) - - -def test_forward_unravel_index(): - """Unravel index""" - x = np.array([0, 1, 2, 3]) - y = np.array([2, 2]) - _test_forward_unravel_index([x, y]) - - x = np.array([0, 1, 2, 5]) - y = np.array([2, 3]) - _test_forward_unravel_index([x, y]) - - x = np.array([0, 1, 2, 5]) - y = np.array([6]) - _test_forward_unravel_index([x, y]) - - x = np.array([102, 300, 16]) - y = np.array([10, 10, 9, 6]) - _test_forward_unravel_index([x, y]) - - x = np.array([100]) - y = np.array([10, 10, 9, 6]) - _test_forward_unravel_index([x, y]) - - # Test scalar input - _test_forward_unravel_index_scalar(13, [1, 4, 5, 2]) - - -####################################################################### -# Dilation2d -# ---------------------- -def _test_dilation2d(tensor_in_sizes, filter_in_sizes, strides, dilations, padding): - """One iteration of dilation2d with given shapes and attributes""" - - total_size_1 = np.prod(tensor_in_sizes) - total_size_2 = np.prod(filter_in_sizes) - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - filter_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32") - in_filter = constant_op.constant(filter_array, shape=filter_in_sizes, dtype="float32") - - nn_ops.dilation2d(in_data, in_filter, strides=strides, rates=dilations, padding=padding) - - compare_tf_with_tvm( - np.reshape(data_array, tensor_in_sizes).astype("float32"), - "Placeholder:0", - "Dilation2D:0", - no_gpu=True, - ) - - -def test_forward_dilation(): - """Dilation2d""" - _test_dilation2d([1, 18, 18, 32], [4, 4, 32], [1, 1, 1, 1], [1, 2, 1, 1], "VALID") - _test_dilation2d([1, 15, 15, 32], [4, 4, 32], [1, 1, 1, 1], [1, 2, 1, 1], "SAME") - _test_dilation2d([1, 5, 5, 1], [2, 2, 1], [1, 1, 1, 1], [1, 1, 1, 1], "VALID") - _test_dilation2d([1, 5, 5, 1], [3, 3, 1], [1, 1, 1, 1], [1, 2, 2, 1], "VALID") - _test_dilation2d([1, 5, 5, 3], [3, 3, 3], [1, 1, 1, 1], [1, 1, 1, 1], "SAME") - _test_dilation2d([1, 28, 28, 3], [5, 5, 3], [1, 2, 2, 1], [1, 1, 1, 1], "VALID") - _test_dilation2d([1, 224, 224, 10], [8, 8, 10], [1, 1, 1, 1], [1, 1, 1, 1], "VALID") - _test_dilation2d([1, 18, 18, 32], [4, 4, 32], [1, 1, 1, 1], [1, 2, 1, 1], "SAME") - _test_dilation2d([1, 15, 15, 32], [4, 4, 32], [1, 1, 1, 1], [1, 2, 1, 1], "VALID") - _test_dilation2d([1, 5, 5, 1], [7, 2, 1], [1, 3, 1, 1], [1, 1, 1, 1], "SAME") - _test_dilation2d([1, 5, 5, 1], [3, 4, 1], [1, 2, 1, 1], [1, 2, 2, 1], "SAME") - _test_dilation2d([1, 5, 5, 3], [3, 3, 3], [1, 1, 4, 1], [1, 1, 1, 1], "VALID") - _test_dilation2d([1, 28, 28, 3], [5, 6, 3], [1, 1, 2, 1], [1, 1, 1, 1], "SAME") - _test_dilation2d([1, 224, 224, 10], [8, 8, 10], [1, 3, 1, 1], [1, 1, 1, 1], "SAME") - _test_dilation2d([1, 3, 3, 1], [2, 2, 1], [1, 1, 1, 1], [1, 2, 2, 1], "SAME") - _test_dilation2d([1, 3, 3, 1], [2, 2, 1], [1, 1, 1, 1], [1, 1, 2, 1], "VALID") - - -def _test_identityn(data_np_list): - with tf.Graph().as_default(): - data_tensors = [] - data_tensors_name = [] - for index, data_np in enumerate(data_np_list): - tensor_name = f"data_{index}" - data_tensors_name.append(tensor_name + ":0") - data_tensors.append( - tf.placeholder(shape=data_np.shape, dtype=str(data_np.dtype), name=tensor_name) - ) - - output = tf.identity_n(data_tensors) - output_names = [out.name for out in output] - compare_tf_with_tvm( - data_np_list, - data_tensors_name, - output_names, - ) - - -@pytest.mark.parametrize( - "data_np_list", - [ - ( - [ - np.array([[1, 1], [0, 3], [0, 1], [2, 0], [3, 1]], dtype=np.int64), - np.array([1, 2, 3, 4, 5], dtype=np.int64), - np.array([5, 6], dtype=np.int64), - ] - ), - ( - [ - np.array([[1, 1], [0, 3], [2, 0], [3, 1]], dtype=np.int64), - np.array([1, 2, 3, 4], dtype=np.int64), - np.array([5, 6], dtype=np.int64), - np.array([True, False, True]), - ] - ), - ( - [ - np.array([]), - np.array([[]]), - ] - ), - ], -) -def test_forward_identityn(data_np_list): - """Identityn""" - _test_identityn(data_np_list) - - -####################################################################### -# infinity ops -# ------------ -def _verify_infiniteness_ops(tf_op, name): - """test operator infinity ops""" - - # Only float types are allowed in Tensorflow for isfinite and isinf - # float16 is failing on cuda - tf_dtypes = ["float32", "float64"] # pylint: disable=redefined-outer-name - for tf_dtype in tf_dtypes: - shape = (8, 8) - data = np.random.uniform(size=shape).astype(tf_dtype) - data.ravel()[np.random.choice(data.size, int(data.size * 0.5), replace=False)] = np.inf - data.ravel()[np.random.choice(data.size, int(data.size * 0.5), replace=False)] = np.nan - - tf.reset_default_graph() - in_data = tf.placeholder(tf_dtype, shape, name="in_data") - tf_op(in_data, name=name) - compare_tf_with_tvm([data], ["in_data:0"], f"{name}:0") - - -def test_forward_isinf(): - _verify_infiniteness_ops(tf.is_inf, "isinf") - - -def test_forward_isfinite(): - _verify_infiniteness_ops(tf.is_finite, "isfinite") - - -def test_forward_isnan(): - _verify_infiniteness_ops(tf.is_nan, "isnan") - - -def _test_spop_placeholder_without_shape_info(): - with tf.Graph().as_default(): - - @function.Defun(*[tf.int32] * 2) - def Forward(x, y): - print(x.name) - print(y.name) - b = tf.add(x, y) - return b - - pl1 = tf.placeholder(tf.int32, name="pl1") - pl2 = tf.placeholder(tf.int32, name="pl2") - pl3 = tf.placeholder(tf.int32, name="pl3") - data = np.array([[-1, 1], [2, -2]], dtype=np.int32) - data2 = np.array([[-2, 3], [4, -6]], dtype=np.int32) - data3 = np.array([[-2, 3], [4, -6]], dtype=np.int32) - z1 = gen_functional_ops.StatefulPartitionedCall(args=[pl1, pl2], Tout=[tf.int32], f=Forward) - z2 = z1 + pl3 - compare_tf_with_tvm( - [data, data2, data3], - ["pl1:0", "pl2:0", "pl3:0"], - ["StatefulPartitionedCall:0", z2.name], - mode="vm", - init_global_variables=True, - ) - - -def _test_spop_placeholder_with_shape_and_default_value(): - with tf.Graph().as_default(): - data = np.ones([1], dtype=int).astype(np.int32) - dataVar = tf.Variable(data, shape=data.shape) - pl1 = array_ops.placeholder_with_default(dataVar, shape=data.shape, name="pl1") - tpl = tf.convert_to_tensor(pl1, dtype=tf.int32) - - @function.Defun(*[tf.int32]) - def pl_with_default(pl): - return tf.expand_dims(tf.multiply(pl, pl), 0) - - _ = gen_functional_ops.StatefulPartitionedCall( - args=[tpl], Tout=[tf.int32], f=pl_with_default - ) - compare_tf_with_tvm( - data, ["pl1:0"], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - - -def _test_spop_placeholder_numpy_arange_feed(): - with tf.Graph().as_default(): - t1 = tf.placeholder(tf.int32, (3, 3, 3), "t1") - t1_data = np.arange(27, dtype=np.int32).reshape((3, 3, 3)) - t2 = tf.placeholder(tf.int32, (3, 3, 3), "t2") - t2_data = np.arange(27, dtype=np.int32).reshape((3, 3, 3)) - - @tf.function - def add(x, y): - return tf.add(x, y, "add_t1_t2") - - t3 = add(t1, t2) - compare_tf_with_tvm( - [t1_data, t2_data], ["t1:0", "t2:0"], [t3.name], mode="vm", init_global_variables=True - ) - - -def _test_spop_placeholder_numpy_array_feed(): - with tf.Graph().as_default(): - t1_data = np.array([[-1, 1, 3], [2, -2, 4], [2, -3, 14]], dtype=np.int32) - t2_data = np.array([[-2, 1, 2], [12, -2, 14], [12, -3, 4]], dtype=np.int32) - t1 = tf.placeholder(tf.int32, name="t1") - t2 = tf.placeholder(tf.int32, name="t2") - - @tf.function - def add(x, y): - return tf.add(x, y, "add_t1_t2") - - t3 = add(t1, t2) - compare_tf_with_tvm( - [t1_data, t2_data], ["t1:0", "t2:0"], [t3.name], mode="vm", init_global_variables=True - ) - - -def _test_spop_function_invocation_basic(): - with tf.Graph().as_default(): - - def fun1(a): - return tf.multiply(a, a) - - def fun2(b): - return tf.multiply(b, 10) - - @tf.function - def fun3(x, y): - x = fun2(x) - y = fun1(y) - z = tf.add(x, y) - return z - - t3 = fun3(tf.constant(10.5), tf.constant(20.4)) - - compare_tf_with_tvm([], [], [t3.name], mode="vm", init_global_variables=True) - - -def _test_spop_function_invocation_nested(): - with tf.Graph().as_default(): - t1 = tf.placeholder(tf.int32, (3, 3, 3), name="t1") - t1_data = np.arange(27, dtype=np.int32).reshape((3, 3, 3)) - t2 = tf.placeholder(tf.int32, name="t2") - t2_data = np.arange(27, dtype=np.int32).reshape((3, 3, 3)) - - @tf.function - def myfunc(x, y): - return tf.add(x, y, "myfunc") - - @tf.function - def myfunc2(x, y): - z = myfunc(x, y) - l = myfunc(z, y) - m = myfunc(l, z) - return tf.add(l, m, "myfunc2") - - res1 = myfunc(t1, t2) - res2 = myfunc2(res1, t1) - - compare_tf_with_tvm( - [t1_data, t2_data], ["t1:0", "t2:0"], [res2.name], mode="vm", init_global_variables=True - ) - - -def _test_spop_function_invocation_no_autograph(): - with tf.Graph().as_default(): - - @tf.function(autograph=False) - def fun1(a): - return tf.multiply(a, a) - - @tf.function(autograph=False) - def fun2(b): - return tf.multiply(b, 10) - - @tf.function - def fun3(x, y): - x = fun2(x) - y = fun1(y) - z = tf.add(x, y) - return z - - t3 = fun3(tf.constant(10.5), tf.constant(20.4)) - - compare_tf_with_tvm([], [], [t3.name], mode="vm", init_global_variables=True) - - -def _test_spop_function_invocation_defun(): - with tf.Graph().as_default(): - - def fun1(a): - return tf.multiply(a, a) - - def fun2(b): - return tf.multiply(b, b) - - @function.Defun(dtypes.float32, dtypes.float32, func_name="Fun3") - def fun3(x, y): - x = fun2(x) - y = fun1(y) - z = tf.add(x, y) - return z - - _ = gen_functional_ops.StatefulPartitionedCall( - args=[tf.constant(10.5), tf.constant(20.4)], - Tout=[dtypes.float32], - f=fun3, - name="SpopFnInvocation", - ) - compare_tf_with_tvm([], [], "SpopFnInvocation:0", mode="vm", init_global_variables=True) - - -def _test_spop_arithmetic(): - with tf.Graph().as_default(): - - @function.Defun(*[dtypes.int32] * 3) - def arithmetic(m, x, c): - z = tf.add(tf.multiply(m, x), c) - return z - - m = tf.constant(10) - x = tf.constant(20) - c = tf.constant(2) - _ = gen_functional_ops.StatefulPartitionedCall( - args=[m, x, c], Tout=[tf.int32], f=arithmetic - ) - - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - - -def _test_spop_control_flow(): - with tf.Graph().as_default(): - - @function.Defun(*[dtypes.float32] * 2) - def Body1(x, y): - with ops.device("/job:localhost/replica:0/task:0/device:CPU:0"): - z = math_ops.multiply(x, y) - i = 0 - while i < 10: - i += 1 - if i == 5: - continue - z = math_ops.multiply(x, y * i) - return z - - _ = gen_functional_ops.StatefulPartitionedCall( - args=[constant_op.constant(32.0), constant_op.constant(100.0)], - Tout=[dtypes.float32], - f=Body1, - ) - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - - -def _test_spop_variables(): - with tf.Graph().as_default(): - const1 = tf.constant(10) - const2 = tf.constant(20) - var1 = tf.Variable(const1, dtype=tf.int32) - var2 = tf.Variable(const2, dtype=tf.int32) - - @function.Defun(tf.int32, tf.int32) - def Forward(x, y): - return tf.multiply(x, y) - - _ = gen_functional_ops.StatefulPartitionedCall( - args=[var1, var2], Tout=[tf.int32], f=Forward - ) - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", init_global_variables=True, mode="vm" - ) - - -def _test_spop_constants(): - with tf.Graph().as_default(): - - @function.Defun(*[dtypes.int32] * 2) - def constantsFn(x, y): - vv = tf.constant([2, 3, 4], name="vv") - z = tf.add(vv + x, y) - return z - - a = tf.constant(20000, name="a") - b = tf.constant(40000, name="b") - _ = gen_functional_ops.StatefulPartitionedCall(args=[a, b], Tout=[tf.int32], f=constantsFn) - - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - - -def _test_spop_stateful(): - # This test case is to test that TVM rejects any TF stateful operations - # (including Resource Variables) except StatefulPartitionedCall/PartitionedCall - # (as these two operators can still be used as container graphs to execute - # "stateless" operations internally. - tf.reset_default_graph() - with tf.Graph().as_default(): - - @tf.function - def FunctionWithStatefulOp_One(i): - b = tf.random.uniform(shape=[2, 4], maxval=10, dtype=tf.float32, seed=10) - y = tf.multiply(b, i) - return y - - @tf.function - def FunctionWithStatefulOp(m, n): - a = tf.random.uniform(shape=[2, 4], maxval=10, dtype=tf.float32, seed=10) - x = tf.multiply(a, m) - y = FunctionWithStatefulOp_One(n) - z = tf.multiply(x, y) - return z - - op = FunctionWithStatefulOp(constant_op.constant(1.0), constant_op.constant(2.0)) - with pytest.raises(Exception) as execinfo: - compare_tf_with_tvm([], [], [op.name], init_global_variables=True, mode="vm") - assert execinfo.value.args[0].startswith("The following operators are not implemented") - - -def _test_spop_device_assignment(): - # This test case is to test that TVM rejects inconsistent device assignment - # while using StatefulPartitionedCall/PartitionedCall operators which in case of TVM will - # be used as container graphs to internally execute "stateless" operations. - - tf.reset_default_graph() - with tf.Graph().as_default(): - - def fun1(a): - with ops.device("/GPU:0"): - return tf.multiply(a, a) - - def fun2(b): - with ops.device("/job:localhost/replica:0/task:0/device:CPU:1"): - return tf.multiply(b, b) - - @function.Defun(dtypes.float32, dtypes.float32, func_name="Fun3") - def fun3(x, y): - with ops.device("/CPU:0"): - x = fun2(x) - with ops.device("/job:localhost/replica:0/task:0/device:CPU:2"): - y = fun1(y) - with ops.device("/job:localhost/replica:0/task:0/device:CPU:3"): - z = tf.add(x, y) - return z - - _ = gen_functional_ops.StatefulPartitionedCall( - args=[tf.constant(10.5), tf.constant(20.4)], Tout=[dtypes.float32], f=fun3 - ) - with pytest.raises(Exception) as execinfo: - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - assert execinfo.value.args[0].startswith("Found inconsistent Device assignment") - - -def _test_spop_resource_variables(): - # This test case is to test that TVM rejects any graph containing - # resource variables with StatefulPartitionedOp. - - tf.reset_default_graph() - with tf.Graph().as_default(): - - const1 = tf.constant(10) - const2 = tf.constant(20) - var1 = tf.Variable(const1, dtype=tf.int32, use_resource=True) - var2 = tf.Variable(const2, dtype=tf.int32, use_resource=True) - - @tf.function - def resourceVariablesTest(x, y): - return tf.multiply(x, y) - - _ = resourceVariablesTest(var1, var2) - with pytest.raises(Exception) as execinfo: - compare_tf_with_tvm( - [], [], "StatefulPartitionedCall:0", mode="vm", init_global_variables=True - ) - # pylint: disable=implicit-str-concat - assert execinfo.value.args[0].startswith("Graph is not frozen." " Provide a frozen graph") - - -def test_forward_spop(): - """Spop""" - _test_spop_stateful() - _test_spop_device_assignment() - # tensorflow version upgrade support - # This test is expected to fail in TF version >= 2.6 - # as the generated graph will be considered frozen, hence - # not passing the criteria for the test below. - if package_version.parse(tf.__version__) < package_version.parse("2.6.1"): - _test_spop_resource_variables() - - # Placeholder test cases - _test_spop_placeholder_without_shape_info() - _test_spop_placeholder_with_shape_and_default_value() - _test_spop_placeholder_numpy_arange_feed() - _test_spop_placeholder_numpy_array_feed() - - # Function Invocation test cases - _test_spop_function_invocation_basic() - _test_spop_function_invocation_nested() - _test_spop_function_invocation_no_autograph() - _test_spop_function_invocation_defun() - - # Test cases for various other TF constructs - _test_spop_arithmetic() - _test_spop_control_flow() - _test_spop_variables() - _test_spop_constants() - - -####################################################################### -# Dynamic input shape -# ------------------- -def test_forward_dynamic_input_shape(): - """Dynamic input shape""" - tf.reset_default_graph() - - with tf.Graph().as_default(): - data = tf.placeholder(tf.float32, name="data", shape=(None,)) - _ = data + 1 - np_data = np.random.uniform(size=(2,)).astype("float32") - out_name = "add" - - with tf.Session() as sess: - graph_def = tf_testing.AddShapesToGraphDef(sess, out_name) - tf_output = run_tf_graph(sess, np_data, "data:0", [f"{out_name}:0"]) - # TODO(kevinthesun): enable gpu test when VM heterogeneous execution is ready. - for device in ["llvm"]: - _ = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print(f"Skip because {device} is not enabled") - continue - tvm_output = run_tvm_graph( - graph_def, - np_data, - ["data"], - 1, - target=device, - layout="NCHW", - out_names=[out_name], - mode="vm", - ignore_in_shape=True, - ) - tvm.testing.assert_allclose(tvm_output[0], tf_output[0], rtol=1e-5, atol=1e-5) - - -def test_forward_dynmaic_rnn_lstmblockcell(): - """Dynmaic rnn lstmblockcell""" - if package_version.parse(tf.VERSION) >= package_version.parse("2.0.0"): - return - - total_series_length = 50000 - truncated_backprop_length = 15 - state_size = 4 - echo_step = 3 - batch_size = 5 - num_layers = 5 - - def generateData(): - x = np.array(np.random.choice(2, total_series_length, p=[0.5, 0.5])) - y = np.roll(x, echo_step) - y[0:echo_step] = 0 - - x = x.reshape((batch_size, -1)) # The first index changing slowest, subseries as rows - y = y.reshape((batch_size, -1)) - - return (x, y) - - batchX_placeholder = tf.placeholder(tf.float32, [batch_size, truncated_backprop_length]) - - init_state = tf.placeholder(tf.float32, [num_layers, 2, batch_size, state_size]) - - state_per_layer_list = tf.unstack(init_state, axis=0) - rnn_tuple_state = tuple( - list( - tf.nn.rnn_cell.LSTMStateTuple( - state_per_layer_list[idx][0], state_per_layer_list[idx][1] - ) - for idx in range(num_layers) - ) - ) - - # Forward passes - def lstm_cell(): - return tensorflow.contrib.rnn.LSTMBlockCell(state_size) - - cell = tf.nn.rnn_cell.MultiRNNCell( - [lstm_cell() for _ in range(num_layers)], state_is_tuple=True - ) - states_series, current_state = tf.nn.dynamic_rnn( - cell, tf.expand_dims(batchX_placeholder, -1), initial_state=rnn_tuple_state - ) - - with tf.Session() as sess: - sess.run(tf.global_variables_initializer()) - x, _ = generateData() - _current_state = np.zeros((num_layers, 2, batch_size, state_size)) - - start_idx = 0 - end_idx = start_idx + truncated_backprop_length - - batchX = x[:, start_idx:end_idx] - - # Save current state for TVM - current_state_tvm = _current_state - - _current_state, _states_series = sess.run( - [current_state, states_series], - feed_dict={batchX_placeholder: batchX, init_state: _current_state}, - ) - - # Organize results and corresponding names - tf_output = [_states_series] - - for c in _current_state: - tf_output.append(c.c) - tf_output.append(c.h) - - name = [states_series.name.split(":")[0]] - - for t in current_state: - name.append(t.c.name.split(":")[0]) - name.append(t.h.name.split(":")[0]) - - graph_def = sess.graph.as_graph_def(add_shapes=True) - - final_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, name) - - _ = run_tvm_graph( - final_graph_def, - [batchX.astype("float32"), current_state_tvm.astype("float32")], - ["Placeholder", "Placeholder_1"], - out_names=name, - num_output=len(name), - mode="vm", - disabled_pass=["FoldScaleAxis"], - ) - - # Compare result - for _, tf_out in enumerate(tf_output): - tvm.testing.assert_allclose(tf_out, tf_out, atol=1e-5, rtol=1e-5) - - -####################################################################### -# Unique -# ------------ - - -def _test_unique(n, dtype, is_dyn): - tf.reset_default_graph() - np_data = np.random.randint(100, size=n).astype(dtype) - with tf.Graph().as_default(): - if is_dyn: - in_data = tf.placeholder(dtype, [n], name="in_data") - else: - in_data = tf.constant(np_data, dtype, name="in_data") - tf.unique(in_data) - if is_dyn: - compare_tf_with_tvm(np_data, "in_data:0", ["Unique:0", "Unique:1"], mode="vm") - else: - compare_tf_with_tvm(np_data, "", ["Unique:0", "Unique:1"], mode="vm") - - -def test_forward_unique(): - """test Unique""" - - for dtype in ["int32", "int64"]: - for is_dyn in [False, True]: - _test_unique(50, dtype, is_dyn) - _test_unique(100, dtype, is_dyn) - - -####################################################################### -# Unique with counts -# ------------ - - -def _test_unique_with_counts(n, dtype, is_dyn): - tf.reset_default_graph() - np_data = np.random.randint(100, size=n).astype(dtype) - with tf.Graph().as_default(): - if is_dyn: - in_data = tf.placeholder(dtype, [n], name="in_data") - else: - in_data = tf.constant(np_data, dtype, name="in_data") - tf.unique_with_counts(in_data) - if is_dyn: - compare_tf_with_tvm( - np_data, - "in_data:0", - ["UniqueWithCounts:0", "UniqueWithCounts:1", "UniqueWithCounts:2"], - mode="vm", - ) - else: - compare_tf_with_tvm( - np_data, - "", - ["UniqueWithCounts:0", "UniqueWithCounts:1", "UniqueWithCounts:2"], - mode="vm", - ) - - -def test_forward_unique_with_counts(): - """test UniqueWithCounts""" - - for dtype in ["int32", "int64"]: - for is_dyn in [False, True]: - _test_unique_with_counts(10, dtype, is_dyn) - _test_unique_with_counts(20, dtype, is_dyn) - - -####################################################################### -# check graph ir for nn.moments -# ------------ - - -def test_moments(): - """NN.moments""" - g = tf.Graph() - shape = [4, 176, 8, 8] - dtype = "float32" - with g.as_default(): - A = tf.placeholder(shape=shape, dtype=dtype, name="A") - _ = tf.placeholder(shape=shape, dtype=dtype, name="B") - mean, variance = tf.nn.moments(A, [1], keep_dims=True) - _ = (A - mean) / tf.sqrt(variance + 0.0005) - - with tvm.testing.disable_span_filling(): - mod, _ = from_tensorflow(g.as_graph_def(add_shapes=True)) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = from_tensorflow(g.as_graph_def(add_shapes=True)) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"], map_free_vars=True) - - program = """ - def @main(%A: Tensor[(4, 176, 8, 8), float32]) { - %527 = mean(%A, axis=[1], keepdims=True) /* moments/mean */; - %528 = subtract(%A, %527) /* sub */; - %529 = subtract(%A, %527); - %530 = multiply(%529, %529) /* moments/SquaredDifference */; - %531 = mean(%530, axis=[1], keepdims=True) /* moments/variance */; - %532 = add(%531, 0.0005f) /* add */; - %533 = sqrt(%532) /* Sqrt */; - divide(%528, %533) /* truediv */ - } - """ - mod_golden = tvm.relay.parse('#[version = "0.0.5"]\n' + program) - tvm.ir.assert_structural_equal(mod["main"].body, mod_golden["main"].body, map_free_vars=True) - - -####################################################################### -# invert_permutation -# -------------------- - - -def test_invert_permutation(): - """test InvertPermutation""" - tf.reset_default_graph() - - input_shape = [6] - x = np.array([3, 4, 0, 2, 1, 5]).astype("int32") - with tf.Graph().as_default(): - in_data = tf.placeholder(shape=input_shape, dtype="int32") - tf.invert_permutation(in_data) - out_name = "InvertPermutation:0" - compare_tf_with_tvm(x, "Placeholder:0", out_name, no_gpu=False) - - -####################################################################### -# Bincount -# ---- - - -def _test_bincount(in_shape, size, weights): - with tf.Graph().as_default(): - inputs = [] - data = [] - inputs.append(tf.placeholder(shape=in_shape, dtype="int32", name="input0")) - data.append(np.random.uniform(0, size, size=in_shape).astype("int32")) - inputs.append(tf.placeholder(shape=(), dtype="int32", name="size")) - data.append(np.array(size, "int32")) - if weights: - inputs.append(tf.placeholder(shape=in_shape, dtype="float32", name="weights")) - data.append(np.reshape(weights, in_shape).astype("float32")) - else: - inputs.append(tf.placeholder(shape=(0,), dtype="float32", name="weights")) - data.append(np.array([], "float32")) - result = tf.raw_ops.Bincount(arr=data[0], size=data[1], weights=data[2]) - compare_tf_with_tvm(data, [a.name for a in inputs], result.name, mode="vm") - - -def test_forward_bincount(): - """Test Bincount Op""" - # 2D input - _test_bincount((3, 10), 20, [1.0] * 30) - _test_bincount((3, 10), 20, [1.5] * 30) - _test_bincount((3, 10), 20, None) - # 1D input - _test_bincount((10,), 20, [1.0] * 10) - _test_bincount((10,), 20, [1.5] * 10) - _test_bincount((10,), 20, None) - - -####################################################################### -# DenseBincount -# ---- - - -def _test_dense_bincount(in_shape, size, weights, binary_output): - with tf.Graph().as_default(): - inputs = [] - data = [] - inputs.append(tf.placeholder(shape=in_shape, dtype="int32", name="input0")) - data.append(np.random.uniform(0, size, size=in_shape).astype("int32")) - inputs.append(tf.placeholder(shape=(), dtype="int32", name="size")) - data.append(np.array(size, "int32")) - if weights: - inputs.append(tf.placeholder(shape=in_shape, dtype="float32", name="weights")) - data.append(np.reshape(weights, in_shape).astype("float32")) - else: - inputs.append(tf.placeholder(shape=(0,), dtype="float32", name="weights")) - data.append(np.array([], "float32")) - result = tf.raw_ops.DenseBincount( - input=data[0], - size=data[1], - weights=data[2], - binary_output=binary_output, - ) - compare_tf_with_tvm(data, [a.name for a in inputs], result.name, mode="vm") - - -def test_forward_dense_bincount(): - """Test DenseBincount Op""" - for binary_output in [False, True]: - # 2D input - _test_dense_bincount((3, 10), 20, [1.0] * 30, binary_output) - _test_dense_bincount((3, 10), 20, [1.5] * 30, binary_output) - _test_dense_bincount((3, 10), 20, None, binary_output) - # 1D input - _test_dense_bincount((10,), 20, [1.0] * 10, binary_output) - _test_dense_bincount((10,), 20, [1.5] * 10, binary_output) - _test_dense_bincount((10,), 20, None, binary_output) - - -####################################################################### -# Test structural_equal and span of a model -# -------------------------------------- -class TestSetSpan: - """Test Structure and span of frequently-used models""" - - def _verify(self, res_fptr, golden_fptr): - with tvm.testing.enable_span_filling(): - with_span = res_fptr() - with tvm.testing.disable_span_filling(): - without_span = res_fptr() - tvm.ir.assert_structural_equal(with_span, without_span) - _verify_structural_equal_with_span(with_span, golden_fptr()) - - def test_conv2d_bias_add_span(self): - """Test Structure and span of conv2d and bias add model match to the expected result""" - - def _res(): - in_shape = (1, 5, 5, 1) - kernel_shpae = (2, 2, 1, 2) - kernel_in = np.ones(kernel_shpae) - bias_val_shape = tuple([2]) - bias_val_in = np.ones(bias_val_shape) - - with tf.Graph().as_default() as g: - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - kernel = tf.constant(kernel_in, dtype=tf.float32, name="filter_weight") - bias_val_tensor = tf.constant(bias_val_in, dtype=tf.float32, name="conv2d_bias") - conv2d = tf.nn.conv2d( - x, kernel, strides=[1, 1, 1, 1], padding="VALID", name="conv2d" - ) - _ = tf.nn.bias_add(conv2d, bias_val_tensor, name="bias_add") - - mod, _ = relay.frontend.from_tensorflow( - g.as_graph_def(), shape={"input": in_shape}, outputs=["bias_add"] - ) - return mod["main"] - - def _golden(): - model_in = relay.var( - "input", relay.TensorType([1, 5, 5, 1]), span=_create_span("input") - ) - weight = relay.var( - "filter_weight", relay.TensorType([2, 2, 1, 2]), span=_create_span("filter_weight") - ) - bias = relay.var("conv2d_bias", relay.TensorType([2]), span=_create_span("conv2d_bias")) - conv2d = _set_span( - relay.nn.conv2d( - model_in, - weight, - channels=2, - kernel_size=[2, 2], - data_layout="NHWC", - kernel_layout="HWIO", - ), - "conv2d", - ) - add = _set_span(relay.op.add(conv2d, bias), "bias_add") - mod = ir.IRModule.from_expr(add) - return mod["main"] - - self._verify(_res, _golden) - - def test_fully_connected_bias_add_span(self): - """Test Structure and span of fully connected model match to the expected result""" - - def _res(): - in_shape = (1, 10) - kernel_shpae = (10, 10) - kernel_in = np.ones(kernel_shpae) - bias_val_shape = tuple([10]) - bias_val_in = np.ones(bias_val_shape) - - with tf.Graph().as_default() as g: - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - in_filter = tf.constant(kernel_in, dtype=tf.float32, name="filter_weight") - bias_val_tensor = tf.constant(bias_val_in, dtype=tf.float32, name="dense_bias") - mat_mul = math_ops.mat_mul(x, in_filter, name="dense") - _ = tf.nn.bias_add(mat_mul, bias_val_tensor, name="bias_add") - - mod, _ = relay.frontend.from_tensorflow( - g.as_graph_def(), - shape={"input": in_shape}, - outputs=["bias_add"], - convert_config={"use_dense": True}, - ) - return mod["main"] - - def _golden(): - model_in = relay.var("input", relay.TensorType([1, 10]), span=_create_span("input")) - weight = relay.var( - "filter_weight", relay.TensorType([10, 10]), span=_create_span("filter_weight") - ) - bias = relay.var("dense_bias", relay.TensorType([10]), span=_create_span("dense_bias")) - transpose = _set_span(relay.transpose(weight, [1, 0]), "dense") - dense = _set_span(relay.nn.dense(model_in, transpose, units=10), "dense") - add = _set_span(relay.op.add(dense, bias), "bias_add") - mod = ir.IRModule.from_expr(add) - return mod["main"] - - self._verify(_res, _golden) - - def test_reshape_span(self): - """Test Structure and span of reshape model match to the expected result""" - - def _res(): - in_shape = (1, 10) - output_shape = (2, 5) - - with tf.Graph().as_default() as g: - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - _ = array_ops.reshape(x, output_shape, "reshape") - - mod, _ = relay.frontend.from_tensorflow( - g.as_graph_def(), shape={"input": in_shape}, outputs=["reshape"] - ) - return mod["main"] - - def _golden(): - model_in = relay.var("input", relay.TensorType([1, 10]), span=_create_span("input")) - reshape = _set_span(relay.reshape(model_in, [2, 5]), "reshape") - mod = ir.IRModule.from_expr(reshape) - return mod["main"] - - self._verify(_res, _golden) - - def test_batch_norm_span(self): - """Test Structure and span of batchnorm model match to the expected result""" - - def _res(): - in_shape = (1, 12, 12, 32) - with tf.Graph().as_default() as g: - input_tensor = tf.placeholder(tf.float32, shape=in_shape, name="input") - alpha = tf.constant( - np.ones( - in_shape[-1], - ), - dtype=tf.float32, - name="alpha", - ) - beta = tf.constant( - np.ones( - in_shape[-1], - ), - dtype=tf.float32, - name="beta", - ) - _ = tf.nn.fused_batch_norm(x=input_tensor, offset=beta, scale=alpha, name="bn") - mod, _ = relay.frontend.from_tensorflow( - g.as_graph_def(), shape={"input": in_shape}, outputs=["bn"] - ) - return mod["main"] - - def _golden(): - model_in = relay.var( - "input", relay.TensorType([1, 12, 12, 32]), span=_create_span("input") - ) - alpha = relay.var("alpha", relay.TensorType([32]), span=_create_span("alpha")) - beta = relay.var("beta", relay.TensorType([32]), span=_create_span("beta")) - mean = _set_span(relay.op.mean(model_in, axis=[3], exclude=True), "bn") - variance_mean = _set_span( - relay.op.mean(model_in, axis=[3], keepdims=True, exclude=True), "bn" - ) - variance = _set_span( - relay.op._make._variance(model_in, variance_mean, [3], False, True, False), "bn" - ) - bn = _set_span( - relay.nn.batch_norm(model_in, alpha, beta, mean, variance, axis=3, epsilon=0.001), - "bn", - ) - mod = ir.IRModule.from_expr(bn[0]) - return mod["main"] - - self._verify(_res, _golden) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/tensorflow/test_no_op.py b/tests/python/frontend/tensorflow/test_no_op.py deleted file mode 100644 index bc6be5c3059c..000000000000 --- a/tests/python/frontend/tensorflow/test_no_op.py +++ /dev/null @@ -1,53 +0,0 @@ -# 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. -"""Unit tests for converting TensorFlow debugging ops to Relay.""" -try: - import tensorflow.compat.v1 as tf - - tf.disable_v2_behavior() -except ImportError: - import tensorflow as tf -import numpy as np -from tvm import relay, ir, testing -from tvm.relay.frontend.tensorflow import from_tensorflow - - -def run_relay(graph): - with testing.disable_span_filling(): - mod, params = from_tensorflow(graph.as_graph_def(add_shapes=True)) - with testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tensorflow(graph.as_graph_def(add_shapes=True)) - assert ir.structural_equal(mod["main"], mod_with_span["main"]) - - return relay.create_executor("debug", mod=mod).evaluate()(**params) - - -def test_no_op(): - g = tf.Graph() - with g.as_default(): - no_op = tf.no_op() - with tf.Session() as sess: - # In TF, the type of a no-op is None. - assert sess.run(no_op) is None - - # In TVM, no-op is currently translated to 0, though it should - # probably be none or an empty tuple. - np.testing.assert_allclose(0, run_relay(g).numpy()) - - -if __name__ == "__main__": - test_no_op() diff --git a/tests/python/frontend/tensorflow2/common.py b/tests/python/frontend/tensorflow2/common.py deleted file mode 100644 index f9bf00e4239e..000000000000 --- a/tests/python/frontend/tensorflow2/common.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, too-many-lines, len-as-condition, broad-except -# pylint: disable=import-outside-toplevel, redefined-builtin -"""TF2 to relay converter test utilities""" - -import tvm -from tvm import relay - -from tvm.runtime.vm import VirtualMachine -import tvm.contrib.graph_executor as runtime -from tvm.relay.frontend.tensorflow2 import from_tensorflow -import tvm.testing -from tvm.relay.testing.tf import vmobj_to_list as vmobj_to_list - -import tensorflow as tf -from tensorflow.python.eager.def_function import Function - - -def run_tf_code(func, input_): - if type(func) is Function: - f_out = func(input_) - if isinstance(f_out, (list, tuple)): - np_out = [x.numpy() for x in f_out] - else: - np_out = [f_out.numpy()] - else: - f_out = func(tf.constant(input_)) - if type(f_out) is dict: - np_out = [f_out[k].numpy() for k in sorted(f_out.keys())] - elif type(f_out) is list: - np_out = [x.numpy() for x in f_out] - else: - np_out = f_out.numpy() - return np_out - - -def compile_graph_executor(mod, params, target="llvm", target_host="llvm", opt_level=3): - with tvm.transform.PassContext(opt_level): - lib = relay.build(mod, target=tvm.target.Target(target, host=target_host), params=params) - return lib - - -def compile_vm(mod, params, target="llvm", target_host="llvm", opt_level=3, disabled_pass=None): - with tvm.transform.PassContext(opt_level, disabled_pass=disabled_pass): - vm_exec = relay.vm.compile( - mod, target=tvm.target.Target(target, host=target_host), params=params - ) - return vm_exec - - -def run_vm(vm_exec, input_, ctx=tvm.cpu(0)): - vm = VirtualMachine(vm_exec, ctx) - _out = vm.invoke("main", input_) - return vmobj_to_list(_out) - - -def run_graph_executor(lib, input_, ctx=tvm.cpu(0)): - mod = runtime.GraphModule(lib["default"](ctx)) - mod.set_input(0, input_) - mod.run() - return [mod.get_output(i).numpy() for i in range(mod.get_num_outputs())] - - -def compare_tf_tvm(gdef, input_, output_, runtime="vm", output_tensors=None): - """compare tf and tvm execution for the same input. - - Parameters - ---------- - gdef: TF2 graph def extracted to be fed into from_tensorflow parser. - (https://www.tensorflow.org/code/tensorflow/core/framework/graph.proto) - - input_: a single numpy array object - - output_: the expected output from TF to match TVM output with - - runtime: choose TVM runtime; either "vm" for VirtualMachine or "graph" for GraphExecutor - - output_tensors : List of output tensor names (Optional) - if not specified then the last node is assumed as graph output. - """ - mod, params = from_tensorflow(gdef, outputs=output_tensors) - if runtime == "vm": - exec_ = compile_vm(mod, params) - tvm_out = run_vm(exec_, input_) - elif runtime == "graph": - lib = compile_graph_executor(mod, params) - tvm_out = run_graph_executor(lib, input_) - else: - raise RuntimeError("Runtime input not supported: %s" % runtime) - - tvm.testing.assert_allclose(output_, tvm_out, atol=1e-5) diff --git a/tests/python/frontend/tensorflow2/test_functional_models.py b/tests/python/frontend/tensorflow2/test_functional_models.py deleted file mode 100644 index 53ece82217a1..000000000000 --- a/tests/python/frontend/tensorflow2/test_functional_models.py +++ /dev/null @@ -1,649 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, too-many-lines, len-as-condition, broad-except -# pylint: disable=import-outside-toplevel, redefined-builtin -"""TF2 to relay converter test: tests basic examples""" - -import tempfile -import tensorflow as tf -import numpy as np -import pytest -from common import compare_tf_tvm -from common import run_tf_code - - -def _function_graph(TestClass): - f = TestClass().func - gdef = f.get_concrete_function().graph.as_graph_def() - gdef_ops = list(set([n.op for n in gdef.node])) - input_ = TestClass().get_input() - output = run_tf_code(f, input_) - return gdef, input_, output - - -def _model_graph(TestClass): - model = TestClass() - with tempfile.TemporaryDirectory() as model_path: - tf.saved_model.save(model, model_path) - imported = tf.saved_model.load(model_path) - - f = imported.signatures["serving_default"] - gdef = f.graph.as_graph_def(add_shapes=True) - - input_ = model.get_input() - output = run_tf_code(f, input_) - return gdef, input_, output - - -def run_func_graph(TestClass, runtime="vm", outputs=None): - compare_tf_tvm(*_function_graph(TestClass), runtime=runtime, output_tensors=outputs) - - -def run_model_graph(TestClass, outputs=None): - compare_tf_tvm(*_model_graph(TestClass), runtime="vm", output_tensors=outputs) - - -def run_all(TestClass): - run_model_graph(TestClass) - for runtime_ in ["vm", "graph"]: - run_func_graph(TestClass, runtime=runtime_) - - -def test_add_one(): - class AddOne(tf.Module): - """simple function to test x=x+1; scalar as input""" - - def get_input(self): - return np.array(1.0, dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(), dtype=tf.float32)]) - def func(self, x): - return x + 1 - - run_all(AddOne) - - -def test_add_one_2d(): - class AddOne2D(tf.Module): - """2D array as input""" - - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - return x + 1 - - run_all(AddOne2D) - - -def test_add_one_2d_constant(): - class AddOne2DConstant(tf.Module): - """2D array as input with 2D constant as well; 2D constant stored in params after convert""" - - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - return x + np.ones((2, 2), dtype="float32") - - run_all(AddOne2DConstant) - - -def test_sub_one_2d_constant(): - class SubOne2DConstant(tf.Module): - """2D array as input with 2D constant as well; 2D constant stored in params after convert""" - - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - return x - np.ones((2, 2), dtype="float32") - - run_all(SubOne2DConstant) - - -def test_mul_one_2d_constant(): - class MulOne2DConstant(tf.Module): - """2D array as input with 2D constant as well; 2D constant stored in params after convert""" - - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - return x * np.ones((2, 2), dtype="float32") - - run_all(MulOne2DConstant) - - -def test_div_one_2d_constant(): - class DivOne2DConstant(tf.Module): - """2D array as input with 2D constant as well; 2D constant stored in params after convert""" - - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - return x / np.ones((2, 2), dtype="float32") - - run_all(DivOne2DConstant) - - -def test_strided_slice(): - class StridedSlice(tf.Module): - def get_input(self): - return np.ones((3, 2, 3), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(3, 2, 3), dtype=tf.float32)]) - def func(self, x): - return tf.strided_slice(x, [1, 0, 0], [2, 1, 3], [1, 1, 1]) - - run_all(StridedSlice) - - -def test_split(): - class Split(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b, c = tf.split(x, 3, axis=1) - return tf.raw_ops.Pack(values=[a, b, c], axis=1) - - run_all(Split) - - -def test_shape(): - class Shape(tf.Module): - def get_input(self): - return np.ones((3, 2, 3), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(3, 2, 3), dtype=tf.float32)]) - def func(self, x): - a = tf.ones_like(tf.raw_ops.Shape(input=x), dtype=tf.float32) - return a + x - - run_all(Shape) - - -def test_pack(): - class Pack(tf.Module): - def get_input(self): - return np.ones((2, 3), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 3), dtype=tf.float32)]) - def func(self, x): - return tf.raw_ops.Pack(values=[x, x], axis=0) - - run_all(Pack) - - -def test_max(): - class Maximum(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b = tf.split(x, 2, axis=1) - return tf.math.maximum(a, b, name=None) - - run_all(Maximum) - - -def test_less(): - class Less(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b = tf.split(x, 2, axis=1) - return tf.math.less(a, b, name=None) - - run_all(Less) - - -def test_equal(): - class Equal(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b = tf.split(x, 2, axis=1) - return tf.math.equal(a, b, name=None) - - run_all(Equal) - - -def test_cast(): - class Cast(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.cast(x, tf.int32) - - run_all(Cast) - - -def test_expand_dims(): - class ExpandDims(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.expand_dims(x, axis=2) - - run_all(ExpandDims) - - -def test_transpose(): - class Transpose(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - x = tf.expand_dims(x, axis=2) - return tf.transpose(x, perm=[0, 2, 1]) - - run_all(Transpose) - - -def test_reshape(): - class Reshape(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.reshape(x, (1, 2, 15)) - - run_all(Reshape) - - -def test_tanh(): - class Tanh(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.math.tanh(x) - - run_all(Tanh) - - -def test_sigmoid(): - class Sigmoid(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.math.sigmoid(x) - - run_all(Sigmoid) - - -def test_relu(): - class Relu(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.nn.relu(x) - - run_all(Relu) - - -def test_floor(): - class Floor(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - return tf.math.floor(x) - - run_all(Floor) - - -def test_floor_mod(): - class FloorMod(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b = tf.split(x, 2, axis=1) - return tf.math.floormod(a, b) - - run_all(FloorMod) - - -def test_concat_v2(): - class ConcatV2(tf.Module): - def get_input(self): - return np.ones((1, 30), dtype=np.float32) - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 30), dtype=tf.float32)]) - def func(self, x): - a, b, c = tf.split(x, 3, axis=1) - axis = tf.add(tf.constant(1, dtype="int32"), tf.constant(0, dtype="int32")) - return tf.raw_ops.ConcatV2(values=[a, b, c], axis=axis) - - run_all(ConcatV2) - - -def test_multi_output(): - class MultiOutput(tf.Module): - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - y = 2 * x - return x, y - - run_func_graph(MultiOutput, runtime="vm", outputs=["Identity:output:0", "Identity_1:output:0"]) - run_func_graph( - MultiOutput, runtime="graph", outputs=["Identity:output:0", "Identity_1:output:0"] - ) - run_model_graph(MultiOutput, outputs=["Identity:output:0"]) - - -def test_if(): - def create_if_class(_condition=True): - class If(tf.Module): - def get_input(self): - return np.ones((2, 2), dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def func(self, x): - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def double(x): - return 2 * x - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 2), dtype=tf.float32)]) - def triple(x): - return 3 * x - - output = tf.raw_ops.If( - cond=_condition, - input=[x], - Tout=[tf.float32], - output_shapes=[(2, 2)], - then_branch=double.get_concrete_function(), - else_branch=triple.get_concrete_function(), - ) - return output[0] - - return If - - for cond in [True, False]: - if_class = create_if_class(_condition=cond) - run_func_graph(if_class, runtime="vm") - run_model_graph(if_class) - - -def test_stateless_while(): - class StatelessWhile(tf.Module): - def get_input(self): - return np.array([6], dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(1,), dtype=tf.float32)]) - def func(self, x): - i = tf.constant(3.0) - cond = lambda i: tf.less(i, x) - body = lambda i: (tf.add(i, 2),) - r = tf.while_loop(cond, body, [i]) - return r[0] - - run_func_graph(StatelessWhile, runtime="vm") - run_model_graph(StatelessWhile) - - -def test_stateless_while_2var(): - class StatelessWhile2Var(tf.Module): - def get_input(self): - return np.array([20], dtype="float32") - - @tf.function(input_signature=[tf.TensorSpec(shape=(1,), dtype=tf.float32)]) - def func(self, x): - i = tf.constant(3.0) - j = tf.constant(5.0) - cond = lambda i, j: tf.less(i + j, x) - body = lambda i, j: (tf.add(i, 2), tf.add(j, 3)) - r = tf.while_loop(cond, body, [i, j]) - return r - - run_func_graph( - StatelessWhile2Var, runtime="vm", outputs=["Identity:output:0", "Identity_1:output:0"] - ) - run_model_graph(StatelessWhile2Var, outputs=["Identity:output:0"]) - - -def test_tensorlist(): - def run_test(elem_shape): - class TensorList(tf.Module): - def get_input(self): - in_tens = np.ones((2, 3), dtype="float32") - in_tens[1, :] = np.zeros((3,), dtype="float32") - return in_tens - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 3), dtype=tf.float32)]) - def func(self, x): - dtype = tf.float32 - tl = tf.raw_ops.TensorListReserve( - element_shape=elem_shape, num_elements=2, element_dtype=dtype - ) - tl = tf.raw_ops.TensorListSetItem(input_handle=tl, index=0, item=x[0, :]) - tl = tf.raw_ops.TensorListSetItem(input_handle=tl, index=1, item=x[1, :]) - output = tf.raw_ops.TensorListGetItem( - input_handle=tl, index=0, element_shape=elem_shape, element_dtype=dtype - ) - return output - - run_model_graph(TensorList) - run_func_graph(TensorList, runtime="vm") - - run_test((3,)) - run_test((-1,)) - - -def test_tensorlist_stack(): - def run_test(elem_shape): - class TensorListStack(tf.Module): - def get_input(self): - in_tens = np.ones((2, 3), dtype="float32") - in_tens[1] = np.zeros((3,), dtype="float32") - return in_tens - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 3), dtype=tf.float32)]) - def func(self, x): - dtype = tf.float32 - tl = tf.raw_ops.TensorListReserve( - element_shape=elem_shape, num_elements=2, element_dtype=dtype - ) - tl = tf.raw_ops.TensorListFromTensor(tensor=x, element_shape=elem_shape) - output = tf.raw_ops.TensorListStack( - input_handle=tl, element_shape=elem_shape, element_dtype=dtype - ) - return output - - run_model_graph(TensorListStack) - run_func_graph(TensorListStack, runtime="vm") - - run_test((3,)) - run_test((-1,)) - - -def test_tensorlist_2d(): - def run_test(elem_shape): - class TensorList2D(tf.Module): - def get_input(self): - in_tens = np.ones((2, 3, 4), dtype="float32") - in_tens[1, :, :] = np.zeros((3, 4), dtype="float32") - return in_tens - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 3, 4), dtype=tf.float32)]) - def func(self, x): - dtype = tf.float32 - tl = tf.raw_ops.TensorListReserve( - element_shape=elem_shape, num_elements=2, element_dtype=dtype - ) - tl = tf.raw_ops.TensorListSetItem(input_handle=tl, index=0, item=x[0, :, :]) - tl = tf.raw_ops.TensorListSetItem(input_handle=tl, index=1, item=x[1, :, :]) - output = tf.raw_ops.TensorListGetItem( - input_handle=tl, index=0, element_shape=elem_shape, element_dtype=dtype - ) - return output - - run_model_graph(TensorList2D) - run_func_graph(TensorList2D, runtime="vm") - - run_test((3, 4)) - run_test((-1, -1)) - - -def test_tensorlist_stack_2d(): - def run_test(elem_shape): - class TensorListStack2D(tf.Module): - def get_input(self): - in_tens = np.ones((2, 3, 4), dtype="float32") - in_tens[1, :, :] = np.zeros((3, 4), dtype="float32") - return in_tens - - @tf.function(input_signature=[tf.TensorSpec(shape=(2, 3, 4), dtype=tf.float32)]) - def func(self, x): - dtype = tf.float32 - tl = tf.raw_ops.TensorListReserve( - element_shape=elem_shape, num_elements=2, element_dtype=dtype - ) - tl = tf.raw_ops.TensorListFromTensor(tensor=x, element_shape=elem_shape) - output = tf.raw_ops.TensorListStack( - input_handle=tl, element_shape=elem_shape, element_dtype=dtype - ) - return output - - run_model_graph(TensorListStack2D) - run_func_graph(TensorListStack2D, runtime="vm") - - run_test((3, 4)) - run_test((-1, -1)) - - -def test_tensorlist_stack_unpack(): - def run_test(elem_shape): - class TensorListStack2D(tf.Module): - def get_input(self): - in_tens = np.ones((1, 3, 4), dtype="float32") - return in_tens - - @tf.function(input_signature=[tf.TensorSpec(shape=(1, 3, 4), dtype=tf.float32)]) - def func(self, x): - dtype = tf.float32 - tl = tf.raw_ops.TensorListReserve( - element_shape=elem_shape, num_elements=1, element_dtype=dtype - ) - tl = tf.raw_ops.TensorListSetItem(input_handle=tl, index=0, item=x[0, :, :]) - output = tf.raw_ops.TensorListStack( - input_handle=tl, element_shape=elem_shape, element_dtype=dtype, num_elements=1 - ) - output = tf.raw_ops.Unpack(value=output, num=1, axis=0) - return output - - run_model_graph(TensorListStack2D) - run_func_graph(TensorListStack2D, runtime="vm") - - run_test((3, 4)) - run_test((-1, -1)) - - -def test_bincount_1d(): - def run_test(weights, minlength, maxlength, axis, binary_output): - class Bincount1D(tf.Module): - def get_input(self): - return np.random.uniform(low=0, high=maxlength, size=(100,)).astype("int32") - - @tf.function(input_signature=[tf.TensorSpec(shape=[None], dtype=tf.int32)]) - def func(self, x): - return tf.math.bincount( - x, - weights=weights, - minlength=minlength, - maxlength=maxlength, - axis=axis, - binary_output=binary_output, - ) - - run_model_graph(Bincount1D) - run_func_graph(Bincount1D, runtime="vm") - - for axis in [None, 0, -1]: - run_test(weights=None, minlength=20, maxlength=20, axis=axis, binary_output=False) - run_test(weights=None, minlength=20, maxlength=20, axis=axis, binary_output=True) - - # weights and axis=None need operator UnsortedSegmentSum to be implemented. Skip axis=None - weights = np.random.uniform(low=0.2, high=5, size=(100,)).astype("float32") - for axis in [0, -1]: - run_test(weights=weights, minlength=20, maxlength=20, axis=axis, binary_output=False) - - -def test_bincount_2d(): - def run_test(weights, minlength, maxlength, axis, binary_output): - class Bincount2D(tf.Module): - def get_input(self): - return np.random.uniform(low=0, high=maxlength, size=(3, 100)).astype("int32") - - @tf.function(input_signature=[tf.TensorSpec([None, None], tf.int32)]) - def func(self, x): - return tf.math.bincount( - x, - weights=weights, - minlength=minlength, - maxlength=maxlength, - axis=axis, - binary_output=binary_output, - ) - - run_model_graph(Bincount2D) - run_func_graph(Bincount2D, runtime="vm") - - for axis in [None, 0, -1]: - run_test(weights=None, minlength=20, maxlength=20, axis=axis, binary_output=False) - run_test(weights=None, minlength=20, maxlength=20, axis=axis, binary_output=True) - - # weights and axis=None need operator UnsortedSegmentSum to be implemented. Skip axis=None - weights = np.random.uniform(low=0.2, high=5, size=(3, 100)).astype("float32") - for axis in [0, -1]: - run_test(weights=weights, minlength=20, maxlength=20, axis=axis, binary_output=False) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/tensorflow2/test_sequential_models.py b/tests/python/frontend/tensorflow2/test_sequential_models.py deleted file mode 100644 index 2ad41508630c..000000000000 --- a/tests/python/frontend/tensorflow2/test_sequential_models.py +++ /dev/null @@ -1,168 +0,0 @@ -# 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. -# pylint: disable=import-self, invalid-name, unused-argument, too-many-lines, len-as-condition, broad-except -# pylint: disable=import-outside-toplevel, redefined-builtin -"""TF2 to relay converter test: testing models built with tf.keras.Sequential()""" - -import tempfile -import numpy as np -import pytest -import tensorflow as tf -from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2 - -from common import compare_tf_tvm -from common import run_tf_code - - -def run_sequential_model(model_fn, input_shape): - def get_input(shape): - _input = np.random.uniform(0, 1, shape).astype(dtype="float32") - return _input - - def save_and_reload(_model): - with tempfile.TemporaryDirectory() as model_path: - tf.saved_model.save(_model, model_path) - loaded = tf.saved_model.load(model_path) - func = loaded.signatures["serving_default"] - frozen_func = convert_variables_to_constants_v2(func) - return frozen_func - - def model_graph(model, input_shape): - _input = get_input(input_shape) - f = save_and_reload(model(input_shape)) - _output = run_tf_code(f, _input) - gdef = f.graph.as_graph_def(add_shapes=True) - return gdef, _input, _output - - compare_tf_tvm(*model_graph(model_fn, input_shape), runtime="vm") - - -def test_dense_model(): - def dense_model(input_shape, num_units=128): - return tf.keras.Sequential( - [tf.keras.layers.Flatten(input_shape=input_shape[1:]), tf.keras.layers.Dense(num_units)] - ) - - run_sequential_model(dense_model, input_shape=(1, 28, 28)) - - -def test_mnist_model(): - def mnist_model(input_shape): - return tf.keras.Sequential( - [ - tf.keras.layers.Flatten(input_shape=input_shape[1:]), - tf.keras.layers.Dense(128, activation="relu"), - tf.keras.layers.Dense(10), - ] - ) - - run_sequential_model(mnist_model, input_shape=(1, 28, 28)) - - -def test_conv2d_model(): - def conv2d_model(input_shape, kernel=(3, 3), filters=16): - model = tf.keras.Sequential( - [ - tf.keras.layers.Input(shape=input_shape[1:], batch_size=1), - tf.keras.layers.Conv2D(filters, kernel), - ] - ) - return model - - run_sequential_model(conv2d_model, input_shape=(1, 32, 32, 3)) - - -def test_maxpool_model(): - def maxpool_model(input_shape, pool_size=(2, 2)): - model = tf.keras.Sequential( - [tf.keras.layers.MaxPool2D(pool_size=pool_size, input_shape=input_shape[1:])] - ) - return model - - run_sequential_model(maxpool_model, input_shape=(1, 32, 32, 3)) - - -def test_maxpool_batchnorm_model(): - def maxpool_batchnorm_model(input_shape, pool_size=(2, 2)): - model = tf.keras.Sequential( - [ - tf.keras.layers.MaxPool2D(pool_size=pool_size, input_shape=input_shape[1:]), - tf.keras.layers.BatchNormalization(), - ] - ) - return model - - run_sequential_model(maxpool_batchnorm_model, input_shape=(1, 32, 32, 3)) - - -def test_tensorlist_stack_model(): - def tensorlist_stack_model(input_shape): - class TensorArrayStackLayer(tf.keras.layers.Layer): - def __init__(self): - super().__init__() - - def call(self, inputs): - inputs = tf.squeeze(inputs) - outputs = tf.TensorArray( - tf.float32, - size=inputs.shape[0], - infer_shape=False, - element_shape=inputs.shape[1:], - ) - outputs = outputs.unstack(inputs) - - return outputs.stack() - - input_shape = (3, 32) - model = tf.keras.Sequential( - [tf.keras.layers.Input(shape=input_shape, batch_size=1), TensorArrayStackLayer()] - ) - return model - - run_sequential_model(tensorlist_stack_model, input_shape=(3, 32)) - - -def test_tensorlist_read_model(): - def tensorlist_read_model(input_shape): - class TensorArrayReadLayer(tf.keras.layers.Layer): - def __init__(self): - super().__init__() - - def call(self, inputs): - inputs = tf.squeeze(inputs) - outputs = tf.TensorArray( - tf.float32, - size=inputs.shape[0], - infer_shape=False, - element_shape=inputs.shape[1:], - ) - for i in range(inputs.shape[0]): - outputs = outputs.write(i, inputs[i, :]) - - return outputs.read(0) - - input_shape = (3, 32) - model = tf.keras.Sequential( - [tf.keras.layers.Input(shape=input_shape, batch_size=1), TensorArrayReadLayer()] - ) - return model - - run_sequential_model(tensorlist_read_model, input_shape=(3, 32)) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/python/frontend/test_common.py b/tests/python/frontend/test_common.py deleted file mode 100644 index 2b35ae71f2d6..000000000000 --- a/tests/python/frontend/test_common.py +++ /dev/null @@ -1,220 +0,0 @@ -# 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 numpy as np - -from tvm import relay, testing, transform -from tvm.relay.frontend.common import StrAttrsDict, set_span -from relay.utils.tag_span import _set_span, _create_span, _verify_structural_equal_with_span - - -def test_key_is_present(): - attrs = StrAttrsDict({"a": 1}) - assert attrs.has_attr("a") - - -def test_key_is_not_present(): - attrs = StrAttrsDict({"a": 1}) - assert not attrs.has_attr("b") - - -class TestSetSpan: - def test_pass_ctx_switch(self): - def _res(should_fill): - if should_fill: - with testing.enable_span_filling(): - return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var") - else: - with testing.disable_span_filling(): - return set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var") - - disable = relay.var("x", shape=(1, 64, 56, 56)) - enable = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var")) - - _verify_structural_equal_with_span(_res(False), disable) - _verify_structural_equal_with_span(_res(True), enable) - - # Should tag all exprs without span, and stop when expr is span-tagged - def test_builtin_tuple(self): - def _res(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.zeros([1, 1, 1]), dtype="int64") - return set_span(tuple([a, b]), "tuple") - - def _golden(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("tuple")) - return tuple([a, b]) - - res_tuple, golden_tuple = _res(), _golden() - assert len(res_tuple) == len(golden_tuple) - for i in range(len(res_tuple)): - _verify_structural_equal_with_span(res_tuple[i], golden_tuple[i]) - - def test_builtin_list(self): - def _res(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.zeros([1, 1, 1]), dtype="int64") - t = relay.Tuple([a, b]) - t_a = relay.TupleGetItem(t, 0) - t_b = relay.TupleGetItem(t, 1) - return set_span([t_a, t_b], "list") - - def _golden(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.zeros([1, 1, 1]), dtype="int64", span=_create_span("list")) - t = relay.Tuple([a, b], span=_create_span("list")) - t_a = relay.TupleGetItem(t, 0, span=_create_span("list")) - t_b = relay.TupleGetItem(t, 1, span=_create_span("list")) - return [t_a, t_b] - - res_list, golden_list = _res(), _golden() - assert len(res_list) == len(golden_list) - for i in range(len(res_list)): - _verify_structural_equal_with_span(res_list[i], golden_list[i]) - - def test_var(self): - x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var") - x_expected = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var")) - _verify_structural_equal_with_span(x, x_expected) - - def test_constant(self): - c = set_span(relay.const(np.ones([64, 64, 3, 3]), dtype="int64"), "const_c") - c_expected = relay.const( - np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("const_c") - ) - _verify_structural_equal_with_span(c, c_expected) - - def test_call(self): - def _res(): - x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var") - w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64") - y = set_span( - relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d" - ) - return relay.Function([x], y) - - def _golden(): - x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var")) - w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("conv2d")) - y = _set_span( - relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "conv2d" - ) - return relay.Function([x], y) - - _verify_structural_equal_with_span(_res(), _golden()) - - def test_tuple(self): - def _res(): - a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a") - b = relay.const(np.ones([1, 1, 1]), dtype="int64") - t = set_span(relay.Tuple([a, b]), "t") - return relay.Function([], t) - - def _golden(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("t")) - t = relay.Tuple([a, b], span=_create_span("t")) - return relay.Function([], t) - - _verify_structural_equal_with_span(_res(), _golden()) - - def test_tuple_getitem(self): - def _res(): - a = set_span(relay.const(np.ones([1, 1, 1]), dtype="int64"), "a") - b = relay.const(np.ones([1, 1, 1]), dtype="int64") - t = relay.Tuple([a, b]) - i = set_span(relay.TupleGetItem(t, 0), "i") - return relay.Function([], i) - - def _golden(): - a = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("a")) - b = relay.const(np.ones([1, 1, 1]), dtype="int64", span=_create_span("i")) - t = relay.Tuple([a, b], span=_create_span("i")) - i = relay.TupleGetItem(t, 0, span=_create_span("i")) - return relay.Function([], i) - - _verify_structural_equal_with_span(_res(), _golden()) - - def test_let(self): - def _res(): - x = set_span(relay.Var("x"), "x_var") - c_1 = relay.const(np.ones(10)) - add = relay.add(x, x) - body = set_span(relay.Let(x, c_1, add), "let") - - c_2 = set_span(relay.const(np.zeros(10)), "zeros") - y = set_span(relay.add(body, c_2), "add_2") - return relay.Function([x], y) - - def _golden(): - x = relay.Var("x", span=_create_span("x_var")) - c_1 = relay.const(np.ones(10), span=_create_span("let")) - add = _set_span(relay.add(x, x), "let") - body = relay.Let(x, c_1, add, span=_create_span("let")) - - c_2 = relay.const(np.zeros(10), span=_create_span("zeros")) - y = _set_span(relay.add(body, c_2), "add_2") - return relay.Function([x], y) - - _verify_structural_equal_with_span(_res(), _golden()) - - def test_if(self): - def _res(): - x = set_span(relay.var("x", shape=[], dtype="float32"), "x_var") - y = set_span(relay.var("y", shape=[], dtype="float32"), "y_var") - eq = relay.equal(x, y) - - true_branch = set_span(relay.add(x, y), "true_branch") - false_branch = relay.subtract(x, y) - ife = set_span(relay.If(eq, true_branch, false_branch), "if") - return relay.Function([x, y], ife) - - def _golden(): - x = relay.var("x", shape=[], dtype="float32", span=_create_span("x_var")) - y = relay.var("y", shape=[], dtype="float32", span=_create_span("y_var")) - eq = _set_span(relay.equal(x, y), "if") - - true_branch = _set_span(relay.add(x, y), "true_branch") - false_branch = _set_span(relay.subtract(x, y), "if") - ife = relay.If(eq, true_branch, false_branch, span=_create_span("if")) - return relay.Function([x, y], ife) - - _verify_structural_equal_with_span(_res(), _golden()) - - def test_fn(self): - def _res(): - x = set_span(relay.var("x", shape=(1, 64, 56, 56)), "x_var") - w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64") - y = relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)) - f = set_span(relay.Function([x], y), "func") - return f - - def _golden(): - x = relay.var("x", shape=(1, 64, 56, 56), span=_create_span("x_var")) - w = relay.const(np.ones([64, 64, 3, 3]), dtype="int64", span=_create_span("func")) - y = _set_span( - relay.nn.conv2d(x, w, channels=64, kernel_size=(3, 3), padding=(1, 1)), "func" - ) - f = relay.Function([x], y, span=_create_span("func")) - return f - - _verify_structural_equal_with_span(_res(), _golden()) - - -if __name__ == "__main__": - testing.main() diff --git a/tests/python/frontend/tflite/test_forward.py b/tests/python/frontend/tflite/test_forward.py deleted file mode 100644 index cb0b17ea3fcf..000000000000 --- a/tests/python/frontend/tflite/test_forward.py +++ /dev/null @@ -1,5722 +0,0 @@ -# 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. -# pylint: disable=unused-argument, import-outside-toplevel, inconsistent-return-statements -""" -TFLite testcases -================ -This article is a test script to test TFLite operator with Relay. -""" -from __future__ import print_function -from functools import partial -import platform -import os -import tempfile -import typing -from packaging import version as package_version -import pytest -import numpy as np - -from PIL import Image - -from tflite.BuiltinOperator import BuiltinOperator - -try: - import tensorflow.compat.v1 as tf - - # tensorflow.python.framework.ops module itself is not part of - # TensorFlow's public API: the precise contents of that module - # may vary from one version to the next - import tensorflow.compat.v1 as ops -except ImportError: - import tensorflow as tf - import tensorflow as ops -from tensorflow.python.framework import constant_op - -from tensorflow.python.ops import math_ops -from tensorflow.python.ops import nn_ops -from tensorflow.python.ops import array_ops -from tensorflow.python.ops import image_ops -from tensorflow.python.ops import gen_array_ops -from tensorflow.python.ops import nn_impl -from tensorflow.python.ops import variables -from tensorflow import raw_ops - -try: - from tensorflow import lite as interpreter_wrapper -except ImportError: - from tensorflow.contrib import lite as interpreter_wrapper - -import tvm -import tvm.relay.testing.tf as tf_testing -from tvm.contrib.download import download_testdata -from tvm import relay, ir -from tvm.contrib import graph_executor -from relay.utils.tag_span import _set_span, _create_span, _verify_structural_equal_with_span - - -####################################################################### -# Generic run functions for TVM & TFLite -# -------------------------------------- -def convert_to_list(x): - if not isinstance(x, list): - x = [x] - return x - - -####################################################################### -# Get a real image for e2e testing -# -------------------------------- -def get_real_image(im_height, im_width, quantized=True): - repo_base = "https://github.com/dmlc/web-data/raw/main/tensorflow/models/InceptionV1/" - img_name = "elephant-299.jpg" - image_url = os.path.join(repo_base, img_name) - img_path = download_testdata(image_url, img_name, module="data") - image = Image.open(img_path).resize((im_height, im_width)) - x = np.array(image).astype("uint8") if quantized else np.array(image).astype("float32") - data = np.reshape(x, (1, im_height, im_width, 3)) - return data - - -def pre_processed_image(height, width): - """Image preprocessed""" - repo_base = "https://github.com/dmlc/web-data/raw/main/tensorflow/models/InceptionV1/" - img_name = "elephant-299.jpg" - image_url = os.path.join(repo_base, img_name) - img_path = download_testdata(image_url, img_name, module="data") - image = tf.io.read_file(img_path) - image = tf.image.decode_jpeg(image, channels=3) - with tf.name_scope("eval_image"): - if image.dtype != tf.float32: - image = tf.image.convert_image_dtype(image, dtype=tf.float32) - image = tf.image.central_crop(image, central_fraction=0.875) - # Resize the image to the specified height and width. - image = tf.image.resize(image, [height, width], align_corners=False) - image = tf.expand_dims(image, axis=0) - return image - - -def get_real_image_object_detection(im_height, im_width): - repo_base = "https://github.com/dmlc/web-data/raw/main/gluoncv/detection/" - img_name = "street_small.jpg" - image_url = os.path.join(repo_base, img_name) - img_path = download_testdata(image_url, img_name, module="data") - image = Image.open(img_path).resize((im_height, im_width)) - x = np.array(image).astype("uint8") - data = np.reshape(x, (1, im_height, im_width, 3)) - return data - - -def vmobj_to_list(obj): - """Converts TVM objects returned by VM execution to Python List.""" - if isinstance(obj, tvm.nd.NDArray): - return [obj.numpy().tolist()] - elif isinstance(obj, tvm.runtime.container.ADT): - result = [] - for f in obj: - result.extend(vmobj_to_list(f)) - return result - elif isinstance(obj, tvm.relay.backend.interpreter.ConstructorValue): - if obj.constructor.name_hint == "Cons": - t_l = vmobj_to_list(obj.fields[1]) - h_d = vmobj_to_list(obj.fields[0]) - h_d.extend(t_l) - return h_d - elif obj.constructor.name_hint == "Nil": - return [] - elif "tensor_nil" in obj.constructor.name_hint: - return [0] - elif "tensor" in obj.constructor.name_hint: - return [obj.fields[0].numpy()] - else: - raise RuntimeError(f"Unknown object type: {obj.constructor.name_hint}") - else: - raise RuntimeError(f"Unknown object type: {type(obj)}") - - -def _quantize_keras_model( - keras_model, - representative_data_gen, - is_float_input=False, - is_float_output=False, - int_quant_dtype=tf.int8, -): - """Utility function to quantize a Keras model using TFLite converter.""" - converter = interpreter_wrapper.TFLiteConverter.from_keras_model(keras_model) - if int_quant_dtype == tf.int8: - converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE] - converter.representative_dataset = representative_data_gen - converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] - inference_dtype = tf.uint8 - elif int_quant_dtype == tf.int16: - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.representative_dataset = representative_data_gen - converter.target_spec.supported_ops = [ - tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8 - ] - inference_dtype = tf.uint16 - else: - raise RuntimeError( - f"Invalid quantized dtype {int_quant_dtype}. Supported types: int8, int16." - ) - - # NOTE: If representative dataset is provided, and inference input type is not set, - # then converter will self add quant & dequant Op accordingly. - if not is_float_input: - converter.inference_input_type = inference_dtype - if not is_float_output: - converter.inference_output_type = inference_dtype - - return converter.convert() - - -def run_tvm_graph( - tflite_model_buf, - input_data, - input_node, - num_output=1, - target="llvm", - out_names=None, - mode="graph_executor", - op_converter=relay.frontend.tflite.OperatorConverter, -): - """Generic function to compile on relay and execute on tvm""" - # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buf, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_buf, 0) - except ImportError as exc: - raise ImportError("The tflite package must be installed") from exc - - input_data = convert_to_list(input_data) - input_node = convert_to_list(input_node) - - shape_dict = {} - dtype_dict = {} - for i, node in enumerate(input_node): - shape_dict[node] = input_data[i].shape - dtype_dict[node] = input_data[i].dtype.name - - with tvm.testing.disable_span_filling(): - mod, params = relay.frontend.from_tflite( - tflite_model, shape_dict=shape_dict, dtype_dict=dtype_dict, op_converter=op_converter - ) - with tvm.testing.enable_span_filling(): - mod_with_span, _ = relay.frontend.from_tflite( - tflite_model, shape_dict=shape_dict, dtype_dict=dtype_dict, op_converter=op_converter - ) - tvm.ir.assert_structural_equal(mod["main"], mod_with_span["main"]) - - if mode in ["debug", "vm"]: - inputs = [] - for param in mod["main"].params: - found = False - for i, n in enumerate(input_node): - if n == param.name_hint: - found = True - inputs.append(tvm.nd.array(input_data[i])) - break - # Interpreter doesn't bind constants, so still need to find in params - if not found: - inputs.append(tvm.nd.array(params[param.name_hint])) - result = relay.create_executor(mode, mod=mod, device=tvm.cpu(), target="llvm").evaluate()( - *inputs - ) - return vmobj_to_list(result) - else: - with tvm.transform.PassContext(opt_level=3): - lib = relay.build(mod, target, params=params) - - dev = tvm.device(target, 0) - - m = graph_executor.GraphModule(lib["default"](dev)) - # set inputs - for i, node in enumerate(input_node): - m.set_input(node, tvm.nd.array(input_data[i].astype(input_data[i].dtype))) - # execute - m.run() - # get outputs - assert out_names is None or num_output == len( - out_names - ), f"out_names: {out_names} num_output: {num_output}" - tvm_output_list = [] - for i in range(0, num_output): - tvm_output = m.get_output(i) - tvm_output_list.append(tvm_output.numpy()) - return tvm_output_list - - -def run_tflite_graph(tflite_model_buf, input_data): - """Generic function to execute TFLite""" - input_data = convert_to_list(input_data) - - interpreter = interpreter_wrapper.Interpreter(model_content=tflite_model_buf) - input_details = interpreter.get_input_details() - output_details = interpreter.get_output_details() - - for i, input_detail in enumerate(input_details): - interpreter.resize_tensor_input(input_detail["index"], input_data[i].shape) - interpreter.allocate_tensors() - - # set input - assert len(input_data) == len(input_details) - for i, input_detail in enumerate(input_details): - interpreter.set_tensor(input_detail["index"], input_data[i]) - - # Run - interpreter.invoke() - - # get output - tflite_output = [] - for _, output_detail in enumerate(output_details): - tflite_output.append(interpreter.get_tensor(output_detail["index"])) - - return tflite_output - - -def compare_tflite_with_tvm( - in_data: typing.List[np.ndarray], - in_name: typing.List[str], - input_tensors: typing.List, - output_tensors: typing.List, - init_global_variables: bool = False, - out_names=None, - quantized=False, - input_range=None, - mode="graph_executor", - experimental_new_converter=False, - fp16_quantized=False, - int_quant_dtype=tf.uint8, -): - """Generic function to generate and compare TFLite and TVM output""" - in_data = convert_to_list(in_data) - in_name = convert_to_list(in_name) - out_names = convert_to_list(out_names) - in_node = [0] * len(in_name) - for i, _ in enumerate(in_name): - in_node[i] = in_name[i].split(":")[0] if ":" in in_name[i] else in_name[i] - - with tf.Session() as sess: - if init_global_variables: - sess.run(variables.global_variables_initializer()) - # convert to tflite model - converter = tf.lite.TFLiteConverter.from_session(sess, input_tensors, output_tensors) - - if len(input_tensors) > 1: - if len(input_tensors[0].shape) <= 4 and len(input_tensors[1].shape) <= 4: - converter._experimental_disable_batchmatmul_unfold = True - else: - converter._experimental_disable_batchmatmul_unfold = False - - converter.experimental_new_converter = experimental_new_converter - if quantized: - if int_quant_dtype == tf.int16: - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.target_spec.supported_ops = [ - tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8 - ] - elif int_quant_dtype == tf.int8: - converter.inference_type = tf.lite.constants.INT8 - else: - # default to int8 quantization - converter.inference_type = tf.lite.constants.QUANTIZED_UINT8 - - input_arrays = converter.get_input_arrays() - input_stats = {} - # calculate the mean and quantization scale for every input tensor, - # with respect to its fp32 input range, defined in fake_quant. - # s = 255/(fmax-fmin); m = -fmin*s (the zero point) - for i in input_arrays: - try: - quant_scale = 255 / (input_range[i][1] - input_range[i][0]) - except ZeroDivisionError: - print("Min and max of the input range for tensor " + i + " can't be equal") - mean = -input_range[i][0] * quant_scale - input_stats[i] = (mean, quant_scale) - converter.quantized_input_stats = input_stats - elif fp16_quantized: - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.target_spec.supported_types = [tf.float16] - - tflite_model_buffer = converter.convert() - tflite_output = run_tflite_graph(tflite_model_buffer, in_data) - - for device in ["llvm"]: - _ = tvm.device(device, 0) - if not tvm.testing.device_enabled(device): - print(f"Skip because {device} is not enabled") - continue - - tvm_output = run_tvm_graph( - tflite_model_buffer, - in_data, - in_node, - target=device, - num_output=len(out_names), - out_names=out_names, - mode=mode, - ) - # WARNING: the results could well be random values clipped to 0 or 255 because of badly - # tuned output range for the specific operator. While adding test ensure that we aren't - # getting only clipped values in output tensors that still pass the assertion. - # For reference see _test_elemwise_qnn_out_range() - if quantized and not fp16_quantized: - for i, _ in enumerate(tflite_output): - # allow absolute tolerance of 1 in the quantized results - tvm.testing.assert_allclose( - tflite_output[i], # pylint: disable=unnecessary-list-index-lookup - tvm_output[i], - atol=1, - rtol=1e-5, - ) - else: - for i, _ in enumerate(tflite_output): - tvm.testing.assert_allclose( - tflite_output[i], # pylint: disable=unnecessary-list-index-lookup - tvm_output[i], - atol=1e-5, - rtol=1e-5, - ) - - -def with_fused_activation_function(input_tensor, fn_name): - """Fused activation function""" - if fn_name is None or fn_name == "NONE": - return input_tensor - if fn_name == "RELU": - return nn_ops.relu(input_tensor) - if fn_name == "RELU6": - return nn_ops.relu6(input_tensor) - if fn_name == "RELU_N1_TO_1": - return math_ops.maximum(-1, math_ops.minimum(input_tensor, 1)) - if fn_name == "TANH": - return math_ops.tanh(input_tensor) - raise AssertionError(f"Unknown fused_activation_function {fn_name}") - - -def _test_split(in_shape, axis, num_splits, dtype): - """internal split tester taking as parameters in_shape, number of tensors to split into - and dtype (data type)""" - - np_data = np.random.uniform(-5, 5, size=in_shape).astype(dtype) - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=in_shape, dtype=dtype, name="in_data") - out = array_ops.split(in_data, num_splits, axis=axis) - num_splits = len(num_splits) if isinstance(num_splits, list) else num_splits - out_names = ["out_" + str(n) + ":0" for n in range(num_splits)] - compare_tflite_with_tvm([np_data], ["in_data"], [in_data], out, out_names=out_names) - - -def test_forward_split(): - """test split layer""" - # rank 1 - _test_split((3,), 0, 1, "float32") - _test_split((3,), 0, 3, "float32") - _test_split((6,), 0, 3, "float32") - # rank 2 - _test_split((6, 2), 0, 3, "float32") - _test_split((2, 6), 1, 6, "float32") - # rank 3 - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_split((6, 2, 4), 0, 2, "int32") - - _test_split((2, 6, 4), 1, 3, "float32") - _test_split((2, 4, 6), 2, 1, "float32") - # rank 4 - _test_split((6, 1, 3, 5), 0, 3, "float32") - _test_split((1, 6, 3, 5), 1, 3, "float32") - _test_split((1, 3, 6, 5), 2, 3, "float32") - _test_split((1, 3, 5, 6), 3, 3, "float32") - # split along negative axis - _test_split((6, 1, 3, 5), -4, 3, "float32") - _test_split((1, 6, 3, 5), -3, 3, "float32") - _test_split((1, 3, 6, 5), -2, 3, "float32") - _test_split((1, 3, 5, 6), -1, 3, "float32") - # size_splits split - _test_split((6,), 0, [1, 2, 3], "float32") - _test_split((3, 6, 4), -2, [1, 4, 1], "float32") - - -####################################################################### -# slice -# ----- - - -def _test_slice(data, begin, size): - """One iteration of SLICE""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = array_ops.slice(in_data, begin, size) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_slice(): - """SLICE""" - _test_slice(np.arange(4, dtype=np.float32).reshape((4,)), begin=[0], size=[2]) - _test_slice(np.arange(18, dtype=np.int32).reshape((3, 2, 3)), begin=[1, 0, 0], size=[1, 1, 3]) - # tflite 1.13 outputs nonsense values if size[i] == -1 - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_slice(np.arange(8, dtype=np.int32).reshape((2, 4)), begin=[0, 1], size=[-1, -1]) - _test_slice(np.arange(5, dtype=np.int32).reshape((5,)), begin=[4], size=[-1]) - - -####################################################################### -# Topk -# ---- -def _test_topk(in_shape, k=1): - """One iteration of TOPK""" - data = np.random.uniform(size=in_shape).astype("float32") - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = nn_ops.top_k(in_data, k, name="TopK") - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out[0]]) - - -def test_forward_topk(): - """TOPK""" - _test_topk((3,), 1) - _test_topk((3,), 3) - _test_topk((3, 5, 7), 3) - _test_topk((3, 5, 7), 3) - - -####################################################################### -# Gather -# ------ - - -def _test_gather(dshape, indices, axis, dtype, quantized=False, oob=False, wrap_idx=False): - """One iteration of Gather""" - indices = np.asarray(indices).astype("int32") - data = np.random.uniform(1, 10, size=dshape) - data = data.astype(np.uint8) if quantized else data.astype(dtype) - with tf.Graph().as_default(): - if wrap_idx: - in_name = "in_indices" - indices_expr = array_ops.placeholder( - shape=indices.shape, dtype=indices.dtype, name=in_name - ) - in_tensor_name = [in_name + ":0"] - in_indices = [indices_expr] - else: - indices_expr = indices - indices = [] - in_tensor_name = [] - in_indices = [] - - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype, name="in_data") - if axis: - out = array_ops.gather(in_data, indices_expr, axis=axis) - else: - out = array_ops.gather(in_data, indices_expr) # tflite conversion fails for None axis - input_range = {"in_data": (-100, 100)} if quantized else None - try: - compare_tflite_with_tvm( - [data] + indices, - ["in_data:0"] + in_tensor_name, - [in_data] + in_indices, - [out], - quantized=quantized, - input_range=input_range, - ) - except ValueError as exc: - if not oob: - raise exc - except Exception as exc: - raise exc - - -def test_forward_gather(): - """GATHER""" - for quantized in [False, True]: - for wrap_idx in [False, True]: - _test_gather((4,), [1], 0, "float32", quantized, wrap_idx) - _test_gather((4,), [1], None, "int32", quantized, wrap_idx) - _test_gather((1, 4), [0], 0, "int32", quantized, wrap_idx) - _test_gather((4,), [[[1, 0], [0, 1]]], 0, "float32", quantized, wrap_idx) - _test_gather((2, 2), [[[1, 0], [0, 1]]], 1, "int32", quantized, wrap_idx) - _test_gather((2, 2), [[[1, 0], [0, 1]]], None, "float32", quantized, wrap_idx) - _test_gather((3, 3, 3), [[[1, 0]]], 0, "int32", quantized, wrap_idx) - _test_gather((3, 3, 3), [[[1, 0]]], 2, "int32", quantized, wrap_idx) - _test_gather((4, 3, 5, 6), [[2, 1, 0, 0]], 0, "float32", quantized, wrap_idx) - _test_gather((3, 3, 3), [[[2, 1]]], -1, "int32", quantized, wrap_idx) - # Out of boundary error cannot be tested with wrapped index - _test_gather((4,), [16], 0, "float32", quantized, oob=True) - _test_gather((1, 3, 3), [12], 0, "int32", quantized, oob=True) - _test_gather((1, 3, 3), [20], 1, "float32", quantized, oob=True) - _test_gather((1, 3, 3), [20, 20], 2, "float32", quantized, oob=True) - - -####################################################################### -# Gather_ND -# --------- - - -def _test_gather_nd(data, indices): - """One iteration of GATHER_ND""" - with tf.Graph().as_default(): - in_data = tf.placeholder(shape=data.shape, dtype=data.dtype, name="data") - indices_data = tf.placeholder(shape=indices.shape, dtype=indices.dtype, name="indices") - out = tf.gather_nd(in_data, indices_data) - - compare_tflite_with_tvm( - [data, indices], ["data:0", "indices:0"], [in_data, indices_data], [out] - ) - - -def test_forward_gather_nd(): - """GATHER_ND""" - _test_gather_nd( - np.array([[[1.2, 2.0], [3.1, 4.1]], [[5.1, 6.1], [7.1, 8.1]]]).astype("float32"), - np.asarray([[0, 1], [1, 0]]).astype("int32"), - ) - _test_gather_nd( - np.reshape(np.arange(30), [5, 6]).astype("int32"), np.asarray([[1, 2]]).astype("int32") - ) - _test_gather_nd( - np.reshape(np.arange(12), [2, 3, 2]).astype("int32"), - np.asarray([[[0, 0], [0, 1]], [[1, 0], [1, 1]]]).astype("int32"), - ) - _test_gather_nd( - np.reshape(np.arange(4), [4]).astype("float32"), np.asarray([1]).astype("int32") - ) - _test_gather_nd( - np.reshape(np.arange(4), [1, 4]).astype("float32"), np.asarray([0]).astype("int32") - ) - _test_gather_nd( - np.reshape(np.arange(4), [1, 4]).astype("float32"), np.asarray([0, 3]).astype("int32") - ) - - -####################################################################### -# StridedSlice -# ------------ - - -def _test_stridedslice( - ip_shape, - begin, - end, - stride, - dtype, - begin_mask=0, - end_mask=0, - new_axis_mask=0, - shrink_axis_mask=0, - ellipsis_mask=0, - quantized=False, -): - """One iteration of a Stridedslice""" - data = np.random.uniform(size=ip_shape).astype(dtype) - data = data.astype(np.uint8) if quantized else data.astype(dtype) - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype, ip_shape, name="in_data") - out = array_ops.strided_slice( - in_data, - begin, - end, - stride, - begin_mask=begin_mask, - end_mask=end_mask, - new_axis_mask=new_axis_mask, - shrink_axis_mask=shrink_axis_mask, - ellipsis_mask=ellipsis_mask, - ) - input_range = {"in_data": (-100, 100)} if quantized else None - compare_tflite_with_tvm( - [data], ["in_data:0"], [in_data], [out], quantized=quantized, input_range=input_range - ) - - -def test_forward_stridedslice(): - """test StridedSlice""" - for quantized in [False, True]: - _test_stridedslice( - (1, 3, 3), - [0, 0, 0], - [3, 3, 3], - [1, 1, 1], - "float32", - shrink_axis_mask=7, - quantized=quantized, - ) - _test_stridedslice( - (1, 3, 3), - [0, 0, 0], - [3, 3, 3], - [1, 1, 1], - "float32", - shrink_axis_mask=5, - quantized=quantized, - ) - _test_stridedslice((2), [1], [1], [1], "float32", shrink_axis_mask=1, quantized=quantized) - _test_stridedslice( - (3, 4, 3), [1, -1, 0], [4, -5, 3], [2, -1, 1], "float32", quantized=quantized - ) - _test_stridedslice( - (3, 4), [1, 0], [4, 4], [1, 1], "float32", shrink_axis_mask=0, quantized=quantized - ) - _test_stridedslice( - (4, 4), [1, 0], [4, 4], [1, 1], "float32", shrink_axis_mask=2, quantized=quantized - ) - _test_stridedslice( - (3, 4), [-1, 0], [0, 3], [1, 1], "float32", shrink_axis_mask=1, quantized=quantized - ) - - -####################################################################### -# transpose -# --------- - - -def _test_forward_transpose(ishape, axes=()): - data = np.random.uniform(size=ishape).astype(np.float32) - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - if not axes: - out = array_ops.transpose(in_data) - else: - out = array_ops.transpose(in_data, axes) - - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_transpose(): - _test_forward_transpose((2, 2)) - _test_forward_transpose((2, 3, 4)) - _test_forward_transpose((7, 8, 8, 10)) - _test_forward_transpose((2, 3, 4), (1, 2, 0)) - _test_forward_transpose((2, 3, 4), (0, 1, 2)) - _test_forward_transpose((2, 3, 4, 5), (3, 0, 1, 2)) - _test_forward_transpose((2, 3, 4, 5), ()) - - -####################################################################### -# Cast -# ---- - - -def _test_cast(data, cast_dtype, use_mlir=False): - """One iteration of CAST""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = math_ops.cast(in_data, cast_dtype) - compare_tflite_with_tvm( - data, "Placeholder:0", [in_data], [out], experimental_new_converter=use_mlir - ) - - -def test_forward_cast(): - """CAST""" - for use_mlir in [False, True]: - _test_cast( - np.arange(6.0, dtype=np.float32).reshape((1, 6)), cast_dtype=tf.int32, use_mlir=use_mlir - ) - _test_cast( - np.arange(6.0, dtype=np.float32).reshape((1, 6)), cast_dtype=tf.uint8, use_mlir=use_mlir - ) - _test_cast( - np.arange(6.0, dtype=np.int32).reshape((1, 6)), cast_dtype=tf.int64, use_mlir=use_mlir - ) - - -####################################################################### -# Batch Mat Mul -# ---- -def _test_batch_matmul( - a_shape, b_shape, dtype, out_dtype, adjoint_a=False, adjoint_b=False, quantized=False -): - with tf.Graph().as_default(): - a = array_ops.placeholder(shape=a_shape, dtype=dtype, name="A") - b = array_ops.placeholder(shape=b_shape, dtype=dtype, name="B") - print(tf.__version__) - - result = raw_ops.BatchMatMulV3( - x=a, y=b, Tout=out_dtype, adj_x=adjoint_a, adj_y=adjoint_b, name="batchmatmul" - ) - input_range = {"A": (-100, 100), "B": (-100, 100)} if quantized else None - - a_np = np.random.uniform(high=5.0, size=a_shape).astype(dtype) - b_np = np.random.uniform(high=5.0, size=b_shape).astype(dtype) - compare_tflite_with_tvm( - [a_np, b_np], - [a.name, b.name], - [a, b], - [result], - experimental_new_converter=True, - quantized=quantized, - input_range=input_range, - ) - - -@pytest.mark.parametrize("config", [("int8", "int32", True), ("float32", "float32", False)]) -def test_forward_batch_matmul(config): - """BATCH_MAT_MUL""" - _test_batch_matmul( - (3, 5, 4), (3, 4, 5), dtype=config[0], out_dtype=config[1], quantized=config[2] - ) - _test_batch_matmul( - (3, 5, 4), - (3, 4, 5), - dtype=config[0], - out_dtype=config[1], - adjoint_a=True, - adjoint_b=True, - quantized=config[2], - ) - _test_batch_matmul( - (3, 5, 4), - (3, 5, 4), - dtype=config[0], - out_dtype=config[1], - adjoint_a=True, - adjoint_b=False, - quantized=config[2], - ) - _test_batch_matmul( - (2, 3, 5, 4), - (1, 3, 5, 4), - dtype=config[0], - out_dtype=config[1], - adjoint_a=True, - adjoint_b=False, - quantized=config[2], - ) - _test_batch_matmul( - (3, 5, 4), - (3, 5, 4), - dtype=config[0], - out_dtype=config[1], - adjoint_a=False, - adjoint_b=True, - quantized=config[2], - ) - _test_batch_matmul( - (2, 3, 5, 4), - (1, 3, 5, 4), - dtype=config[0], - out_dtype=config[1], - adjoint_a=False, - adjoint_b=True, - quantized=config[2], - ) - _test_batch_matmul( - (3, 4, 5, 6), (3, 4, 6, 5), dtype=config[0], out_dtype=config[1], quantized=config[2] - ) - # BatchMatMul doesn't support larger than 4D tensors - # _test_batch_matmul( - # (2, 3, 4, 5, 6), (2, 3, 4, 6, 5), dtype=config[0], out_dtype=config[1], quantized=config[2] - # ) - - -####################################################################### -# Tile -# ---- - - -def _test_forward_tile(in_shape, reps, dtype): - data = np.random.uniform(-5, 5, size=in_shape).astype(dtype) - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - out = array_ops.tile(in_data, reps) - - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_tile(): - _test_forward_tile((2,), (3,), "int32") - _test_forward_tile((2, 2), (2, 3), "float32") - - -###################################################################### -# BatchToSpaceND -# -------------- - - -def _test_batch_to_space_nd(input_shape, block_shape, crops, dtype="int32"): - data = np.random.uniform(0, 5, size=input_shape).astype(dtype) - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype=dtype) - - out = array_ops.batch_to_space_nd(in_data, block_shape, crops) - - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_batch_to_space_nd(): - # test cases: https://www.tensorflow.org/api_docs/cc/class/tensorflow/ops/batch-to-space-n-d - _test_batch_to_space_nd(input_shape=[4, 1, 1, 1], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd(input_shape=[4, 1, 1, 3], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd(input_shape=[4, 2, 2, 1], block_shape=[2, 2], crops=[[0, 0], [0, 0]]) - - _test_batch_to_space_nd(input_shape=[4, 3, 3, 1], block_shape=[2, 2], crops=[[0, 1], [0, 1]]) - - -###################################################################### -# SpaceToBatchND -# -------------- - - -def _test_space_to_batch_nd(input_shape, block_shape, paddings, dtype="int32"): - data = np.random.uniform(0, 5, size=input_shape).astype(dtype) - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype=dtype) - - out = array_ops.space_to_batch_nd(in_data, block_shape, paddings) - - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_space_to_batch_nd(): - # test cases: https://www.tensorflow.org/api_docs/python/tf/space_to_batch_nd - _test_space_to_batch_nd(input_shape=[1, 2, 2, 1], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd(input_shape=[1, 2, 2, 3], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd(input_shape=[1, 4, 4, 1], block_shape=[2, 2], paddings=[[0, 0], [0, 0]]) - - _test_space_to_batch_nd(input_shape=[2, 2, 4, 1], block_shape=[2, 2], paddings=[[0, 0], [2, 0]]) - - -####################################################################### -# Pooling -# ------- -def _test_pooling_iteration(input_shape, **kwargs): - """One iteration of pool operation with given shapes and attributes""" - - x = -np.arange(np.prod(input_shape), dtype=np.float32).reshape(input_shape) - 1 - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=input_shape, dtype="float32") - out = nn_ops.pool(in_data, **kwargs) - - compare_tflite_with_tvm(x, "Placeholder:0", [in_data], [out]) - - -def _test_pooling(input_shape, **kwargs): - _test_pooling_iteration(input_shape, **kwargs) - - -def test_forward_pooling(): - """Pooling""" - - for pool_type in ["AVG", "MAX"]: - _test_pooling( - input_shape=[2, 9, 10, 2], - window_shape=[1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 10, 9, 2], - window_shape=[1, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 9, 10, 2], - window_shape=[2, 1], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[1, 1], - ) - - _test_pooling( - input_shape=[2, 10, 9, 2], - window_shape=[2, 3], - padding="SAME", - pooling_type=pool_type, - dilation_rate=[1, 1], - strides=[2, 1], - ) - - -def _test_l2_pool2d(input_shape, ksize, strides, padding, data_format, fused_func_name=None): - x = np.arange(np.prod(input_shape), dtype=np.float32).reshape(input_shape) - 1 - - with tf.Graph().as_default(): - in_data = tf.placeholder(dtype=tf.float32, name="input", shape=input_shape) - out = tf.sqrt( - tf.nn.avg_pool( - tf.square(in_data), - ksize=ksize, - strides=strides, - padding=padding, - data_format=data_format, - ) - ) - out = with_fused_activation_function(out, fused_func_name) - - compare_tflite_with_tvm(x, "input", [in_data], [out]) - - -def test_forward_l2_pool2d(): - _test_l2_pool2d([1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], "SAME", "NHWC", "RELU6") - _test_l2_pool2d([2, 9, 10, 2], [1, 1, 1, 1], [1, 1, 1, 1], "SAME", "NHWC", "RELU6") - _test_l2_pool2d([2, 9, 10, 2], [1, 2, 1, 1], [1, 1, 1, 1], "SAME", "NHWC") - _test_l2_pool2d([2, 9, 10, 2], [1, 2, 1, 1], [1, 1, 2, 1], "SAME", "NHWC") - _test_l2_pool2d([1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], "VALID", "NHWC", "RELU") - _test_l2_pool2d([2, 9, 10, 2], [1, 1, 1, 1], [1, 1, 1, 1], "VALID", "NHWC") - _test_l2_pool2d([2, 9, 10, 2], [1, 2, 1, 1], [1, 1, 1, 1], "VALID", "NHWC") - _test_l2_pool2d([2, 9, 10, 2], [1, 2, 1, 1], [1, 1, 2, 1], "VALID", "NHWC", "RELU6") - - -####################################################################### -# Convolution -# ----------- - - -def _test_tflite2_quantized_convolution( - input_shape, - kernel_shape, - filters, - padding="valid", - data_format=None, - int_quant_dtype=tf.int8, - groups=1, -): - """One iteration of TFLite2 quantized convolution with given shapes and attributes""" - data_format = "channels_last" if data_format == "NHWC" else "channels_first" - data = np.random.uniform(0, 1, input_shape).astype("float32") - _ = np.random.uniform(0, 1, kernel_shape).astype("float32") - - data_in = tf.keras.layers.Input(shape=data.shape[1:]) - conv = tf.keras.layers.Conv2D( - filters=filters, - kernel_size=(kernel_shape[0], kernel_shape[1]), - activation=tf.nn.relu, - padding=padding, - data_format=data_format, - groups=groups, - )(data_in) - keras_model = tf.keras.models.Model(data_in, conv) - - # To create quantized values with dynamic range of activations, needs representative dataset - def representative_data_gen(): - for _ in range(1): - yield [data] - - tflite_model_quant = _quantize_keras_model( - keras_model, - representative_data_gen, - is_float_input=True, - is_float_output=True, - int_quant_dtype=int_quant_dtype, - ) - # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_quant, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_quant, 0) - except ImportError as exc: - raise ImportError("The tflite package must be installed") from exc - - subgraph = tflite_model.Subgraphs(0) - model_input = subgraph.InputsAsNumpy() - input_node = subgraph.Tensors(model_input).Name().decode("utf-8") - - tflite_output = run_tflite_graph(tflite_model_quant, data) - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - input_node = data_in.name.replace(":0", "") - else: - input_node = "serving_default_" + data_in.name + ":0" - tvm_output = run_tvm_graph(tflite_model_quant, data, input_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-2, atol=1e-2 - ) - - -def test_forward_quantized_convolution(): - """Quantized convolution""" - for int_quant_dtype in [tf.int8, tf.int16]: - _test_tflite2_quantized_convolution( - (1, 28, 28, 1), - (1, 1), - 12, - data_format="NHWC", - int_quant_dtype=int_quant_dtype, - ) - - _test_tflite2_quantized_convolution( - (1, 1, 28, 28), - (1, 1), - 12, - data_format="NCWH", - int_quant_dtype=int_quant_dtype, - ) - - _test_tflite2_quantized_convolution( - (64, 2, 28, 28), - (1, 1), - 12, - data_format="NCWH", - int_quant_dtype=int_quant_dtype, - ) - - _test_tflite2_quantized_convolution( - (2, 32, 28, 28), - (1, 1), - 16, - data_format="NCWH", - int_quant_dtype=int_quant_dtype, - groups=8, - ) - - if platform.machine() == "aarch64": - pytest.skip( - reason=( - "Grouped convolution type inference error for `arm_cpu`. " - "See https://github.com/apache/tvm/issues/16532" - ) - ) - - _test_tflite2_quantized_convolution( - (1, 16, 10, 10), - (3, 3), - 2, - data_format="NCWH", - int_quant_dtype=int_quant_dtype, - groups=2, - ) - - -def test_forward_quantized_depthwise_convolution(): - """Test qnn.conv2d depthwise compiled with TVM against TFLite reference.""" - for int_quant_dtype in [tf.int8, tf.int16]: - _test_tflite2_quantized_depthwise_convolution( - [1, 17, 17, 12], [3, 3, 12, 1], [1, 1], [2, 2], "VALID", "NHWC", 1, int_quant_dtype - ) - _test_tflite2_quantized_depthwise_convolution( - [1, 24, 24, 3], [7, 7, 3, 8], [1, 1], [2, 2], "SAME", "NHWC", 8, int_quant_dtype - ) - _test_tflite2_quantized_depthwise_convolution( - [1, 8, 8, 128], [1, 1, 128, 1], [1, 1], [1, 1], "SAME", "NHWC", 1, tf.int8 - ) - - if platform.machine() == "aarch64": - pytest.skip( - reason=( - "Tensor intrinsic data type mismatch error. " - "See https://github.com/apache/tvm/issues/16533" - ) - ) - - _test_tflite2_quantized_depthwise_convolution( - [1, 8, 8, 128], [1, 1, 128, 1], [1, 1], [1, 1], "SAME", "NHWC", 1, tf.int16 - ) - - -def _test_tflite2_quantized_depthwise_convolution( - input_shape, - kernel_shape, - dilations, - strides, - padding, - data_format, - depth_multiplier, - int_quant_dtype=tf.int8, -): - """One iteration of TFLite2 quantized depthwise convolution with given shapes and attributes""" - - data_format = "channels_last" if data_format == "NHWC" else "channels_first" - data = np.random.uniform(0, 1, input_shape).astype("float32") - kernel = np.random.uniform(0, 1, kernel_shape).astype("float32") - - data_in = tf.keras.layers.Input(shape=data.shape[1:]) - conv = tf.keras.layers.DepthwiseConv2D( - kernel_size=(kernel_shape[0], kernel_shape[1]), - strides=strides, - padding=padding, - data_format=data_format, - activation="relu", - use_bias=False, - depth_multiplier=depth_multiplier, - )(data_in) - keras_model = tf.keras.models.Model(data_in, conv) - keras_model.layers[1].set_weights([kernel]) - - # To create quantized values with dynamic range of activations, needs representative dataset - def representative_data_gen(): - for _ in range(1): - yield [data] - - tflite_model_quant = _quantize_keras_model( - keras_model, - representative_data_gen, - is_float_input=True, - is_float_output=True, - int_quant_dtype=int_quant_dtype, - ) - - # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_quant, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_quant, 0) - except ImportError as exc: - raise ImportError("The tflite package must be installed") from exc - - subgraph = tflite_model.Subgraphs(0) - model_input = subgraph.InputsAsNumpy() - input_node = subgraph.Tensors(model_input).Name().decode("utf-8") - - tflite_output = run_tflite_graph(tflite_model_quant, data) - tvm_output = run_tvm_graph(tflite_model_quant, data, input_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-2, atol=1e-2 - ) - - -def _test_convolution( - tensor_in_sizes, - filter_in_sizes, - dilations, - strides, - padding, - data_format, - is_depthwise=False, - quantized=False, - fp16_quantized=False, -): - """One iteration of convolution with given shapes and attributes""" - - total_size_1 = 1 - total_size_2 = 1 - for s in tensor_in_sizes: - total_size_1 *= s - for s in filter_in_sizes: - total_size_2 *= s - # Initializes the input tensor with array containing incrementing - # numbers from 1. - if quantized: - data_array = np.random.uniform(0, 255, tensor_in_sizes).astype("uint8") - filter_array = np.random.uniform(0, 255, filter_in_sizes).astype("uint8") - else: - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - filter_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32", name="in_data") - in_filter = constant_op.constant( - filter_array, shape=filter_in_sizes, dtype="float32", name="in_filter" - ) - strides = [1] + strides + [1] - dilations = [1] + dilations + [1] - - if is_depthwise: - out = nn_ops.depthwise_conv2d_native( - in_data, in_filter, strides=strides, padding=padding, data_format=data_format - ) - else: - out = nn_ops.conv2d( - in_data, in_filter, strides=strides, padding=padding, data_format=data_format - ) - - if quantized and not fp16_quantized: - if is_depthwise: - # Quantized the inputs and feed them to the convolution - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-100, max=100, name="inq_data" - ) - inq_filter = tf.quantization.fake_quant_with_min_max_args( - in_filter, min=-100, max=100, name="inq_filter" - ) - out = nn_ops.depthwise_conv2d_native( - inq_data, inq_filter, strides=strides, padding=padding, data_format=data_format - ) - out = tf.quantization.fake_quant_with_min_max_args( - out, min=-200, max=200, name="out" - ) - - # Set the input quantization range - input_range = {"in_data": (-100, 100)} if quantized else None - - # Compare - compare_tflite_with_tvm( - data_array, - "in_data", - [in_data], - [out], - quantized=quantized, - input_range=input_range, - experimental_new_converter=True, - ) - else: - # Quantized the inputs and feed them to the convolution - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-100, max=100, name="inq_data" - ) - inq_filter = tf.quantization.fake_quant_with_min_max_args( - in_filter, min=-100, max=100, name="inq_filter" - ) - out = nn_ops.conv2d( - inq_data, inq_filter, strides=strides, padding=padding, data_format=data_format - ) - out = tf.quantization.fake_quant_with_min_max_args( - out, min=-200, max=200, name="out" - ) - - # Set the input quantization range - input_range = {"in_data": (-100, 100)} if quantized else None - - # Compare - compare_tflite_with_tvm( - data_array, - "in_data", - [in_data], - [out], - quantized=quantized, - input_range=input_range, - experimental_new_converter=True, - ) - else: - data_array = np.reshape(data_array, tensor_in_sizes).astype("float32") - compare_tflite_with_tvm(data_array, "in_data", [in_data], [out]) - - -def test_forward_convolution(): - """Convolution""" - for quantized in [False, True]: - for fp16_quantized in [False, True]: - _test_convolution( - [4, 8, 8, 176], - [1, 1, 176, 32], - [1, 1], - [1, 1], - "SAME", - "NHWC", - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 19], - [3, 3, 19, 19], - [1, 1], - [2, 2], - "VALID", - "NHWC", - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 124], - [1, 1, 124, 19], - [1, 1], - [1, 1], - "SAME", - "NHWC", - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 12], - [3, 3, 12, 32], - [1, 1], - [2, 2], - "VALID", - "NHWC", - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - - # depthwise convolution - _test_convolution( - [4, 8, 8, 176], - [1, 1, 176, 1], - [1, 1], - [1, 1], - "SAME", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 19], - [3, 3, 19, 1], - [1, 1], - [2, 2], - "VALID", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 124], - [1, 1, 124, 1], - [1, 1], - [1, 1], - "SAME", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 12], - [3, 3, 12, 1], - [1, 1], - [2, 2], - "VALID", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - _test_convolution( - [4, 17, 17, 12], - [3, 3, 12, 2], - [1, 1], - [2, 2], - "VALID", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - # depthwise convolution with single input channel - _test_convolution( - [1, 76, 64, 1], - [9, 5, 1, 96], - [1, 1], - [1, 1], - "SAME", - "NHWC", - True, - quantized=quantized, - fp16_quantized=fp16_quantized, - ) - - # TFLite2 quantized convolution testing - if package_version.parse(tf.VERSION) >= package_version.parse("2.3.0"): - _test_convolution( - [1, 8, 8, 176], [1, 1, 176, 32], [1, 1], [1, 1], "SAME", "NHWC", quantized=True - ) - _test_convolution( - [1, 17, 17, 12], [3, 3, 12, 32], [1, 1], [2, 2], "VALID", "NHWC", quantized=True - ) - _test_convolution( - [1, 17, 17, 19], [3, 3, 19, 19], [1, 1], [2, 2], "VALID", "NHWC", quantized=True - ) - _test_convolution( - [1, 17, 17, 124], [1, 1, 124, 19], [1, 1], [1, 1], "SAME", "NHWC", quantized=True - ) - - -####################################################################### -# Transpose Convolution -# --------------------- - - -def _test_transpose_conv( - tensor_in_sizes, - filter_in_sizes, - output_shape, - strides, - padding, - quantized=False, - fp16_quantized=False, -): - """One iteration of transpose convolution with given shapes and attributes""" - - total_size_1 = 1 - total_size_2 = 1 - for s in tensor_in_sizes: - total_size_1 *= s - for s in filter_in_sizes: - total_size_2 *= s - - with tf.Graph().as_default(): - if quantized and not fp16_quantized: - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [max(f, 255) for f in range(1, total_size_1 + 1)] - filter_array = [max(f, 255) for f in range(1, total_size_2 + 1)] - data_array = np.reshape(data_array, tensor_in_sizes).astype("uint8") - filter_array = np.reshape(filter_array, filter_in_sizes).astype("uint8") - - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32", name="in_data") - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-100, max=100, name="q_data" - ) - input_range = {"q_data": (-100, 100)} - - in_filter = constant_op.constant( - filter_array, shape=filter_in_sizes, dtype="float32", name="in_filter" - ) - inq_filter = tf.quantization.fake_quant_with_min_max_args( - in_filter, min=-100, max=100, name="q_filter" - ) - - strides = [1] + strides + [1] - - out = nn_ops.conv2d_transpose( - inq_data, inq_filter, output_shape=output_shape, strides=strides, padding=padding - ) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-100, max=100, name="out") - compare_tflite_with_tvm( - [data_array], ["q_data"], [inq_data], [out], quantized=True, input_range=input_range - ) - else: - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = [f * 1.0 for f in range(1, total_size_1 + 1)] - filter_array = [f * 1.0 for f in range(1, total_size_2 + 1)] - - in_data = array_ops.placeholder(shape=tensor_in_sizes, dtype="float32", name="in_data") - in_filter = constant_op.constant( - filter_array, shape=filter_in_sizes, dtype="float32", name="in_filter" - ) - strides = [1] + strides + [1] - # in_filter layout is HWOI - out = nn_ops.conv2d_transpose( - in_data, in_filter, output_shape=output_shape, strides=strides, padding=padding - ) - data_array = np.reshape(data_array, tensor_in_sizes).astype("float32") - compare_tflite_with_tvm( - [data_array], ["in_data"], [in_data], [out], fp16_quantized=fp16_quantized - ) - - -def test_forward_transpose_conv(): - """Transpose convolution""" - for quantized in [True, False]: - for fp16_quantized in [True, False]: - # odd size input, padding VALID - _test_transpose_conv( - [1, 5, 6, 16], - [2, 2, 16, 16], - [1, 10, 12, 16], - [2, 2], - "VALID", - quantized, - fp16_quantized, - ) - # odd size input, padding SAME - _test_transpose_conv( - [1, 5, 6, 16], - [2, 2, 16, 16], - [1, 10, 12, 16], - [2, 2], - "SAME", - quantized, - fp16_quantized, - ) - # kernel 3x3, padding VALID - _test_transpose_conv( - [4, 32, 32, 16], - [3, 3, 5, 16], - [4, 34, 34, 5], - [1, 1], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [3, 3, 5, 16], - [1, 65, 65, 5], - [2, 2], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [3, 3, 5, 16], - [1, 65, 34, 5], - [2, 1], - "VALID", - quantized, - fp16_quantized, - ) - - # kernel 3x3, padding SAME - _test_transpose_conv( - [4, 32, 32, 16], - [3, 3, 5, 16], - [4, 32, 32, 5], - [1, 1], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [3, 3, 5, 16], - [1, 64, 64, 5], - [2, 2], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [3, 3, 5, 16], - [1, 64, 32, 5], - [2, 1], - "SAME", - quantized, - fp16_quantized, - ) - - # kernel 2x2, padding VALID - _test_transpose_conv( - [4, 32, 32, 16], - [2, 2, 5, 16], - [4, 33, 33, 5], - [1, 1], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [2, 2, 5, 16], - [1, 64, 64, 5], - [2, 2], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [2, 2, 5, 16], - [1, 64, 33, 5], - [2, 1], - "VALID", - quantized, - fp16_quantized, - ) - - # kernel 2x2, padding SAME - _test_transpose_conv( - [4, 32, 32, 16], - [2, 2, 5, 16], - [4, 32, 32, 5], - [1, 1], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [2, 2, 5, 16], - [1, 64, 64, 5], - [2, 2], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [2, 2, 5, 16], - [1, 64, 32, 5], - [2, 1], - "SAME", - quantized, - fp16_quantized, - ) - - # kernel 1x1, padding VALID - _test_transpose_conv( - [4, 32, 32, 16], - [1, 1, 5, 16], - [4, 32, 32, 5], - [1, 1], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [1, 1, 5, 16], - [1, 63, 63, 5], - [2, 2], - "VALID", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [1, 1, 5, 16], - [1, 63, 32, 5], - [2, 1], - "VALID", - quantized, - fp16_quantized, - ) - - # kernel 1x1, padding SAME - _test_transpose_conv( - [4, 32, 32, 16], - [1, 1, 5, 16], - [4, 32, 32, 5], - [1, 1], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [1, 1, 5, 16], - [1, 63, 63, 5], - [2, 2], - "SAME", - quantized, - fp16_quantized, - ) - _test_transpose_conv( - [1, 32, 32, 16], - [1, 1, 5, 16], - [1, 63, 32, 5], - [2, 1], - "SAME", - quantized, - fp16_quantized, - ) - - -def _test_tflite2_quantized_transpose_conv( - input_shape, - kernel_shape, - filters, - padding="valid", - strides=(1, 1), - data_format=None, - int_quant_dtype=tf.int8, -): - """One iteration of TFLite2 quantized tranpose conv with given shapes and attributes""" - data_format = "channels_last" if data_format == "NHWC" else "channels_first" - data = np.random.uniform(0, 1, input_shape).astype("float32") - _ = np.random.uniform(0, 1, kernel_shape).astype("float32") - - data_in = tf.keras.layers.Input(shape=data.shape[1:], batch_size=1) - transpose_conv = tf.keras.layers.Conv2DTranspose( - filters=filters, - kernel_size=(kernel_shape[0], kernel_shape[1]), - padding=padding, - strides=strides, - use_bias=True, - )(data_in) - keras_model = tf.keras.models.Model(data_in, transpose_conv) - - # To create quantized values with dynamic range of activations, needs representative dataset - def representative_data_gen(): - for _ in range(1): - yield [data] - - tflite_model_quant = _quantize_keras_model( - keras_model, - representative_data_gen, - is_float_input=True, - is_float_output=True, - int_quant_dtype=int_quant_dtype, - ) - - # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_quant, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_quant, 0) - except ImportError as exc: - raise ImportError("The tflite package must be installed") from exc - - subgraph = tflite_model.Subgraphs(0) - model_input = subgraph.InputsAsNumpy() - input_node = subgraph.Tensors(model_input).Name().decode("utf-8") - - tflite_output = run_tflite_graph(tflite_model_quant, data) - - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - input_node = data_in.name.replace(":0", "") - else: - input_node = "serving_default_" + data_in.name + ":0" - - tvm_output = run_tvm_graph(tflite_model_quant, data, input_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-2, atol=1e-2 - ) - - -def test_forward_quantized_transpose_conv(): - """Quantized convolution""" - for int_quant_dtype in [tf.int8, tf.int16]: - _test_tflite2_quantized_transpose_conv( - (1, 1, 5, 64), - (3, 3), - 64, - padding="same", - strides=(1, 2), - data_format="NHWC", - int_quant_dtype=int_quant_dtype, - ) - - -####################################################################### -# Reshape -# ------- - - -def _test_reshape(data, out_shape, wrap_shape, quantized=False): - """One iteration of reshape operation with given data and out shape""" - if quantized: - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in") - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-100, max=100, name="inq_0" - ) - - input_range = {"inq_0": (-100, 100)} - out_shape = out_shape if not wrap_shape else np.array(out_shape, dtype=np.int32) - - in_shape = ( - out_shape - if not wrap_shape - else array_ops.placeholder( - shape=out_shape.shape, dtype=out_shape.dtype, name="Newshape" - ) - ) - - out = array_ops.reshape(inq_data, in_shape) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-200, max=200, name="out") - compare_tflite_with_tvm( - [data, out_shape] if wrap_shape else [data], - ["inq_0:0", "Newshape:0"] if wrap_shape else ["inq_0:0"], - [inq_data, in_shape] if wrap_shape else [inq_data], - [out], - quantized=True, - input_range=input_range, - mode="vm", - ) - else: - # Test with tensor and constant - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - out_shape = out_shape if not wrap_shape else np.array(out_shape, dtype=np.int32) - - in_shape = ( - out_shape - if not wrap_shape - else array_ops.placeholder( - shape=out_shape.shape, dtype=out_shape.dtype, name="Newshape" - ) - ) - - out = array_ops.reshape(in_data, in_shape) - - compare_tflite_with_tvm( - [data, out_shape] if wrap_shape else [data], - ["Placeholder:0", "Newshape:0"] if wrap_shape else ["Placeholder:0"], - [in_data, in_shape] if wrap_shape else [in_data], - [out], - mode="vm", - ) - - -def test_forward_reshape(): - for wrap in [True, False]: - _test_reshape(np.arange(6.0, dtype=np.float32), [2, 3], wrap) - _test_reshape(np.arange(6), [-1, 2], wrap) - _test_reshape(np.arange(6), [3, -1], wrap) - _test_reshape(np.arange(6), [-1], wrap) - - _test_reshape(np.arange(6, dtype=np.uint8), [2, 3], False, True) - _test_reshape(np.arange(6, dtype=np.uint8), [-1, 2], False, True) - - -####################################################################### -# Resize -# ------ - - -def _test_resize( - tf_resize_op, images_data, size_data, align_corners, half_pixel_centers, quantized=False -): - """One iteration of Resize""" - # Test with tensor and constant - with tf.Graph().as_default(): - images_tensor = array_ops.placeholder(shape=images_data.shape, dtype="float32", name="in") - size = ops.convert_to_tensor(size_data, dtype=size_data.dtype) - - if quantized: - images_tensor_q = tf.quantization.fake_quant_with_min_max_args( - images_tensor, min=-3, max=2, name="in" - ) - input_range = {"in": (-3, 2)} - out_tensor = tf_resize_op( - images=images_tensor_q, - size=size, - align_corners=align_corners, - half_pixel_centers=half_pixel_centers, - ) - out_tensor = tf.quantization.fake_quant_with_min_max_args( - out_tensor, min=-3, max=2, name="out_tensor" - ) - - compare_tflite_with_tvm( - [images_data], - ["in:0"], - [images_tensor], - [out_tensor], - quantized=True, - input_range=input_range, - ) - else: - out_tensor = tf_resize_op( - images=images_tensor, - size=size, - align_corners=align_corners, - half_pixel_centers=half_pixel_centers, - ) - compare_tflite_with_tvm([images_data], ["in:0"], [images_tensor], [out_tensor]) - - -def test_all_resize(): - """Resize""" - images_data = np.random.uniform(0, 255, (1, 16, 16, 3)) - images_data_float32 = images_data.astype(np.float32) - images_data_uint8 = images_data.astype(np.uint8) - size_data = np.array([8, 8]).astype("int32") - ### RESIZE_BILINEAR - _test_resize( - tf.image.resize_bilinear, - images_data_float32, - size_data, - align_corners=False, - half_pixel_centers=False, - quantized=False, - ) - _test_resize( - tf.image.resize_bilinear, - images_data_float32, - size_data, - align_corners=True, - half_pixel_centers=False, - quantized=False, - ) - _test_resize( - tf.image.resize_bilinear, - images_data_uint8, - size_data, - align_corners=False, - half_pixel_centers=False, - quantized=True, - ) - _test_resize( - tf.image.resize_bilinear, - images_data_uint8, - size_data, - align_corners=True, - half_pixel_centers=False, - quantized=True, - ) - _test_resize( - tf.image.resize_bilinear, - images_data_uint8, - size_data, - align_corners=False, - half_pixel_centers=True, - quantized=True, - ) - ### RESIZE_NEAREST_NEIGHBOR (was added in v1.13) - # According to topi resize.h - # Align corners not supported for nearest neighbour - - if "RESIZE_NEAREST_NEIGHBOR" in dir(BuiltinOperator()): - _test_resize( - tf.image.resize_nearest_neighbor, - images_data_float32, - size_data, - align_corners=False, - half_pixel_centers=False, - ) - _test_resize( - tf.image.resize_nearest_neighbor, - images_data_float32, - size_data, - align_corners=True, - half_pixel_centers=False, - ) - _test_resize( - tf.image.resize_nearest_neighbor, - images_data_float32, - size_data, - align_corners=False, - half_pixel_centers=True, - ) - - -####################################################################### -# Range -# ----- -def _test_range(start, limit, delta): - # tflite 1.13 convert method does not accept empty shapes - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - tf.reset_default_graph() - with tf.Graph().as_default(): - start_scalar, limit_scalar, delta_scalar = ( - tf.placeholder(dtype=start.dtype, shape=(), name="start"), - tf.placeholder(dtype=limit.dtype, shape=(), name="limit"), - tf.placeholder(dtype=delta.dtype, shape=(), name="delta"), - ) - - out = tf.range(start_scalar, limit_scalar, delta_scalar, name="range") - - compare_tflite_with_tvm( - [start, limit, delta], - ["start", "limit", "delta"], - [start_scalar, limit_scalar, delta_scalar], - [out], - mode="vm", - quantized=False, - ) - - -def _test_range_default(): - # tflite 1.13 convert method does not accept empty shapes - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - tf.reset_default_graph() - with tf.Graph().as_default(): - inputs = [ - tf.placeholder(dtype=tf.int32, shape=(), name="p1"), - tf.placeholder(dtype=tf.int32, shape=(), name="p2"), - ] - outputs = [ - tf.range(start=inputs[0], limit=inputs[1]), # use default delta - tf.range( - start=inputs[1] - ), # use start as limit with 0 as the first item in the range - ] - - compare_tflite_with_tvm( - [np.int32(1), np.int32(18)], ["p1", "p2"], inputs, outputs, mode="vm" - ) - - -def test_forward_range(): - _test_range(np.int32(1), np.int32(18), np.int32(3)) - _test_range(np.int32(1), np.int32(18), np.float32(3.1)) # increment is of type float - _test_range(np.float32(1.0), np.int32(18), np.int32(3.1)) # start is of type float - _test_range_default() - - -####################################################################### -# Shape -# ----- - - -def _test_shape(dtype): - # tflite 1.13 convert method does not accept empty shapes - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - tf.reset_default_graph() - with tf.Graph().as_default(): - data = np.array([1, 18, 3], dtype=np.int32) - start = tf.placeholder(dtype=tf.int32, shape=[], name="start") - limit = tf.placeholder(dtype=tf.int32, shape=[], name="limit") - delta = tf.placeholder(dtype=tf.int32, shape=[], name="delta") - tf_range = tf.range(start, limit, delta, tf.int32, name="range") - out = tf.shape(tf_range, out_type=dtype) - out = tf.add(out, tf.constant([1], dtype=dtype)) - compare_tflite_with_tvm( - list(np.nditer(data)), - ["start", "limit", "delta"], - [start, limit, delta], - [out], - mode="vm", - ) - - -def test_forward_shape(): - _test_shape(tf.int32) - _test_shape(tf.int64) - - -####################################################################### -# Concatenation -# ------------- - - -def _test_concatenation(data, axis): - """One iteration of concatenation""" - - assert len(data) >= 1 - - with tf.Graph().as_default(): - in_data = [ - array_ops.placeholder(shape=tensor.shape, dtype=tensor.dtype, name=f"in_{idx}") - for idx, tensor in enumerate(data) - ] - out = array_ops.concat(in_data, axis) - name = [f"in_{idx}:0" for idx in range(len(data))] - - compare_tflite_with_tvm(data, name, in_data, [out]) - - -def test_forward_concatenation(): - - _test_concatenation([np.arange(6).reshape((1, 2, 1, 3)), np.arange(6).reshape((1, 2, 1, 3))], 1) - - _test_concatenation([np.arange(6).reshape((3, 2)), np.arange(6).reshape((3, 2))], 1) - - _test_concatenation( - [ - np.arange(6).reshape((2, 1, 1, 3)), - np.arange(6).reshape((2, 1, 1, 3)), - np.arange(6).reshape((2, 1, 1, 3)), - ], - 1, - ) - - -####################################################################### -# Unary elemwise -# -------------- - - -def _test_unary_elemwise(math_op, data, quantized, quant_range=(-6, 6), int_quant_dtype=tf.int8): - """One iteration of unary elemwise""" - if quantized: - with tf.Graph().as_default(): - quant_min, quant_max = quant_range - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=quant_min, max=quant_max, name="inq_0" - ) - input_range = {"inq_0": (quant_min, quant_max)} - out = math_op(inq_data) - out = tf.quantization.fake_quant_with_min_max_args( - out, min=quant_min, max=quant_max, name="out" - ) - compare_tflite_with_tvm( - data, - "inq_0:0", - [inq_data], - [out], - quantized=True, - input_range=input_range, - experimental_new_converter=True, - int_quant_dtype=int_quant_dtype, - ) - else: - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype, name="in") - out = math_op(in_data) - compare_tflite_with_tvm( - data, ["in:0"], [in_data], [out], experimental_new_converter=True - ) - - -def _unary_elewise_create_model(math_op, data, offset=0, int_quant_dtype=tf.int8): - class Model(tf.Module): - @tf.function - def tf_function(self, x): - op = math_op(x) - return op - - if int_quant_dtype in (tf.int8, tf.uint8): - _ = "int8" - elif int_quant_dtype in (tf.int16, tf.uint16): - _ = "int16" - else: - raise Exception(f"Unsupported dtype '{int_quant_dtype}' for unary elementwise test.") - - model = Model() - - # Save the model - export_dir = tempfile.gettempdir() + "/tf_model" - tf.saved_model.save( - model, - export_dir, - signatures=model.tf_function.get_concrete_function( - tf.TensorSpec(data.shape, tf.float32, name="input") - ), - ) - - # Convert the model - def representative_dataset(): - for _ in range(100): - tmp_data = np.random.rand(*tuple(data.shape)) - yield [tmp_data.astype(np.float32) * 2 - offset] - - converter = tf.lite.TFLiteConverter.from_saved_model(export_dir) - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.representative_dataset = representative_dataset - - if int_quant_dtype in (tf.int16, tf.uint16): - converter.target_spec.supported_ops = [ - tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8 - ] - else: - converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8] - - converter.inference_input_type = int_quant_dtype - converter.inference_output_type = int_quant_dtype - - tflite_model = converter.convert() - return tflite_model - - -####################################################################### -# Abs -# ---- - - -def _test_abs(data, quantized, int_quant_dtype=tf.int8): - """One iteration of abs""" - if quantized: - tflite_model_quant = _unary_elewise_create_model( - tf.math.abs, data, offset=1, int_quant_dtype=int_quant_dtype - ) - tflite_output = run_tflite_graph(tflite_model_quant, data) - - # TFLite 2.6.x upgrade support - if package_version.parse(tf.__version__) < package_version.parse("2.6.1"): - in_node = ["serving_default_input_int8"] - elif package_version.parse(tf.__version__) < package_version.parse("2.9"): - in_node = ( - ["serving_default_input_int16"] if int_quant_dtype == tf.int16 else ["tfl.quantize"] - ) - else: - in_node = "serving_default_input" - - tvm_output = run_tvm_graph(tflite_model_quant, data, in_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-2 - ) - else: - return _test_unary_elemwise(math_ops.abs, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Rsqrt -# ---- - - -def _test_rsqrt(data, quantized, int_quant_dtype=tf.int8): - """One iteration of rsqrt""" - - # tensorflow version upgrade support - if package_version.parse(tf.__version__) < package_version.parse("2.6.1") or not quantized: - return _test_unary_elemwise( - math_ops.rsqrt, data, quantized, quant_range=[1, 6], int_quant_dtype=int_quant_dtype - ) - else: - tflite_model_quant = _unary_elewise_create_model( - tf.math.rsqrt, data, int_quant_dtype=int_quant_dtype - ) - tflite_output = run_tflite_graph(tflite_model_quant, data) - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - in_node = ["tfl.quantize"] - else: - in_node = "serving_default_input" - tvm_output = run_tvm_graph(tflite_model_quant, data, in_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-2 - ) - - -####################################################################### -# Ceil -# ---- - - -def _test_ceil(data, quantized, int_quant_dtype=tf.int8): - """One iteration of ceil""" - return _test_unary_elemwise(math_ops.ceil, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Floor -# ----- - - -def _test_floor(data, quantized, int_quant_dtype=tf.int8): - """One iteration of floor""" - return _test_unary_elemwise(math_ops.floor, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Round -# ----- - - -def _test_round(data, quantized, int_quant_dtype=tf.int8): - """One iteration of round""" - return _test_unary_elemwise(math_ops.round, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Exp -# --- - - -def _test_exp(data, quantized, int_quant_dtype=tf.int8): - """One iteration of exp""" - return _test_unary_elemwise(math_ops.exp, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Log -# --- - - -def _test_log(data, quantized, int_quant_dtype=tf.int8): - """One iteration of log""" - return _test_unary_elemwise( - math_ops.log, data, quantized, quant_range=[1, 6], int_quant_dtype=int_quant_dtype - ) - - -####################################################################### -# Sin -# --- - - -def _test_sin(data, quantized, int_quant_dtype=tf.int8): - """One iteration of sin""" - return _test_unary_elemwise(math_ops.sin, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Cos -# --- - - -def _test_cos(data, quantized, int_quant_dtype=tf.int8): - """One iteration of cos""" - if quantized: - tflite_model_quant = _unary_elewise_create_model( - tf.math.cos, data, int_quant_dtype=int_quant_dtype - ) - tflite_output = run_tflite_graph(tflite_model_quant, data) - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - in_node = ["tfl.quantize"] - else: - in_node = "serving_default_input" - tvm_output = run_tvm_graph(tflite_model_quant, data, in_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-2 - ) - else: - return _test_unary_elemwise(math_ops.cos, data, quantized) - - -####################################################################### -# Tan -# --- - - -def _test_tan(data, quantized, int_quant_dtype=tf.int8): - """One iteration of tan""" - return _test_unary_elemwise(math_ops.tan, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Square -# ------ - - -def _test_square(data, quantized, int_quant_dtype=tf.int8): - """One iteration of square""" - return _test_unary_elemwise(math_ops.square, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Neg -# ------ - - -def _test_neg(data, quantized, int_quant_dtype=tf.int8): - """One iteration of neg""" - return _test_unary_elemwise(math_ops.neg, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Sqrt -# ------ - - -def _test_sqrt(data, quantized, int_quant_dtype=tf.int8): - """One iteration of sqrt""" - return _test_unary_elemwise( - math_ops.sqrt, data, quantized, quant_range=[1, 6], int_quant_dtype=int_quant_dtype - ) - - -####################################################################### -# Elu -# --- - - -def _test_elu(data, quantized, int_quant_dtype=tf.int8): - """One iteration of elu""" - return _test_unary_elemwise(nn_ops.elu, data, quantized, int_quant_dtype=int_quant_dtype) - - -####################################################################### -# Gelu -# --- - - -def _test_gelu(data, quantized, int_quant_dtype=tf.int8): - """One iteration of elu""" - return _test_unary_elemwise(nn_ops.gelu, data, quantized, int_quant_dtype=int_quant_dtype) - - -def _test_forward_unary_elemwise(test_op, int_quant_dtype=None, quantized=True, negative=True): - # input data - in_data, inq_data = [], [] - - np_dtype = int_quant_dtype.as_numpy_dtype if int_quant_dtype else np.uint8 - - # quantized input data - if quantized: - inq_data.append(np.arange(1, 240, 40, dtype=np_dtype)) - inq_data.append(np.arange(1, 240, 40, dtype=np_dtype).reshape((2, 1, 3))) - if int_quant_dtype == np.int8: - inq_data.append(np.arange(-128, 127, 45, dtype=np.int8)) - - for data in inq_data: - test_op(data, quantized=True, int_quant_dtype=int_quant_dtype) - - # normal input data - if negative: - in_data.append(np.arange(-2.0, 4.0, dtype=np.float32)) - in_data.append(np.arange(-2.0, 4.0, dtype=np.float32).reshape((2, 1, 3))) - else: - in_data.append(np.arange(1.0, 7.0, dtype=np.float32)) - in_data.append(np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 3))) - - for data in in_data: - test_op(data, quantized=False, int_quant_dtype=int_quant_dtype) - - -def test_all_unary_elemwise(): - """All unary elemwise""" - _test_forward_unary_elemwise(_test_abs, int_quant_dtype=tf.int8) - _test_forward_unary_elemwise(_test_abs, int_quant_dtype=tf.int16) - _test_forward_unary_elemwise(_test_floor) - _test_forward_unary_elemwise(_test_exp) - _test_forward_unary_elemwise(_test_log, negative=False) - _test_forward_unary_elemwise(_test_square, int_quant_dtype=tf.int8) - _test_forward_unary_elemwise(_test_sin) - _test_forward_unary_elemwise(_test_neg) - _test_forward_unary_elemwise(_test_sqrt, negative=False) - _test_forward_unary_elemwise(_test_gelu, quantized=False) - # tensorflow version upgrade support - if package_version.parse(tf.VERSION) < package_version.parse("2.6.1"): - _test_forward_unary_elemwise(_test_rsqrt, negative=False, int_quant_dtype=tf.uint8) - else: - _test_forward_unary_elemwise(_test_rsqrt, negative=False, int_quant_dtype=tf.int8) - # ceil and cos come with TFLite 1.14.0.post1 fbs schema - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_forward_unary_elemwise(_test_ceil) - if package_version.parse(tf.VERSION) < package_version.parse("2.6.1"): - _test_forward_unary_elemwise(_test_cos, quantized=False) - else: - _test_forward_unary_elemwise(_test_cos, int_quant_dtype=tf.int8) - _test_forward_unary_elemwise(_test_round) - # This fails with TF and Tflite 1.15.2, this could not have been tested - # in CI or anywhere else. The failure mode is that we see a backtrace - # from the converter that we need to provide a custom Tan operator - # implementation. - # _test_forward_unary_elemwise(_test_tan) - _test_forward_unary_elemwise(_test_elu) - - -####################################################################### -# Element-wise -# ------------ - - -def _test_elemwise( - math_op, - data, - fused_activation_function=None, - quantized=False, - qnn_op=None, - same_qnn_params=False, - comparison_op=False, - exclude_zero_point=False, -): - """One iteration of elemwise""" - - assert len(data) == 2 - - def __test_elemwise(in_data): - assert len(in_data) == 2 - if quantized: - int_quant_dtype = None - if data[0].dtype == "int8": - int_quant_dtype = tf.int8 - elif data[0].dtype == "uint8": - int_quant_dtype = tf.uint8 - elif data[0].dtype == "int16": - int_quant_dtype = tf.int16 - else: - assert False, "Unsupported conversion from numpy to tflite dtype!" - - # set the fp32 output range with respect to the operation - out_min, out_max = _test_elemwise_qnn_out_range(qnn_op) - inq0_min, inq0_max = (-100, 100) - inq1_min, inq1_max = (-50, 50) - - # if requested use same quantization parameters provided by _test_elemwise_qnn_out_range - if same_qnn_params: - inq0_min, inq0_max = (out_min, out_max) - inq1_min, inq1_max = (out_min, out_max) - - if exclude_zero_point: - if inq1_max == inq1_min: - raise ZeroDivisionError("Input range is 0.") - - # only compute for rhs. - quant_scale = 255 / (inq1_max - inq1_min) - zero_point = int(round(-inq1_min * quant_scale)) - data[1][data[1] == zero_point] += 1 - data[1][data[1] == 0] += 1 - - # fake_quant will keep the tensors in float32 until the conversion in the session - inq_data = [ - tf.quantization.fake_quant_with_min_max_args( - in_data[0], min=out_min, max=out_max, name="inq_0" - ) - if in_data[0] is not None - else tf.quantization.fake_quant_with_min_max_args( - data[0], min=out_min, max=out_max, name="const_tensor0" - ), - tf.quantization.fake_quant_with_min_max_args( - in_data[1], min=out_min, max=out_max, name="inq_1" - ) - if in_data[1] is not None - else tf.quantization.fake_quant_with_min_max_args( - data[1], min=out_min, max=out_max, name="const_tensor1" - ), - ] - - input_range = { - x[1][0]: x[1][1] - for x in zip( - in_data, (("inq_0", (inq0_min, inq0_max)), ("inq_1", (inq1_min, inq1_max))) - ) - if x[0] is not None - } - - if comparison_op: - out = math_op(inq_data[0], inq_data[1]) - out = with_fused_activation_function(out, fused_activation_function) - - compare_tflite_with_tvm( - [x[1] for x in zip(in_data, data) if x[0] is not None], - [x + ":0" for x in input_range.keys()], - [x[1] for x in zip(in_data, inq_data) if x[0] is not None], - [out], - quantized=True, - input_range=input_range, - experimental_new_converter=same_qnn_params, - int_quant_dtype=int_quant_dtype, - ) - else: - out = math_op(inq_data[0], inq_data[1]) - out = with_fused_activation_function(out, fused_activation_function) - out = tf.quantization.fake_quant_with_min_max_args( - out, min=out_min, max=out_max, name="out" - ) - - # Note same_qnn_params uses experimental_new_converter as toco failed - compare_tflite_with_tvm( - [x[1] for x in zip(in_data, data) if x[0] is not None], - [x + ":0" for x in input_range.keys()], - [x[1] for x in zip(in_data, inq_data) if x[0] is not None], - [out], - quantized=True, - input_range=input_range, - experimental_new_converter=same_qnn_params, - int_quant_dtype=int_quant_dtype, - ) - else: - out = math_op( - in_data[0] - if in_data[0] is not None - else ops.convert_to_tensor(data[0], dtype=data[0].dtype), - in_data[1] - if in_data[1] is not None - else ops.convert_to_tensor(data[1], dtype=data[1].dtype), - ) - out = with_fused_activation_function(out, fused_activation_function) - compare_tflite_with_tvm( - [x[1] for x in zip(in_data, data) if x[0] is not None], - [x[1] for x in zip(in_data, ("in_0:0", "in_1:0")) if x[0] is not None], - [x for x in in_data if x is not None], - [out], - ) - - # Test with two tensors - with tf.Graph().as_default(): - __test_elemwise( - in_data=[ - array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in_0"), - array_ops.placeholder(shape=data[1].shape, dtype="float32", name="in_1"), - ] - ) - # Test with tensor and constant - with tf.Graph().as_default(): - __test_elemwise( - in_data=[array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in_0"), None] - ) - # Test with constant and tensor - with tf.Graph().as_default(): - __test_elemwise( - in_data=[None, array_ops.placeholder(shape=data[1].shape, dtype="float32", name="in_1")] - ) - - -####################################################################### -# Add -# --- - - -def _test_add(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of add""" - return _test_elemwise(math_ops.add, data, fused_activation_function, quantized, qnn_op) - - -####################################################################### -# Subtract -# -------- - - -def _test_sub(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of subtract""" - return _test_elemwise(math_ops.subtract, data, fused_activation_function, quantized, qnn_op) - - -####################################################################### -# Mul -# --- - - -def _test_mul(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of mul""" - return _test_elemwise(math_ops.multiply, data, fused_activation_function, quantized, qnn_op) - - -####################################################################### -# Divide -# ------ - - -def _test_div(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of divide""" - return _test_elemwise( - math_ops.divide, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - exclude_zero_point=True, - ) - - -####################################################################### -# Power -# ----- - - -def _test_pow(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of power""" - return _test_elemwise( - math_ops.pow, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - ) - - -####################################################################### -# Maximum -# ------- - - -def _test_maximum(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of maximum""" - return _test_elemwise( - math_ops.maximum, data, fused_activation_function, quantized, qnn_op, same_qnn_params=True - ) - - -####################################################################### -# Minimum -# ------- - - -def _test_minimum(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of minimum""" - return _test_elemwise( - math_ops.minimum, data, fused_activation_function, quantized, qnn_op, same_qnn_params=True - ) - - -####################################################################### -# Greater -# ------- - - -def _test_greater(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of greater""" - return _test_elemwise( - math_ops.greater, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Greater_equal -# ------------- - - -def _test_greater_equal(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of greater_equal""" - return _test_elemwise( - math_ops.greater_equal, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Less -# ---- - - -def _test_less(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of less""" - return _test_elemwise( - math_ops.less, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Less_equal -# ---------- - - -def _test_less_equal(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of less_equal""" - return _test_elemwise( - math_ops.less_equal, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Equal -# ----- - - -def _test_equal(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of equal""" - return _test_elemwise( - math_ops.equal, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Not_equal -# --------- - - -def _test_not_equal(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of not_equal""" - return _test_elemwise( - math_ops.not_equal, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - comparison_op=True, - ) - - -####################################################################### -# Squared_difference -# ------------------ - - -def _test_squared_difference(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of squared difference""" - return _test_elemwise( - math_ops.squared_difference, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - ) - - -####################################################################### -# Floor_divide -# ------------ - - -def _test_floor_divide(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of floor_div""" - return _test_elemwise( - math_ops.floordiv, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - exclude_zero_point=True, - ) - - -####################################################################### -# Floor_mod -# --------- - - -def _test_floor_mod(data, fused_activation_function=None, quantized=False, qnn_op=None): - """One iteration of floor_mod""" - return _test_elemwise( - math_ops.floormod, - data, - fused_activation_function, - quantized, - qnn_op, - same_qnn_params=True, - ) - - -def _test_forward_elemwise(testop): - """Elewise""" - testop( - [ - np.arange(6.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - ] - ) - testop( - [ - np.arange(6.0, dtype=np.float32).reshape((2, 1, 3)), - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 3)), - ] - ) - testop( - [ - np.arange(3.0, dtype=np.float32).reshape((1, 3)), - np.arange(1.0, 4.0, dtype=np.float32).reshape((1, 3)), - ] - ) - - -def _test_forward_elemwise_quantized(testop, dtype=np.uint8): - type_info = np.iinfo(dtype) - _min, _max = type_info.min, type_info.max - testop( - [ - np.array(np.random.uniform(_min, _max, (3, 6)), dtype=dtype), - np.array(np.random.uniform(_min, _max, (3, 6)), dtype=dtype), - ], - quantized=True, - qnn_op=testop, - ) - - -def _test_elemwise_qnn_out_range(qnn_op): - # set the fake_quant output range with respect to the input tensors float32 range - qnn_out_range = { - _test_add: (-150, 150), - _test_sub: (-150, 150), - _test_mul: (-5e3, 5e3), - _test_div: (-150, 150), - _test_maximum: (-112, 111), - _test_minimum: (-128, 127), - _test_equal: (-150, 150), - _test_greater: (-150, 150), - _test_squared_difference: (0, 65025), - _test_floor_divide: (-150, 150), - _test_less: (-150, 150), - _test_floor_mod: (-150, 150), - _test_not_equal: (-150, 150), - _test_pow: (0, 3), - _test_less_equal: (-150, 150), - _test_greater_equal: (-150, 150), - } - - return qnn_out_range[qnn_op] - - -def test_all_elemwise(): - """All_elemwise""" - _test_forward_elemwise(_test_add) - _test_forward_elemwise_quantized(_test_add) - _test_forward_elemwise(partial(_test_add, fused_activation_function="RELU")) - # this is broken with tf upgrade 1.15.2 and hits a segfault that needs - # further investigation. - # _test_forward_elemwise(partial(_test_add, fused_activation_function="RELU6")) - _test_forward_elemwise(_test_sub) - _test_forward_elemwise_quantized(_test_sub) - _test_forward_elemwise(partial(_test_sub, fused_activation_function="RELU")) - _test_forward_elemwise(partial(_test_sub, fused_activation_function="RELU6")) - _test_forward_elemwise(_test_mul) - _test_forward_elemwise_quantized(_test_mul) - _test_forward_elemwise(partial(_test_mul, fused_activation_function="RELU")) - _test_forward_elemwise(partial(_test_mul, fused_activation_function="RELU6")) - _test_forward_elemwise(_test_div) - _test_forward_elemwise(partial(_test_div, fused_activation_function="RELU")) - _test_forward_elemwise(partial(_test_div, fused_activation_function="RELU6")) - _test_forward_elemwise_quantized(_test_div) - _test_forward_elemwise(_test_pow) - _test_forward_elemwise_quantized(_test_pow) - _test_forward_elemwise(_test_maximum) - _test_forward_elemwise_quantized(_test_maximum) - _test_forward_elemwise(_test_minimum) - _test_forward_elemwise_quantized(_test_minimum) - _test_forward_elemwise(_test_greater) - _test_forward_elemwise_quantized(_test_greater) - _test_forward_elemwise(_test_squared_difference) - _test_forward_elemwise_quantized(_test_squared_difference, np.int8) - _test_forward_elemwise(_test_greater_equal) - _test_forward_elemwise_quantized(_test_greater_equal) - _test_forward_elemwise(_test_less) - _test_forward_elemwise_quantized(_test_less) - _test_forward_elemwise(_test_less_equal) - _test_forward_elemwise_quantized(_test_less_equal) - _test_forward_elemwise(_test_equal) - _test_forward_elemwise_quantized(_test_equal) - _test_forward_elemwise(_test_not_equal) - _test_forward_elemwise_quantized(_test_not_equal) - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_forward_elemwise(_test_floor_divide) - _test_forward_elemwise_quantized(_test_floor_divide) - _test_forward_elemwise(_test_floor_mod) - # This test of quantized floor mod is currently disabled due - # to flaky CI failures in main, failing approximately 45% of - # the time. - # - # _test_forward_elemwise_quantized(_test_floor_mod) - - -####################################################################### -# AddN -# ---- - - -def _test_forward_add_n(inputs): - tf.reset_default_graph() - with tf.Graph().as_default(): - temp = [] - for each in inputs: - temp.append(tf.placeholder(shape=each.shape, dtype=each.dtype)) - output = tf.add_n(temp) - compare_tflite_with_tvm( - list(inputs), - [each.name for each in temp], - list(temp), - [output], - ) - - -def test_forward_add_n(): - """Add n""" - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - x = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - y = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - z_1 = np.random.randint(1, 100, size=(3, 3, 3), dtype=np.int32) - x_1, x_2, z_2 = x.astype(np.float32), y.astype(np.float32), z_1.astype(np.float32) - in0 = x - in1 = [x, y] - in2 = (x, y, z_1) - in3 = x_1 - in4 = [x_1, x_2] - in5 = (x_1, x_2, z_2) - _test_forward_add_n(in0) - _test_forward_add_n(in1) - _test_forward_add_n(in2) - _test_forward_add_n(in3) - _test_forward_add_n(in4) - _test_forward_add_n(in5) - - -####################################################################### -# Logical operators -# ----------------- - - -def _test_logical_binary(logical_bin_op, data): - - with tf.Graph().as_default(): - in_data = [ - array_ops.placeholder(shape=data[0].shape, dtype="bool", name="in_0"), - array_ops.placeholder(shape=data[1].shape, dtype="bool", name="in_1"), - ] - if logical_bin_op is math_ops.logical_not: - out = math_ops.logical_or(in_data[0], in_data[1], name="out1") - out = logical_bin_op(out, name="out") - else: - out = logical_bin_op(in_data[0], in_data[1], name="out") - - compare_tflite_with_tvm(data, ["in_0:0", "in_1:0"], in_data, [out]) - - -def _test_forward_logical_and(data): - """One iteration of logical and""" - return _test_logical_binary(math_ops.logical_and, data) - - -def _test_forward_logical_or(data): - """One iteration of logical or""" - return _test_logical_binary(math_ops.logical_or, data) - - -def _test_forward_logical_not(data): - """One iteration of logical not""" - return _test_logical_binary(math_ops.logical_not, data) - - -def test_all_logical(): - data = [ - np.random.choice(a=[False, True], size=(2, 3, 4)).astype("bool"), - np.random.choice(a=[False, True], size=(2, 3, 4)).astype("bool"), - ] - # boolean dtype is not supported by older versions than TFLite 1.15.0 - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - _test_forward_logical_and(data) - _test_forward_logical_or(data) - _test_forward_logical_not(data) - - -####################################################################### -# Zeros like -# ---------- - - -def _test_zeros_like(data): - """One iteration of ZEROS LIKE""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = gen_array_ops.zeros_like(in_data) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_zeros_like(): - """ZEROS LIKE""" - _test_zeros_like(np.arange(6.0, dtype=np.float32).reshape((1, 6))) - - -####################################################################### -# Fill -# ---- - - -def _test_fill(dims, value_data, value_dtype): - """Use the fill op to create a tensor of value_data with constant dims.""" - - value_data = np.array(value_data, dtype=value_dtype) - # TF 1.13 TFLite convert method does not accept empty shapes - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - with tf.Graph().as_default(): - value = array_ops.placeholder(dtype=value_dtype, name="value", shape=[]) - out = tf.fill(dims, value) - compare_tflite_with_tvm([value_data], ["value"], [value], [out]) - - with tf.Graph().as_default(): - input1 = array_ops.placeholder(dtype=value_dtype, name="input1", shape=dims) - # Fill op gets converted to static tensor during conversion - out = tf.fill(dims, value_data) - out1 = tf.add(out, input1) - input1_data = np.random.uniform(0, 5, size=dims).astype(value_dtype) - compare_tflite_with_tvm([input1_data], ["input1"], [input1], [out1]) - - -def test_forward_fill(): - """Test FILL op""" - - _test_fill((1, 2, 2, 4), 5, "int32") - _test_fill((1, 2, 2, 4), 5, "float32") - _test_fill((5,), 5, "int32") - - -####################################################################### -# Reduce -# ------ - - -def _test_reduce(math_op, data, keep_dims=None): - """One iteration of reduce""" - - assert len(data) == 2 - - # Test with tensor and constant - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data[0].shape, dtype=data[0].dtype, name="in") - out = math_op(in_data, data[1], keep_dims) - compare_tflite_with_tvm([data[0]], ["in:0"], [in_data], [out]) - - -def _test_reduce_quantize(math_op, data, keep_dims=None): - """One iteration of reduce""" - - assert len(data) == 2 - - # Test with tensor and constant - with tf.Graph().as_default(): - in_data = [array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in")] - inq_data = [ - tf.quantization.fake_quant_with_min_max_args( - in_data[0], min=-100, max=100, name="inq_0" - ) - ] - input_range = {"inq_0": (-100, 100)} - out = math_op(inq_data, data[1], keep_dims) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-200, max=200, name="out") - compare_tflite_with_tvm( - [data[0]], ["inq_0:0"], [inq_data[0]], [out], quantized=True, input_range=input_range - ) - - -####################################################################### -# Reduce_min -# ---------- - - -def _test_reduce_min(data, keep_dims=None): - """One iteration of reduce_min""" - return _test_reduce(math_ops.reduce_min, data, keep_dims) - - -####################################################################### -# Reduce_max -# ---------- - - -def _test_reduce_max(data, keep_dims=None): - """One iteration of reduce_max""" - return _test_reduce(math_ops.reduce_max, data, keep_dims) - - -####################################################################### -# Reduce_mean -# ----------- - - -def _test_reduce_mean(data, keep_dims=None, quantized=False): - """One iteration of reduce_mean""" - if quantized: - return _test_reduce_quantize(math_ops.reduce_mean, data, keep_dims) - else: - return _test_reduce(math_ops.reduce_mean, data, keep_dims) - - -####################################################################### -# Reduce_prod -# ----------- - - -def _test_reduce_prod(data, keep_dims=None): - """One iteration of reduce_prod""" - return _test_reduce(math_ops.reduce_prod, data, keep_dims) - - -####################################################################### -# Reduce_sum -# ----------- - - -def _test_reduce_sum(data, keep_dims=None): - """One iteration of reduce_sum""" - return _test_reduce(math_ops.reduce_sum, data, keep_dims) - - -####################################################################### -# Reduce_any -# ---------- - - -def _test_reduce_any(data, keep_dims=None): - """One iteration of reduce_any""" - return _test_reduce(math_ops.reduce_any, data, keep_dims) - - -def _test_forward_reduce(testop, dtype="float32"): - """Reduce""" - if dtype == "bool": - data0 = [np.random.choice(a=[False, True], size=(16, 16, 16, 16)).astype(dtype), None] - data1 = [ - np.random.choice(a=[False, True], size=(16, 16, 16, 16)).astype(dtype), - np.array(1, dtype=np.int32), - ] - data2 = [ - np.random.choice(a=[False, True], size=(16, 16, 16, 16)).astype(dtype), - np.array([1, 2], dtype=np.int32), - ] - else: - data0 = [np.random.rand(16, 16, 16, 16).astype(dtype), None] - data1 = [np.random.rand(16, 16, 16, 16).astype(dtype), np.array(1, dtype=np.int32)] - data2 = [np.random.rand(16, 16, 16, 16).astype(dtype), np.array([1, 2], dtype=np.int32)] - - for data in [data0, data1, data2]: - testop(data) - testop(data, keep_dims=False) - testop(data, keep_dims=True) - - -def _test_forward_reduce_quantized(testop): - data0 = [ - np.array(np.random.uniform(0, 255, (3, 6)), dtype=np.uint8), - np.array([1, 2], dtype=np.int32), - ] - testop(data0, quantized=True) - testop(data0, keep_dims=False, quantized=True) - testop(data0, keep_dims=True, quantized=True) - - -def test_all_reduce(): - _test_forward_reduce(_test_reduce_min) - _test_forward_reduce(_test_reduce_max) - _test_forward_reduce(_test_reduce_mean) - _test_forward_reduce_quantized(_test_reduce_mean) - _test_forward_reduce(_test_reduce_prod) - _test_forward_reduce(_test_reduce_sum) - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - _test_forward_reduce(_test_reduce_any, dtype="bool") - - -####################################################################### -# Arg_min_max -# ----------- - - -def _test_arg_min_max(math_op, data, axis, quantized=False): - """One iteration of arg_min_max""" - - with tf.Graph().as_default(): - t_name = "in" - in_data = array_ops.placeholder(shape=data.shape, dtype=np.float32, name=t_name) - input_range = None - qmin, qmax = -100, 102 - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=qmin, max=qmax, name="q" + t_name - ) - input_range = {inq_data.name.split(":")[0]: (qmin, qmax)} - out = math_op(input=inq_data, axis=axis) - compare_tflite_with_tvm( - [data], [inq_data.name], [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = math_op(input=in_data, axis=axis) - compare_tflite_with_tvm([data], [in_data.name], [in_data], [out]) - - -def test_forward_arg_min_max(): - """Arg min max""" - # test quantized - for data in [np.array(np.random.uniform(-100, 100, (3, 4)), dtype=np.uint8)]: - # There is no quantized version of ArgMin - for axis in [None, 0, 1, -1]: - _test_arg_min_max(math_ops.argmax, data, axis, True) - - for data in [np.array(np.random.uniform(-100, 100, (3, 4)), dtype=np.float32)]: - for axis in [None, 0, 1, -1]: - _test_arg_min_max(math_ops.argmax, data, axis) - _test_arg_min_max(math_ops.argmin, data, axis) - - -####################################################################### -# Select, Where -# ------------- - - -def test_forward_select(): - """Select""" - with tf.Graph().as_default(): - with tf.Session() as _: - input1 = tf.placeholder(tf.int32, shape=[1, 4, 4, 3], name="input1") - input2 = tf.placeholder(tf.int32, shape=[1, 4, 4, 3], name="input2") - mask = input1 > input2 - out = tf.where(mask, input1 + 1, input2 * 2) - in_data1 = np.random.uniform(0, 10, size=(1, 4, 4, 3)).astype("int32") - in_data2 = np.random.uniform(0, 10, size=(1, 4, 4, 3)).astype("int32") - - compare_tflite_with_tvm( - [in_data1, in_data2], ["input1:0", "input2:0"], [input1, input2], [out] - ) - - -@pytest.mark.parametrize("quant_bits", [2, 4, 8, 16]) -@pytest.mark.parametrize( - "value, min_value, max_value", - [[-10.11, -6, 6], [-3.55, -6, 6], [0, -6, 6], [3.55, -6, 6], [10.11, -6, 6]], -) -def test_forward_fake_quant(value, min_value, max_value, quant_bits): - """Fake quant""" - with tf.Graph().as_default(): - with tf.Session() as _: - input_placeholder = tf.placeholder(tf.float32, shape=[1], name="input") - out = tf.quantization.fake_quant_with_min_max_args( - input_placeholder, min=min_value, max=max_value, num_bits=quant_bits, name=None - ) - - in_data = np.float32(value) - compare_tflite_with_tvm([in_data], ["input:0"], [input_placeholder], [out]) - - -# Squeeze -# ------- - - -def _test_squeeze(data, squeeze_dims=None): - """One iteration of squeeze""" - - if squeeze_dims is None: - squeeze_dims = [] - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - - if squeeze_dims: - out = array_ops.squeeze(in_data, squeeze_dims) - else: - out = array_ops.squeeze(in_data) - - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_squeeze(): - """Squeeze""" - _test_squeeze(np.arange(6).reshape((1, 2, 1, 3)), [0, 2]) - _test_squeeze(np.arange(6).reshape((2, 1, 3, 1)), [1, 3]) - - -####################################################################### -# Quantize/DeQuantize -# ------------------- - - -def _test_quantize_dequantize(data): - """One iteration of quantize and dequantize""" - - # Keras model to force TFLite converter to insert 2 TFLite quantize ops. - # First TFLite quantize op converts float32 tensor to int8 tensor - Qnn quantize. - # Second TFLite quantize op converts int8 tensor to int8 tensor - Qnn requantize. - data_in = tf.keras.layers.Input(shape=data.shape[1:]) - relu = tf.keras.layers.ReLU()(data_in) - add = tf.keras.layers.Add()([data_in, relu]) - concat = tf.keras.layers.Concatenate(axis=0)([relu, add]) - keras_model = tf.keras.models.Model(inputs=data_in, outputs=concat) - - # To create quantized values with dynamic range of activations, needs representative dataset - def representative_data_gen(): - for _ in range(1): - yield [data] - - tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen, True, True) - - tflite_output = run_tflite_graph(tflite_model_quant, data) - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - in_node = data_in.name.split(":")[0] - else: - in_node = "serving_default_" + data_in.name + ":0" - tvm_output = run_tvm_graph(tflite_model_quant, data, in_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-2 - ) - - -def _test_quantize_dequantize_const(data): - """One iteration of quantize and dequantize""" - - # Keras model to force TFLite converter to insert 2 TFLite quantize ops. - # First TFLite quantize op converts float32 tensor to int8 tensor - Qnn quantize. - # Second TFLite quantize op converts int8 tensor to int8 tensor - Qnn requantize. - data_in = tf.keras.layers.Input(shape=data.shape[1:]) - relu = tf.keras.layers.ReLU()(data_in) - add = tf.keras.layers.Add()([data, relu]) - concat = tf.keras.layers.Concatenate(axis=0)([relu, add]) - keras_model = tf.keras.models.Model(inputs=data_in, outputs=concat) - - # To create quantized values with dynamic range of activations, needs representative dataset - def representative_data_gen(): - for _ in range(1): - yield [data] - - tflite_model_quant = _quantize_keras_model(keras_model, representative_data_gen, True, True) - - tflite_output = run_tflite_graph(tflite_model_quant, data) - if package_version.parse(tf.__version__) < package_version.parse("2.9"): - in_node = data_in.name.split(":")[0] - else: - in_node = "serving_default_" + data_in.name + ":0" - tvm_output = run_tvm_graph(tflite_model_quant, data, in_node) - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-2 - ) - - -def test_forward_quantize_dequantize(): - """Quantize Dequantize""" - data = np.random.uniform(0, 1, (1, 4, 4, 3)).astype("float32") - if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"): - _test_quantize_dequantize(data) - _test_quantize_dequantize_const(data) - - -####################################################################### -# Pad -# --- - - -def _test_pad(data, mode="CONSTANT", quantized=False): - """One iteration of PAD""" - - assert len(data) == 2 - - # Test with tensor and constant - with tf.Graph().as_default(): - in_data = [array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in")] - - if quantized: - # fake_quant will keep the tensors in float32 until the conversion in the session - input_range = {"inq_0": (-100, 100)} - inq_data = [ - tf.quantization.fake_quant_with_min_max_args( - in_data[0], min=-100, max=100, name="inq_0" - ) - ] - out = array_ops.pad( - inq_data[0], ops.convert_to_tensor(data[1], dtype=data[1].dtype), mode=mode - ) - compare_tflite_with_tvm( - [data[0]], - ["inq_0:0"], - inq_data, - [out], - quantized=True, - input_range=input_range, - experimental_new_converter=True, - ) - else: - out = array_ops.pad( - in_data[0], ops.convert_to_tensor(data[1], dtype=data[1].dtype), mode=mode - ) - compare_tflite_with_tvm([data[0]], ["in:0"], in_data, [out]) - - -def test_forward_pad(): - """Pad""" - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.array([[1, 1], [2, 2], [1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 3)), - np.array([[2, 2], [1, 1], [1, 1]], dtype=np.int32), - ] - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_pad( - [ - np.arange(1.0, 4.0, dtype=np.float32).reshape((1, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - mode="REFLECT", - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - mode="SYMMETRIC", - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int64), - ], - mode="REFLECT", - ) - _test_pad( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int64), - ], - mode="SYMMETRIC", - ) - _test_pad( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - quantized=True, - ) - _test_pad( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - quantized=True, - mode="SYMMETRIC", - ) - _test_pad( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[0, 0], [2, 2]], dtype=np.int32), - ], - quantized=True, - mode="REFLECT", - ) - - -####################################################################### -# PADV2 -# ----- - - -def _test_padv2(data, mode="CONSTANT", quantized=False): - """One iteration of PADV2""" - - assert len(data) == 2 or len(data) == 3 - - with_constant_values = len(data) == 3 - - # Test with tensor and constant - with tf.Graph().as_default(): - in_data = [array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in")] - - if quantized: - # fake_quant will keep the tensors in float32 until the conversion in the session - input_range = {"inq_0": (-100, 100)} - inq_data = [ - tf.quantization.fake_quant_with_min_max_args( - in_data[0], min=-100, max=100, name="inq_0" - ) - ] - if with_constant_values: - in_constant_values = constant_op.constant( - data[2], shape=data[2].shape, dtype="float32", name="in_constant_values" - ) - inq_constant_values = tf.quantization.fake_quant_with_min_max_args( - in_constant_values, min=-100, max=100, name="inq_constant_values" - ) - out = array_ops.pad_v2( - inq_data[0], - ops.convert_to_tensor(data[1], dtype=data[1].dtype), - constant_values=inq_constant_values, - mode=mode, - ) - out = tf.quantization.fake_quant_with_min_max_args( - out, min=-100, max=100, name="out" - ) - else: - out = array_ops.pad_v2( - inq_data[0], ops.convert_to_tensor(data[1], dtype=data[1].dtype), mode=mode - ) - compare_tflite_with_tvm( - [data[0]], ["inq_0:0"], inq_data, [out], quantized=True, input_range=input_range - ) - else: - if with_constant_values: - out = array_ops.pad_v2( - in_data[0], - ops.convert_to_tensor(data[1], dtype=data[1].dtype), - constant_values=ops.convert_to_tensor(data[2], dtype=data[2].dtype), - mode=mode, - ) - else: - out = array_ops.pad_v2( - in_data[0], ops.convert_to_tensor(data[1], dtype=data[1].dtype), mode=mode - ) - compare_tflite_with_tvm([data[0]], ["in:0"], in_data, [out]) - - -def test_forward_padv2(): - """PADV2""" - # Tests without Constant_values - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.array([[1, 1], [2, 2], [1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 3)), - np.array([[2, 2], [1, 1], [1, 1]], dtype=np.int32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 4.0, dtype=np.float32).reshape((1, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - mode="REFLECT", - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - mode="SYMMETRIC", - ) - _test_padv2( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - ], - quantized=True, - ) - - # Tests with Constant_values - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.array([[1, 1], [2, 2], [1, 1], [2, 2]], dtype=np.int32), - np.array([2], dtype=np.float32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 3)), - np.array([[2, 2], [1, 1], [1, 1]], dtype=np.int32), - np.array([1], dtype=np.float32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - np.array([-1], dtype=np.float32), - ] - ) - _test_padv2( - [ - np.arange(1.0, 4.0, dtype=np.float32).reshape((1, 3)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - np.array([2], dtype=np.float32), - ] - ) - # NOTE: In versions > 2.1.0, there is a bug in Tensorflow package for this scenario. - # Hence, it is disabled temporarily for TF version > 2.1.0 . - if package_version.parse(tf.VERSION) <= package_version.parse("2.1.0"): - _test_padv2( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - np.array([2], dtype=np.float32), - ], - quantized=True, - ) - - # Constant Values input can be scalar - _test_padv2( - [ - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.array([[1, 1], [2, 2], [1, 1], [2, 2]], dtype=np.int32), - np.float32(2), - ] - ) - # NOTE: In versions > 2.1.0, there is a bug in Tensorflow package for this scenario. - # Hence, it is disabled temporarily for TF versions > 2.1.0. - if package_version.parse(tf.VERSION) <= package_version.parse("2.1.0"): - _test_padv2( - [ - np.arange(0, 256, dtype=np.uint8).reshape((1, 256)), - np.array([[1, 1], [2, 2]], dtype=np.int32), - np.uint8(10), - ], - quantized=True, - ) - - -####################################################################### -# EXPAND_DIMS -# ----------- - - -def _test_expand_dims(input_shape, input_type, axis, quantized=False): - """One iteration of EXPAND_DIMS""" - with tf.Graph().as_default(): - axis = ops.convert_to_tensor(axis, dtype=axis.dtype) - - if quantized: - # ignoring input_type as quantized requires uint8 - input_array = np.random.uniform(0, 256, input_shape).astype("uint8") - in_input = tf.placeholder(dtype="float32", shape=input_array.shape, name="input") - - input_range = {"q_input": (-100, 100)} - inq_input = tf.quantization.fake_quant_with_min_max_args( - in_input, min=-100, max=100, name="q_input" - ) - - out = array_ops.expand_dims(inq_input, axis=axis) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-100, max=100, name="out") - - compare_tflite_with_tvm( - [input_array], - ["q_input"], - [inq_input], - [out], - quantized=True, - input_range=input_range, - ) - else: - input_array = np.random.uniform(-100, 100, input_shape).astype(input_type) - in_input = tf.placeholder( - dtype=input_array.dtype, shape=input_array.shape, name="input" - ) - - out = array_ops.expand_dims(in_input, axis=axis) - - compare_tflite_with_tvm([input_array], ["input"], [in_input], [out]) - - -def test_forward_expand_dims(): - """EXPAND_DIMS""" - for quantized in [False, True]: - _test_expand_dims((6, 2, 7, 5), "float32", np.int32(0), quantized=quantized) - _test_expand_dims((1, 2, 3), "int32", np.int32(-2), quantized=quantized) - _test_expand_dims((2, 4, 5), "float32", np.array([1], dtype=np.int32), quantized=quantized) - - -####################################################################### -# ONE_HOT -# ------- - - -def _test_one_hot(indices, depth, on_value, off_value, axis=None): - """One iteration of One_Hot""" - with tf.Graph().as_default(): - in_indices = tf.placeholder(dtype=indices.dtype, shape=indices.shape, name="indices") - in_depth = ops.convert_to_tensor(depth, dtype=depth.dtype) - in_on_value = tf.placeholder(dtype=on_value.dtype, shape=on_value.shape, name="on_value") - in_off_value = tf.placeholder( - dtype=off_value.dtype, shape=off_value.shape, name="off_value" - ) - if axis is not None: - out = array_ops.one_hot(in_indices, in_depth, in_on_value, in_off_value, axis=axis) - else: - out = array_ops.one_hot(in_indices, in_depth, in_on_value, in_off_value) - compare_tflite_with_tvm( - [indices, on_value, off_value], - ["indices", "on_value", "off_value"], - [in_indices, in_on_value, in_off_value], - [out], - ) - - -def test_forward_one_hot(): - """One_Hot""" - _test_one_hot(np.int32(2), np.int32(8), np.int32(1), np.int32(0)) - _test_one_hot(np.int32(4), np.int32(8), np.float32(1), np.float32(0)) - _test_one_hot(np.array([1, 2, 3], dtype=np.int32), np.int32(8), np.int32(3), np.int32(-1)) - _test_one_hot( - np.array([1, 2, 3], dtype=np.int32), np.int32(8), np.int32(3), np.int32(-1), axis=0 - ) - - -####################################################################### -# Pack -# ---- - - -def _test_pack(data, is_var, axis, quantized=False): - """One iteration of pack""" - - assert len(data) >= 1 - assert len(data) == len(is_var) - if quantized: - with tf.Graph().as_default(): - in_data = [ - array_ops.placeholder(shape=d.shape, dtype="float32", name="in_" + str(idx)) - if is_var[idx] - else constant_op.constant( - d, shape=d.shape, dtype="float32", name="in_constant_" + str(idx) - ) - for idx, d in enumerate(data) - ] - inq_data = [ - tf.quantization.fake_quant_with_min_max_args( - i_data, min=-100, max=100, name=f"inq_{idx}" - ) - for idx, i_data in enumerate(in_data) - ] - input_range = {} - for i in range(len(data)): - input_range[f"inq_{i}"] = (-100, 100) - - out = array_ops.pack(inq_data, axis=axis) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-100, max=100, name="out") - name = [f"inq_{idx}:0" for idx in range(len(data))] - compare_tflite_with_tvm( - data, name, inq_data, [out], quantized=True, input_range=input_range - ) - else: - with tf.Graph().as_default(): - in_data = [ - array_ops.placeholder(shape=d.shape, dtype=d.dtype, name="in_" + str(idx)) - if is_var[idx] - else constant_op.constant( - d, shape=d.shape, dtype=d.dtype, name="in_constant_" + str(idx) - ) - for idx, d in enumerate(data) - ] - - out = array_ops.pack(in_data, axis=axis) - name = [_.name for _ in in_data] - compare_tflite_with_tvm(data, name, in_data, [out], experimental_new_converter=True) - - -def test_forward_pack(): - """Pack""" - _test_pack([np.int32(1), np.int32(5)], [False, False], 0) - _test_pack([np.array([1, 4]), np.array([2, 5]), np.array([3, 6])], [True, False, False], 0) - _test_pack( - [np.arange(6).reshape((1, 2, 1, 3)), np.arange(6).reshape((1, 2, 1, 3))], [True, True], 1 - ) - - _test_pack([np.arange(6).reshape((3, 2)), np.arange(6).reshape((3, 2))], [True, True], 1) - - _test_pack( - [ - np.arange(6).reshape((2, 1, 1, 3)), - np.arange(6).reshape((2, 1, 1, 3)), - np.arange(6).reshape((2, 1, 1, 3)), - ], - [True, True, True], - 1, - ) - - _test_pack( - [ - np.arange(6, dtype=np.uint8).reshape((2, 1, 1, 3)), - np.arange(6, dtype=np.uint8).reshape((2, 1, 1, 3)), - np.arange(6, dtype=np.uint8).reshape((2, 1, 1, 3)), - ], - [True, True, True], - 1, - quantized=True, - ) - - -####################################################################### -# Unpack -# ------ - - -def _test_unpack(data, axis, num_unpacks): - """One iteration of UNPACK""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = gen_array_ops.unpack(in_data, num=num_unpacks, axis=axis, name="unpack") - out_names = ["out_" + str(n) + ":0" for n in range(num_unpacks)] - compare_tflite_with_tvm([data], "Placeholder:0", [in_data], out, out_names=out_names) - - -def test_forward_unpack(): - """UNPACK""" - _test_unpack(np.array(np.random.uniform(0, 5, (3, 1)), dtype=np.int32), axis=1, num_unpacks=1) - _test_unpack(np.array(np.random.uniform(0, 5, (3, 4)), dtype=np.float32), axis=0, num_unpacks=3) - _test_unpack( - np.array(np.random.uniform(0, 5, (3, 1, 2)), dtype=np.float32), axis=0, num_unpacks=3 - ) - # tflite 1.13 doesn't accept negative axis - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_unpack( - np.array(np.random.uniform(0, 5, (3, 6)), dtype=np.int32), axis=-2, num_unpacks=3 - ) - _test_unpack( - np.array(np.random.uniform(0, 5, (2, 3, 4)), dtype=np.int32), axis=-3, num_unpacks=2 - ) - - -####################################################################### -# Local response normalization -# ---------------------------- - - -def _test_local_response_normalization(data, depth_radius, bias, alpha, beta): - """One iteration of LOCAL_RESPONSE_NORMALIZATION""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - out = nn_ops.local_response_normalization( - in_data, depth_radius=depth_radius, bias=bias, alpha=alpha, beta=beta - ) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_local_response_normalization(): - """LOCAL_RESPONSE_NORMALIZATION""" - data = np.random.uniform(size=(1, 6, 4, 3)).astype("float32") - # LOCAL_RESPONSE_NORMALIZATION come with TFLite >= 1.14.0 fbs schema - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_local_response_normalization(data, depth_radius=5, bias=1, alpha=1, beta=0.5) - - -####################################################################### -# L2 normalization -# ---------------- - - -def _test_l2_normalization(data, axis, fused_activation_function=None): - """One iteration of L2_NORMALIZATION""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = nn_impl.l2_normalize(in_data, axis) - out = with_fused_activation_function(out, fused_activation_function) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_l2_normalization(): - """L2_NORMALIZATION""" - data = np.random.uniform(size=(3, 6, 4)).astype("float32") - _test_l2_normalization(data, axis=2) - _test_l2_normalization(data, axis=2, fused_activation_function="RELU") - - -####################################################################### -# Logistic -# -------- - - -def _test_logistic(data, quantized=False): - """One iteration of LOGISTIC""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-5, max=5, name="inq_0" - ) - input_range = {"inq_0": (-5, 5)} - out = math_ops.sigmoid(inq_data) - out = tf.quantization.fake_quant_with_min_max_args(out, min=0, max=1, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = math_ops.sigmoid(in_data) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_logistic(): - """LOGISTIC""" - _test_logistic(np.arange(6.0, dtype=np.float32).reshape((1, 6))) - _test_logistic(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True) - - -####################################################################### -# Softmax -# ------- - - -def _test_softmax(data): - """One iteration of softmax""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = nn_ops.softmax(in_data) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_softmax(): - """Softmax""" - _test_softmax(np.arange(6.0, dtype=np.float32).reshape((1, 6))) - _test_softmax(np.arange(6.0, dtype=np.float32).reshape((1, 2, 3))) - - -###################################################################### -# Log_softmax -# ----------- - - -def _test_log_softmax(data, quantized=False): - """One iteration of log_softmax""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-10, max=10, name="inq_0" - ) - input_range = {"inq_0": (-10, 10)} - # tflite log_softmax supports only the case when axis is not specified - out = nn_ops.log_softmax(inq_data) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-20, max=0, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = nn_ops.log_softmax(in_data) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_log_softmax(): - """Log_softmax""" - _test_log_softmax(np.random.uniform(-10, 10, size=(3, 6)).astype(np.float32)) - _test_log_softmax(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True) - - -####################################################################### -# Tanh -# ---- - - -def _test_tanh(data, quantized=False): - """One iteration of TANH""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-3, max=3, name="inq_0" - ) - input_range = {"inq_0": (-3, 3)} - out = math_ops.tanh(inq_data) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-1, max=1, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = math_ops.tanh(in_data) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_tanh(): - """TANH""" - _test_tanh(np.arange(6.0, dtype=np.float32).reshape((1, 6)), quantized=False) - _test_tanh(np.arange(0, 256, 30, dtype=np.uint8), quantized=True) - - -####################################################################### -# ReLu -# ---- - - -def _test_relu(data, quantized=False): - """One iteration of ReLU""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-10, max=10, name="inq_0" - ) - input_range = {"inq_0": (-10, 10)} - out = nn_ops.relu(inq_data) - out = tf.quantization.fake_quant_with_min_max_args(out, min=0, max=6, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = nn_ops.relu(in_data) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_relu(): - """ReLU""" - _test_relu(np.arange(6.0, dtype=np.float32).reshape((1, 6))) - _test_relu(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True) - - -####################################################################### -# ReLU6 -# ----- - - -def _test_relu6(data, quantized=False): - """One iteration of ReLU6""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-10, max=10, name="inq_0" - ) - input_range = {"inq_0": (-10, 10)} - out = nn_ops.relu6(inq_data) - out = tf.quantization.fake_quant_with_min_max_args(out, min=0, max=6, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = nn_ops.relu6(in_data) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_relu6(): - """ReLU6""" - _test_relu6(np.random.uniform(-10, 10, size=(3, 6)).astype(np.float32)) - _test_relu6(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True) - - -####################################################################### -# Leaky_ReLU -# ---------- - - -def _test_leaky_relu(data, alpha, quantized=False): - """One iteration of Leaky_ReLU""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-3, max=2, name="inq_0" - ) - input_range = {"inq_0": (-3, 2)} - out = nn_ops.leaky_relu(inq_data, alpha) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-3, max=2, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = nn_ops.leaky_relu(in_data, alpha) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_leaky_relu(): - """Leaky_ReLU""" - _test_leaky_relu(np.random.uniform(-5, 5, (1, 6)).astype(np.float32), alpha=0.2) - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_leaky_relu( - np.random.uniform(0, 255, (2, 3)).astype(np.uint8), alpha=0.3, quantized=True - ) - - -####################################################################### -# ReLU_n1_to_1 -# ------------ - - -def _test_relu_n1_to_1(data, quantized=False): - """One iteration of ReLU_n1_to_1""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype="float32", name="in_0") - - if quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-3, max=3, name="inq_0" - ) - input_range = {"inq_0": (-3, 3)} - # There is no such tf operation. - # The specific pattern will be replaced into RELU_N1_TO_1 by tflite - out = math_ops.maximum(-1.0, math_ops.minimum(inq_data, 1.0)) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-1, max=1, name="out") - compare_tflite_with_tvm( - data, "inq_0:0", [inq_data], [out], quantized=True, input_range=input_range - ) - else: - out = math_ops.maximum(-1.0, math_ops.minimum(in_data, 1.0)) - compare_tflite_with_tvm(data, "in_0:0", [in_data], [out]) - - -def test_forward_relu_n1_to_1(): - """ReLU_n1_to_1""" - _test_relu_n1_to_1(np.random.uniform(-3, 3, (1, 6)).astype(np.float32)) - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_relu_n1_to_1(np.random.uniform(0, 255, (3, 6)).astype(np.uint8), quantized=True) - - -####################################################################### -# PReLU -# ----- - - -def _test_prelu(data, alpha): - """One iteration of PReLU""" - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - # This specific pattern will be replaced into PRelu by tflite - out = nn_ops.relu(in_data) + (-alpha * nn_ops.relu(-in_data)) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_prelu(): - """PReLU""" - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((3,), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((1, 3), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((1, 1, 3), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((1, 1, 1, 3), 0.2, dtype="float32"), - ) - # - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((32, 3), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((32, 32, 3), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 32, 3)).astype("float32"), - np.full((1, 32, 1, 3), 0.2, dtype="float32"), - ) - # - _test_prelu( - np.random.uniform(-5, 5, size=(1, 1, 3)).astype("float32"), - np.full((3,), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(1, 32, 3)).astype("float32"), - np.full((32, 3), 0.2, dtype="float32"), - ) - _test_prelu( - np.random.uniform(-5, 5, size=(32, 3)).astype("float32"), np.full((3), 0.2, dtype="float32") - ) - - -####################################################################### -# DepthToSpace -# ------------ - - -def _test_depthtospace(data, block_size): - """One iteration of depth_to_space operation with given data and block size""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = array_ops.depth_to_space(in_data, block_size) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_depthtospace(): - # DEPTH_TO_SPACE comes with TFLite >= 1.15.0 fbs schema - if package_version.parse(tf.VERSION) >= package_version.parse("1.15.0"): - _test_depthtospace(np.random.normal(size=[1, 32, 32, 4]).astype("float32"), 2) - _test_depthtospace(np.random.normal(size=[1, 16, 8, 32]).astype("float32"), 4) - - -####################################################################### -# SpaceToDepth -# ------------ - - -def _test_spacetodepth(data, block_size): - """One iteration of space_to_depth operation with given data and block size""" - - with tf.Graph().as_default(): - in_data = array_ops.placeholder(shape=data.shape, dtype=data.dtype) - out = array_ops.space_to_depth(in_data, block_size) - compare_tflite_with_tvm(data, "Placeholder:0", [in_data], [out]) - - -def test_forward_spacetodepth(): - _test_spacetodepth(np.random.normal(size=[1, 32, 32, 4]).astype("float32"), 2) - _test_spacetodepth(np.random.normal(size=[1, 16, 8, 32]).astype("float32"), 4) - - -####################################################################### -# ReverseSequence -# --------------- - - -def _test_reverse_sequence(shape, dtype, seq_lengths, batch_axis, seq_axis): - """One iteration of reverse_sequence operation with given data and attributes""" - - data = np.random.uniform(0, 100, size=shape).astype(dtype) - with tf.Graph().as_default(): - in_data = array_ops.placeholder(dtype=dtype, name="input", shape=shape) - out = tf.reverse_sequence( - in_data, seq_lengths=seq_lengths, batch_axis=batch_axis, seq_axis=seq_axis - ) - - compare_tflite_with_tvm(data, "input", [in_data], [out]) - - -def test_forward_reverse_sequence(): - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - _test_reverse_sequence([4, 3], "float32", [3, 2, 1], 1, 0) - _test_reverse_sequence([4, 3], "float32", [3, 2, 1, 3], 0, 1) - _test_reverse_sequence([2, 3, 3, 3], "float32", [2, 3, 2], 2, 1) - _test_reverse_sequence([2, 4, 6, 4, 5], "float32", [5, 3], 0, 2) - _test_reverse_sequence([2, 4, 6, 4, 5], "float32", [5, 3, 1, 4], 3, 2) - - -####################################################################### -# Sparse To Dense -# --------------- -def _test_sparse_to_dense(sparse_indices, sparse_values, default_value, output_shape): - # tflite 1.13 convert method does not accept empty shapes - if package_version.parse(tf.VERSION) >= package_version.parse("1.14.0"): - with tf.Graph().as_default(): - indices = tf.placeholder( - shape=sparse_indices.shape, dtype=str(sparse_indices.dtype), name="indices" - ) - values = tf.placeholder( - shape=sparse_values.shape, dtype=str(sparse_values.dtype), name="values" - ) - oshape = tf.constant( - output_shape, shape=output_shape.shape, dtype=str(output_shape.dtype) - ) - - if default_value is None: - output = tf.sparse_to_dense(indices, oshape, values) - compare_tflite_with_tvm( - [sparse_indices, sparse_values], - ["indices", "values"], - [indices, values], - [output], - ) - else: - dv_placeholder = tf.placeholder( - shape=(), dtype=str(default_value.dtype), name="default_value" - ) - output = tf.sparse_to_dense(indices, oshape, values, dv_placeholder) - compare_tflite_with_tvm( - [sparse_indices, sparse_values, default_value], - ["indices", "values", "default_value"], - [indices, values, dv_placeholder], - [output], - ) - - -def test_forward_sparse_to_dense(): - """ - Works in tvm/topi/tensorflow. But tflite converter breaks this test case - _test_sparse_to_dense( - np.int32(1), - np.int32(3), - np.int32(0), - np.array([5]).astype("int32") - ) - """ - # vector - _test_sparse_to_dense( - np.array([0, 1, 4]).astype("int32"), - np.array([3, 3, 3]).astype("int32"), - np.int32(0), - np.array([5]).astype("int32"), - ) - # vector nXd - _test_sparse_to_dense( - np.array([[0, 0], [1, 2]]).astype("int32"), - np.array([1, 2]).astype("int32"), - np.int32(0), - np.array([3, 4]).astype("int32"), - ) - _test_sparse_to_dense( - np.array([[0, 0, 0], [1, 2, 3]]).astype("int32"), - np.array([1, 2]).astype("int32"), - np.int32(4), - np.array([2, 3, 4]).astype("int32"), - ) - # floats - _test_sparse_to_dense( - np.array([0, 1, 4]).astype("int32"), - np.array([3.1, 3.1, 3.1]).astype("float32"), - np.float32(3.5), - np.array([5]).astype("int32"), - ) - # default value not specified - _test_sparse_to_dense( - np.array([0, 1, 4]).astype("int32"), - np.array([3.1, 3.1, 3.1]).astype("float32"), - None, - np.array([5]).astype("int32"), - ) - - -####################################################################### -# Fully Connected -# --------------- -def _test_fully_connected( - tensor_in_sizes, - const_input, - filter_in_sizes, - bias_in_size=None, - quantized=False, - fp16_quantized=False, -): - """One iteration of fully connected""" - - total_size_1 = np.prod(tensor_in_sizes) - total_size_2 = np.prod(filter_in_sizes) - - assert ( - int(total_size_1 / tensor_in_sizes[0]) == filter_in_sizes[0] - ), "input size and filter size are mismatched" - - # Initializes the input tensor with array containing incrementing - # numbers from 1. - data_array = np.arange( - 1, total_size_1 + 1, dtype=np.uint8 if quantized and not fp16_quantized else np.float32 - ) - filter_array = np.arange( - 1, total_size_2 + 1, dtype=np.uint8 if quantized and not fp16_quantized else np.float32 - ) - in_name = "input" - - with tf.Graph().as_default(): - in_data = ( - constant_op.constant(data_array, shape=tensor_in_sizes, dtype=np.float32, name=in_name) - if const_input - else array_ops.placeholder(shape=tensor_in_sizes, dtype=np.float32, name=in_name) - ) - - in_filter = constant_op.constant(filter_array, shape=filter_in_sizes, dtype=np.float32) - data_array = np.reshape(data_array, tensor_in_sizes) - - # if we have bias - if bias_in_size: - assert bias_in_size[0] == filter_in_sizes[1], "bias and filter size are mismatched" - bias_array = np.arange( - 1, bias_in_size[0] + 1, dtype=np.uint8 if quantized else np.float32 - ) - in_bias = constant_op.constant(bias_array, shape=bias_in_size, dtype=np.float32) - - if quantized and not fp16_quantized: - inq_data = tf.quantization.fake_quant_with_min_max_args( - in_data, min=-100, max=100, name="inq_0" - ) - input_range = {"inq_0": (-100, 100)} - inq_filter = tf.quantization.fake_quant_with_min_max_args( - in_filter, min=-100, max=100, name="inq_1" - ) - input_range = {"inq_0": (-100, 100), "inq_1": (-100, 100)} - # reshape N H W C into N H*W*C - inq_data_reshape = array_ops.reshape(inq_data, [tensor_in_sizes[0], -1]) - out = math_ops.mat_mul(inq_data_reshape, inq_filter) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-100, max=100, name="out") - - # if we have bias - if bias_in_size: - out = nn_ops.bias_add(out, in_bias) - - compare_tflite_with_tvm( - data_array, - inq_data.name, - [inq_data], - [out], - quantized=True, - input_range=input_range, - experimental_new_converter=True, - ) - else: - # reshape N H W C into N H*W*C - in_data_reshape = array_ops.reshape(in_data, [tensor_in_sizes[0], -1]) - out = math_ops.mat_mul(in_data_reshape, in_filter) - # TODO : Need to construct a fc op with (keep_num_dims == True) - - # if we have bias - if bias_in_size: - out = nn_ops.bias_add(out, in_bias) - - compare_tflite_with_tvm( - data_array, - in_data.name, - [in_data], - [out], - experimental_new_converter=True, - fp16_quantized=fp16_quantized, - ) - - -def test_forward_fully_connected(): - """Fully Connected""" - for input_shape, weight_shape, bias_shape in [ - ([1, 4], [4, 4], None), - ([1, 4], [4, 4], [4]), - ([1, 1, 1, 5], [5, 5], None), - ([1, 1, 10], [10, 103], None), - ([1, 1, 1, 150], [150, 100], None), - ([1, 1, 1, 150], [150, 100], None), - ([1, 1, 1, 150], [150, 100], [100]), - ([5, 1, 1, 150], [150, 100], None), - ([5, 1, 1, 150], [150, 100], [100]), - ]: - for const_input in [False, True]: - for quantized in [False, True]: - for fp16_quantized in [False, True]: - _test_fully_connected( - input_shape, - const_input, - weight_shape, - bias_shape, - quantized, - fp16_quantized, - ) - - -####################################################################### -# REVERSE_V2 -# ---------- - - -def _test_reverse_v2(input_shape, axis, dtype): - """One iteration of REVERSE_V2""" - with tf.Graph().as_default(): - input_array = np.random.randint(0, 100, size=input_shape).astype(dtype) - in_input = tf.placeholder(dtype=input_array.dtype, shape=input_array.shape, name="input") - in_axis = ops.convert_to_tensor(axis, dtype=axis.dtype) - - out = array_ops.reverse(in_input, in_axis) - - compare_tflite_with_tvm([input_array], ["input"], [in_input], [out]) - - -def test_forward_reverse_v2(): - """REVERSE_V2""" - for dtype in ["float32", "int32"]: - _test_reverse_v2((5), np.array([0], dtype="int32"), dtype) - _test_reverse_v2((5, 6, 4, 2), np.array([2], dtype="int32"), dtype) - - -####################################################################### -# MATRIX_SET_DIAG -# --------------- - - -def _test_matrix_set_diag(input_shape, input_type, quantized=False): - """One iteration of MATRIX_SET_DIAG""" - with tf.Graph().as_default(): - diagonal_shape = list(input_shape[:-2]) - diagonal_shape.append(min(input_shape[-2], input_shape[-1])) - - if quantized: - # ignoring input_type as quantized requires uint8 - input_array = np.random.uniform(0, 256, input_shape).astype("uint8") - in_input = tf.placeholder(dtype="float32", shape=input_array.shape, name="input") - inq_input = tf.quantization.fake_quant_with_min_max_args( - in_input, min=-100, max=100, name="q_input" - ) - - diagonal = np.random.uniform(0, 256, diagonal_shape).astype("uint8") - in_diagonal = tf.placeholder(dtype="float32", shape=diagonal.shape, name="diagonal") - inq_diagonal = tf.quantization.fake_quant_with_min_max_args( - in_diagonal, min=-100, max=100, name="q_diagonal" - ) - - input_range = {"q_input": (-100, 100), "q_diagonal": (-100, 100)} - - out = array_ops.matrix_set_diag(inq_input, inq_diagonal) - out = tf.quantization.fake_quant_with_min_max_args(out, min=-100, max=100, name="out") - - compare_tflite_with_tvm( - [input_array, diagonal], - ["q_input", "q_diagonal"], - [inq_input, inq_diagonal], - [out], - quantized=True, - input_range=input_range, - ) - else: - input_array = np.random.uniform(0, 100, input_shape).astype(input_type) - diagonal = np.random.uniform(0, 100, diagonal_shape).astype(input_type) - - in_input = tf.placeholder( - dtype=input_array.dtype, shape=input_array.shape, name="input" - ) - in_diagonal = tf.placeholder( - dtype=diagonal.dtype, shape=diagonal.shape, name="diagonal" - ) - - out = array_ops.matrix_set_diag(in_input, in_diagonal) - - compare_tflite_with_tvm( - [input_array, diagonal], ["input", "diagonal"], [in_input, in_diagonal], [out] - ) - - -def test_forward_matrix_set_diag(): - """MATRIX_SET_DIAG""" - for dtype in [np.float32, np.int32]: - _test_matrix_set_diag((4, 4), dtype) - _test_matrix_set_diag((5, 4, 3, 4), dtype) - _test_matrix_set_diag((4, 4, 2), dtype) - - _test_matrix_set_diag((4, 4), np.uint8, quantized=True) - _test_matrix_set_diag((5, 4, 3, 4), np.uint8, quantized=True) - _test_matrix_set_diag((4, 4, 2), np.uint8, quantized=True) - - -####################################################################### -# MATRIX_DIAG -# ----------- - - -def _test_matrix_diag(diagonal_shape, dtype): - """One iteration of MATRIX_DIAG""" - with tf.Graph().as_default(): - diagonal = np.random.uniform(0, 100, diagonal_shape).astype(dtype) - in_diagonal = tf.placeholder(dtype=diagonal.dtype, shape=diagonal.shape, name="diagonal") - - out = array_ops.matrix_diag(in_diagonal) - - compare_tflite_with_tvm( - [diagonal], ["diagonal"], [in_diagonal], [out], experimental_new_converter=True - ) - - -def test_forward_matrix_diag(): - """MATRIX_DIAG""" - for dtype in [np.float32, np.int32]: - _test_matrix_diag((4), dtype) - _test_matrix_diag((5, 4, 3), dtype) - _test_matrix_diag((2, 3), dtype) - - -####################################################################### -# Custom Operators -# ---------------- - - -def _test_detection_postprocess(tf_model_file, box_encodings_size, class_predictions_size): - """One iteration of detection postProcess with given model and shapes""" - converter = tf.lite.TFLiteConverter.from_frozen_graph( - tf_model_file, - input_arrays=["raw_outputs/box_encodings", "raw_outputs/class_predictions"], - output_arrays=[ - "TFLite_Detection_PostProcess", - "TFLite_Detection_PostProcess:1", - "TFLite_Detection_PostProcess:2", - "TFLite_Detection_PostProcess:3", - ], - input_shapes={ - "raw_outputs/box_encodings": box_encodings_size, - "raw_outputs/class_predictions": class_predictions_size, - }, - ) - converter.allow_custom_ops = True - converter.inference_type = tf.lite.constants.FLOAT - tflite_model = converter.convert() - np.random.seed(0) - box_encodings = np.random.uniform(size=box_encodings_size).astype("float32") - class_predictions = np.random.uniform(size=class_predictions_size).astype("float32") - tflite_output = run_tflite_graph(tflite_model, [box_encodings, class_predictions]) - tvm_output = run_tvm_graph( - tflite_model, - [box_encodings, class_predictions], - ["raw_outputs/box_encodings", "raw_outputs/class_predictions"], - num_output=4, - ) - - # Check all output shapes are equal - assert all( - list( - tvm_tensor.shape == tflite_tensor.shape - for (tvm_tensor, tflite_tensor) in zip(tvm_output, tflite_output) - ) - ) - - # Check valid count is the same - assert tvm_output[3] == tflite_output[3] - valid_count = tvm_output[3][0] - - # For boxes that do not have any detections, TFLite puts random values. Therefore, we compare - # tflite and tvm tensors for only valid boxes. - for i in range(0, valid_count): - # Check bounding box co-ords - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0][0][i]), - np.squeeze(tflite_output[0][0][i]), - rtol=1e-5, - atol=1e-5, - ) - - # Check the class - # Stricter check to ensure class remains same - np.testing.assert_equal(np.squeeze(tvm_output[1][0][i]), np.squeeze(tflite_output[1][0][i])) - - # Check the score - tvm.testing.assert_allclose( - np.squeeze(tvm_output[2][0][i]), - np.squeeze(tflite_output[2][0][i]), - rtol=1e-5, - atol=1e-5, - ) - - -def test_detection_postprocess(): - """Detection PostProcess""" - - # Fast-NMS - box_encodings_size = (1, 1917, 4) - class_predictions_size = (1, 1917, 91) - tf_model_file = tf_testing.get_workload_official( - "http://download.tensorflow.org/models/object_detection/" - "ssd_mobilenet_v2_quantized_300x300_coco_2019_01_03.tar.gz", - "ssd_mobilenet_v2_quantized_300x300_coco_2019_01_03/tflite_graph.pb", - ) - _test_detection_postprocess(tf_model_file, box_encodings_size, class_predictions_size) - - # Fast-NMS - box_encodings_size = (1, 2034, 4) - class_predictions_size = (1, 2034, 91) - tf_model_file = download_testdata( - "https://github.com/czh978/models_for_tvm_test/raw/main/tflite_graph_with_postprocess.pb", - "tflite_graph_with_postprocess.pb", - ) - _test_detection_postprocess(tf_model_file, box_encodings_size, class_predictions_size) - - # Regular NMS - box_encodings_size = (1, 1917, 4) - class_predictions_size = (1, 1917, 91) - tf_model_file = download_testdata( - ( - "https://github.com/Grovety/ModelZoo/raw/52fb82156ae8c8e3f62c7d7caf6867b25261dda4/" - "models/object_detection/ssd_mobilenet_v1/tflite_int8/tflite_graph_with_regular_nms.pb" - ), - "tflite_graph_with_regular_nms.pb", - ) - _test_detection_postprocess(tf_model_file, box_encodings_size, class_predictions_size) - - -####################################################################### -# Custom Converter -# ---------------- - - -def test_custom_op_converter(): - """Test case for user-defined operator converter in TFLite frontend""" - - class DummyOperatorConverter(relay.frontend.tflite.OperatorConverter): - """Operator Converter for converting TFLite ops to relay ops""" - - def __init__(self, model, subgraph, exp_tab): - super().__init__(model, subgraph, exp_tab) - self.allow_custom_ops = True - - convert_map_overwrite = {"SUB": self.convert_sub_dummy} - - self.convert_map.update(convert_map_overwrite) - - def convert_sub_dummy(self, op): - """Convert TFLite SUB""" - input_tensors = self.get_input_tensors(op) - assert len(input_tensors) == 2, "input tensors length should be 2" - - lhs_tensor = input_tensors[0] - rhs_tensor = input_tensors[1] - - lhs_expr = self.get_expr(lhs_tensor.tensor_idx) - rhs_expr = self.get_expr(rhs_tensor.tensor_idx) - - temp_expr = relay.op.negative(rhs_expr) - out = relay.op.add(lhs_expr, temp_expr) - - return out - - with tf.Graph().as_default(): - # Generate TFLite model for single addition - data = [ - np.arange(6.0, dtype=np.float32).reshape((2, 1, 1, 3)), - np.arange(1.0, 7.0, dtype=np.float32).reshape((2, 1, 1, 3)), - ] - in_data = [ - array_ops.placeholder(shape=data[0].shape, dtype="float32", name="in_0"), - array_ops.placeholder(shape=data[1].shape, dtype="float32", name="in_1"), - ] - out = math_ops.subtract(in_data[0], in_data[1]) - in_name = [x[1] for x in zip(in_data, ("in_0:0", "in_1:0"))] - input_tensors = in_data - output_tensors = [out] - in_node = [0] * len(in_name) - for i, _ in enumerate(in_name): - in_node[i] = in_name[i].split(":")[0] - - with tf.Session() as sess: - converter = tf.lite.TFLiteConverter.from_session(sess, input_tensors, output_tensors) - tflite_model_buf = converter.convert() - in_data = [x[1] for x in zip(in_data, data)] - tvm_output_orig = run_tvm_graph(tflite_model_buf, in_data, in_node) - tvm_output_dummy = run_tvm_graph( - tflite_model_buf, in_data, in_node, op_converter=DummyOperatorConverter - ) - tvm.testing.assert_allclose( - np.squeeze(tvm_output_orig[0]), np.squeeze(tvm_output_dummy[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Mobilenet -# --------- - - -def test_forward_mobilenet_v1(): - """Test the Mobilenet V1 TF Lite model.""" - # MobilenetV1 - tflite_model_file = tf_testing.get_workload_official( - "http://download.tensorflow.org/models/mobilenet_v1_2018_08_02/mobilenet_v1_1.0_224.tgz", - "mobilenet_v1_1.0_224.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -def test_forward_mobilenet_v2(): - """Test the Mobilenet V2 TF Lite model.""" - # MobilenetV2 - tflite_model_file = tf_testing.get_workload_official( - "http://download.tensorflow.org/models/tflite_11_05_08/mobilenet_v2_1.0_224.tgz", - "mobilenet_v2_1.0_224.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Mobilenet V3 -# ------------ - - -def test_forward_mobilenet_v3(): - """Test the Mobilenet V3 TF Lite model.""" - # In MobilenetV3, some ops are not supported before tf 1.15 fbs schema - if package_version.parse(tf.VERSION) < package_version.parse("1.15.0"): - return - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/mobilenet_v3/checkpoints/v3-large_224_1.0_float.tgz", - "v3-large_224_1.0_float/v3-large_224_1.0_float.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Mobilenet V1 Sparse -# ----------------- - - -def test_forward_sparse_mobilenet_v1(): - """Test the Sparse version of Mobilenet V1 TF Lite model.""" - # MobilenetV1 - tflite_model_file = download_testdata( - "https://storage.googleapis.com/fast-convnets/tflite-models/mbv1_140_90_12b4_720.tflite", - "mbv1_140_90_12b4_720.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "float_image_input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Mobilenet V2 Sparse -# ----------------- - - -def test_forward_sparse_mobilenet_v2(): - """Test the Sparse version of Mobilenet V2 TF Lite model.""" - # MobilenetV1 - tflite_model_file = download_testdata( - "https://storage.googleapis.com/fast-convnets/tflite-models/mbv2_200_85_11-16b2_744.tflite", - "mbv2_200_85_11-16b2_744.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 224, 224, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "float_image_input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Inception -# --------- - - -def test_forward_inception_v3_net(): - """Test the Inception V3 TF Lite model.""" - # InceptionV3 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/tflite/model_zoo/" - "upload_20180427/inception_v3_2018_04_27.tgz", - "inception_v3.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 299, 299, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -def test_forward_inception_v4_net(): - """Test the Inception V4 TF Lite model.""" - # InceptionV4 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/" - "tflite/model_zoo/upload_20180427/" - "inception_v4_2018_04_27.tgz", - "inception_v4.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 299, 299, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -def test_forward_inception_v4_net_batched(): - """Test the Inception V4 TF Lite model.""" - # InceptionV4 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/" - "tflite/model_zoo/upload_20180427/" - "inception_v4_2018_04_27.tgz", - "inception_v4.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(4, 299, 299, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0]), np.squeeze(tflite_output[0]), rtol=1e-5, atol=1e-5 - ) - - -def test_forward_qnn_inception_v1_net(): - """Test the Quantized TFLite Inception model.""" - # InceptionV1 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/" - "inception_v1_224_quant_20181026.tgz", - "inception_v1_224_quant.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - data = get_real_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -def test_forward_qnn_mobilenet_v1_net(): - """Test the Quantized TFLite Mobilenet V1 model.""" - # MobilenetV1 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_2018_08_02/" - "mobilenet_v1_1.0_224_quant.tgz", - "mobilenet_v1_1.0_224_quant.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - data = get_real_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -def test_forward_qnn_mobilenet_v2_net(): - """Test the Quantized TFLite Mobilenet V2 model.""" - # MobilenetV2 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/tflite_11_05_08/" - "mobilenet_v2_1.0_224_quant.tgz", - "mobilenet_v2_1.0_224_quant.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - data = get_real_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -####################################################################### -# Mobilenet V3 Quantized -# ---------------------- - - -def test_forward_qnn_mobilenet_v3_net(): - """Test the Quantized TFLite Mobilenet V3 model.""" - # In MobilenetV3, some ops are not supported before tf 1.15 fbs schema - if package_version.parse(tf.VERSION) < package_version.parse("1.15.0"): - pytest.skip("Unsupported in tflite < 1.15.0") - else: - pytest.skip("This segfaults with tensorflow 1.15.2 and above") - - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/mobilenet_v3/checkpoints/v3-large_224_1.0_uint8.tgz", - "v3-large_224_1.0_uint8/v3-large_224_1.0_uint8.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - data = get_real_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -@pytest.mark.skipif( - platform.machine() == "aarch64", - reason="Fails with an output mismatch. See https://github.com/apache/tvm/issues/16534", -) -def test_forward_tflite2_qnn_resnet50(): - """Test the Quantized TFLite version 2.1.0 Resnet50 model.""" - if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"): - tflite_model_file = download_testdata( - "https://raw.githubusercontent.com/dmlc/web-data/main/tensorflow/models/Quantized/" - "resnet_50_quantized.tflite", - "resnet_50_quantized.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = pre_processed_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, np.array(data), "input_1") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -def test_forward_tflite2_qnn_inception_v1(): - """Test the Quantized TFLite version 2.1.0 Inception V1 model.""" - if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"): - tflite_model_file = download_testdata( - "https://raw.githubusercontent.com/dmlc/web-data/main/tensorflow/models/Quantized/" - "inception_v1_quantized.tflite", - "inception_v1_quantized.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = pre_processed_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, np.array(data), "input_1") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -def test_forward_tflite2_qnn_mobilenet_v2(): - """Test the Quantized TFLite version 2.1.0 Mobilenet V2 model.""" - if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"): - tflite_model_file = download_testdata( - "https://raw.githubusercontent.com/dmlc/web-data/main/tensorflow/models/Quantized/" - "mobilenet_v2_quantized.tflite", - "mobilenet_v2_quantized.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = pre_processed_image(224, 224) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, np.array(data), "input_1") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -def test_forward_tflite_float16(): - """Test float16 quantized model""" - # MobilenetV2 - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_2018_02_22/" - "mobilenet_v1_0.25_128.tgz", - "mobilenet_v1_0.25_128_frozen.pb", - ) - - converter = tf.lite.TFLiteConverter.from_frozen_graph( - tflite_model_file, ["input"], ["MobilenetV1/Predictions/Reshape_1"] - ) - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.target_spec.supported_types = [tf.float16] - tflite_model_buf = converter.convert() - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - data = get_real_image(128, 128, quantized=False) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -@pytest.mark.skipif( - platform.machine() == "aarch64", - reason="Fails during leagalization due to int16 datatype. " - "See https://github.com/apache/tvm/issues/16535", -) -def test_forward_mobilenet_int16(): - """Test int16 quantized model""" - # MobilenetV2 - model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/mobilenet_v1_2018_02_22/" - "mobilenet_v1_0.25_128.tgz", - "mobilenet_v1_0.25_128_frozen.pb", - ) - - # Test image. Checking the labels because the requantize implementation is different between - # TFLite and Relay. This cause final output numbers to mismatch. So, testing accuracy via - # labels. Also, giving a real image, instead of random inputs. - # - # According to TFLite documentation, despite the quantization being done to make this model - # use int16 types, inputs and outputs are kept float32 by default. - # https://www.tensorflow.org/lite/performance/post_training_integer_quant_16x8 - data = get_real_image(128, 128, quantized=False) - - converter = tf.lite.TFLiteConverter.from_frozen_graph( - model_file, ["input"], ["MobilenetV1/Predictions/Reshape_1"] - ) - - def representative_dataset(): - for _ in range(1): - yield [data] - - converter.optimizations = [tf.lite.Optimize.DEFAULT] - converter.target_spec.supported_ops = [ - tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8 - ] - converter.representative_dataset = representative_dataset - tflite_model_buf = converter.convert() - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "input") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -@pytest.mark.skipif( - platform.machine() == "aarch64", - reason="Fails during leagalization due to int16 datatype. " - "See https://github.com/apache/tvm/issues/16535", -) -def test_forward_ds_cnn_int16(): - """Test DS_CNN int16 quantized model""" - tflite_model_file = download_testdata( - "https://github.com/ARM-software/ML-zoo/blob/48f458af1e9065d9aad2ad94d24b58d6e7c00817/" - "models/keyword_spotting/ds_cnn_small/tflite_int16/ds_cnn_quantized.tflite?raw=true", - "ds_cnn_quantized_int16.tflite", - ) - - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = np.random.uniform(size=(1, 490)).astype("int16") - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tflite_predictions = np.squeeze(tflite_output) - tflite_sorted_labels = tflite_predictions.argsort()[-3:][::-1] - tvm_output = run_tvm_graph(tflite_model_buf, data, "serving_default_input:0") - tvm_predictions = np.squeeze(tvm_output) - tvm_sorted_labels = tvm_predictions.argsort()[-3:][::-1] - tvm.testing.assert_allclose(tvm_sorted_labels, tflite_sorted_labels) - - -####################################################################### -# Unidirectional Sequence LSTM -# --------------------- -def test_forward_unidirectional_sequence_lstm(): - """Test the UnidirectionalSequenceLSTM TFLite""" - if package_version.parse(tf.VERSION) >= package_version.parse("2.1.0"): - tflite_model_file = download_testdata( - "https://github.com/SebastianBoblestETAS/nn_models/blob/" - "ce49c5de64889493161ca4194a20e0fd5eb707e6/lstm_1_in_3_out_2_ts_4.tflite?raw=true", - "lstm_1_in_3_out_2_ts_4.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = np.array( - [ - [ - [0.5488135, 0.71518934, 0.60276335], - [0.5448832, 0.4236548, 0.6458941], - [0.4375872, 0.891773, 0.96366274], - [0.3834415, 0.79172504, 0.5288949], - ] - ], - dtype="float32", - ) - - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "serving_default_input_1:0") - tvm.testing.assert_allclose(tflite_output, tvm_output) - - -####################################################################### -# Quantized SSD Mobilenet -# ----------------------- - - -def test_forward_qnn_coco_ssd_mobilenet_v1(): - """Test the quantized Coco SSD Mobilenet V1 TF Lite model.""" - pytest.skip( - "LLVM bug - getExtendedVectorNumElements - " - + "https://discuss.tvm.apache.org/t/segfault-in-llvm/3567. The workaround is to use a " - + "specific target, for example, llvm -mpcu=core-avx2" - ) - - tflite_model_file = tf_testing.get_workload_official( - "https://storage.googleapis.com/download.tensorflow.org/models/tflite/" - "coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip", - "detect.tflite", - ) - - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - data = get_real_image_object_detection(300, 300) - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph( - tflite_model_buf, data, "normalized_input_image_tensor", num_output=4 - ) - - # Check all output shapes are equal - assert all( - list( - tvm_tensor.shape == tflite_tensor.shape - for (tvm_tensor, tflite_tensor) in zip(tvm_output, tflite_output) - ) - ) - - # Check valid count is the same - assert tvm_output[3] == tflite_output[3] - valid_count = tvm_output[3][0] - - # For boxes that do not have any detections, TFLite puts random values. Therefore, we compare - # tflite and tvm tensors for only valid boxes. - for i in range(0, valid_count): - # We compare the bounding boxes whose prediction score is above 60%. This is typical in end - # to end application where a low prediction score is discarded. This is also needed because - # multiple low score bounding boxes can have same score and TFlite and TVM can have - # different orderings for same score bounding boxes. Another reason for minor differences in - # low score bounding boxes is the difference between TVM and TFLite for requantize operator. - if tvm_output[2][0][i] > 0.6: - # Check bounding box co-ords. The tolerances have to be adjusted, from 1e-5 to 1e-2, - # because of differences between for requantiize operator in TFLite and TVM. - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0][0][i]), - np.squeeze(tflite_output[0][0][i]), - rtol=1e-2, - atol=1e-2, - ) - - # Check the class - # Stricter check to ensure class remains same - np.testing.assert_equal( - np.squeeze(tvm_output[1][0][i]), np.squeeze(tflite_output[1][0][i]) - ) - - # Check the score - tvm.testing.assert_allclose( - np.squeeze(tvm_output[2][0][i]), - np.squeeze(tflite_output[2][0][i]), - rtol=1e-5, - atol=1e-5, - ) - - -####################################################################### -# SSD Mobilenet -# ------------- - - -def test_forward_coco_ssd_mobilenet_v1(): - """Test the FP32 Coco SSD Mobilenet V1 TF Lite model.""" - tflite_model_file = tf_testing.get_workload_official( - "https://raw.githubusercontent.com/dmlc/web-data/main/tensorflow/models/object_detection/" - "ssd_mobilenet_v1_coco_2018_01_28.tgz", - "ssd_mobilenet_v1_coco_2018_01_28.tflite", - ) - - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - - np.random.seed(0) - data = np.random.uniform(size=(1, 300, 300, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph( - tflite_model_buf, data, "normalized_input_image_tensor", num_output=4 - ) - - # Check all output shapes are equal - assert all( - list( - tvm_tensor.shape == tflite_tensor.shape - for (tvm_tensor, tflite_tensor) in zip(tvm_output, tflite_output) - ) - ) - - # Check valid count is the same - assert tvm_output[3] == tflite_output[3] - valid_count = tvm_output[3][0] - - # For boxes that do not have any detections, TFLite puts random values. Therefore, we compare - # tflite and tvm tensors for only valid boxes. - for i in range(0, valid_count): - # Check bounding box co-ords - tvm.testing.assert_allclose( - np.squeeze(tvm_output[0][0][i]), - np.squeeze(tflite_output[0][0][i]), - rtol=1e-5, - atol=1e-5, - ) - # Check the class - np.testing.assert_equal(np.squeeze(tvm_output[1][0][i]), np.squeeze(tflite_output[1][0][i])) - - # Check the score - tvm.testing.assert_allclose( - np.squeeze(tvm_output[2][0][i]), - np.squeeze(tflite_output[2][0][i]), - rtol=1e-5, - atol=1e-5, - ) - - -####################################################################### -# MediaPipe -# ------------- -def test_forward_mediapipe_hand_landmark(): - """Test MediaPipe 2D hand landmark TF Lite model.""" - # MediaPipe 2D hand landmark TF - tflite_model_file = download_testdata( - "https://github.com/google/mediapipe/raw/v0.7.4/mediapipe/models/hand_landmark.tflite", - "hand_landmark.tflite", - ) - with open(tflite_model_file, "rb") as f: - tflite_model_buf = f.read() - data = np.random.uniform(size=(1, 256, 256, 3)).astype("float32") - tflite_output = run_tflite_graph(tflite_model_buf, data) - tvm_output = run_tvm_graph(tflite_model_buf, data, "input_1", num_output=2) - for i in range(2): - tvm.testing.assert_allclose( - np.squeeze(tvm_output[i]), np.squeeze(tflite_output[i]), rtol=1e-5, atol=1e-5 - ) - - -####################################################################### -# Test check for Tensorflow "dynamic range quantization" optimization -# -------------- -def test_prevent_tensorflow_dynamic_range(): - """ - Should prevent running "dynamic range quantization" optimized TFLite graph - """ - data_array = np.random.randint(0, 2, (1, 1024, 1024)).astype(dtype=np.float32) - filter_array = np.random.randint(0, 2, (1024, 1024)).astype(dtype=np.float32) - data_in = tf.keras.layers.Input(shape=data_array.shape[1:]) - dense = tf.keras.layers.Dense(units=filter_array.shape[-1], use_bias=False)(data_in) - keras_model = tf.keras.models.Model(data_in, dense) - keras_model.layers[1].set_weights([filter_array]) - - converter = interpreter_wrapper.TFLiteConverter.from_keras_model(keras_model) - converter.optimizations = [tf.lite.Optimize.DEFAULT] - tflite_model = converter.convert() - with pytest.raises(tvm.error.OpNotImplemented): - _ = run_tvm_graph(tflite_model, data_array, data_in.name.replace(":0", "")) - - -def _test_nms_v5( - bx_shape, score_shape, iou_threshold, score_threshold, max_output_size, dtype="float32" -): - """One iteration of nms_v5 with given attributes""" - boxes = np.random.uniform(0, 10, size=bx_shape).astype(dtype) - scores = np.random.uniform(size=score_shape).astype(dtype) - - tf.reset_default_graph() - tf.compat.v1.disable_eager_execution() - in_data_1 = array_ops.placeholder(dtype, boxes.shape, name="in_data_1") - in_data_2 = array_ops.placeholder(dtype, scores.shape, name="in_data_2") - out = image_ops.non_max_suppression_with_scores( - boxes=in_data_1, - scores=in_data_2, - max_output_size=max_output_size, - iou_threshold=iou_threshold, - score_threshold=score_threshold, - name="nms", - ) - - compare_tflite_with_tvm( - [boxes, scores], - ["in_data_1:0", "in_data_2:0"], - [in_data_1, in_data_2], - [out[0], out[1]], - out_names=[out[0].name, out[1].name], - experimental_new_converter=True, - ) - - -def test_forward_nms_v5(): - """test nms_v5""" - _test_nms_v5((10000, 4), (10000,), 0.5, 0.4, 100) - _test_nms_v5((1000, 4), (1000,), 0.7, 0.3, 50) - - -####################################################################### -# Test structural_equal and span of a model -# -------------------------------------- -def test_structure_and_span(): - """Test Structure and span of frequently-used models""" - - def _verify(res_fptr, golden_fptr): - with tvm.testing.enable_span_filling(): - with_span = res_fptr() - with tvm.testing.disable_span_filling(): - without_span = res_fptr() - tvm.ir.assert_structural_equal(with_span, without_span) - _verify_structural_equal_with_span(with_span, golden_fptr()) - - def _tf_to_tflite( - input_tensors, output_tensors, init_global_variables=False, experimental_new_converter=False - ): - with tf.Session() as sess: - if init_global_variables: - sess.run(variables.global_variables_initializer()) - converter = tf.lite.TFLiteConverter.from_session(sess, input_tensors, output_tensors) - converter.experimental_new_converter = experimental_new_converter - - tflite_model_buffer = converter.convert() - - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buffer, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_buffer, 0) - except ImportError: - raise ImportError("The tflite package must be installed") - return tflite_model - - def _test_conv2d_bias_add_span(): - def _res(): - in_shape = (1, 5, 5, 1) - kernel_shpae = (2, 2, 1, 2) - kernel_in = np.ones(kernel_shpae) - - with tf.Graph().as_default(): - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - kernel = tf.constant(kernel_in, dtype=tf.float32, name="filter_weight") - tf_model = tf.nn.conv2d( - x, kernel, strides=[1, 1, 1, 1], padding="VALID", name="conv2d" - ) - tflite_model = _tf_to_tflite([x], [tf_model]) - - mod, _ = relay.frontend.from_tflite( - tflite_model, - shape_dict={"input": in_shape}, - dtype_dict={"input": "float32"}, - op_converter=relay.frontend.tflite.OperatorConverter, - ) - return mod["main"] - - def _golden(): - in_input = relay.var( - "input", relay.TensorType([1, 5, 5, 1]), span=_create_span("input") - ) - weight = relay.var( - "_param_1", relay.TensorType([2, 2, 1, 2]), span=_create_span("filter_weight") - ) - bias = relay.var("_param_2", relay.TensorType([2]), span=_create_span("conv2d_bias")) - conv2d = _set_span( - relay.nn.conv2d( - in_input, - weight, - channels=2, - kernel_size=[2, 2], - data_layout="NHWC", - kernel_layout="HWIO", - ), - "conv2d", - ) - bias_add = _set_span(relay.nn.bias_add(conv2d, bias, axis=3), "conv2d") - attrs = ir.make_node("DictAttrs", **{"output_tensor_names": ["conv2d"]}) - func = relay.Function([in_input, weight, bias], bias_add, attrs=attrs) - mod = ir.IRModule.from_expr(func) - return mod["main"] - - _verify(_res, _golden) - - def _test_fully_connected_bias_add_span(): - def _res(): - in_shape = (1, 10) - kernel_shpae = (10, 10) - kernel_in = np.ones(kernel_shpae) - - with tf.Graph().as_default(): - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - weight = tf.constant(kernel_in, dtype=tf.float32, name="filter_weight") - tf_model = math_ops.mat_mul(x, weight, name="dense") - tflite_model = _tf_to_tflite([x], [tf_model]) - - mod, _ = relay.frontend.from_tflite( - tflite_model, - shape_dict={"input": in_shape}, - dtype_dict={"input": "float32"}, - op_converter=relay.frontend.tflite.OperatorConverter, - ) - return mod["main"] - - def _golden(): - in_input = relay.var("input", relay.TensorType([1, 10]), span=_create_span("input")) - weight = relay.var( - "_param_1", relay.TensorType([10, 10]), span=_create_span("filter_weight/transpose") - ) - bias = relay.var("_param_2", relay.TensorType([10]), span=_create_span("dense_bias")) - reshape = _set_span(relay.reshape(in_input, [-1, 10]), "dense") - dense = _set_span(relay.nn.dense(reshape, weight, units=10), "dense") - bias_add = _set_span(relay.nn.bias_add(dense, bias), "dense") - attrs = ir.make_node("DictAttrs", **{"output_tensor_names": ["dense"]}) - func = relay.Function([in_input, weight, bias], bias_add, attrs=attrs) - mod = ir.IRModule.from_expr(func) - return mod["main"] - - _verify(_res, _golden) - - def _test_reshape_span(): - def _res(): - in_shape = (1, 10) - output_shape = (2, 5) - - with tf.Graph().as_default(): - x = array_ops.placeholder(shape=in_shape, dtype="float32", name="input") - tf_model = array_ops.reshape(x, output_shape, "reshape") - tflite_model = _tf_to_tflite([x], [tf_model]) - - mod, _ = relay.frontend.from_tflite( - tflite_model, - shape_dict={"input": in_shape}, - dtype_dict={"input": "float32"}, - op_converter=relay.frontend.tflite.OperatorConverter, - ) - return mod["main"] - - def _golden(): - in_input = relay.var("input", relay.TensorType([1, 10]), span=_create_span("input")) - reshape = _set_span(relay.reshape(in_input, [2, 5]), "reshape") - attrs = ir.make_node("DictAttrs", **{"output_tensor_names": ["reshape"]}) - func = relay.Function([in_input], reshape, attrs=attrs) - mod = ir.IRModule.from_expr(func) - return mod["main"] - - _verify(_res, _golden) - - _test_conv2d_bias_add_span() - _test_fully_connected_bias_add_span() - _test_reshape_span() - - -class TestConv2d: - """Import Conv2d operator from TFLite, build with Relay and test.""" - - input_shape, kernel_shape, padding = tvm.testing.parameters( - ((1, 128, 256, 6), (5, 5, 6, 10), "SAME"), - ((1, 128, 256, 6), (5, 5, 6, 10), "VALID"), - # conv2d_group cases - ((1, 30, 40, 6), (5, 5, 1, 6), "SAME"), - ((1, 30, 40, 6), (5, 5, 1, 6), "VALID"), - ) - - def test_conv2d(self, input_shape: tuple, kernel_shape: tuple, padding: str): - dtype = tf.float32 - kernel_in = np.ones(kernel_shape) - with tf.Graph().as_default(): - x = array_ops.placeholder(shape=input_shape, dtype=dtype.name, name="input") - kernel = tf.constant(kernel_in, dtype=dtype, name="filter_weight") - out = tf.nn.conv2d(x, kernel, strides=[1, 1, 1, 1], padding=padding, name="conv2d") - input_data = np.random.randn(*input_shape).astype(dtype.name) - compare_tflite_with_tvm( - [input_data], - ["input"], - [x], - [out], - ) - - -if __name__ == "__main__": - tvm.testing.main() diff --git a/tests/scripts/task_python_frontend.sh b/tests/scripts/task_python_frontend.sh index 593e8f50c1d0..22d9d9ee22db 100755 --- a/tests/scripts/task_python_frontend.sh +++ b/tests/scripts/task_python_frontend.sh @@ -25,33 +25,4 @@ export OMP_NUM_THREADS=1 export TVM_TEST_TARGETS="llvm;cuda" -find . -type f -path "*.pyc" | xargs rm -f - -# Rebuild cython -make cython3 - - -echo "Running relay ONNX frontend test..." -run_pytest cython python-frontend-onnx tests/python/frontend/onnx - -echo "Running relay PyTorch frontend test..." -run_pytest cython python-frontend-pytorch tests/python/frontend/pytorch - -echo "Running relay Tensorflow frontend test..." -# Note: Tensorflow tests often have memory issues, so invoke each one separately -TENSORFLOW_TESTS=$(./ci/scripts/jenkins/pytest_ids.py --folder tests/python/frontend/tensorflow) -i=0 -for node_id in $TENSORFLOW_TESTS; do - echo "$node_id" - run_pytest cython "python-frontend-tensorflow-$i" "$node_id" - i=$((i+1)) -done - -echo "Running relay DarkNet frontend test..." -run_pytest cython python-frontend-darknet tests/python/frontend/darknet - -echo "Running relay PaddlePaddle frontend test..." -run_pytest cython python-frontend-paddlepaddle tests/python/frontend/paddlepaddle - -echo "Running relay CoreML frontend test..." -run_pytest cython python-frontend-coreml tests/python/frontend/coreml +# TODO(Siyuan): Keep this file for passing CI diff --git a/tests/scripts/task_python_frontend_cpu.sh b/tests/scripts/task_python_frontend_cpu.sh index aac554bea53a..73f21c3c924b 100755 --- a/tests/scripts/task_python_frontend_cpu.sh +++ b/tests/scripts/task_python_frontend_cpu.sh @@ -26,13 +26,4 @@ export OMP_NUM_THREADS=1 export TVM_TEST_TARGETS="llvm" -find . -type f -path "*.pyc" | xargs rm -f - -# Rebuild cython -make cython3 - -echo "Running relay TFLite frontend test..." -run_pytest cython python-frontend-tflite tests/python/frontend/tflite - -echo "Running relay Keras frontend test..." -run_pytest cython python-frontend-keras tests/python/frontend/keras +# TODO(Siyuan): Keep this file for passing CI diff --git a/tests/scripts/task_python_unittest.sh b/tests/scripts/task_python_unittest.sh index 5b07b5256ea5..4a13c6ce1ed2 100755 --- a/tests/scripts/task_python_unittest.sh +++ b/tests/scripts/task_python_unittest.sh @@ -55,7 +55,6 @@ TEST_FILES=( ) for TEST_FILE in ${TEST_FILES[@]}; do - run_pytest ctypes ${TEST_FILE}-0, tests/python/${TEST_FILE} run_pytest cython ${TEST_FILE}-1, tests/python/${TEST_FILE} done diff --git a/tests/scripts/task_python_unittest_gpuonly.sh b/tests/scripts/task_python_unittest_gpuonly.sh index b478bbdc773d..e68fcba25c91 100755 --- a/tests/scripts/task_python_unittest_gpuonly.sh +++ b/tests/scripts/task_python_unittest_gpuonly.sh @@ -33,5 +33,4 @@ export TVM_UNITTEST_TESTSUITE_NAME=python-codegen-vulkan source tests/scripts/setup-pytest-env.sh -run_pytest ctypes ${TVM_UNITTEST_TESTSUITE_NAME}-0 tests/python/codegen/test_target_codegen_vulkan.py run_pytest cython ${TVM_UNITTEST_TESTSUITE_NAME}-1 tests/python/codegen/test_target_codegen_vulkan.py