-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Medium
-
Code Generation Tools
-
CODEGEN-15610
-
MCU_NNC_2.1.1
-
MCU_NNC_2.1.2
-
default
TI MCU NNC crashes when accessing several optional relay attributes that are None when not specified in the model. The bug exists in ti_mcu_nnc 2.1.1.LTS release, and will be fixed in 2.1.2.LTS release.
Typical behavior of the bug
The ti_mcu_nnc compiler will emit the following errors:
File "lib/python3.10/site-packages/tvm/relay/backend/contrib/tinie/prepare.py", line 371, in visit_call
out_axes.append((axes[i], output_shape[i]))
TypeError: 'NoneType' object is not subscriptable
or:
File "lib/python3.10/site-packages/tvm/relay/backend/contrib/tinie/prepare.py", line 716, in is_height_only_strided_slice
return len(slice_call.attrs.axes) == 1 and slice_call.attrs.axes[0] == haxis and \
TypeError: object of type 'NoneType' has no len()
Typical use cases that could trigger this bug
When a user compiles a custom model with such layers without specifying optional attributes that is accessed.
Fixes / Workarounds
Fixes will be available in 2.1.2.LTS release.
For workaround, user can apply the following patch before the patch release is available:
diff --git a/python/tvm/relay/backend/contrib/tinie/prepare.py b/python/tvm/relay/backend/contrib/tinie/prepare.py
index 468f2c47d9..7b4541a99a 100644
--- a/python/tvm/relay/backend/contrib/tinie/prepare.py
+++ b/python/tvm/relay/backend/contrib/tinie/prepare.py
@@ -269,9 +269,11 @@ class CanonicalizeFloatModel(ExprMutator):
if res_op_name == "add":
if add_val and add_axis != -1:
if arg0_op_name == "squeeze":
- new_add_axis = add_axis + len([x for x in arg0.attrs['axis'] if x < add_axis])
- b_add = relay.nn.bias_add(arg0.args[0], add_val, axis=new_add_axis)
- return relay.squeeze(b_add, axis=arg0.attrs['axis'])
+ if arg0.attrs['axis'] is not None:
+ new_add_axis = add_axis + len([x for x in arg0.attrs['axis'] if x < add_axis])
+ b_add = relay.nn.bias_add(arg0.args[0], add_val, axis=new_add_axis)
+ return relay.squeeze(b_add, axis=arg0.attrs['axis'])
+ return relay.nn.bias_add(arg0, add_val, axis=add_axis)
return relay.nn.bias_add(arg0, add_val, axis=add_axis)
elif add_val and add_axis == -1 and \
arg0_op_name in ["nn.dense", "nn.conv2d", "nn.conv2d_transpose"]:
@@ -353,6 +355,8 @@ class CanonicalizeFloatModel(ExprMutator):
elif res_op_name == "transpose":
# Rewrite transpose with layout transform semantics
axes = res.attrs.axes
+ if axes is None: # axes=None means reverse order, not applicable
+ return res
if len(out_type.shape) == 3 and [x.value for x in axes] == [0, 2, 1]:
return relay.layout_transform(arg0, "NWC", "NCW")
elif len(out_type.shape) == 4 and [x.value for x in axes] == [0, 3, 1, 2]:
@@ -713,7 +717,10 @@ class HoistPadding(ExprMutator):
return super().visit_call(call)
def is_height_only_strided_slice(self, slice_call, haxis):
- return len(slice_call.attrs.axes) == 1 and slice_call.attrs.axes[0] == haxis and \
+ axes = slice_call.attrs.axes
+ if axes is None: # axes=None means all axes, not height-only
+ return False
+ return len(axes) == 1 and axes[0] == haxis and \
slice_call.attrs.strides[0] == 1
# Hoist padding out of conv2d/max_pool2d, merge with previous height-only "strided_slice" if any
@@ -1162,7 +1169,10 @@ class RemoveInputNormalization(ExprMutator):
transpose2 = add.args[0]
in_arg = transpose2.args[0]
# can only remove input norm with transposes if they invert themselves
- assert list(transpose1.attrs.axes) == list(transpose2.attrs.axes), \
+ axes1 = transpose1.attrs.axes
+ axes2 = transpose2.attrs.axes
+ assert (axes1 is None and axes2 is None) or \
+ (axes1 is not None and axes2 is not None and list(axes1) == list(axes2)), \
"input normalization transposes must invert themselves"
else:
in_arg = add.args[0]