blob: 87bf0d6c3d495e26d2666632ac04912fa4b4623d [file] [log] [blame]
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +00001//
2// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include <armnn_delegate.hpp>
9
10#include "ConvolutionTestHelper.hpp"
11#include "TestUtils.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 <tensorflow/lite/schema/schema_generated.h>
18#include <tensorflow/lite/version.h>
19
20#include <doctest/doctest.h>
21
22namespace
23{
24
25struct StreamRedirector
26{
27public:
28 StreamRedirector(std::ostream &stream, std::streambuf *newStreamBuffer)
29 : m_Stream(stream), m_BackupBuffer(m_Stream.rdbuf(newStreamBuffer)) {}
30
31 ~StreamRedirector() { m_Stream.rdbuf(m_BackupBuffer); }
32
33private:
34 std::ostream &m_Stream;
35 std::streambuf *m_BackupBuffer;
36};
37
38std::vector<char> CreateAddDivTfLiteModel(tflite::TensorType tensorType,
39 const std::vector<int32_t>& tensorShape,
40 float quantScale = 1.0f,
41 int quantOffset = 0)
42{
43 using namespace tflite;
44 flatbuffers::FlatBufferBuilder flatBufferBuilder;
45
46 std::vector<flatbuffers::Offset<tflite::Buffer>> buffers;
47 buffers.push_back(CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({})));
48
49 auto quantizationParameters =
50 CreateQuantizationParameters(flatBufferBuilder,
51 0,
52 0,
53 flatBufferBuilder.CreateVector<float>({ quantScale }),
54 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
55
56
57 std::array<flatbuffers::Offset<Tensor>, 5> tensors;
58 tensors[0] = CreateTensor(flatBufferBuilder,
59 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
60 tensorShape.size()),
61 tensorType,
62 0,
63 flatBufferBuilder.CreateString("input_0"),
64 quantizationParameters);
65 tensors[1] = CreateTensor(flatBufferBuilder,
66 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
67 tensorShape.size()),
68 tensorType,
69 0,
70 flatBufferBuilder.CreateString("input_1"),
71 quantizationParameters);
72 tensors[2] = CreateTensor(flatBufferBuilder,
73 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
74 tensorShape.size()),
75 tensorType,
76 0,
77 flatBufferBuilder.CreateString("input_2"),
78 quantizationParameters);
79 tensors[3] = CreateTensor(flatBufferBuilder,
80 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
81 tensorShape.size()),
82 tensorType,
83 0,
84 flatBufferBuilder.CreateString("add"),
85 quantizationParameters);
86 tensors[4] = CreateTensor(flatBufferBuilder,
87 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
88 tensorShape.size()),
89 tensorType,
90 0,
91 flatBufferBuilder.CreateString("output"),
92 quantizationParameters);
93
94 // create operator
95 tflite::BuiltinOptions addBuiltinOptionsType = tflite::BuiltinOptions_AddOptions;
96 flatbuffers::Offset<void> addBuiltinOptions =
97 CreateAddOptions(flatBufferBuilder, ActivationFunctionType_NONE).Union();
98
99 tflite::BuiltinOptions divBuiltinOptionsType = tflite::BuiltinOptions_DivOptions;
100 flatbuffers::Offset<void> divBuiltinOptions =
101 CreateAddOptions(flatBufferBuilder, ActivationFunctionType_NONE).Union();
102
103 std::array<flatbuffers::Offset<Operator>, 2> operators;
104 const std::vector<int32_t> addInputs{0, 1};
105 const std::vector<int32_t> addOutputs{3};
106 operators[0] = CreateOperator(flatBufferBuilder,
107 0,
108 flatBufferBuilder.CreateVector<int32_t>(addInputs.data(), addInputs.size()),
109 flatBufferBuilder.CreateVector<int32_t>(addOutputs.data(), addOutputs.size()),
110 addBuiltinOptionsType,
111 addBuiltinOptions);
112 const std::vector<int32_t> divInputs{3, 2};
113 const std::vector<int32_t> divOutputs{4};
114 operators[1] = CreateOperator(flatBufferBuilder,
115 1,
116 flatBufferBuilder.CreateVector<int32_t>(divInputs.data(), divInputs.size()),
117 flatBufferBuilder.CreateVector<int32_t>(divOutputs.data(), divOutputs.size()),
118 divBuiltinOptionsType,
119 divBuiltinOptions);
120
121 const std::vector<int> subgraphInputs{0, 1, 2};
122 const std::vector<int> subgraphOutputs{4};
123 flatbuffers::Offset<SubGraph> subgraph =
124 CreateSubGraph(flatBufferBuilder,
125 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
126 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
127 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
128 flatBufferBuilder.CreateVector(operators.data(), operators.size()));
129
130 flatbuffers::Offset<flatbuffers::String> modelDescription =
131 flatBufferBuilder.CreateString("ArmnnDelegate: Add and Div Operator Model");
132
133 std::array<flatbuffers::Offset<OperatorCode>, 2> codes;
134 codes[0] = CreateOperatorCode(flatBufferBuilder, tflite::BuiltinOperator_ADD);
135 codes[1] = CreateOperatorCode(flatBufferBuilder, tflite::BuiltinOperator_DIV);
136
137 flatbuffers::Offset<Model> flatbufferModel =
138 CreateModel(flatBufferBuilder,
139 TFLITE_SCHEMA_VERSION,
140 flatBufferBuilder.CreateVector(codes.data(), codes.size()),
141 flatBufferBuilder.CreateVector(&subgraph, 1),
142 modelDescription,
143 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
144
145 flatBufferBuilder.Finish(flatbufferModel);
146
147 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
148 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
149}
150
Sadik Armaganca565c12022-08-16 12:17:24 +0100151std::vector<char> CreateCeilTfLiteModel(tflite::TensorType tensorType,
152 const std::vector <int32_t>& tensorShape,
153 float quantScale = 1.0f,
154 int quantOffset = 0)
155{
156 using namespace tflite;
157 flatbuffers::FlatBufferBuilder flatBufferBuilder;
158
159 std::vector<flatbuffers::Offset<tflite::Buffer>> buffers;
160 buffers.push_back(CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({})));
161
162 auto quantizationParameters =
163 CreateQuantizationParameters(flatBufferBuilder,
164 0,
165 0,
166 flatBufferBuilder.CreateVector<float>({quantScale}),
167 flatBufferBuilder.CreateVector<int64_t>({quantOffset}));
168
169 std::array<flatbuffers::Offset<Tensor>, 2> tensors;
170 tensors[0] = CreateTensor(flatBufferBuilder,
171 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
172 tensorShape.size()),
173 tensorType,
174 0,
175 flatBufferBuilder.CreateString("input"),
176 quantizationParameters);
177 tensors[1] = CreateTensor(flatBufferBuilder,
178 flatBufferBuilder.CreateVector<int32_t>(tensorShape.data(),
179 tensorShape.size()),
180 tensorType,
181 0,
182 flatBufferBuilder.CreateString("output"),
183 quantizationParameters);
184
185 const std::vector<int32_t> operatorInputs({0});
186 const std::vector<int32_t> operatorOutputs({1});
187
188 flatbuffers::Offset<Operator> ceilOperator =
189 CreateOperator(flatBufferBuilder,
190 0,
191 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
192 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
193 BuiltinOptions_NONE);
194
195 flatbuffers::Offset<flatbuffers::String> modelDescription =
196 flatBufferBuilder.CreateString("ArmnnDelegate: CEIL Operator Model");
197 flatbuffers::Offset<OperatorCode> operatorCode =
198 CreateOperatorCode(flatBufferBuilder, tflite::BuiltinOperator_CEIL);
199
200 const std::vector<int32_t> subgraphInputs({0});
201 const std::vector<int32_t> subgraphOutputs({1});
202 flatbuffers::Offset<SubGraph> subgraph =
203 CreateSubGraph(flatBufferBuilder,
204 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
205 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
206 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
207 flatBufferBuilder.CreateVector(&ceilOperator, 1));
208
209 flatbuffers::Offset<Model> flatbufferModel =
210 CreateModel(flatBufferBuilder,
211 TFLITE_SCHEMA_VERSION,
212 flatBufferBuilder.CreateVector(&operatorCode, 1),
213 flatBufferBuilder.CreateVector(&subgraph, 1),
214 modelDescription,
215 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
216
217 flatBufferBuilder.Finish(flatbufferModel);
218 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
219 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
220}
221
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000222void ReduceFp32ToBf16TestImpl()
223{
224 using namespace tflite;
225 // Set input data
226 std::vector<int32_t> inputShape{ 1, 5, 5, 1 };
227 std::vector<int32_t> filterShape{ 1, 3, 3, 1 };
228 std::vector<int32_t> biasShape{ 1 };
229 std::vector<int32_t> outputShape{ 1, 3, 3, 1 };
230
231 std::vector<float> inputValues =
232 {
233 1, 5, 2, 3, 5,
234 8, 7, 3, 6, 3,
235 3, 3, 9, 1, 9,
236 4, 1, 8, 1, 3,
237 6, 8, 1, 9, 2
238 };
239
240 std::vector<float> filterValues =
241 {
242 4, 5, 6,
243 0, 0, 0,
244 3, 2, 1
245 };
246
247 std::vector<float> biasValues = { 5 };
248
249 std::vector<float> expectedResult =
250 {
251 28, 38, 29,
252 96, 104, 53,
253 31, 55, 24
254 };
255
256 tflite::Padding padding = Padding_SAME;
257
258 std::vector<char> modelBuffer;
259 modelBuffer = CreateConv2dTfLiteModel<float>(BuiltinOperator_CONV_2D,
260 ::tflite::TensorType_FLOAT32,
261 2,
262 2,
263 1,
264 1,
265 padding,
266 ActivationFunctionType_NONE,
267 inputShape,
268 filterShape,
269 biasShape,
270 outputShape,
271 filterValues,
272 biasValues);
273
274
275 const Model* tfLiteModel = GetModel(modelBuffer.data());
276 // Create TfLite Interpreters
277 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
278 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
279 (&armnnDelegateInterpreter) == kTfLiteOk);
280 CHECK(armnnDelegateInterpreter != nullptr);
281 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
282
283 // Create the Armnn Delegate
284 std::vector<armnn::BackendId> backends = {armnn::Compute::CpuRef};
285 std::vector<armnn::BackendOptions> backendOptions;
286
287 // Enable debug with BF16 enabled
288 armnn::OptimizerOptions optimizerOptions(false, true, true, false);
289
290 armnnDelegate::DelegateOptions delegateOptions(backends, optimizerOptions);
291 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
292 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
293 armnnDelegate::TfLiteArmnnDelegateDelete);
294 CHECK(theArmnnDelegate != nullptr);
295 // Modify armnnDelegateInterpreter to use armnnDelegate
296 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
297
298 // Set input data
299 armnnDelegate::FillInput(armnnDelegateInterpreter, 0, inputValues);
300
301 // Run EnqueueWorkload
302 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
303
304 // Compare output data
305 auto armnnDelegateOutputId = armnnDelegateInterpreter->outputs()[0];
306 auto armnnDelegateOutputData = armnnDelegateInterpreter->typed_tensor<float>(armnnDelegateOutputId);
307 armnnDelegate::CompareData(expectedResult.data(), armnnDelegateOutputData, expectedResult.size());
308 armnnDelegateInterpreter.reset(nullptr);
309}
310
311template <typename T>
312void DelegateOptionTest(tflite::TensorType tensorType,
313 const std::vector<armnn::BackendId>& backends,
314 std::vector<int32_t>& tensorShape,
315 std::vector<T>& input0Values,
316 std::vector<T>& input1Values,
317 std::vector<T>& input2Values,
318 std::vector<T>& expectedOutputValues,
319 const armnnDelegate::DelegateOptions& delegateOptions,
320 float quantScale = 1.0f,
321 int quantOffset = 0)
322{
323 using namespace tflite;
324 std::vector<char> modelBuffer = CreateAddDivTfLiteModel(tensorType,
325 tensorShape,
326 quantScale,
327 quantOffset);
328
329 const Model* tfLiteModel = GetModel(modelBuffer.data());
330 // Create TfLite Interpreters
331 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
332 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
333 (&armnnDelegateInterpreter) == kTfLiteOk);
334 CHECK(armnnDelegateInterpreter != nullptr);
335 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
336
337 std::unique_ptr<Interpreter> tfLiteInterpreter;
338 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
339 (&tfLiteInterpreter) == kTfLiteOk);
340 CHECK(tfLiteInterpreter != nullptr);
341 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
342
343 // Create the ArmNN Delegate
344 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
345 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
346 armnnDelegate::TfLiteArmnnDelegateDelete);
347 CHECK(theArmnnDelegate != nullptr);
348 // Modify armnnDelegateInterpreter to use armnnDelegate
349 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
350
351 // Set input data
352 armnnDelegate::FillInput(tfLiteInterpreter, 0, input0Values);
353 armnnDelegate::FillInput(tfLiteInterpreter, 1, input1Values);
354 armnnDelegate::FillInput(tfLiteInterpreter, 2, input2Values);
355
356 armnnDelegate::FillInput(armnnDelegateInterpreter, 0, input0Values);
357 armnnDelegate::FillInput(armnnDelegateInterpreter, 1, input1Values);
358 armnnDelegate::FillInput(armnnDelegateInterpreter, 2, input2Values);
359
360 // Run EnqueueWorkload
361 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
362 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
363
364 armnnDelegate::CompareOutputData<T>(tfLiteInterpreter, armnnDelegateInterpreter, tensorShape, expectedOutputValues);
365
366 armnnDelegateInterpreter.reset(nullptr);
367}
368
Sadik Armaganca565c12022-08-16 12:17:24 +0100369template <typename T>
370void DelegateOptionNoFallbackTest(tflite::TensorType tensorType,
371 const std::vector<armnn::BackendId>& backends,
372 std::vector<int32_t>& tensorShape,
373 std::vector<T>& inputValues,
374 std::vector<T>& expectedOutputValues,
375 const armnnDelegate::DelegateOptions& delegateOptions,
376 float quantScale = 1.0f,
377 int quantOffset = 0)
378{
379 using namespace tflite;
380 std::vector<char> modelBuffer = CreateCeilTfLiteModel(tensorType,
381 tensorShape,
382 quantScale,
383 quantOffset);
384
385 const Model* tfLiteModel = GetModel(modelBuffer.data());
386 // Create TfLite Interpreters
387 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
388 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
389 (&armnnDelegateInterpreter) == kTfLiteOk);
390 CHECK(armnnDelegateInterpreter != nullptr);
391 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
392
393 std::unique_ptr<Interpreter> tfLiteInterpreter;
394 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
395 (&tfLiteInterpreter) == kTfLiteOk);
396 CHECK(tfLiteInterpreter != nullptr);
397 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
398
399 // Create the ArmNN Delegate
400 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
401 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
402 armnnDelegate::TfLiteArmnnDelegateDelete);
403 CHECK(theArmnnDelegate != nullptr);
404 // Modify armnnDelegateInterpreter to use armnnDelegate
405 try
406 {
407 armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get());
408 }
409 catch (const armnn::Exception& e)
410 {
411 // Forward the exception message to std::cout
412 std::cout << e.what() << std::endl;
413 }
414
415 // Set input data
416 armnnDelegate::FillInput(tfLiteInterpreter, 0, inputValues);
417 armnnDelegate::FillInput(armnnDelegateInterpreter, 0, inputValues);
418
419 // Run EnqueueWorkload
420 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
421 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
422
423 armnnDelegate::CompareOutputData<T>(tfLiteInterpreter, armnnDelegateInterpreter, tensorShape, expectedOutputValues);
424
425 armnnDelegateInterpreter.reset(nullptr);
426}
427
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000428} // anonymous namespace