aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Hall <tim.hall@arm.com>2023-02-14 14:54:18 +0000
committertim.hall <tim.hall@arm.com>2023-02-15 16:58:50 +0000
commitd0e41cf4c20a0f5780a8dd072df29bdb3267d960 (patch)
treed53c9fefac1a8a2c80ad275cd42a456cfdf9d270
parent46c9477ded912f26ddf0a761c728d23f7d616004 (diff)
downloadethos-u-vela-d0e41cf4c20a0f5780a8dd072df29bdb3267d960.tar.gz
MLBEDSW-7343: MLCE: Unsupported STRIDED_SLICE with negative index and shrinking an axis
- The problem was that the end values of STRIDED_SLICE operators were not taking the shrink_axis_mask into account - The fix is simply to ignore the end value set on the operator and calculate one based upon shrinking the axis Change-Id: I2e5f2d3c9b08035dfd9b1629c775408f2356d1cf Signed-off-by: Tim Hall <tim.hall@arm.com>
-rw-r--r--ethosu/vela/operation.py24
-rw-r--r--ethosu/vela/tflite_model_semantic.py34
2 files changed, 36 insertions, 22 deletions
diff --git a/ethosu/vela/operation.py b/ethosu/vela/operation.py
index de35dcc7..f85cb4bb 100644
--- a/ethosu/vela/operation.py
+++ b/ethosu/vela/operation.py
@@ -1,4 +1,4 @@
-# SPDX-FileCopyrightText: Copyright 2020-2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+# SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -458,19 +458,6 @@ def create_activation_function(op_type: Op, min=None, max=None) -> ActivationFun
return act
-def get_slice_offsets(input_shape: List[int], offset_tens: Tensor, offset_mask: int, is_begin: bool = True):
- # For strided slice operator: get start or end offsets
- offsets = len(input_shape) * [0] if is_begin else input_shape[:]
- for idx in range(len(input_shape)):
- # If the i:th bit in the mask is set then the value on offset_tens[i] should be ignored
- if (offset_mask & (1 << idx)) == 0:
- offsets[idx] = offset_tens.values[idx]
- if offsets[idx] < 0:
- # Convert offset to positive value
- offsets[idx] += input_shape[idx]
- return offsets
-
-
class Operation:
"""Class representing a Neural Network operation. Has a name, a type,
input and output tensors, as well as an attribute dictionary."""
@@ -775,17 +762,18 @@ class Operation:
outputs = self.outputs
# Extract masks
- begin_mask = self.attrs["begin_mask"]
ellipsis_mask = self.attrs["ellipsis_mask"]
- end_mask = self.attrs["end_mask"]
new_axis_mask = self.attrs["new_axis_mask"]
shrink_axis_mask = self.attrs["shrink_axis_mask"]
# shrink_axis_mask/new_axis_mask/ellipsis_mask is not supported by the Operation class but the operation
# may have the attribute modified and handled in the graph optimization phase.
assert shrink_axis_mask == new_axis_mask == ellipsis_mask == 0
- offset_start = get_slice_offsets(input_tens.shape, begin_tens, begin_mask, is_begin=True)
- offset_end = get_slice_offsets(input_tens.shape, end_tens, end_mask, is_begin=False)
+ # use the begin and end values that were calculated in the model semantic check. this is because the end
+ # values can be affected (ignored) by the shrink_axis_mask and this mask may have been changed in the graph
+ # optimizer (see assert above)
+ offset_start = self.attrs["offset_begin"]
+ offset_end = self.attrs["offset_end"]
elif self.type == Op.UnpackReshaped:
# Requires fixup_unpack_output to be called before this point
input_tens = self.inputs[0]
diff --git a/ethosu/vela/tflite_model_semantic.py b/ethosu/vela/tflite_model_semantic.py
index 2851ab16..0c2086c3 100644
--- a/ethosu/vela/tflite_model_semantic.py
+++ b/ethosu/vela/tflite_model_semantic.py
@@ -23,7 +23,6 @@ import numpy as np
from .data_type import BaseType
from .data_type import DataType
from .numeric_util import is_integer
-from .operation import get_slice_offsets
from .operation import Op
from .supported_operators_util import docstring_format_args
from .supported_operators_util import list_formatter
@@ -551,15 +550,42 @@ class TFLiteSemantic:
valid = (new_axis == 0) or (shrink_axis == 0)
return valid, f"Op has new_axis_mask={new_axis} and shrink_axis_mask={shrink_axis}"
+ def _get_slice_offsets(input_shape, offset_tens, offset_mask, is_begin=True):
+ # For strided slice operator: get start or end offsets
+ # input_shape: List[int], offset_tens: Tensor, offset_mask: int, is_begin: bool = True
+ offsets = len(input_shape) * [0] if is_begin else input_shape[:]
+ for idx in range(len(input_shape)):
+ # If the i:th bit in the mask is not set then the value in offset_tens[i] should be used, otherwise it
+ # should be ignored
+ if (offset_mask & (1 << idx)) == 0:
+ offsets[idx] = offset_tens.values[idx]
+ if offsets[idx] < 0:
+ # Convert negative indexing to positive ones
+ offsets[idx] += input_shape[idx]
+ return offsets
+
@staticmethod
def constraint_slice_ranges(op):
"Slice 'end' values must be greater than 'begin' values"
ifm, begin, end, _ = op.inputs
+ shrink_axis_mask = op.attrs["shrink_axis_mask"]
# Calculate offset begin/end
- offset_begin = get_slice_offsets(ifm.shape, begin, op.attrs["begin_mask"], is_begin=True)
- offset_end = get_slice_offsets(ifm.shape, end, op.attrs["end_mask"], is_begin=False)
+ offset_begin = TFLiteSemantic._get_slice_offsets(ifm.shape, begin, op.attrs["begin_mask"], is_begin=True)
+ offset_end = TFLiteSemantic._get_slice_offsets(ifm.shape, end, op.attrs["end_mask"], is_begin=False)
# Check "end - begin" doesn't result in any zero or negative elements
- valid = all((e - b) > 0 for b, e in zip(offset_begin, offset_end))
+ valid = True
+ # if a shrink mask bit is set then the end position provided by the operation should be ignored, and instead a
+ # new end position should be calculated so that calculations in the graph optimiser, such as (end - start),
+ # result in the correct value. otherwise, we just need to check that the begin and end values are valid
+ for i in range(len(ifm.shape)):
+ if (shrink_axis_mask & (1 << i)) != 0:
+ offset_end[i] = offset_begin[i] + 1
+ else:
+ if offset_end[i] <= offset_begin[i]:
+ valid = False
+
+ op.attrs["offset_begin"] = offset_begin
+ op.attrs["offset_end"] = offset_end
return valid, f"Op has begin_values={begin.values} and end_values={end.values}"
@staticmethod