From 3c5cfe9e110b402f60fa7e1cdd5aa5e1c31bd511 Mon Sep 17 00:00:00 2001 From: Tim Hall Date: Wed, 16 Mar 2022 16:31:57 +0000 Subject: MLBEDSW-6298: MLCE: Unable to find a valid block config - Fixed a bug due to ResizeBilinear modifying the attributes of a shared IFM - The ifm_resampling_mode is now an attribute of an operator rather than a tensor - Changed all calls to try_block_config() to use the attribute rather than recalculating it in multiple places Signed-off-by: Tim Hall Change-Id: I4641e9cd6b049bd4186776d98e3e751c5e5bcc06 --- ethosu/vela/high_level_command_to_npu_op.py | 22 ++++++++++------------ ethosu/vela/operation.py | 3 +++ ethosu/vela/scheduler.py | 2 +- ethosu/vela/tensor.py | 3 --- ethosu/vela/tflite_graph_optimiser.py | 7 +++---- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/ethosu/vela/high_level_command_to_npu_op.py b/ethosu/vela/high_level_command_to_npu_op.py index f7c91aa2..c8221320 100644 --- a/ethosu/vela/high_level_command_to_npu_op.py +++ b/ethosu/vela/high_level_command_to_npu_op.py @@ -49,6 +49,7 @@ from .architecture_features import ArchitectureFeatures from .data_type import DataType from .debug_database import DebugDatabase from .errors import UnsupportedFeatureError +from .ethos_u55_regs.ethos_u55_regs import resampling_mode from .high_level_command_stream import Box from .high_level_command_stream import Command from .high_level_command_stream import DMA @@ -104,6 +105,14 @@ elementwise_op_map = { } +# inverse of the resampling_mode_map in the register command stream generator +resampling_mode_inv_map = { + resampling_mode.NONE: NpuResamplingMode.NONE, + resampling_mode.NEAREST: NpuResamplingMode.NEAREST, + resampling_mode.TRANSPOSE: NpuResamplingMode.TRANSPOSE, +} + + def ifm_ifm2_correct_order(ifm_shape: List[int], ifm2_shape: List[int]) -> bool: if ifm_shape == []: # Scalar needs to be in IFM2 @@ -193,17 +202,6 @@ def get_mem_limits_for_regions(arch: ArchitectureFeatures) -> Dict[int, int]: return mem_limits -def get_upscale(op: Operation) -> NpuResamplingMode: - upscale = NpuResamplingMode.NONE - if op.type == Op.ResizeBilinear: - # perform nearest neighbor upscale - upscale = NpuResamplingMode.NEAREST - elif op.type == Op.Conv2DBackpropInputSwitchedBias: - # perform insert zero upscale - upscale = NpuResamplingMode.TRANSPOSE - return upscale - - def get_double_buffer_offset(arch: ArchitectureFeatures, range_index: int, core: int) -> int: """Returns 0 if the first half of a double buffer should be used, 1 if the second half should be used""" return ((range_index - core) // arch.ncores) % 2 @@ -409,7 +407,7 @@ def set_common_op_fields(npu_op: NpuBlockOperation, cmd: NpuStripe, arch: Archit if not op.type.is_elementwise_op(): npu_op.padding = create_padding(cmd, op) npu_op.kernel = to_npu_kernel(op.kernel) - npu_op.ifm_upscale = get_upscale(op) + npu_op.ifm_upscale = resampling_mode_inv_map[op.ifm_resampling_mode] return npu_op diff --git a/ethosu/vela/operation.py b/ethosu/vela/operation.py index 5a6423d8..d5b92d8d 100644 --- a/ethosu/vela/operation.py +++ b/ethosu/vela/operation.py @@ -31,6 +31,7 @@ from typing import Union from .api import NpuRoundingMode from .errors import VelaError +from .ethos_u55_regs.ethos_u55_regs import resampling_mode from .numeric_util import full_shape from .shape4d import Shape4D @@ -488,6 +489,7 @@ class Operation: "low_precision_scaling", "write_offset", "write_shape", + "ifm_resampling_mode", ) def __init__(self, op_type: Op, name: str): @@ -530,6 +532,7 @@ class Operation: # E.g. an operation that only fills the bottom row of an OFM of size 1x10x8x1 would have # write_offset 0,9,0,0, write_shape 1,1,8,1 self.write_shape: Optional[Shape4D] = None + self.ifm_resampling_mode: resampling_mode = resampling_mode.NONE def clone(self, suffix="_clone"): res = Operation(self.type, self.name + suffix) diff --git a/ethosu/vela/scheduler.py b/ethosu/vela/scheduler.py index 73133bcd..e8e49092 100644 --- a/ethosu/vela/scheduler.py +++ b/ethosu/vela/scheduler.py @@ -170,7 +170,7 @@ class SchedulerOperation: self.op_type = ps.primary_op.type self.activation = ps.primary_op.activation self.kernel = ps.primary_op.kernel - self.resampling_mode = ps.primary_op.ifm.resampling_mode + self.resampling_mode = ps.primary_op.ifm_resampling_mode self.uses_scalar = ps.primary_op.ifm2 is not None and ( ps.primary_op.ifm.shape == [] or ps.primary_op.ifm2.shape == [] ) diff --git a/ethosu/vela/tensor.py b/ethosu/vela/tensor.py index 19016a0f..783f459e 100644 --- a/ethosu/vela/tensor.py +++ b/ethosu/vela/tensor.py @@ -36,7 +36,6 @@ from .data_type import BaseType from .data_type import DataType from .errors import UnsupportedFeatureError from .errors import VelaError -from .ethos_u55_regs.ethos_u55_regs import resampling_mode from .numeric_util import full_shape from .operation import Op from .operation import Operation @@ -367,7 +366,6 @@ class Tensor: "element_size_bytes", "block_traversal", "equivalence_id", - "resampling_mode", "src_tensor", "needs_linear_format", "ifm_write_protected", @@ -414,7 +412,6 @@ class Tensor: # quantization parameters self.quantization: Optional[QuantizationParameters] = None self.block_traversal: TensorBlockTraversal = TensorBlockTraversal.Default - self.resampling_mode: resampling_mode = resampling_mode.NONE self.needs_linear_format = True self.ifm_write_protected = False diff --git a/ethosu/vela/tflite_graph_optimiser.py b/ethosu/vela/tflite_graph_optimiser.py index 576ead03..fb8a08c0 100644 --- a/ethosu/vela/tflite_graph_optimiser.py +++ b/ethosu/vela/tflite_graph_optimiser.py @@ -268,7 +268,7 @@ def fixup_conv2d_backprop(op, arch, nng): # flip the inputs op.inputs[0], op.inputs[2] = op.inputs[2], op.inputs[0] op.type = Op.Conv2DBackpropInputSwitchedBias - op.ifm.resampling_mode = resampling_mode.TRANSPOSE + op.ifm_resampling_mode = resampling_mode.TRANSPOSE # Update strides op.attrs.update({"stride_w": 1, "stride_h": 1, "strides": (1, 1, 1, 1)}) @@ -312,7 +312,7 @@ def convert_resizebilinear_to_nearest_neighbor_upscaling_and_pool(op): else: shape_modifier = 0 op.attrs["padding"] = Padding.SAME - op.inputs[0].resampling_mode = resampling_mode.NEAREST + op.ifm_resampling_mode = resampling_mode.NEAREST upscaled_shape = np.array(op.ifm_shapes[0].get_hw_as_list()) out_shape = np.array(op.ofm_shapes[0].get_hw_as_list()) @@ -1128,7 +1128,6 @@ def convert_pad(op: Operation, arch, nng): def add_attrs_to_resizebilinear(op, arch, nng): if op.type == Op.ResizeBilinear and op.run_on_npu: - input_tensor = op.inputs[0] input_shape = op.ifm_shapes[0] upscaled_height = input_shape.height * 2 upscaled_width = input_shape.width * 2 @@ -1147,7 +1146,7 @@ def add_attrs_to_resizebilinear(op, arch, nng): op.attrs["padding"] = Padding.VALID else: return op - input_tensor.resampling_mode = resampling_mode.NEAREST + op.ifm_resampling_mode = resampling_mode.NEAREST op.attrs.update({"strides": (1, 1, 1, 1), "ksize": (1, 2, 2, 1)}) return op -- cgit v1.2.1