IVGCVSW-2093 Add SpaceToBatchNd layer and corresponding no-op factory implementations
[platform/upstream/armnn.git] / src / backends / test / Pooling2dTestImpl.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6
7 #include <string>
8 #include <armnn/ArmNN.hpp>
9
10 #include <test/TensorHelpers.hpp>
11 #include "QuantizeHelper.hpp"
12
13 #include <backends/CpuTensorHandle.hpp>
14 #include <backends/WorkloadFactory.hpp>
15 #include <backends/WorkloadInfo.hpp>
16 #include <algorithm>
17 #include "Permute.hpp"
18 #include <boost/numeric/conversion/cast.hpp>
19
20 template<typename T>
21 LayerTestResult<T, 4> SimplePooling2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
22                                               armnn::Pooling2dDescriptor descriptor,
23                                               float qScale,
24                                               int32_t qOffset,
25                                               const boost::multi_array<T, 4>& input,
26                                               const boost::multi_array<T, 4>& outputExpected)
27 {
28     const armnn::DataLayoutIndexed dataLayout = descriptor.m_DataLayout;
29     auto heightIndex = dataLayout.GetHeightIndex();
30     auto widthIndex = dataLayout.GetWidthIndex();
31     auto channelsIndex = dataLayout.GetChannelsIndex();
32
33     unsigned int inputHeight     = boost::numeric_cast<unsigned int>(input.shape()[heightIndex]);
34     unsigned int inputWidth      = boost::numeric_cast<unsigned int>(input.shape()[widthIndex]);
35     unsigned int inputChannels   = boost::numeric_cast<unsigned int>(input.shape()[channelsIndex]);
36     unsigned int inputBatchSize  = boost::numeric_cast<unsigned int>(input.shape()[0]);
37
38     unsigned int outputHeight    = boost::numeric_cast<unsigned int>(outputExpected.shape()[heightIndex]);
39     unsigned int outputWidth     = boost::numeric_cast<unsigned int>(outputExpected.shape()[widthIndex]);
40     unsigned int outputChannels  = boost::numeric_cast<unsigned int>(outputExpected.shape()[channelsIndex]);
41     unsigned int outputBatchSize = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
42
43     armnn::TensorInfo inputTensorInfo = GetTensorInfo<T>(inputBatchSize, inputChannels, inputHeight,
44                                                          inputWidth, dataLayout);
45     armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(outputBatchSize, outputChannels, outputHeight,
46                                                           outputWidth, dataLayout);
47
48     // Set quantization parameters if the requested type is a quantized type.
49     if(armnn::IsQuantizedType<T>())
50     {
51         inputTensorInfo.SetQuantizationScale(qScale);
52         inputTensorInfo.SetQuantizationOffset(qOffset);
53         outputTensorInfo.SetQuantizationScale(qScale);
54         outputTensorInfo.SetQuantizationOffset(qOffset);
55     }
56
57     LayerTestResult<T, 4> result(outputTensorInfo);
58
59     std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
60     std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
61
62     armnn::Pooling2dQueueDescriptor queueDescriptor;
63     queueDescriptor.m_Parameters = descriptor;
64     queueDescriptor.m_Parameters.m_DataLayout = dataLayout;
65
66     armnn::WorkloadInfo workloadInfo;
67     AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfo, inputHandle.get());
68     AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get());
69
70     // Don't execute if Pooling is not supported, as an exception will be raised.
71     armnn::BackendId backend = workloadFactory.GetBackendId();
72     const size_t reasonIfUnsupportedMaxLen = 255;
73     char reasonIfUnsupported[reasonIfUnsupportedMaxLen+1];
74     result.supported = armnn::IsPooling2dSupported(backend, inputTensorInfo, outputTensorInfo,
75                                                    queueDescriptor.m_Parameters,
76                                                    reasonIfUnsupported, reasonIfUnsupportedMaxLen);
77     if (!result.supported)
78     {
79         return result;
80     }
81
82     std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreatePooling2d(queueDescriptor, workloadInfo);
83
84     inputHandle->Allocate();
85     outputHandle->Allocate();
86
87     CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
88
89     workload->Execute();
90
91     CopyDataFromITensorHandle(&result.output[0][0][0][0], outputHandle.get());
92
93     result.outputExpected = outputExpected;
94
95     return result;
96 }
97
98 //
99 // Tests max pooling with the following parameters:
100 //
101 //   Pooling size: 3x3
102 //   Stride:       (2,4)
103 //   input size:   8x13
104 //   channels:     2
105 //   batch size:   2
106 //
107 template<typename T>
108 LayerTestResult<T, 4> SimpleMaxPooling2dSize3x3Stride2x4TestCommon(armnn::IWorkloadFactory& workloadFactory,
109                                                                    bool forceNoPadding,
110                                                                    float qScale = 1.0f,
111                                                                    int32_t qOffset = 0)
112 {
113     armnn::Pooling2dDescriptor descriptor;
114     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
115     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
116     descriptor.m_StrideX = 2;
117     descriptor.m_StrideY = 4;
118     // forceNoPadding is mainly used for compatibility with ARM Compute.
119     // As of 16/05/2017, it errors if padX or padY are equal to or greater than the pool size.
120     descriptor.m_PadLeft = descriptor.m_PadRight = forceNoPadding ? 0 : 3;
121     descriptor.m_PadTop = descriptor.m_PadBottom = 0;
122     descriptor.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
123     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
124
125     unsigned int inputWidth = 8;
126     unsigned int inputHeight = 13;
127     unsigned int outputWidth =
128         (inputWidth + descriptor.m_PadLeft + descriptor.m_PadRight + descriptor.m_StrideX - descriptor.m_PoolWidth) /
129         descriptor.m_StrideX;
130     unsigned int outputHeight =
131         (inputHeight + descriptor.m_PadTop + descriptor.m_PadBottom + descriptor.m_StrideY - descriptor.m_PoolHeight) /
132         descriptor.m_StrideY;
133     unsigned int channels = 2;
134     unsigned int batchSize = 2;
135
136     armnn::TensorInfo inputTensorInfo({ batchSize, channels, inputHeight, inputWidth }, armnn::GetDataType<T>());
137     armnn::TensorInfo outputTensorInfo({ batchSize, channels, outputHeight, outputWidth }, armnn::GetDataType<T>());
138
139     // Set quantization parameters if the requested type is a quantized type.
140     if(armnn::IsQuantizedType<T>())
141     {
142         inputTensorInfo.SetQuantizationScale(qScale);
143         inputTensorInfo.SetQuantizationOffset(qOffset);
144         outputTensorInfo.SetQuantizationScale(qScale);
145         outputTensorInfo.SetQuantizationOffset(qOffset);
146     }
147
148     std::vector<float> singleChannelData({
149         0.0f, 4.0f, 8.0f, 1.0f, 6.0f, 4.0f, 5.0f, 8.0f,
150         1.0f, 1.0f, 6.0f, 0.0f, 3.0f, 7.0f, 4.0f, 7.0f,
151         8.0f, 5.0f, 0.0f, 0.0f, 8.0f, 3.0f, 4.0f, 3.0f,
152         8.0f, 2.0f, 5.0f, 4.0f, 1.0f, 9.0f, 2.0f, 0.0f,
153         5.0f, 4.0f, 5.0f, 0.0f, 0.0f, 0.0f, 7.0f, 2.0f,
154         1.0f, 2.0f, 6.0f, 2.0f, 7.0f, 9.0f, 5.0f, 2.0f,
155         9.0f, 7.0f, 3.0f, 1.0f, 3.0f, 4.0f, 8.0f, 3.0f,
156         1.0f, 0.0f, 0.0f, 5.0f, 5.0f, 4.0f, 2.0f, 0.0f,
157         6.0f, 4.0f, 3.0f, 6.0f, 9.0f, 5.0f, 5.0f, 6.0f,
158         8.0f, 7.0f, 9.0f, 6.0f, 1.0f, 4.0f, 1.0f, 9.0f,
159         7.0f, 1.0f, 9.0f, 2.0f, 9.0f, 9.0f, 8.0f, 1.0f,
160         4.0f, 4.0f, 5.0f, 9.0f, 2.0f, 6.0f, 6.0f, 4.0f,
161         3.0f, 5.0f, 4.0f, 0.0f, 1.0f, 5.0f, 9.0f, 7.0f,
162     });
163
164     // Constructs input data.
165     std::vector<float> inputData;
166     auto negator = [](float f) { return -f; };
167
168     // First image (two channels where the second channel is the negative of the first one).
169     inputData.insert(inputData.end(), singleChannelData.begin(), singleChannelData.end());
170     std::transform(singleChannelData.begin(), singleChannelData.end(), std::back_inserter(inputData), negator);
171
172     // Second image (same as first image).
173     inputData.insert(inputData.end(), singleChannelData.begin(), singleChannelData.end());
174     std::transform(singleChannelData.begin(), singleChannelData.end(), std::back_inserter(inputData), negator);
175
176     auto input = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, inputData));
177
178     // These were calculated manually.
179     auto shape(GetTensorShapeAsArray<4>(outputTensorInfo));
180     boost::multi_array<T, 4> outputExpected(shape);
181     if (forceNoPadding)
182     {
183         outputExpected = MakeTensor<T, 4>(outputTensorInfo,
184             QuantizedVector<T>(qScale, qOffset, {
185                  8.0f,  8.0f,  8.0f,
186                  9.0f,  7.0f,  9.0f,
187                  9.0f,  9.0f,  9.0f,
188
189                  0.0f,  0.0f, -3.0f,
190                 -1.0f,  0.0f,  0.0f,
191                 -1.0f, -1.0f, -1.0f,
192
193                  8.0f,  8.0f,  8.0f,
194                  9.0f,  7.0f,  9.0f,
195                  9.0f,  9.0f,  9.0f,
196
197                  0.0f,  0.0f, -3.0f,
198                 -1.0f,  0.0f,  0.0f,
199                 -1.0f, -1.0f, -1.0f
200         }));
201     }
202     else
203     {
204         outputExpected = MakeTensor<T, 4>(outputTensorInfo,
205             QuantizedVector<T>(qScale, qOffset, {
206                 0.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f,
207                 0.0f, 9.0f, 7.0f, 9.0f, 9.0f, 3.0f,
208                 0.0f, 8.0f, 9.0f, 9.0f, 9.0f, 9.0f,
209
210                 0.0f, 0.0f, 0.0f, 0.0f,-3.0f, 0.0f,
211                 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
212                 0.0f,-1.0f,-1.0f,-1.0f,-1.0f, 0.0f,
213
214                 0.0f, 8.0f, 8.0f, 8.0f, 8.0f, 8.0f,
215                 0.0f, 9.0f, 7.0f, 9.0f, 9.0f, 3.0f,
216                 0.0f, 8.0f, 9.0f, 9.0f, 9.0f, 9.0f,
217
218                 0.0f, 0.0f, 0.0f, 0.0f,-3.0f, 0.0f,
219                 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
220                 0.0f,-1.0f,-1.0f,-1.0f,-1.0f, 0.0f
221         }));
222     }
223
224     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
225 }
226
227 template<typename T>
228 LayerTestResult<T, 4> SimpleMaxPooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
229                                                    const armnn::DataLayoutIndexed& dataLayout = armnn::DataLayout::NCHW,
230                                                    float qScale = 1.0f,
231                                                    int32_t qOffset = 0)
232 {
233     armnn::Pooling2dDescriptor descriptor;
234     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
235     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
236     descriptor.m_StrideX = descriptor.m_StrideY = 2;
237     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
238     descriptor.m_DataLayout = dataLayout;
239
240     armnn::TensorInfo inputTensorInfo  = GetTensorInfo<T>(1, 2, 4, 4, dataLayout);
241     armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(1, 2, 2, 2, dataLayout);
242
243     // Set quantization parameters if the requested type is a quantized type.
244     if(armnn::IsQuantizedType<T>())
245     {
246         inputTensorInfo.SetQuantizationScale(qScale);
247         inputTensorInfo.SetQuantizationOffset(qOffset);
248         outputTensorInfo.SetQuantizationScale(qScale);
249         outputTensorInfo.SetQuantizationOffset(qOffset);
250     }
251
252     std::vector<T> inputData(
253         QuantizedVector<T>(qScale, qOffset, {
254              1.0f,  2.0f,  5.0f,  6.0f,
255              3.0f,  4.0f,  7.0f,  8.0f,
256              9.0f, 10.0f, 13.0f, 14.0f,
257             11.0f, 12.0f, 15.0f, 16.0f,
258
259             17.0f, 18.0f, 21.0f, 22.0f,
260             19.0f, 20.0f, 23.0f, 24.0f,
261             25.0f, 26.0f, 29.0f, 30.0f,
262             27.0f, 28.0f, 31.0f, 32.0f,
263         }));
264
265     std::vector<T> outputData(
266         QuantizedVector<T>(qScale, qOffset, {
267              4.0f,  8.0f,
268             12.0f, 16.0f,
269
270             20.0f, 24.0f,
271             28.0f, 32.0f,
272         }));
273
274     const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
275     if (dataLayout.GetDataLayout() == armnn::DataLayout::NHWC)
276     {
277         std::vector<T> tmp(inputData.size());
278         armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data());
279         inputData = tmp;
280
281         std::vector<T> tmp1(outputData.size());
282         armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp1.data());
283         outputData = tmp1;
284     }
285
286     auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
287
288     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
289
290     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
291 }
292
293 template<typename T>
294 LayerTestResult<T, 4> SimpleAveragePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
295                                                        armnn::DataLayoutIndexed dataLayout = armnn::DataLayout::NCHW,
296                                                        float qScale = 1.0f,
297                                                        int32_t qOffset = 0)
298 {
299     armnn::Pooling2dDescriptor descriptor;
300     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
301     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
302     descriptor.m_StrideX = descriptor.m_StrideY = 2;
303     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
304     descriptor.m_DataLayout = dataLayout;
305
306     armnn::TensorInfo inputTensorInfo  = GetTensorInfo<T>(1, 2, 4, 4, dataLayout);
307     armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(1, 2, 2, 2, dataLayout);
308
309     // Set quantization parameters if the requested type is a quantized type.
310     if(armnn::IsQuantizedType<T>())
311     {
312         inputTensorInfo.SetQuantizationScale(qScale);
313         inputTensorInfo.SetQuantizationOffset(qOffset);
314         outputTensorInfo.SetQuantizationScale(qScale);
315         outputTensorInfo.SetQuantizationOffset(qOffset);
316     }
317
318     std::vector<T> inputData(
319         QuantizedVector<T>(qScale, qOffset, {
320              2.0f,  2.0f,  6.0f,  6.0f,
321              4.0f,  4.0f,  8.0f,  8.0f,
322             10.0f, 12.0f, 14.0f, 16.0f,
323             10.0f, 12.0f, 16.0f, 14.0f,
324
325             18.0f, 20.0f, 24.0f, 22.0f,
326             20.0f, 18.0f, 22.0f, 24.0f,
327             26.0f, 28.0f,  0.0f,  0.0f,
328             26.0f, 28.0f,  0.0f,  0.0f,
329         }));
330
331     std::vector<T> outputData(
332         QuantizedVector<T>(qScale, qOffset, {
333              3.0f,  7.0f,
334             11.0f, 15.0f,
335
336             19.0f, 23.0f,
337             27.0f,  0.0f,
338         }));
339
340     const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
341     if (dataLayout.GetDataLayout() == armnn::DataLayout::NHWC)
342     {
343         std::vector<T> tmp(inputData.size());
344         armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data());
345         inputData = tmp;
346
347         std::vector<T> tmp1(outputData.size());
348         armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp1.data());
349         outputData = tmp1;
350     }
351
352     auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
353
354     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
355
356     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
357 }
358
359 template<typename T>
360 LayerTestResult<T, 4> LargeTensorsAveragePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
361                                                              float qScale = 1.0f,
362                                                              int32_t qOffset = 0)
363 {
364     armnn::Pooling2dDescriptor descriptor;
365     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
366     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 100;
367     descriptor.m_StrideX = descriptor.m_StrideY = 5;
368     descriptor.m_PadLeft = 50;
369     descriptor.m_PadRight = 50;
370     descriptor.m_PadTop = 50;
371     descriptor.m_PadBottom = 50;
372     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
373
374     armnn::TensorInfo inputTensorInfo({ 5, 3, 52, 60 }, armnn::GetDataType<T>());
375     armnn::TensorInfo outputTensorInfo({ 5, 3, 11, 13 }, armnn::GetDataType<T>());
376
377     // Set quantization parameters if the requested type is a quantized type.
378     if(armnn::IsQuantizedType<T>())
379     {
380         inputTensorInfo.SetQuantizationScale(qScale);
381         inputTensorInfo.SetQuantizationOffset(qOffset);
382         outputTensorInfo.SetQuantizationScale(qScale);
383         outputTensorInfo.SetQuantizationOffset(qOffset);
384     }
385
386     std::vector<T> inputVec;
387
388     for (unsigned int i = 0 ; i < inputTensorInfo.GetShape().GetNumElements(); ++i)
389     {
390         inputVec.push_back(1);
391     }
392
393     auto input = MakeTensor<T, 4>(inputTensorInfo, inputVec);
394
395     std::vector<T> outputVec;
396
397     for (unsigned int i = 0 ; i < outputTensorInfo.GetShape().GetNumElements(); ++i)
398     {
399         outputVec.push_back(1);
400     }
401
402     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputVec);
403
404     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
405 }
406
407 template<typename T>
408 LayerTestResult<T, 4> SimpleL2Pooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
409                                                   armnn::DataLayoutIndexed dataLayout = armnn::DataLayout::NCHW,
410                                                   float qScale = 1.0f,
411                                                   int32_t qOffset = 0)
412 {
413     armnn::Pooling2dDescriptor descriptor;
414     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
415     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
416     descriptor.m_StrideX = descriptor.m_StrideY = 2;
417     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
418     descriptor.m_DataLayout = dataLayout;
419
420     armnn::TensorInfo inputTensorInfo  = GetTensorInfo<T>(1, 2, 4, 4, dataLayout);
421     armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(1, 2, 2, 2, dataLayout);
422
423     std::vector<T> inputData(
424         QuantizedVector<T>(qScale, qOffset, {
425             1.0f, 7.0f, 5.0f, 5.0f,
426             1.0f, 7.0f, 5.0f, 5.0f,
427             3.0f, 3.0f, 1.0f, 1.0f,
428             3.0f, 3.0f, 1.0f, 1.0f,
429
430             1.0f, 7.0f, 0.0f, 0.0f,
431             1.0f, 7.0f, 2.0f, 0.0f,
432             0.0f, 2.0f, 1.0f, 1.0f,
433             0.0f, 0.0f, 1.0f, 1.0f,
434         }));
435
436     std::vector<T> outputData(
437         QuantizedVector<T>(qScale, qOffset, {
438             5.0f, 5.0f,
439             3.0f, 1.0f,
440
441             5.0f, 1.0f,
442             1.0f, 1.0f,
443         }));
444
445     const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
446     if (dataLayout.GetDataLayout() == armnn::DataLayout::NHWC)
447     {
448         std::vector<T> tmp(inputData.size());
449         armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data());
450         inputData = tmp;
451
452         std::vector<T> tmp1(outputData.size());
453         armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp1.data());
454         outputData = tmp1;
455     }
456
457     auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
458
459     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
460
461     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
462 }
463
464 template<typename T>
465 LayerTestResult<T, 4> L2Pooling2dSize3Stride1TestCommon(armnn::IWorkloadFactory& workloadFactory,
466                                                         float qScale = 1.0f,
467                                                         int32_t qOffset = 0)
468 {
469     armnn::Pooling2dDescriptor descriptor;
470     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
471     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
472     descriptor.m_StrideX = descriptor.m_StrideY = 1;
473     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
474
475     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
476     auto input = MakeTensor<T, 4>(inputTensorInfo,
477         QuantizedVector<T>(qScale, qOffset, {
478             2.0f, 1.0f, 5.0f, 2.0f,
479             1.0f, 2.0f, 2.0f, 1.0f,
480             5.0f, 4.0f, 1.0f, 5.0f,
481             2.0f, 1.0f, 5.0f, 2.0f,
482         }));
483
484     armnn::TensorInfo outputTensorInfo({ 1, 1, 2, 2 }, armnn::GetDataType<T>());
485     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
486         QuantizedVector<T>(qScale, qOffset, {
487             3.0f, 3.0f,
488             3.0f, 3.0f,
489         }));
490
491     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
492 }
493
494 template<typename T>
495 LayerTestResult<T, 4> L2Pooling2dSize3Stride3TestCommon(armnn::IWorkloadFactory& workloadFactory,
496                                                         float qScale = 1.0f,
497                                                         int32_t qOffset = 0)
498 {
499     armnn::Pooling2dDescriptor descriptor;
500     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
501     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
502     descriptor.m_StrideX = descriptor.m_StrideY = 3;
503     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
504
505     armnn::TensorInfo inputTensorInfo({ 1, 1, 9, 9 }, armnn::GetDataType<T>());
506     auto input = MakeTensor<T, 4>(inputTensorInfo,
507         QuantizedVector<T>(qScale, qOffset, {
508             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
509             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
510             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
511             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
512             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
513             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
514             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
515             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
516             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
517         }));
518
519     armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, armnn::GetDataType<T>());
520     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
521         QuantizedVector<T>(qScale, qOffset, {
522             3.0f, 3.0f, 3.0f,
523             3.0f, 3.0f, 3.0f,
524             3.0f, 3.0f, 3.0f,
525         }));
526
527     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
528 }
529
530 template<typename T>
531 LayerTestResult<T, 4> L2Pooling2dSize3Stride4TestCommon(armnn::IWorkloadFactory& workloadFactory,
532                                                         float qScale = 1.0f,
533                                                         int32_t qOffset = 0)
534 {
535     armnn::Pooling2dDescriptor descriptor;
536     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
537     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
538     descriptor.m_StrideX = descriptor.m_StrideY = 4;
539     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
540
541     armnn::TensorInfo inputTensorInfo({ 1, 1, 7, 7 }, armnn::GetDataType<T>());
542     auto input = MakeTensor<T, 4>(inputTensorInfo,
543         QuantizedVector<T>(qScale, qOffset, {
544             2.0f, 1.0f, 5.0f, 0.0f, 2.0f, 1.0f, 5.0f,
545             1.0f, 2.0f, 2.0f, 0.0f, 1.0f, 2.0f, 2.0f,
546             5.0f, 4.0f, 1.0f, 0.0f, 5.0f, 4.0f, 1.0f,
547             0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
548             2.0f, 1.0f, 5.0f, 0.0f, 2.0f, 1.0f, 5.0f,
549             1.0f, 2.0f, 2.0f, 0.0f, 1.0f, 2.0f, 2.0f,
550             5.0f, 4.0f, 1.0f, 0.0f, 5.0f, 4.0f, 1.0f,
551         }));
552
553     armnn::TensorInfo outputTensorInfo({ 1, 1, 2, 2 }, armnn::GetDataType<T>());
554     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
555         QuantizedVector<T>(qScale, qOffset, {
556             3.0f, 3.0f,
557             3.0f, 3.0f,
558         }));
559
560     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
561 }
562
563 template<typename T>
564 LayerTestResult<T, 4> L2Pooling2dSize7TestCommon(armnn::IWorkloadFactory& workloadFactory,
565                                                  float qScale = 1.0f,
566                                                  int32_t qOffset = 0)
567 {
568     armnn::Pooling2dDescriptor descriptor;
569     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
570     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 7;
571     descriptor.m_StrideX = descriptor.m_StrideY = 7;
572     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
573
574     armnn::TensorInfo inputTensorInfo({ 1, 1, 7, 7 }, armnn::GetDataType<T>());
575     auto input = MakeTensor<T, 4>(inputTensorInfo,
576         QuantizedVector<T>(qScale, qOffset, {
577             1.0f, 0.0f, 2.0f, 0.0f,  3.0f, 0.0f, 4.0f,
578             0.0f, 0.0f, 0.0f, 0.0f,  0.0f, 0.0f, 0.0f,
579             0.0f, 5.0f, 0.0f, 6.0f,  0.0f, 7.0f, 0.0f,
580             8.0f, 0.0f, 9.0f, 0.0f, 10.0f, 0.0f, 5.0f,
581             0.0f, 5.0f, 0.0f, 2.0f,  0.0f, 1.0f, 1.0f,
582             0.0f, 0.0f, 0.0f, 0.0f,  0.0f, 0.0f, 0.0f,
583             0.0f, 0.0f, 0.0f, 0.0f,  0.0f, 0.0f, 0.0f,
584         }));
585
586     armnn::TensorInfo outputTensorInfo({ 1, 1, 1, 1 }, armnn::GetDataType<T>());
587     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
588         QuantizedVector<T>(qScale, qOffset, {
589             3.0f,
590         }));
591
592     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
593 }
594
595 template<typename T>
596 LayerTestResult<T, 4> L2Pooling2dSize9TestCommon(armnn::IWorkloadFactory& workloadFactory,
597                                                  float qScale = 1.0f,
598                                                  int32_t qOffset = 0)
599 {
600     armnn::Pooling2dDescriptor descriptor;
601     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
602     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 9;
603     descriptor.m_StrideX = descriptor.m_StrideY = 9;
604     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
605
606     armnn::TensorInfo inputTensorInfo({ 1, 1, 9, 9 }, armnn::GetDataType<T>());
607     auto input = MakeTensor<T, 4>(inputTensorInfo,
608         QuantizedVector<T>(qScale, qOffset, {
609             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
610             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
611             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
612             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
613             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
614             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
615             2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f, 2.0f, 1.0f, 5.0f,
616             1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f, 1.0f, 2.0f, 2.0f,
617             5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f, 5.0f, 4.0f, 1.0f,
618         }));
619
620     armnn::TensorInfo outputTensorInfo({ 1, 1, 1, 1 }, armnn::GetDataType<T>());
621     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
622         QuantizedVector<T>(qScale, qOffset, {
623             3.0f,
624         }));
625
626     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
627 }
628
629 template<typename T>
630 LayerTestResult<T, 4> AsymmetricNonSquarePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
631                                                              float qScale = 1.0f,
632                                                              int32_t qOffset = 0)
633 {
634     armnn::TensorInfo inputTensorInfo({ 1, 1, 1, 3 }, armnn::GetDataType<T>());
635     armnn::TensorInfo outputTensorInfo({ 1, 1, 2, 2 }, armnn::GetDataType<T>());
636
637     armnn::Pooling2dDescriptor descriptor;
638     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
639     descriptor.m_PoolWidth = 2;
640     descriptor.m_PoolHeight = 3;
641     descriptor.m_StrideX = 2;
642     descriptor.m_StrideY = 1;
643     descriptor.m_PadLeft = 2;
644     descriptor.m_PadRight = 0;
645     descriptor.m_PadTop = 1;
646     descriptor.m_PadBottom = 2;
647     descriptor.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
648     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
649
650     // Construct input data.
651     auto input = MakeTensor<T, 4>(inputTensorInfo,
652         QuantizedVector<T>(qScale, qOffset, {
653             1.0f, 3.0f, 4.0f,
654         }));
655
656     // These were calculated manually.
657     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
658         QuantizedVector<T>(qScale, qOffset, {
659             0.0f, 3.0f, 0.0f, 3.0f,
660         }));
661
662     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
663 }
664
665 template<typename T>
666 LayerTestResult<T, 4> ComparePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
667                                                  armnn::IWorkloadFactory& refWorkloadFactory,
668                                                  armnn::PoolingAlgorithm poolingType,
669                                                  float qScale = 1.0f,
670                                                  int32_t qOffset = 0)
671 {
672     const unsigned int inputWidth = 16;
673     const unsigned int inputHeight = 32;
674     const unsigned int channelCount = 2;
675     const unsigned int batchSize = 5;
676
677     const unsigned int poolSize = 3;
678     const unsigned int strideX = 2;
679     const unsigned int strideY = 4;
680     const unsigned int padX = 0;
681     const unsigned int padY = 0;
682
683     const unsigned int outputWidth = (inputWidth + 2 * padX + strideX - poolSize) / strideX;
684     const unsigned int outputHeight = (inputHeight + 2 * padY + strideY - poolSize) / strideY;
685
686     armnn::TensorInfo inputTensorInfo;
687     armnn::TensorInfo outputTensorInfo;
688
689     unsigned int inputShape[] = { batchSize, channelCount, inputHeight, inputWidth };
690     unsigned int outputShape[] = { batchSize, channelCount, outputHeight, outputWidth };
691
692     inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::GetDataType<T>());
693     outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::GetDataType<T>());
694
695     // Set quantization parameters if the requested type is a quantized type.
696     if(armnn::IsQuantizedType<T>())
697     {
698         inputTensorInfo.SetQuantizationScale(qScale);
699         inputTensorInfo.SetQuantizationOffset(qOffset);
700         outputTensorInfo.SetQuantizationScale(qScale);
701         outputTensorInfo.SetQuantizationOffset(qOffset);
702     }
703
704     boost::multi_array<T, 4> input = MakeRandomTensor<T, 4>(inputTensorInfo, 81715);
705
706     LayerTestResult<T, 4> comparisonResult(outputTensorInfo);
707
708     std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
709     std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
710
711     armnn::Pooling2dQueueDescriptor data;
712     armnn::WorkloadInfo info;
713     AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
714     AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
715     data.m_Parameters.m_PoolType = poolingType;
716     data.m_Parameters.m_PoolWidth = poolSize;
717     data.m_Parameters.m_PoolHeight = poolSize;
718     data.m_Parameters.m_StrideX = strideX;
719     data.m_Parameters.m_StrideY = strideY;
720     data.m_Parameters.m_PadLeft = padX;
721     data.m_Parameters.m_PadRight = padX;
722     data.m_Parameters.m_PadTop = padY;
723     data.m_Parameters.m_PadBottom = padY;
724     data.m_Parameters.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
725
726     std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refWorkloadFactory.CreateTensorHandle(outputTensorInfo);
727     std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refWorkloadFactory.CreateTensorHandle(inputTensorInfo);
728
729     // Don't execute if Pooling is not supported, as an exception will be raised.
730     armnn::BackendId backend = workloadFactory.GetBackendId();
731     const size_t reasonIfUnsupportedMaxLen = 255;
732     char reasonIfUnsupported[reasonIfUnsupportedMaxLen+1];
733     comparisonResult.supported = armnn::IsPooling2dSupported(backend, inputTensorInfo, outputTensorInfo,
734                                                              data.m_Parameters,
735                                                              reasonIfUnsupported, reasonIfUnsupportedMaxLen);
736     if (!comparisonResult.supported)
737     {
738         return comparisonResult;
739     }
740
741     armnn::Pooling2dQueueDescriptor refData = data;
742     armnn::WorkloadInfo refInfo = info;
743     SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
744     SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
745
746     std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreatePooling2d(data, info);
747     std::unique_ptr<armnn::IWorkload> workloadRef = refWorkloadFactory.CreatePooling2d(refData, refInfo);
748
749     outputHandleRef->Allocate();
750     inputHandleRef->Allocate();
751     inputHandle->Allocate();
752     outputHandle->Allocate();
753
754     CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
755     CopyDataToITensorHandle(inputHandleRef.get(), &input[0][0][0][0]);
756
757     workload->Execute();
758     workloadRef->Execute();
759
760     CopyDataFromITensorHandle(&comparisonResult.output[0][0][0][0], outputHandle.get());
761     CopyDataFromITensorHandle(&comparisonResult.outputExpected[0][0][0][0], outputHandleRef.get());
762
763     return comparisonResult;
764 }
765
766 //
767 // Tests max pooling with the following parameters:
768 //
769 //   Pooling size: 2x2
770 //   Stride:       (2,2)
771 //   input size:   4x4
772 //   channels:     1
773 //   batch size:   1
774 //
775 template<typename T>
776 LayerTestResult<T, 4> SimpleMaxPooling2dSize2x2Stride2x2TestCommon(armnn::IWorkloadFactory& workloadFactory,
777                                                                    bool forceNoPadding,
778                                                                    float qScale = 1.0f,
779                                                                    int32_t qOffset = 0)
780 {
781     armnn::Pooling2dDescriptor descriptor;
782     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
783     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
784     descriptor.m_StrideX = 2;
785     descriptor.m_StrideY = 2;
786     descriptor.m_PadLeft = descriptor.m_PadRight = forceNoPadding ? 0 : 3;
787     descriptor.m_PadTop = descriptor.m_PadBottom = 0;
788     descriptor.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
789     descriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
790
791     unsigned int inputWidth = 4;
792     unsigned int inputHeight = 4;
793     unsigned int outputWidth =
794         (inputWidth + descriptor.m_PadLeft + descriptor.m_PadRight + descriptor.m_StrideX - descriptor.m_PoolWidth) /
795         descriptor.m_StrideX;
796     unsigned int outputHeight =
797         (inputHeight + descriptor.m_PadTop + descriptor.m_PadBottom + descriptor.m_StrideY - descriptor.m_PoolHeight) /
798         descriptor.m_StrideY;
799     unsigned int channels = 1;
800     unsigned int batchSize = 1;
801
802     std::vector<float> inputData = {
803         510.0f, 222.0f, 780.0f, 654.0f,
804         141.0f, 276.0f,  15.0f, 546.0f,
805         303.0f, 618.0f, 582.0f, 339.0f,
806         438.0f, 564.0f, 573.0f, 402.0f
807     };
808
809     // Note that left and right edges will be 0.f, due to the 2x2 max pooling only accessing zeros here.
810     std::vector<float> expectedOutputDataWithPadding = {
811         0.0f, 510.0f, 780.0f, 654.0f, 0.0f,
812         0.0f, 438.0f, 618.0f, 402.0f, 0.0f
813     };
814
815     std::vector<float> expectedOutputDataNoPadding = {
816         510.0f, 780.0f,
817         618.0f, 582.0f
818     };
819
820     armnn::TensorInfo inputTensorInfo({ batchSize, channels, inputHeight, inputWidth }, armnn::GetDataType<T>());
821
822     // Scale and offset should match input - we're just calculating maximum values.
823     armnn::TensorInfo outputTensorInfo({ batchSize, channels, outputHeight, outputWidth }, armnn::GetDataType<T>());
824
825     // Set quantization parameters if the requested type is a quantized type.
826     if(armnn::IsQuantizedType<T>())
827     {
828         inputTensorInfo.SetQuantizationScale(qScale);
829         inputTensorInfo.SetQuantizationOffset(qOffset);
830         outputTensorInfo.SetQuantizationScale(qScale);
831         outputTensorInfo.SetQuantizationOffset(qOffset);
832     }
833
834     auto input = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, inputData));
835
836     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
837         forceNoPadding ? QuantizedVector<T>(qScale, qOffset, expectedOutputDataNoPadding) :
838                          QuantizedVector<T>(qScale, qOffset, expectedOutputDataWithPadding));
839
840     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
841 }
842
843 //
844 // Tests max pooling with the following parameters:
845 //
846 //   Pooling size: 3x2
847 //   Stride:       (2,2)
848 //   input size:   3x2
849 //   channels:     1
850 //   batch size:   1
851 //
852 template<typename T>
853 LayerTestResult<T, 4> IgnorePaddingAveragePooling2dSize3x2Stride2x2TestCommon(
854         armnn::IWorkloadFactory& workloadFactory,
855         bool forceNoPadding,
856         float qScale = 1.0f,
857         int32_t qOffset = 0)
858 {
859     armnn::Pooling2dDescriptor descriptor;
860     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
861     descriptor.m_PoolWidth = 3;
862     descriptor.m_PoolHeight = 2;
863     descriptor.m_StrideX = 2;
864     descriptor.m_StrideY = 2;
865     descriptor.m_PadLeft = (forceNoPadding) ? 0 : 1;
866     descriptor.m_PadRight = descriptor.m_PadLeft;
867     descriptor.m_PadTop = 0;
868     descriptor.m_PadBottom = 0;
869     descriptor.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor;
870     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
871
872     unsigned int inputWidth = 3;
873     unsigned int inputHeight = 2;
874     unsigned int outputWidth =
875         (inputWidth + descriptor.m_PadLeft + descriptor.m_PadRight + descriptor.m_StrideX - descriptor.m_PoolWidth) /
876         descriptor.m_StrideX;
877     unsigned int outputHeight =
878         (inputHeight + descriptor.m_PadTop + descriptor.m_PadBottom + descriptor.m_StrideY - descriptor.m_PoolHeight) /
879         descriptor.m_StrideY;
880     unsigned int channels = 1;
881     unsigned int batchSize = 1;
882
883     std::vector<float> inputData = {
884         3.0f, 6.0f, 9.0f,
885         12.0f, 15.0f, 18.0f,
886     };
887
888     std::vector<float> expectedOutputDataWithPadding = {
889         6.0f, 8.0f,
890     };
891
892     std::vector<float> expectedOutputDataNoPadding = {
893         10.5f,
894     };
895
896     armnn::TensorInfo inputTensorInfo({ batchSize, channels, inputHeight, inputWidth }, armnn::GetDataType<T>());
897
898     // Scale and offset should match input - we're just calculating average values.
899     armnn::TensorInfo outputTensorInfo({ batchSize, channels, outputHeight, outputWidth }, armnn::GetDataType<T>());
900
901     // Set quantization parameters if the requested type is a quantized type.
902     if(armnn::IsQuantizedType<T>())
903     {
904         inputTensorInfo.SetQuantizationScale(qScale);
905         inputTensorInfo.SetQuantizationOffset(qOffset);
906         outputTensorInfo.SetQuantizationScale(qScale);
907         outputTensorInfo.SetQuantizationOffset(qOffset);
908     }
909
910     auto input = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, inputData));
911
912     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
913         forceNoPadding ? QuantizedVector<T>(qScale, qOffset, expectedOutputDataNoPadding) :
914                          QuantizedVector<T>(qScale, qOffset, expectedOutputDataWithPadding));
915
916     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
917 }
918
919
920 template<typename T>
921 LayerTestResult<T, 4> IgnorePaddingSimpleMaxPooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
922                                                             float qScale = 1.0f,
923                                                             int32_t qOffset = 0)
924 {
925     armnn::Pooling2dDescriptor descriptor;
926     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
927     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
928     descriptor.m_StrideX = descriptor.m_StrideY = 2;
929     descriptor.m_PadLeft = 1;
930     descriptor.m_PadRight = 1;
931     descriptor.m_PadTop = 1;
932     descriptor.m_PadBottom = 1;
933     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
934
935     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
936     armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, armnn::GetDataType<T>());
937
938     // Set quantization parameters if the requested type is a quantized type.
939     if(armnn::IsQuantizedType<T>())
940     {
941         inputTensorInfo.SetQuantizationScale(qScale);
942         inputTensorInfo.SetQuantizationOffset(qOffset);
943         outputTensorInfo.SetQuantizationScale(qScale);
944         outputTensorInfo.SetQuantizationOffset(qOffset);
945     }
946
947     auto input = MakeTensor<T, 4>(inputTensorInfo,
948         QuantizedVector<T>(qScale, qOffset, {
949             -1.0f, -2.0f,  3.0f,  4.0f,
950             -1.0f, -2.0f,  3.0f,  4.0f,
951              1.0f,  2.0f, -3.0f, -4.0f,
952              1.0f,  2.0f, -3.0f, -4.0f,
953         }));
954
955     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
956         QuantizedVector<T>(qScale, qOffset, {
957             -1.0f,  3.0f,  4.0f,
958              1.0f,  3.0f,  4.0f,
959              1.0f,  2.0f, -4.0f,
960         }));
961
962     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
963 }
964
965 template<typename T>
966 LayerTestResult<T, 4> IgnorePaddingMaxPooling2dSize3TestCommon(armnn::IWorkloadFactory& workloadFactory,
967                                                             float qScale = 1.0f,
968                                                             int32_t qOffset = 0)
969 {
970     armnn::Pooling2dDescriptor descriptor;
971     descriptor.m_PoolType = armnn::PoolingAlgorithm::Max;
972     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
973     descriptor.m_StrideX = descriptor.m_StrideY = 1;
974     descriptor.m_PadLeft = 1;
975     descriptor.m_PadRight = 1;
976     descriptor.m_PadTop = 1;
977     descriptor.m_PadBottom = 1;
978     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
979
980     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
981     armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
982
983     // Set quantization parameters if the requested type is a quantized type.
984     if(armnn::IsQuantizedType<T>())
985     {
986         inputTensorInfo.SetQuantizationScale(qScale);
987         inputTensorInfo.SetQuantizationOffset(qOffset);
988         outputTensorInfo.SetQuantizationScale(qScale);
989         outputTensorInfo.SetQuantizationOffset(qOffset);
990     }
991
992     auto input = MakeTensor<T, 4>(inputTensorInfo,
993         QuantizedVector<T>(qScale, qOffset, {
994             -1.0f, -2.0f,  3.0f,  4.0f,
995             -1.0f, -2.0f,  3.0f,  4.0f,
996              1.0f,  2.0f, -3.0f, -4.0f,
997              1.0f,  2.0f, -3.0f, -4.0f,
998         }));
999
1000     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1001         QuantizedVector<T>(qScale, qOffset, {
1002             -1.0f,  3.0f,  4.0f,  4.0f,
1003              2.0f,  3.0f,  4.0f,  4.0f,
1004              2.0f,  3.0f,  4.0f,  4.0f,
1005              2.0f,  2.0f,  2.0f, -3.0f,
1006         }));
1007
1008     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1009 }
1010
1011 template<typename T>
1012 LayerTestResult<T, 4> IgnorePaddingSimpleAveragePooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
1013                                                                  float qScale = 1.0f,
1014                                                                  int32_t qOffset = 0)
1015 {
1016     armnn::Pooling2dDescriptor descriptor;
1017     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
1018     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
1019     descriptor.m_StrideX = descriptor.m_StrideY = 2;
1020     descriptor.m_PadLeft = 1;
1021     descriptor.m_PadRight = 1;
1022     descriptor.m_PadTop = 1;
1023     descriptor.m_PadBottom = 1;
1024     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
1025
1026     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1027     armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, armnn::GetDataType<T>());
1028
1029     // Set quantization parameters if the requested type is a quantized type.
1030     if(armnn::IsQuantizedType<T>())
1031     {
1032         inputTensorInfo.SetQuantizationScale(qScale);
1033         inputTensorInfo.SetQuantizationOffset(qOffset);
1034         outputTensorInfo.SetQuantizationScale(qScale);
1035         outputTensorInfo.SetQuantizationOffset(qOffset);
1036     }
1037
1038     auto input = MakeTensor<T, 4>(inputTensorInfo,
1039         QuantizedVector<T>(qScale, qOffset, {
1040             12.0f, 20.0f, 32.0f, 40.0f,
1041             12.0f, 20.0f, 32.0f, 40.0f,
1042             12.0f, 20.0f, 32.0f, 40.0f,
1043             12.0f, 20.0f, 32.0f, 40.0f,
1044         }));
1045
1046     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1047         QuantizedVector<T>(qScale, qOffset, {
1048             3.0f,  13.0f,  10.0f,
1049             6.0f,  26.0f,  20.0f,
1050             3.0f,  13.0f,  10.0f,
1051         }));
1052
1053     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1054 }
1055
1056 template<typename T>
1057 LayerTestResult<T, 4> IgnorePaddingSimpleAveragePooling2dNoPaddingTestCommon(armnn::IWorkloadFactory& workloadFactory,
1058                                                                  float qScale = 1.0f,
1059                                                                  int32_t qOffset = 0)
1060 {
1061     armnn::Pooling2dDescriptor descriptor;
1062     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
1063     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
1064     descriptor.m_StrideX = descriptor.m_StrideY = 2;
1065     descriptor.m_PadLeft = 0;
1066     descriptor.m_PadRight = 0;
1067     descriptor.m_PadTop = 0;
1068     descriptor.m_PadBottom = 0;
1069     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
1070     descriptor.m_OutputShapeRounding = armnn::OutputShapeRounding::Ceiling;
1071
1072     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4}, armnn::GetDataType<T>());
1073     armnn::TensorInfo outputTensorInfo({ 1, 1, 2, 2 }, armnn::GetDataType<T>());
1074
1075     // Set quantization parameters if the requested type is a quantized type.
1076     if(armnn::IsQuantizedType<T>())
1077     {
1078         inputTensorInfo.SetQuantizationScale(qScale);
1079         inputTensorInfo.SetQuantizationOffset(qOffset);
1080         outputTensorInfo.SetQuantizationScale(qScale);
1081         outputTensorInfo.SetQuantizationOffset(qOffset);
1082     }
1083
1084     auto input = MakeTensor<T, 4>(inputTensorInfo,
1085         QuantizedVector<T>(qScale, qOffset, {
1086             1.0f, 2.0f, 3.0f, 4.0f,
1087             1.0f, 2.0f, 3.0f, 4.0f,
1088             1.0f, 2.0f, 3.0f, 4.0f,
1089             1.0f, 2.0f, 3.0f, 4.0f,
1090         }));
1091
1092     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1093         QuantizedVector<T>(qScale, qOffset, {
1094             2.0f, 3.5f,
1095             2.0f, 3.5f
1096         }));
1097
1098     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1099 }
1100
1101 template<typename T>
1102 LayerTestResult<T, 4> IgnorePaddingAveragePooling2dSize3TestCommon(armnn::IWorkloadFactory& workloadFactory,
1103                                                                 float qScale = 1.0f,
1104                                                                 int32_t qOffset = 0)
1105 {
1106     armnn::Pooling2dDescriptor descriptor;
1107     descriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
1108     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
1109     descriptor.m_StrideX = descriptor.m_StrideY = 1;
1110     descriptor.m_PadLeft = 1;
1111     descriptor.m_PadRight = 1;
1112     descriptor.m_PadTop = 1;
1113     descriptor.m_PadBottom = 1;
1114     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
1115
1116     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1117     armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1118
1119     // Set quantization parameters if the requested type is a quantized type.
1120     if(armnn::IsQuantizedType<T>())
1121     {
1122         inputTensorInfo.SetQuantizationScale(qScale);
1123         inputTensorInfo.SetQuantizationOffset(qOffset);
1124         outputTensorInfo.SetQuantizationScale(qScale);
1125         outputTensorInfo.SetQuantizationOffset(qOffset);
1126     }
1127
1128     auto input = MakeTensor<T, 4>(inputTensorInfo,
1129         QuantizedVector<T>(qScale, qOffset, {
1130             9.0f,   27.0f,  18.0f,  36.0f,
1131             18.0f,   9.0f,  18.0f,   9.0f,
1132             27.0f,  18.0f,   9.0f,  27.0f,
1133             9.0f,   27.0f,   9.0f,  18.0f,
1134         }));
1135
1136     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1137         QuantizedVector<T>(qScale, qOffset, {
1138              7.0f,  11.0f,  13.0f, 9.0f,
1139             12.0f,  17.0f,  19.0f, 13.0f,
1140             12.0f,  16.0f,  16.0f, 10.0f,
1141              9.0f,  11.0f,  12.0f, 7.0f,
1142         }));
1143
1144     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1145 }
1146
1147 template<typename T>
1148 LayerTestResult<T, 4> IgnorePaddingSimpleL2Pooling2dTestCommon(armnn::IWorkloadFactory& workloadFactory,
1149                                                             float qScale = 1.0f,
1150                                                             int32_t qOffset = 0)
1151 {
1152     armnn::Pooling2dDescriptor descriptor;
1153     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
1154     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 2;
1155     descriptor.m_StrideX = descriptor.m_StrideY = 2;
1156     descriptor.m_PadLeft = 1;
1157     descriptor.m_PadRight = 1;
1158     descriptor.m_PadTop = 1;
1159     descriptor.m_PadBottom = 1;
1160     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
1161
1162     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1163     armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3 }, armnn::GetDataType<T>());
1164
1165     // Set quantization parameters if the requested type is a quantized type.
1166     if(armnn::IsQuantizedType<T>())
1167     {
1168         inputTensorInfo.SetQuantizationScale(qScale);
1169         inputTensorInfo.SetQuantizationOffset(qOffset);
1170         outputTensorInfo.SetQuantizationScale(qScale);
1171         outputTensorInfo.SetQuantizationOffset(qOffset);
1172     }
1173
1174     auto input = MakeTensor<T, 4>(inputTensorInfo,
1175         QuantizedVector<T>(qScale, qOffset, {
1176             2.0f,  4.0f, 8.0f, 16.0f,
1177             4.0f,  2.0f, 2.0f, 4.0f,
1178             8.0f,  2.0f, 4.0f, 2.0f,
1179             16.0f, 2.0f, 2.0f, 8.0f,
1180         }));
1181
1182     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1183         QuantizedVector<T>(qScale, qOffset, {
1184                1.0f,     4.4721f,   8.0f,
1185             4.4721f,     2.6457f,   2.236f,
1186                8.0f,     1.4142f,   4.0f,
1187         }));
1188
1189     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1190 }
1191
1192 template<typename T>
1193 LayerTestResult<T, 4> IgnorePaddingL2Pooling2dSize3TestCommon(armnn::IWorkloadFactory& workloadFactory,
1194                                                            float qScale = 1.0f,
1195                                                            int32_t qOffset = 0)
1196 {
1197     armnn::Pooling2dDescriptor descriptor;
1198     descriptor.m_PoolType = armnn::PoolingAlgorithm::L2;
1199     descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
1200     descriptor.m_StrideX = descriptor.m_StrideY = 1;
1201     descriptor.m_PadLeft = 1;
1202     descriptor.m_PadRight = 1;
1203     descriptor.m_PadTop = 1;
1204     descriptor.m_PadBottom = 1;
1205     descriptor.m_PaddingMethod = armnn::PaddingMethod::IgnoreValue;
1206
1207     armnn::TensorInfo inputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1208     armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4 }, armnn::GetDataType<T>());
1209
1210     // Set quantization parameters if the requested type is a quantized type.
1211     if(armnn::IsQuantizedType<T>())
1212     {
1213         inputTensorInfo.SetQuantizationScale(qScale);
1214         inputTensorInfo.SetQuantizationOffset(qOffset);
1215         outputTensorInfo.SetQuantizationScale(qScale);
1216         outputTensorInfo.SetQuantizationOffset(qOffset);
1217     }
1218
1219     auto input = MakeTensor<T, 4>(inputTensorInfo,
1220         QuantizedVector<T>(qScale, qOffset, {
1221             1.0f, 2.0f, 3.0f, 4.0f,
1222             1.0f, 2.0f, 3.0f, 4.0f,
1223             1.0f, 2.0f, 3.0f, 4.0f,
1224             1.0f, 2.0f, 3.0f, 4.0f,
1225         }));
1226
1227     auto outputExpected = MakeTensor<T, 4>(outputTensorInfo,
1228         QuantizedVector<T>(qScale, qOffset, {
1229             1.0540f, 1.7638f, 2.5385f, 2.3570f,
1230             1.2909f, 2.1602f, 3.1091f, 2.8867f,
1231             1.2909f, 2.1602f, 3.1091f, 2.8867f,
1232             1.0540f, 1.7638f, 2.5385f, 2.3570f,
1233         }));
1234
1235     return SimplePooling2dTestImpl<T>(workloadFactory, descriptor, qScale, qOffset, input, outputExpected);
1236 }