blob: 7c2efc855d3707093de6c858ce6c29cc75c74629 [file] [log] [blame]
Matthew Sloyan91c41712020-11-13 09:47:35 +00001//
Ryan OShea238ecd92023-03-07 11:44:23 +00002// Copyright © 2020, 2023 Arm Ltd and Contributors. All rights reserved.
Matthew Sloyan91c41712020-11-13 09:47:35 +00003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include "TestUtils.hpp"
9
10#include <armnn_delegate.hpp>
Matthew Sloyanebe392d2023-03-30 10:12:08 +010011#include <DelegateTestInterpreter.hpp>
Matthew Sloyan91c41712020-11-13 09:47:35 +000012
13#include <flatbuffers/flatbuffers.h>
Matthew Sloyan91c41712020-11-13 09:47:35 +000014#include <tensorflow/lite/kernels/register.h>
Matthew Sloyan91c41712020-11-13 09:47:35 +000015#include <tensorflow/lite/version.h>
16
Matthew Sloyanebe392d2023-03-30 10:12:08 +010017#include <doctest/doctest.h>
Matthew Sloyan91c41712020-11-13 09:47:35 +000018
19namespace
20{
21
22std::vector<char> CreateConcatTfLiteModel(tflite::BuiltinOperator controlOperatorCode,
23 tflite::TensorType tensorType,
24 std::vector<int32_t>& inputTensorShape,
25 const std::vector <int32_t>& outputTensorShape,
26 const int32_t inputTensorNum,
27 int32_t axis = 0,
28 float quantScale = 1.0f,
29 int quantOffset = 0)
30{
31 using namespace tflite;
32 flatbuffers::FlatBufferBuilder flatBufferBuilder;
33
34 std::vector<flatbuffers::Offset<tflite::Buffer>> buffers;
Ryan OShea238ecd92023-03-07 11:44:23 +000035 buffers.push_back(CreateBuffer(flatBufferBuilder));
36 buffers.push_back(CreateBuffer(flatBufferBuilder));
37 buffers.push_back(CreateBuffer(flatBufferBuilder));
Matthew Sloyan91c41712020-11-13 09:47:35 +000038
39 auto quantizationParameters =
40 CreateQuantizationParameters(flatBufferBuilder,
41 0,
42 0,
43 flatBufferBuilder.CreateVector<float>({ quantScale }),
44 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
45
46 std::vector<int32_t> operatorInputs{};
47 const std::vector<int32_t> operatorOutputs{inputTensorNum};
48 std::vector<int> subgraphInputs{};
49 const std::vector<int> subgraphOutputs{inputTensorNum};
50
51 std::vector<flatbuffers::Offset<Tensor>> tensors(inputTensorNum + 1);
52 for (int i = 0; i < inputTensorNum; ++i)
53 {
54 tensors[i] = CreateTensor(flatBufferBuilder,
55 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
56 inputTensorShape.size()),
57 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000058 1,
Matthew Sloyan91c41712020-11-13 09:47:35 +000059 flatBufferBuilder.CreateString("input" + std::to_string(i)),
60 quantizationParameters);
61
62 // Add number of inputs to vector.
63 operatorInputs.push_back(i);
64 subgraphInputs.push_back(i);
65 }
66
67 // Create output tensor
68 tensors[inputTensorNum] = CreateTensor(flatBufferBuilder,
69 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
70 outputTensorShape.size()),
71 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000072 2,
Matthew Sloyan91c41712020-11-13 09:47:35 +000073 flatBufferBuilder.CreateString("output"),
74 quantizationParameters);
75
76 // create operator
77 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_ConcatenationOptions;
78 flatbuffers::Offset<void> operatorBuiltinOptions = CreateConcatenationOptions(flatBufferBuilder, axis).Union();
79
80 flatbuffers::Offset <Operator> controlOperator =
81 CreateOperator(flatBufferBuilder,
82 0,
83 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
84 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
85 operatorBuiltinOptionsType,
86 operatorBuiltinOptions);
87
88 flatbuffers::Offset <SubGraph> subgraph =
89 CreateSubGraph(flatBufferBuilder,
90 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
91 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
92 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
93 flatBufferBuilder.CreateVector(&controlOperator, 1));
94
95 flatbuffers::Offset <flatbuffers::String> modelDescription =
96 flatBufferBuilder.CreateString("ArmnnDelegate: Concatenation Operator Model");
97 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, controlOperatorCode);
98
99 flatbuffers::Offset <Model> flatbufferModel =
100 CreateModel(flatBufferBuilder,
101 TFLITE_SCHEMA_VERSION,
102 flatBufferBuilder.CreateVector(&operatorCode, 1),
103 flatBufferBuilder.CreateVector(&subgraph, 1),
104 modelDescription,
105 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
106
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100107 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000108
109 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
110 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
111}
112
113std::vector<char> CreateMeanTfLiteModel(tflite::BuiltinOperator controlOperatorCode,
114 tflite::TensorType tensorType,
115 std::vector<int32_t>& input0TensorShape,
116 std::vector<int32_t>& input1TensorShape,
117 const std::vector <int32_t>& outputTensorShape,
118 std::vector<int32_t>& axisData,
119 const bool keepDims,
120 float quantScale = 1.0f,
121 int quantOffset = 0)
122{
123 using namespace tflite;
124 flatbuffers::FlatBufferBuilder flatBufferBuilder;
125
126 std::array<flatbuffers::Offset<tflite::Buffer>, 2> buffers;
Ryan OShea238ecd92023-03-07 11:44:23 +0000127 buffers[0] = CreateBuffer(flatBufferBuilder);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000128 buffers[1] = CreateBuffer(flatBufferBuilder,
129 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(axisData.data()),
130 sizeof(int32_t) * axisData.size()));
131
132 auto quantizationParameters =
133 CreateQuantizationParameters(flatBufferBuilder,
134 0,
135 0,
136 flatBufferBuilder.CreateVector<float>({ quantScale }),
137 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
138
139 std::array<flatbuffers::Offset<Tensor>, 3> tensors;
140 tensors[0] = CreateTensor(flatBufferBuilder,
141 flatBufferBuilder.CreateVector<int32_t>(input0TensorShape.data(),
142 input0TensorShape.size()),
143 tensorType,
144 0,
145 flatBufferBuilder.CreateString("input"),
146 quantizationParameters);
147
148 tensors[1] = CreateTensor(flatBufferBuilder,
149 flatBufferBuilder.CreateVector<int32_t>(input1TensorShape.data(),
150 input1TensorShape.size()),
151 ::tflite::TensorType_INT32,
152 1,
153 flatBufferBuilder.CreateString("axis"),
154 quantizationParameters);
155
156 // Create output tensor
157 tensors[2] = CreateTensor(flatBufferBuilder,
158 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
159 outputTensorShape.size()),
160 tensorType,
161 0,
162 flatBufferBuilder.CreateString("output"),
163 quantizationParameters);
164
165 // create operator. Mean uses ReducerOptions.
166 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_ReducerOptions;
167 flatbuffers::Offset<void> operatorBuiltinOptions = CreateReducerOptions(flatBufferBuilder, keepDims).Union();
168
169 const std::vector<int> operatorInputs{ {0, 1} };
170 const std::vector<int> operatorOutputs{ 2 };
171 flatbuffers::Offset <Operator> controlOperator =
172 CreateOperator(flatBufferBuilder,
173 0,
174 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
175 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
176 operatorBuiltinOptionsType,
177 operatorBuiltinOptions);
178
179 const std::vector<int> subgraphInputs{ {0, 1} };
180 const std::vector<int> subgraphOutputs{ 2 };
181 flatbuffers::Offset <SubGraph> subgraph =
182 CreateSubGraph(flatBufferBuilder,
183 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
184 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
185 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
186 flatBufferBuilder.CreateVector(&controlOperator, 1));
187
188 flatbuffers::Offset <flatbuffers::String> modelDescription =
189 flatBufferBuilder.CreateString("ArmnnDelegate: Mean Operator Model");
190 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, controlOperatorCode);
191
192 flatbuffers::Offset <Model> flatbufferModel =
193 CreateModel(flatBufferBuilder,
194 TFLITE_SCHEMA_VERSION,
195 flatBufferBuilder.CreateVector(&operatorCode, 1),
196 flatBufferBuilder.CreateVector(&subgraph, 1),
197 modelDescription,
198 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
199
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100200 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000201
202 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
203 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
204}
205
206template <typename T>
207void ConcatenationTest(tflite::BuiltinOperator controlOperatorCode,
208 tflite::TensorType tensorType,
Matthew Sloyan91c41712020-11-13 09:47:35 +0000209 std::vector<int32_t>& inputShapes,
210 std::vector<int32_t>& expectedOutputShape,
211 std::vector<std::vector<T>>& inputValues,
212 std::vector<T>& expectedOutputValues,
213 int32_t axis = 0,
214 float quantScale = 1.0f,
Colm Donelaneff204a2023-11-28 15:46:09 +0000215 int quantOffset = 0,
216 const std::vector<armnn::BackendId>& backends = {})
Matthew Sloyan91c41712020-11-13 09:47:35 +0000217{
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100218 using namespace delegateTestInterpreter;
Matthew Sloyan91c41712020-11-13 09:47:35 +0000219 std::vector<char> modelBuffer = CreateConcatTfLiteModel(controlOperatorCode,
220 tensorType,
221 inputShapes,
222 expectedOutputShape,
223 inputValues.size(),
224 axis,
225 quantScale,
226 quantOffset);
227
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100228 // Setup interpreter with just TFLite Runtime.
229 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
230 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000231
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100232 // Setup interpreter with Arm NN Delegate applied.
Colm Donelaneff204a2023-11-28 15:46:09 +0000233 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, CaptureAvailableBackends(backends));
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100234 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000235
Matthew Sloyan91c41712020-11-13 09:47:35 +0000236 for (unsigned int i = 0; i < inputValues.size(); ++i)
237 {
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100238 CHECK(tfLiteInterpreter.FillInputTensor<T>(inputValues[i], i) == kTfLiteOk);
239 CHECK(armnnInterpreter.FillInputTensor<T>(inputValues[i], i) == kTfLiteOk);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000240 }
241
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100242 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
243 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
244 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000245
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100246 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
247 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
248 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000249
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100250 armnnDelegate::CompareOutputData<T>(tfLiteOutputValues, armnnOutputValues, expectedOutputValues);
251 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, expectedOutputShape);
252
253 tfLiteInterpreter.Cleanup();
254 armnnInterpreter.Cleanup();
Matthew Sloyan91c41712020-11-13 09:47:35 +0000255}
256
257template <typename T>
258void MeanTest(tflite::BuiltinOperator controlOperatorCode,
259 tflite::TensorType tensorType,
Matthew Sloyan91c41712020-11-13 09:47:35 +0000260 std::vector<int32_t>& input0Shape,
261 std::vector<int32_t>& input1Shape,
262 std::vector<int32_t>& expectedOutputShape,
263 std::vector<T>& input0Values,
264 std::vector<int32_t>& input1Values,
265 std::vector<T>& expectedOutputValues,
266 const bool keepDims,
267 float quantScale = 1.0f,
Colm Donelaneff204a2023-11-28 15:46:09 +0000268 int quantOffset = 0,
269 const std::vector<armnn::BackendId>& backends = {})
Matthew Sloyan91c41712020-11-13 09:47:35 +0000270{
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100271 using namespace delegateTestInterpreter;
Matthew Sloyan91c41712020-11-13 09:47:35 +0000272 std::vector<char> modelBuffer = CreateMeanTfLiteModel(controlOperatorCode,
273 tensorType,
274 input0Shape,
275 input1Shape,
276 expectedOutputShape,
277 input1Values,
278 keepDims,
279 quantScale,
280 quantOffset);
281
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100282 // Setup interpreter with just TFLite Runtime.
283 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
284 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
285 CHECK(tfLiteInterpreter.FillInputTensor<T>(input0Values, 0) == kTfLiteOk);
286 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
287 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
288 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000289
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100290 // Setup interpreter with Arm NN Delegate applied.
Colm Donelaneff204a2023-11-28 15:46:09 +0000291 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, CaptureAvailableBackends(backends));
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100292 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
293 CHECK(armnnInterpreter.FillInputTensor<T>(input0Values, 0) == kTfLiteOk);
294 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
295 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
296 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000297
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100298 armnnDelegate::CompareOutputData<T>(tfLiteOutputValues, armnnOutputValues, expectedOutputValues);
299 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, expectedOutputShape);
Matthew Sloyan91c41712020-11-13 09:47:35 +0000300
Matthew Sloyanebe392d2023-03-30 10:12:08 +0100301 tfLiteInterpreter.Cleanup();
302 armnnInterpreter.Cleanup();
Matthew Sloyan91c41712020-11-13 09:47:35 +0000303}
304
305} // anonymous namespace