// // Copyright © 2021, 2023-2024 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include "TestUtils.hpp" #include #include #include namespace { std::vector CreateNormalizationTfLiteModel(tflite::BuiltinOperator normalizationOperatorCode, tflite::TensorType tensorType, const std::vector& inputTensorShape, const std::vector& outputTensorShape, int32_t radius, float bias, float alpha, float beta, float quantScale = 1.0f, int quantOffset = 0) { using namespace tflite; flatbuffers::FlatBufferBuilder flatBufferBuilder; auto quantizationParameters = CreateQuantizationParameters(flatBufferBuilder, 0, 0, flatBufferBuilder.CreateVector({ quantScale }), flatBufferBuilder.CreateVector({ quantOffset })); auto inputTensor = CreateTensor(flatBufferBuilder, flatBufferBuilder.CreateVector(inputTensorShape.data(), inputTensorShape.size()), tensorType, 1, flatBufferBuilder.CreateString("input"), quantizationParameters); auto outputTensor = CreateTensor(flatBufferBuilder, flatBufferBuilder.CreateVector(outputTensorShape.data(), outputTensorShape.size()), tensorType, 2, flatBufferBuilder.CreateString("output"), quantizationParameters); std::vector> tensors = { inputTensor, outputTensor }; std::vector> buffers; buffers.push_back(CreateBuffer(flatBufferBuilder)); buffers.push_back(CreateBuffer(flatBufferBuilder)); buffers.push_back(CreateBuffer(flatBufferBuilder)); std::vector operatorInputs = { 0 }; std::vector subgraphInputs = { 0 }; tflite::BuiltinOptions operatorBuiltinOptionsType = BuiltinOptions_L2NormOptions; flatbuffers::Offset operatorBuiltinOptions = CreateL2NormOptions(flatBufferBuilder, tflite::ActivationFunctionType_NONE).Union(); if (normalizationOperatorCode == tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION) { operatorBuiltinOptionsType = BuiltinOptions_LocalResponseNormalizationOptions; operatorBuiltinOptions = CreateLocalResponseNormalizationOptions(flatBufferBuilder, radius, bias, alpha, beta).Union(); } // create operator const std::vector operatorOutputs{ 1 }; flatbuffers::Offset normalizationOperator = CreateOperator(flatBufferBuilder, 0, flatBufferBuilder.CreateVector(operatorInputs.data(), operatorInputs.size()), flatBufferBuilder.CreateVector(operatorOutputs.data(), operatorOutputs.size()), operatorBuiltinOptionsType, operatorBuiltinOptions); const std::vector subgraphOutputs{ 1 }; flatbuffers::Offset subgraph = CreateSubGraph(flatBufferBuilder, flatBufferBuilder.CreateVector(tensors.data(), tensors.size()), flatBufferBuilder.CreateVector(subgraphInputs.data(), subgraphInputs.size()), flatBufferBuilder.CreateVector(subgraphOutputs.data(), subgraphOutputs.size()), flatBufferBuilder.CreateVector(&normalizationOperator, 1)); flatbuffers::Offset modelDescription = flatBufferBuilder.CreateString("ArmnnDelegate: Normalization Operator Model"); flatbuffers::Offset operatorCode = CreateOperatorCode(flatBufferBuilder, normalizationOperatorCode); flatbuffers::Offset flatbufferModel = CreateModel(flatBufferBuilder, TFLITE_SCHEMA_VERSION, flatBufferBuilder.CreateVector(&operatorCode, 1), flatBufferBuilder.CreateVector(&subgraph, 1), modelDescription, flatBufferBuilder.CreateVector(buffers.data(), buffers.size())); flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER); return std::vector(flatBufferBuilder.GetBufferPointer(), flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize()); } template void NormalizationTest(tflite::BuiltinOperator normalizationOperatorCode, tflite::TensorType tensorType, const std::vector& inputShape, std::vector& outputShape, std::vector& inputValues, std::vector& expectedOutputValues, const std::vector& backends = {}, int32_t radius = 0, float bias = 0.f, float alpha = 0.f, float beta = 0.f, float quantScale = 1.0f, int quantOffset = 0) { using namespace delegateTestInterpreter; std::vector modelBuffer = CreateNormalizationTfLiteModel(normalizationOperatorCode, tensorType, inputShape, outputShape, radius, bias, alpha, beta, quantScale, quantOffset); // Setup interpreter with just TFLite Runtime. auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer); CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk); CHECK(tfLiteInterpreter.FillInputTensor(inputValues, 0) == kTfLiteOk); CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk); std::vector tfLiteOutputValues = tfLiteInterpreter.GetOutputResult(0); std::vector tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0); // Setup interpreter with Arm NN Delegate applied. auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, CaptureAvailableBackends(backends)); CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk); CHECK(armnnInterpreter.FillInputTensor(inputValues, 0) == kTfLiteOk); CHECK(armnnInterpreter.Invoke() == kTfLiteOk); std::vector armnnOutputValues = armnnInterpreter.GetOutputResult(0); std::vector armnnOutputShape = armnnInterpreter.GetOutputShape(0); armnnDelegate::CompareOutputData(tfLiteOutputValues, armnnOutputValues, expectedOutputValues); armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, outputShape); tfLiteInterpreter.Cleanup(); armnnInterpreter.Cleanup(); } void L2NormalizationTest(const std::vector& backends = {}) { // Set input data std::vector inputShape { 1, 1, 1, 10 }; std::vector outputShape { 1, 1, 1, 10 }; std::vector inputValues { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f }; const float approxInvL2Norm = 0.050964719f; std::vector expectedOutputValues { 1.0f * approxInvL2Norm, 2.0f * approxInvL2Norm, 3.0f * approxInvL2Norm, 4.0f * approxInvL2Norm, 5.0f * approxInvL2Norm, 6.0f * approxInvL2Norm, 7.0f * approxInvL2Norm, 8.0f * approxInvL2Norm, 9.0f * approxInvL2Norm, 10.0f * approxInvL2Norm }; NormalizationTest(tflite::BuiltinOperator_L2_NORMALIZATION, ::tflite::TensorType_FLOAT32, inputShape, outputShape, inputValues, expectedOutputValues, backends); } void LocalResponseNormalizationTest(int32_t radius, float bias, float alpha, float beta, const std::vector& backends = {}) { // Set input data std::vector inputShape { 2, 2, 2, 1 }; std::vector outputShape { 2, 2, 2, 1 }; std::vector inputValues { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; std::vector expectedOutputValues { 0.5f, 0.400000006f, 0.300000012f, 0.235294119f, 0.192307696f, 0.16216217f, 0.140000001f, 0.123076923f }; NormalizationTest(tflite::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, ::tflite::TensorType_FLOAT32, inputShape, outputShape, inputValues, expectedOutputValues, backends, radius, bias, alpha, beta); } } // anonymous namespace