2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
6 #include "WorkloadTestUtils.hpp"
8 #include <armnn/Exceptions.hpp>
10 #include <backendsCommon/CpuTensorHandle.hpp>
11 #include <backendsCommon/Workload.hpp>
13 #include <reference/workloads/RefWorkloads.hpp>
14 #include <reference/RefWorkloadFactory.hpp>
16 #include <boost/test/unit_test.hpp>
18 using namespace armnn;
20 BOOST_AUTO_TEST_SUITE(WorkloadInfoValidation)
24 BOOST_AUTO_TEST_CASE(QueueDescriptor_Validate_WrongNumOfInputsOutputs)
26 InputQueueDescriptor invalidData;
27 WorkloadInfo invalidInfo;
28 //Invalid argument exception is expected, because no inputs and no outputs were defined.
29 BOOST_CHECK_THROW(RefWorkloadFactory().CreateInput(invalidData, invalidInfo), armnn::InvalidArgumentException);
32 BOOST_AUTO_TEST_CASE(RefPooling2dFloat32Workload_Validate_WrongDimTensor)
34 armnn::TensorInfo inputTensorInfo;
35 armnn::TensorInfo outputTensorInfo;
37 unsigned int inputShape[] = {2, 3, 4}; // <- Invalid - input tensor has to be 4D.
38 unsigned int outputShape[] = {2, 3, 4, 5};
40 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
41 inputTensorInfo = armnn::TensorInfo(3, inputShape, armnn::DataType::Float32);
43 Pooling2dQueueDescriptor invalidData;
44 WorkloadInfo invalidInfo;
46 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
47 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
49 // Invalid argument exception is expected, input tensor has to be 4D.
50 BOOST_CHECK_THROW(RefPooling2dFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
53 BOOST_AUTO_TEST_CASE(SoftmaxQueueDescriptor_Validate_WrongInputHeight)
55 unsigned int inputHeight = 1;
56 unsigned int inputWidth = 1;
57 unsigned int inputChannels = 4;
58 unsigned int inputNum = 2;
60 unsigned int outputChannels = inputChannels;
61 unsigned int outputHeight = inputHeight + 1; //Makes data invalid - Softmax expects height and width to be 1.
62 unsigned int outputWidth = inputWidth;
63 unsigned int outputNum = inputNum;
65 armnn::TensorInfo inputTensorInfo;
66 armnn::TensorInfo outputTensorInfo;
68 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
69 unsigned int outputShape[] = { outputNum, outputChannels, outputHeight, outputWidth };
71 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
72 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
74 SoftmaxQueueDescriptor invalidData;
75 WorkloadInfo invalidInfo;
77 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
78 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
80 //Invalid argument exception is expected, because height != 1.
81 BOOST_CHECK_THROW(RefSoftmaxFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
84 BOOST_AUTO_TEST_CASE(FullyConnectedQueueDescriptor_Validate_RequiredDataMissing)
86 unsigned int inputWidth = 1;
87 unsigned int inputHeight = 1;
88 unsigned int inputChannels = 5;
89 unsigned int inputNum = 2;
91 unsigned int outputWidth = 1;
92 unsigned int outputHeight = 1;
93 unsigned int outputChannels = 3;
94 unsigned int outputNum = 2;
96 // Define the tensor descriptors.
97 armnn::TensorInfo inputTensorInfo;
98 armnn::TensorInfo outputTensorInfo;
99 armnn::TensorInfo weightsDesc;
100 armnn::TensorInfo biasesDesc;
102 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
103 unsigned int outputShape[] = { outputNum, outputChannels, outputHeight, outputWidth };
104 unsigned int weightsShape[] = { 1, 1, inputChannels, outputChannels };
105 unsigned int biasShape[] = { 1, outputChannels, outputHeight, outputWidth };
107 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
108 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
109 weightsDesc = armnn::TensorInfo(4, weightsShape, armnn::DataType::Float32);
110 biasesDesc = armnn::TensorInfo(4, biasShape, armnn::DataType::Float32);
112 FullyConnectedQueueDescriptor invalidData;
113 WorkloadInfo invalidInfo;
115 ScopedCpuTensorHandle weightTensor(weightsDesc);
116 ScopedCpuTensorHandle biasTensor(biasesDesc);
118 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
119 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
120 invalidData.m_Weight = &weightTensor;
121 invalidData.m_Bias = &biasTensor;
122 invalidData.m_Parameters.m_BiasEnabled = true;
123 invalidData.m_Parameters.m_TransposeWeightMatrix = false;
126 //Invalid argument exception is expected, because not all required fields have been provided.
127 //In particular inputsData[0], outputsData[0] and weightsData can not be null.
128 BOOST_CHECK_THROW(RefFullyConnectedFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
132 BOOST_AUTO_TEST_CASE(NormalizationQueueDescriptor_Validate_WrongInputHeight)
134 constexpr unsigned int inputNum = 5;
135 constexpr unsigned int inputHeight = 32;
136 constexpr unsigned int inputWidth = 24;
137 constexpr unsigned int inputChannels = 3;
139 constexpr unsigned int outputNum = inputNum;
140 constexpr unsigned int outputChannels = inputChannels;
141 constexpr unsigned int outputHeight = inputHeight + 1; //Makes data invalid - normalization requires.
142 //Input and output to have the same dimensions.
143 constexpr unsigned int outputWidth = inputWidth;
146 armnn::TensorInfo inputTensorInfo;
147 armnn::TensorInfo outputTensorInfo;
149 unsigned int inputShape[] = {inputNum, inputChannels, inputHeight, inputWidth};
150 unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
152 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
153 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
156 armnn::NormalizationAlgorithmMethod normMethod = armnn::NormalizationAlgorithmMethod::LocalBrightness;
157 armnn::NormalizationAlgorithmChannel normChannel = armnn::NormalizationAlgorithmChannel::Across;
161 uint32_t normSize = 5;
163 NormalizationQueueDescriptor invalidData;
164 WorkloadInfo invalidInfo;
166 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
167 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
168 invalidData.m_Parameters.m_NormChannelType = normChannel;
169 invalidData.m_Parameters.m_NormMethodType = normMethod;
170 invalidData.m_Parameters.m_NormSize = normSize;
171 invalidData.m_Parameters.m_Alpha = alpha;
172 invalidData.m_Parameters.m_Beta = beta;
173 invalidData.m_Parameters.m_K = kappa;
175 //Invalid argument exception is expected, because input height != output height.
176 BOOST_CHECK_THROW(RefNormalizationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
179 BOOST_AUTO_TEST_CASE(SplitterQueueDescriptor_Validate_WrongWindow)
181 constexpr unsigned int inputNum = 1;
182 constexpr unsigned int inputHeight = 32;
183 constexpr unsigned int inputWidth = 24;
184 constexpr unsigned int inputChannels = 3;
186 constexpr unsigned int outputNum = inputNum;
187 constexpr unsigned int outputChannels = inputChannels;
188 constexpr unsigned int outputHeight = 18;
189 constexpr unsigned int outputWidth = inputWidth;
192 armnn::TensorInfo inputTensorInfo;
193 armnn::TensorInfo outputTensorInfo;
195 unsigned int inputShape[] = {inputNum, inputChannels, inputHeight, inputWidth};
196 unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
198 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
199 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
201 SplitterQueueDescriptor invalidData;
202 WorkloadInfo invalidInfo;
204 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
205 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
207 // Invalid, since it has only 3 dimensions while the input tensor is 4d.
208 std::vector<unsigned int> wOrigin = {0, 0, 0};
209 armnn::SplitterQueueDescriptor::ViewOrigin window(wOrigin);
210 invalidData.m_ViewOrigins.push_back(window);
212 BOOST_TEST_INFO("Invalid argument exception is expected, because split window dimensionality does not "
214 BOOST_CHECK_THROW(RefSplitterFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
216 // Invalid, since window extends past the boundary of input tensor.
217 std::vector<unsigned int> wOrigin3 = {0, 0, 15, 0};
218 armnn::SplitterQueueDescriptor::ViewOrigin window3(wOrigin3);
219 invalidData.m_ViewOrigins[0] = window3;
220 BOOST_TEST_INFO("Invalid argument exception is expected (wOrigin3[2]+ outputHeight > inputHeight");
221 BOOST_CHECK_THROW(RefSplitterFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
224 std::vector<unsigned int> wOrigin4 = {0, 0, 0, 0};
225 armnn::SplitterQueueDescriptor::ViewOrigin window4(wOrigin4);
226 invalidData.m_ViewOrigins[0] = window4;
228 std::vector<unsigned int> wOrigin5 = {1, 16, 20, 2};
229 armnn::SplitterQueueDescriptor::ViewOrigin window5(wOrigin4);
230 invalidData.m_ViewOrigins.push_back(window5);
232 BOOST_TEST_INFO("Invalid exception due to number of split windows not matching number of outputs.");
233 BOOST_CHECK_THROW(RefSplitterFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
237 BOOST_AUTO_TEST_CASE(MergerQueueDescriptor_Validate_WrongWindow)
239 constexpr unsigned int inputNum = 1;
240 constexpr unsigned int inputChannels = 3;
241 constexpr unsigned int inputHeight = 32;
242 constexpr unsigned int inputWidth = 24;
244 constexpr unsigned int outputNum = 1;
245 constexpr unsigned int outputChannels = 3;
246 constexpr unsigned int outputHeight = 32;
247 constexpr unsigned int outputWidth = 24;
250 armnn::TensorInfo inputTensorInfo;
251 armnn::TensorInfo outputTensorInfo;
253 unsigned int inputShape[] = {inputNum, inputChannels, inputHeight, inputWidth};
254 unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
256 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
257 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
259 MergerQueueDescriptor invalidData;
260 WorkloadInfo invalidInfo;
262 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
263 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
265 // Invalid, since it has only 3 dimensions while the input tensor is 4d.
266 std::vector<unsigned int> wOrigin = {0, 0, 0};
267 armnn::MergerQueueDescriptor::ViewOrigin window(wOrigin);
268 invalidData.m_ViewOrigins.push_back(window);
270 BOOST_TEST_INFO("Invalid argument exception is expected, because merge window dimensionality does not "
272 BOOST_CHECK_THROW(RefMergerFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
274 // Invalid, since window extends past the boundary of output tensor.
275 std::vector<unsigned int> wOrigin3 = {0, 0, 15, 0};
276 armnn::MergerQueueDescriptor::ViewOrigin window3(wOrigin3);
277 invalidData.m_ViewOrigins[0] = window3;
278 BOOST_TEST_INFO("Invalid argument exception is expected (wOrigin3[2]+ inputHeight > outputHeight");
279 BOOST_CHECK_THROW(RefMergerFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
282 std::vector<unsigned int> wOrigin4 = {0, 0, 0, 0};
283 armnn::MergerQueueDescriptor::ViewOrigin window4(wOrigin4);
284 invalidData.m_ViewOrigins[0] = window4;
286 std::vector<unsigned int> wOrigin5 = {1, 16, 20, 2};
287 armnn::MergerQueueDescriptor::ViewOrigin window5(wOrigin4);
288 invalidData.m_ViewOrigins.push_back(window5);
290 BOOST_TEST_INFO("Invalid exception due to number of merge windows not matching number of inputs.");
291 BOOST_CHECK_THROW(RefMergerFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
294 BOOST_AUTO_TEST_CASE(AdditionQueueDescriptor_Validate_InputNumbers)
296 armnn::TensorInfo input1TensorInfo;
297 armnn::TensorInfo input2TensorInfo;
298 armnn::TensorInfo input3TensorInfo;
299 armnn::TensorInfo outputTensorInfo;
301 unsigned int shape[] = {1, 1, 1, 1};
303 input1TensorInfo = armnn::TensorInfo(4, shape, armnn::DataType::Float32);
304 input2TensorInfo = armnn::TensorInfo(4, shape, armnn::DataType::Float32);
305 input3TensorInfo = armnn::TensorInfo(4, shape, armnn::DataType::Float32);
306 outputTensorInfo = armnn::TensorInfo(4, shape, armnn::DataType::Float32);
308 AdditionQueueDescriptor invalidData;
309 WorkloadInfo invalidInfo;
311 AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
312 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
315 BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
317 AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
320 BOOST_CHECK_NO_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo));
322 AddInputToWorkload(invalidData, invalidInfo, input3TensorInfo, nullptr);
325 BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
328 BOOST_AUTO_TEST_CASE(AdditionQueueDescriptor_Validate_InputShapes)
330 armnn::TensorInfo input1TensorInfo;
331 armnn::TensorInfo input2TensorInfo;
332 armnn::TensorInfo outputTensorInfo;
334 unsigned int shape1[] = {1, 1, 2, 1};
335 unsigned int shape2[] = {1, 1, 3, 2};
337 // Incompatible shapes even with broadcasting.
339 input1TensorInfo = armnn::TensorInfo(4, shape1, armnn::DataType::Float32);
340 input2TensorInfo = armnn::TensorInfo(4, shape2, armnn::DataType::Float32);
341 outputTensorInfo = armnn::TensorInfo(4, shape1, armnn::DataType::Float32);
343 AdditionQueueDescriptor invalidData;
344 WorkloadInfo invalidInfo;
346 AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
347 AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
348 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
350 BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
353 // Output size not compatible with input sizes.
355 input1TensorInfo = armnn::TensorInfo(4, shape1, armnn::DataType::Float32);
356 input2TensorInfo = armnn::TensorInfo(4, shape1, armnn::DataType::Float32);
357 outputTensorInfo = armnn::TensorInfo(4, shape2, armnn::DataType::Float32);
359 AdditionQueueDescriptor invalidData;
360 WorkloadInfo invalidInfo;
362 AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
363 AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
364 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
367 BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
371 BOOST_AUTO_TEST_CASE(MultiplicationQueueDescriptor_Validate_InputTensorDimensionMismatch)
373 armnn::TensorInfo input0TensorInfo;
374 armnn::TensorInfo input1TensorInfo;
375 armnn::TensorInfo outputTensorInfo;
377 constexpr unsigned int input0Shape[] = { 2, 2, 4, 4 };
378 constexpr std::size_t dimensionCount = std::extent<decltype(input0Shape)>::value;
380 // Checks dimension consistency for input tensors.
381 for (unsigned int dimIndex = 0; dimIndex < dimensionCount; ++dimIndex)
383 unsigned int input1Shape[dimensionCount];
384 for (unsigned int i = 0; i < dimensionCount; ++i)
386 input1Shape[i] = input0Shape[i];
389 ++input1Shape[dimIndex];
391 input0TensorInfo = armnn::TensorInfo(dimensionCount, input0Shape, armnn::DataType::Float32);
392 input1TensorInfo = armnn::TensorInfo(dimensionCount, input1Shape, armnn::DataType::Float32);
393 outputTensorInfo = armnn::TensorInfo(dimensionCount, input0Shape, armnn::DataType::Float32);
395 MultiplicationQueueDescriptor invalidData;
396 WorkloadInfo invalidInfo;
398 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
399 AddInputToWorkload(invalidData, invalidInfo, input0TensorInfo, nullptr);
400 AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
402 BOOST_CHECK_THROW(RefMultiplicationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
405 // Checks dimension consistency for input and output tensors.
406 for (unsigned int dimIndex = 0; dimIndex < dimensionCount; ++dimIndex)
408 unsigned int outputShape[dimensionCount];
409 for (unsigned int i = 0; i < dimensionCount; ++i)
411 outputShape[i] = input0Shape[i];
414 ++outputShape[dimIndex];
416 input0TensorInfo = armnn::TensorInfo(dimensionCount, input0Shape, armnn::DataType::Float32);
417 input1TensorInfo = armnn::TensorInfo(dimensionCount, input0Shape, armnn::DataType::Float32);
418 outputTensorInfo = armnn::TensorInfo(dimensionCount, outputShape, armnn::DataType::Float32);
420 MultiplicationQueueDescriptor invalidData;
421 WorkloadInfo invalidInfo;
423 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
424 AddInputToWorkload(invalidData, invalidInfo, input0TensorInfo, nullptr);
425 AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
427 BOOST_CHECK_THROW(RefMultiplicationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
431 BOOST_AUTO_TEST_CASE(ReshapeQueueDescriptor_Validate_MismatchingNumElements)
433 armnn::TensorInfo inputTensorInfo;
434 armnn::TensorInfo outputTensorInfo;
436 // The input and output shapes should have the same number of elements, but these don't.
437 unsigned int inputShape[] = { 1, 1, 2, 3 };
438 unsigned int outputShape[] = { 1, 1, 1, 2 };
440 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
441 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
443 ReshapeQueueDescriptor invalidData;
444 WorkloadInfo invalidInfo;
446 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
447 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
449 // InvalidArgumentException is expected, because the number of elements don't match.
450 BOOST_CHECK_THROW(RefReshapeFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
454 BOOST_AUTO_TEST_CASE(LstmQueueDescriptor_Validate)
456 armnn::TensorInfo inputTensorInfo;
457 armnn::TensorInfo outputTensorInfo;
459 unsigned int inputShape[] = { 1, 2 };
460 unsigned int outputShape[] = { 1 };
462 inputTensorInfo = armnn::TensorInfo(2, inputShape, armnn::DataType::Float32);
463 outputTensorInfo = armnn::TensorInfo(1, outputShape, armnn::DataType::Float32);
465 LstmQueueDescriptor invalidData;
466 WorkloadInfo invalidInfo;
468 AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
469 AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
471 BOOST_CHECK_THROW(invalidData.Validate(invalidInfo), armnn::InvalidArgumentException);
474 BOOST_AUTO_TEST_SUITE_END()