blob: 464a5d9cbee3b46fb7024c3164480639dc0ede2b [file] [log] [blame]
Matthew Sloyana35b40b2021-02-05 17:22:28 +00001//
2// Copyright © 2021 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
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
24std::vector<char> CreateBatchSpaceTfLiteModel(tflite::BuiltinOperator batchSpaceOperatorCode,
25 tflite::TensorType tensorType,
26 std::vector<int32_t>& inputTensorShape,
27 std::vector <int32_t>& outputTensorShape,
28 std::vector<unsigned int>& blockData,
29 std::vector<std::pair<unsigned int, unsigned int>>& cropsPadData,
30 float quantScale = 1.0f,
31 int quantOffset = 0)
32{
33 using namespace tflite;
34 flatbuffers::FlatBufferBuilder flatBufferBuilder;
35
36 std::array<flatbuffers::Offset<tflite::Buffer>, 3> buffers;
37 buffers[0] = CreateBuffer(flatBufferBuilder, flatBufferBuilder.CreateVector({}));
38 buffers[1] = CreateBuffer(flatBufferBuilder,
39 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(blockData.data()),
40 sizeof(int32_t) * blockData.size()));
41 buffers[2] = CreateBuffer(flatBufferBuilder,
42 flatBufferBuilder.CreateVector(reinterpret_cast<const uint8_t*>(cropsPadData.data()),
43 sizeof(int64_t) * cropsPadData.size()));
44
45 auto quantizationParameters =
46 CreateQuantizationParameters(flatBufferBuilder,
47 0,
48 0,
49 flatBufferBuilder.CreateVector<float>({ quantScale }),
50 flatBufferBuilder.CreateVector<int64_t>({ quantOffset }));
51
52 std::string cropsOrPadding =
53 batchSpaceOperatorCode == tflite::BuiltinOperator_BATCH_TO_SPACE_ND ? "crops" : "padding";
54
55 std::vector<int32_t> blockShape { 2 };
56 std::vector<int32_t> cropsOrPaddingShape { 2, 2 };
57
58 std::array<flatbuffers::Offset<Tensor>, 4> tensors;
59 tensors[0] = CreateTensor(flatBufferBuilder,
60 flatBufferBuilder.CreateVector<int32_t>(inputTensorShape.data(),
61 inputTensorShape.size()),
62 tensorType,
63 0,
64 flatBufferBuilder.CreateString("input"),
65 quantizationParameters);
66
67 tensors[1] = CreateTensor(flatBufferBuilder,
68 flatBufferBuilder.CreateVector<int32_t>(blockShape.data(),
69 blockShape.size()),
70 ::tflite::TensorType_INT32,
71 1,
72 flatBufferBuilder.CreateString("block"),
73 quantizationParameters);
74
75 tensors[2] = CreateTensor(flatBufferBuilder,
76 flatBufferBuilder.CreateVector<int32_t>(cropsOrPaddingShape.data(),
77 cropsOrPaddingShape.size()),
78 ::tflite::TensorType_INT32,
79 2,
80 flatBufferBuilder.CreateString(cropsOrPadding),
81 quantizationParameters);
82
83 // Create output tensor
84 tensors[3] = CreateTensor(flatBufferBuilder,
85 flatBufferBuilder.CreateVector<int32_t>(outputTensorShape.data(),
86 outputTensorShape.size()),
87 tensorType,
88 0,
89 flatBufferBuilder.CreateString("output"),
90 quantizationParameters);
91
92 // Create operator
93 tflite::BuiltinOptions operatorBuiltinOptionsType = tflite::BuiltinOptions_NONE;
94 flatbuffers::Offset<void> operatorBuiltinOptions = 0;
95 switch (batchSpaceOperatorCode)
96 {
97 case tflite::BuiltinOperator_BATCH_TO_SPACE_ND:
98 {
99 operatorBuiltinOptionsType = tflite::BuiltinOptions_BatchToSpaceNDOptions;
100 operatorBuiltinOptions = CreateBatchToSpaceNDOptions(flatBufferBuilder).Union();
101 break;
102 }
103 case tflite::BuiltinOperator_SPACE_TO_BATCH_ND:
104 {
105 operatorBuiltinOptionsType = tflite::BuiltinOptions_SpaceToBatchNDOptions;
106 operatorBuiltinOptions = CreateSpaceToBatchNDOptions(flatBufferBuilder).Union();
107 break;
108 }
109 default:
110 break;
111 }
112
113 const std::vector<int> operatorInputs{ {0, 1, 2} };
114 const std::vector<int> operatorOutputs{ 3 };
115 flatbuffers::Offset <Operator> batchSpaceOperator =
116 CreateOperator(flatBufferBuilder,
117 0,
118 flatBufferBuilder.CreateVector<int32_t>(operatorInputs.data(), operatorInputs.size()),
119 flatBufferBuilder.CreateVector<int32_t>(operatorOutputs.data(), operatorOutputs.size()),
120 operatorBuiltinOptionsType,
121 operatorBuiltinOptions);
122
123 const std::vector<int> subgraphInputs{ {0, 1, 2} };
124 const std::vector<int> subgraphOutputs{ 3 };
125 flatbuffers::Offset <SubGraph> subgraph =
126 CreateSubGraph(flatBufferBuilder,
127 flatBufferBuilder.CreateVector(tensors.data(), tensors.size()),
128 flatBufferBuilder.CreateVector<int32_t>(subgraphInputs.data(), subgraphInputs.size()),
129 flatBufferBuilder.CreateVector<int32_t>(subgraphOutputs.data(), subgraphOutputs.size()),
130 flatBufferBuilder.CreateVector(&batchSpaceOperator, 1));
131
132 flatbuffers::Offset <flatbuffers::String> modelDescription =
133 flatBufferBuilder.CreateString("ArmnnDelegate: BatchSpace Operator Model");
134 flatbuffers::Offset <OperatorCode> operatorCode = CreateOperatorCode(flatBufferBuilder, batchSpaceOperatorCode);
135
136 flatbuffers::Offset <Model> flatbufferModel =
137 CreateModel(flatBufferBuilder,
138 TFLITE_SCHEMA_VERSION,
139 flatBufferBuilder.CreateVector(&operatorCode, 1),
140 flatBufferBuilder.CreateVector(&subgraph, 1),
141 modelDescription,
142 flatBufferBuilder.CreateVector(buffers.data(), buffers.size()));
143
144 flatBufferBuilder.Finish(flatbufferModel);
145
146 return std::vector<char>(flatBufferBuilder.GetBufferPointer(),
147 flatBufferBuilder.GetBufferPointer() + flatBufferBuilder.GetSize());
148}
149
150template <typename T>
151void BatchSpaceTest(tflite::BuiltinOperator controlOperatorCode,
152 tflite::TensorType tensorType,
153 std::vector<armnn::BackendId>& backends,
154 std::vector<int32_t>& inputShape,
155 std::vector<int32_t>& expectedOutputShape,
156 std::vector<T>& inputValues,
157 std::vector<unsigned int>& blockShapeValues,
158 std::vector<std::pair<unsigned int, unsigned int>>& cropsPaddingValues,
159 std::vector<T>& expectedOutputValues,
160 float quantScale = 1.0f,
161 int quantOffset = 0)
162{
163 using namespace tflite;
164 std::vector<char> modelBuffer = CreateBatchSpaceTfLiteModel(controlOperatorCode,
165 tensorType,
166 inputShape,
167 expectedOutputShape,
168 blockShapeValues,
169 cropsPaddingValues,
170 quantScale,
171 quantOffset);
172
173 const Model* tfLiteModel = GetModel(modelBuffer.data());
174
175 // Create TfLite Interpreters
176 std::unique_ptr<Interpreter> armnnDelegateInterpreter;
177 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
178 (&armnnDelegateInterpreter) == kTfLiteOk);
179 CHECK(armnnDelegateInterpreter != nullptr);
180 CHECK(armnnDelegateInterpreter->AllocateTensors() == kTfLiteOk);
181
182 std::unique_ptr<Interpreter> tfLiteInterpreter;
183 CHECK(InterpreterBuilder(tfLiteModel, ::tflite::ops::builtin::BuiltinOpResolver())
184 (&tfLiteInterpreter) == kTfLiteOk);
185 CHECK(tfLiteInterpreter != nullptr);
186 CHECK(tfLiteInterpreter->AllocateTensors() == kTfLiteOk);
187
188 // Create the ArmNN Delegate
189 armnnDelegate::DelegateOptions delegateOptions(backends);
190 std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)>
191 theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions),
192 armnnDelegate::TfLiteArmnnDelegateDelete);
193 CHECK(theArmnnDelegate != nullptr);
194
195 // Modify armnnDelegateInterpreter to use armnnDelegate
196 CHECK(armnnDelegateInterpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) == kTfLiteOk);
197
198 // Set input data
199 armnnDelegate::FillInput<T>(tfLiteInterpreter, 0, inputValues);
200 armnnDelegate::FillInput<T>(armnnDelegateInterpreter, 0, inputValues);
201
202 // Run EnqueWorkload
203 CHECK(tfLiteInterpreter->Invoke() == kTfLiteOk);
204 CHECK(armnnDelegateInterpreter->Invoke() == kTfLiteOk);
205
206 // Compare output data
207 armnnDelegate::CompareOutputData<T>(tfLiteInterpreter,
208 armnnDelegateInterpreter,
209 expectedOutputShape,
210 expectedOutputValues);
211
212 armnnDelegateInterpreter.reset(nullptr);
213 tfLiteInterpreter.reset(nullptr);
214}
215
216} // anonymous namespace