From a7218c6fa65f2b8efb5c5471ebd4a24ce0aac787 Mon Sep 17 00:00:00 2001 From: Luke Hutton Date: Fri, 15 Oct 2021 13:35:39 +0000 Subject: [PATCH 1/4] [microNPU] Fix typo in depthwise to allow int8 weights Small typo means that ifm datatype is checked when it should be weight. Change-Id: I975e87c0bc91049ddee650f485f3a94841c55aba --- src/relay/op/contrib/ethosu/depthwise.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/relay/op/contrib/ethosu/depthwise.cc b/src/relay/op/contrib/ethosu/depthwise.cc index fa73645d45de..b102ce26c912 100644 --- a/src/relay/op/contrib/ethosu/depthwise.cc +++ b/src/relay/op/contrib/ethosu/depthwise.cc @@ -126,7 +126,7 @@ bool EthosuDepthwiseConv2DRel(const Array& types, int num_inputs, const At ICHECK(ifm->dtype == DataType::UInt(8) || ifm->dtype == DataType::Int(8)) << "Expected ethosu_depthwise_conv2d type(uint8) or type(int8) for ifm but was " << ifm->dtype; - ICHECK(weight->dtype == DataType::UInt(8) || ifm->dtype == DataType::Int(8)) + ICHECK(weight->dtype == DataType::UInt(8) || weight->dtype == DataType::Int(8)) << "Expected ethosu_depthwise_conv2d type(uint8) or type(int8) for weight but was " << weight->dtype; ICHECK(scale_bias->dtype == DataType::UInt(8)) From ebc23199bf4513eb145843f4801b8fb01c1ab718 Mon Sep 17 00:00:00 2001 From: Luke Hutton Date: Mon, 18 Oct 2021 09:11:21 +0000 Subject: [PATCH 2/4] Add testcase Change-Id: I19fd934cda105187c86191313acf0fe88c75d244 --- .../test_replace_depthwise_conv2d.py | 93 ++++++++++++++++--- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py index b3ce74c4e84a..d7488b3cd965 100644 --- a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py +++ b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py @@ -29,16 +29,76 @@ @pytest.mark.parametrize( "trial", [ - [(1, 8, 8, 3), 3, (3, 2), (0, 0), (1, 1), (1, 1), "CLIP", "NHWC", "NHWC"], - [(1, 8, 8, 3), 3, (1, 1), (2, 1), (1, 1), (1, 1), "TANH", "NHWC", "NHWC"], - [(1, 8, 8, 3), 3, (1, 1), (0, 0), (1, 1), (1, 1), "NONE", "NHWC", "NHWC"], - [(1, 1, 1, 1), 1, (1, 1), (0, 0), (1, 1), (1, 1), "CLIP", "NHWC", "NHWC"], - [(1, 7, 9, 4), 4, (3, 2), (1, 2), (2, 1), (1, 2), "SIGMOID", "NHWC", "NHWC"], - [(1, 8, 2, 8, 16), 18, (1, 1), (2, 1), (1, 1), (1, 1), "CLIP", "NHCWB16", "NHWC"], - [(1, 7, 9, 40), 40, (3, 2), (1, 2), (2, 1), (1, 2), "CLIP", "NHWC", "NHCWB16"], - [(1, 4, 12, 9, 16), 182, (2, 3), (6, 3), (2, 2), (1, 1), "CLIP", "NHCWB16", "NHCWB16"], - [(1, 7, 9, 4), 4, (3, 2), (1, 2), (2, 1), (2, 2), "CLIP", "NHWC", "NHWC"], - [(1, 7, 9, 41), 41, (3, 2), (1, 2), (2, 1), (2, 2), "CLIP", "NHWC", "NHCWB16"], + [(1, 8, 8, 3), 3, (3, 2), (0, 0), (1, 1), (1, 1), "CLIP", "NHWC", "NHWC", "int8", "int8"], + [(1, 8, 8, 3), 3, (1, 1), (2, 1), (1, 1), (1, 1), "TANH", "NHWC", "NHWC", "int8", "int8"], + [(1, 8, 8, 3), 3, (1, 1), (0, 0), (1, 1), (1, 1), "NONE", "NHWC", "NHWC", "uint8", "int8"], + [(1, 1, 1, 1), 1, (1, 1), (0, 0), (1, 1), (1, 1), "CLIP", "NHWC", "NHWC", "uint8", "int8"], + [ + (1, 7, 9, 4), + 4, + (3, 2), + (1, 2), + (2, 1), + (1, 2), + "SIGMOID", + "NHWC", + "NHWC", + "uint8", + "uint8", + ], + [ + (1, 8, 2, 8, 16), + 18, + (1, 1), + (2, 1), + (1, 1), + (1, 1), + "CLIP", + "NHCWB16", + "NHWC", + "int8", + "int8", + ], + [ + (1, 7, 9, 40), + 40, + (3, 2), + (1, 2), + (2, 1), + (1, 2), + "CLIP", + "NHWC", + "NHCWB16", + "int8", + "int8", + ], + [ + (1, 4, 12, 9, 16), + 182, + (2, 3), + (6, 3), + (2, 2), + (1, 1), + "CLIP", + "NHCWB16", + "NHCWB16", + "int8", + "int8", + ], + [(1, 7, 9, 4), 4, (3, 2), (1, 2), (2, 1), (2, 2), "CLIP", "NHWC", "NHWC", "int8", "int8"], + [ + (1, 7, 9, 41), + 41, + (3, 2), + (1, 2), + (2, 1), + (2, 2), + "CLIP", + "NHWC", + "NHCWB16", + "int8", + "int8", + ], [ (1, 13, 12, 19, 16), 182, @@ -49,6 +109,8 @@ "CLIP", "NHCWB16", "NHCWB16", + "int8", + "int8", ], ], ) @@ -63,8 +125,10 @@ def _get_func( activation, ifm_layout, ofm_layout, + dtype, + weight_dtype, ): - ifm = relay.var("ifm", shape=ifm_shape, dtype="int8") + ifm = relay.var("ifm", shape=ifm_shape, dtype=dtype) depthwise = make_ethosu_depthwise_conv2d( ifm, channels, @@ -75,6 +139,7 @@ def _get_func( activation, ifm_layout, ofm_layout, + weight_dtype, ) func = relay.Function(relay.analysis.free_vars(depthwise), depthwise) func = run_opt_pass(func, relay.transform.InferType()) @@ -99,6 +164,8 @@ def _visit(stmt): activation, ifm_layout, ofm_layout, + dtype, + _, ) = trial dilated_kernel_h = (kernel_shape[0] - 1) * dilation[0] + 1 dilated_kernel_w = (kernel_shape[1] - 1) * dilation[1] + 1 @@ -125,7 +192,7 @@ def _visit(stmt): ofm_stride_h = 16 * ofm_width * ((channels - 1) // 16 + 1) answer = [ - "int8", + dtype, ifm_shape[1], ifm_shape[2] if ifm_layout == "NHWC" else ifm_shape[3], channels, @@ -142,7 +209,7 @@ def _visit(stmt): ifm_stride_h, ifm_stride_w, ifm_stride_c, - "int8", + dtype, ofm_height, ofm_width, channels, From 6ca9535b8103a348630768b450c90b3ff299d029 Mon Sep 17 00:00:00 2001 From: Luke Hutton Date: Thu, 28 Oct 2021 10:26:02 +0000 Subject: [PATCH 3/4] Add test for incorrect weight data type Change-Id: Ibaf202287e2173bee638f9db8e553350ce1dff31 --- .../test_replace_depthwise_conv2d.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py index d7488b3cd965..0fdb4ba3147e 100644 --- a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py +++ b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py @@ -20,9 +20,10 @@ pytest.importorskip("ethosu.vela") import tvm -from tvm import relay +from tvm import relay, TVMError from tvm.relay.testing import run_opt_pass from tvm.relay.backend.contrib.ethosu.tir.compiler import lower_to_tir + from .infra import make_ethosu_depthwise_conv2d, get_convolutional_args @@ -243,3 +244,29 @@ def _visit(stmt): "NONE", ] assert data[0] == answer, data[0] + + +def test_incompatible_weight_data_type(): + ifm = relay.var("ifm", shape=(1, 8, 8, 3), dtype="int8") + + depthwise = make_ethosu_depthwise_conv2d( + ifm=ifm, + channels=3, + kernel_shape=(3, 2), + padding=(0, 0), + strides=(1, 1), + dilation=(1, 1), + activation="NONE", + ifm_layout="NHWC", + ofm_layout="NHWC", + weight_dtype="int16", + ) + + func = relay.Function(relay.analysis.free_vars(depthwise), depthwise) + mod = tvm.IRModule.from_expr(func) + + with pytest.raises(TVMError) as err: + mod = relay.transform.InferType()(mod) + + message = "Expected ethosu_depthwise_conv2d type(uint8) or type(int8) for weight but was int16" + assert message in str(err.value) From 7938edc3301a7ebbedb7b1fd1e5fb5c220c7f195 Mon Sep 17 00:00:00 2001 From: Luke Hutton Date: Thu, 28 Oct 2021 13:08:06 +0000 Subject: [PATCH 4/4] Flatten error check, also move test to type inference tests which is a more sensible location. Change-Id: I11f707ed4d81454765d7b3b597fa0c51e6909e3f --- .../test_replace_depthwise_conv2d.py | 28 +------------------ .../test_ethosu/test_type_inference.py | 26 ++++++++++++++++- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py index 0fdb4ba3147e..93a2f9e133ce 100644 --- a/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py +++ b/tests/python/contrib/test_ethosu/test_replace_depthwise_conv2d.py @@ -20,7 +20,7 @@ pytest.importorskip("ethosu.vela") import tvm -from tvm import relay, TVMError +from tvm import relay from tvm.relay.testing import run_opt_pass from tvm.relay.backend.contrib.ethosu.tir.compiler import lower_to_tir @@ -244,29 +244,3 @@ def _visit(stmt): "NONE", ] assert data[0] == answer, data[0] - - -def test_incompatible_weight_data_type(): - ifm = relay.var("ifm", shape=(1, 8, 8, 3), dtype="int8") - - depthwise = make_ethosu_depthwise_conv2d( - ifm=ifm, - channels=3, - kernel_shape=(3, 2), - padding=(0, 0), - strides=(1, 1), - dilation=(1, 1), - activation="NONE", - ifm_layout="NHWC", - ofm_layout="NHWC", - weight_dtype="int16", - ) - - func = relay.Function(relay.analysis.free_vars(depthwise), depthwise) - mod = tvm.IRModule.from_expr(func) - - with pytest.raises(TVMError) as err: - mod = relay.transform.InferType()(mod) - - message = "Expected ethosu_depthwise_conv2d type(uint8) or type(int8) for weight but was int16" - assert message in str(err.value) diff --git a/tests/python/contrib/test_ethosu/test_type_inference.py b/tests/python/contrib/test_ethosu/test_type_inference.py index 47fddad773b2..681c49eb68ba 100644 --- a/tests/python/contrib/test_ethosu/test_type_inference.py +++ b/tests/python/contrib/test_ethosu/test_type_inference.py @@ -18,7 +18,7 @@ pytest.importorskip("ethosu.vela") -from tvm import relay +from tvm import relay, TVMError from tvm.relay.testing import run_opt_pass from .infra import make_ethosu_conv2d from .infra import make_ethosu_depthwise_conv2d @@ -92,5 +92,29 @@ def test_ethosu_depthwise_conv2d_type_inference( assert tuple(f.body.checked_type.shape) == ofm_shape +def test_incompatible_weight_data_type(): + ifm = relay.var("ifm", shape=(1, 8, 8, 3), dtype="int8") + depthwise = make_ethosu_depthwise_conv2d( + ifm=ifm, + channels=3, + kernel_shape=(3, 2), + padding=(0, 0), + strides=(1, 1), + dilation=(1, 1), + activation="NONE", + ifm_layout="NHWC", + ofm_layout="NHWC", + weight_dtype="int16", + ) + + func = relay.Function(relay.analysis.free_vars(depthwise), depthwise) + + message = ( + r"Expected ethosu_depthwise_conv2d type\(uint8\) or type\(int8\) for weight but was int16" + ) + with pytest.raises(TVMError, match=message): + run_opt_pass(func, relay.transform.InferType()) + + if __name__ == "__main__": pytest.main([__file__])