diff options
author | Matthew Sloyan <matthew.sloyan@arm.com> | 2021-10-22 15:48:12 +0100 |
---|---|---|
committer | Teresa Charlin <teresa.charlinreyes@arm.com> | 2021-10-27 20:55:51 +0100 |
commit | af3a4ef77d8f330a995911b979417857514df62c (patch) | |
tree | 97c022fcf407d49649d4dceb285be2d047056132 /delegate/src | |
parent | 2e5d0b2e2a212ceb803681b717cbaf821f5e0929 (diff) | |
download | armnn-af3a4ef77d8f330a995911b979417857514df62c.tar.gz |
IVGCVSW-6469 Add MirrorPad TfLiteParser and TfLiteDelegate Support
Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: Ia1c97adb401c5381341408ec1e4da287ef2d48fe
Diffstat (limited to 'delegate/src')
-rw-r--r-- | delegate/src/Pad.hpp | 42 | ||||
-rw-r--r-- | delegate/src/armnn_delegate.cpp | 6 | ||||
-rw-r--r-- | delegate/src/test/MirrorPadTest.cpp | 341 | ||||
-rw-r--r-- | delegate/src/test/PadTestHelper.hpp | 16 |
4 files changed, 402 insertions, 3 deletions
diff --git a/delegate/src/Pad.hpp b/delegate/src/Pad.hpp index 431b8d33f2..78e07760fb 100644 --- a/delegate/src/Pad.hpp +++ b/delegate/src/Pad.hpp @@ -23,6 +23,7 @@ TfLiteStatus VisitPadOperator(DelegateData& delegateData, switch(tfLitePadOperatorCode) { + case kTfLiteBuiltinMirrorPad: case kTfLiteBuiltinPad: TF_LITE_ENSURE_STATUS(ValidateNumInputs(tfLiteContext, tfLiteNode, 2, nodeIndex)); break; @@ -106,6 +107,47 @@ TfLiteStatus VisitPadOperator(DelegateData& delegateData, return kTfLiteError; } } + else if (tfLitePadOperatorCode == kTfLiteBuiltinMirrorPad) + { + TfLiteMirrorPaddingParams* options = reinterpret_cast<TfLiteMirrorPaddingParams*>(tfLiteNode->builtin_data); + + + if (options->mode == TfLiteMirrorPaddingMode::kTfLiteMirrorPaddingReflect) + { + descriptor.m_PaddingMode = armnn::PaddingMode::Reflect; + } + else if (options->mode == TfLiteMirrorPaddingMode::kTfLiteMirrorPaddingSymmetric) + { + descriptor.m_PaddingMode = armnn::PaddingMode::Symmetric; + } + else + { + TF_LITE_MAYBE_KERNEL_LOG( + tfLiteContext, + "TfLiteArmnnDelegate: PaddingMode must be either REFLECT or SYMMETRIC in operator #%d node #%d: ", + tfLitePadOperatorCode, nodeIndex); + } + + // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1. + // If padding mode is Symmetric then both paddings must be no greater than inputShape(i). + auto inputShape = inputTensorInfo.GetShape(); + auto padList = descriptor.m_PadList; + + const unsigned int isReflect = + static_cast<unsigned int>(descriptor.m_PaddingMode == armnn::PaddingMode::Reflect); + for(unsigned int i = 0; i < padList.size(); ++i) + { + if(padList.at(i).first > (inputShape[i] - isReflect) || + padList.at(i).second > (inputShape[i] - isReflect)) + { + TF_LITE_MAYBE_KERNEL_LOG( + tfLiteContext, + "TfLiteArmnnDelegate: Padding values must be less (Reflect) or " + "equal (Symmetric) to the dimension size in operator #%d node #%d: ", + tfLitePadOperatorCode, nodeIndex); + } + } + } if (!delegateData.m_Network) { diff --git a/delegate/src/armnn_delegate.cpp b/delegate/src/armnn_delegate.cpp index e029e2c420..ae25430e0d 100644 --- a/delegate/src/armnn_delegate.cpp +++ b/delegate/src/armnn_delegate.cpp @@ -725,6 +725,12 @@ TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData, tfLiteNode, nodeIndex, kTfLiteBuiltinMinimum); + case kTfLiteBuiltinMirrorPad: + return VisitPadOperator(delegateData, + tfLiteContext, + tfLiteNode, + nodeIndex, + kTfLiteBuiltinMirrorPad); case kTfLiteBuiltinMul: return VisitElementwiseBinaryOperator(delegateData, tfLiteContext, diff --git a/delegate/src/test/MirrorPadTest.cpp b/delegate/src/test/MirrorPadTest.cpp new file mode 100644 index 0000000000..ca66181a30 --- /dev/null +++ b/delegate/src/test/MirrorPadTest.cpp @@ -0,0 +1,341 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "PadTestHelper.hpp" + +#include <armnn_delegate.hpp> + +#include <flatbuffers/flatbuffers.h> +#include <tensorflow/lite/schema/schema_generated.h> + +#include <doctest/doctest.h> + +namespace armnnDelegate +{ + +void MirrorPadSymmetric2dTest(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 3, 3 }; + std::vector<int32_t> outputShape { 7, 7 }; + std::vector<int32_t> paddingShape { 2, 2 }; + + std::vector<float> inputValues = + { + 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f + }; + + std::vector<float> expectedOutputValues = + { + 5.0f, 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f, + 2.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 2.0f, + 2.0f, 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 2.0f, + 5.0f, 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f, + 8.0f, 7.0f, 7.0f, 8.0f, 9.0f, 9.0f, 8.0f, + 8.0f, 7.0f, 7.0f, 8.0f, 9.0f, 9.0f, 8.0f, + 5.0f, 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f + }; + + std::vector<int32_t> paddingDim = { 2, 2, 2, 2 }; + + PadTest<float>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_FLOAT32, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 0, // Offset + tflite::MirrorPadMode_SYMMETRIC); +} + +void MirrorPadReflect2dTest(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 3, 3 }; + std::vector<int32_t> outputShape { 7, 7 }; + std::vector<int32_t> paddingShape { 2, 2 }; + + std::vector<float> inputValues = + { + 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, + 7.0f, 8.0f, 9.0f + }; + + std::vector<float> expectedOutputValues = + { + 9.0f, 8.0f, 7.0f, 8.0f, 9.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 4.0f, 5.0f, 6.0f, 5.0f, 4.0f, + 3.0f, 2.0f, 1.0f, 2.0f, 3.0f, 2.0f, 1.0f, + 6.0f, 5.0f, 4.0f, 5.0f, 6.0f, 5.0f, 4.0f, + 9.0f, 8.0f, 7.0f, 8.0f, 9.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 4.0f, 5.0f, 6.0f, 5.0f, 4.0f, + 3.0f, 2.0f, 1.0f, 2.0f, 3.0f, 2.0f, 1.0f + }; + + std::vector<int32_t> paddingDim = { 2, 2, 2, 2 }; + + PadTest<float>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_FLOAT32, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 0, // Offset + tflite::MirrorPadMode_REFLECT); +} + +void MirrorPadSymmetric3dTest(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 2, 2, 2 }; + std::vector<int32_t> outputShape { 4, 4, 4 }; + std::vector<int32_t> paddingShape { 3, 2 }; + + std::vector<float> inputValues = + { + // Channel 0, Height (2) x Width (2) + 1.0f, 2.0f, + 3.0f, 4.0f, + + // Channel 1, Height (2) x Width (2) + 5.0f, 6.0f, + 7.0f, 8.0f + }; + + std::vector<float> expectedOutputValues = + { + 1.0f, 1.0f, 2.0f, 2.0f, + 1.0f, 1.0f, 2.0f, 2.0f, + 3.0f, 3.0f, 4.0f, 4.0f, + 3.0f, 3.0f, 4.0f, 4.0f, + + 1.0f, 1.0f, 2.0f, 2.0f, + 1.0f, 1.0f, 2.0f, 2.0f, + 3.0f, 3.0f, 4.0f, 4.0f, + 3.0f, 3.0f, 4.0f, 4.0f, + + 5.0f, 5.0f, 6.0f, 6.0f, + 5.0f, 5.0f, 6.0f, 6.0f, + 7.0f, 7.0f, 8.0f, 8.0f, + 7.0f, 7.0f, 8.0f, 8.0f, + + 5.0f, 5.0f, 6.0f, 6.0f, + 5.0f, 5.0f, 6.0f, 6.0f, + 7.0f, 7.0f, 8.0f, 8.0f, + 7.0f, 7.0f, 8.0f, 8.0f + }; + + std::vector<int32_t> paddingDim = { 1, 1, 1, 1, 1, 1 }; + + PadTest<float>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_FLOAT32, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 0, // Offset + tflite::MirrorPadMode_SYMMETRIC); +} + +void MirrorPadReflect3dTest(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 2, 2, 2 }; + std::vector<int32_t> outputShape { 4, 4, 4 }; + std::vector<int32_t> paddingShape { 3, 2 }; + + std::vector<float> inputValues = + { + // Channel 0, Height (2) x Width (2) + 1.0f, 2.0f, + 3.0f, 4.0f, + + // Channel 1, Height (2) x Width (2) + 5.0f, 6.0f, + 7.0f, 8.0f + }; + + std::vector<float> expectedOutputValues = + { + 8.0f, 7.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 6.0f, 5.0f, + 8.0f, 7.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 6.0f, 5.0f, + + 4.0f, 3.0f, 4.0f, 3.0f, + 2.0f, 1.0f, 2.0f, 1.0f, + 4.0f, 3.0f, 4.0f, 3.0f, + 2.0f, 1.0f, 2.0f, 1.0f, + + 8.0f, 7.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 6.0f, 5.0f, + 8.0f, 7.0f, 8.0f, 7.0f, + 6.0f, 5.0f, 6.0f, 5.0f, + + 4.0f, 3.0f, 4.0f, 3.0f, + 2.0f, 1.0f, 2.0f, 1.0f, + 4.0f, 3.0f, 4.0f, 3.0f, + 2.0f, 1.0f, 2.0f, 1.0f + }; + + std::vector<int32_t> paddingDim = { 1, 1, 1, 1, 1, 1 }; + + PadTest<float>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_FLOAT32, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 0, // Offset + tflite::MirrorPadMode_REFLECT); +} + +void MirrorPadSymmetricUint8Test(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 3, 3 }; + std::vector<int32_t> outputShape { 5, 7 }; + std::vector<int32_t> paddingShape { 2, 2 }; + + std::vector<uint8_t> inputValues = + { + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + }; + + std::vector<uint8_t> expectedOutputValues = + { + 2, 1, 1, 2, 3, 3, 2, + 2, 1, 1, 2, 3, 3, 2, + 5, 4, 4, 5, 6, 6, 5, + 8, 7, 7, 8, 9, 9, 8, + 8, 7, 7, 8, 9, 9, 8, + }; + + std::vector<int32_t> paddingDim = { 1, 1, 2, 2 }; + + PadTest<uint8_t>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_UINT8, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 1, // Offset + tflite::MirrorPadMode_SYMMETRIC); +} + +void MirrorPadReflectInt8Test(std::vector<armnn::BackendId>& backends) +{ + // Set input data + std::vector<int32_t> inputShape { 3, 3 }; + std::vector<int32_t> outputShape { 7, 5 }; + std::vector<int32_t> paddingShape { 2, 2 }; + + std::vector<int8_t> inputValues = + { + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + }; + + std::vector<int8_t> expectedOutputValues = + { + 8, 7, 8, 9, 8, + 5, 4, 5, 6, 5, + 2, 1, 2, 3, 2, + 5, 4, 5, 6, 5, + 8, 7, 8, 9, 8, + 5, 4, 5, 6, 5, + 2, 1, 2, 3, 2 + }; + + std::vector<int32_t> paddingDim = { 2, 2, 1, 1 }; + + PadTest<int8_t>(tflite::BuiltinOperator_MIRROR_PAD, + ::tflite::TensorType_INT8, + backends, + inputShape, + paddingShape, + outputShape, + inputValues, + paddingDim, + expectedOutputValues, + 0, // Padding value - Not used in these tests. + 1.0f, // Scale + 1, // Offset + tflite::MirrorPadMode_REFLECT); +} + +TEST_SUITE("MirrorPad_CpuRefTests") +{ + +TEST_CASE ("MirrorPadSymmetric2d_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadSymmetric2dTest(backends); +} + +TEST_CASE ("MirrorPadReflect2d_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadReflect2dTest(backends); +} + +TEST_CASE ("MirrorPadSymmetric3d_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadSymmetric3dTest(backends); +} + +TEST_CASE ("MirrorPadReflect3d_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadReflect3dTest(backends); +} + +TEST_CASE ("MirrorPadSymmetricUint8_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadSymmetricUint8Test(backends); +} + +TEST_CASE ("MirrorPadSymmetricInt8_CpuRef_Test") +{ + std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef }; + MirrorPadReflectInt8Test(backends); +} + +} // TEST_SUITE("MirrorPad_CpuRefTests") + +} // namespace armnnDelegate
\ No newline at end of file diff --git a/delegate/src/test/PadTestHelper.hpp b/delegate/src/test/PadTestHelper.hpp index 3d6e6493d9..5b9a1bcc36 100644 --- a/delegate/src/test/PadTestHelper.hpp +++ b/delegate/src/test/PadTestHelper.hpp @@ -25,6 +25,7 @@ template <typename T> std::vector<char> CreatePadTfLiteModel( tflite::BuiltinOperator padOperatorCode, tflite::TensorType tensorType, + tflite::MirrorPadMode paddingMode, const std::vector<int32_t>& inputTensorShape, const std::vector<int32_t>& paddingTensorShape, const std::vector<int32_t>& outputTensorShape, @@ -87,7 +88,14 @@ std::vector<char> CreatePadTfLiteModel( operatorInputs = {{ 0, 1 }}; subgraphInputs = {{ 0, 1 }}; operatorBuiltinOptions = CreatePadOptions(flatBufferBuilder).Union(); + } + else if(padOperatorCode == tflite::BuiltinOperator_MIRROR_PAD) + { + operatorInputs = {{ 0, 1 }}; + subgraphInputs = {{ 0, 1 }}; + operatorBuiltinOptionsType = BuiltinOptions_MirrorPadOptions; + operatorBuiltinOptions = CreateMirrorPadOptions(flatBufferBuilder, paddingMode).Union(); } else if (padOperatorCode == tflite::BuiltinOperator_PADV2) { @@ -116,7 +124,7 @@ std::vector<char> CreatePadTfLiteModel( // create operator const std::vector<int32_t> operatorOutputs{ 2 }; - flatbuffers::Offset <Operator> redefineOperator = + flatbuffers::Offset <Operator> paddingOperator = CreateOperator(flatBufferBuilder, 0, flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()), @@ -130,7 +138,7 @@ std::vector<char> CreatePadTfLiteModel( flatBufferBuilder.CreateVector(tensors.data(), tensors.size()), flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()), flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()), - flatBufferBuilder.CreateVector(&redefineOperator, 1)); + flatBufferBuilder.CreateVector(&paddingOperator, 1)); flatbuffers::Offset <flatbuffers::String> modelDescription = flatBufferBuilder.CreateString("ArmnnDelegate: Pad Operator Model"); @@ -163,11 +171,13 @@ void PadTest(tflite::BuiltinOperator padOperatorCode, std::vector<T>& expectedOutputValues, T paddingValue, float quantScale = 1.0f, - int quantOffset = 0) + int quantOffset = 0, + tflite::MirrorPadMode paddingMode = tflite::MirrorPadMode_SYMMETRIC) { using namespace tflite; std::vector<char> modelBuffer = CreatePadTfLiteModel<T>(padOperatorCode, tensorType, + paddingMode, inputShape, paddingShape, outputShape, |