blob: ce1f951d2109b5729c0099b83ff18da322131eb7 [file] [log] [blame]
Sadik Armagan32ca1442020-11-13 17:51:56 +00001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
Matthew Sloyan81ec9942021-10-12 10:26:30 +01008#include "TestUtils.hpp"
9
Sadik Armagan32ca1442020-11-13 17:51:56 +000010#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>
16#include <tensorflow/lite/schema/schema_generated.h>
17#include <tensorflow/lite/version.h>
18
19#include <doctest/doctest.h>
20
21namespace
22{
23
24template <typename T, typename B = float>
25std::vector<char> CreateConv2dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,
26 tflite::TensorType tensorType,
27 uint32_t strideX,
28 uint32_t strideY,
29 uint32_t dilationX,
30 uint32_t dilationY,
31 tflite::Padding padding,
32 tflite::ActivationFunctionType fused_activation_function,
33 const std::vector <int32_t>& inputTensorShape,
34 const std::vector <int32_t>& filterTensorShape,
35 const std::vector <int32_t>& biasTensorShape,
36 const std::vector <int32_t>& outputTensorShape,
37 const std::vector <T>& filterData,
38 const std::vector <B>& biasData,
Jan Eilers7612bd62021-04-06 17:29:03 +010039 const std::vector<float> biasScales = {1.0f},
40 const std::vector<int64_t> biasOffsets = {0},
41 const std::vector<float> filterScales = {1.0f},
42 const std::vector<int64_t> filterOffsets = {0},
Sadik Armagan32ca1442020-11-13 17:51:56 +000043 float outputQuantScale = 2.0f,
44 int outputQuantOffset = 0,
45 float quantScale = 1.0f,
46 int quantOffset = 0,
Jan Eilers7612bd62021-04-06 17:29:03 +010047 int32_t depth_multiplier = 1,
48 int32_t filterQuantizationDim = 0)
Sadik Armagan32ca1442020-11-13 17:51:56 +000049{
50 using namespace tflite;
51 flatbuffers::FlatBufferBuilder flatBufferBuilder;
52
53 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
54 buffers[0] = CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({}));
55 buffers[1] = CreateBuffer(flatBufferBuilder,
56 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
57 sizeof(T) * filterData.size()));
58
59 buffers[2] = CreateBuffer(flatBufferBuilder,
60 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(biasData.data()),
61 sizeof(B) * biasData.size()));
62
63 auto quantizationParameters =
64 CreateQuantizationParameters(flatBufferBuilder,
65 0,
66 0,
67 flatBufferBuilder.CreateVector<float>({ quantScale }),
68 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
69 auto outputQuantizationParameters =
70 CreateQuantizationParameters(flatBufferBuilder,
71 0,
72 0,
73 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
74 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
Jan Eilers7612bd62021-04-06 17:29:03 +010075
Sadik Armagan32ca1442020-11-13 17:51:56 +000076 auto filterQuantizationParameters =
Jan Eilers7612bd62021-04-06 17:29:03 +010077 CreateQuantizationParameters(flatBufferBuilder,
78 0,
79 0,
80 flatBufferBuilder.CreateVector<float>(filterScales),
81 flatBufferBuilder.CreateVector<int64_t>(filterOffsets),
82 tflite::QuantizationDetails_NONE,
83 0,
84 filterQuantizationDim);
85
86 auto biasQuantizationParameters =
87 CreateQuantizationParameters(flatBufferBuilder,
88 0,
89 0,
90 flatBufferBuilder.CreateVector<float>(biasScales),
91 flatBufferBuilder.CreateVector<int64_t>(biasOffsets));
Sadik Armagan32ca1442020-11-13 17:51:56 +000092
93 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
94 tensors[0] = CreateTensor(flatBufferBuilder,
95 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
96 inputTensorShape.size()),
97 tensorType,
98 0,
99 flatBufferBuilder.CreateString("input"),
100 quantizationParameters);
101 tensors[1] = CreateTensor(flatBufferBuilder,
102 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
103 filterTensorShape.size()),
104 tensorType,
105 1,
106 flatBufferBuilder.CreateString("filter"),
107 filterQuantizationParameters);
108
109 auto biasTensorType = ::tflite::TensorType_FLOAT32;
Jan Eilerseb616122020-11-20 11:59:40 +0000110 if (tensorType == ::tflite::TensorType_INT8 || tensorType == ::tflite::TensorType_UINT8)
Sadik Armagan32ca1442020-11-13 17:51:56 +0000111 {
112 biasTensorType = ::tflite::TensorType_INT32;
113 }
114 tensors[2] = CreateTensor(flatBufferBuilder,
115 flatBufferBuilder.CreateVector<int32_t>(biasTensorShape.data(), biasTensorShape.size()),
116 biasTensorType,
117 2,
118 flatBufferBuilder.CreateString("bias"),
Jan Eilers7612bd62021-04-06 17:29:03 +0100119 biasQuantizationParameters);
Sadik Armagan32ca1442020-11-13 17:51:56 +0000120 tensors[3] = CreateTensor(flatBufferBuilder,
121 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
122 outputTensorShape.size()),
123 tensorType,
124 0,
125 flatBufferBuilder.CreateString("output"),
126 outputQuantizationParameters);
127
128 flatbuffers::Offset<void> operatorBuiltinOptions;
129 tflite::BuiltinOptions operatorBuiltinOptionsType;
130
131 if(convolutionOperatorCode == tflite::BuiltinOperator_DEPTHWISE_CONV_2D)
132 {
133 operatorBuiltinOptionsType = tflite::BuiltinOptions_DepthwiseConv2DOptions;
134 operatorBuiltinOptions = CreateDepthwiseConv2DOptions(flatBufferBuilder,
135 padding,
136 strideX,
137 strideY,
138 depth_multiplier,
139 fused_activation_function,
140 dilationX,
141 dilationY).Union();
142 }
143 if(convolutionOperatorCode == tflite::BuiltinOperator_CONV_2D)
144 {
145 operatorBuiltinOptionsType = tflite::BuiltinOptions_Conv2DOptions;
146 operatorBuiltinOptions = CreateConv2DOptions(flatBufferBuilder,
147 padding,
148 strideX,
149 strideY,
150 fused_activation_function,
151 dilationX,
152 dilationY).Union();
153 }
154
155 // create operator
Keith Davis892fafe2020-11-26 17:40:35 +0000156 const std::vector<int> operatorInputs{0, 1, 2};
157 const std::vector<int> operatorOutputs{3};
Sadik Armagan32ca1442020-11-13 17:51:56 +0000158 flatbuffers::Offset <Operator> convolutionOperator =
159 CreateOperator(flatBufferBuilder,
160 0,
161 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
162 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
163 operatorBuiltinOptionsType,
164 operatorBuiltinOptions);
165
Keith Davis892fafe2020-11-26 17:40:35 +0000166 const std::vector<int> subgraphInputs{0, 1, 2};
167 const std::vector<int> subgraphOutputs{3};
Sadik Armagan32ca1442020-11-13 17:51:56 +0000168 flatbuffers::Offset <SubGraph> subgraph =
169 CreateSubGraph(flatBufferBuilder,
170 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
171 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
172 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
173 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
174
175 flatbuffers::Offset <flatbuffers::String> modelDescription =
176 flatBufferBuilder.CreateString("ArmnnDelegate: Convolution2d Operator Model");
177 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, convolutionOperatorCode);
178
179 flatbuffers::Offset <Model> flatbufferModel =
180 CreateModel(flatBufferBuilder,
181 TFLITE_SCHEMA_VERSION,
182 flatBufferBuilder.CreateVector(&operatorCode, 1),
183 flatBufferBuilder.CreateVector(&subgraph, 1),
184 modelDescription,
185 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
186
187 flatBufferBuilder.Finish(flatbufferModel);
188
189 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
190 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
191}
192
193template <typename T, typename B = float>
194void ConvolutionTest(tflite::BuiltinOperator convolutionOperatorCode,
195 tflite::TensorType tensorType,
196 uint32_t strideX,
197 uint32_t strideY,
198 uint32_t dilationX,
199 uint32_t dilationY,
200 tflite::Padding padding,
201 tflite::ActivationFunctionType fused_activation_function,
202 std::vector<armnn::BackendId>& backends,
203 std::vector<int32_t>& inputShape,
204 std::vector<int32_t>& filterShape,
205 std::vector<int32_t>& outputShape,
206 std::vector<T>& inputValues,
207 std::vector<T>& filterValues,
208 std::vector<T>& expectedOutputValues,
209 const std::vector<int32_t>& biasShape = {},
210 const std::vector<B>& biasValues = {},
Jan Eilers7612bd62021-04-06 17:29:03 +0100211 const std::vector<float> biasScales = {1.0f},
212 const std::vector<int64_t> biasOffsets = {0},
213 const std::vector<float> filterScales = {1.0f},
214 const std::vector<int64_t> filterOffsets = {0},
Sadik Armagan32ca1442020-11-13 17:51:56 +0000215 float outputQuantScale = 2.0f,
216 int outputQuantOffset = 0,
217 float quantScale = 1.0f,
218 int quantOffset = 0,
Jan Eilers7612bd62021-04-06 17:29:03 +0100219 int32_t depth_multiplier = 1,
220 int32_t filterQuantizationDim = 3)
Sadik Armagan32ca1442020-11-13 17:51:56 +0000221
222{
223 using namespace tflite;
224
225 std::vector<char> modelBuffer;
Matthew Sloyan81ec9942021-10-12 10:26:30 +0100226
Sadik Armagan32ca1442020-11-13 17:51:56 +0000227 modelBuffer = CreateConv2dTfLiteModel(convolutionOperatorCode,
228 tensorType,
229 strideX,
230 strideY,
231 dilationX,
232 dilationY,
233 padding,
234 fused_activation_function,
235 inputShape,
236 filterShape,
237 biasShape,
238 outputShape,
239 filterValues,
240 biasValues,
Jan Eilers7612bd62021-04-06 17:29:03 +0100241 biasScales,
242 biasOffsets,
243 filterScales,
244 filterOffsets,
Sadik Armagan32ca1442020-11-13 17:51:56 +0000245 outputQuantScale,
246 outputQuantOffset,
247 quantScale,
248 quantOffset,
Jan Eilers7612bd62021-04-06 17:29:03 +0100249 depth_multiplier,
250 filterQuantizationDim);
Sadik Armagan32ca1442020-11-13 17:51:56 +0000251
252
253 const Model* tfLiteModel = GetModel(modelBuffer.data());
254 // Create TfLite Interpreters
255 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
256 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
257 (&armnnDelegateInterpreter) == kTfLiteOk);
258 CHECK(armnnDelegateInterpreter != nullptr);
259 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
260
261 std::unique_ptr<Interpreter> tfLiteInterpreter;
262 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
263 (&tfLiteInterpreter) == kTfLiteOk);
264 CHECK(tfLiteInterpreter != nullptr);
265 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
266
267 // Create the ArmNN Delegate
268 armnnDelegate::DelegateOptions delegateOptions(backends);
269 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
270 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
271 armnnDelegate::TfLiteArmnnDelegateDelete);
272 CHECK(theArmnnDelegate != nullptr);
273 // Modify armnnDelegateInterpreter to use armnnDelegate
274 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
275
276 // Set input data
277 auto tfLiteDelegateInputId = tfLiteInterpreter->inputs()[0];
278 auto tfLiteDelageInputData = tfLiteInterpreter->typed_tensor<T>(tfLiteDelegateInputId);
279 for (unsigned int i = 0; i < inputValues.size(); ++i)
280 {
281 tfLiteDelageInputData[i] = inputValues[i];
282 }
283
284 auto armnnDelegateInputId = armnnDelegateInterpreter->inputs()[0];
285 auto armnnDelegateInputData = armnnDelegateInterpreter->typed_tensor<T>(armnnDelegateInputId);
286 for (unsigned int i = 0; i < inputValues.size(); ++i)
287 {
288 armnnDelegateInputData[i] = inputValues[i];
289 }
290 // Run EnqueueWorkload
291 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
292 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
293
294 // Compare output data
295 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[0];
296 auto tfLiteDelagateOutputData = tfLiteInterpreter->typed_tensor<T>(tfLiteDelegateOutputId);
297 auto armnnDelegateOutputId = armnnDelegateInterpreter->outputs()[0];
298 auto armnnDelegateOutputData = armnnDelegateInterpreter->typed_tensor<T>(armnnDelegateOutputId);
299 for (size_t i = 0; i < expectedOutputValues.size(); i++)
300 {
301 CHECK(tfLiteDelagateOutputData[i] == armnnDelegateOutputData[i]);
302 CHECK(doctest::Approx(tfLiteDelagateOutputData[i]).epsilon(0.000001f) == expectedOutputValues[i]);
303 CHECK(doctest::Approx(armnnDelegateOutputData[i]).epsilon(0.000001f) == expectedOutputValues[i]);
304 }
305}
306
Matthew Sloyan81ec9942021-10-12 10:26:30 +0100307// Conv3d is only correctly supported for external delegates from TF Lite v2.6, as there was a breaking bug in v2.5.
308#if defined(ARMNN_POST_TFLITE_2_5)
309template <typename T, typename B = float>
310std::vector<char> CreateConv3dTfLiteModel(tflite::BuiltinOperator convolutionOperatorCode,
311 tflite::TensorType tensorType,
312 std::vector<uint32_t> strides,
313 std::vector<uint32_t> dilation,
314 tflite::Padding padding,
315 tflite::ActivationFunctionType fused_activation_function,
316 const std::vector<int32_t>& inputTensorShape,
317 const std::vector<int32_t>& filterTensorShape,
318 const std::vector<int32_t>& biasTensorShape,
319 const std::vector<int32_t>& outputTensorShape,
320 const std::vector<T>& filterData,
321 const std::vector<B>& biasData,
322 const std::vector<float> biasScales = {1.0f},
323 const std::vector<int64_t> biasOffsets = {0},
324 const std::vector<float> filterScales = {1.0f},
325 const std::vector<int64_t> filterOffsets = {0},
326 float outputQuantScale = 2.0f,
327 int outputQuantOffset = 0,
328 float quantScale = 1.0f,
329 int quantOffset = 0,
330 int32_t depth_multiplier = 1,
331 int32_t filterQuantizationDim = 0)
332{
333 using namespace tflite;
334 flatbuffers::FlatBufferBuilder flatBufferBuilder;
335
336 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
337 buffers[0] = CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({}));
338 buffers[1] = CreateBuffer(flatBufferBuilder,
339 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
340 sizeof(T) * filterData.size()));
341
342 buffers[2] = CreateBuffer(flatBufferBuilder,
343 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(biasData.data()),
344 sizeof(B) * biasData.size()));
345
346 auto quantizationParameters =
347 CreateQuantizationParameters(flatBufferBuilder,
348 0,
349 0,
350 flatBufferBuilder.CreateVector<float>({ quantScale }),
351 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
352 auto outputQuantizationParameters =
353 CreateQuantizationParameters(flatBufferBuilder,
354 0,
355 0,
356 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
357 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
358
359 auto filterQuantizationParameters =
360 CreateQuantizationParameters(flatBufferBuilder,
361 0,
362 0,
363 flatBufferBuilder.CreateVector<float>(filterScales),
364 flatBufferBuilder.CreateVector<int64_t>(filterOffsets),
365 tflite::QuantizationDetails_NONE,
366 0,
367 filterQuantizationDim);
368
369 auto biasQuantizationParameters =
370 CreateQuantizationParameters(flatBufferBuilder,
371 0,
372 0,
373 flatBufferBuilder.CreateVector<float>(biasScales),
374 flatBufferBuilder.CreateVector<int64_t>(biasOffsets));
375
376 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
377 tensors[0] = CreateTensor(flatBufferBuilder,
378 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
379 inputTensorShape.size()),
380 tensorType,
381 0,
382 flatBufferBuilder.CreateString("input"),
383 quantizationParameters);
384 tensors[1] = CreateTensor(flatBufferBuilder,
385 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
386 filterTensorShape.size()),
387 tensorType,
388 1,
389 flatBufferBuilder.CreateString("filter"),
390 filterQuantizationParameters);
391
392 auto biasTensorType = ::tflite::TensorType_FLOAT32;
393 if (tensorType == ::tflite::TensorType_INT8 || tensorType == ::tflite::TensorType_UINT8)
394 {
395 biasTensorType = ::tflite::TensorType_INT32;
396 }
397 tensors[2] = CreateTensor(flatBufferBuilder,
398 flatBufferBuilder.CreateVector<int32_t>(biasTensorShape.data(), biasTensorShape.size()),
399 biasTensorType,
400 2,
401 flatBufferBuilder.CreateString("bias"),
402 biasQuantizationParameters);
403 tensors[3] = CreateTensor(flatBufferBuilder,
404 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
405 outputTensorShape.size()),
406 tensorType,
407 0,
408 flatBufferBuilder.CreateString("output"),
409 outputQuantizationParameters);
410
411 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_Conv3DOptions;
412 flatbuffers::Offset<void> operatorBuiltinOptions = CreateConv3DOptions(flatBufferBuilder,
413 padding,
414 strides[2], // Depth
415 strides[0], // Width
416 strides[1], // Height
417 fused_activation_function,
418 dilation[2],
419 dilation[0],
420 dilation[1]).Union();
421
422 // Create operator
423 const std::vector<int> operatorInputs{0, 1, 2};
424 const std::vector<int> operatorOutputs{3};
425 flatbuffers::Offset <Operator> convolutionOperator =
426 CreateOperator(flatBufferBuilder,
427 0,
428 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
429 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
430 operatorBuiltinOptionsType,
431 operatorBuiltinOptions);
432
433 const std::vector<int> subgraphInputs{0, 1, 2};
434 const std::vector<int> subgraphOutputs{3};
435 flatbuffers::Offset <SubGraph> subgraph =
436 CreateSubGraph(flatBufferBuilder,
437 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
438 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
439 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
440 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
441
442 flatbuffers::Offset <flatbuffers::String> modelDescription =
443 flatBufferBuilder.CreateString("ArmnnDelegate: Convolution 3d Operator Model");
444
445 // If using an operator with a code greater than 127 then the enum value should be passed as the fifth
446 // parameter rather than the second like in other tests.
447 flatbuffers::Offset <OperatorCode> operatorCode =
448 CreateOperatorCode(flatBufferBuilder, 0, 0, 1, tflite::BuiltinOperator_CONV_3D);
449
450 flatbuffers::Offset <Model> flatbufferModel =
451 CreateModel(flatBufferBuilder,
452 TFLITE_SCHEMA_VERSION,
453 flatBufferBuilder.CreateVector(&operatorCode, 1),
454 flatBufferBuilder.CreateVector(&subgraph, 1),
455 modelDescription,
456 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
457
458 flatBufferBuilder.Finish(flatbufferModel);
459
460 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
461 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
462}
463
464template <typename T, typename B = float>
465void Convolution3dTest(tflite::BuiltinOperator convolutionOperatorCode,
466 tflite::TensorType tensorType,
467 std::vector<uint32_t> strides,
468 std::vector<uint32_t> dilation,
469 tflite::Padding padding,
470 tflite::ActivationFunctionType fused_activation_function,
471 std::vector<armnn::BackendId>& backends,
472 std::vector<int32_t>& inputShape,
473 std::vector<int32_t>& filterShape,
474 std::vector<int32_t>& outputShape,
475 std::vector<T>& inputValues,
476 std::vector<T>& filterValues,
477 std::vector<T>& expectedOutputValues,
478 const std::vector<int32_t>& biasShape = {},
479 const std::vector<B>& biasValues = {},
480 const std::vector<float> biasScales = {1.0f},
481 const std::vector<int64_t> biasOffsets = {0},
482 const std::vector<float> filterScales = {1.0f},
483 const std::vector<int64_t> filterOffsets = {0},
484 float outputQuantScale = 2.0f,
485 int outputQuantOffset = 0,
486 float quantScale = 1.0f,
487 int quantOffset = 0,
488 int32_t depth_multiplier = 1,
489 int32_t filterQuantizationDim = 3)
490{
491 using namespace tflite;
492
493 std::vector<char> modelBuffer;
494 modelBuffer = CreateConv3dTfLiteModel(convolutionOperatorCode,
495 tensorType,
496 strides,
497 dilation,
498 padding,
499 fused_activation_function,
500 inputShape,
501 filterShape,
502 biasShape,
503 outputShape,
504 filterValues,
505 biasValues,
506 biasScales,
507 biasOffsets,
508 filterScales,
509 filterOffsets,
510 outputQuantScale,
511 outputQuantOffset,
512 quantScale,
513 quantOffset,
514 depth_multiplier,
515 filterQuantizationDim);
516
517 const Model* tfLiteModel = GetModel(modelBuffer.data());
518
519 // Create TfLite Interpreters
520 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
521 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
522 (&armnnDelegateInterpreter) == kTfLiteOk);
523 CHECK(armnnDelegateInterpreter != nullptr);
524 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
525
526 std::unique_ptr<Interpreter> tfLiteInterpreter;
527 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
528 (&tfLiteInterpreter) == kTfLiteOk);
529 CHECK(tfLiteInterpreter != nullptr);
530 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
531
532 // Create the ArmNN Delegate
533 armnnDelegate::DelegateOptions delegateOptions(backends);
534 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
535 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
536 armnnDelegate::TfLiteArmnnDelegateDelete);
537 CHECK(theArmnnDelegate != nullptr);
538
539 // Modify armnnDelegateInterpreter to use armnnDelegate
540 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
541
542 // Set input data
543 armnnDelegate::FillInput<T>(tfLiteInterpreter, 0, inputValues);
544 armnnDelegate::FillInput<T>(armnnDelegateInterpreter, 0, inputValues);
545
546 // Run EnqueueWorkload
547 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
548 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
549
550 // Compare output data
551 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[0];
552 auto tfLiteDelagateOutputData = tfLiteInterpreter->typed_tensor<float>(tfLiteDelegateOutputId);
553 auto armnnDelegateOutputId = armnnDelegateInterpreter->outputs()[0];
554 auto armnnDelegateOutputData = armnnDelegateInterpreter->typed_tensor<float>(armnnDelegateOutputId);
555
556 armnnDelegate::CompareData(expectedOutputValues.data(), armnnDelegateOutputData, expectedOutputValues.size(), 1);
557 armnnDelegate::CompareData(expectedOutputValues.data(), tfLiteDelagateOutputData, expectedOutputValues.size(), 1);
558 armnnDelegate::CompareData(tfLiteDelagateOutputData, armnnDelegateOutputData, expectedOutputValues.size(), 1);
559}
560#endif
561
Sadik Armagan32ca1442020-11-13 17:51:56 +0000562template <typename T>
563std::vector<char> CreateTransposeConvTfLiteModel(tflite::TensorType tensorType,
564 uint32_t strideX,
565 uint32_t strideY,
566 tflite::Padding padding,
567 const std::vector <int32_t>& transposeTensorShape,
568 const std::vector <int32_t>& filterTensorShape,
569 const std::vector <int32_t>& inputTensorShape,
570 const std::vector <int32_t>& outputTensorShape,
571 const std::vector <int32_t>& transposeData,
572 const std::vector <T>& filterData,
573 float filterScale = 1.0f,
574 int filterOffset = 0,
575 float outputQuantScale = 2.0f,
576 int outputQuantOffset = 0,
577 float quantScale = 1.0f,
578 int quantOffset = 0)
579{
580 using namespace tflite;
581 flatbuffers::FlatBufferBuilder flatBufferBuilder;
582
583 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
584 buffers[0] = CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({}));
585 buffers[1] = CreateBuffer(flatBufferBuilder,
586 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(transposeData.data()),
587 sizeof(int32_t) * transposeData.size()));
588 buffers[2] = CreateBuffer(flatBufferBuilder,
589 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(filterData.data()),
590 sizeof(T) * filterData.size()));
591
592 auto quantizationParameters =
593 CreateQuantizationParameters(flatBufferBuilder,
594 0,
595 0,
596 flatBufferBuilder.CreateVector<float>({ quantScale }),
597 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
598 auto outputQuantizationParameters =
599 CreateQuantizationParameters(flatBufferBuilder,
600 0,
601 0,
602 flatBufferBuilder.CreateVector<float>({ outputQuantScale }),
603 flatBufferBuilder.CreateVector<int64_t>({ outputQuantOffset }));
604 auto filterQuantizationParameters =
605 CreateQuantizationParameters(flatBufferBuilder,
606 0,
607 0,
608 flatBufferBuilder.CreateVector<float>({ filterScale }),
609 flatBufferBuilder.CreateVector<int64_t>({ filterOffset }));
610
611 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
612 tensors[0] = CreateTensor(flatBufferBuilder,
613 flatBufferBuilder.CreateVector<int32_t>(transposeTensorShape.data(),
614 transposeTensorShape.size()),
615 tflite::TensorType_INT32,
616 1);
617 tensors[1] = CreateTensor(flatBufferBuilder,
618 flatBufferBuilder.CreateVector<int32_t>(filterTensorShape.data(),
619 filterTensorShape.size()),
620 tensorType,
621 2,
622 flatBufferBuilder.CreateString("filter"),
623 filterQuantizationParameters);
624 tensors[2] = CreateTensor(flatBufferBuilder,
625 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
626 inputTensorShape.size()),
627 tensorType,
628 0,
629 flatBufferBuilder.CreateString("input"),
630 quantizationParameters);
631 tensors[3] = CreateTensor(flatBufferBuilder,
632 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
633 outputTensorShape.size()),
634 tensorType,
635 0,
636 flatBufferBuilder.CreateString("output"),
637 outputQuantizationParameters);
638
639 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_TransposeConvOptions;
640 flatbuffers::Offset<void> operatorBuiltinOptions =
641 CreateTransposeConvOptions(flatBufferBuilder, padding, strideX, strideY).Union();
642
643 // create operator
Keith Davis892fafe2020-11-26 17:40:35 +0000644 const std::vector<int> operatorInputs{0, 1, 2};
645 const std::vector<int> operatorOutputs{3};
Sadik Armagan32ca1442020-11-13 17:51:56 +0000646 flatbuffers::Offset <Operator> convolutionOperator =
647 CreateOperator(flatBufferBuilder,
648 0,
649 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
650 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
651 operatorBuiltinOptionsType,
652 operatorBuiltinOptions);
653
Keith Davis892fafe2020-11-26 17:40:35 +0000654 const std::vector<int> subgraphInputs{0, 1, 2};
655 const std::vector<int> subgraphOutputs{3};
Sadik Armagan32ca1442020-11-13 17:51:56 +0000656 flatbuffers::Offset <SubGraph> subgraph =
657 CreateSubGraph(flatBufferBuilder,
658 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
659 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
660 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
661 flatBufferBuilder.CreateVector(&convolutionOperator, 1));
662
663 flatbuffers::Offset <flatbuffers::String> modelDescription =
664 flatBufferBuilder.CreateString("ArmnnDelegate: TransposeConv Operator Model");
665 flatbuffers::Offset <OperatorCode> operatorCode =
666 CreateOperatorCode(flatBufferBuilder, tflite::BuiltinOperator_TRANSPOSE_CONV);
667
668 flatbuffers::Offset <Model> flatbufferModel =
669 CreateModel(flatBufferBuilder,
670 TFLITE_SCHEMA_VERSION,
671 flatBufferBuilder.CreateVector(&operatorCode, 1),
672 flatBufferBuilder.CreateVector(&subgraph, 1),
673 modelDescription,
674 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
675
676 flatBufferBuilder.Finish(flatbufferModel);
677
678 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
679 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
680}
681
682template <typename T>
683void TransposeConvTest(std::vector<armnn::BackendId>& backends,
684 tflite::TensorType tensorType,
685 uint32_t strideX,
686 uint32_t strideY,
687 tflite::Padding padding,
688 const std::vector <int32_t>& transposeTensorShape,
689 const std::vector <int32_t>& filterTensorShape,
690 const std::vector <int32_t>& inputTensorShape,
691 const std::vector <int32_t>& outputTensorShape,
692 const std::vector <int32_t>& transposeData,
693 const std::vector <T>& filterData,
694 std::vector<T>& inputValues,
695 std::vector<T>& expectedOutputValues,
696 float filterScale = 1.0f,
697 int filterOffset = 0,
698 float outputQuantScale = 1.0f,
699 int outputQuantOffset = 0,
700 float quantScale = 1.0f,
701 int quantOffset = 0)
702{
703 using namespace tflite;
704
705 std::vector<char> modelBuffer;
706 modelBuffer = CreateTransposeConvTfLiteModel<T>(tensorType,
707 strideX,
708 strideY,
709 padding,
710 transposeTensorShape,
711 filterTensorShape,
712 inputTensorShape,
713 outputTensorShape,
714 transposeData,
715 filterData,
716 filterScale,
717 filterOffset,
718 outputQuantScale,
719 outputQuantOffset,
720 quantScale,
721 quantOffset);
722
723
724 const Model* tfLiteModel = GetModel(modelBuffer.data());
725 // Create TfLite Interpreters
726 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
727 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
728 (&armnnDelegateInterpreter) == kTfLiteOk);
729 CHECK(armnnDelegateInterpreter != nullptr);
730 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
731
732 std::unique_ptr<Interpreter> tfLiteInterpreter;
733 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
734 (&tfLiteInterpreter) == kTfLiteOk);
735 CHECK(tfLiteInterpreter != nullptr);
736 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
737
738 // Create the ArmNN Delegate
739 armnnDelegate::DelegateOptions delegateOptions(backends);
740 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
741 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
742 armnnDelegate::TfLiteArmnnDelegateDelete);
743 CHECK(theArmnnDelegate != nullptr);
744 // Modify armnnDelegateInterpreter to use armnnDelegate
745 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
746
747 // Set input data
748 auto tfLiteDelegateInputId = tfLiteInterpreter->inputs()[2];
749 auto tfLiteDelageInputData = tfLiteInterpreter->typed_tensor<T>(tfLiteDelegateInputId);
750 for (unsigned int i = 0; i < inputValues.size(); ++i)
751 {
752 tfLiteDelageInputData[i] = inputValues[i];
753 }
754
755 auto armnnDelegateInputId = armnnDelegateInterpreter->inputs()[2];
756 auto armnnDelegateInputData = armnnDelegateInterpreter->typed_tensor<T>(armnnDelegateInputId);
757 for (unsigned int i = 0; i < inputValues.size(); ++i)
758 {
759 armnnDelegateInputData[i] = inputValues[i];
760 }
761 // Run EnqueueWorkload
762 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
763 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
764
765 // Compare output data
766 auto tfLiteDelegateOutputId = tfLiteInterpreter->outputs()[0];
767 auto tfLiteDelagateOutputData = tfLiteInterpreter->typed_tensor<T>(tfLiteDelegateOutputId);
768 auto armnnDelegateOutputId = armnnDelegateInterpreter->outputs()[0];
769 auto armnnDelegateOutputData = armnnDelegateInterpreter->typed_tensor<T>(armnnDelegateOutputId);
770 for (size_t i = 0; i < expectedOutputValues.size(); i++)
771 {
772 CHECK(armnnDelegateOutputData[i] == expectedOutputValues[i]);
773 CHECK(tfLiteDelagateOutputData[i] == expectedOutputValues[i]);
774 CHECK(tfLiteDelagateOutputData[i] == armnnDelegateOutputData[i]);
775 }
776}
777
778} // anonymous namespace
779
780
781
782