diff options
-rw-r--r-- | delegate/src/Control.hpp | 24 | ||||
-rw-r--r-- | delegate/src/Convolution.hpp | 63 | ||||
-rw-r--r-- | delegate/src/ElementwiseBinary.hpp | 21 | ||||
-rw-r--r-- | delegate/src/FullyConnected.hpp | 24 | ||||
-rw-r--r-- | delegate/src/Pooling.hpp | 104 | ||||
-rw-r--r-- | delegate/src/SharedFunctions.cpp | 77 | ||||
-rw-r--r-- | delegate/src/SharedFunctions.hpp | 8 |
7 files changed, 256 insertions, 65 deletions
diff --git a/delegate/src/Control.hpp b/delegate/src/Control.hpp index 02426a5616..fd1fdee940 100644 --- a/delegate/src/Control.hpp +++ b/delegate/src/Control.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -99,6 +99,12 @@ TfLiteStatus VisitConcatenationOperator(DelegateData& delegateData, uint32_t inputRank = tfLiteTensors[tfLiteNode->inputs->data[0]].dims->size; auto* concatenationParameters = reinterpret_cast<TfLiteConcatenationParams*>(tfLiteNode->builtin_data); + + if(!concatenationParameters) + { + throw armnn::Exception(&"TfLiteArmnnDelegate: Concat parameters are null in: " [ nodeIndex]); + } + const unsigned int concatDimInput = static_cast<unsigned int>( (static_cast<int>(inputRank) + concatenationParameters->axis) % static_cast<int>(inputRank)); @@ -117,6 +123,17 @@ TfLiteStatus VisitConcatenationOperator(DelegateData& delegateData, const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + // Verify we support the fused activation before attempting to create a layer + TfLiteFusedActivation activationType = concatenationParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + // Check if supported bool isSupported = false; armnn::BackendId setBackend; @@ -158,14 +175,13 @@ TfLiteStatus VisitConcatenationOperator(DelegateData& delegateData, outputSlot.SetTensorInfo(outputTensorInfo); Connect(concatenationLayer, tfLiteNode, delegateData); - if (!concatenationParameters) + if (activationType == kTfLiteActNone) { // No Activation return kTfLiteOk; } - // Check activation - TfLiteFusedActivation activationType = concatenationParameters->activation; + // Check and Create activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, concatenationLayer, 0, delegateData); } diff --git a/delegate/src/Convolution.hpp b/delegate/src/Convolution.hpp index e307bb9be3..7ea3a3a987 100644 --- a/delegate/src/Convolution.hpp +++ b/delegate/src/Convolution.hpp @@ -1,11 +1,12 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include "DelegateUtils.hpp" +#include "SharedFunctions.hpp" #include <tensorflow/lite/builtin_ops.h> #include <tensorflow/lite/c/builtin_op_data.h> @@ -100,6 +101,22 @@ TfLiteStatus VisitConv2dOperator(DelegateData& delegateData, const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor); const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + auto* tfLiteNodeParameters = reinterpret_cast<TfLiteConvParams*>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + + } + armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor); armnn::TensorInfo biasTensorInfo; @@ -198,14 +215,12 @@ TfLiteStatus VisitConv2dOperator(DelegateData& delegateData, Connect(layer, tfLiteNode, delegateData); - auto* tfLiteNodeParameters = reinterpret_cast<TfLiteConvParams*>(tfLiteNode->builtin_data); if (!tfLiteNodeParameters) { // No Activation return kTfLiteOk; } - // Check activation - TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + // Check and Create activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData); } @@ -263,6 +278,22 @@ TfLiteStatus VisitConv3dOperator(DelegateData& delegateData, const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor); const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + auto* tfLiteNodeParameters = reinterpret_cast<TfLiteConv3DParams*>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + + } + armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor); armnn::TensorInfo biasTensorInfo; @@ -362,15 +393,13 @@ TfLiteStatus VisitConv3dOperator(DelegateData& delegateData, Connect(layer, tfLiteNode, delegateData); - auto* tfLiteNodeParameters = reinterpret_cast<TfLiteConv3DParams*>(tfLiteNode->builtin_data); if (!tfLiteNodeParameters) { // No Activation return kTfLiteOk; } - // Check activation - TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + // Check and create activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData); } #endif @@ -460,6 +489,22 @@ TfLiteStatus VisitDepthwiseConv2dOperator(DelegateData& delegateData, const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor); const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + auto* tfLiteNodeParameters = reinterpret_cast<TfLiteDepthwiseConvParams *>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + + } + armnn::TensorInfo filterTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteFilterTensor); // Assuming input is NHWC @@ -553,14 +598,12 @@ TfLiteStatus VisitDepthwiseConv2dOperator(DelegateData& delegateData, outputSlot.SetTensorInfo(outputTensorInfo); Connect(layer, tfLiteNode, delegateData); - auto* tfLiteNodeParameters = reinterpret_cast<TfLiteDepthwiseConvParams*>(tfLiteNode->builtin_data); if (!tfLiteNodeParameters) { // No Activation return kTfLiteOk; } - // Check activation - TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + // Check and create activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData); } diff --git a/delegate/src/ElementwiseBinary.hpp b/delegate/src/ElementwiseBinary.hpp index caf02624be..f21d6afc28 100644 --- a/delegate/src/ElementwiseBinary.hpp +++ b/delegate/src/ElementwiseBinary.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -254,6 +254,21 @@ TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData, const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + auto* tfLiteNodeParameters = reinterpret_cast<TfLiteAddParams*>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + } + if (!delegateData.m_Network) { switch(elementwiseBinaryOperatorCode) @@ -361,14 +376,12 @@ TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData, return kTfLiteError; } - auto* tfLiteNodeParameters = reinterpret_cast<TfLiteAddParams*>(tfLiteNode->builtin_data); if (!tfLiteNodeParameters) { // No Activation return kTfLiteOk; } - // Check activation - TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + // Check and Create Activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, elementwiseBinaryLayer, 0, delegateData); } diff --git a/delegate/src/FullyConnected.hpp b/delegate/src/FullyConnected.hpp index 2243ad0e0c..ee553ce81c 100644 --- a/delegate/src/FullyConnected.hpp +++ b/delegate/src/FullyConnected.hpp @@ -57,6 +57,22 @@ TfLiteStatus VisitFullyConnectedOperator(DelegateData& delegateData, armnn::TensorInfo weightsTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteWeightsTensor); const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + // Check that we support fused activation before we attempt to create a layer + auto* tfLiteNodeParameters = reinterpret_cast<TfLiteFullyConnectedParams *>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + } + // Fully Connected Layer accepts two dimensional weights input int32_t weightsDimension = static_cast<int32_t>(weightsTensorInfo.GetNumDimensions()); if (weightsDimension != 2) @@ -221,9 +237,7 @@ TfLiteStatus VisitFullyConnectedOperator(DelegateData& delegateData, { Connect(layer, tfLiteNode, delegateData); } - - auto* tfLiteNodeParameters = reinterpret_cast<TfLiteFullyConnectedParams*>(tfLiteNode->builtin_data); - + if (outputTensorInfo.GetNumDimensions() > 2) { layer = AddReshapeLayer(tfLiteContext, tfLiteNode, layer, reshapedOutputTensorInfo, outputTensorInfo, @@ -244,8 +258,8 @@ TfLiteStatus VisitFullyConnectedOperator(DelegateData& delegateData, // No Activation return kTfLiteOk; } - // Check Activation - TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + + // Check and Create Activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, layer, 0, delegateData); } diff --git a/delegate/src/Pooling.hpp b/delegate/src/Pooling.hpp index 824156742d..d0a73b433b 100644 --- a/delegate/src/Pooling.hpp +++ b/delegate/src/Pooling.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -49,6 +49,22 @@ TfLiteStatus VisitPooling2dOperator(DelegateData& delegateData, const armnn::TensorInfo& inputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteInputTensor); const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + auto* tfLiteNodeParameters = reinterpret_cast<TfLitePoolParams*>(tfLiteNode->builtin_data); + TfLiteFusedActivation activationType; + if (tfLiteNodeParameters) + { + activationType = tfLiteNodeParameters->activation; + + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + + } + armnn::PoolingAlgorithm poolingAlgorithm; switch(tfLitePoolingOperatorCode) { @@ -68,20 +84,19 @@ TfLiteStatus VisitPooling2dOperator(DelegateData& delegateData, armnn::Pooling2dDescriptor descriptor; descriptor.m_PoolType = poolingAlgorithm; - auto* params = reinterpret_cast<TfLitePoolParams*>(tfLiteNode->builtin_data); - descriptor.m_PoolWidth = params->filter_width; - descriptor.m_PoolHeight = params->filter_height; - descriptor.m_StrideX = params->stride_width; - descriptor.m_StrideY = params->stride_height; + descriptor.m_PoolWidth = tfLiteNodeParameters->filter_width; + descriptor.m_PoolHeight = tfLiteNodeParameters->filter_height; + descriptor.m_StrideX = tfLiteNodeParameters->stride_width; + descriptor.m_StrideY = tfLiteNodeParameters->stride_height; descriptor.m_DataLayout = armnn::DataLayout::NHWC; unsigned int inputHeight = inputTensorInfo.GetShape()[1]; unsigned int inputWidth = inputTensorInfo.GetShape()[2]; CalcPadding(inputHeight, descriptor.m_PoolHeight, descriptor.m_StrideY, 1u, - descriptor.m_PadTop, descriptor.m_PadBottom, params->padding); + descriptor.m_PadTop, descriptor.m_PadBottom, tfLiteNodeParameters->padding); CalcPadding(inputWidth, descriptor.m_PoolWidth, descriptor.m_StrideX, 1u, - descriptor.m_PadLeft, descriptor.m_PadRight, params->padding); + descriptor.m_PadLeft, descriptor.m_PadRight, tfLiteNodeParameters->padding); bool isSupported = false; armnn::BackendId setBackend; @@ -112,8 +127,7 @@ TfLiteStatus VisitPooling2dOperator(DelegateData& delegateData, outputSlot.SetTensorInfo(outputTensorInfo); Connect(poolingLayer, tfLiteNode, delegateData); - // Check activation - TfLiteFusedActivation activationType = params->activation; + // Check and create activation return FusedActivation(tfLiteContext, tfLiteNode, activationType, poolingLayer, 0, delegateData); } @@ -216,36 +230,6 @@ TfLiteStatus VisitPooling3dOperator(DelegateData& delegateData, CalcPadding(inputDepth, descriptor.m_PoolDepth, descriptor.m_StrideZ, 1u, descriptor.m_PadFront, descriptor.m_PadBack, padding); - // Validate the output info. - bool isSupported = false; - armnn::BackendId setBackend; - auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported) { - FORWARD_LAYER_SUPPORT_FUNC("POOLING_3D", - tfLiteContext, - IsPooling3dSupported, - delegateData.m_Backends, - isSupported, - setBackend, - inputTensorInfo, - outputTensorInfo, - descriptor); - }; - - if (!delegateData.m_Network) - { - validateFunc(outputTensorInfo, isSupported); - return isSupported ? kTfLiteOk : kTfLiteError; - } - - // Create the Layer - armnn::IConnectableLayer* poolingLayer = delegateData.m_Network->AddPooling3dLayer(descriptor); - poolingLayer->SetBackendId(setBackend); - ARMNN_ASSERT(poolingLayer != nullptr); - - // Create and set output slots - armnn::IOutputSlot& outputSlot = poolingLayer->GetOutputSlot(0); - outputSlot.SetTensorInfo(outputTensorInfo); - Connect(poolingLayer, tfLiteNode, delegateData); // Check activation by parsing the string from the flexbuffer map std::string activationTypeStr = m["activation"].AsString().str(); @@ -280,6 +264,46 @@ TfLiteStatus VisitPooling3dOperator(DelegateData& delegateData, activationType = kTfLiteActNone; } + const armnn::TensorInfo& activationOutputInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor, true); + TfLiteStatus activationStatus = ValidateFusedActivationOperator(delegateData, tfLiteContext, outputTensorInfo, + outputTensorInfo, activationType); + if(activationStatus != kTfLiteOk) + { + return kTfLiteError; + } + + + // Validate the output info. + bool isSupported = false; + armnn::BackendId setBackend; + auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported) { + FORWARD_LAYER_SUPPORT_FUNC("POOLING_3D", + tfLiteContext, + IsPooling3dSupported, + delegateData.m_Backends, + isSupported, + setBackend, + inputTensorInfo, + outputTensorInfo, + descriptor); + }; + + if (!delegateData.m_Network) + { + validateFunc(outputTensorInfo, isSupported); + return isSupported ? kTfLiteOk : kTfLiteError; + } + + // Create the Layer + armnn::IConnectableLayer* poolingLayer = delegateData.m_Network->AddPooling3dLayer(descriptor); + poolingLayer->SetBackendId(setBackend); + ARMNN_ASSERT(poolingLayer != nullptr); + + // Create and set output slots + armnn::IOutputSlot& outputSlot = poolingLayer->GetOutputSlot(0); + outputSlot.SetTensorInfo(outputTensorInfo); + Connect(poolingLayer, tfLiteNode, delegateData); + return FusedActivation(tfLiteContext, tfLiteNode, activationType, poolingLayer, 0, delegateData); } diff --git a/delegate/src/SharedFunctions.cpp b/delegate/src/SharedFunctions.cpp index 22f578a9d7..fef970173e 100644 --- a/delegate/src/SharedFunctions.cpp +++ b/delegate/src/SharedFunctions.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2021,2022 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2021-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -37,5 +37,80 @@ TfLiteStatus ValidateFloorOperator(DelegateData& delegateData, return isSupported ? kTfLiteOk : kTfLiteError; } +TfLiteStatus ValidateFusedActivationOperator(DelegateData& delegateData, + TfLiteContext* tfLiteContext, + const armnn::TensorInfo& inputInfo, + const armnn::TensorInfo& outputInfo, + TfLiteFusedActivation activationType) +{ + armnn::ActivationDescriptor activationDesc; + + switch (activationType) + { + case kTfLiteActNone: + { + // No Activation + return kTfLiteOk; + } + case kTfLiteActRelu: + { + activationDesc.m_Function = armnn::ActivationFunction::ReLu; + break; + } +// The name of kTfLiteActRelu1 changed after TF Lite v2.3 +#if defined(ARMNN_POST_TFLITE_2_3) + case kTfLiteActReluN1To1: +#else + case kTfLiteActRelu1: +#endif + { + activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu; + activationDesc.m_A = 1.0f; + activationDesc.m_B = -1.0f; + break; + } + case kTfLiteActRelu6: + { + activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu; + activationDesc.m_A = 6.0f; + activationDesc.m_B = 0.0f; + break; + } + case kTfLiteActSigmoid: + { + activationDesc.m_Function = armnn::ActivationFunction::Sigmoid; + break; + } + case kTfLiteActTanh: + { + activationDesc.m_Function = armnn::ActivationFunction::TanH; + activationDesc.m_A = 1.0f; + activationDesc.m_B = 1.0f; + break; + } + default: + return kTfLiteError; + } + + bool isSupported = false; + armnn::BackendId setBackend; + + auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) + { + FORWARD_LAYER_SUPPORT_FUNC("ACTIVATION", + tfLiteContext, + IsActivationSupported, + delegateData.m_Backends, + isSupported, + armnn::BackendId(), + inputInfo, + outputInfo, + activationDesc); + }; + validateFunc(outputInfo, isSupported); + return isSupported ? kTfLiteOk : kTfLiteError; +} + + } // namespace armnnDelegate diff --git a/delegate/src/SharedFunctions.hpp b/delegate/src/SharedFunctions.hpp index bf6b603cf9..b03a63ded9 100644 --- a/delegate/src/SharedFunctions.hpp +++ b/delegate/src/SharedFunctions.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2021, 2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -15,5 +15,11 @@ TfLiteStatus ValidateFloorOperator(DelegateData& delegateData, const armnn::TensorInfo& inputTensorInfo, const armnn::TensorInfo& outputTensorInfo); +TfLiteStatus ValidateFusedActivationOperator(DelegateData& delegateData, + TfLiteContext* tfLiteContext, + const armnn::TensorInfo& inputInfo, + const armnn::TensorInfo& outputInfo, + TfLiteFusedActivation activationType); + } // namespace armnnDelegate |