diff --git a/CHANGELOG.md b/CHANGELOG.md index 717ff7cf096316efd7f8768c93cbe4e5e4fc9ab4..47bd81aaf91510fad8508c8c93520547fc58cee5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,13 +22,15 @@ main feature changes, interface changes and reported defects that have been fixed. The version numbering adheres to the [semantic versioning](https://semver.org/) scheme. -## Release 4.3.0 - 25/04/2025 +## Release 4.3.0 - 20/05/2025 **Main feature changes:** * Extended operator support: * Ethos-U85: - * TFLite: LOG + * TFLite: LOG and RELU_0_TO_1 + * Ethos-U55/Ethos-U65: + * TFLite: RELU_0_TO_1 **Interface changes:** diff --git a/SUPPORTED_OPS.md b/SUPPORTED_OPS.md index 5febbaa84a2511d52023ae1d462666cb45922448..42a030e7fcdaa52291a0c004c7a202db051874a1 100644 --- a/SUPPORTED_OPS.md +++ b/SUPPORTED_OPS.md @@ -19,7 +19,7 @@ limitations under the License. # Supported Ops This file was automatically generated by Vela using the `--supported-ops-report` parameter. -Vela version: `4.2.0` +Vela version: `4.3.0rc2.dev0+gfddbad1d.d20250520` This file complies with [**Gitiles Markdown syntax**](https://gerrit.googlesource.com/gitiles/+/HEAD/Documentation/markdown.md) @@ -62,6 +62,7 @@ Please check the supported operator list for your chosen runtime for further inf | QUANTIZE | [Generic](#tflite-generic-constraints) | | RELU | [Generic](#tflite-generic-constraints) | | RELU6 | [Generic](#tflite-generic-constraints) | +| RELU_0_TO_1 | [Generic](#tflite-generic-constraints) | | RELU_N1_TO_1 | [Generic](#tflite-generic-constraints) | | RESHAPE | [Generic](#tflite-generic-constraints), [Specific](#ethos-u55-and-ethos-u65-tflite-reshape-constraints) | | RESIZE_BILINEAR | [Generic](#tflite-generic-constraints), [Specific](#ethos-u55-and-ethos-u65-tflite-resize_bilinear-constraints) | @@ -119,6 +120,7 @@ Please check the supported operator list for your chosen runtime for further inf | QUANTIZE | [Generic](#tflite-generic-constraints) | | RELU | [Generic](#tflite-generic-constraints) | | RELU6 | [Generic](#tflite-generic-constraints) | +| RELU_0_TO_1 | [Generic](#tflite-generic-constraints) | | RELU_N1_TO_1 | [Generic](#tflite-generic-constraints) | | RESHAPE | [Generic](#tflite-generic-constraints), [Specific](#ethos-u85-tflite-reshape-constraints) | | RESIZE_BILINEAR | [Generic](#tflite-generic-constraints), [Specific](#ethos-u85-tflite-resize_bilinear-constraints) | @@ -162,7 +164,7 @@ This is a list of constraints that most operators must satisfy in order to be sc - Tensor dimensions must be in the range [1, 65535] - Per-axis quantization is only supported for the following op types: CONV_2D, DEPTHWISE_CONV_2D, FULLY_CONNECTED, TRANSPOSE_CONV - IFM Tensor batch size must be 1 - [FULLY_CONNECTED, RESHAPE, SHAPE, SLICE, SOFTMAX, SPLIT, SPLIT_V, SQUEEZE, STRIDED_SLICE, UNPACK] -- The fused activation function (if present) must be one of type: LOGISTIC, RELU, RELU6, RELU_N1_TO_1, TANH +- The fused activation function (if present) must be one of type: LOGISTIC, RELU, RELU6, RELU_0_TO_1, RELU_N1_TO_1, TANH - If a fused activation function is present, the Output tensor must be one of type: int16, int8, uint8 ## Ethos-U55 and Ethos-U65 Specific Operator constraints @@ -661,22 +663,22 @@ This is a list of constraints that the LEAKY_RELU operator must satisfy in order - At least one Input's shape must match the OFM's shape - IFM and OFM data types must match -### Ethos-U85 TFLite LOG Constraints +### Ethos-U85 TFLite MAXIMUM Constraints -This is a list of constraints that the LOG operator must satisfy in order to be scheduled on the NPU. +This is a list of constraints that the MAXIMUM operator must satisfy in order to be scheduled on the NPU. - At least one Input's shape must match the OFM's shape - IFM and OFM data types must match -- IFM must be int8 or int16 +- Both Input quantization parameters must match OFM quantization parameters +- Broadcasting is only allowed for rank indices with dimension 1, from either IFM1 or IFM2 -### Ethos-U85 TFLite MAXIMUM Constraints +### Ethos-U85 TFLite LOG Constraints -This is a list of constraints that the MAXIMUM operator must satisfy in order to be scheduled on the NPU. +This is a list of constraints that the LOG operator must satisfy in order to be scheduled on the NPU. - At least one Input's shape must match the OFM's shape - IFM and OFM data types must match -- Both Input quantization parameters must match OFM quantization parameters -- Broadcasting is only allowed for rank indices with dimension 1, from either IFM1 or IFM2 +- IFM must be int8 or int16 ### Ethos-U85 TFLite MAX_POOL_2D Constraints diff --git a/ethosu/regor/architecture/ethosu55/ethos_u55_performance.cpp b/ethosu/regor/architecture/ethosu55/ethos_u55_performance.cpp index bd6afa5f0df64aab9e338dfc663aada1b872de91..d150264b2cdc214c3708b2d5454b9c7243f40f40 100644 --- a/ethosu/regor/architecture/ethosu55/ethos_u55_performance.cpp +++ b/ethosu/regor/architecture/ethosu55/ethos_u55_performance.cpp @@ -499,7 +499,7 @@ EthosU55ElementCycles EthosU55Performance::EstimateOutputCyclesPerElement(const { activationPerfIndex = 0; } - else if ( fusedOp.type == OpType::Relu || fusedOp.type == OpType::Relu6 || fusedOp.type == OpType::ReluN1To1 ) + else if ( fusedOp.type == OpType::Relu || fusedOp.type == OpType::Relu0To1 || fusedOp.type == OpType::Relu6 || fusedOp.type == OpType::ReluN1To1 ) { activationPerfIndex = 1; } diff --git a/ethosu/regor/architecture/ethosu85/ethos_u85_performance.cpp b/ethosu/regor/architecture/ethosu85/ethos_u85_performance.cpp index 0c7c0909ac1615bdc3f9c0f653b91d875ac770d0..0b9fedf49ddbccc72af881aa06aa151bee50935a 100644 --- a/ethosu/regor/architecture/ethosu85/ethos_u85_performance.cpp +++ b/ethosu/regor/architecture/ethosu85/ethos_u85_performance.cpp @@ -408,7 +408,7 @@ EthosU85ElementCycles EthosU85Performance::EstimateOutputCyclesPerElement(const { activationPerfIndex = 0; } - else if ( fusedOp.type == OpType::Relu || fusedOp.type == OpType::Relu6 || fusedOp.type == OpType::ReluN1To1 ) + else if ( fusedOp.type == OpType::Relu || fusedOp.type == OpType::Relu0To1 || fusedOp.type == OpType::Relu6 || fusedOp.type == OpType::ReluN1To1 ) { activationPerfIndex = 1; } diff --git a/ethosu/regor/compiler/op_type.cpp b/ethosu/regor/compiler/op_type.cpp index 3d90d4b0816e197873ddf1bf720f09c5fb96db40..0a37f270238c168987d09d1423cb773c63b85e97 100644 --- a/ethosu/regor/compiler/op_type.cpp +++ b/ethosu/regor/compiler/op_type.cpp @@ -153,6 +153,7 @@ BEGIN_ENUM_TABLE(regor::OpType) ADD_ENUM_NAME(Range) ADD_ENUM_NAME(Rank) ADD_ENUM_NAME(Relu) + ADD_ENUM_NAME(Relu0To1) ADD_ENUM_NAME(Relu6) ADD_ENUM_NAME(ReluN1To1) ADD_ENUM_NAME(ReluN) diff --git a/ethosu/regor/compiler/op_type.hpp b/ethosu/regor/compiler/op_type.hpp index 77c8ef5fc1b8c3dc8adcb07d1c6f9e19348ac6af..512b0d1815061d6b3be793e661b3e6e222bb93e4 100644 --- a/ethosu/regor/compiler/op_type.hpp +++ b/ethosu/regor/compiler/op_type.hpp @@ -164,6 +164,7 @@ enum class OpType : uint16_t Range, Rank, Relu, + Relu0To1, Relu6, ReluN1To1, ReluN, @@ -211,8 +212,9 @@ inline std::string OpTypeToString(const OpType type) constexpr inline bool IsActivation(OpType opType) { - return opType == OpType::Relu || opType == OpType::Relu6 || opType == OpType::ReluN || opType == OpType::ReluN1To1 || - opType == OpType::Prelu || opType == OpType::Clamp || opType == OpType::Sigmoid || opType == OpType::Tanh || opType == OpType::LUT; + return opType == OpType::Relu || opType == OpType::Relu0To1 || opType == OpType::Relu6 || opType == OpType::ReluN || + opType == OpType::ReluN1To1 || opType == OpType::Prelu || opType == OpType::Clamp || + opType == OpType::Sigmoid || opType == OpType::Tanh || opType == OpType::LUT; } constexpr inline bool IsUnaryElementwise(OpType opType) diff --git a/ethosu/regor/compiler/tflite_graph_optimiser.cpp b/ethosu/regor/compiler/tflite_graph_optimiser.cpp index 78fb7a9550e089386a836e9c2fe9c6a424a5f845..e4a4db81697f60792629e25d45881726e234d297 100644 --- a/ethosu/regor/compiler/tflite_graph_optimiser.cpp +++ b/ethosu/regor/compiler/tflite_graph_optimiser.cpp @@ -2878,6 +2878,11 @@ Operation *TFLiteGraphOptimiser::ClampActivations(Graph *const graph, Operation { quant.quantMin = {Quantize(0, quant)}; } + else if ( opType == OpType::Relu0To1 ) + { + quant.quantMin = {Quantize(0, quant)}; + quant.quantMax = {Quantize(1, quant)}; + } else if ( opType == OpType::Relu6 ) { quant.quantMin = {Quantize(0, quant)}; diff --git a/ethosu/regor/tflite/tflite_mapping.cpp b/ethosu/regor/tflite/tflite_mapping.cpp index f4b4eec0f1a8909377322455b5b8b5d772058739..4026456f55f83bc33c077c14b84b203ddc880ce7 100644 --- a/ethosu/regor/tflite/tflite_mapping.cpp +++ b/ethosu/regor/tflite/tflite_mapping.cpp @@ -199,7 +199,8 @@ const std::map TfLiteMapping::_builtinOperatorT {tflite::BuiltinOperator::SEGMENT_SUM, OpType::SegmentSum}, {tflite::BuiltinOperator::BATCH_MATMUL, OpType::BatchMatMul}, {tflite::BuiltinOperator::CUMSUM, OpType::Cumsum}, - {tflite::BuiltinOperator::REDUCE_ALL, OpType::ReduceAll} + {tflite::BuiltinOperator::REDUCE_ALL, OpType::ReduceAll}, + {tflite::BuiltinOperator::RELU_0_TO_1, OpType::Relu0To1} // clang-format on }; @@ -557,6 +558,7 @@ const std::multimap TfLiteMapping::_inputTensorIndices = { {OpType::ReduceSum, TensorUsage::IFM0}, {OpType::ReduceSum, TensorUsage::Params}, {OpType::Relu, TensorUsage::IFM0}, + {OpType::Relu0To1, TensorUsage::IFM0}, {OpType::Relu6, TensorUsage::IFM0}, {OpType::ReluN1To1, TensorUsage::IFM0}, {OpType::ReluN, TensorUsage::IFM0}, diff --git a/ethosu/regor/tflite/tflite_supported_operators_u55.cpp b/ethosu/regor/tflite/tflite_supported_operators_u55.cpp index 156f46eee51fbec5d4fdd04806be95c916f16287..1c9fdc3c5e536eb72e1bffabee249da4dfe90978 100644 --- a/ethosu/regor/tflite/tflite_supported_operators_u55.cpp +++ b/ethosu/regor/tflite/tflite_supported_operators_u55.cpp @@ -44,8 +44,9 @@ TfLiteSupportedOperatorsU55::TfLiteSupportedOperatorsU55(IArchitectureConstraint OpType::MaxPool, OpType::Mul, OpType::Relu, - OpType::ReluN1To1, + OpType::Relu0To1, OpType::Relu6, + OpType::ReluN1To1, OpType::Reshape, OpType::Softmax, OpType::Tanh, diff --git a/ethosu/regor/tflite/tflite_supported_operators_u85.cpp b/ethosu/regor/tflite/tflite_supported_operators_u85.cpp index db231e77bbe3180586dfeff405c5b230bd603b47..b01d9809efaaf6f4b4aabd65de07a0f98680fd4d 100644 --- a/ethosu/regor/tflite/tflite_supported_operators_u85.cpp +++ b/ethosu/regor/tflite/tflite_supported_operators_u85.cpp @@ -43,8 +43,9 @@ TfLiteSupportedOperatorsU85::TfLiteSupportedOperatorsU85(IArchitectureConstraint OpType::MaxPool, OpType::Mul, OpType::Relu, - OpType::ReluN1To1, + OpType::Relu0To1, OpType::Relu6, + OpType::ReluN1To1, OpType::Reshape, OpType::ResizeBilinear, OpType::Softmax, diff --git a/ethosu/vela/npu_performance.py b/ethosu/vela/npu_performance.py index 32d0749aedad04cb93d759cdeb0b38a0fb540624..5b54e022ab1a9ed3751bdf43e6d716b5a320fba0 100644 --- a/ethosu/vela/npu_performance.py +++ b/ethosu/vela/npu_performance.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 # @@ -292,7 +292,7 @@ def _estimate_output_cycles_per_element(arch, op_type: Op, faf_type: Op, query: if faf_type in (Op.Sigmoid, Op.Tanh, Op.LUT): activation_perf_index = 0 - elif faf_type in (Op.Relu, Op.Relu6, Op.ReluN1To1): + elif faf_type in (Op.Relu, Op.Relu6, Op.Relu0To1, Op.ReluN1To1): activation_perf_index = 1 else: activation_perf_index = 2 diff --git a/ethosu/vela/operation.py b/ethosu/vela/operation.py index f9bf7fe63b21073aab7c16136894e5c0ca12a601..ba88b10d22ff78d91773036a947d5ac309b77f3c 100644 --- a/ethosu/vela/operation.py +++ b/ethosu/vela/operation.py @@ -373,7 +373,7 @@ class Op(Enum): return self.info.block_type == NpuBlockType.ElementWise and not self.info.is_unary def is_relu_op(self): - return self in (Op.Relu, Op.Relu6, Op.ReluN1To1, Op.ReluN, Op.Clip, Op.Clamp) + return self in (Op.Relu, Op.Relu6, Op.Relu0To1, Op.ReluN1To1, Op.ReluN, Op.Clip, Op.Clamp) def is_activation_op(self): return self.is_relu_op() or self in (Op.Tanh, Op.Sigmoid, Op.Softmax, Op.LUT, Op.HardSwish) @@ -454,6 +454,9 @@ def create_activation_function(op_type: Op, min=None, max=None) -> ActivationFun elif op_type == Op.Relu6: act.min = 0.0 act.max = 6.0 + elif op_type == Op.Relu0To1: + act.min = 0.0 + act.max = 1.0 elif op_type == Op.ReluN1To1: act.min = -1.0 act.max = 1.0 diff --git a/ethosu/vela/tflite_supported_operators.py b/ethosu/vela/tflite_supported_operators.py index 1fd284b43155193aa251681afd2af35de0315420..776f534cc55fa37ec2a10a9850a8d9ece03a7eac 100644 --- a/ethosu/vela/tflite_supported_operators.py +++ b/ethosu/vela/tflite_supported_operators.py @@ -126,6 +126,7 @@ class TFLiteSupportedOperators: ( Op.Relu, Op.Relu6, + Op.Relu0To1, Op.ReluN1To1, Op.Clip, ) diff --git a/ethosu/vela/vela.py b/ethosu/vela/vela.py index 55591e02c276fddaacb0b37597108a9a99a64273..3f2d0c2d746aed632dfb9e0322328ff00c4d1b16 100755 --- a/ethosu/vela/vela.py +++ b/ethosu/vela/vela.py @@ -396,6 +396,7 @@ Please check the supported operator list for your chosen runtime for further inf | QUANTIZE | [Generic](#tflite-generic-constraints) | | RELU | [Generic](#tflite-generic-constraints) | | RELU6 | [Generic](#tflite-generic-constraints) | +| RELU_0_TO_1 | [Generic](#tflite-generic-constraints) | | RELU_N1_TO_1 | [Generic](#tflite-generic-constraints) | | RESHAPE | [Generic](#tflite-generic-constraints), [Specific](#ethos-u85-tflite-reshape-constraints) | | RESIZE_BILINEAR | [Generic](#tflite-generic-constraints), [Specific](#ethos-u85-tflite-resize_bilinear-constraints) |