1 //
2 // Copyright © 2020, 2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #pragma once
7
8 #include "TestUtils.hpp"
9
10 #include <armnn_delegate.hpp>
11 #include <DelegateTestInterpreter.hpp>
12
13 #include <flatbuffers/flatbuffers.h>
14 #include <tensorflow/lite/interpreter.h>
15 #include <tensorflow/lite/kernels/register.h>
16 #include <tensorflow/lite/model.h>
17 #include <schema_generated.h>
18 #include <tensorflow/lite/version.h>
19
20 #include <doctest/doctest.h>
21
22 namespace
23 {
24
25 template <typename T, typename B = float>
CreateConv2dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,tflite::TensorType tensorType,uint32_t strideX,uint32_t strideY,uint32_t dilationX,uint32_t dilationY,tflite::Padding padding,tflite::ActivationFunctionType fused_activation_function,const std::vector<int32_t> & inputTensorShape,const std::vector<int32_t> & filterTensorShape,const std::vector<int32_t> & biasTensorShape,const std::vector<int32_t> & outputTensorShape,const std::vector<T> & filterData,const std::vector<B> & biasData,const std::vector<float> biasScales={1.0f},const std::vector<int64_t> biasOffsets={0},const std::vector<float> filterScales={1.0f},const std::vector<int64_t> filterOffsets={0},float outputQuantScale=2.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0,int32_t depth_multiplier=1,int32_t filterQuantizationDim=0)26 std::vector<char> CreateConv2dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,
27 tflite::TensorType tensorType,
28 uint32_t strideX,
29 uint32_t strideY,
30 uint32_t dilationX,
31 uint32_t dilationY,
32 tflite::Padding padding,
33 tflite::ActivationFunctionType fused_activation_function,
34 const std::vector <int32_t>& inputTensorShape,
35 const std::vector <int32_t>& filterTensorShape,
36 const std::vector <int32_t>& biasTensorShape,
37 const std::vector <int32_t>& outputTensorShape,
38 const std::vector <T>& filterData,
39 const std::vector <B>& biasData,
40 const std::vector<float> biasScales = {1.0f},
41 const std::vector<int64_t> biasOffsets = {0},
42 const std::vector<float> filterScales = {1.0f},
43 const std::vector<int64_t> filterOffsets = {0},
44 float outputQuantScale = 2.0f,
45 int outputQuantOffset = 0,
46 float quantScale = 1.0f,
47 int quantOffset = 0,
48 int32_t depth_multiplier = 1,
49 int32_t filterQuantizationDim = 0)
50 {
51 using namespace tflite;
52 flatbuffers::FlatBufferBuilder flatBufferBuilder;
53
54 std::array<flatbuffers::Offset<tflite::Buffer>, 5> buffers;
55 buffers[0] = CreateBuffer(flatBufferBuilder);
56 buffers[1] = CreateBuffer(flatBufferBuilder);
57 buffers[2] = CreateBuffer(flatBufferBuilder,
58 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
59 sizeof(T) * filterData.size()));
60
61 buffers[3] = CreateBuffer(flatBufferBuilder,
62 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(biasData.data()),
63 sizeof(B) * biasData.size()));
64 buffers[4] = CreateBuffer(flatBufferBuilder);
65
66 auto quantizationParameters =
67 CreateQuantizationParameters(flatBufferBuilder,
68 0,
69 0,
70 flatBufferBuilder.CreateVector<float>({ quantScale }),
71 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
72 auto outputQuantizationParameters =
73 CreateQuantizationParameters(flatBufferBuilder,
74 0,
75 0,
76 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
77 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
78
79 auto filterQuantizationParameters =
80 CreateQuantizationParameters(flatBufferBuilder,
81 0,
82 0,
83 flatBufferBuilder.CreateVector<float>(filterScales),
84 flatBufferBuilder.CreateVector<int64_t>(filterOffsets),
85 tflite::QuantizationDetails_NONE,
86 0,
87 filterQuantizationDim);
88
89 auto biasQuantizationParameters =
90 CreateQuantizationParameters(flatBufferBuilder,
91 0,
92 0,
93 flatBufferBuilder.CreateVector<float>(biasScales),
94 flatBufferBuilder.CreateVector<int64_t>(biasOffsets));
95
96 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
97 tensors[0] = CreateTensor(flatBufferBuilder,
98 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
99 inputTensorShape.size()),
100 tensorType,
101 1,
102 flatBufferBuilder.CreateString("input"),
103 quantizationParameters);
104 tensors[1] = CreateTensor(flatBufferBuilder,
105 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
106 filterTensorShape.size()),
107 tensorType,
108 2,
109 flatBufferBuilder.CreateString("filter"),
110 filterQuantizationParameters);
111
112 auto biasTensorType = ::tflite::TensorType_FLOAT32;
113 if (tensorType == ::tflite::TensorType_INT8 || tensorType == ::tflite::TensorType_UINT8)
114 {
115 biasTensorType = ::tflite::TensorType_INT32;
116 }
117 tensors[2] = CreateTensor(flatBufferBuilder,
118 flatBufferBuilder.CreateVector<int32_t>(biasTensorShape.data(), biasTensorShape.size()),
119 biasTensorType,
120 3,
121 flatBufferBuilder.CreateString("bias"),
122 biasQuantizationParameters);
123 tensors[3] = CreateTensor(flatBufferBuilder,
124 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
125 outputTensorShape.size()),
126 tensorType,
127 4,
128 flatBufferBuilder.CreateString("output"),
129 outputQuantizationParameters);
130
131 flatbuffers::Offset<void> operatorBuiltinOptions;
132 tflite::BuiltinOptions operatorBuiltinOptionsType;
133
134 if(convolutionOperatorCode == tflite::BuiltinOperator_DEPTHWISE_CONV_2D)
135 {
136 operatorBuiltinOptionsType = tflite::BuiltinOptions_DepthwiseConv2DOptions;
137 operatorBuiltinOptions = CreateDepthwiseConv2DOptions(flatBufferBuilder,
138 padding,
139 strideX,
140 strideY,
141 depth_multiplier,
142 fused_activation_function,
143 dilationX,
144 dilationY).Union();
145 }
146 if(convolutionOperatorCode == tflite::BuiltinOperator_CONV_2D)
147 {
148 operatorBuiltinOptionsType = tflite::BuiltinOptions_Conv2DOptions;
149 operatorBuiltinOptions = CreateConv2DOptions(flatBufferBuilder,
150 padding,
151 strideX,
152 strideY,
153 fused_activation_function,
154 dilationX,
155 dilationY).Union();
156 }
157
158 // create operator
159 const std::vector<int> operatorInputs{0, 1, 2};
160 const std::vector<int> operatorOutputs{3};
161 flatbuffers::Offset <Operator> convolutionOperator =
162 CreateOperator(flatBufferBuilder,
163 0,
164 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
165 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
166 operatorBuiltinOptionsType,
167 operatorBuiltinOptions);
168
169 const std::vector<int> subgraphInputs{0, 1, 2};
170 const std::vector<int> subgraphOutputs{3};
171 flatbuffers::Offset <SubGraph> subgraph =
172 CreateSubGraph(flatBufferBuilder,
173 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
174 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
175 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
176 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
177
178 flatbuffers::Offset <flatbuffers::String> modelDescription =
179 flatBufferBuilder.CreateString("ArmnnDelegate: Convolution2d Operator Model");
180 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, convolutionOperatorCode);
181
182 flatbuffers::Offset <Model> flatbufferModel =
183 CreateModel(flatBufferBuilder,
184 TFLITE_SCHEMA_VERSION,
185 flatBufferBuilder.CreateVector(&operatorCode, 1),
186 flatBufferBuilder.CreateVector(&subgraph, 1),
187 modelDescription,
188 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
189
190 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
191
192 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
193 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
194 }
195
196 template <typename T, typename B = float>
ConvolutionTest(tflite::BuiltinOperator convolutionOperatorCode,tflite::TensorType tensorType,uint32_t strideX,uint32_t strideY,uint32_t dilationX,uint32_t dilationY,tflite::Padding padding,tflite::ActivationFunctionType fused_activation_function,std::vector<armnn::BackendId> & backends,std::vector<int32_t> & inputShape,std::vector<int32_t> & filterShape,std::vector<int32_t> & outputShape,std::vector<T> & inputValues,std::vector<T> & filterValues,std::vector<T> & expectedOutputValues,const std::vector<int32_t> & biasShape={},const std::vector<B> & biasValues={},const std::vector<float> biasScales={1.0f},const std::vector<int64_t> biasOffsets={0},const std::vector<float> filterScales={1.0f},const std::vector<int64_t> filterOffsets={0},float outputQuantScale=2.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0,int32_t depth_multiplier=1,int32_t filterQuantizationDim=3)197 void ConvolutionTest(tflite::BuiltinOperator convolutionOperatorCode,
198 tflite::TensorType tensorType,
199 uint32_t strideX,
200 uint32_t strideY,
201 uint32_t dilationX,
202 uint32_t dilationY,
203 tflite::Padding padding,
204 tflite::ActivationFunctionType fused_activation_function,
205 std::vector<armnn::BackendId>& backends,
206 std::vector<int32_t>& inputShape,
207 std::vector<int32_t>& filterShape,
208 std::vector<int32_t>& outputShape,
209 std::vector<T>& inputValues,
210 std::vector<T>& filterValues,
211 std::vector<T>& expectedOutputValues,
212 const std::vector<int32_t>& biasShape = {},
213 const std::vector<B>& biasValues = {},
214 const std::vector<float> biasScales = {1.0f},
215 const std::vector<int64_t> biasOffsets = {0},
216 const std::vector<float> filterScales = {1.0f},
217 const std::vector<int64_t> filterOffsets = {0},
218 float outputQuantScale = 2.0f,
219 int outputQuantOffset = 0,
220 float quantScale = 1.0f,
221 int quantOffset = 0,
222 int32_t depth_multiplier = 1,
223 int32_t filterQuantizationDim = 3)
224
225 {
226 using namespace delegateTestInterpreter;
227
228 std::vector<char> modelBuffer;
229 modelBuffer = CreateConv2dTfLiteModel(convolutionOperatorCode,
230 tensorType,
231 strideX,
232 strideY,
233 dilationX,
234 dilationY,
235 padding,
236 fused_activation_function,
237 inputShape,
238 filterShape,
239 biasShape,
240 outputShape,
241 filterValues,
242 biasValues,
243 biasScales,
244 biasOffsets,
245 filterScales,
246 filterOffsets,
247 outputQuantScale,
248 outputQuantOffset,
249 quantScale,
250 quantOffset,
251 depth_multiplier,
252 filterQuantizationDim);
253
254 // Setup interpreter with just TFLite Runtime.
255 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
256 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
257 CHECK(tfLiteInterpreter.FillInputTensor<T>(inputValues, 0) == kTfLiteOk);
258 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
259 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
260 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
261
262 // Setup interpreter with Arm NN Delegate applied.
263 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, backends);
264 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
265 CHECK(armnnInterpreter.FillInputTensor<T>(inputValues, 0) == kTfLiteOk);
266 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
267 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
268 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
269
270 armnnDelegate::CompareOutputData<T>(tfLiteOutputValues, armnnOutputValues, expectedOutputValues);
271 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, outputShape);
272
273 tfLiteInterpreter.Cleanup();
274 armnnInterpreter.Cleanup();
275 }
276
277 // Conv3d is only correctly supported for external delegates from TF Lite v2.6, as there was a breaking bug in v2.5.
278 #if defined(ARMNN_POST_TFLITE_2_5)
279 template <typename T, typename B = float>
CreateConv3dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,tflite::TensorType tensorType,std::vector<uint32_t> strides,std::vector<uint32_t> dilation,tflite::Padding padding,tflite::ActivationFunctionType fused_activation_function,const std::vector<int32_t> & inputTensorShape,const std::vector<int32_t> & filterTensorShape,const std::vector<int32_t> & biasTensorShape,const std::vector<int32_t> & outputTensorShape,const std::vector<T> & filterData,const std::vector<B> & biasData,const std::vector<float> biasScales={1.0f},const std::vector<int64_t> biasOffsets={0},const std::vector<float> filterScales={1.0f},const std::vector<int64_t> filterOffsets={0},float outputQuantScale=2.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0,int32_t depth_multiplier=1,int32_t filterQuantizationDim=0)280 std::vector<char> CreateConv3dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,
281 tflite::TensorType tensorType,
282 std::vector<uint32_t> strides,
283 std::vector<uint32_t> dilation,
284 tflite::Padding padding,
285 tflite::ActivationFunctionType fused_activation_function,
286 const std::vector<int32_t>& inputTensorShape,
287 const std::vector<int32_t>& filterTensorShape,
288 const std::vector<int32_t>& biasTensorShape,
289 const std::vector<int32_t>& outputTensorShape,
290 const std::vector<T>& filterData,
291 const std::vector<B>& biasData,
292 const std::vector<float> biasScales = {1.0f},
293 const std::vector<int64_t> biasOffsets = {0},
294 const std::vector<float> filterScales = {1.0f},
295 const std::vector<int64_t> filterOffsets = {0},
296 float outputQuantScale = 2.0f,
297 int outputQuantOffset = 0,
298 float quantScale = 1.0f,
299 int quantOffset = 0,
300 int32_t depth_multiplier = 1,
301 int32_t filterQuantizationDim = 0)
302 {
303 using namespace tflite;
304 flatbuffers::FlatBufferBuilder flatBufferBuilder;
305
306 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
307 buffers[0] = CreateBuffer(flatBufferBuilder);
308 buffers[1] = CreateBuffer(flatBufferBuilder,
309 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
310 sizeof(T) * filterData.size()));
311
312 buffers[2] = CreateBuffer(flatBufferBuilder,
313 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(biasData.data()),
314 sizeof(B) * biasData.size()));
315
316 auto quantizationParameters =
317 CreateQuantizationParameters(flatBufferBuilder,
318 0,
319 0,
320 flatBufferBuilder.CreateVector<float>({ quantScale }),
321 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
322 auto outputQuantizationParameters =
323 CreateQuantizationParameters(flatBufferBuilder,
324 0,
325 0,
326 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
327 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
328
329 auto filterQuantizationParameters =
330 CreateQuantizationParameters(flatBufferBuilder,
331 0,
332 0,
333 flatBufferBuilder.CreateVector<float>(filterScales),
334 flatBufferBuilder.CreateVector<int64_t>(filterOffsets),
335 tflite::QuantizationDetails_NONE,
336 0,
337 filterQuantizationDim);
338
339 auto biasQuantizationParameters =
340 CreateQuantizationParameters(flatBufferBuilder,
341 0,
342 0,
343 flatBufferBuilder.CreateVector<float>(biasScales),
344 flatBufferBuilder.CreateVector<int64_t>(biasOffsets));
345
346 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
347 tensors[0] = CreateTensor(flatBufferBuilder,
348 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
349 inputTensorShape.size()),
350 tensorType,
351 0,
352 flatBufferBuilder.CreateString("input"),
353 quantizationParameters);
354 tensors[1] = CreateTensor(flatBufferBuilder,
355 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
356 filterTensorShape.size()),
357 tensorType,
358 1,
359 flatBufferBuilder.CreateString("filter"),
360 filterQuantizationParameters);
361
362 auto biasTensorType = ::tflite::TensorType_FLOAT32;
363 if (tensorType == ::tflite::TensorType_INT8 || tensorType == ::tflite::TensorType_UINT8)
364 {
365 biasTensorType = ::tflite::TensorType_INT32;
366 }
367 tensors[2] = CreateTensor(flatBufferBuilder,
368 flatBufferBuilder.CreateVector<int32_t>(biasTensorShape.data(), biasTensorShape.size()),
369 biasTensorType,
370 2,
371 flatBufferBuilder.CreateString("bias"),
372 biasQuantizationParameters);
373 tensors[3] = CreateTensor(flatBufferBuilder,
374 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
375 outputTensorShape.size()),
376 tensorType,
377 0,
378 flatBufferBuilder.CreateString("output"),
379 outputQuantizationParameters);
380
381 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_Conv3DOptions;
382 flatbuffers::Offset<void> operatorBuiltinOptions = CreateConv3DOptions(flatBufferBuilder,
383 padding,
384 strides[2], // Depth
385 strides[0], // Width
386 strides[1], // Height
387 fused_activation_function,
388 dilation[2],
389 dilation[0],
390 dilation[1]).Union();
391
392 // Create operator
393 const std::vector<int> operatorInputs{0, 1, 2};
394 const std::vector<int> operatorOutputs{3};
395 flatbuffers::Offset <Operator> convolutionOperator =
396 CreateOperator(flatBufferBuilder,
397 0,
398 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
399 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
400 operatorBuiltinOptionsType,
401 operatorBuiltinOptions);
402
403 const std::vector<int> subgraphInputs{0, 1, 2};
404 const std::vector<int> subgraphOutputs{3};
405 flatbuffers::Offset <SubGraph> subgraph =
406 CreateSubGraph(flatBufferBuilder,
407 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
408 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
409 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
410 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
411
412 flatbuffers::Offset <flatbuffers::String> modelDescription =
413 flatBufferBuilder.CreateString("ArmnnDelegate: Convolution 3d Operator Model");
414
415 // If using an operator with a code greater than 127 then the enum value should be passed as the fifth
416 // parameter rather than the second like in other tests.
417 flatbuffers::Offset <OperatorCode> operatorCode =
418 CreateOperatorCode(flatBufferBuilder, 0, 0, 1, tflite::BuiltinOperator_CONV_3D);
419
420 flatbuffers::Offset <Model> flatbufferModel =
421 CreateModel(flatBufferBuilder,
422 TFLITE_SCHEMA_VERSION,
423 flatBufferBuilder.CreateVector(&operatorCode, 1),
424 flatBufferBuilder.CreateVector(&subgraph, 1),
425 modelDescription,
426 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
427
428 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
429
430 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
431 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
432 }
433
434 template <typename T, typename B = float>
Convolution3dTest(tflite::BuiltinOperator convolutionOperatorCode,tflite::TensorType tensorType,std::vector<uint32_t> strides,std::vector<uint32_t> dilation,tflite::Padding padding,tflite::ActivationFunctionType fused_activation_function,std::vector<armnn::BackendId> & backends,std::vector<int32_t> & inputShape,std::vector<int32_t> & filterShape,std::vector<int32_t> & outputShape,std::vector<T> & inputValues,std::vector<T> & filterValues,std::vector<T> & expectedOutputValues,const std::vector<int32_t> & biasShape={},const std::vector<B> & biasValues={},const std::vector<float> biasScales={1.0f},const std::vector<int64_t> biasOffsets={0},const std::vector<float> filterScales={1.0f},const std::vector<int64_t> filterOffsets={0},float outputQuantScale=2.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0,int32_t depth_multiplier=1,int32_t filterQuantizationDim=3)435 void Convolution3dTest(tflite::BuiltinOperator convolutionOperatorCode,
436 tflite::TensorType tensorType,
437 std::vector<uint32_t> strides,
438 std::vector<uint32_t> dilation,
439 tflite::Padding padding,
440 tflite::ActivationFunctionType fused_activation_function,
441 std::vector<armnn::BackendId>& backends,
442 std::vector<int32_t>& inputShape,
443 std::vector<int32_t>& filterShape,
444 std::vector<int32_t>& outputShape,
445 std::vector<T>& inputValues,
446 std::vector<T>& filterValues,
447 std::vector<T>& expectedOutputValues,
448 const std::vector<int32_t>& biasShape = {},
449 const std::vector<B>& biasValues = {},
450 const std::vector<float> biasScales = {1.0f},
451 const std::vector<int64_t> biasOffsets = {0},
452 const std::vector<float> filterScales = {1.0f},
453 const std::vector<int64_t> filterOffsets = {0},
454 float outputQuantScale = 2.0f,
455 int outputQuantOffset = 0,
456 float quantScale = 1.0f,
457 int quantOffset = 0,
458 int32_t depth_multiplier = 1,
459 int32_t filterQuantizationDim = 3)
460 {
461 using namespace delegateTestInterpreter;
462
463 std::vector<char> modelBuffer;
464 modelBuffer = CreateConv3dTfLiteModel(convolutionOperatorCode,
465 tensorType,
466 strides,
467 dilation,
468 padding,
469 fused_activation_function,
470 inputShape,
471 filterShape,
472 biasShape,
473 outputShape,
474 filterValues,
475 biasValues,
476 biasScales,
477 biasOffsets,
478 filterScales,
479 filterOffsets,
480 outputQuantScale,
481 outputQuantOffset,
482 quantScale,
483 quantOffset,
484 depth_multiplier,
485 filterQuantizationDim);
486
487 // Setup interpreter with just TFLite Runtime.
488 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
489 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
490 CHECK(tfLiteInterpreter.FillInputTensor<T>(inputValues, 0) == kTfLiteOk);
491 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
492 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
493 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
494
495 // Setup interpreter with Arm NN Delegate applied.
496 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, backends);
497 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
498 CHECK(armnnInterpreter.FillInputTensor<T>(inputValues, 0) == kTfLiteOk);
499 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
500 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
501 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
502
503 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, outputShape);
504
505 armnnDelegate::CompareData(expectedOutputValues.data(), armnnOutputValues.data(), expectedOutputValues.size(), 1);
506 armnnDelegate::CompareData(expectedOutputValues.data(), tfLiteOutputValues.data(), expectedOutputValues.size(), 1);
507 armnnDelegate::CompareData(tfLiteOutputValues.data(), armnnOutputValues.data(), expectedOutputValues.size(), 1);
508
509 tfLiteInterpreter.Cleanup();
510 armnnInterpreter.Cleanup();
511 }
512 #endif
513
514 template <typename T>
CreateTransposeConvTfLiteModel(tflite::TensorType tensorType,uint32_t strideX,uint32_t strideY,tflite::Padding padding,const std::vector<int32_t> & transposeTensorShape,const std::vector<int32_t> & filterTensorShape,const std::vector<int32_t> & inputTensorShape,const std::vector<int32_t> & outputTensorShape,const std::vector<int32_t> & transposeData,const std::vector<T> & filterData,float filterScale=1.0f,int filterOffset=0,float outputQuantScale=2.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0)515 std::vector<char> CreateTransposeConvTfLiteModel(tflite::TensorType tensorType,
516 uint32_t strideX,
517 uint32_t strideY,
518 tflite::Padding padding,
519 const std::vector <int32_t>& transposeTensorShape,
520 const std::vector <int32_t>& filterTensorShape,
521 const std::vector <int32_t>& inputTensorShape,
522 const std::vector <int32_t>& outputTensorShape,
523 const std::vector <int32_t>& transposeData,
524 const std::vector <T>& filterData,
525 float filterScale = 1.0f,
526 int filterOffset = 0,
527 float outputQuantScale = 2.0f,
528 int outputQuantOffset = 0,
529 float quantScale = 1.0f,
530 int quantOffset = 0)
531 {
532 using namespace tflite;
533 flatbuffers::FlatBufferBuilder flatBufferBuilder;
534
535 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
536 buffers[0] = CreateBuffer(flatBufferBuilder);
537 buffers[1] = CreateBuffer(flatBufferBuilder,
538 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(transposeData.data()),
539 sizeof(int32_t) * transposeData.size()));
540 buffers[2] = CreateBuffer(flatBufferBuilder,
541 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
542 sizeof(T) * filterData.size()));
543
544 auto quantizationParameters =
545 CreateQuantizationParameters(flatBufferBuilder,
546 0,
547 0,
548 flatBufferBuilder.CreateVector<float>({ quantScale }),
549 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
550 auto outputQuantizationParameters =
551 CreateQuantizationParameters(flatBufferBuilder,
552 0,
553 0,
554 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
555 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
556 auto filterQuantizationParameters =
557 CreateQuantizationParameters(flatBufferBuilder,
558 0,
559 0,
560 flatBufferBuilder.CreateVector<float>({ filterScale }),
561 flatBufferBuilder.CreateVector<int64_t>({ filterOffset }));
562
563 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
564 tensors[0] = CreateTensor(flatBufferBuilder,
565 flatBufferBuilder.CreateVector<int32_t>(transposeTensorShape.data(),
566 transposeTensorShape.size()),
567 tflite::TensorType_INT32,
568 1);
569 tensors[1] = CreateTensor(flatBufferBuilder,
570 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
571 filterTensorShape.size()),
572 tensorType,
573 2,
574 flatBufferBuilder.CreateString("filter"),
575 filterQuantizationParameters);
576 tensors[2] = CreateTensor(flatBufferBuilder,
577 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
578 inputTensorShape.size()),
579 tensorType,
580 0,
581 flatBufferBuilder.CreateString("input"),
582 quantizationParameters);
583 tensors[3] = CreateTensor(flatBufferBuilder,
584 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
585 outputTensorShape.size()),
586 tensorType,
587 0,
588 flatBufferBuilder.CreateString("output"),
589 outputQuantizationParameters);
590
591 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_TransposeConvOptions;
592 flatbuffers::Offset<void> operatorBuiltinOptions =
593 CreateTransposeConvOptions(flatBufferBuilder, padding, strideX, strideY).Union();
594
595 // create operator
596 const std::vector<int> operatorInputs{0, 1, 2};
597 const std::vector<int> operatorOutputs{3};
598 flatbuffers::Offset <Operator> convolutionOperator =
599 CreateOperator(flatBufferBuilder,
600 0,
601 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
602 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
603 operatorBuiltinOptionsType,
604 operatorBuiltinOptions);
605
606 const std::vector<int> subgraphInputs{0, 1, 2};
607 const std::vector<int> subgraphOutputs{3};
608 flatbuffers::Offset <SubGraph> subgraph =
609 CreateSubGraph(flatBufferBuilder,
610 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
611 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
612 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
613 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
614
615 flatbuffers::Offset <flatbuffers::String> modelDescription =
616 flatBufferBuilder.CreateString("ArmnnDelegate: TransposeConv Operator Model");
617 flatbuffers::Offset <OperatorCode> operatorCode =
618 CreateOperatorCode(flatBufferBuilder, tflite::BuiltinOperator_TRANSPOSE_CONV);
619
620 flatbuffers::Offset <Model> flatbufferModel =
621 CreateModel(flatBufferBuilder,
622 TFLITE_SCHEMA_VERSION,
623 flatBufferBuilder.CreateVector(&operatorCode, 1),
624 flatBufferBuilder.CreateVector(&subgraph, 1),
625 modelDescription,
626 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
627
628 flatBufferBuilder.Finish(flatbufferModel, armnnDelegate::FILE_IDENTIFIER);
629
630 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
631 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
632 }
633
634 template <typename T>
TransposeConvTest(std::vector<armnn::BackendId> & backends,tflite::TensorType tensorType,uint32_t strideX,uint32_t strideY,tflite::Padding padding,const std::vector<int32_t> & transposeTensorShape,const std::vector<int32_t> & filterTensorShape,const std::vector<int32_t> & inputTensorShape,const std::vector<int32_t> & outputTensorShape,const std::vector<int32_t> & transposeData,const std::vector<T> & filterData,std::vector<T> & inputValues,std::vector<T> & expectedOutputValues,float filterScale=1.0f,int filterOffset=0,float outputQuantScale=1.0f,int outputQuantOffset=0,float quantScale=1.0f,int quantOffset=0)635 void TransposeConvTest(std::vector<armnn::BackendId>& backends,
636 tflite::TensorType tensorType,
637 uint32_t strideX,
638 uint32_t strideY,
639 tflite::Padding padding,
640 const std::vector <int32_t>& transposeTensorShape,
641 const std::vector <int32_t>& filterTensorShape,
642 const std::vector <int32_t>& inputTensorShape,
643 const std::vector <int32_t>& outputTensorShape,
644 const std::vector <int32_t>& transposeData,
645 const std::vector <T>& filterData,
646 std::vector<T>& inputValues,
647 std::vector<T>& expectedOutputValues,
648 float filterScale = 1.0f,
649 int filterOffset = 0,
650 float outputQuantScale = 1.0f,
651 int outputQuantOffset = 0,
652 float quantScale = 1.0f,
653 int quantOffset = 0)
654 {
655 using namespace delegateTestInterpreter;
656
657 std::vector<char> modelBuffer;
658 modelBuffer = CreateTransposeConvTfLiteModel<T>(tensorType,
659 strideX,
660 strideY,
661 padding,
662 transposeTensorShape,
663 filterTensorShape,
664 inputTensorShape,
665 outputTensorShape,
666 transposeData,
667 filterData,
668 filterScale,
669 filterOffset,
670 outputQuantScale,
671 outputQuantOffset,
672 quantScale,
673 quantOffset);
674
675
676 // Setup interpreter with just TFLite Runtime.
677 auto tfLiteInterpreter = DelegateTestInterpreter(modelBuffer);
678 CHECK(tfLiteInterpreter.AllocateTensors() == kTfLiteOk);
679 CHECK(tfLiteInterpreter.FillInputTensor<T>(inputValues, 2) == kTfLiteOk);
680 CHECK(tfLiteInterpreter.Invoke() == kTfLiteOk);
681 std::vector<T> tfLiteOutputValues = tfLiteInterpreter.GetOutputResult<T>(0);
682 std::vector<int32_t> tfLiteOutputShape = tfLiteInterpreter.GetOutputShape(0);
683
684 // Setup interpreter with Arm NN Delegate applied.
685 auto armnnInterpreter = DelegateTestInterpreter(modelBuffer, backends);
686 CHECK(armnnInterpreter.AllocateTensors() == kTfLiteOk);
687 CHECK(armnnInterpreter.FillInputTensor<T>(inputValues, 2) == kTfLiteOk);
688 CHECK(armnnInterpreter.Invoke() == kTfLiteOk);
689 std::vector<T> armnnOutputValues = armnnInterpreter.GetOutputResult<T>(0);
690 std::vector<int32_t> armnnOutputShape = armnnInterpreter.GetOutputShape(0);
691
692 armnnDelegate::CompareOutputData<T>(tfLiteOutputValues, armnnOutputValues, expectedOutputValues);
693 armnnDelegate::CompareOutputShape(tfLiteOutputShape, armnnOutputShape, outputTensorShape);
694
695 tfLiteInterpreter.Cleanup();
696 armnnInterpreter.Cleanup();
697 }
698
699 } // anonymous namespace
700
701
702
703
704