From 67e95f2aebc827f2e3c571385b9e623f09a65141 Mon Sep 17 00:00:00 2001 From: Sadik Armagan Date: Thu, 29 Oct 2020 16:14:54 +0000 Subject: IVGCVSW-5379 'TfLiteDelegate: Implement the ElementWiseBinary operators' * Implemented ADD operator * Implemented FP32 unit tests for ADD operator Signed-off-by: Sadik Armagan Change-Id: Id7238749308855bd2b2118f4b6e60e765815c38f --- delegate/src/ElementwiseBinary.hpp | 125 ++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) (limited to 'delegate/src/ElementwiseBinary.hpp') diff --git a/delegate/src/ElementwiseBinary.hpp b/delegate/src/ElementwiseBinary.hpp index ff24012bdb..a22d9f5751 100644 --- a/delegate/src/ElementwiseBinary.hpp +++ b/delegate/src/ElementwiseBinary.hpp @@ -5,6 +5,8 @@ #pragma once +#include "DelegateUtils.hpp" + #include #include #include @@ -13,13 +15,134 @@ namespace armnnDelegate { +TfLiteStatus ValidateAddOperator(DelegateData& delegateData, + TfLiteContext* tfLiteContext, + const armnn::TensorInfo& inputInfo1, + const armnn::TensorInfo& inputInfo2, + const armnn::TensorInfo& outputInfo) +{ + bool isSupported = false; + auto validateFunc = [&](const armnn::TensorInfo& outputTensorInfo, bool& isSupported) + { + FORWARD_LAYER_SUPPORT_FUNC(__func__, + tfLiteContext, + IsAdditionSupported, + delegateData.m_Backends, + isSupported, + inputInfo1, + inputInfo2, + outputTensorInfo); + }; + + validateFunc(outputInfo, isSupported); + return isSupported ? kTfLiteOk : kTfLiteError; +} + +armnn::IConnectableLayer* AddAdditionLayer(DelegateData& delegateData) +{ + + if (!delegateData.m_Network) + { + return nullptr; + } + + return delegateData.m_Network->AddAdditionLayer(); +} + TfLiteStatus VisitElementwiseBinaryOperator(DelegateData& delegateData, TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode, int nodeIndex, int32_t elementwiseBinaryOperatorCode) { - return kTfLiteError; + TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex)); + TF_LITE_ENSURE_STATUS(ValidateNumOutputs(tfLiteContext, tfLiteNode, 1, nodeIndex)); + + const TfLiteTensor* tfLiteTensors = tfLiteContext->tensors; + const TfLiteTensor& tfLiteInputTensor0 = tfLiteTensors[tfLiteNode->inputs->data[0]]; + if (IsDynamicTensor(tfLiteInputTensor0)) + { + TF_LITE_MAYBE_KERNEL_LOG( + tfLiteContext, + "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ", + elementwiseBinaryOperatorCode, nodeIndex); + return kTfLiteError; + } + + const TfLiteTensor& tfLiteInputTensor1 = tfLiteTensors[tfLiteNode->inputs->data[1]]; + if (IsDynamicTensor(tfLiteInputTensor1)) + { + TF_LITE_MAYBE_KERNEL_LOG( + tfLiteContext, + "TfLiteArmnnDelegate: Dynamic input tensors are not supported in operator #%d node #%d: ", + elementwiseBinaryOperatorCode, nodeIndex); + return kTfLiteError; + } + + const TfLiteTensor& tfLiteOutputTensor = tfLiteTensors[tfLiteNode->outputs->data[0]]; + if (IsDynamicTensor(tfLiteOutputTensor)) + { + TF_LITE_MAYBE_KERNEL_LOG( + tfLiteContext, + "TfLiteArmnnDelegate: Dynamic output tensors are not supported in operator #%d node #%d: ", + elementwiseBinaryOperatorCode, nodeIndex); + return kTfLiteError; + } + + const armnn::TensorInfo& inputTensorInfo0 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor0); + const armnn::TensorInfo& inputTensorInfo1 = GetTensorInfoForTfLiteTensor(tfLiteInputTensor1); + const armnn::TensorInfo& outputTensorInfo = GetTensorInfoForTfLiteTensor(tfLiteOutputTensor); + + if (!delegateData.m_Network) + { + switch(elementwiseBinaryOperatorCode) + { + case kTfLiteBuiltinAdd: + return ValidateAddOperator(delegateData, + tfLiteContext, + inputTensorInfo0, + inputTensorInfo1, + outputTensorInfo); + default: + return kTfLiteError; + } + } + + armnn::IConnectableLayer* elementwiseBinaryLayer = nullptr; + + switch(elementwiseBinaryOperatorCode) + { + case kTfLiteBuiltinAdd: + elementwiseBinaryLayer = AddAdditionLayer(delegateData); + break; + default: + return kTfLiteError; + } + ARMNN_ASSERT(elementwiseBinaryLayer != nullptr); + + armnn::IOutputSlot& outputSlot = elementwiseBinaryLayer->GetOutputSlot(0); + outputSlot.SetTensorInfo(outputTensorInfo); + + auto reshapeLayer = BroadcastTensor(inputTensorInfo0, + inputTensorInfo1, + elementwiseBinaryLayer, + tfLiteContext, + tfLiteNode, + delegateData); + if (!reshapeLayer) + { + return kTfLiteError; + } + + auto* tfLiteNodeParameters = reinterpret_cast(tfLiteNode->builtin_data); + if (!tfLiteNodeParameters) + { + // No Activation + return kTfLiteOk; + } + // Check activation + TfLiteFusedActivation activationType = tfLiteNodeParameters->activation; + return FusedActivation(tfLiteContext, tfLiteNode, activationType, reshapeLayer, 0, delegateData); } } // namespace armnnDelegate -- cgit v1.2.1