blob: 503fbc85aec99026b3310e00f933f52718e96684 [file] [log] [blame]
Sadik Armagan34fa1bd2020-11-27 12:40:52 +00001//
Ryan OShea238ecd92023-03-07 11:44:23 +00002// Copyright © 2020, 2023 Arm Ltd and Contributors. All rights reserved.
Sadik Armagan34fa1bd2020-11-27 12:40:52 +00003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include "TestUtils.hpp"
9
10#include <armnn_delegate.hpp>
11
12#include <flatbuffers/flatbuffers.h>
13#include <tensorflow/lite/interpreter.h>
14#include <tensorflow/lite/kernels/register.h>
15#include <tensorflow/lite/model.h>
Teresa Charlinad1b3d72023-03-14 12:10:28 +000016#include <schema_generated.h>
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000017#include <tensorflow/lite/version.h>
18
19#include <doctest/doctest.h>
20
21#include <string>
22
23namespace
24{
25
26std::vector<char> CreateSplitTfLiteModel(tflite::TensorType tensorType,
27 std::vector<int32_t>& axisTensorShape,
28 std::vector<int32_t>& inputTensorShape,
29 const std::vector<std::vector<int32_t>>& outputTensorShapes,
30 std::vector<int32_t>& axisData,
31 const int32_t numSplits,
32 float quantScale = 1.0f,
33 int quantOffset = 0)
34{
35 using namespace tflite;
36 flatbuffers::FlatBufferBuilder flatBufferBuilder;
37
Ryan OShea238ecd92023-03-07 11:44:23 +000038 std::vector<flatbuffers::Offset<tflite::Buffer>> buffers;
39 buffers.push_back(CreateBuffer(flatBufferBuilder));
40 buffers.push_back(CreateBuffer(flatBufferBuilder));
41 buffers.push_back(CreateBuffer(flatBufferBuilder,
42 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(axisData.data()),
43 sizeof(int32_t) * axisData.size())));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000044
45 auto quantizationParameters =
46 CreateQuantizationParameters(flatBufferBuilder,
47 0,
48 0,
49 flatBufferBuilder.CreateVector<float>({ quantScale }),
50 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
51
52 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
53 tensors[0] = CreateTensor(flatBufferBuilder,
54 flatBufferBuilder.CreateVector<int32_t>(axisTensorShape.data(),
55 axisTensorShape.size()),
56 ::tflite::TensorType_INT32,
Ryan OShea238ecd92023-03-07 11:44:23 +000057 2,
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000058 flatBufferBuilder.CreateString("axis"),
59 quantizationParameters);
60 tensors[1] = CreateTensor(flatBufferBuilder,
61 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
62 inputTensorShape.size()),
63 tensorType,
Ryan OShea238ecd92023-03-07 11:44:23 +000064 1,
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000065 flatBufferBuilder.CreateString("input"),
66 quantizationParameters);
67
68 // Create output tensor
69 for (unsigned int i = 0; i < outputTensorShapes.size(); ++i)
70 {
Ryan OShea238ecd92023-03-07 11:44:23 +000071 buffers.push_back(CreateBuffer(flatBufferBuilder));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000072 tensors[i + 2] = CreateTensor(flatBufferBuilder,
Ryan OShea238ecd92023-03-07 11:44:23 +000073 flatBufferBuilder.CreateVector<int32_t>(outputTensorShapes[i].data(),
74 outputTensorShapes[i].size()),
75 tensorType,
76 (i+3),
77 flatBufferBuilder.CreateString("output"),
78 quantizationParameters);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000079 }
80
81 // create operator. Mean uses ReducerOptions.
82 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_SplitOptions;
83 flatbuffers::Offset<void> operatorBuiltinOptions = CreateSplitOptions(flatBufferBuilder, numSplits).Union();
84
85 const std::vector<int> operatorInputs{ {0, 1} };
86 const std::vector<int> operatorOutputs{ {2, 3} };
87 flatbuffers::Offset <Operator> controlOperator =
88 CreateOperator(flatBufferBuilder,
89 0,
90 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
91 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
92 operatorBuiltinOptionsType,
93 operatorBuiltinOptions);
94
95 const std::vector<int> subgraphInputs{ {0, 1} };
96 const std::vector<int> subgraphOutputs{ {2, 3} };
97 flatbuffers::Offset <SubGraph> subgraph =
98 CreateSubGraph(flatBufferBuilder,
99 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
100 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
101 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
102 flatBufferBuilder.CreateVector(&controlOperator, 1));
103
104 flatbuffers::Offset <flatbuffers::String> modelDescription =
105 flatBufferBuilder.CreateString("ArmnnDelegate: SPLIT Operator Model");
106 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, BuiltinOperator_SPLIT);
107
108 flatbuffers::Offset <Model> flatbufferModel =
109 CreateModel(flatBufferBuilder,
110 TFLITE_SCHEMA_VERSION,
111 flatBufferBuilder.CreateVector(&operatorCode, 1),
112 flatBufferBuilder.CreateVector(&subgraph, 1),
113 modelDescription,
Ryan OShea238ecd92023-03-07 11:44:23 +0000114 flatBufferBuilder.CreateVector(buffers));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000115
116 flatBufferBuilder.Finish(flatbufferModel);
117
118 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
119 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
120}
121
122template <typename T>
123void SplitTest(tflite::TensorType tensorType,
124 std::vector<armnn::BackendId>& backends,
125 std::vector<int32_t>& axisTensorShape,
126 std::vector<int32_t>& inputTensorShape,
127 std::vector<std::vector<int32_t>>& outputTensorShapes,
128 std::vector<int32_t>& axisData,
129 std::vector<T>& inputValues,
130 std::vector<std::vector<T>>& expectedOutputValues,
131 const int32_t numSplits,
132 float quantScale = 1.0f,
133 int quantOffset = 0)
134{
135 using namespace tflite;
136 std::vector<char> modelBuffer = CreateSplitTfLiteModel(tensorType,
137 axisTensorShape,
138 inputTensorShape,
139 outputTensorShapes,
140 axisData,
141 numSplits,
142 quantScale,
143 quantOffset);
144 const Model* tfLiteModel = GetModel(modelBuffer.data());
145
146 // Create TfLite Interpreters
147 std::unique_ptr<Interpreter> armnnDelegate;
148 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
Ryan OShea238ecd92023-03-07 11:44:23 +0000149 (&armnnDelegate) == kTfLiteOk);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000150 CHECK(armnnDelegate != nullptr);
151 CHECK(armnnDelegate->AllocateTensors() == kTfLiteOk);
152
153 std::unique_ptr<Interpreter> tfLiteDelegate;
154 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
Ryan OShea238ecd92023-03-07 11:44:23 +0000155 (&tfLiteDelegate) == kTfLiteOk);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000156 CHECK(tfLiteDelegate != nullptr);
157 CHECK(tfLiteDelegate->AllocateTensors() == kTfLiteOk);
158
159 // Create the ArmNN Delegate
160 armnnDelegate::DelegateOptions delegateOptions(backends);
161 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
Ryan OShea238ecd92023-03-07 11:44:23 +0000162 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
163 armnnDelegate::TfLiteArmnnDelegateDelete);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000164 CHECK(theArmnnDelegate != nullptr);
165
166 // Modify armnnDelegateInterpreter to use armnnDelegate
167 CHECK(armnnDelegate->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
168
169 // Set input data
170 armnnDelegate::FillInput<T>(tfLiteDelegate, 1, inputValues);
171 armnnDelegate::FillInput<T>(armnnDelegate, 1, inputValues);
172
173 // Run EnqueWorkload
174 CHECK(tfLiteDelegate->Invoke() == kTfLiteOk);
175 CHECK(armnnDelegate->Invoke() == kTfLiteOk);
176
177 // Compare output data
178 for (unsigned int i = 0; i < expectedOutputValues.size(); ++i)
179 {
180 armnnDelegate::CompareOutputData<T>(tfLiteDelegate,
181 armnnDelegate,
182 outputTensorShapes[i],
183 expectedOutputValues[i],
184 i);
185 }
186
187 tfLiteDelegate.reset(nullptr);
188 armnnDelegate.reset(nullptr);
189} // End of SPLIT Test
190
191std::vector<char> CreateSplitVTfLiteModel(tflite::TensorType tensorType,
192 std::vector<int32_t>& inputTensorShape,
193 std::vector<int32_t>& splitsTensorShape,
194 std::vector<int32_t>& axisTensorShape,
195 const std::vector<std::vector<int32_t>>& outputTensorShapes,
196 std::vector<int32_t>& splitsData,
197 std::vector<int32_t>& axisData,
198 const int32_t numSplits,
199 float quantScale = 1.0f,
200 int quantOffset = 0)
201{
202 using namespace tflite;
203 flatbuffers::FlatBufferBuilder flatBufferBuilder;
204
205 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
206 buffers[0] = CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({}));
207 buffers[1] = CreateBuffer(flatBufferBuilder,
208 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(splitsData.data()),
209 sizeof(int32_t) * splitsData.size()));
210 buffers[2] = CreateBuffer(flatBufferBuilder,
211 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(axisData.data()),
212 sizeof(int32_t) * axisData.size()));
213
214 auto quantizationParameters =
Ryan OShea238ecd92023-03-07 11:44:23 +0000215 CreateQuantizationParameters(flatBufferBuilder,
216 0,
217 0,
218 flatBufferBuilder.CreateVector<float>({ quantScale }),
219 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000220
221 std::array<flatbuffers::Offset<Tensor>, 5> tensors;
222 tensors[0] = CreateTensor(flatBufferBuilder,
223 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
224 inputTensorShape.size()),
225 tensorType,
226 0,
227 flatBufferBuilder.CreateString("input"),
228 quantizationParameters);
229 tensors[1] = CreateTensor(flatBufferBuilder,
230 flatBufferBuilder.CreateVector<int32_t>(splitsTensorShape.data(),
231 splitsTensorShape.size()),
232 ::tflite::TensorType_INT32,
233 1,
234 flatBufferBuilder.CreateString("splits"),
235 quantizationParameters);
236 tensors[2] = CreateTensor(flatBufferBuilder,
237 flatBufferBuilder.CreateVector<int32_t>(axisTensorShape.data(),
238 axisTensorShape.size()),
239 ::tflite::TensorType_INT32,
240 2,
241 flatBufferBuilder.CreateString("axis"),
242 quantizationParameters);
243
244 // Create output tensor
245 for (unsigned int i = 0; i < outputTensorShapes.size(); ++i)
246 {
247 tensors[i + 3] = CreateTensor(flatBufferBuilder,
248 flatBufferBuilder.CreateVector<int32_t>(outputTensorShapes[i].data(),
249 outputTensorShapes[i].size()),
250 tensorType,
251 0,
252 flatBufferBuilder.CreateString("output"),
253 quantizationParameters);
254 }
255
256 // create operator. Mean uses ReducerOptions.
257 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_SplitVOptions;
258 flatbuffers::Offset<void> operatorBuiltinOptions = CreateSplitVOptions(flatBufferBuilder, numSplits).Union();
259
260 const std::vector<int> operatorInputs{ {0, 1, 2} };
261 const std::vector<int> operatorOutputs{ {3, 4} };
262 flatbuffers::Offset <Operator> controlOperator =
Ryan OShea238ecd92023-03-07 11:44:23 +0000263 CreateOperator(flatBufferBuilder,
264 0,
265 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
266 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
267 operatorBuiltinOptionsType,
268 operatorBuiltinOptions);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000269
270 const std::vector<int> subgraphInputs{ {0, 1, 2} };
271 const std::vector<int> subgraphOutputs{ {3, 4} };
272 flatbuffers::Offset <SubGraph> subgraph =
Ryan OShea238ecd92023-03-07 11:44:23 +0000273 CreateSubGraph(flatBufferBuilder,
274 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
275 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
276 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
277 flatBufferBuilder.CreateVector(&controlOperator, 1));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000278
279 flatbuffers::Offset <flatbuffers::String> modelDescription =
Ryan OShea238ecd92023-03-07 11:44:23 +0000280 flatBufferBuilder.CreateString("ArmnnDelegate: SPLIT_V Operator Model");
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000281 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, BuiltinOperator_SPLIT_V);
282
283 flatbuffers::Offset <Model> flatbufferModel =
Ryan OShea238ecd92023-03-07 11:44:23 +0000284 CreateModel(flatBufferBuilder,
285 TFLITE_SCHEMA_VERSION,
286 flatBufferBuilder.CreateVector(&operatorCode, 1),
287 flatBufferBuilder.CreateVector(&subgraph, 1),
288 modelDescription,
289 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000290
291 flatBufferBuilder.Finish(flatbufferModel);
292
293 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
294 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
295}
296
297template <typename T>
298void SplitVTest(tflite::TensorType tensorType,
299 std::vector<armnn::BackendId>& backends,
300 std::vector<int32_t>& inputTensorShape,
301 std::vector<int32_t>& splitsTensorShape,
302 std::vector<int32_t>& axisTensorShape,
303 std::vector<std::vector<int32_t>>& outputTensorShapes,
304 std::vector<T>& inputValues,
305 std::vector<int32_t>& splitsData,
306 std::vector<int32_t>& axisData,
307 std::vector<std::vector<T>>& expectedOutputValues,
308 const int32_t numSplits,
309 float quantScale = 1.0f,
310 int quantOffset = 0)
311{
312 using namespace tflite;
313 std::vector<char> modelBuffer = CreateSplitVTfLiteModel(tensorType,
314 inputTensorShape,
315 splitsTensorShape,
316 axisTensorShape,
317 outputTensorShapes,
318 splitsData,
319 axisData,
320 numSplits,
321 quantScale,
322 quantOffset);
323 const Model* tfLiteModel = GetModel(modelBuffer.data());
324
325 // Create TfLite Interpreters
326 std::unique_ptr<Interpreter> armnnDelegate;
327 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
328 (&armnnDelegate) == kTfLiteOk);
329 CHECK(armnnDelegate != nullptr);
330 CHECK(armnnDelegate->AllocateTensors() == kTfLiteOk);
331
332 std::unique_ptr<Interpreter> tfLiteDelegate;
333 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
334 (&tfLiteDelegate) == kTfLiteOk);
335 CHECK(tfLiteDelegate != nullptr);
336 CHECK(tfLiteDelegate->AllocateTensors() == kTfLiteOk);
337
338 // Create the ArmNN Delegate
339 armnnDelegate::DelegateOptions delegateOptions(backends);
340 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
341 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
342 armnnDelegate::TfLiteArmnnDelegateDelete);
343 CHECK(theArmnnDelegate != nullptr);
344
345 // Modify armnnDelegateInterpreter to use armnnDelegate
346 CHECK(armnnDelegate->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
347
348 // Set input data
349 armnnDelegate::FillInput<T>(tfLiteDelegate, 0, inputValues);
350 armnnDelegate::FillInput<T>(armnnDelegate, 0, inputValues);
351
352 // Run EnqueWorkload
353 CHECK(tfLiteDelegate->Invoke() == kTfLiteOk);
354 CHECK(armnnDelegate->Invoke() == kTfLiteOk);
355
356 // Compare output data
357 for (unsigned int i = 0; i < expectedOutputValues.size(); ++i)
358 {
359 armnnDelegate::CompareOutputData<T>(tfLiteDelegate,
360 armnnDelegate,
361 outputTensorShapes[i],
362 expectedOutputValues[i],
363 i);
364 }
365
366 tfLiteDelegate.reset(nullptr);
367 armnnDelegate.reset(nullptr);
368} // End of SPLIT_V Test
369
370} // anonymous namespace