From b3adc0b792cd413fa5c30da951dd6f13a77fda0a Mon Sep 17 00:00:00 2001 From: Nicola Lancellotti Date: Tue, 30 Aug 2022 09:53:42 +0000 Subject: [PATCH] [ETHOSN] Fix tests pylint errors --- tests/lint/pylint.sh | 1 + .../contrib/test_ethosn/infrastructure.py | 50 +++++++++++-------- .../contrib/test_ethosn/test_concatenate.py | 10 +++- .../test_ethosn/test_constant_duplication.py | 10 ++-- .../python/contrib/test_ethosn/test_conv2d.py | 18 ++++--- .../test_ethosn/test_depth_to_space.py | 4 ++ .../test_ethosn/test_fullyconnected.py | 25 +++++----- .../contrib/test_ethosn/test_leaky_relu.py | 2 + tests/python/contrib/test_ethosn/test_mean.py | 2 + .../contrib/test_ethosn/test_multiply.py | 3 ++ .../contrib/test_ethosn/test_networks.py | 13 +++-- .../test_ethosn/test_partition_params.py | 24 ++++++--- .../contrib/test_ethosn/test_pooling.py | 8 ++- tests/python/contrib/test_ethosn/test_relu.py | 4 ++ .../contrib/test_ethosn/test_requantize.py | 5 ++ .../python/contrib/test_ethosn/test_resize.py | 4 ++ .../contrib/test_ethosn/test_sigmoid.py | 11 ++-- .../python/contrib/test_ethosn/test_split.py | 9 +++- tests/python/contrib/test_ethosn/test_tanh.py | 4 ++ .../contrib/test_ethosn/test_topologies.py | 33 +++++++----- 20 files changed, 158 insertions(+), 82 deletions(-) diff --git a/tests/lint/pylint.sh b/tests/lint/pylint.sh index 2228e110c15e..94fae289b6b9 100755 --- a/tests/lint/pylint.sh +++ b/tests/lint/pylint.sh @@ -21,6 +21,7 @@ python3 -m pylint python/tvm --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint vta/python/vta --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/unittest/test_tvmscript_type.py --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/contrib/test_cmsisnn --rcfile="$(dirname "$0")"/pylintrc +python3 -m pylint tests/python/contrib/test_ethosn --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/relay/aot/*.py --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/ci --rcfile="$(dirname "$0")"/pylintrc python3 -m pylint tests/python/integration/ --rcfile="$(dirname "$0")"/pylintrc diff --git a/tests/python/contrib/test_ethosn/infrastructure.py b/tests/python/contrib/test_ethosn/infrastructure.py index a1c8ca0a32d2..0071b1a7f52e 100644 --- a/tests/python/contrib/test_ethosn/infrastructure.py +++ b/tests/python/contrib/test_ethosn/infrastructure.py @@ -18,17 +18,17 @@ """Arm(R) Ethos(TM)-N test functions""" from __future__ import absolute_import, print_function -import tvm -from tvm import relay -from tvm.contrib import utils, graph_executor, download from hashlib import md5 from itertools import zip_longest, combinations +import os import numpy as np from PIL import Image -import os -from . import _infrastructure +import tvm +from tvm import relay +from tvm.contrib import utils, graph_executor, download from tvm.relay.op.contrib import partition_for_ethosn +from . import _infrastructure def get_real_image(im_height, im_width): @@ -82,23 +82,25 @@ def make_module(func, params): def make_ethosn_composite(ethosn_expr, name): - vars = relay.analysis.free_vars(ethosn_expr) - inner_vars = [relay.Var(v.name_hint, v.type_annotation) for v in vars] + variables = relay.analysis.free_vars(ethosn_expr) + inner_vars = [relay.Var(v.name_hint, v.type_annotation) for v in variables] func = relay.Function(inner_vars, ethosn_expr) func = func.with_attr("Composite", name) - call = relay.Call(func, vars) + call = relay.Call(func, variables) return call def make_ethosn_partition(ethosn_expr): + """Make an Ethos(TM)-N partition.""" + # Create an Ethos-N global function mod = tvm.IRModule({}) - vars = relay.analysis.free_vars(ethosn_expr) + variables = relay.analysis.free_vars(ethosn_expr) # NB: it is illegal to reuse variables inside and outside a scope in Relay # if you want to duplicate types and names you must re-allocate them. - fresh_vars = [relay.Var(v.name_hint, v.type_annotation) for v in vars] + fresh_vars = [relay.Var(v.name_hint, v.type_annotation) for v in variables] binds = {} - for var, fresh_var in zip(vars, fresh_vars): + for var, fresh_var in zip(variables, fresh_vars): binds[var] = fresh_var ethosn_expr_fresh = relay.bind(ethosn_expr, binds) func = relay.Function(fresh_vars, ethosn_expr_fresh) @@ -106,19 +108,21 @@ def make_ethosn_partition(ethosn_expr): func = func.with_attr("Inline", tvm.tir.IntImm("int32", 1)) func = func.with_attr("Compiler", "ethos-n") func = func.with_attr("global_symbol", "ethos-n_0") - g1 = relay.GlobalVar("ethos-n_0") - mod[g1] = func + global_var = relay.GlobalVar("ethos-n_0") + mod[global_var] = func mod = relay.transform.InferType()(mod) # These are the vars to call the Ethos-N partition with more_vars = relay.analysis.free_vars(ethosn_expr) # Call the Ethos-N partition in main - call_fn1 = g1(*more_vars) + call_fn1 = global_var(*more_vars) mod["main"] = relay.Function(more_vars, call_fn1) return relay.transform.InferType()(mod) def get_host_op_count(mod): + """Return the number of host operators.""" + class Counter(tvm.relay.ExprVisitor): def __init__(self): super().__init__() @@ -219,9 +223,7 @@ def run(lib, inputs, outputs, npu=True): return out -def build_and_run( - mod, inputs, outputs, params, device=tvm.cpu(), npu=True, expected_host_ops=0, npu_partitions=1 -): +def build_and_run(mod, inputs, outputs, params, npu=True, expected_host_ops=0, npu_partitions=1): lib = build(mod, params, npu, expected_host_ops, npu_partitions) return run(lib, inputs, outputs, npu) @@ -254,6 +256,8 @@ def inference_result(outputs): def test_error(mod, params, err_msg): + """Test an operator error message.""" + caught = None with tvm.transform.PassContext( opt_level=3, config={"relay.ext.ethos-n.options": {"variant": get_ethosn_variant()}} @@ -262,8 +266,8 @@ def test_error(mod, params, err_msg): try: mod = relay.transform.InferType()(mod) relay.build(mod, params=params) - except tvm.error.TVMError as e: - caught = e.args[0] + except tvm.error.TVMError as error: + caught = error.args[0] finally: relay.backend.te_compiler.get().clear() @@ -275,8 +279,8 @@ def get_conv2d(var, shape, dtype): """Standard convolution to test activation functions""" weight_shape = (1, 1, shape[3], 1) - w = tvm.nd.array(np.ones(weight_shape, dtype)) - weights = relay.const(w, dtype) + weights_array = tvm.nd.array(np.ones(weight_shape, dtype)) + weights = relay.const(weights_array, dtype) conv = relay.qnn.op.conv2d( var, weights, @@ -300,13 +304,15 @@ def get_conv2d(var, shape, dtype): relay.const(0, "int32"), # output zero point out_dtype=dtype, ) - params = {"w": w, "b": b} + params = {"w": weights_array, "b": b} return req, params def get_conv2d_qnn_params( dtype, input_zp, input_sc, kernel_zp, kernel_sc, kernel_h, kernel_w, channels ): + """Return Conv2D QNN params.""" + kernel_sc = ( kernel_sc.numpy() if isinstance(kernel_sc, tvm.runtime.ndarray.NDArray) else [kernel_sc] ) diff --git a/tests/python/contrib/test_ethosn/test_concatenate.py b/tests/python/contrib/test_ethosn/test_concatenate.py index b2eba6d650e0..cd4ec7a4e4b2 100644 --- a/tests/python/contrib/test_ethosn/test_concatenate.py +++ b/tests/python/contrib/test_ethosn/test_concatenate.py @@ -57,6 +57,8 @@ def _get_model(shapes, dtype, axis): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_concatenate(dtype): + """Compare Concatenate output with TVM.""" + trials = [ ([(1, 4), (1, 6)], 1), ([(1, 16, 4), (1, 16, 4)], 1), @@ -78,19 +80,23 @@ def test_concatenate(dtype): @requires_ethosn def test_concatenate_failure(): + """Check Concatenate error messages.""" + trials = [ ([(1, 4, 4, 4, 4), (1, 4, 4, 4, 4)], "uint8", 1, "dimensions=5, dimensions must be <= 4;"), ( [(1, 4, 4, 4), (1, 4, 4, 4)], "uint8", 3, - "Concatenation along the channels dimension (axis 3) requires input tensors with a multiple of 16 channels;", + "Concatenation along the channels dimension (axis 3) " + "requires input tensors with a multiple of 16 channels;", ), ( [(1, 4, 4, 4), (1, 4, 4, 4)], "int16", 2, - "dtype='int16', dtype must be either uint8, int8 or int32; dtype='int16', dtype must be either uint8, int8 or int32;", + "dtype='int16', dtype must be either uint8, int8 or int32; dtype='int16', " + "dtype must be either uint8, int8 or int32;", ), ( [(2, 4, 4, 4), (2, 4, 4, 4)], diff --git a/tests/python/contrib/test_ethosn/test_constant_duplication.py b/tests/python/contrib/test_ethosn/test_constant_duplication.py index 84956840ecbb..b3cd0046f508 100644 --- a/tests/python/contrib/test_ethosn/test_constant_duplication.py +++ b/tests/python/contrib/test_ethosn/test_constant_duplication.py @@ -36,8 +36,10 @@ def _get_model(): add_const = relay.const(add_const_value, "uint8") a = relay.add(a, add_const) weight_shape = (kernel_h, kernel_w, shape[3], out_channels) - w = tvm.nd.array(np.random.randint(low=0, high=255, size=weight_shape, dtype="uint8")) - weights = relay.const(w, "uint8") + weights_array = tvm.nd.array( + np.random.randint(low=0, high=255, size=weight_shape, dtype="uint8") + ) + weights = relay.const(weights_array, "uint8") conv = relay.qnn.op.conv2d( a, weights, @@ -66,12 +68,14 @@ def _get_model(): relay.const(0, "int32"), # output zero point out_dtype="uint8", ) - params = {"w": w, "b": b} + params = {"w": weights_array, "b": b} return req, params @requires_ethosn def test_constant_duplication(): + """Test that constants are not duplicated.""" + np.random.seed(0) model, params = _get_model() mod = tei.make_module(model, params) diff --git a/tests/python/contrib/test_ethosn/test_conv2d.py b/tests/python/contrib/test_ethosn/test_conv2d.py index a411701ea0bc..ffe66f0d2be2 100644 --- a/tests/python/contrib/test_ethosn/test_conv2d.py +++ b/tests/python/contrib/test_ethosn/test_conv2d.py @@ -17,9 +17,9 @@ """Arm(R) Ethos(TM)-N integration conv2d tests""" +import math import numpy as np import pytest -import math import tvm from tvm import relay from tvm.testing import requires_ethosn @@ -61,7 +61,7 @@ def _get_model( ): """Return a model and any parameters it may have""" a = relay.var("a", shape=shape, dtype=dtype) - if pad == "op" or pad == "both": + if pad in ("op", "both"): p = _get_same_padding((shape[1], shape[2]), (kernel_h, kernel_w), dilation, strides) a = relay.nn.pad( a, @@ -76,12 +76,12 @@ def _get_model( weight_shape = (kernel_h, kernel_w, shape[3] // groups, out_channels) else: weight_shape = (kernel_h, kernel_w, out_channels, 1) - w = tvm.nd.array( + weights_array = tvm.nd.array( np.random.randint( np.iinfo(dtype).min, high=np.iinfo(dtype).max + 1, size=weight_shape, dtype=dtype ) ) - weights = relay.const(w, dtype) + weights = relay.const(weights_array, dtype) conv = relay.qnn.op.conv2d( a, weights, @@ -96,7 +96,7 @@ def _get_model( strides=strides, groups=groups, channels=out_channels, - padding=p if pad == "attr" or pad == "both" else (0, 0, 0, 0), + padding=p if pad in ("attr", "both") else (0, 0, 0, 0), out_dtype="int32", ) b = tvm.nd.array( @@ -118,7 +118,7 @@ def _get_model( relay.const(output_zp, "int32"), # output zero point out_dtype=dtype, ) - params = {"w": w, "b": b} + params = {"w": weights_array, "b": b} return req, params @@ -126,6 +126,8 @@ def _get_model( @pytest.mark.parametrize("depthwise", [False, True]) @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_conv2d(dtype, depthwise): + """Compare Conv2D output with TVM.""" + trials = [ [(1, 17, 20, 26), 4, 3, 1, "attr", (2, 2), (1, 1), False], [(1, 30, 27, 30), 5, 5, 3, "none", (1, 1), (1, 1), False], @@ -208,6 +210,8 @@ def test_conv2d(dtype, depthwise): @requires_ethosn def test_conv2d_failure(): + """Check Conv2D error messages.""" + trials = [ ( (1, 4, 4, 4), @@ -326,7 +330,7 @@ def test_conv2d_failure(): weight_format, err_msg, ) in trials: - model, params = _get_model( + model, _ = _get_model( shape, kernel_h, kernel_w, diff --git a/tests/python/contrib/test_ethosn/test_depth_to_space.py b/tests/python/contrib/test_ethosn/test_depth_to_space.py index 1675b82eeace..c071fe00f212 100644 --- a/tests/python/contrib/test_ethosn/test_depth_to_space.py +++ b/tests/python/contrib/test_ethosn/test_depth_to_space.py @@ -34,6 +34,8 @@ def _get_model(shape, block, dtype, layout): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_depth_to_space(dtype): + """Compare Depth To Space output with TVM.""" + trials = [ (1, 16, 16, 16), (1, 64, 32, 16), @@ -59,6 +61,8 @@ def test_depth_to_space(dtype): @requires_ethosn def test_depth_to_space_failure(): + """Check Depth To Space error messages.""" + trials = [ ((2, 16, 16, 16), 2, "uint8", "NHWC", "batch size=2, batch size must = 1"), ( diff --git a/tests/python/contrib/test_ethosn/test_fullyconnected.py b/tests/python/contrib/test_ethosn/test_fullyconnected.py index 2caca9e890a2..d5510bb79d2c 100644 --- a/tests/python/contrib/test_ethosn/test_fullyconnected.py +++ b/tests/python/contrib/test_ethosn/test_fullyconnected.py @@ -30,9 +30,9 @@ def _get_model( ): """Return a model an any parameters it may have""" a = relay.var("a", shape=shape, dtype=dtype) - w = tvm.nd.array(np.ones(weight_shape, dtype)) - weights = relay.const(w, dtype) - fc = relay.qnn.op.dense( + weights_array = tvm.nd.array(np.ones(weight_shape, dtype)) + weights = relay.const(weights_array, dtype) + dense = relay.qnn.op.dense( a, weights, input_zero_point=relay.const(input_zp, "int32"), @@ -44,7 +44,7 @@ def _get_model( ) b = tvm.nd.array(np.random.randint(0, high=255, size=(weight_shape[0],), dtype="int32")) biasc = relay.const(b, "int32") - bias = relay.nn.bias_add(fc, biasc) + bias = relay.nn.bias_add(dense, biasc) req = relay.qnn.op.requantize( bias, relay.const(input_sc * kernel_sc, "float32"), # input zero scale @@ -53,7 +53,7 @@ def _get_model( relay.const(output_zp, "int32"), # output zero point out_dtype=dtype, ) - params = {"w": w, "b": b} + params = {"w": weights_array, "b": b} return req, params @@ -76,9 +76,8 @@ def _get_model( ], ) def test_fullyconnected(shape, out_channels, dtype, input_zp, input_sc, kernel_zp, kernel_sc): - """ - Test fully connected offloading. - """ + """Compare Fully Connected output with TVM.""" + np.random.seed(0) inputs = { "a": tvm.nd.array( @@ -116,6 +115,8 @@ def test_fullyconnected(shape, out_channels, dtype, input_zp, input_sc, kernel_z @requires_ethosn def test_fullyconnected_failure(): + """Check Fully Connected error messages.""" + trials = [ ( (1, 64), @@ -139,7 +140,8 @@ def test_fullyconnected_failure(): 0, 1, "uint8", - "Weights tensor must have I dimension equal to the number of channels of the input tensor.;", + "Weights tensor must have I dimension equal to the number" + " of channels of the input tensor.;", ), ((1024, 64), (1, 64), 0, 1, 0, 1, 0, 1, "uint8", "batch size=1024, batch size must = 1;"), ] @@ -157,10 +159,7 @@ def test_fullyconnected_failure(): dtype, err_msg, ) in trials: - inputs = { - "a": tvm.nd.array(np.random.randint(0, high=255, size=shape, dtype=dtype)), - } - model, params = _get_model( + model, _ = _get_model( shape, weight_shape, input_zp, diff --git a/tests/python/contrib/test_ethosn/test_leaky_relu.py b/tests/python/contrib/test_ethosn/test_leaky_relu.py index cdd06f5e73e4..3c3bbc709679 100644 --- a/tests/python/contrib/test_ethosn/test_leaky_relu.py +++ b/tests/python/contrib/test_ethosn/test_leaky_relu.py @@ -49,6 +49,7 @@ def _get_model(shape, input_zp, input_sc, output_zp, output_sc, dtype, alpha): @pytest.mark.parametrize("alpha", [0.001, 0.5678]) def test_leaky_relu(dtype, shape, alpha): """Compare Leaky ReLU output with TVM.""" + np.random.seed(0) iinfo = np.iinfo(dtype) @@ -75,6 +76,7 @@ def test_leaky_relu(dtype, shape, alpha): @pytest.mark.parametrize("alpha", [-1.34, 2.32, 1, 0]) def test_leaky_relu_unsupported_alpha(dtype, shape, alpha): """Test unsupported values of alpha (<= 0, >= 1) in Leaky ReLU.""" + iinfo = np.iinfo(dtype) zp_min = iinfo.min diff --git a/tests/python/contrib/test_ethosn/test_mean.py b/tests/python/contrib/test_ethosn/test_mean.py index 548743fe9548..0ad7e17faed8 100644 --- a/tests/python/contrib/test_ethosn/test_mean.py +++ b/tests/python/contrib/test_ethosn/test_mean.py @@ -45,6 +45,7 @@ def _get_model(shape, axis, keepdims, input_zp, input_sc, output_zp, output_sc, @pytest.mark.parametrize("shape", [(1, 7, 7, 2048), (1, 8, 8)]) def test_mean(dtype, shape): """Compare Mean output with TVM.""" + np.random.seed(0) zp_min = np.iinfo(dtype).min @@ -68,6 +69,7 @@ def test_mean(dtype, shape): @pytest.mark.parametrize("dtype", ["int8", "uint8"]) def test_mean_non_equal_quantization(dtype): """Test mean is not offloaded when quantization is not equal.""" + np.random.seed(0) shape = (1, 7, 7, 2048) diff --git a/tests/python/contrib/test_ethosn/test_multiply.py b/tests/python/contrib/test_ethosn/test_multiply.py index 38d8516b6721..cb95a97db529 100644 --- a/tests/python/contrib/test_ethosn/test_multiply.py +++ b/tests/python/contrib/test_ethosn/test_multiply.py @@ -69,6 +69,7 @@ def _get_model( @pytest.mark.parametrize("reverse_inputs", [False, True]) def test_multiply(dtype, shape, constant_shape, reverse_inputs): """Compare Multiply output with TVM.""" + np.random.seed(0) iinfo = np.iinfo(dtype) @@ -106,6 +107,7 @@ def test_multiply(dtype, shape, constant_shape, reverse_inputs): @requires_ethosn def test_multiply_multiple_inputs_unsupported(): """Check multiply operator with two inputs is not offloaded.""" + np.random.seed(0) shape = (1, 4, 5, 6) @@ -151,6 +153,7 @@ def test_multiply_multiple_inputs_unsupported(): @requires_ethosn def test_multiply_unsupported_datatype(): """Check multiply operator with unsupported datatype is not offloaded.""" + np.random.seed(0) shape = (1, 4, 5, 6) diff --git a/tests/python/contrib/test_ethosn/test_networks.py b/tests/python/contrib/test_ethosn/test_networks.py index 11745409d4ea..db1b41244846 100644 --- a/tests/python/contrib/test_ethosn/test_networks.py +++ b/tests/python/contrib/test_ethosn/test_networks.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - +# pylint: disable=wrong-import-position """Arm(R) Ethos(TM)-N integration end-to-end network tests""" import pytest @@ -22,12 +22,11 @@ pytest.importorskip("tflite") pytest.importorskip("tensorflow") +import tflite.Model from tvm import relay from tvm.testing import requires_ethosn from tvm.contrib import download - import tvm.relay.testing.tf as tf_testing -import tflite.Model from . import infrastructure as tei @@ -41,10 +40,10 @@ def _get_tflite_model(tflite_model_path, inputs_dict, dtype): tflite_model = tflite.Model.GetRootAsModel(tflite_model_buffer, 0) shape_dict = {} dtype_dict = {} - for input in inputs_dict: - input_shape = inputs_dict[input] - shape_dict[input] = input_shape - dtype_dict[input] = dtype + for value in inputs_dict: + input_shape = inputs_dict[value] + shape_dict[value] = input_shape + dtype_dict[value] = dtype return relay.frontend.from_tflite( tflite_model, diff --git a/tests/python/contrib/test_ethosn/test_partition_params.py b/tests/python/contrib/test_ethosn/test_partition_params.py index 34e22e6aaba8..e8ac687c04b0 100644 --- a/tests/python/contrib/test_ethosn/test_partition_params.py +++ b/tests/python/contrib/test_ethosn/test_partition_params.py @@ -18,19 +18,23 @@ """Arm(R) Ethos(TM)-N partition parameter tests""" import pytest -import tvm -from tvm import relay import numpy as np +import tvm +from tvm import relay from tvm.relay.op.contrib.ethosn import partition_for_ethosn from tvm.testing import requires_ethosn @requires_ethosn def test_ethosn78_partition_no_error(): + """Test Arm(R) Ethos(TM)-N78 partition""" + a = relay.var("a", shape=[2, 7, 8, 8], dtype="uint8") - w = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) - res = relay.nn.conv2d(a, w, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8") + weights = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) + res = relay.nn.conv2d( + a, weights, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8" + ) b = relay.var("b", shape=[8], dtype="uint8") res = relay.nn.bias_add(res, b, axis=1) @@ -41,13 +45,15 @@ def test_ethosn78_partition_no_error(): @requires_ethosn def test_ethosn78_partition_undefined_variant(): + """Test Arm(R) Ethos(TM)-N78 partition with undefined variant""" + with pytest.raises( ValueError, match=r".*Please specify a variant in the target string, e.g. -variant=n78.*" ): a = relay.var("a", shape=[2, 7, 8, 8], dtype="uint8") - w = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) + weights = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) res = relay.nn.conv2d( - a, w, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8" + a, weights, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8" ) b = relay.var("b", shape=[8], dtype="uint8") res = relay.nn.bias_add(res, b, axis=1) @@ -58,13 +64,15 @@ def test_ethosn78_partition_undefined_variant(): @requires_ethosn def test_ethosn78_partition_invalid_variant(): + """Test Arm(R) Ethos(TM)-N78 partition with invalid variant""" + with pytest.raises( ValueError, match=r".*When targeting Ethos\(TM\)-N78, -variant=n78 should be set.*" ): a = relay.var("a", shape=[2, 7, 8, 8], dtype="uint8") - w = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) + wwights = relay.const(np.random.uniform(-10, 10, (8, 7, 3, 3)).astype("uint8")) res = relay.nn.conv2d( - a, w, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8" + a, wwights, kernel_size=(3, 3), padding=(1, 1), channels=8, out_dtype="uint8" ) b = relay.var("b", shape=[8], dtype="uint8") res = relay.nn.bias_add(res, b, axis=1) diff --git a/tests/python/contrib/test_ethosn/test_pooling.py b/tests/python/contrib/test_ethosn/test_pooling.py index 3defaa55e853..e1c7358f71a1 100644 --- a/tests/python/contrib/test_ethosn/test_pooling.py +++ b/tests/python/contrib/test_ethosn/test_pooling.py @@ -28,10 +28,10 @@ def _get_model(shape, typef, sizes, strides, pads, layout, dtype): """Return a model and any parameters it may have""" req = relay.var("a", shape=shape, dtype=dtype) - if typef == relay.nn.avg_pool2d: + if typef is relay.nn.avg_pool2d: req = relay.cast(req, "int32") req = typef(req, pool_size=sizes, strides=strides, padding=pads, ceil_mode=True, layout=layout) - if typef == relay.nn.avg_pool2d: + if typef is relay.nn.avg_pool2d: req = relay.cast(req, dtype) return req @@ -39,6 +39,8 @@ def _get_model(shape, typef, sizes, strides, pads, layout, dtype): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_pooling(dtype): + """Compare Pooling output with TVM.""" + trials = [ ((1, 8, 8, 8), relay.nn.max_pool2d, (2, 2), (2, 2), (0, 0, 0, 0), "NHWC"), ((1, 9, 9, 9), relay.nn.max_pool2d, (3, 3), (2, 2), (0, 0, 0, 0), "NHWC"), @@ -65,6 +67,8 @@ def test_pooling(dtype): @requires_ethosn def test_pooling_failure(): + """Check Pooling error messages.""" + trials = [ ( (2, 8, 8, 8), diff --git a/tests/python/contrib/test_ethosn/test_relu.py b/tests/python/contrib/test_ethosn/test_relu.py index 5d3e8f1e9921..f56a1cd7ad3c 100644 --- a/tests/python/contrib/test_ethosn/test_relu.py +++ b/tests/python/contrib/test_ethosn/test_relu.py @@ -35,6 +35,8 @@ def _get_model(shape, dtype, a_min, a_max): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_relu(dtype): + """Compare Relu output with TVM.""" + trials = [ ((1, 4, 4, 4), 65, 178, "uint8"), ((1, 8, 4, 2), 1, 254, "uint8"), @@ -68,6 +70,8 @@ def test_relu(dtype): @requires_ethosn def test_relu_failure(): + """Check Relu error messages.""" + trials = [ ((1, 4, 4, 4, 4), "uint8", 65, 78, "dimensions=5, dimensions must be <= 4"), ((1, 8, 4, 2), "int16", 1, 254, "dtype='int16', dtype must be either uint8, int8 or int32"), diff --git a/tests/python/contrib/test_ethosn/test_requantize.py b/tests/python/contrib/test_ethosn/test_requantize.py index e20c3beeabfa..3187c22f3391 100644 --- a/tests/python/contrib/test_ethosn/test_requantize.py +++ b/tests/python/contrib/test_ethosn/test_requantize.py @@ -43,6 +43,8 @@ def _get_model(shape, input_zp, input_sc, output_zp, output_sc, in_dtype, out_dt @pytest.mark.parametrize("out_dtype", ["int8", "uint8"]) @pytest.mark.parametrize("shape", [(1, 52, 52, 3)]) def test_requantize(in_dtype, out_dtype, shape): + """Compare Requantize output with TVM.""" + np.random.seed(0) low = 0 if in_dtype == "uint8" else -5 high = low + 10 @@ -74,6 +76,7 @@ def test_requantize_mixed_precision_with_following_op(): Checks a requantize operation that changes precision from uint8 to int8 with a following add op. """ + np.random.seed(0) shape = (1, 4, 6, 8) in_sc = 0.012566 @@ -133,6 +136,8 @@ def get_model(): @requires_ethosn def test_requantize_failure(): + """Check Requantize error messages.""" + input_sc = 0.8 output_sc = (input_sc / 128) - 0.0001 model = _get_model( diff --git a/tests/python/contrib/test_ethosn/test_resize.py b/tests/python/contrib/test_ethosn/test_resize.py index b9d807d21926..2cc641e63b5c 100644 --- a/tests/python/contrib/test_ethosn/test_resize.py +++ b/tests/python/contrib/test_ethosn/test_resize.py @@ -68,6 +68,8 @@ def _get_model( ], ) def test_resize(dtype, shape, size, coordinate_transformation_mode, rounding_method): + """Compare Resize output with TVM.""" + np.random.seed(0) zp_min = np.iinfo(dtype).min zp_max = np.iinfo(dtype).max @@ -96,6 +98,8 @@ def test_resize(dtype, shape, size, coordinate_transformation_mode, rounding_met @requires_ethosn def test_resize_failure(): + """Check Resize error messages.""" + trials = [ ( (30, 20), diff --git a/tests/python/contrib/test_ethosn/test_sigmoid.py b/tests/python/contrib/test_ethosn/test_sigmoid.py index 9947bee3b86b..ae8c301ff01a 100644 --- a/tests/python/contrib/test_ethosn/test_sigmoid.py +++ b/tests/python/contrib/test_ethosn/test_sigmoid.py @@ -45,6 +45,8 @@ def _get_model(shape, input_zp, input_sc, output_zp, output_sc, dtype): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_sigmoid(dtype): + """Compare Sigmoid output with TVM.""" + trials = [ (1, 16, 16, 16), (1, 8, 8), @@ -61,7 +63,7 @@ def test_sigmoid(dtype): } outputs = [] for npu in [False, True]: - for d in range(1, 2): + for _ in range(1, 2): if dtype == "uint8": input_zp = 0 output_zp = 0 @@ -78,21 +80,22 @@ def test_sigmoid(dtype): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_sigmoid_failure(dtype): + """Check Sigmoid error messages.""" + test_zp = 0 if dtype == "uint8" else -128 trials = [ - ((2, 4, 4, 4), 64, 0.2, test_zp, 1 / 256, dtype, "batch size=2, batch size must = 1"), + ((2, 4, 4, 4), 64, 0.2, test_zp, 1 / 256, "batch size=2, batch size must = 1"), ( (1, 4, 4, 4), 64, 0.2, 3, 1, - dtype, f"output quantization params=(3, 1), must = ({test_zp}, 1/256)", ), ] - for shape, input_zp, input_sc, output_zp, output_sc, dtype, err_msg in trials: + for shape, input_zp, input_sc, output_zp, output_sc, err_msg in trials: model = _get_model(shape, input_zp, input_sc, output_zp, output_sc, dtype) model = tei.make_ethosn_composite(model, "ethos-n.qnn_sigmoid") mod = tei.make_ethosn_partition(model) diff --git a/tests/python/contrib/test_ethosn/test_split.py b/tests/python/contrib/test_ethosn/test_split.py index 4d1743d07a32..7f8787afe947 100644 --- a/tests/python/contrib/test_ethosn/test_split.py +++ b/tests/python/contrib/test_ethosn/test_split.py @@ -37,6 +37,8 @@ def _get_model(shape, dtype, splits, axis): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_split(dtype): + """Compare Split output with TVM.""" + trials = [ ((1, 16, 16, 32), (2, 7, 10), 2), ((1, 12, 8, 16), 3, 1), @@ -55,7 +57,7 @@ def test_split(dtype): for npu in [False, True]: model = _get_model(shape, dtype, splits, axis) mod = tei.make_module(model, {}) - output_count = splits if type(splits) == int else len(splits) + 1 + output_count = splits if isinstance(splits, int) else len(splits) + 1 outputs.append(tei.build_and_run(mod, inputs, output_count, {}, npu=npu)) tei.verify(outputs, dtype, 0) @@ -64,6 +66,8 @@ def test_split(dtype): @pytest.mark.skip("Split is not supported by the 3.0.1 version of the driver stack.") @requires_ethosn def test_split_failure(): + """Check Split error messages.""" + trials = [ ((1, 4, 4, 4, 4), "uint8", 4, 2, "dimensions=5, dimensions must be <= 4;"), ((1, 4, 4, 4), "int16", 4, 2, "dtype='int16', dtype must be either uint8, int8 or int32;"), @@ -74,7 +78,8 @@ def test_split_failure(): "uint8", 4, 3, - "Split along the channels dimension (axis 3) requires all output sizes (specified in splitInfo.m_Sizes) to be multiples of 16;", + "Split along the channels dimension (axis 3) requires all output sizes " + "(specified in splitInfo.m_Sizes) to be multiples of 16;", ), ] diff --git a/tests/python/contrib/test_ethosn/test_tanh.py b/tests/python/contrib/test_ethosn/test_tanh.py index 8f44936fdc4f..68170601c5f8 100644 --- a/tests/python/contrib/test_ethosn/test_tanh.py +++ b/tests/python/contrib/test_ethosn/test_tanh.py @@ -46,6 +46,8 @@ def _get_model(shape, input_zp, input_sc, output_zp, output_sc, dtype): @pytest.mark.parametrize("dtype", ["uint8", "int8"]) @pytest.mark.parametrize("shape", [(1, 52, 52, 3)]) def test_tanh(dtype, shape): + """Compare Tanh output with TVM.""" + zp_min = np.iinfo(dtype).min zp_max = np.iinfo(dtype).max @@ -78,6 +80,8 @@ def test_tanh(dtype, shape): ], ) def test_tanh_failure(shape, input_zp, input_sc, output_zp, output_sc, err_msg, dtype): + """Check Tanh error messages.""" + test_zp = 0 if dtype == "int8" else 128 model = _get_model(shape, input_zp, input_sc, output_zp, output_sc, dtype) model = tei.make_ethosn_composite(model, "ethos-n.qnn_tanh") diff --git a/tests/python/contrib/test_ethosn/test_topologies.py b/tests/python/contrib/test_ethosn/test_topologies.py index 970f7dce5cbd..19d7accadb6d 100644 --- a/tests/python/contrib/test_ethosn/test_topologies.py +++ b/tests/python/contrib/test_ethosn/test_topologies.py @@ -31,6 +31,8 @@ @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_split_add_concat(dtype): + """Test a model with split, add and contatenate.""" + def get_model(input_shape, dtype, var_names): """Return a model""" @@ -148,23 +150,25 @@ def get_model(dtype): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_output_order(dtype): + """Test the output order.""" + def get_model(input_shape, dtype, var_names): """Return a model""" - min = np.iinfo(dtype).min - max = np.iinfo(dtype).max + min_value = np.iinfo(dtype).min + max_value = np.iinfo(dtype).max a = relay.var(next(var_names), shape=input_shape, dtype=dtype) - z = relay.op.clip(a, min, max) - b = relay.op.clip(z, min, min + 15) - c = relay.op.clip(z, min + 16, min + 31) - d = relay.op.clip(z, min + 32, min + 47) - e = relay.op.clip(z, min + 48, min + 63) - f = relay.op.clip(z, min + 64, min + 79) - g = relay.op.clip(z, min + 80, min + 95) - h = relay.op.clip(z, min + 96, min + 111) - i = relay.op.clip(z, min + 112, max) - return relay.Tuple((d, c, e, f, i, b, h, g)) + op_z = relay.op.clip(a, min_value, max_value) + op_b = relay.op.clip(op_z, min_value, min_value + 15) + op_c = relay.op.clip(op_z, min_value + 16, min_value + 31) + op_d = relay.op.clip(op_z, min_value + 32, min_value + 47) + op_e = relay.op.clip(op_z, min_value + 48, min_value + 63) + op_f = relay.op.clip(op_z, min_value + 64, min_value + 79) + op_g = relay.op.clip(op_z, min_value + 80, min_value + 95) + op_h = relay.op.clip(op_z, min_value + 96, min_value + 111) + op_i = relay.op.clip(op_z, min_value + 112, max_value) + return relay.Tuple((op_d, op_c, op_e, op_f, op_i, op_b, op_h, op_g)) np.random.seed(0) inputs = { @@ -190,6 +194,7 @@ def test_output_order_different_sizes(dtype): """ Test the output order when there are multiple outputs of different sizes. """ + np.random.seed(0) input_name = "a" input_shape = (1, 8, 8, 4) @@ -233,6 +238,8 @@ def get_model(): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_split_with_asym_concats(dtype): + """Test a model with split and contatenates.""" + def get_model(shape, dtype, splits, axis): a = relay.var("a", shape=shape, dtype=dtype) split = relay.op.split(a, indices_or_sections=splits, axis=axis) @@ -335,6 +342,8 @@ def get_model(dtype): @requires_ethosn @pytest.mark.parametrize("dtype", ["uint8", "int8"]) def test_input_tuples(dtype): + """Test a model with a tuple as input.""" + def get_model(shapes, dtype, axis): tup = [] for i, shape in enumerate(shapes):