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 254e90a82a [microNPU][ETHOSU] Fix LUT size for int16 activations 
(#16680)
254e90a82a is described below

commit 254e90a82ae82fc803364b2b5aa18c447e87d3f7
Author: Aleksei-grovety <[email protected]>
AuthorDate: Mon Mar 11 15:28:48 2024 +0400

    [microNPU][ETHOSU] Fix LUT size for int16 activations (#16680)
    
    When passing the look-up table values to the TE graph, the table size value 
for int8 type was used, now the required value is set depending on the type of 
input data
---
 .../contrib/ethosu/te/binary_elementwise.py        |  4 ++--
 .../tvm/relay/backend/contrib/ethosu/te/common.py  | 26 ++++++++++++++++++++++
 .../relay/backend/contrib/ethosu/te/convolution.py |  4 ++--
 .../relay/backend/contrib/ethosu/te/depthwise.py   |  4 ++--
 .../relay/backend/contrib/ethosu/te/identity.py    |  3 ++-
 .../tvm/relay/backend/contrib/ethosu/te/pooling.py |  4 ++--
 tests/python/contrib/test_ethosu/test_scheduler.py | 19 ++++++++++++++++
 7 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py 
b/python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py
index 86fdb958fd..99ee932119 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py
@@ -22,7 +22,7 @@ from tvm import te
 from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, 
register_matcher
 
 from .dma import dma_ofm_compute, dma_ifm_compute
-from .common import get_layout_transform_matrices
+from .common import get_layout_transform_matrices, get_lut_expr
 
 
 def binary_elementwise_compute(
@@ -180,7 +180,7 @@ def binary_elementwise_compute(
 
     has_lut = activation in ("TANH", "LUT", "SIGMOID")
     # This is a trick to insert the LUT tensor into the TE graph if LUT is 
present
-    lut_expr = (lut[0] + lut[255]).astype(ifm.dtype) if has_lut else 0
+    lut_expr = get_lut_expr(lut, ifm.dtype) if has_lut else 0
 
     # Add the LUT tensor to the attributes to be able to later tell which 
tensor is the LUT
     if has_lut:
diff --git a/python/tvm/relay/backend/contrib/ethosu/te/common.py 
b/python/tvm/relay/backend/contrib/ethosu/te/common.py
index edbece4e13..82528e7504 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/common.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/common.py
@@ -61,3 +61,29 @@ def get_layout_transform_matrices(ofm_channels: int) -> 
Tuple[List[List[float]],
     ]
 
     return nhwc_to_nhcwb16, nhcwb16_to_nhwc
+
+
+def get_lut_expr(lut, ifm_dtype):
+    """Get the LUT expression to pass it to the TE graph.
+    For information about the LUT see
+    
https://developer.arm.com/documentation/102420/0200/Functional-description/Functional-blocks-/Output-unit/tanh--sigmoid--and-LUT
+
+    Parameters
+    ----------
+    lut : te.Tensor
+        The look-up table values.
+    ifm_dtype : str
+        The type of Input Feature Map tensor (IFM).
+
+    Returns
+    -------
+    lut_expr : tvm.tir.expr.Cast
+        The LUT expression to pass it to the TE graph
+    """
+    assert ifm_dtype in ["int8", "int16"]
+    if ifm_dtype == "int8":
+        assert lut.shape[0] == 256
+    if ifm_dtype == "int16":
+        assert lut.shape[0] == 512
+    lut_expr = (lut[0] + lut[lut.shape[0] - 1]).astype(ifm_dtype)
+    return lut_expr
diff --git a/python/tvm/relay/backend/contrib/ethosu/te/convolution.py 
b/python/tvm/relay/backend/contrib/ethosu/te/convolution.py
index 645a0d5822..d7ed4a010c 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/convolution.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/convolution.py
@@ -23,7 +23,7 @@ from tvm import te  # type: ignore
 from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, 
register_matcher
 
 from .dma import dma_ofm_compute, dma_ifm_compute
-from .common import get_layout_transform_matrices
+from .common import get_layout_transform_matrices, get_lut_expr
 
 
 def conv2d_compute(
@@ -155,7 +155,7 @@ def conv2d_compute(
     has_lut = activation in ("TANH", "LUT", "SIGMOID")
 
     # This is a trick to insert the LUT tensor into the TE graph if LUT is 
present
-    lut_expr = (lut[0] + lut[255]).astype(ifm.dtype) if has_lut else 0
+    lut_expr = get_lut_expr(lut, ifm.dtype) if has_lut else 0
 
     # Add the LUT tensor to the attributes to be able to later tell which 
tensor is the LUT
     if has_lut:
diff --git a/python/tvm/relay/backend/contrib/ethosu/te/depthwise.py 
b/python/tvm/relay/backend/contrib/ethosu/te/depthwise.py
index 25f262434c..ea88b5dfff 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/depthwise.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/depthwise.py
@@ -23,7 +23,7 @@ from tvm import te
 from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, 
register_matcher
 
 from .dma import dma_ofm_compute, dma_ifm_compute
-from .common import get_layout_transform_matrices
+from .common import get_layout_transform_matrices, get_lut_expr
 
 
 def depthwise_conv2d_compute(
@@ -147,7 +147,7 @@ def depthwise_conv2d_compute(
     has_lut = activation in ("TANH", "LUT", "SIGMOID")
 
     # This is a trick to insert the LUT tensor into the TE graph if LUT is 
present
-    lut_expr = (lut[0] + lut[255]).astype(ifm.dtype) if has_lut else 0
+    lut_expr = get_lut_expr(lut, ifm.dtype) if has_lut else 0
 
     # Add the LUT tensor to the attributes to be able to later tell which 
tensor is the LUT
     if has_lut:
diff --git a/python/tvm/relay/backend/contrib/ethosu/te/identity.py 
b/python/tvm/relay/backend/contrib/ethosu/te/identity.py
index 7f9bcebf70..9b0925056f 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/identity.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/identity.py
@@ -20,6 +20,7 @@ import numpy as np
 from tvm import te
 from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, 
register_matcher
 
+from .common import get_lut_expr
 from .dma import read_compute, write_compute
 
 
@@ -72,7 +73,7 @@ def identity_compute(
     has_lut = activation in ("TANH", "LUT", "SIGMOID")
 
     # This is a trick to insert the LUT tensor into the TE graph if LUT is 
present
-    lut_expr = (lut[0] + lut[255]).astype(ifm.dtype) if has_lut else 0
+    lut_expr = get_lut_expr(lut, ifm.dtype) if has_lut else 0
 
     # Add the LUT tensor to the attributes to be able to later tell which 
tensor is the LUT
     if has_lut:
diff --git a/python/tvm/relay/backend/contrib/ethosu/te/pooling.py 
b/python/tvm/relay/backend/contrib/ethosu/te/pooling.py
index 7308103240..bf65f380d2 100644
--- a/python/tvm/relay/backend/contrib/ethosu/te/pooling.py
+++ b/python/tvm/relay/backend/contrib/ethosu/te/pooling.py
@@ -23,7 +23,7 @@ from tvm import te
 from tvm.contrib.ethosu.cascader import TESubgraph, EthosuPart, Propagator, 
register_matcher
 
 from .dma import dma_ofm_compute, dma_ifm_compute
-from .common import get_layout_transform_matrices
+from .common import get_layout_transform_matrices, get_lut_expr
 
 
 def pooling_compute(
@@ -147,7 +147,7 @@ def pooling_compute(
     has_lut = activation in ("TANH", "LUT", "SIGMOID")
 
     # This is a trick to insert the LUT tensor into the TE graph if LUT is 
present
-    lut_expr = (lut[0] + lut[255]).astype(ifm.dtype) if has_lut else 0
+    lut_expr = get_lut_expr(lut, ifm.dtype) if has_lut else 0
 
     # Add the LUT tensor to the attributes to be able to later tell which 
tensor is the LUT
     if has_lut:
diff --git a/tests/python/contrib/test_ethosu/test_scheduler.py 
b/tests/python/contrib/test_ethosu/test_scheduler.py
index 1edd840b0b..e7abb707a6 100644
--- a/tests/python/contrib/test_ethosu/test_scheduler.py
+++ b/tests/python/contrib/test_ethosu/test_scheduler.py
@@ -178,6 +178,25 @@ def test_copy_luts():
     assert ".local" in sch.stages[10].op.name
 
 
+# This test makes sure that LUT have a correct size
[email protected]("dtype,lut_size", [["int8", 256], ["int16", 512]])
+def test_lut_size(dtype, lut_size):
+    ifm_shape = (1, 2, 4, 8)
+    ifm = relay.var("IFM", shape=ifm_shape, dtype=dtype)
+    lut = relay.const([i for i in range(lut_size)], dtype=dtype)
+    identity = make_ethosu_identity(ifm, lut=lut, activation="TANH")
+    func = relay.Function(relay.analysis.free_vars(identity), identity)
+    func = run_opt_pass(func, relay.transform.InferType())
+
+    func, const_dict = extract_constants(func)
+    te_graph = lower_to_te(func)
+
+    sch = te.create_schedule([te_graph.outputs[0].op])
+    copy_luts()(te_graph, const_dict, sch)
+
+    assert sch.stages[3].all_iter_vars[0].dom == tvm.ir.expr.Range(0, lut_size)
+
+
 def test_schedule_cache_reads():
     a = te.placeholder((12, 12), dtype="uint8", name="a")
     b = te.placeholder((12, 12), dtype="uint8", name="b")

Reply via email to