diff options
author | Cathal Corbett <cathal.corbett@arm.com> | 2024-06-27 15:48:31 +0100 |
---|---|---|
committer | Cathal Corbett <cathal.corbett@arm.com> | 2024-06-28 16:22:45 +0100 |
commit | 443804adee542d4330713e8dda6357b9495856fa (patch) | |
tree | afd5a983f129770e09fb04672e29a611e4f6dc06 | |
parent | 66d0e7d5c6d3c271f72848a180616ebc2e3403cc (diff) | |
download | armnn-443804adee542d4330713e8dda6357b9495856fa.tar.gz |
IVGCVSW-8444 Implement Activation:BoundedReLu in TosaRef
Signed-off-by: Cathal Corbett <cathal.corbett@arm.com>
Change-Id: I8908b85bd2476432a47002ea52699afb06fc455d
-rw-r--r-- | src/backends/tosaCommon/TosaMappings.cpp | 3 | ||||
-rw-r--r-- | src/backends/tosaCommon/operatorMappings/ReluOperator.cpp | 53 | ||||
-rw-r--r-- | src/backends/tosaReference/test/TosaRefEndToEndTests.cpp | 32 |
3 files changed, 76 insertions, 12 deletions
diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp index 8608776471..bc1376b9cc 100644 --- a/src/backends/tosaCommon/TosaMappings.cpp +++ b/src/backends/tosaCommon/TosaMappings.cpp @@ -30,7 +30,8 @@ TosaSerializationBasicBlock* GetTosaMapping(const Layer* layer, { return ConvertLeakyReluToTosaOperator(layer, inputs, outputs, activationDesc); } - if (activationDesc->m_Function == ActivationFunction::ReLu) + if (activationDesc->m_Function == ActivationFunction::ReLu || + activationDesc->m_Function == ActivationFunction::BoundedReLu) { return ConvertReluToTosaOperator(layer, inputs, outputs, activationDesc); } diff --git a/src/backends/tosaCommon/operatorMappings/ReluOperator.cpp b/src/backends/tosaCommon/operatorMappings/ReluOperator.cpp index bd1a59670e..541b39cd8d 100644 --- a/src/backends/tosaCommon/operatorMappings/ReluOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/ReluOperator.cpp @@ -17,7 +17,7 @@ TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer, const std::vector<const TensorInfo*>& inputs, const std::vector<const TensorInfo*>& outputs, - const ActivationDescriptor*) + const ActivationDescriptor* desc) { if (inputs.size() != 1) { @@ -31,7 +31,36 @@ TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer, std::string inputName = std::string("input_"); std::string outputName = std::string("output0_"); - std::string blockName = std::string("Op_RELU_block_") + GetUniqueTosaMappingID(); + std::string blockName = ""; + + int32_t clamp_min = 0; + int32_t clamp_max = 0; + float float_max = 0.0f; + switch (desc->m_Function) + { + case ActivationFunction::ReLu: + { + clamp_max = std::numeric_limits<int32_t>::max(); + float_max = std::numeric_limits<float>::max(); + blockName = std::string("Op_RELU_block_") + GetUniqueTosaMappingID(); + break; + } + case ActivationFunction::BoundedReLu: + { + clamp_max = static_cast<int32_t>(desc->m_A); + float_max = desc->m_A; + blockName = std::string("Op_BOUNDED_RELU_block_") + GetUniqueTosaMappingID(); + break; + } + case ActivationFunction::LeakyReLu: + { + throw Exception("LeakyRelu TOSA mappings are performed in ConvertLeakyReluToTosaOperator()."); + } + default: + { + throw Exception("Activation function is not supported in ConvertReluToTosaOperator()."); + } + } // If a layer is present then the block will be used for execution, so input and output names need to be determined // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter. @@ -60,8 +89,6 @@ TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer, DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType()); tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {})); - int32_t clamp_min = 0; - int32_t clamp_max = std::numeric_limits<int32_t>::max(); std::string clampInputNameStr = inputName; if (inputDType0 == tosa::DType::DType_INT8 || inputDType0 == tosa::DType::DType_INT16) { @@ -72,18 +99,26 @@ TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer, int32_t input_zp = inputs[0]->GetQuantizationOffset(); int32_t output_zp = outputs[0]->GetQuantizationOffset(); - clamp_min = outputs[0]->GetQuantizationOffset(); + clamp_min = output_zp; + + if (desc->m_Function == ActivationFunction::BoundedReLu) + { + clamp_max = static_cast<int32_t>(std::round(desc->m_A / outputs[0]->GetQuantizationScale())) + output_zp; + } + if (inputDType0 == tosa::DType::DType_INT8) { clamp_min = clamp_min < std::numeric_limits<int8_t>::min() ? std::numeric_limits<int8_t>::min() : clamp_min; - clamp_max = std::numeric_limits<int8_t>::max(); + clamp_max = + clamp_max > std::numeric_limits<int8_t>::max() ? std::numeric_limits<int8_t>::max() : clamp_max; } else { clamp_min = clamp_min < std::numeric_limits<int16_t>::min() ? std::numeric_limits<int16_t>::min() : clamp_min; - clamp_max = std::numeric_limits<int16_t>::max(); + clamp_max = + clamp_max > std::numeric_limits<int16_t>::max() ? std::numeric_limits<int16_t>::max() : clamp_max; } TosaSerializationOperator* rescaleOp = nullptr; @@ -101,8 +136,8 @@ TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer, inputDType0, {})); } - - TosaClampAttribute attribute(clamp_min, clamp_max, 0, std::numeric_limits<float>::max()); + + TosaClampAttribute attribute(clamp_min, clamp_max, 0, float_max); auto* clamp_op = new TosaSerializationOperator(Op_CLAMP, Attribute_ClampAttribute, &attribute, diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp index 09a3d44c02..22fd782a1a 100644 --- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp +++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp @@ -30,25 +30,28 @@ TEST_SUITE("TosaRefEndToEnd") static std::vector<BackendId> tosaDefaultBackends = { "TosaRef" }; // Activation -//LeakyRelu +// LeakyRelu TEST_CASE("TosaRefLeakyReluActivationFloat32") { ActivationEndToEndTest<DataType::Float32>(tosaDefaultBackends, ActivationFunction::LeakyReLu, 1.f, 0, 0.01f); } + TEST_CASE("TosaRefLeakyReluActivationFloat16") { ActivationEndToEndTest<DataType::Float16>(tosaDefaultBackends, ActivationFunction::LeakyReLu, 0.3f, 5, 0.01f); } + TEST_CASE("TosaRefLeakyReluActivationInt8") { ActivationEndToEndTest<DataType::QAsymmS8>(tosaDefaultBackends, ActivationFunction::LeakyReLu, 0.6f, 7, 0.01f); } + TEST_CASE("TosaRefLeakyReluActivationInt16") { ActivationEndToEndTest<DataType::QSymmS16>(tosaDefaultBackends, ActivationFunction::LeakyReLu, 0.15f, 0, 0.01f); } -//Relu +// Relu TEST_CASE("TosaRefReLuEndToEndTestQAsymmS8") { ActivationEndToEndTest<armnn::DataType::QAsymmS8>(tosaDefaultBackends, ActivationFunction::ReLu); @@ -69,6 +72,31 @@ TEST_CASE("TosaRefReLuEndToEndTestQSymmS16") ActivationEndToEndTest<armnn::DataType::QSymmS16>(tosaDefaultBackends, ActivationFunction::ReLu); } +// BoundedRelu +TEST_CASE("TosaRefBoundedReLuEndToEndTestFloat32") +{ + ActivationEndToEndTest<armnn::DataType::Float32>( + tosaDefaultBackends, ActivationFunction::BoundedReLu, 1.0f, 0, 6.0f, 0.0f); +} + +TEST_CASE("TosaRefBoundedReLuEndToEndTestFloat16") +{ + ActivationEndToEndTest<armnn::DataType::Float16>( + tosaDefaultBackends, ActivationFunction::BoundedReLu, 1.0f, 0, 6.0f, 0.0f); +} + +TEST_CASE("TosaRefBoundedReLuEndToEndTestQAsymmS8") +{ + ActivationEndToEndTest<armnn::DataType::QAsymmS8>( + tosaDefaultBackends, ActivationFunction::BoundedReLu, 1.0f, 0, 6.0f, 0.0f); +} + +TEST_CASE("TosaRefBoundedReLuEndToEndTestQSymmS16") +{ + ActivationEndToEndTest<armnn::DataType::QSymmS16>( + tosaDefaultBackends, ActivationFunction::BoundedReLu, 1.0f, 0, 6.0f, 0.0f); +} + // Addition TEST_CASE("TosaRefAdditionEndtoEndTestFloat32") { |