From cf72890e5dd89dada3189816a61d174b984086bd Mon Sep 17 00:00:00 2001 From: Patrik Gustavsson Date: Thu, 30 Apr 2020 08:57:23 +0200 Subject: MLBEDSW-1998: Add support for new_axis_mask -Added support for new_axis_mask -Added support for more than 1 bit set in new/shrink_axis mask -Added checks for strided slice in supported operator check -Added assert if nothing has been put on NPU Change-Id: I66e2d04784f14d7ad82371f5d649a455d576a818 Signed-off-by: Patrik Gustavsson --- ethosu/vela/compiler_driver.py | 2 ++ ethosu/vela/graph_optimiser.py | 48 +++++++++++++++++++++++++++++--------- ethosu/vela/operation.py | 8 +++---- ethosu/vela/supported_operators.py | 8 ++++++- 4 files changed, 49 insertions(+), 17 deletions(-) (limited to 'ethosu') diff --git a/ethosu/vela/compiler_driver.py b/ethosu/vela/compiler_driver.py index 7f8c4ca4..db669ac7 100644 --- a/ethosu/vela/compiler_driver.py +++ b/ethosu/vela/compiler_driver.py @@ -141,6 +141,8 @@ def compiler_driver(nng, arch, options, scheduler_options): sg, permanent_storage, ignore_subgraph_input_output_tensors=True, lr_graph=lr_graph_flash ) + assert len(nng.subgraphs) > 1, "Error: No operators can be hardware accelerated; cancelling compilation" + # Allocate all Npu constant tensors to the first Npu subgraph since it is # processed first during serialization into tensors first_npu_sg = nng.subgraphs[1] diff --git a/ethosu/vela/graph_optimiser.py b/ethosu/vela/graph_optimiser.py index f0afcf8f..a4ed39ff 100644 --- a/ethosu/vela/graph_optimiser.py +++ b/ethosu/vela/graph_optimiser.py @@ -208,23 +208,49 @@ def fixup_unpack_output(tens, arch): if op.type in set(("Unpack", "StridedSlice")): # Unpack is also referred to as Unstack # Requires the rewrite_split function to be called on the op afterwards + + reshape_input_shape = tens.shape if op.type == "StridedSlice": + new_axis_mask = op.attrs["new_axis_mask"] shrink_axis_mask = op.attrs["shrink_axis_mask"] - if shrink_axis_mask == 0: + ellipsis_mask = op.attrs["ellipsis_mask"] + + if (new_axis_mask != 0 and shrink_axis_mask != 0) or ellipsis_mask != 0: + # Not supported, will be put on CPU + return tens + if shrink_axis_mask == 0 and new_axis_mask == 0: # Equal Rank StridedSlice, no need to insert reshape return tens - - # Only allow shrinking 1 axis for now - assert shrink_axis_mask & (shrink_axis_mask - 1) == 0 - assert len(tens.shape) == (len(op.inputs[0].shape) - 1) - - axis = int(math.log2(shrink_axis_mask)) - op.attrs["shrink_axis_mask"] = 0 + elif shrink_axis_mask != 0: + n = 0 + axis = 0 + while shrink_axis_mask: + prev_mask = shrink_axis_mask + n += 1 + shrink_axis_mask &= shrink_axis_mask - 1 + axis = int(math.log2(prev_mask - shrink_axis_mask)) + reshape_input_shape = reshape_input_shape[:axis] + [1] + reshape_input_shape[axis:] + + assert len(tens.shape) == (len(op.inputs[0].shape) - n) + op.attrs["shrink_axis_mask"] = 0 + + elif new_axis_mask != 0: + n = 0 + axis = 0 + while new_axis_mask: + prev_mask = new_axis_mask + n += 1 + new_axis_mask &= new_axis_mask - 1 + axis = int(math.log2(prev_mask - new_axis_mask)) + reshape_input_shape = reshape_input_shape[:axis] + reshape_input_shape[(axis + 1):] + new_axis_mask >>= 1 + + assert len(tens.shape) == (len(op.inputs[0].shape) + n) + op.attrs["new_axis_mask"] = 0 else: axis = int(op.attrs["axis"]) op.type = "UnpackReshaped" - - desired_shape = tens.shape[:axis] + [1] + tens.shape[axis:] + reshape_input_shape = tens.shape[:axis] + [1] + tens.shape[axis:] # Construct 1 shape tensor to be used by all inserted reshape ops new_shape_name = op.name + "_reshape_shape" @@ -239,7 +265,7 @@ def fixup_unpack_output(tens, arch): reshape_op = Operation("Reshape", reshape_name) reshape_op.outputs = [out_tens] reshape_in = out_tens.clone("_reshaped") - reshape_in.shape = reshape_in.storage_shape = reshape_in.bandwidth_shape = desired_shape + reshape_in.shape = reshape_in.storage_shape = reshape_in.bandwidth_shape = reshape_input_shape reshape_in.ops = [op] out_tens.ops = [reshape_op] reshape_op.inputs = [reshape_in, new_shape_tens] diff --git a/ethosu/vela/operation.py b/ethosu/vela/operation.py index f36e61c6..a25574a6 100644 --- a/ethosu/vela/operation.py +++ b/ethosu/vela/operation.py @@ -248,12 +248,10 @@ input and output tensors, as well as an attribute dictionary.""" end_mask = self.attrs["end_mask"] new_axis_mask = self.attrs["new_axis_mask"] shrink_axis_mask = self.attrs["shrink_axis_mask"] - # TODO: Either extend this to support these different masks or check - # for this at an earlier stage and place the op on Cpu if needed - assert new_axis_mask == ellipsis_mask == 0 - # shrink_axis_mask is not supported by the Operation class but the operation + + # 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 == 0 + assert shrink_axis_mask == new_axis_mask == ellipsis_mask == 0 assert len(input_tens.shape) == len(out_tens.shape) for idx in range(len(input_tens.shape)): diff --git a/ethosu/vela/supported_operators.py b/ethosu/vela/supported_operators.py index 1e11d788..1a25887f 100644 --- a/ethosu/vela/supported_operators.py +++ b/ethosu/vela/supported_operators.py @@ -240,8 +240,14 @@ class SupportedOperators: return True def check_memory_only_restrictions(self, op): - # check stride size if op.type == "StridedSlice": + # check stride size if len(op.inputs) > 3 and any(stride != 1 for stride in op.inputs[3].values): return False + # check ellipsis_mask + if op.attrs["ellipsis_mask"] != 0: + return False + # check if both new_axis_mask and shrink_axis_mask have bit set + if op.attrs["new_axis_mask"] != 0 and op.attrs["shrink_axis_mask"] != 0: + return False return True -- cgit v1.2.1