From fddbad1d05da8251d7002418be581cac94fe11a9 Mon Sep 17 00:00:00 2001 From: William Isaksson Date: Thu, 10 Apr 2025 11:46:19 +0200 Subject: [PATCH] MLBEDSW-10683: Port 1x1 IFM resize for Ethos-U55/U65 Adds support for 1x1 IFM resizes to Regor. Change-Id: Ia16bc65748ac5518291e1e4a78cd3b6350c7b0d5 Signed-off-by: William Isaksson --- .../ethosu55/ethos_u55_constraints.cpp | 4 +++ ethosu/regor/compiler/graphir_optimiser.cpp | 31 +++++++++++++++++++ ethosu/regor/compiler/graphir_optimiser.hpp | 2 ++ ethosu/regor/compiler/scheduler_packing.cpp | 2 +- .../regor/compiler/tflite_graph_optimiser.cpp | 17 +++++----- 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/ethosu/regor/architecture/ethosu55/ethos_u55_constraints.cpp b/ethosu/regor/architecture/ethosu55/ethos_u55_constraints.cpp index 89b061f4..5849e0be 100644 --- a/ethosu/regor/architecture/ethosu55/ethos_u55_constraints.cpp +++ b/ethosu/regor/architecture/ethosu55/ethos_u55_constraints.cpp @@ -331,6 +331,10 @@ Flags EthosU55Constraints::OperatorQuery(OpType opType, const ArchO } if ( opType == OpType::Resize ) { + if ( query->ifm[0].shape.ElementsWH() == 1 ) + { + return QueryResult::Unsupported; + } if ( req ) { req->req = ArchRequirement::Decompose; diff --git a/ethosu/regor/compiler/graphir_optimiser.cpp b/ethosu/regor/compiler/graphir_optimiser.cpp index c0a919e3..d0296632 100644 --- a/ethosu/regor/compiler/graphir_optimiser.cpp +++ b/ethosu/regor/compiler/graphir_optimiser.cpp @@ -2216,6 +2216,37 @@ Operation *GraphIrOptimiser::RewriteArgmax(Graph *const graph, Operation *const return returnOp; } +// Rewrite 1x1 Resize to Add op with input broadcasted to OFM +Operation *GraphIrOptimiser::RewriteResize(Graph *const, Operation *const operation) +{ + if ( operation->Type() != OpType::Resize ) + { + return operation; + } + auto *ifmConn = operation->Input(TensorUsage::IFM); + + ArchOperatorQuery query; + query.ifm[0].shape = ifmConn->shape; + if ( !_constraints->OperatorQuery(OpType::Resize, &query).Any(QueryResult::Unsupported) || ifmConn->shape.ElementsWH() != 1 ) + { + return operation; + } + + auto *ofmConn = operation->Output(TensorUsage::OFM); + auto dtype = ofmConn->tensor->Type(); + int zp = ifmConn->quantization.zeroPoints.empty() ? 0 : ifmConn->quantization.zeroPoints[0]; + + std::vector zeroVector(DataTypeStorageSizeBytes(dtype, ofmConn->shape.Elements()), zp); + auto zeroBuffer = std::make_shared(std::move(zeroVector)); + auto zeroTensor = CreateConstTensor("const_zeros", dtype, zeroBuffer, &ofmConn->shape); + + auto copyOp = std::make_shared(OpType::Add); + ReplaceOperation(operation, copyOp.get()); + copyOp->ConnectInput(TensorUsage::IFM1, zeroTensor).Set(copyOp->Input(TensorUsage::IFM)->quantization); + RecordOptimisation(operation, copyOp.get()); + return copyOp.get(); +} + // Move Split/slice op to consumer void GraphIrOptimiser::MoveToConsumer(const Operation *const operation, Operation *const cons) { diff --git a/ethosu/regor/compiler/graphir_optimiser.hpp b/ethosu/regor/compiler/graphir_optimiser.hpp index 59037ce7..c9f4c28a 100644 --- a/ethosu/regor/compiler/graphir_optimiser.hpp +++ b/ethosu/regor/compiler/graphir_optimiser.hpp @@ -60,6 +60,7 @@ private: Operation *RewriteNegate(Graph *const graph, Operation *const operation); Operation *RewriteSelect(Graph *const graph, Operation *const operation); Operation *RewriteReduceSum(Graph *const graph, Operation *const operation); + Operation *RewriteResize(Graph *const graph, Operation *const operation); Operation *RewriteTile(Graph *const graph, Operation *const operation); Operation *RewriteMatmul(Graph *const graph, Operation *const operation); Operation *RewriteArgmax(Graph *const graph, Operation *const operation); @@ -147,6 +148,7 @@ private: &GraphIrOptimiser::RewriteSlice, &GraphIrOptimiser::RewriteNegate, &GraphIrOptimiser::RewriteReduceSum, + &GraphIrOptimiser::RewriteResize, &GraphIrOptimiser::RewriteTile, &GraphIrOptimiser::RewriteMatmul, &GraphIrOptimiser::RewriteSelect, diff --git a/ethosu/regor/compiler/scheduler_packing.cpp b/ethosu/regor/compiler/scheduler_packing.cpp index 2e7b9cbd..ec1cd006 100644 --- a/ethosu/regor/compiler/scheduler_packing.cpp +++ b/ethosu/regor/compiler/scheduler_packing.cpp @@ -629,7 +629,7 @@ std::unique_ptr SchedulerPacking::MakeSchedulerOperation(Ope } // Adjust axis attribute if tensors have been reshaped - if ( schedOp->HasAttribute() ) + if ( schedOp->Type() != OpType::Passthrough && schedOp->HasAttribute() ) { auto attr = schedOp->Attribute(); int paddedAxes = schedOp->Output(TensorUsage::OFM)->shape.Size() - op->Output(TensorUsage::OFM)->shape.Size(); diff --git a/ethosu/regor/compiler/tflite_graph_optimiser.cpp b/ethosu/regor/compiler/tflite_graph_optimiser.cpp index ce1369f4..78fb7a95 100644 --- a/ethosu/regor/compiler/tflite_graph_optimiser.cpp +++ b/ethosu/regor/compiler/tflite_graph_optimiser.cpp @@ -1193,13 +1193,16 @@ Operation *TFLiteGraphOptimiser::ConvertResize(Graph *const graph, Operation *co } // Set explicit scaling - Quantization ofmQuant = ofmConn->quantization; - ofmQuant.scales.clear(); - ofmQuant.zeroPoints.clear(); - ofmQuant.scales.emplace_back(QuantizedScale(1, shift)); - ofmQuant.zeroPoints.emplace_back(0); - ofmQuant.type = QuantizationType::EXPLICIT; - resizeOp->Output(TensorUsage::OFM)->Set(ofmQuant); + Quantization quant = ofmConn->quantization; + quant.scales.clear(); + quant.zeroPoints.clear(); + quant.scales.emplace_back(QuantizedScale(1, shift)); + quant.zeroPoints.emplace_back(0); + quant.type = QuantizationType::EXPLICIT; + resizeOp->Output(TensorUsage::OFM)->Set(quant); + // IFM and OFM must have same quantization for Resize ops, except for down-shift required for TOSA legalisation + quant.scales[0] = QuantizedScale(1, 0); + resizeOp->Input(TensorUsage::IFM)->Set(quant); RecordOptimisation(operation, resizeOp.get()); returnOp = resizeOp.get(); -- GitLab