Skip to content

Commit 5b41a6b

Browse files
committed
rebase and add support for no-upsampling case.
Change-Id: I840d8ee3671a40c5c99f22119442c349dbed39cf
1 parent 92f4aef commit 5b41a6b

File tree

9 files changed

+77
-60
lines changed

9 files changed

+77
-60
lines changed

python/tvm/relay/backend/contrib/ethosu/legalize.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,8 @@ class Resize2dRewriter(DFPatternCallback):
12741274
Convert ethos-u.resize2d composite function to an equivalent operation that
12751275
performs the relevant upsampling operation.
12761276
1277+
Case 1: No upsampling (upscale factor of 1):
1278+
Identity.
12771279
Case 1: Nearest neighbor upsampling:
12781280
1x1 pooling with 2x2 nearest neighbor upsampling.
12791281
Case 2: Bilinear upsampling:
@@ -1296,23 +1298,32 @@ def callback(
12961298
ifm_shape = params.ifm.shape
12971299
in_channels = ifm_shape[-1]
12981300
reduced_op = params.ifm.tensor
1301+
current_size = np.array(ifm_shape[1:3])
1302+
output_size = np.array(params.size)
12991303

1300-
if params.method == "nearest_neighbor":
1301-
pool_shape = [1, 1]
1302-
padding = [0, 0, 0, 0]
1303-
rounding_mode = "TFL"
1304-
else: # Bilinear upsampling
1304+
if (current_size == output_size).all():
1305+
return ethosu_ops.ethosu_identity(
1306+
reduced_op,
1307+
lut,
1308+
ifm_scale=float(params.ifm.q_params.scale_f32),
1309+
ifm_zero_point=int(params.ifm.q_params.zero_point),
1310+
ofm_scale=float(params.ofm.q_params.scale_f32),
1311+
ofm_zero_point=int(params.ofm.q_params.zero_point),
1312+
)
1313+
1314+
padding = [0, 0, 0, 0]
1315+
rounding_mode = "TFL"
1316+
pool_shape = [1, 1]
1317+
if params.method == "linear":
13051318
pool_shape = [2, 2]
13061319
rounding_mode = "NATURAL"
1307-
# For align_corners use VALID padding, otherwise use SAME padding
1308-
if params.coordinate_transformation_mode == "align_corners":
1309-
padding = [0, 0, 0, 0]
1310-
else:
1320+
if params.coordinate_transformation_mode == "asymmetric":
1321+
# Use SAME padding.
13111322
ypad = Resize2dRewriter.get_required_padding(ifm_shape[1])
13121323
xpad = Resize2dRewriter.get_required_padding(ifm_shape[2])
13131324
padding = [ypad // 2, xpad // 2, (ypad + 1) // 2, (xpad + 1) // 2]
13141325

1315-
reduced_op = ethosu_ops.ethosu_pooling(
1326+
return ethosu_ops.ethosu_pooling(
13161327
ifm=reduced_op,
13171328
lut=lut,
13181329
pooling_type="AVG",
@@ -1328,8 +1339,6 @@ def callback(
13281339
rounding_mode=rounding_mode,
13291340
)
13301341

1331-
return reduced_op
1332-
13331342
@staticmethod
13341343
def get_required_padding(input_size: int, pool_size: int = 2) -> int:
13351344
"""Gets the amount of padding required needed to achieve

python/tvm/relay/backend/contrib/ethosu/te/binary_elementwise.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,10 @@ def match_ethosu_binary_elementwise(output_tensor, device_config):
288288
pad = binary_elementwise.op.input_tensors[0]
289289
if pad.op.name != "ethosu_pad":
290290
return None
291-
convert_to_nhwc = pad.op.input_tensors[0]
291+
upscale = pad.op.input_tensors[0]
292+
if upscale.op.name != "ethosu_upscale":
293+
return None
294+
convert_to_nhwc = upscale.op.input_tensors[0]
292295
if convert_to_nhwc.op.name != "ethosu_convert_to_nhwc":
293296
return None
294297
read = convert_to_nhwc.op.input_tensors[0]
@@ -297,7 +300,10 @@ def match_ethosu_binary_elementwise(output_tensor, device_config):
297300
pad2 = binary_elementwise.op.input_tensors[1]
298301
if pad2.op.name != "ethosu_pad":
299302
return None
300-
convert_to_nhwc2 = pad2.op.input_tensors[0]
303+
upscale2 = pad2.op.input_tensors[0]
304+
if upscale2.op.name != "ethosu_upscale":
305+
return None
306+
convert_to_nhwc2 = upscale2.op.input_tensors[0]
301307
if convert_to_nhwc2.op.name != "ethosu_convert_to_nhwc":
302308
return None
303309
read2 = convert_to_nhwc2.op.input_tensors[0]

python/tvm/relay/backend/contrib/ethosu/te/depthwise.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,10 @@ def match_ethosu_depthwise_conv2d(output_tensor, device_config):
267267
pad = depthwise2d.op.input_tensors[0]
268268
if pad.op.name != "ethosu_pad":
269269
return None
270-
convert_to_nhwc = pad.op.input_tensors[0]
270+
upscale = pad.op.input_tensors[0]
271+
if upscale.op.name != "ethosu_upscale":
272+
return None
273+
convert_to_nhwc = upscale.op.input_tensors[0]
271274
if convert_to_nhwc.op.name != "ethosu_convert_to_nhwc":
272275
return None
273276
read = convert_to_nhwc.op.input_tensors[0]

python/tvm/relay/backend/contrib/ethosu/te/pooling.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ def match_ethosu_pooling(output_tensor, device_config):
231231
pad = pool2d.op.input_tensors[0]
232232
if pad.op.name != "ethosu_pad":
233233
return None
234-
convert_to_nhwc = pad.op.input_tensors[0]
234+
upscale = pad.op.input_tensors[0]
235+
if upscale.op.name != "ethosu_upscale":
236+
return None
237+
convert_to_nhwc = upscale.op.input_tensors[0]
235238
if convert_to_nhwc.op.name != "ethosu_convert_to_nhwc":
236239
return None
237240
read = convert_to_nhwc.op.input_tensors[0]

python/tvm/relay/backend/contrib/ethosu/te/unary_elementwise.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ def match_ethosu_unary_elementwise(output_tensor, device_config):
205205
pad = unary_elementwise.op.input_tensors[0]
206206
if pad.op.name != "ethosu_pad":
207207
return None
208-
convert_to_nhwc = pad.op.input_tensors[0]
208+
upscale = pad.op.input_tensors[0]
209+
if upscale.op.name != "ethosu_upscale":
210+
return None
211+
convert_to_nhwc = upscale.op.input_tensors[0]
209212
if convert_to_nhwc.op.name != "ethosu_convert_to_nhwc":
210213
return None
211214
read = convert_to_nhwc.op.input_tensors[0]

python/tvm/relay/backend/contrib/ethosu/util.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,6 @@ class QConv2DArgs(Enum):
4747
WEIGHTS_SCALE = 5
4848

4949

50-
class QConv2DTransposeArgs(Enum):
51-
"""
52-
This is a helper enum to obtain the correct index of
53-
qnn.conv2d_transpose aruments.
54-
"""
55-
56-
IFM = 0
57-
WEIGHTS = 1
58-
IFM_ZERO_POINT = 2
59-
WEIGHTS_ZERO_POINT = 3
60-
IFM_SCALE = 4
61-
WEIGHTS_SCALE = 5
62-
63-
6450
class RequantArgs(Enum):
6551
"""
6652
This is a helper enum to obtain the correct index

python/tvm/relay/op/contrib/ethosu.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
# pylint: disable=ungrouped-imports, import-outside-toplevel
1818
"""Arm(R) Ethos(TM)-U NPU supported operators."""
1919
import functools
20-
2120
from typing import Dict, List, Tuple, Callable, Optional
21+
2222
import numpy as np # type: ignore
2323

2424
import tvm # type: ignore
@@ -1239,16 +1239,17 @@ def is_valid(self) -> bool:
12391239
Checks whether image.resize2d has compatible attributes with HW.
12401240
"""
12411241

1242-
def check_compatible_size(mode, method, upscale_size, height, width):
1242+
def check_compatible_size(mode, method, upscale_size, ifm_size):
12431243
"""Checking the provided upscale_size is compatible with the NPU. The NPU only
12441244
supports upsampling when the upsampling size is 2 * input_size, or when there is
12451245
no upsampling to be done, so check that this is the case. In the special case of
12461246
resize_bilinear with align_corners=True, the NPU only supports an upsampling
12471247
size of 2 * input_size - 1."""
12481248
delta = 1 if mode == "align_corners" and method == "linear" else 0
1249-
upscale_height = height * 2 - delta
1250-
upscale_width = width * 2 - delta
1251-
return upscale_height == int(upscale_size[0]) and upscale_width == int(upscale_size[1])
1249+
upscale_size = np.array(upscale_size)
1250+
ifm_size = np.array(ifm_size)
1251+
ifm_upscaled = ifm_size * 2 - delta
1252+
return (ifm_upscaled == upscale_size).all() or (ifm_size == upscale_size).all()
12521253

12531254
tensor_params = [self.ifm, self.ofm]
12541255
if not check_valid_dtypes(tensor_params, supported_dtypes=[np.int8]):
@@ -1265,8 +1266,7 @@ def check_compatible_size(mode, method, upscale_size, height, width):
12651266
self.coordinate_transformation_mode,
12661267
self.method,
12671268
self.size,
1268-
self.ifm.shape[1],
1269-
self.ifm.shape[2],
1269+
self.ifm.shape[1:3],
12701270
):
12711271
return False
12721272
if self.rounding_method != "":

tests/python/contrib/test_ethosu/test_codegen.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,10 +1023,7 @@ def create_model():
10231023
@pytest.mark.parametrize("accel_type", ACCEL_TYPES)
10241024
@pytest.mark.parametrize(
10251025
"ifm_shape,size",
1026-
[
1027-
[(1, 2, 2, 1), (4, 4)],
1028-
[(1, 4, 7, 3), (8, 14)],
1029-
],
1026+
[[(1, 2, 2, 1), (4, 4)], [(1, 4, 7, 3), (8, 14)], [(1, 3, 5, 3), (3, 5)]],
10301027
)
10311028
def test_tflite_resize2d_nearest_neighbor(accel_type, ifm_shape, size):
10321029
align_corners = False
@@ -1048,6 +1045,7 @@ def resize_model(x):
10481045
[(1, 4, 7, 3), (8, 14), False],
10491046
[(1, 2, 2, 1), (3, 3), True],
10501047
[(1, 4, 7, 3), (7, 13), True],
1048+
[(1, 3, 5, 3), (3, 5), False],
10511049
],
10521050
)
10531051
def test_tflite_resize2d_bilinear(accel_type, ifm_shape, size, align_corners):

tests/python/contrib/test_ethosu/test_legalize.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,7 @@ def verify(ext_func):
16081608
[
16091609
[(1, 2, 2, 1), (4, 4)],
16101610
[(1, 4, 7, 3), (8, 14)],
1611+
[(1, 3, 5, 3), (3, 5)],
16111612
],
16121613
)
16131614
def test_tflite_resize2d_nearest_neighbor(ifm_shape, size):
@@ -1647,21 +1648,25 @@ def representative_dataset():
16471648
return mod
16481649

16491650
def verify(ext_func):
1650-
identity = ext_func.body
1651-
in_var = identity.args[0]
1651+
op = ext_func.body
1652+
in_var = op.args[0]
16521653

16531654
# check IFM
16541655
assert tuple(in_var.checked_type.shape) == ifm_shape
16551656
assert in_var.checked_type.dtype == dtype
16561657

16571658
# check OFM
1658-
attrs = dict(identity.attrs)
1659+
attrs = dict(op.attrs)
16591660
out_shape = (ifm_shape[0], size[0], size[1], ifm_shape[3])
1660-
assert tuple(identity.checked_type.shape) == out_shape
1661-
assert identity.checked_type.dtype == dtype
1661+
assert tuple(op.checked_type.shape) == out_shape
1662+
assert op.checked_type.dtype == dtype
16621663

16631664
# Check Op attributes
1664-
assert attrs["upscale"] == "NEAREST"
1665+
if size[0] == ifm_shape[1] and size[1] == ifm_shape[2]:
1666+
assert op.op.name == "contrib.ethosu.identity"
1667+
else:
1668+
assert attrs["pooling_type"] == "AVG"
1669+
assert attrs["upscale"] == "NEAREST"
16651670

16661671
rewriter = legalize.Resize2dRewriter()
16671672
pattern_table = [
@@ -1687,6 +1692,7 @@ def verify(ext_func):
16871692
[(1, 4, 7, 3), (8, 14), False],
16881693
[(1, 2, 2, 1), (3, 3), True],
16891694
[(1, 4, 7, 3), (7, 13), True],
1695+
[(1, 3, 5, 3), (3, 5), False],
16901696
],
16911697
)
16921698
def test_tflite_resize2d_bilinear(ifm_shape, size, align_corners):
@@ -1725,28 +1731,31 @@ def representative_dataset():
17251731
return mod
17261732

17271733
def verify(ext_func):
1728-
avg_pool = ext_func.body
1729-
in_var = avg_pool.args[0]
1734+
op = ext_func.body
1735+
in_var = op.args[0]
17301736

17311737
# check IFM
17321738
assert tuple(in_var.checked_type.shape) == ifm_shape
17331739
assert in_var.checked_type.dtype == dtype
17341740

17351741
# check OFM
1736-
attrs = dict(avg_pool.attrs)
1742+
attrs = dict(op.attrs)
17371743
out_shape = (ifm_shape[0], size[0], size[1], ifm_shape[3])
1738-
assert tuple(avg_pool.checked_type.shape) == out_shape
1739-
assert avg_pool.checked_type.dtype == dtype
1744+
assert tuple(op.checked_type.shape) == out_shape
1745+
assert op.checked_type.dtype == dtype
17401746

17411747
# Check Op attributes
1742-
assert attrs["pooling_type"] == "AVG"
1743-
assert attrs["upscale"] == "NEAREST"
1744-
1745-
# Check padding
1746-
if align_corners:
1747-
assert list(attrs["padding"]) == [0, 0, 0, 0]
1748+
if size[0] == ifm_shape[1] and size[1] == ifm_shape[2]:
1749+
assert op.op.name == "contrib.ethosu.identity"
17481750
else:
1749-
assert list(attrs["padding"]) == [0, 0, 1, 1]
1751+
assert attrs["pooling_type"] == "AVG"
1752+
assert attrs["upscale"] == "NEAREST"
1753+
1754+
# Check padding
1755+
if align_corners:
1756+
assert list(attrs["padding"]) == [0, 0, 0, 0]
1757+
else:
1758+
assert list(attrs["padding"]) == [0, 0, 1, 1]
17501759

17511760
rewriter = legalize.Resize2dRewriter()
17521761
pattern_table = [

0 commit comments

Comments
 (0)