IVGCVSW-1946: Remove armnn/src from the include paths
[platform/upstream/armnn.git] / src / backends / backendsCommon / test / WorkloadDataValidation.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "WorkloadTestUtils.hpp"
7
8 #include <armnn/Exceptions.hpp>
9
10 #include <backendsCommon/CpuTensorHandle.hpp>
11 #include <backendsCommon/Workload.hpp>
12
13 #include <reference/workloads/RefWorkloads.hpp>
14 #include <reference/RefWorkloadFactory.hpp>
15
16 #include <boost/test/unit_test.hpp>
17
18 using namespace armnn;
19
20 BOOST_AUTO_TEST_SUITE(WorkloadInfoValidation)
21
22
23
24 BOOST_AUTO_TEST_CASE(QueueDescriptor_Validate_WrongNumOfInputsOutputs)
25 {
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);
30 }
31
32 BOOST_AUTO_TEST_CASE(RefPooling2dFloat32Workload_Validate_WrongDimTensor)
33 {
34     armnn::TensorInfo inputTensorInfo;
35     armnn::TensorInfo outputTensorInfo;
36
37     unsigned int inputShape[]  = {2, 3, 4}; // <- Invalid - input tensor has to be 4D.
38     unsigned int outputShape[] = {2, 3, 4, 5};
39
40     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
41     inputTensorInfo  = armnn::TensorInfo(3, inputShape, armnn::DataType::Float32);
42
43     Pooling2dQueueDescriptor invalidData;
44     WorkloadInfo           invalidInfo;
45
46     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
47     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
48
49     // Invalid argument exception is expected, input tensor has to be 4D.
50     BOOST_CHECK_THROW(RefPooling2dFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
51 }
52
53 BOOST_AUTO_TEST_CASE(SoftmaxQueueDescriptor_Validate_WrongInputHeight)
54 {
55     unsigned int inputHeight = 1;
56     unsigned int inputWidth = 1;
57     unsigned int inputChannels = 4;
58     unsigned int inputNum = 2;
59
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;
64
65     armnn::TensorInfo inputTensorInfo;
66     armnn::TensorInfo outputTensorInfo;
67
68     unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
69     unsigned int outputShape[] = { outputNum, outputChannels, outputHeight, outputWidth };
70
71     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
72     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
73
74     SoftmaxQueueDescriptor invalidData;
75     WorkloadInfo           invalidInfo;
76
77     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
78     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
79
80     //Invalid argument exception is expected, because height != 1.
81     BOOST_CHECK_THROW(RefSoftmaxFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
82 }
83
84 BOOST_AUTO_TEST_CASE(FullyConnectedQueueDescriptor_Validate_RequiredDataMissing)
85 {
86     unsigned int inputWidth = 1;
87     unsigned int inputHeight = 1;
88     unsigned int inputChannels = 5;
89     unsigned int inputNum = 2;
90
91     unsigned int outputWidth = 1;
92     unsigned int outputHeight = 1;
93     unsigned int outputChannels = 3;
94     unsigned int outputNum = 2;
95
96     // Define the tensor descriptors.
97     armnn::TensorInfo inputTensorInfo;
98     armnn::TensorInfo outputTensorInfo;
99     armnn::TensorInfo weightsDesc;
100     armnn::TensorInfo biasesDesc;
101
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 };
106
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);
111
112     FullyConnectedQueueDescriptor invalidData;
113     WorkloadInfo                  invalidInfo;
114
115     ScopedCpuTensorHandle weightTensor(weightsDesc);
116     ScopedCpuTensorHandle biasTensor(biasesDesc);
117
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;
124
125
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);
129 }
130
131
132 BOOST_AUTO_TEST_CASE(NormalizationQueueDescriptor_Validate_WrongInputHeight)
133 {
134     constexpr unsigned int inputNum = 5;
135     constexpr unsigned int inputHeight   = 32;
136     constexpr unsigned int inputWidth    = 24;
137     constexpr unsigned int inputChannels = 3;
138
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;
144
145
146     armnn::TensorInfo inputTensorInfo;
147     armnn::TensorInfo outputTensorInfo;
148
149     unsigned int inputShape[]  = {inputNum, inputChannels, inputHeight, inputWidth};
150     unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
151
152     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
153     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
154
155
156     armnn::NormalizationAlgorithmMethod normMethod = armnn::NormalizationAlgorithmMethod::LocalBrightness;
157     armnn::NormalizationAlgorithmChannel normChannel = armnn::NormalizationAlgorithmChannel::Across;
158     float alpha = 1.f;
159     float beta = 1.f;
160     float kappa = 1.f;
161     uint32_t normSize = 5;
162
163     NormalizationQueueDescriptor invalidData;
164     WorkloadInfo                 invalidInfo;
165
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;
174
175     //Invalid argument exception is expected, because input height != output height.
176     BOOST_CHECK_THROW(RefNormalizationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
177 }
178
179 BOOST_AUTO_TEST_CASE(SplitterQueueDescriptor_Validate_WrongWindow)
180 {
181     constexpr unsigned int inputNum = 1;
182     constexpr unsigned int inputHeight   = 32;
183     constexpr unsigned int inputWidth    = 24;
184     constexpr unsigned int inputChannels = 3;
185
186     constexpr unsigned int outputNum = inputNum;
187     constexpr unsigned int outputChannels = inputChannels;
188     constexpr unsigned int outputHeight = 18;
189     constexpr unsigned int outputWidth  = inputWidth;
190
191
192     armnn::TensorInfo inputTensorInfo;
193     armnn::TensorInfo outputTensorInfo;
194
195     unsigned int inputShape[]  = {inputNum, inputChannels, inputHeight, inputWidth};
196     unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
197
198     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
199     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
200
201     SplitterQueueDescriptor invalidData;
202     WorkloadInfo            invalidInfo;
203
204     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
205     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
206
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);
211
212     BOOST_TEST_INFO("Invalid argument exception is expected, because split window dimensionality does not "
213         "match input.");
214     BOOST_CHECK_THROW(RefSplitterFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
215
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);
222
223
224     std::vector<unsigned int> wOrigin4 = {0, 0, 0, 0};
225     armnn::SplitterQueueDescriptor::ViewOrigin window4(wOrigin4);
226     invalidData.m_ViewOrigins[0] = window4;
227
228     std::vector<unsigned int> wOrigin5 = {1, 16, 20, 2};
229     armnn::SplitterQueueDescriptor::ViewOrigin window5(wOrigin4);
230     invalidData.m_ViewOrigins.push_back(window5);
231
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);
234 }
235
236
237 BOOST_AUTO_TEST_CASE(MergerQueueDescriptor_Validate_WrongWindow)
238 {
239     constexpr unsigned int inputNum = 1;
240     constexpr unsigned int inputChannels = 3;
241     constexpr unsigned int inputHeight   = 32;
242     constexpr unsigned int inputWidth    = 24;
243
244     constexpr unsigned int outputNum = 1;
245     constexpr unsigned int outputChannels = 3;
246     constexpr unsigned int outputHeight = 32;
247     constexpr unsigned int outputWidth  = 24;
248
249
250     armnn::TensorInfo inputTensorInfo;
251     armnn::TensorInfo outputTensorInfo;
252
253     unsigned int inputShape[]  = {inputNum, inputChannels, inputHeight, inputWidth};
254     unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
255
256     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
257     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
258
259     MergerQueueDescriptor invalidData;
260     WorkloadInfo          invalidInfo;
261
262     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
263     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
264
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);
269
270     BOOST_TEST_INFO("Invalid argument exception is expected, because merge window dimensionality does not "
271         "match input.");
272     BOOST_CHECK_THROW(RefMergerFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
273
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);
280
281
282     std::vector<unsigned int> wOrigin4 = {0, 0, 0, 0};
283     armnn::MergerQueueDescriptor::ViewOrigin window4(wOrigin4);
284     invalidData.m_ViewOrigins[0] = window4;
285
286     std::vector<unsigned int> wOrigin5 = {1, 16, 20, 2};
287     armnn::MergerQueueDescriptor::ViewOrigin window5(wOrigin4);
288     invalidData.m_ViewOrigins.push_back(window5);
289
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);
292 }
293
294 BOOST_AUTO_TEST_CASE(AdditionQueueDescriptor_Validate_InputNumbers)
295 {
296     armnn::TensorInfo input1TensorInfo;
297     armnn::TensorInfo input2TensorInfo;
298     armnn::TensorInfo input3TensorInfo;
299     armnn::TensorInfo outputTensorInfo;
300
301     unsigned int shape[]  = {1, 1, 1, 1};
302
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);
307
308     AdditionQueueDescriptor invalidData;
309     WorkloadInfo            invalidInfo;
310
311     AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
312     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
313
314     // Too few inputs.
315     BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
316
317     AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
318
319     // Correct.
320     BOOST_CHECK_NO_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo));
321
322     AddInputToWorkload(invalidData, invalidInfo, input3TensorInfo, nullptr);
323
324     // Too many inputs.
325     BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
326 }
327
328 BOOST_AUTO_TEST_CASE(AdditionQueueDescriptor_Validate_InputShapes)
329 {
330     armnn::TensorInfo input1TensorInfo;
331     armnn::TensorInfo input2TensorInfo;
332     armnn::TensorInfo outputTensorInfo;
333
334     unsigned int shape1[] = {1, 1, 2, 1};
335     unsigned int shape2[] = {1, 1, 3, 2};
336
337     // Incompatible shapes even with broadcasting.
338     {
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);
342
343         AdditionQueueDescriptor invalidData;
344         WorkloadInfo            invalidInfo;
345
346         AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
347         AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
348         AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
349
350         BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
351     }
352
353     // Output size not compatible with input sizes.
354     {
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);
358
359         AdditionQueueDescriptor invalidData;
360         WorkloadInfo            invalidInfo;
361
362         AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
363         AddInputToWorkload(invalidData, invalidInfo, input2TensorInfo, nullptr);
364         AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
365
366         // Output differs.
367         BOOST_CHECK_THROW(RefAdditionFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
368     }
369 }
370
371 BOOST_AUTO_TEST_CASE(MultiplicationQueueDescriptor_Validate_InputTensorDimensionMismatch)
372 {
373     armnn::TensorInfo input0TensorInfo;
374     armnn::TensorInfo input1TensorInfo;
375     armnn::TensorInfo outputTensorInfo;
376
377     constexpr unsigned int input0Shape[] = { 2, 2, 4, 4 };
378     constexpr std::size_t dimensionCount = std::extent<decltype(input0Shape)>::value;
379
380     // Checks dimension consistency for input tensors.
381     for (unsigned int dimIndex = 0; dimIndex < dimensionCount; ++dimIndex)
382     {
383         unsigned int input1Shape[dimensionCount];
384         for (unsigned int i = 0; i < dimensionCount; ++i)
385         {
386             input1Shape[i] = input0Shape[i];
387         }
388
389         ++input1Shape[dimIndex];
390
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);
394
395         MultiplicationQueueDescriptor invalidData;
396         WorkloadInfo                  invalidInfo;
397
398         AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
399         AddInputToWorkload(invalidData, invalidInfo, input0TensorInfo, nullptr);
400         AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
401
402         BOOST_CHECK_THROW(RefMultiplicationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
403     }
404
405     // Checks dimension consistency for input and output tensors.
406     for (unsigned int dimIndex = 0; dimIndex < dimensionCount; ++dimIndex)
407     {
408         unsigned int outputShape[dimensionCount];
409         for (unsigned int i = 0; i < dimensionCount; ++i)
410         {
411             outputShape[i] = input0Shape[i];
412         }
413
414         ++outputShape[dimIndex];
415
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);
419
420         MultiplicationQueueDescriptor invalidData;
421         WorkloadInfo                  invalidInfo;
422
423         AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
424         AddInputToWorkload(invalidData, invalidInfo, input0TensorInfo, nullptr);
425         AddInputToWorkload(invalidData, invalidInfo, input1TensorInfo, nullptr);
426
427         BOOST_CHECK_THROW(RefMultiplicationFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
428     }
429 }
430
431 BOOST_AUTO_TEST_CASE(ReshapeQueueDescriptor_Validate_MismatchingNumElements)
432 {
433     armnn::TensorInfo inputTensorInfo;
434     armnn::TensorInfo outputTensorInfo;
435
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 };
439
440     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
441     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32);
442
443     ReshapeQueueDescriptor invalidData;
444     WorkloadInfo           invalidInfo;
445
446     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
447     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
448
449     // InvalidArgumentException is expected, because the number of elements don't match.
450     BOOST_CHECK_THROW(RefReshapeFloat32Workload(invalidData, invalidInfo), armnn::InvalidArgumentException);
451 }
452
453
454 BOOST_AUTO_TEST_CASE(LstmQueueDescriptor_Validate)
455 {
456     armnn::TensorInfo inputTensorInfo;
457     armnn::TensorInfo outputTensorInfo;
458
459     unsigned int inputShape[] = { 1, 2 };
460     unsigned int outputShape[] = { 1 };
461
462     inputTensorInfo = armnn::TensorInfo(2, inputShape, armnn::DataType::Float32);
463     outputTensorInfo = armnn::TensorInfo(1, outputShape, armnn::DataType::Float32);
464
465     LstmQueueDescriptor invalidData;
466     WorkloadInfo        invalidInfo;
467
468     AddInputToWorkload(invalidData, invalidInfo, inputTensorInfo, nullptr);
469     AddOutputToWorkload(invalidData, invalidInfo, outputTensorInfo, nullptr);
470
471     BOOST_CHECK_THROW(invalidData.Validate(invalidInfo), armnn::InvalidArgumentException);
472 }
473
474 BOOST_AUTO_TEST_SUITE_END()