You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by lu...@apache.org on 2022/08/23 13:28:20 UTC

[tvm] branch main updated: [ETHOSN] Fix requantize output conversion (#12540)

This is an automated email from the ASF dual-hosted git repository.

lukhut pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new ff46fa15e0 [ETHOSN] Fix requantize output conversion (#12540)
ff46fa15e0 is described below

commit ff46fa15e063ef499f666e63b9d5ed3faf2e3bfb
Author: Luke Hutton <lu...@arm.com>
AuthorDate: Tue Aug 23 14:28:12 2022 +0100

    [ETHOSN] Fix requantize output conversion (#12540)
    
    Fixes a small issue when converting the output information to the support library API. The `requantize_info` output datatype needed updating with the output datatype from the relay function to ensure the graph is compiled correctly by the support library. Included a test to prevent regression in the future.
---
 src/relay/backend/contrib/ethosn/ethosn_api.cc     | 22 ++++----
 .../python/contrib/test_ethosn/test_requantize.py  | 63 ++++++++++++++++++++++
 2 files changed, 75 insertions(+), 10 deletions(-)

diff --git a/src/relay/backend/contrib/ethosn/ethosn_api.cc b/src/relay/backend/contrib/ethosn/ethosn_api.cc
index c828762096..55d0b57bcc 100644
--- a/src/relay/backend/contrib/ethosn/ethosn_api.cc
+++ b/src/relay/backend/contrib/ethosn/ethosn_api.cc
@@ -678,11 +678,17 @@ EthosnError EthosnAPI::Relu(const Expr& expr, ReluParams* params) {
 
 EthosnError EthosnAPI::Requantize(const Expr& expr, RequantizeParams* params) {
   Call call = Downcast<Call>(expr);
-  const auto* input_dtype = call->args[0]->checked_type().as<TensorTypeNode>();
+  const auto* input_ttype = call->args[0]->checked_type().as<TensorTypeNode>();
   sl::TensorShape input_tensor_shape = {1, 1, 1, 1};
   sl::DataType input_data_type;
-  EthosnError err = Tvm2Npu(input_dtype->shape, &input_tensor_shape);
-  err += Tvm2Npu(input_dtype->dtype, &input_data_type);
+  EthosnError err = Tvm2Npu(input_ttype->shape, &input_tensor_shape);
+  err += Tvm2Npu(input_ttype->dtype, &input_data_type);
+
+  const auto* output_ttype = call->checked_type().as<TensorTypeNode>();
+  sl::TensorShape output_tensor_shape = {1, 1, 1, 1};
+  sl::DataType output_data_type;
+  err += Tvm2Npu(output_ttype->shape, &output_tensor_shape);
+  err += Tvm2Npu(output_ttype->dtype, &output_data_type);
 
   float input_sc, output_sc;
   int input_zp, output_zp;
@@ -699,14 +705,10 @@ EthosnError EthosnAPI::Requantize(const Expr& expr, RequantizeParams* params) {
   sl::QuantizationInfo requantize_q_info;
   err += Tvm2Npu(output_zp, output_sc, &requantize_q_info);
   params->requantize_info = sl::RequantizeInfo(requantize_q_info);
+  params->requantize_info.m_OutputDataType = output_data_type;
 
-  sl::TensorInfo output_info = params->input_info;
-  output_info.m_QuantizationInfo = params->requantize_info.m_OutputQuantizationInfo;
-  if (params->requantize_info.m_OutputDataType.has_value()) {
-    output_info.m_DataType = params->requantize_info.m_OutputDataType.value();
-  }
-  params->output_info = output_info;
-
+  params->output_info = sl::TensorInfo(output_tensor_shape, output_data_type, sl::DataFormat::NHWC,
+                                       requantize_q_info);
   return err;
 }
 
diff --git a/tests/python/contrib/test_ethosn/test_requantize.py b/tests/python/contrib/test_ethosn/test_requantize.py
index 4626a0d92b..e20c3beeab 100644
--- a/tests/python/contrib/test_ethosn/test_requantize.py
+++ b/tests/python/contrib/test_ethosn/test_requantize.py
@@ -68,6 +68,69 @@ def test_requantize(in_dtype, out_dtype, shape):
     tei.verify(outputs, out_dtype, 1)
 
 
+@requires_ethosn
+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
+    in_zp = 131
+    out_sc = 0.012566
+    out_zp = 3
+    in_dtype = "uint8"
+    out_dtype = "int8"
+
+    def get_model():
+        a = relay.var("a", shape=shape, dtype=in_dtype)
+        b = relay.var("b", shape=shape, dtype=out_dtype)
+        req = relay.qnn.op.requantize(
+            data=a,
+            input_scale=relay.const(in_sc, "float32"),
+            input_zero_point=relay.const(in_zp, "int32"),
+            output_scale=relay.const(out_sc, "float32"),
+            output_zero_point=relay.const(out_zp, "int32"),
+            out_dtype=out_dtype,
+        )
+        req = relay.qnn.op.add(
+            req,
+            b,
+            lhs_scale=relay.const(out_sc, "float32"),
+            lhs_zero_point=relay.const(out_zp, "int32"),
+            rhs_scale=relay.const(out_sc, "float32"),
+            rhs_zero_point=relay.const(out_zp, "int32"),
+            output_scale=relay.const(out_sc, "float32"),
+            output_zero_point=relay.const(out_zp, "int32"),
+        )
+        return req
+
+    inputs = {
+        "a": tvm.nd.array(
+            np.random.randint(
+                low=np.iinfo(in_dtype).min, high=np.iinfo(in_dtype).max, size=shape, dtype=in_dtype
+            )
+        ),
+        "b": tvm.nd.array(
+            np.random.randint(
+                low=np.iinfo(out_dtype).min,
+                high=np.iinfo(out_dtype).max,
+                size=shape,
+                dtype=out_dtype,
+            )
+        ),
+    }
+    outputs = []
+    for npu in [False, True]:
+        model = get_model()
+        mod = tei.make_module(model, {})
+        x = tei.build_and_run(mod, inputs, 1, {}, npu=npu)
+        outputs.append(x)
+
+    tei.verify(outputs, out_dtype, 1)
+
+
 @requires_ethosn
 def test_requantize_failure():
     input_sc = 0.8