blob: bb57657aa68206485f2d1eabbd6f3fc5106c02b3 [file] [log] [blame]
Matthew Sloyanba5fad32022-09-26 13:31:43 +01001
2// Copyright (c) 2022, ARM Limited.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
17#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
18#endif
19
Matthew Sloyanba5fad32022-09-26 13:31:43 +010020#include "general_utils.h"
Grant Watson64285a12022-11-16 15:32:39 +000021#include "model_runner.h"
22#include "operators.h"
23
24#include <numeric>
Matthew Sloyanba5fad32022-09-26 13:31:43 +010025
James Ward71dfc702022-10-11 14:13:09 +010026// Remove conflicting REQUIRE definition between doctest and reference_model
27#undef REQUIRE
28
Matthew Sloyanba5fad32022-09-26 13:31:43 +010029#include "doctest.h"
30
31using namespace TosaReference;
32using namespace tosa;
33
34template <typename T>
35void compareOutput(std::vector<T>& tensor1, std::vector<T>& tensor2, size_t size)
36{
37 for (size_t i = 0; i < size; ++i)
38 {
Grant Watson64285a12022-11-16 15:32:39 +000039 CHECK_MESSAGE(tensor1[i] == doctest::Approx(tensor2[i]), "");
Matthew Sloyanba5fad32022-09-26 13:31:43 +010040 }
41}
42
43TEST_SUITE("model_runner")
44{
45
Grant Watson64285a12022-11-16 15:32:39 +000046 TEST_CASE("op_entry_add")
47 {
48 // Inputs/Outputs
49 tosa_datatype_t dt = tosa_datatype_fp32_t;
50 std::vector<int32_t> input_shape = { 2, 4, 4, 1 };
51 std::vector<int32_t> output_shape = { 2, 4, 4, 1 };
52 std::vector<float> srcData1(32, 4.0f);
53 std::vector<float> srcData2(32, 3.0f);
54 std::vector<float> dstData(32, 0.0f);
Matthew Sloyanba5fad32022-09-26 13:31:43 +010055
Grant Watson64285a12022-11-16 15:32:39 +000056 tosa_tensor_t input1;
57 input1.shape = input_shape.data();
58 input1.num_dims = input_shape.size();
59 input1.data_type = dt;
60 input1.data = reinterpret_cast<uint8_t*>(srcData1.data());
61 input1.size = srcData1.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +010062
Grant Watson64285a12022-11-16 15:32:39 +000063 tosa_tensor_t input2;
64 input2.shape = input_shape.data();
65 input2.num_dims = input_shape.size();
66 input2.data_type = dt;
67 input2.data = reinterpret_cast<uint8_t*>(srcData2.data());
68 input2.size = srcData2.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +010069
Grant Watson64285a12022-11-16 15:32:39 +000070 tosa_tensor_t output;
71 output.shape = output_shape.data();
72 output.num_dims = output_shape.size();
73 output.data_type = dt;
74 output.data = reinterpret_cast<uint8_t*>(dstData.data());
75 output.size = dstData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +010076
Grant Watson64285a12022-11-16 15:32:39 +000077 // Execution
78 auto status = tosa_run_add(input1, input2, output);
79 CHECK((status == tosa_status_valid));
Matthew Sloyanba5fad32022-09-26 13:31:43 +010080
Grant Watson64285a12022-11-16 15:32:39 +000081 // Compare results
82 std::vector<float> expectedData(8, 7.0f);
83 compareOutput(dstData, expectedData, expectedData.size());
84 }
Matthew Sloyanba5fad32022-09-26 13:31:43 +010085
Grant Watson64285a12022-11-16 15:32:39 +000086 TEST_CASE("op_entry_avg_pool2d")
87 {
88 // Pool parameters
89 const int32_t kernel[2] = { 2, 2 };
90 const int32_t stride[2] = { 2, 2 };
91 const int32_t pad[4] = { 0, 0, 0, 0 };
Matthew Sloyanba5fad32022-09-26 13:31:43 +010092
Grant Watson64285a12022-11-16 15:32:39 +000093 // Inputs/Outputs
94 tosa_datatype_t dt = tosa_datatype_fp32_t;
95 std::vector<int32_t> input_shape = { 2, 4, 4, 1 };
96 std::vector<int32_t> output_shape = { 2, 2, 2, 1 };
97 std::vector<float> srcData(32, 7.0f);
98 std::vector<float> dstData(8, 0.f);
Matthew Sloyanba5fad32022-09-26 13:31:43 +010099
Grant Watson64285a12022-11-16 15:32:39 +0000100 tosa_tensor_t input;
101 input.shape = input_shape.data();
102 input.num_dims = input_shape.size();
103 input.data_type = dt;
104 input.data = reinterpret_cast<uint8_t*>(srcData.data());
105 input.size = srcData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100106
Grant Watson64285a12022-11-16 15:32:39 +0000107 tosa_tensor_t output;
108 output.shape = output_shape.data();
109 output.num_dims = output_shape.size();
110 output.data_type = dt;
111 output.data = reinterpret_cast<uint8_t*>(dstData.data());
112 output.size = dstData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100113
Grant Watson64285a12022-11-16 15:32:39 +0000114 // Execution
115 auto status = tosa_run_avg_pool2d(input, kernel, stride, pad, 0, 0, output);
116 CHECK((status == tosa_status_valid));
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100117
Grant Watson64285a12022-11-16 15:32:39 +0000118 // Compare results
119 std::vector<float> expectedData(8, 7.0f);
120 compareOutput(dstData, expectedData, expectedData.size());
121 }
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100122
Grant Watson64285a12022-11-16 15:32:39 +0000123 TEST_CASE("op_entry_conv2d")
124 {
125 // Conv parameters
126 const int32_t stride[2] = { 1, 1 };
127 const int32_t pad[4] = { 0, 0, 0, 0 };
128 const int32_t dilation[2] = { 1, 1 };
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100129
Grant Watson64285a12022-11-16 15:32:39 +0000130 // Inputs/Outputs
131 tosa_datatype_t dt = tosa_datatype_fp32_t;
132 std::vector<int32_t> input_shape = { 1, 32, 32, 8 };
133 std::vector<int32_t> output_shape = { 1, 32, 32, 16 };
134 std::vector<int32_t> weight_shape = { 16, 1, 1, 8 };
135 std::vector<int32_t> bias_shape = { 16 };
136 std::vector<float> srcData(32 * 32 * 8, 1.0f);
137 std::vector<float> dstData(32 * 32 * 16, 0.f);
138 std::vector<float> biasData(16, 0.f);
139 std::vector<float> weightData(16 * 8, 1.0f);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100140
Grant Watson64285a12022-11-16 15:32:39 +0000141 tosa_tensor_t input;
142 input.shape = input_shape.data();
143 input.num_dims = input_shape.size();
144 input.data_type = dt;
145 input.data = reinterpret_cast<uint8_t*>(srcData.data());
146 input.size = srcData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100147
Grant Watson64285a12022-11-16 15:32:39 +0000148 tosa_tensor_t weight;
149 weight.shape = weight_shape.data();
150 weight.num_dims = weight_shape.size();
151 weight.data_type = dt;
152 weight.data = reinterpret_cast<uint8_t*>(weightData.data());
153 weight.size = weightData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100154
Grant Watson64285a12022-11-16 15:32:39 +0000155 tosa_tensor_t bias;
156 bias.shape = bias_shape.data();
157 bias.num_dims = bias_shape.size();
158 bias.data_type = dt;
159 bias.data = reinterpret_cast<uint8_t*>(biasData.data());
160 bias.size = biasData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100161
Grant Watson64285a12022-11-16 15:32:39 +0000162 tosa_tensor_t output;
163 output.shape = output_shape.data();
164 output.num_dims = output_shape.size();
165 output.data_type = dt;
166 output.data = reinterpret_cast<uint8_t*>(dstData.data());
167 output.size = dstData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100168
Grant Watson64285a12022-11-16 15:32:39 +0000169 const int32_t input_zp = 0;
170 const int32_t weight_zp = 0;
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100171
Grant Watson64285a12022-11-16 15:32:39 +0000172 // Execution
173 auto status = tosa_run_conv2d(input, weight, bias, pad, stride, dilation, input_zp, weight_zp, output);
174 CHECK((status == tosa_status_valid));
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100175
Grant Watson64285a12022-11-16 15:32:39 +0000176 // Compare results
177 std::vector<float> expectedData(32 * 32 * 16, 8.0f);
178 compareOutput(dstData, expectedData, expectedData.size());
179 }
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100180
Grant Watson64285a12022-11-16 15:32:39 +0000181 TEST_CASE("op_entry_max_pool2d")
182 {
183 // Pool parameters
184 const int32_t kernel[2] = { 2, 2 };
185 const int32_t stride[2] = { 2, 2 };
186 const int32_t pad[4] = { 0, 0, 0, 0 };
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100187
Grant Watson64285a12022-11-16 15:32:39 +0000188 // Inputs/Outputs
189 tosa_datatype_t dt = tosa_datatype_fp32_t;
190 std::vector<int32_t> input_shape = { 2, 4, 4, 1 };
191 std::vector<int32_t> output_shape = { 2, 2, 2, 1 };
192 std::vector<float> srcData(32);
193 std::vector<float> dstData(8, 0.f);
194 std::iota(std::begin(srcData), std::end(srcData), 1);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100195
Grant Watson64285a12022-11-16 15:32:39 +0000196 tosa_tensor_t input;
197 input.shape = input_shape.data();
198 input.num_dims = input_shape.size();
199 input.data_type = dt;
200 input.data = reinterpret_cast<uint8_t*>(srcData.data());
201 input.size = srcData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100202
Grant Watson64285a12022-11-16 15:32:39 +0000203 tosa_tensor_t output;
204 output.shape = output_shape.data();
205 output.num_dims = output_shape.size();
206 output.data_type = dt;
207 output.data = reinterpret_cast<uint8_t*>(dstData.data());
208 output.size = dstData.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100209
Grant Watson64285a12022-11-16 15:32:39 +0000210 // Execution
211 auto status = tosa_run_max_pool2d(input, kernel, stride, pad, 0, 0, output);
212 CHECK((status == tosa_status_valid));
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100213
Grant Watson64285a12022-11-16 15:32:39 +0000214 // Compare results
215 std::vector<float> expectedData = { 6, 8, 14, 16, 22, 24, 30, 32 };
216 compareOutput(dstData, expectedData, expectedData.size());
217 }
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100218
Grant Watson64285a12022-11-16 15:32:39 +0000219 TEST_CASE("op_entry_pad")
220 {
221 // Inputs/Outputs
222 tosa_datatype_t dt = tosa_datatype_fp32_t;
223 std::vector<int32_t> input_shape = { 2, 2 };
224 std::vector<int32_t> output_shape = { 4, 4 };
225 std::vector<float> srcData1(4, 4.0f);
226 std::vector<float> dstData(16, 0.0f);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100227
Grant Watson64285a12022-11-16 15:32:39 +0000228 tosa_tensor_t input1;
229 input1.shape = input_shape.data();
230 input1.num_dims = input_shape.size();
231 input1.data_type = dt;
232 input1.data = reinterpret_cast<uint8_t*>(srcData1.data());
233 input1.size = srcData1.size() * sizeof(float);
Matthew Sloyanba5fad32022-09-26 13:31:43 +0100234
Grant Watson64285a12022-11-16 15:32:39 +0000235 tosa_tensor_t output;
236 output.shape = output_shape.data();
237 output.num_dims = output_shape.size();
238 output.data_type = dt;
239 output.data = reinterpret_cast<uint8_t*>(dstData.data());
240 output.size = dstData.size() * sizeof(float);
241
242 // Execution
243 int32_t padding[4] = { 1, 1, 1, 1 };
244 int32_t padding_len = 4;
245 int32_t pad_const_int = 0;
246 float pad_const_fp = 5.0f;
247 auto status = tosa_run_pad(input1, padding_len, padding, pad_const_int, pad_const_fp, output);
248 CHECK((status == tosa_status_valid));
249
250 // Compare results
251 // Expect a 4x4 array with a border of 5's and inner 2x2 of 4's
252 std::vector<float> expectedData(16, 5.0f);
253 expectedData[5] = 4.0f;
254 expectedData[6] = 4.0f;
255 expectedData[9] = 4.0f;
256 expectedData[10] = 4.0f;
257 compareOutput(dstData, expectedData, expectedData.size());
258 }
259
260 TEST_CASE("simple_add_f32_test")
261 {
262 std::string test_root(std::string(PROJECT_ROOT) + "../examples/test_add_1x4x4x4_f32/");
263 std::string tosa_model_file(test_root + "flatbuffer-tflite/test_add_1x4x4x4_f32.tosa");
264 std::string input0_file(test_root + "placeholder_0.npy");
265 std::string input1_file(test_root + "placeholder_1.npy");
266 std::string expected_output_file(test_root + "tflite_result.npy");
267
268 std::vector<std::string> input_names = { "TosaInput_0", "TosaInput_1" };
269 std::string output_name = "TosaOutput_0";
270
271 std::vector<int32_t> input0_shape = { 1, 4, 4, 1 };
272 std::vector<int32_t> input1_shape = { 1, 4, 4, 4 };
273 std::vector<int32_t> output_shape = { 1, 4, 4, 4 };
274
275 std::vector<std::vector<float>> inputs(input_names.size());
276 std::vector<float> actual_outputs = {};
277 std::vector<float> expected_outputs = {};
278
279 // Read in inputs and expected outputs.
280 inputs[0] = readFromNpyFile<float>(input0_file.c_str(), input0_shape);
281 inputs[1] = readFromNpyFile<float>(input1_file.c_str(), input1_shape);
282 expected_outputs = readFromNpyFile<float>(expected_output_file.c_str(), output_shape);
283
284 TosaSerializationHandler handler;
285 tosa_err_t error = handler.LoadFileTosaFlatbuffer(tosa_model_file.c_str());
286 CHECK((error == tosa::TOSA_OK));
287
288 GraphStatus status;
289
290 // Initialize the ModelRunner with configurations.
291 IModelRunner runner;
292 status = runner.initialize(handler);
293 CHECK((status == GraphStatus::TOSA_VALID));
294
295 runner.setInput(input_names[0], inputs[0]);
296 runner.setInput(input_names[1], inputs[1]);
297
298 // Run the ModelRunner using test inputs.
299 status = runner.run();
300 CHECK((status == GraphStatus::TOSA_VALID));
301
302 actual_outputs = runner.getOutput<float>(output_name);
303 CHECK(!actual_outputs.empty());
304
305 compareOutput(expected_outputs, actual_outputs, expected_outputs.size());
306 }
307
308 TEST_CASE("conv2d_f32_test")
309 {
310 std::string test_root(std::string(PROJECT_ROOT) +
311 "../examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/");
312 std::string tosa_model_file(test_root +
313 "flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa");
314 std::string input_file(test_root + "placeholder_0.npy");
315 std::string expected_output_file(test_root + "tflite_result.npy");
316
317 std::string input_name = "TosaInput_0";
318 std::string output_name = "TosaOutput_0";
319
320 std::vector<int32_t> input_shape = { 1, 32, 32, 8 };
321 std::vector<int32_t> output_shape = { 1, 32, 32, 16 };
322
323 // Read in inputs and expected outputs.
324 std::vector<float> inputs = readFromNpyFile<float>(input_file.c_str(), input_shape);
325 std::vector<float> expected_outputs = readFromNpyFile<float>(expected_output_file.c_str(), output_shape);
326
327 TosaSerializationHandler handler;
328 tosa_err_t error = handler.LoadFileTosaFlatbuffer(tosa_model_file.c_str());
329 CHECK((error == tosa::TOSA_OK));
330
331 GraphStatus status;
332
333 // Initialize the ModelRunner with configurations.
334 IModelRunner runner;
335 status = runner.initialize(handler);
336 CHECK((status == GraphStatus::TOSA_VALID));
337
338 runner.setInput(input_name, inputs);
339
340 // Run the ModelRunner using test inputs.
341 status = runner.run();
342 CHECK((status == GraphStatus::TOSA_VALID));
343
344 std::vector<float> actual_outputs = runner.getOutput<float>(output_name);
345 CHECK(!actual_outputs.empty());
346
347 compareOutput(expected_outputs, actual_outputs, expected_outputs.size());
348 }
349
350 TEST_CASE("conv2d_f32_validate_only_test")
351 {
352 std::string test_root(std::string(PROJECT_ROOT) +
353 "../examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/");
354 std::string tosa_model_file(test_root +
355 "flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa");
356
357 TosaSerializationHandler handler;
358 tosa_err_t error = handler.LoadFileTosaFlatbuffer(tosa_model_file.c_str());
359 CHECK((error == tosa::TOSA_OK));
360
361 GraphStatus status;
362 func_debug_t funcDebug;
363
364 func_config_t funcConfig;
365 funcConfig.validate_only = 1;
366
367 // Initialize the ModelRunner with configurations.
368 IModelRunner runner = IModelRunner(funcConfig, funcDebug);
369 runner.setFuncConfig(funcConfig);
370 status = runner.initialize(handler);
371 CHECK((status == GraphStatus::TOSA_VALID));
372
373 // Run the ModelRunner using no inputs, as validate_only is specified run() should still work.
374 status = runner.run();
375 CHECK((status == GraphStatus::TOSA_VALID));
376 }
377
378} // TEST_SUITE(model_runner)