blob: fc7549161c2c3628e75c35110a82749ad810013f [file] [log] [blame]
Sadik Armagan67e95f22020-10-29 16:14:54 +00001//
Ryan OShea238ecd92023-03-07 11:44:23 +00002// Copyright © 2020, 2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan67e95f22020-10-29 16:14:54 +00003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Sadik Armaganf7ac72c2021-05-05 15:03:50 +01008#include "TestUtils.hpp"
9
Sadik Armagan67e95f22020-10-29 16:14:54 +000010#include <armnn_delegate.hpp>
Matthew Sloyanebe392d2023-03-30 10:12:08 +010011#include <DelegateTestInterpreter.hpp>
Sadik Armagan67e95f22020-10-29 16:14:54 +000012
13#include <flatbuffers/flatbuffers.h>
Sadik Armagan67e95f22020-10-29 16:14:54 +000014#include <tensorflow/lite/kernels/register.h>
Sadik Armagan67e95f22020-10-29 16:14:54 +000015#include <tensorflow/lite/version.h>
16
Matthew Sloyanebe392d2023-03-30 10:12:08 +010017#include <schema_generated.h>
18
Sadik Armagan67e95f22020-10-29 16:14:54 +000019#include <doctest/doctest.h>
20
21namespace
22{
23
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010024template <typename T>
Sadik Armagan67e95f22020-10-29 16:14:54 +000025std::vector<char> CreateElementwiseBinaryTfLiteModel(tflite::BuiltinOperator binaryOperatorCode,
26 tflite::ActivationFunctionType activationType,
27 tflite::TensorType tensorType,
28 const std::vector <int32_t>& input0TensorShape,
29 const std::vector <int32_t>& input1TensorShape,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000030 const std::vector <int32_t>& outputTensorShape,
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010031 std::vector<T>& input1Values,
32 bool constantInput = false,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000033 float quantScale = 1.0f,
34 int quantOffset = 0)
Sadik Armagan67e95f22020-10-29 16:14:54 +000035{
36 using namespace tflite;
37 flatbuffers::FlatBufferBuilder flatBufferBuilder;
38
39 std::vector<flatbuffers::Offset<tflite::Buffer>> buffers;
Ryan OShea238ecd92023-03-07 11:44:23 +000040 buffers.push_back(CreateBuffer(flatBufferBuilder));
41 buffers.push_back(CreateBuffer(flatBufferBuilder));
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010042 if (constantInput)
43 {
44 buffers.push_back(
45 CreateBuffer(flatBufferBuilder,
46 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(input1Values.data()),
47 sizeof(T) * input1Values.size())));
48 }
49 else
50 {
Ryan OShea238ecd92023-03-07 11:44:23 +000051 buffers.push_back(CreateBuffer(flatBufferBuilder));
Sadik Armaganf7ac72c2021-05-05 15:03:50 +010052 }
Ryan OShea238ecd92023-03-07 11:44:23 +000053 buffers.push_back(CreateBuffer(flatBufferBuilder));
Sadik Armagan67e95f22020-10-29 16:14:54 +000054
Sadik Armagan21a94ff2020-11-09 08:38:30 +000055 auto quantizationParameters =
56 CreateQuantizationParameters(flatBufferBuilder,
57 0,
58 0,
59 flatBufferBuilder.CreateVector<float>({ quantScale }),
60 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
61
62
Sadik Armagan67e95f22020-10-29 16:14:54 +000063 std::array<flatbuffers::Offset<Tensor>, 3> tensors;
64 tensors[0] = CreateTensor(flatBufferBuilder,
65 flatBufferBuilder.CreateVector<int32_t>(input0TensorShape.data(),
66 input0TensorShape.size()),
Sadik Armagan21a94ff2020-11-09 08:38:30 +000067 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000068 1,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000069 flatBufferBuilder.CreateString("input_0"),
70 quantizationParameters);
Sadik Armagan67e95f22020-10-29 16:14:54 +000071 tensors[1] = CreateTensor(flatBufferBuilder,
72 flatBufferBuilder.CreateVector<int32_t>(input1TensorShape.data(),
73 input1TensorShape.size()),
Sadik Armagan21a94ff2020-11-09 08:38:30 +000074 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000075 2,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000076 flatBufferBuilder.CreateString("input_1"),
77 quantizationParameters);
Sadik Armagan67e95f22020-10-29 16:14:54 +000078 tensors[2] = CreateTensor(flatBufferBuilder,
79 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
80 outputTensorShape.size()),
Sadik Armagan21a94ff2020-11-09 08:38:30 +000081 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000082 3,
Sadik Armagan21a94ff2020-11-09 08:38:30 +000083 flatBufferBuilder.CreateString("output"),
84 quantizationParameters);
Sadik Armagan67e95f22020-10-29 16:14:54 +000085
86 // create operator
87 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_NONE;
88 flatbuffers::Offset<void> operatorBuiltinOptions = 0;
89 switch (binaryOperatorCode)
90 {
91 case BuiltinOperator_ADD:
92 {
93 operatorBuiltinOptionsType = BuiltinOptions_AddOptions;
94 operatorBuiltinOptions = CreateAddOptions(flatBufferBuilder, activationType).Union();
95 break;
96 }
97 case BuiltinOperator_DIV:
98 {
99 operatorBuiltinOptionsType = BuiltinOptions_DivOptions;
100 operatorBuiltinOptions = CreateDivOptions(flatBufferBuilder, activationType).Union();
101 break;
102 }
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000103 case BuiltinOperator_MAXIMUM:
104 {
105 operatorBuiltinOptionsType = BuiltinOptions_MaximumMinimumOptions;
106 operatorBuiltinOptions = CreateMaximumMinimumOptions(flatBufferBuilder).Union();
107 break;
108 }
109 case BuiltinOperator_MINIMUM:
110 {
111 operatorBuiltinOptionsType = BuiltinOptions_MaximumMinimumOptions;
112 operatorBuiltinOptions = CreateMaximumMinimumOptions(flatBufferBuilder).Union();
113 break;
114 }
Sadik Armagan67e95f22020-10-29 16:14:54 +0000115 case BuiltinOperator_MUL:
116 {
117 operatorBuiltinOptionsType = BuiltinOptions_MulOptions;
118 operatorBuiltinOptions = CreateMulOptions(flatBufferBuilder, activationType).Union();
119 break;
120 }
121 case BuiltinOperator_SUB:
122 {
123 operatorBuiltinOptionsType = BuiltinOptions_SubOptions;
124 operatorBuiltinOptions = CreateSubOptions(flatBufferBuilder, activationType).Union();
125 break;
126 }
John Mcloughlin0ec00872023-05-15 17:03:49 +0100127 case BuiltinOperator_POW:
128 {
129 operatorBuiltinOptionsType = BuiltinOptions_PowOptions;
130 operatorBuiltinOptions = CreatePowOptions(flatBufferBuilder).Union();
131 break;
132 }
133 case BuiltinOperator_SQUARED_DIFFERENCE:
134 {
135 operatorBuiltinOptionsType = BuiltinOptions_SquaredDifferenceOptions;
136 operatorBuiltinOptions = CreateSquaredDifferenceOptions(flatBufferBuilder).Union();
137 break;
138 }
Jim Flynn4b2f3472021-10-13 21:20:07 +0100139 case BuiltinOperator_FLOOR_DIV:
140 {
141 operatorBuiltinOptionsType = tflite::BuiltinOptions_FloorDivOptions;
142 operatorBuiltinOptions = CreateSubOptions(flatBufferBuilder, activationType).Union();
143 break;
144 }
Sadik Armagan67e95f22020-10-29 16:14:54 +0000145 default:
146 break;
147 }
Keith Davis892fafe2020-11-26 17:40:35 +0000148 const std::vector<int32_t> operatorInputs{0, 1};
149 const std::vector<int32_t> operatorOutputs{2};
Sadik Armagan67e95f22020-10-29 16:14:54 +0000150 flatbuffers::Offset <Operator> elementwiseBinaryOperator =
151 CreateOperator(flatBufferBuilder,
152 0,
153 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
154 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
155 operatorBuiltinOptionsType,
156 operatorBuiltinOptions);
157
Keith Davis892fafe2020-11-26 17:40:35 +0000158 const std::vector<int> subgraphInputs{0, 1};
159 const std::vector<int> subgraphOutputs{2};
Sadik Armagan67e95f22020-10-29 16:14:54 +0000160 flatbuffers::Offset <SubGraph> subgraph =
161 CreateSubGraph(flatBufferBuilder,
162 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
163 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
164 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
165 flatBufferBuilder.CreateVector(&elementwiseBinaryOperator, 1));
166
167 flatbuffers::Offset <flatbuffers::String> modelDescription =
168 flatBufferBuilder.CreateString("ArmnnDelegate: Elementwise Binary Operator Model");
169 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, binaryOperatorCode);
170
171 flatbuffers::Offset <Model> flatbufferModel =
172 CreateModel(flatBufferBuilder,
173 TFLITE_SCHEMA_VERSION,
174 flatBufferBuilder.CreateVector(&operatorCode, 1),
175 flatBufferBuilder.CreateVector(&subgraph, 1),
176 modelDescription,
177 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
178
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100179 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000180
181 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
182 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
183}
184
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000185template <typename T>
186void ElementwiseBinaryTest(tflite::BuiltinOperator binaryOperatorCode,
187 tflite::ActivationFunctionType activationType,
188 tflite::TensorType tensorType,
189 std::vector<armnn::BackendId>& backends,
190 std::vector<int32_t>& input0Shape,
191 std::vector<int32_t>& input1Shape,
192 std::vector<int32_t>& outputShape,
193 std::vector<T>& input0Values,
194 std::vector<T>& input1Values,
195 std::vector<T>& expectedOutputValues,
196 float quantScale = 1.0f,
Sadik Armaganf7ac72c2021-05-05 15:03:50 +0100197 int quantOffset = 0,
198 bool constantInput = false)
Sadik Armagan67e95f22020-10-29 16:14:54 +0000199{
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100200 using namespace delegateTestInterpreter;
Sadik Armaganf7ac72c2021-05-05 15:03:50 +0100201 std::vector<char> modelBuffer = CreateElementwiseBinaryTfLiteModel<T>(binaryOperatorCode,
202 activationType,
203 tensorType,
204 input0Shape,
205 input1Shape,
206 outputShape,
207 input1Values,
208 constantInput,
209 quantScale,
210 quantOffset);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000211
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100212 // Setup interpreter with just TFLite Runtime.
213 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
214 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
215 CHECK(tfLiteInterpreter.FillInputTensor<T>(input0Values, 0) == kTfLiteOk);
216 CHECK(tfLiteInterpreter.FillInputTensor<T>(input1Values, 1) == kTfLiteOk);
217 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
218 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
219 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000220
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100221 // Setup interpreter with Arm NN Delegate applied.
222 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, backends);
223 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
224 CHECK(armnnInterpreter.FillInputTensor<T>(input0Values, 0) == kTfLiteOk);
225 CHECK(armnnInterpreter.FillInputTensor<T>(input1Values, 1) == kTfLiteOk);
226 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
227 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
228 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000229
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100230 armnnDelegate::CompareOutputData<T>(tfLiteOutputValues, armnnOutputValues, expectedOutputValues);
231 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, outputShape);
Sadik Armagan67e95f22020-10-29 16:14:54 +0000232
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100233 tfLiteInterpreter.Cleanup();
234 armnnInterpreter.Cleanup();
Sadik Armagan67e95f22020-10-29 16:14:54 +0000235}
236
Sadik Armagan21a94ff2020-11-09 08:38:30 +0000237} // anonymous namespace