From 8b52522fc32f3a5f05b2f7bab1707d7f3fd47286 Mon Sep 17 00:00:00 2001 From: Jacob Bohlin Date: Mon, 6 Jan 2025 20:17:36 +0000 Subject: [PATCH] MLBEDSW-8927 Extend PAD/MIRROR_PAD support to 3D tensors Created utility functions for getting the padding values for different axes which are not dependent on the input tensor being 4-dimensional. Change-Id: If3398f7e665f5dae39b184efecbb8caed439f225 Signed-off-by: Jacob Bohlin --- .../regor/compiler/tflite_graph_optimiser.cpp | 84 ++++++++++--------- .../regor/compiler/tflite_graph_optimiser.hpp | 14 ++++ ethosu/vela/tflite_graph_optimiser.py | 8 +- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/ethosu/regor/compiler/tflite_graph_optimiser.cpp b/ethosu/regor/compiler/tflite_graph_optimiser.cpp index d4ff52e0..fc805e15 100644 --- a/ethosu/regor/compiler/tflite_graph_optimiser.cpp +++ b/ethosu/regor/compiler/tflite_graph_optimiser.cpp @@ -2514,6 +2514,27 @@ Operation *TFLiteGraphOptimiser::ConvertRSqrtToLUT(Graph *const graph, Operation return returnOp; } +int TFLiteGraphOptimiser::GetPadValue(BufferReader &padValues, int numPadValues, PadAxis axis) +{ + int index = numPadValues - static_cast(axis); + return index < 0 ? 0 : padValues[index]; +} + +BufferReader TFLiteGraphOptimiser::GetPadValuesFromTensor(const std::shared_ptr tensor) +{ + BufferReader padValues; + if ( tensor->Type() == DataType::Int32 ) + { + padValues = tensor->View().Values(); + } + else + { + assert(tensor->Type() == DataType::Int64); + padValues = tensor->View().Values(); + } + return padValues; +} + // Based on explicit padding provided in a PAD operation, returns adjusted value for // padAfter that provides equivalent results when used with explicit padding int TFLiteGraphOptimiser::CalcPadAfter(int inputSize, int stride, int filterSize, int padBefore, int padAfter) @@ -2551,11 +2572,14 @@ Operation *TFLiteGraphOptimiser::ReplacePadByExplicitPadding(Graph *const graph, { return operation; } - const auto padValues = padOp->Input(MakeTensorUsage(TensorUsage::Params, 0))->tensor->View().Values(); - int top = padValues[2]; - int bottom = padValues[3]; - int left = padValues[4]; - int right = padValues[5]; + auto padTensor = padOp->Input(TensorUsage::Params)->tensor; + BufferReader padValues = GetPadValuesFromTensor(padTensor); + int numPadValues = padTensor->View().Elements(); + int top = GetPadValue(padValues, numPadValues, PadAxis::Top); + int bottom = GetPadValue(padValues, numPadValues, PadAxis::Bottom); + int left = GetPadValue(padValues, numPadValues, PadAxis::Left); + int right = GetPadValue(padValues, numPadValues, PadAxis::Right); + const auto &k = operation->Kernel(); const auto &kwh = k->DilatedWH(); if ( left + right >= kwh.x || top + bottom >= kwh.y ) @@ -2614,24 +2638,15 @@ Operation *TFLiteGraphOptimiser::ConvertPad(Graph *const graph, Operation *const const auto &ofmConn = operation->Output(TensorUsage::OFM); const auto &ofmShape = ofmConn->shape; const auto ¶msConn = operation->Input(TensorUsage::Params); - BufferReader padValues; - if ( paramsConn->tensor->Type() == DataType::Int32 ) - { - padValues = paramsConn->tensor->View().Values(); - } - else - { - assert(paramsConn->tensor->Type() == DataType::Int64); - padValues = paramsConn->tensor->View().Values(); - } - auto pads = paramsConn->tensor->View().Elements(); - auto padValue = [&](int index) { return (pads > index) ? padValues[index] : 0; }; - int top = padValue(2); - int bottom = padValue(3); - int left = padValue(4); - int right = padValue(5); - int near = padValue(6); - int far = padValue(7); + + BufferReader padValues = GetPadValuesFromTensor(paramsConn->tensor); + int numPadValues = paramsConn->tensor->View().Elements(); + int top = GetPadValue(padValues, numPadValues, PadAxis::Top); + int bottom = GetPadValue(padValues, numPadValues, PadAxis::Bottom); + int left = GetPadValue(padValues, numPadValues, PadAxis::Left); + int right = GetPadValue(padValues, numPadValues, PadAxis::Right); + int near = GetPadValue(padValues, numPadValues, PadAxis::Near); + int far = GetPadValue(padValues, numPadValues, PadAxis::Far); // Create MemoryCopy op that copies IFM to the right place inside the OFM Shape shp0 = ofmShape.WithZeros(); @@ -2706,22 +2721,13 @@ Operation *TFLiteGraphOptimiser::ConvertMirrorPad(Graph *const graph, Operation const auto &ofmConn = operation->Output(TensorUsage::OFM); const auto &ofmShape = ofmConn->shape; const auto ¶msConn = operation->Input(TensorUsage::Params); - BufferReader padValues; - if ( paramsConn->tensor->Type() == DataType::Int32 ) - { - padValues = paramsConn->tensor->View().Values(); - } - else - { - assert(paramsConn->tensor->Type() == DataType::Int64); - padValues = paramsConn->tensor->View().Values(); - } - auto pads = paramsConn->tensor->View().Elements(); - auto padValue = [&](int index) { return (pads > index) ? padValues[index] : 0; }; - int top = padValue(2); - int bottom = padValue(3); - int left = padValue(4); - int right = padValue(5); + + BufferReader padValues = GetPadValuesFromTensor(paramsConn->tensor); + int numPadValues = paramsConn->tensor->View().Elements(); + int top = GetPadValue(padValues, numPadValues, PadAxis::Top); + int bottom = GetPadValue(padValues, numPadValues, PadAxis::Bottom); + int left = GetPadValue(padValues, numPadValues, PadAxis::Left); + int right = GetPadValue(padValues, numPadValues, PadAxis::Right); auto *attr = operation->Attribute(); assert((attr->mode >= tflite::MirrorPadMode::MIN) && (attr->mode <= tflite::MirrorPadMode::MAX)); diff --git a/ethosu/regor/compiler/tflite_graph_optimiser.hpp b/ethosu/regor/compiler/tflite_graph_optimiser.hpp index 92b6922c..e76ff4dd 100644 --- a/ethosu/regor/compiler/tflite_graph_optimiser.hpp +++ b/ethosu/regor/compiler/tflite_graph_optimiser.hpp @@ -45,6 +45,16 @@ static double ClampSigmoid8(double value) return ClampSigmoid(value, 8.0); }; +enum class PadAxis : int +{ + Top = 6, + Bottom = 5, + Left = 4, + Right = 3, + Near = 2, + Far = 1, +}; + /// /// TFLite Graph optimiser /// @@ -136,6 +146,10 @@ private: // Converts RSqrt to a LUT based solution. Operation *ConvertRSqrtToLUT(Graph *const graph, Operation *const operation); + int GetPadValue(BufferReader &padValues, int dimensions, PadAxis axis); + + BufferReader GetPadValuesFromTensor(const std::shared_ptr tensor); + // Based on explicit padding provided in a PAD operation, returns adjusted value for // padAfter that provides equivalent results when used with explicit padding int CalcPadAfter(int inputSize, int stride, int filterSize, int padBefore, int padAfter); diff --git a/ethosu/vela/tflite_graph_optimiser.py b/ethosu/vela/tflite_graph_optimiser.py index 7103edeb..18bc1a23 100644 --- a/ethosu/vela/tflite_graph_optimiser.py +++ b/ethosu/vela/tflite_graph_optimiser.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2020-2024 Arm Limited and/or its affiliates +# SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates # # SPDX-License-Identifier: Apache-2.0 # @@ -1916,15 +1916,15 @@ def convert_mirror_pad(op: Operation, arch, nng): if op.type != Op.MirrorPad or not op.run_on_npu: return op - _, (top, bot), (left, right), _ = op.ifm2.values + top, left, bot, right, _, _ = get_pad_values_from_input(op.ifm2.values) mode = op.attrs["mode"] # 0 = reflect, 1 = symmetric ifm = op.ifm ofm = op.ofm ofm.ops = [] elem_size = 2 if ofm.dtype == DataType.int16 else 1 - n, h, w, c = ifm.shape - _, oh, ow, _ = ofm.shape + n, h, w, c = Shape4D(ifm.shape) + _, oh, ow, _ = Shape4D(ofm.shape) # Force linear format on OFM to allow negative stride multipliers ofm.force_linear_format = True -- GitLab