diff options
-rw-r--r-- | delegate/TensorFlowLiteDelegateSupport.md | 4 | ||||
-rw-r--r-- | delegate/src/Activation.hpp | 24 | ||||
-rw-r--r-- | delegate/src/test/ActivationTest.cpp | 98 | ||||
-rw-r--r-- | delegate/src/test/ActivationTestHelper.hpp | 36 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TensorFlowLiteSupport.md | 4 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TfLiteParser.cpp | 14 | ||||
-rw-r--r-- | src/armnnTfLiteParser/TfLiteParser.hpp | 1 | ||||
-rw-r--r-- | src/armnnTfLiteParser/test/Activations.cpp | 12 |
8 files changed, 156 insertions, 37 deletions
diff --git a/delegate/TensorFlowLiteDelegateSupport.md b/delegate/TensorFlowLiteDelegateSupport.md index c334018e49..7531834643 100644 --- a/delegate/TensorFlowLiteDelegateSupport.md +++ b/delegate/TensorFlowLiteDelegateSupport.md @@ -24,6 +24,8 @@ The Arm NN SDK TensorFlow Lite delegate currently supports the following operato * EQUAL +* ELU + * EXP * FULLY_CONNECTED, Supported Fused Activation: RELU , RELU6 , TANH, NONE @@ -34,6 +36,8 @@ The Arm NN SDK TensorFlow Lite delegate currently supports the following operato * GREATER_OR_EQUAL +* HARD_SWISH + * LESS * LESS_OR_EQUAL diff --git a/delegate/src/Activation.hpp b/delegate/src/Activation.hpp index b50854aca5..5f14e2c45c 100644 --- a/delegate/src/Activation.hpp +++ b/delegate/src/Activation.hpp @@ -49,21 +49,14 @@ TfLiteStatus VisitActivationOperator(DelegateData& delegateData, const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors; const TfLiteTensor& tfLiteInputTensor = tfLiteTensors[tfLiteNode->inputs->data[0]]; - if (IsDynamicTensor(tfLiteInputTensor)) + if (!IsValid(tfLiteContext, tfLiteInputTensor, operatorCode, nodeIndex)) { - TF_LITE_MAYBE_KERNEL_LOG( - tfLiteContext, - "TfLiteArmnnDelegate: Dynamic input tensors are not supported in node #%d: ", - nodeIndex); return kTfLiteError; } + const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]]; - if (IsDynamicTensor(tfLiteOutputTensor)) + if (!IsValid(tfLiteContext, tfLiteOutputTensor, operatorCode, nodeIndex)) { - TF_LITE_MAYBE_KERNEL_LOG( - tfLiteContext, - "TfLiteArmnnDelegate: Dynamic output tensors are not supported in node #%d: ", - nodeIndex); return kTfLiteError; } @@ -96,6 +89,17 @@ TfLiteStatus VisitActivationOperator(DelegateData& delegateData, activationDesc.m_B = 1.0f; break; } + case kTfLiteBuiltinElu: + { + activationDesc.m_Function = armnn::ActivationFunction::Elu; + activationDesc.m_A = 1.0f; + break; + } + case kTfLiteBuiltinHardSwish: + { + activationDesc.m_Function = armnn::ActivationFunction::HardSwish; + break; + } default: { return kTfLiteError; diff --git a/delegate/src/test/ActivationTest.cpp b/delegate/src/test/ActivationTest.cpp index f894d67372..69041d77a2 100644 --- a/delegate/src/test/ActivationTest.cpp +++ b/delegate/src/test/ActivationTest.cpp @@ -22,7 +22,6 @@ namespace armnnDelegate void ActivationReLuTest(std::vector<armnn::BackendId>& backends) { - std::vector<float> inputData = { -0.1f, -0.2f, -0.3f, -0.4f, 0.1f, 0.2f, 0.3f, 0.4f, @@ -116,6 +115,64 @@ void ActivationTanHTest(std::vector<armnn::BackendId>& backends) outputExpectedData); } +void ActivationEluTest(std::vector<armnn::BackendId>& backends) +{ + std::vector<float> inputData = { + -0.1f, -0.2f, -0.3f, -0.4f, + 0.1f, 0.2f, 0.3f, 0.4f, + -1.0f, -2.0f, -3.0f, -4.0f, + 1.0f, 2.0f, 3.0f, 4.0f + }; + + // Calculate output values for input. + auto f = [](float value) + { + if (value < 0) + { + // alpha * (exp(x) - 1) + return 1 * (std::exp(value) - 1); + } + return value; + }; + std::vector<float> outputExpectedData(inputData.size()); + std::transform(inputData.begin(), inputData.end(), outputExpectedData.begin(), f); + + ActivationTest(tflite::BuiltinOperator_ELU, + backends, + inputData, + outputExpectedData); +} + +void ActivationHardSwishTest(std::vector<armnn::BackendId>& backends) +{ + std::vector<float> inputData = { + -0.1f, -0.2f, -0.3f, -0.4f, + 0.1f, 0.2f, 0.3f, 0.4f, + -1.0f, -2.0f, -3.0f, -4.0f, + 1.0f, 2.0f, 3.0f, 4.0f + }; + + // Calculate output values for input. + auto f = [](float x) + { + // Break down the calculation to help with verification. + // hard_swish(x) = x * relu6(x+3) / 6 + // relu6(x) = min(max(x,0),6) + float reLu6_step1 = std::max((x + 3),0.0f); + float reLu6Complete = std::min(reLu6_step1, 6.0f); + float hardSwish_step1 = x * reLu6Complete; + float result = hardSwish_step1 / 6; + return result; + }; + std::vector<float> outputExpectedData(inputData.size()); + std::transform(inputData.begin(), inputData.end(), outputExpectedData.begin(), f); + + ActivationTest(tflite::BuiltinOperator_HARD_SWISH, + backends, + inputData, + outputExpectedData); +} + TEST_SUITE("Activation_CpuRefTests") { @@ -137,13 +194,24 @@ TEST_CASE ("Activation_Sigmoid_CpuRef_Test") ActivationSigmoidTest(backends); } - TEST_CASE ("Activation_TanH_CpuRef_Test") { std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; ActivationTanHTest(backends); } +TEST_CASE ("Activation_Elu_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + ActivationEluTest(backends); +} + +TEST_CASE ("Activation_HardSwish_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + ActivationHardSwishTest(backends); +} + } TEST_SUITE("Activation_CpuAccTests") @@ -167,13 +235,24 @@ TEST_CASE ("Activation_Sigmoid_CpuAcc_Test") ActivationSigmoidTest(backends); } - TEST_CASE ("Activation_TanH_CpuAcc_Test") { std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc }; ActivationTanHTest(backends); } +TEST_CASE ("Activation_Elu_CpuAcc_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc }; + ActivationEluTest(backends); +} + +TEST_CASE ("Activation_HardSwish_CpuAcc_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc }; + ActivationHardSwishTest(backends); +} + } TEST_SUITE("Activation_GpuAccTests") @@ -197,13 +276,24 @@ TEST_CASE ("Activation_Sigmoid_GpuAcc_Test") ActivationSigmoidTest(backends); } - TEST_CASE ("Activation_TanH_GpuAcc_Test") { std::vector<armnn::BackendId> backends = { armnn::Compute::GpuAcc }; ActivationTanHTest(backends); } +TEST_CASE ("Activation_Elu_GpuAcc_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::GpuAcc }; + ActivationEluTest(backends); +} + +TEST_CASE ("Activation_HardSwish_GpuAcc_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::GpuAcc }; + ActivationHardSwishTest(backends); +} + } } // namespace armnnDelegate
\ No newline at end of file diff --git a/delegate/src/test/ActivationTestHelper.hpp b/delegate/src/test/ActivationTestHelper.hpp index 2368a36931..0f4d944685 100644 --- a/delegate/src/test/ActivationTestHelper.hpp +++ b/delegate/src/test/ActivationTestHelper.hpp @@ -5,6 +5,8 @@ #pragma once +#include "TestUtils.hpp" + #include <armnn_delegate.hpp> #include <flatbuffers/flatbuffers.h> @@ -79,7 +81,7 @@ void ActivationTest(tflite::BuiltinOperator activationOperatorCode, std::vector<float>& expectedOutputValues) { using namespace tflite; - const std::vector<int32_t> inputShape { { 4, 1, 4} }; + std::vector<int32_t> inputShape { { 4, 1, 4} }; std::vector<char> modelBuffer = CreateActivationTfLiteModel(activationOperatorCode, ::tflite::TensorType_FLOAT32, inputShape); @@ -108,33 +110,21 @@ void ActivationTest(tflite::BuiltinOperator activationOperatorCode, CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk); // Set input data - auto tfLiteDelegateInputId = tfLiteInterpreter->inputs()[0]; - auto tfLiteDelageInputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateInputId); - for (unsigned int i = 0; i < inputValues.size(); ++i) - { - tfLiteDelageInputData[i] = inputValues[i]; - } - - auto armnnDelegateInputId = armnnDelegateInterpreter->inputs()[0]; - auto armnnDelegateInputData = armnnDelegateInterpreter->typed_tensor<float>(armnnDelegateInputId); - for (unsigned int i = 0; i < inputValues.size(); ++i) - { - armnnDelegateInputData[i] = inputValues[i]; - } + armnnDelegate::FillInput<float>(tfLiteInterpreter, 0, inputValues); + armnnDelegate::FillInput<float>(armnnDelegateInterpreter, 0, inputValues); + // Run EnqueWorkload CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk); CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk); // Compare output data - auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[0]; - auto tfLiteDelageOutputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId); - auto armnnDelegateOutputId = armnnDelegateInterpreter->outputs()[0]; - auto armnnDelegateOutputData = armnnDelegateInterpreter->typed_tensor<float>(armnnDelegateOutputId); - for (size_t i = 0; i < inputValues.size(); i++) - { - CHECK(expectedOutputValues[i] == doctest::Approx(armnnDelegateOutputData[i])); - CHECK(tfLiteDelageOutputData[i] == doctest::Approx(armnnDelegateOutputData[i])); - } + armnnDelegate::CompareOutputData<float>(tfLiteInterpreter, + armnnDelegateInterpreter, + inputShape, + expectedOutputValues); + + tfLiteInterpreter.reset(nullptr); + armnnDelegateInterpreter.reset(nullptr); } } // anonymous namespace
\ No newline at end of file diff --git a/src/armnnTfLiteParser/TensorFlowLiteSupport.md b/src/armnnTfLiteParser/TensorFlowLiteSupport.md index faad3d0fa9..118fed7f7c 100644 --- a/src/armnnTfLiteParser/TensorFlowLiteSupport.md +++ b/src/armnnTfLiteParser/TensorFlowLiteSupport.md @@ -22,10 +22,14 @@ The Arm NN SDK TensorFlow Lite parser currently supports the following operators * DIV +* ELU + * EXP * FULLY_CONNECTED, Supported Fused Activation: RELU , RELU6 , TANH, NONE +* HARD_SWISH + * LEAKY_RELU * LOGISTIC diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index c3d56b13d3..9d9f4fa14b 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -549,6 +549,7 @@ TfLiteParser::TfLiteParser(const Optional<ITfLiteParser::TfLiteParserOptions>& o m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParser::ParseCustomOperator; m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParser::ParseDepthwiseConv2D; m_ParserFunctions[tflite::BuiltinOperator_DEQUANTIZE] = &TfLiteParser::ParseDequantize; + m_ParserFunctions[tflite::BuiltinOperator_ELU] = &TfLiteParser::ParseElu; m_ParserFunctions[tflite::BuiltinOperator_EXP] = &TfLiteParser::ParseExp; m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED] = &TfLiteParser::ParseFullyConnected; m_ParserFunctions[tflite::BuiltinOperator_HARD_SWISH] = &TfLiteParser::ParseHardSwish; @@ -1928,6 +1929,11 @@ void TfLiteParser::ParseTanH(size_t subgraphIndex, size_t operatorIndex) ParseActivation(subgraphIndex,operatorIndex,ActivationFunction::TanH); } +void TfLiteParser::ParseElu(size_t subgraphIndex, size_t operatorIndex) +{ + ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::Elu); +} + void TfLiteParser::ParseHardSwish(size_t subgraphIndex, size_t operatorIndex) { ParseActivation(subgraphIndex, operatorIndex, ActivationFunction::HardSwish); @@ -1982,9 +1988,17 @@ void TfLiteParser::ParseActivation(size_t subgraphIndex, size_t operatorIndex, A activationDesc.m_A = options->alpha; break; } + case ActivationFunction::Elu: + { + layerName += fmt::format("ELU:{}:{}", subgraphIndex, operatorIndex); + activationDesc.m_A = 1.0f; + break; + } case ActivationFunction::HardSwish: + { layerName += fmt::format("HARDSWISH:{}:{}", subgraphIndex, operatorIndex); break; + } default: { throw ParseException( diff --git a/src/armnnTfLiteParser/TfLiteParser.hpp b/src/armnnTfLiteParser/TfLiteParser.hpp index 9b081a5db9..a8ddc69df8 100644 --- a/src/armnnTfLiteParser/TfLiteParser.hpp +++ b/src/armnnTfLiteParser/TfLiteParser.hpp @@ -102,6 +102,7 @@ private: void ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorIndex); void ParseDequantize(size_t subgraphIndex, size_t operatorIndex); void ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex); + void ParseElu(size_t subgraphIndex, size_t operatorIndex); void ParseExp(size_t subgraphIndex, size_t operatorIndex); void ParseFullyConnected(size_t subgraphIndex, size_t operatorIndex); void ParseHardSwish(size_t subgraphIndex, size_t operatorIndex); diff --git a/src/armnnTfLiteParser/test/Activations.cpp b/src/armnnTfLiteParser/test/Activations.cpp index e57477e620..f74c22d107 100644 --- a/src/armnnTfLiteParser/test/Activations.cpp +++ b/src/armnnTfLiteParser/test/Activations.cpp @@ -106,6 +106,18 @@ BOOST_FIXTURE_TEST_CASE(ParseTanH, TanHFixture) { -0.09966799f, -0.19737528f, -0.29131261f, -0.379949f, 0.09966799f, 0.19737528f, 0.29131261f }); } +struct EluFixture : ActivationFixture +{ + EluFixture() : ActivationFixture("ELU", "FLOAT32") {} +}; + +BOOST_FIXTURE_TEST_CASE(ParseElu, EluFixture) +{ + RunTest<2, armnn::DataType::Float32>(0, + { -2.0f, -1.0f, -0.0f, 0.0f, 1.0f, 2.0f, 3.0f }, + { -0.86466471676f, -0.63212055882f, -0.0f, 0.0f, 1.0f, 2.0f, 3.0f }); +} + struct HardSwishFixture : ActivationFixture { HardSwishFixture() : ActivationFixture("HARD_SWISH", "FLOAT32") {} |