blob: e825fffaea3c0e6357cb1cfcf56b5b03bb95b06d [file] [log] [blame]
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "Conv2dTestImpl.hpp"
7
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01008#include <QuantizeHelper.hpp>
Matteo Martincighe011d202019-11-28 11:35:47 +00009#include <armnnUtils/TensorUtils.hpp>
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010010
11#include <armnn/ArmNN.hpp>
12
Matteo Martincighe011d202019-11-28 11:35:47 +000013#include <armnnUtils/DataLayoutIndexed.hpp>
14#include <armnnUtils/Permute.hpp>
15
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010016#include <backendsCommon/CpuTensorHandle.hpp>
17
Aron Virginas-Tar5edc8812019-11-05 18:00:21 +000018#include <backendsCommon/test/DataLayoutUtils.hpp>
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010019#include <backendsCommon/test/TensorCopyUtils.hpp>
20#include <backendsCommon/test/WorkloadTestUtils.hpp>
21
22#include <test/TensorHelpers.hpp>
23
24#include <boost/numeric/conversion/cast.hpp>
25
26#include <string>
27
28//
29// Static data
30//
31
32// 2-channel bias used by a number of Conv2d tests.
33static std::vector<float> Bias2({0, 2});
34
35static std::vector<float> Bias4({1, 2, 3, 4});
36
37static std::vector<float> Bias8({1, 2, 3, 4, 1, 2, 3, 4});
38
39// 3-channel 16x8 image used as common input data for a number of Conv2d tests.
40static std::vector<float> ConvInput3x8x16({
41 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
42 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
43 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
44 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
45 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
46 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
47 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
48 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
49 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
60 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
65});
66
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010067using namespace armnnUtils;
68
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010069//
70// Helper templates
71//
72
73// Helper template that returns either Bias2 or an empty vector depending on whether bias is enabled.
74template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
75boost::multi_array<T, 1> GetBias2(bool biasEnabled, float qScale)
76{
77 if(biasEnabled)
78 {
79 armnn::TensorInfo biasDesc({static_cast<unsigned int>(Bias2.size())}, ArmnnType);
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010080 boost::multi_array<T, 1> bias = MakeTensor<T, 1>(biasDesc, QuantizedVector<T>(Bias2, qScale, 0.0f));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010081 return bias;
82 }
83 else
84 {
85 return boost::multi_array<T, 1>();
86 }
87}
88
89// Helper template that returns either Bias4 or an empty vector depending on whether bias is enabled.
90template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
91boost::multi_array<T, 1> GetBias4(bool biasEnabled, float qScale)
92{
93 if(biasEnabled)
94 {
95 armnn::TensorInfo biasDesc({static_cast<unsigned int>(Bias4.size())}, ArmnnType);
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010096 boost::multi_array<T, 1> bias = MakeTensor<T, 1>(biasDesc, QuantizedVector<T>(Bias4, qScale, 0.0f));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010097 return bias;
98 }
99 else
100 {
101 return boost::multi_array<T, 1>();
102 }
103}
104
105// Helper template that returns either Bias8 or an empty vector depending on whether bias is enabled.
106template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
107boost::multi_array<T, 1> GetBias8(bool biasEnabled, float qScale)
108{
109 if(biasEnabled)
110 {
111 armnn::TensorInfo biasDesc({static_cast<unsigned int>(Bias4.size())}, ArmnnType);
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100112 boost::multi_array<T, 1> bias = MakeTensor<T, 1>(biasDesc, QuantizedVector<T>(Bias8, qScale, 0.0f));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100113 return bias;
114 }
115 else
116 {
117 return boost::multi_array<T, 1>();
118 }
119}
120
121// Helper template that returns either Bias4 or an empty vector depending on whether bias is enabled.
122template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
123boost::multi_array<T, 1> GetBias(bool biasEnabled, float qScale, armnn::TensorInfo outputInfo, armnn::DataLayout layout)
124{
125 const armnnUtils::DataLayoutIndexed dataLayoutIndexed(layout);
126 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
127 const unsigned int outputChannels = outputInfo.GetShape()[channelsIndex];
128
129 switch (outputChannels)
130 {
131 case 2:
132 default:
133 {
134 return GetBias2<ArmnnType>(biasEnabled, qScale);
135 }
136 case 4:
137 {
138 return GetBias4<ArmnnType>(biasEnabled, qScale);
139 }
140 case 8:
141 {
142 return GetBias8<ArmnnType>(biasEnabled, qScale);
143 }
144 }
145}
146
147//
148// Implementation templates
149//
150
151// Mapping from input type to bias type for fully connected layers.
152// float => float, uint8_t => int32_t
153template<typename T>
154struct FullyConnectedBiasTypeForInputType;
155
156template<>
157struct FullyConnectedBiasTypeForInputType<float>
158{
159 using Type = float;
160};
161
162template<>
163struct FullyConnectedBiasTypeForInputType<uint8_t>
164{
165 using Type = int32_t;
166};
167
168// Modifies a std::vector in-place using a specified bias.
169template<typename T, typename B>
170void ApplyBias(std::vector<T>& v, float vScale, int32_t vOffset,
171 const std::vector<B>& bias, float bScale, int32_t bOffset, uint32_t w, uint32_t h)
172{
173 BOOST_ASSERT_MSG((armnn::IsQuantizedType<T>() && vScale != 0.0f) || (!armnn::IsQuantizedType<T>()),
174 "Invalid type and parameter combination.");
175 BOOST_ASSERT_MSG((armnn::IsQuantizedType<B>() && bScale != 0.0f) || (!armnn::IsQuantizedType<B>()),
176 "Invalid type and parameter combination.");
177
178 // Note we need to dequantize and re-quantize the image value and the bias.
179 for (uint32_t i = 0; i < bias.size(); ++i)
180 {
181 float dBias = SelectiveDequantize(bias[i], bScale, bOffset);
182 for (uint32_t y = 0; y < h; ++y)
183 {
184 for (uint32_t x = 0; x < w; ++x)
185 {
186 uint32_t offset = (i * h + y) * w + x;
187 BOOST_ASSERT(offset < v.size());
188 T& outRef = v[offset];
189 float dOutput = SelectiveDequantize(outRef, vScale, vOffset);
190 outRef = SelectiveQuantize<T>(dOutput + dBias, vScale, vOffset);
191 }
192 }
193 }
194}
195
196//
197// Convolution2d implementations
198//
199
200template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
201 typename T = armnn::ResolveType<ArmnnType>, typename B = armnn::ResolveType<ArmnnBType>>
202LayerTestResult<T, 4> SimpleConvolution2dTestImpl(
203 armnn::IWorkloadFactory& workloadFactory,
204 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
205 const boost::multi_array<T, 4>& originalInput,
206 const boost::multi_array<T, 4>& originalKernel,
207 const boost::multi_array<B, 1>& bias,
208 const boost::multi_array<T, 4>& originalOutputExpected,
209 float qScale,
210 int32_t qOffset,
211 const armnn::DataLayout layout = armnn::DataLayout::NCHW,
212 uint32_t padLeft = 0,
213 uint32_t padTop = 0,
214 uint32_t padRight = 0,
215 uint32_t padBottom = 0,
216 uint32_t strideX = 1,
217 uint32_t strideY = 1,
218 uint32_t dilationX = 1,
219 uint32_t dilationY = 1)
220{
221 unsigned int inputHeight = boost::numeric_cast<unsigned int>(originalInput.shape()[2]);
222 unsigned int inputWidth = boost::numeric_cast<unsigned int>(originalInput.shape()[3]);
223 unsigned int inputChannels = boost::numeric_cast<unsigned int>(originalInput.shape()[1]);
224 unsigned int inputNum = boost::numeric_cast<unsigned int>(originalInput.shape()[0]);
225
226 unsigned int outputHeight = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[2]);
227 unsigned int outputWidth = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[3]);
228 unsigned int outputChannels = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[1]);
229 unsigned int outputNum = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[0]);
230
231 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(originalKernel.shape()[2]);
232 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(originalKernel.shape()[3]);
233 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(originalKernel.shape()[1]);
234 unsigned int kernelDepthMul = boost::numeric_cast<unsigned int>(originalKernel.shape()[0]);
235
236 bool biasEnabled = bias.size() > 0;
237
238 // This function currently assumes 1 batch of input/output (and duplicates this into 2 batches).
239 BOOST_ASSERT(inputNum == 1);
240 BOOST_ASSERT(outputNum == 1);
241
242 // If a bias is used, its size must equal the number of output channels.
243 BOOST_ASSERT(!biasEnabled || bias.size() == outputChannels);
244
245
246 // Note these tensors will use two (identical) batches.
247 armnn::TensorInfo inputTensorInfo =
248 armnnUtils::GetTensorInfo(2*inputNum, inputChannels, inputHeight, inputWidth, layout, ArmnnType);
249 armnn::TensorInfo outputTensorInfo =
250 armnnUtils::GetTensorInfo(2*outputNum, outputChannels, outputHeight, outputWidth, layout, ArmnnType);
251 armnn::TensorInfo kernelDesc =
252 armnnUtils::GetTensorInfo(kernelDepthMul, kernelChannels, kernelHeight, kernelWidth, layout, ArmnnType);
253 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, ArmnnBType);
254
255 // Set quantization parameters if the requested type is a quantized type.
256 if(armnn::IsQuantizedType<T>())
257 {
258 inputTensorInfo.SetQuantizationScale(qScale);
259 inputTensorInfo.SetQuantizationOffset(qOffset);
260 outputTensorInfo.SetQuantizationScale(qScale);
261 outputTensorInfo.SetQuantizationOffset(qOffset);
262 kernelDesc.SetQuantizationScale(qScale);
263 kernelDesc.SetQuantizationOffset(qOffset);
264 biasDesc.SetQuantizationScale(qScale*qScale);
265 biasDesc.SetQuantizationOffset(0);
266 }
267
268 LayerTestResult<T, 4> ret(outputTensorInfo);
269
270 // Construct input data - two batches of the same input image.
271 std::vector<T> inputImage;
272 inputImage.assign(originalInput.data(), originalInput.data() + 1*inputChannels*inputHeight*inputWidth);
273 std::vector<T> inputData;
274 inputData.insert(inputData.end(), inputImage.begin(), inputImage.end());
275 inputData.insert(inputData.end(), inputImage.begin(), inputImage.end());
276
277 // at this point if we require it permute the input data
278 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
279 if (layout == armnn::DataLayout::NHWC)
280 {
281 std::vector<T> tmp(inputData.size());
282 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data(), sizeof(T));
283 inputData = tmp;
284 }
285
286 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
287
288 std::vector<T> outputImage;
289 outputImage.assign(originalOutputExpected.data(),
290 originalOutputExpected.data() + outputChannels*outputHeight*outputWidth);
291
292 // Apply bias to output image if it is enabled.
293 if(biasEnabled)
294 {
295 std::vector<T> biasV;
296 biasV.assign(bias.data(), bias.data() + outputChannels);
297 ApplyBias(outputImage, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
298 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
299 outputWidth, outputHeight);
300 }
301
302 // Construct expected output data - two identical images.
303 std::vector<T> outputData;
304 outputData.insert(outputData.end(), outputImage.begin(), outputImage.end());
305 outputData.insert(outputData.end(), outputImage.begin(), outputImage.end());
306
307 // at this point if we require it permute the expected output
308 if (layout == armnn::DataLayout::NHWC)
309 {
310 std::vector<T> tmp(outputData.size());
311 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data(), sizeof(T));
312 outputData = tmp;
313 }
314 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
315
316 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
317 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
318
319 armnn::Convolution2dQueueDescriptor data;
320 armnn::WorkloadInfo info;
321 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
322 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
323 // Permute the kernel if necessary
324 boost::multi_array<T, 4> kernel = boost::multi_array<T, 4>(originalKernel);
325 if (layout == armnn::DataLayout::NHWC)
326 {
327 armnnUtils::Permute(kernelDesc.GetShape(), NCHWToNHWC, originalKernel.data(), kernel.data(), sizeof(T));
328 }
329 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
330
331 if(biasEnabled)
332 {
333 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
334 }
335
336 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
337 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
338
339 data.m_Weight = &weightsTensor;
340 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
341 data.m_Parameters.m_StrideX = strideX;
342 data.m_Parameters.m_StrideY = strideY;
343 data.m_Parameters.m_PadLeft = padLeft;
344 data.m_Parameters.m_PadRight = padRight;
345 data.m_Parameters.m_PadTop = padTop;
346 data.m_Parameters.m_PadBottom = padBottom;
347 data.m_Parameters.m_BiasEnabled = biasEnabled;
348 data.m_Parameters.m_DataLayout = layout;
349 data.m_Parameters.m_DilationX = dilationX;
350 data.m_Parameters.m_DilationY = dilationY;
351
352 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
353 inputHandle->Allocate();
354 outputHandle->Allocate();
355
356 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
357
358 ExecuteWorkload(*workload, memoryManager);
359
360 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
361
362 return ret;
363}
364
365template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
366 typename T = armnn::ResolveType<ArmnnType>, typename B = armnn::ResolveType<ArmnnBType>>
367LayerTestResult<T, 4> SimpleConvolution2dNhwcTestImpl(
368 armnn::IWorkloadFactory& workloadFactory,
369 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
370 const boost::multi_array<T, 4>& input,
371 const boost::multi_array<T, 4>& kernel,
372 const boost::multi_array<B, 1>& bias,
373 const boost::multi_array<T, 4>& outputExpected,
374 const armnn::DataLayout dataLayout,
375 float qScale,
376 int32_t qOffset,
377 uint32_t padLeft = 1,
378 uint32_t padTop = 1,
379 uint32_t padRight = 1,
380 uint32_t padBottom = 1,
381 uint32_t strideX = 1,
382 uint32_t strideY = 1)
383{
384 unsigned int inputNum = boost::numeric_cast<unsigned int>(input.shape()[0]);
385 unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[3]);
386 unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[1]);
387 unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[2]);
388
389 unsigned int kernelChanMul = boost::numeric_cast<unsigned int>(kernel.shape()[0]);
390 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(kernel.shape()[3]);
391 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(kernel.shape()[1]);
392 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(kernel.shape()[2]);
393
394 unsigned int outputNum = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
395 unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]);
396 unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]);
397 unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]);
398
399 bool biasEnabled = bias.size() > 0;
400
401 // Creates the tensors.
402 armnn::TensorInfo inputTensorInfo({inputNum, inputHeight, inputWidth, inputChannels}, ArmnnType);
403 armnn::TensorInfo outputTensorInfo({outputNum, outputHeight, outputWidth, outputChannels},
404 ArmnnType);
405 armnn::TensorInfo kernelDesc({kernelChanMul, kernelHeight, kernelWidth, kernelChannels}, ArmnnType);
406 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, ArmnnBType);
407
408 // Construct the input data.
409 std::vector<T> inputData;
410 inputData.assign(input.data(), input.data() + inputHeight*inputWidth*inputChannels);
411 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
412
413 // Construct the output data, with bias applied, as appropriate.
414 std::vector<T> outputData;
415 outputData.assign(outputExpected.data(), outputExpected.data() + outputHeight*outputWidth*outputChannels);
416
417 LayerTestResult<T, 4> ret(outputTensorInfo);
418 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
419
420 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
421 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
422
423 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
424 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
425
426 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
427
428 armnn::Convolution2dQueueDescriptor data;
429
430 data.m_Weight = &weightsTensor;
431 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
432 data.m_Parameters.m_StrideX = strideX;
433 data.m_Parameters.m_StrideY = strideY;
434 data.m_Parameters.m_PadLeft = padLeft;
435 data.m_Parameters.m_PadRight = padRight;
436 data.m_Parameters.m_PadTop = padTop;
437 data.m_Parameters.m_PadBottom = padBottom;
438 data.m_Parameters.m_BiasEnabled = biasEnabled;
439 data.m_Parameters.m_DataLayout = dataLayout;
440
441 armnn::WorkloadInfo info;
442 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
443 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
444
445 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
446 inputHandle->Allocate();
447 outputHandle->Allocate();
448
449 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
450
451 ExecuteWorkload(*workload, memoryManager);
452
453 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
454
455 return ret;
456}
457
458template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
459LayerTestResult<T,4> Convolution1dTestImpl(
460 armnn::IWorkloadFactory& workloadFactory,
461 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
462 float qScale,
463 int32_t qOffset,
464 bool biasEnabled)
465{
466 using B = armnn::ResolveType<ArmnnBType>;
467 // Until we have a specialist 1D convolution layer, we can fake one using
468 // 2D convolution with the final dimension set to 1.
469 // I don't anticipate this being particularly slow, given that convolution is implemented
470 // as a matrix multiplication, at which point dimension doesn't matter.
471
472 unsigned int batchSize = 1;
473 unsigned int inputChannels = 2;
474 unsigned int outputChannels = 3;
475 unsigned int inputSize = 5; // The 1D size (could view as 'width' or 'height').
476 unsigned int kernelSize = 3;
477 unsigned int padSize = 2;
478 unsigned int stride = 1;
479 unsigned int outputSize = 7; // (inputSize + 2 * padSize - kernelSize + 1) / stride.
480
481 armnn::TensorInfo inputInfo({batchSize, inputChannels, inputSize, 1}, ArmnnType);
482 armnn::TensorInfo outputInfo({batchSize, outputChannels, outputSize, 1}, ArmnnType);
483 armnn::TensorInfo kernelInfo({outputChannels, inputChannels, kernelSize, 1}, ArmnnType);
484 armnn::TensorInfo biasInfo({outputChannels}, ArmnnBType);
485
486 // Set quantization parameters if the requested type is a quantized type.
487 if(armnn::IsQuantizedType<T>())
488 {
489 inputInfo.SetQuantizationScale(qScale);
490 inputInfo.SetQuantizationOffset(qOffset);
491 outputInfo.SetQuantizationScale(qScale);
492 outputInfo.SetQuantizationOffset(qOffset);
493 kernelInfo.SetQuantizationScale(qScale);
494 kernelInfo.SetQuantizationOffset(qOffset);
495 biasInfo.SetQuantizationScale(inputInfo.GetQuantizationScale()*kernelInfo.GetQuantizationScale());
496 biasInfo.SetQuantizationOffset(0);
497 }
498
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100499 std::vector<T> inputData = QuantizedVector<T>(
500 {
501 5.0f, -2.0f, 2.5f, 0.0f, 1.0f,
502 -3.0f, 3.2f, 5.0f, 2.0f, 3.0f,
503 },
504 inputInfo.GetQuantizationScale(),
505 inputInfo.GetQuantizationOffset());
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100506
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100507 std::vector<T> kernelData = QuantizedVector<T>(
508 {
509 1.0f, 0.0f, 0.0f,
510 0.0f, 2.0f, -1.5f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100511
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100512 0.0f, 0.0f, 0.0f,
513 0.2f, 0.2f, 0.2f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100514
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100515 0.5f, 0.0f, 0.5f,
516 0.0f, -1.0f, 0.0f
517 },
518 kernelInfo.GetQuantizationScale(),
519 kernelInfo.GetQuantizationOffset());
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100520
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100521 std::vector<B> biasData =
522 QuantizedVector<B>({ 1.0f, 0.0f, 0.0f }, biasInfo.GetQuantizationScale(), biasInfo.GetQuantizationOffset());
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100523
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100524 std::vector<T> outputData = QuantizedVector<T>(
525 {
526 4.5f, -10.8f, 5.0f + 6.4f - 7.5f, -2.0f + 10.0f -3.0f, 2.5f + 4.0f - 4.5f, 6.0f, 1.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100527 -0.6f, -0.6f + 0.64f, -0.6f + 0.64f + 1.0f, 0.64f + 1.0f + 0.4f, 1.0f + 0.4f + 0.6f, 0.4f + 0.6f, 0.6f,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100528 2.5f, -1.0f + 3.0f, 1.25f - 3.2f + 2.5f, -1.0f - 5.0f, 1.25f + 0.5f - 2.0f, -3.0f, 0.5f
529 },
530 outputInfo.GetQuantizationScale(),
531 outputInfo.GetQuantizationOffset());
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100532
533 // Optionally apply bias to output image.
534 if(biasEnabled)
535 {
536 ApplyBias(outputData, outputInfo.GetQuantizationScale(), outputInfo.GetQuantizationOffset(),
537 biasData, biasInfo.GetQuantizationScale(), biasInfo.GetQuantizationOffset(),
538 1, outputSize);
539 }
540
541 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputInfo);
542 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputInfo);
543
544 armnn::Convolution2dQueueDescriptor data;
545 armnn::WorkloadInfo info;
546 armnn::ScopedCpuTensorHandle weightsTensor(kernelInfo);
547 armnn::ScopedCpuTensorHandle biasTensor(biasInfo);
548
549 AllocateAndCopyDataToITensorHandle(&weightsTensor, kernelData.data());
550 AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data());
551
552 AddInputToWorkload(data, info, inputInfo, inputHandle.get());
553 AddOutputToWorkload(data, info, outputInfo, outputHandle.get());
554
555 data.m_Weight = &weightsTensor;
556 data.m_Bias = &biasTensor;
557 data.m_Parameters.m_StrideX = 1;
558 data.m_Parameters.m_StrideY = stride;
559 data.m_Parameters.m_PadLeft = 0;
560 data.m_Parameters.m_PadRight = 0;
561 data.m_Parameters.m_PadTop = padSize;
562 data.m_Parameters.m_PadBottom = padSize;
563 data.m_Parameters.m_BiasEnabled = biasEnabled;
564
565 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
566 inputHandle->Allocate();
567 outputHandle->Allocate();
568
569 CopyDataToITensorHandle(inputHandle.get(), inputData.data());
570
571 ExecuteWorkload(*workload, memoryManager);
572
573 // Output
574 LayerTestResult<T,4> ret(outputInfo);
575 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
576 ret.outputExpected = MakeTensor<T, 4>(outputInfo, outputData);
577 return ret;
578}
579
580template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
581LayerTestResult<T, 4> SimpleConvolution2d3x3NhwcTestCommon(
582 armnn::IWorkloadFactory& workloadFactory,
583 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
584 float qScale,
585 int32_t qOffset,
586 bool biasEnabled,
587 armnn::DataLayout dataLayout)
588{
589 // Use common single-batch 5x5 image.
590
591 armnn::TensorInfo inputDesc({1, 3, 4, 1}, ArmnnType);
592 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc,
593 {
594 1, 5, 2, 3,
595 8, 7, 3, 6,
596 3, 3, 9, 1
597 });
598
599
600 // Use a 2-element batch of 3-channel 3x3 kernels.
601 armnn::TensorInfo kernelDesc({1, 3, 3, 1}, ArmnnType);
602 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc, {
603 4, 5, 6,
604 0, 0, 0,
605 3, 2, 1
606 });
607
608 // Expected output is 1 batch of a 5x5 image.
609 armnn::TensorInfo outputDesc({1, 3, 4, 1}, ArmnnType);
610
611 const std::vector<float> outputData =
612 {
613 23, 41, 33, 21,
614 44, 65, 76, 52,
615 82, 85, 79, 42
616 };
617
618 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, outputData);
619
620 return SimpleConvolution2dNhwcTestImpl<ArmnnType, ArmnnType>(
621 workloadFactory,
622 memoryManager,
623 input,
624 kernel,
625 boost::multi_array<T, 1>(),
626 expectedOutput,
627 dataLayout,
628 qScale,
629 qOffset);
630}
631
632template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
633LayerTestResult<T, 4> SimpleConvolution2d3x3Stride2x2TestCommon(
634 armnn::IWorkloadFactory& workloadFactory,
635 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
636 float qScale,
637 int32_t qOffset,
638 bool biasEnabled,
639 const armnn::DataLayout& dataLayout)
640{
641 // Input is a single-batch, 1 channel, 5x5 image.
642 armnn::TensorInfo inputDesc({1, 5, 5, 1}, ArmnnType);
643 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc,
644 {
645 1, 5, 2, 3, 5,
646 8, 7, 3, 6, 3,
647 3, 3, 9, 1, 9,
648 4, 1, 8, 1, 3,
649 6, 8, 1, 9, 2
650 });
651
652 // Use a 3x3 kernel.
653 armnn::TensorInfo kernelDesc({1, 3, 3, 1}, ArmnnType);
654 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc,
655 {
656 4, 5, 6,
657 0, 0, 0,
658 3, 2, 1
659 });
660
661 // Expected output is a single-batch, 1 channel, 3x3 image.
662 armnn::TensorInfo outputDesc({1, 3, 3, 1}, ArmnnType);
663
664 const std::vector<T> outputData =
665 {
666 23, 33, 24,
667 91, 99, 48,
668 26, 50, 19
669 };
670
671 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, outputData);
672
673 uint32_t padLeft = 1;
674 uint32_t padTop = 1;
675 uint32_t padRight = 1;
676 uint32_t padBottom = 1;
677 uint32_t strideX = 2;
678 uint32_t strideY = 2;
679
680 return SimpleConvolution2dNhwcTestImpl<ArmnnType, ArmnnType>(
681 workloadFactory,
682 memoryManager,
683 input,
684 kernel,
685 boost::multi_array<T, 1>(),
686 expectedOutput,
687 dataLayout,
688 qScale,
689 qOffset,
690 padLeft,
691 padTop,
692 padRight,
693 padBottom,
694 strideX,
695 strideY);
696}
697
698template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
699LayerTestResult<T, 4> SimpleConvolution2d3x5TestCommon(
700 armnn::IWorkloadFactory& workloadFactory,
701 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
702 float qScale,
703 int32_t qOffset,
704 bool biasEnabled,
705 const armnn::DataLayout layout)
706{
707 // Use common single-batch 3-channel 16x8 image.
708 armnn::TensorInfo inputDesc({1, 3, 8, 16}, ArmnnType);
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100709 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc, QuantizedVector<T>(ConvInput3x8x16, qScale, qOffset));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100710
711 // Use a 2-element batch with 3-channel 3x5 kernels.
712 armnn::TensorInfo kernelDesc({2, 3, 5, 3}, ArmnnType);
713 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100714 QuantizedVector<T>({
715 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100716 1, -1, 1,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100717 1, 1, 1,
718 1, 1, 1,
719 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100720
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100721 0, 0, 0,
722 0, 0, 0,
723 0, 0, 0,
724 0, 0, 0,
725 0, 0, 0,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100726
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100727 2, 2, 2,
728 2, 2, 2,
729 2, 2, 2,
730 2, 2, 2,
731 2, 2, 2,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100732
733
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100734 0, 0, 0,
735 0, 0, 0,
736 0, 0, 0,
737 0, 0, 0,
738 0, 0, 0,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100739
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100740 1, 1, 1,
741 1, 1, 1,
742 1, 1, 1,
743 1, 1, 1,
744 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100745
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100746 0, 0, 0,
747 0, 0, 0,
748 0, 0, 0,
749 0, 0, 0,
750 0, 0, 0
751 },
752 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100753
754 // Expected output is 2 batch elements of a 1-channel 14x4 image.
755 armnn::TensorInfo outputDesc({1, 2, 4, 14}, ArmnnType);
756 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100757 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100758 -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24,
759 -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
760 -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f,
761 -23.5f, -23.5f, -23.5f,
762 -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f, -23.5f,
763 -23.5f, -23.5f, -23.5f,
764
765 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
766 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
767 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
768 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100769 },
770 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100771
772 return SimpleConvolution2dTestImpl<ArmnnType, ArmnnBType>(
773 workloadFactory,
774 memoryManager,
775 input,
776 kernel,
777 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
778 expectedOutput,
779 qScale,
780 qOffset,
781 layout);
782}
783
784template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
785 typename T = armnn::ResolveType<ArmnnType>>
786LayerTestResult<T, 4> SimpleConvolution2d3x3TestCommon(
787 armnn::IWorkloadFactory& workloadFactory,
788 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
789 float qScale,
790 int32_t qOffset,
791 bool biasEnabled,
792 const armnn::DataLayout layout)
793{
794 // Use a 3x3 kernel, which exercises ArmCompute's direct convolution path.
795
796 // Use common single-batch 3-channel 16x8 image.
797 armnn::TensorInfo inputDesc({1, 3, 8, 16}, ArmnnType);
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100798 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc, QuantizedVector<T>(ConvInput3x8x16, qScale, qOffset));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100799
800 // Use a 2-element batch of 3-channel 3x3 kernels.
801 armnn::TensorInfo kernelDesc({2, 3, 3, 3}, ArmnnType);
802 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100803 QuantizedVector<T>({
804 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100805 1, -1, 1,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100806 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100807
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100808 0, 0, 0,
809 0, 0, 0,
810 0, 0, 0,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100811
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100812 2, 2, 2,
813 2, 2, 2,
814 2, 2, 2,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100815
816
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100817 0, 0, 0,
818 0, 0, 0,
819 0, 0, 0,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100820
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100821 1, 1, 1,
822 1, 1, 1,
823 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100824
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100825 0, 0, 0,
826 0, 0, 0,
827 0, 0, 0
828 },
829 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100830
831 // Expected output is 1 batch of a 2-channel 14x6 image.
832 armnn::TensorInfo outputDesc({1, 2, 6, 14}, ArmnnType);
833 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100834 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100835 -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
836 -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
837 -14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,
838 -14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,
839 -14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,
840 -14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,-14.5f,
841
842 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
843 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
844 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
845 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
846 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
847 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100848 },
849 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100850
851 return SimpleConvolution2dTestImpl<ArmnnType, ArmnnBType>(
852 workloadFactory,
853 memoryManager,
854 input,
855 kernel,
856 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
857 expectedOutput,
858 qScale,
859 qOffset,
860 layout);
861}
862
863template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
864 typename T = armnn::ResolveType<ArmnnType>>
865LayerTestResult<T, 4> Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTestCommon(
866 armnn::IWorkloadFactory& workloadFactory,
867 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
868 const armnn::DataLayout layout,
869 float qScale,
870 int32_t qOffset)
871{
872 // Use a single-batch 1-channel 3x3 image as input.
873 armnn::TensorInfo inputDesc({1, 1, 3, 3}, ArmnnType);
874 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100875 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100876 11,21,31,
877 12,22,32,
878 13,23,33
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100879 },
880 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100881
882 // Use 1 batch of a 1-channel 2x2 kernel.
883 armnn::TensorInfo kernelDesc({1, 1, 2, 2}, ArmnnType);
884 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100885 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100886 -11,-21,
887 -12,-22,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100888 },
889 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100890
891// Expected output is 1 batch of a 1-channel 6x8 image.
892// Manually calculated like this:
893//[-11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ..]
894//[-11*0 -21*0 -12*0 -22*11 ; -11*0 -21*0 -12*11 -22*21 ; -11*0 -21*0 -12*21 -22*31 ; -11*0 -21*0 -12*31 -22*0 ..]
895//[-11*0 -21*11 -12*0 -22*12 ; -11*11 -21*21 -12*12 -22*22 ; -11*21 -21*31 -12*22 -22*32 ; -11*31 -21*0 -12*32 -22*0 ..]
896//[-11*0 -21*12 -12*0 -22*13 ; -11*12 -21*22 -12*13 -22*23 ; -11*22 -21*32 -12*23 -22*33 ; -11*32 -21*0 -12*33 -22*0 ..]
897//[-11*0 -21*13 -12*0 -22*0 ; -11*13 -21*23 -12*0 -22*0 ; -11*23 -21*33 -12*0 -22*0 ; -11*33 -21*0 -12*0 -22*0 ..]
898//[-11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ; -11*0 -21*0 -12*0 -22*0 ..]
899//[..... ..... ..... ..... ; ..... ..... ..... ..... ; ..... ..... ..... ..... ; ..... ..... ..... ..... ..]
900 armnn::TensorInfo outputDesc({1, 1, 8, 6}, ArmnnType);
901 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100902 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100903 0, 0, 0, 0, 0, 0,
904 -242, -594, -934, -372, 0, 0,
905 -495, -1190, -1850, -725, 0, 0,
906 -538, -1256, -1916, -748, 0, 0,
907 -273, -626, -946, -363, 0, 0,
908 0, 0, 0, 0, 0, 0,
909 0, 0, 0, 0, 0, 0,
910 0, 0, 0, 0, 0, 0
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100911 },
912 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100913
914 return SimpleConvolution2dTestImpl<ArmnnType, ArmnnBType>(
915 workloadFactory,
916 memoryManager,
917 input,
918 kernel,
919 GetBias2<ArmnnBType>(false, qScale * qScale),
920 expectedOutput,
921 qScale,
922 qOffset,
923 layout,
924 1, // Padding left.
925 2, // Padding top.
926 3, // Padding right.
927 4); // Padding bottom.
928}
929
930template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
931 typename T = armnn::ResolveType<ArmnnType>>
932LayerTestResult<T, 4> SimpleConvolution2dAsymmetricPaddingTestCommon(
933 armnn::IWorkloadFactory& workloadFactory,
934 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
935 const armnn::DataLayout layout,
936 float qScale,
937 int32_t qOffset)
938{
939 // Use a single-batch 1-channel 5x5 image as input.
940 armnn::TensorInfo inputDesc({ 1, 1, 5, 5 }, ArmnnType);
941 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100942 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100943 11,21,31,41,51,
944 12,22,32,42,52,
945 13,23,33,43,53,
946 14,24,34,44,54,
947 15,25,35,45,55,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100948 }, qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100949
950 // Use 1 batch of a 1-channel 4x4 kernel.
951 armnn::TensorInfo kernelDesc({ 1, 1, 4, 4 }, ArmnnType);
952 boost::multi_array<T, 4> kernel = MakeTensor<T, 4>(kernelDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100953 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100954 -11,-21,-31,-41,
955 -12,-22,-32,-42,
956 -13,-23,-33,-43,
957 -14,-24,-34,-44,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100958 },
959 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100960
961 // Expected output is 1 batch of a 1-channel 5x5 image.
962 armnn::TensorInfo outputDesc({ 1, 1, 5, 5 }, ArmnnType);
963 std::vector<T> myVec(outputDesc.GetNumElements(), 0);
964 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputDesc, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100965 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100966 -7140, -10580, -13940, -9300, -5230,
967 -9590, -14120, -18520, -12290, -6860,
968 -9980, -14560, -18960, -12560, -7000,
969 -7518, -10904, -14144, -9318, -5152,
970 -5032, -7256, -9376, -6142, -3368,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100971 },
972 qScale, qOffset)));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100973
974 return SimpleConvolution2dTestImpl<ArmnnType, ArmnnBType>(
975 workloadFactory,
976 memoryManager,
977 input,
978 kernel,
979 GetBias2<ArmnnBType>(false, qScale * qScale),
980 expectedOutput,
981 qScale,
982 qOffset,
983 layout,
984 1, // Padding left.
985 1, // Padding top.
986 2, // Padding right.
987 2); // Padding bottom.
988}
989
990template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
991LayerTestResult<T, 4> Convolution2d3x3DilationTestCommon(
992 armnn::IWorkloadFactory& workloadFactory,
993 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
994 const std::vector<float>& inputNoQuantizedValues,
995 armnn::TensorInfo& inputTensorInfo,
996 const std::vector<float>& kernelNoQuantizedValues,
997 armnn::TensorInfo& kernelTensorInfo,
998 const std::vector<float>& outputExpectedNoQuantizedValues,
999 armnn::TensorInfo& outputTensorInfo,
1000 uint32_t dilationX,
1001 uint32_t dilationY,
1002 armnn::DataLayout layout = armnn::DataLayout::NCHW,
1003 uint32_t padLeft = 0,
1004 uint32_t padTop = 0,
1005 uint32_t padRight = 0,
1006 uint32_t padBottom = 0,
1007 uint32_t strideX = 1,
1008 uint32_t strideY = 1,
1009 bool biasEnabled = false
1010)
1011{
1012 float qScale;
1013 int32_t qOffset;
1014 switch (ArmnnType)
1015 {
1016 case armnn::DataType::QuantisedAsymm8:
1017 {
1018 qScale = 0.1f;
1019 qOffset = 128;
1020 break;
1021 }
1022 case armnn::DataType::QuantisedSymm16:
1023 {
1024 qScale = 0.1f;
1025 qOffset = 0;
1026 break;
1027 }
1028 case armnn::DataType::Float32:
1029 default:
1030 {
1031 qScale = 0.f;
1032 qOffset = 0;
1033 break;
1034 }
1035 }
1036
1037 inputTensorInfo.SetQuantizationScale(qScale);
1038 inputTensorInfo.SetQuantizationOffset(qOffset);
1039 kernelTensorInfo.SetQuantizationScale(qScale);
1040 kernelTensorInfo.SetQuantizationOffset(qOffset);
1041 outputTensorInfo.SetQuantizationScale(qScale);
1042 outputTensorInfo.SetQuantizationOffset(qOffset);
1043
1044 auto input = MakeTensor<T, 4>(inputTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001045 std::vector<T>(QuantizedVector<T>(inputNoQuantizedValues,
1046 inputTensorInfo.GetQuantizationScale(),
1047 inputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001048 auto kernel = MakeTensor<T, 4>(kernelTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001049 std::vector<T>(QuantizedVector<T>(kernelNoQuantizedValues,
1050 kernelTensorInfo.GetQuantizationScale(),
1051 kernelTensorInfo.GetQuantizationOffset())));
1052 auto expectedOutput =
1053 MakeTensor<T, 4>(outputTensorInfo,
1054 std::vector<T>(QuantizedVector<T>(outputExpectedNoQuantizedValues,
1055 outputTensorInfo.GetQuantizationScale(),
1056 outputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001057
1058 return SimpleConvolution2dTestImpl<ArmnnType, ArmnnBType>(
1059 workloadFactory,
1060 memoryManager,
1061 input,
1062 kernel,
1063 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
1064 expectedOutput,
1065 qScale,
1066 qOffset,
1067 layout,
1068 padLeft,
1069 padTop,
1070 padRight,
1071 padBottom,
1072 strideX,
1073 strideY,
1074 dilationX,
1075 dilationY);
1076}
1077
1078template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
1079LayerTestResult<T, 4> Convolution2d3x3Dilation3x3Test(
1080 armnn::IWorkloadFactory& workloadFactory,
1081 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1082 bool biasEnabled,
1083 const armnn::DataLayout layout)
1084{
1085 armnn::TensorInfo inputTensorInfo({1, 1, 10, 10}, ArmnnType);
1086 std::vector<float> inputNoQuantizedValues =
1087 {
1088 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1089 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1091 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1092 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1093 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1094 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1095 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1096 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1098 };
1099
1100 armnn::TensorInfo kernelTensorInfo({ 1, 1, 3, 3}, ArmnnType);
1101 std::vector<float> kernelNoQuantizedValues =
1102 {
1103 1, 2, 3,
1104 4, 5, 6,
1105 7, 8, 9
1106 };
1107
1108 // Since the dilation rate is 3 this will dilate the kernel to be like 7x7,
1109 // therefore the output will be 4x4: (I−K+2P)/S +1 => (10-7 +0)/1 +1
1110 armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4}, ArmnnType);
1111 std::vector<float> outputExpectedNoQuantizedValues =
1112 {
1113 6., 5., 5., 5.,
1114 6., 5., 5., 5.,
1115 6., 5., 5., 5.,
1116 3., 2., 2., 2.
1117 };
1118
1119 return Convolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
1120 workloadFactory,
1121 memoryManager,
1122 inputNoQuantizedValues,
1123 inputTensorInfo,
1124 kernelNoQuantizedValues,
1125 kernelTensorInfo,
1126 outputExpectedNoQuantizedValues,
1127 outputTensorInfo,
1128 3,
1129 3,
1130 layout,
1131 biasEnabled);
1132}
1133
1134template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
1135LayerTestResult<T, 4> Convolution2d2x3x3Dilation3x3Test(
1136 armnn::IWorkloadFactory& workloadFactory,
1137 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1138 bool biasEnabled,
1139 const armnn::DataLayout layout)
1140{
1141 armnn::TensorInfo inputTensorInfo({1, 2, 10, 10}, ArmnnType);
1142 std::vector<float> inputNoQuantizedValues =
1143 {
1144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1147 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1148 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1149 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1151 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1154
1155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1158 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1159 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1160 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1161 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1162 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1165 };
1166
1167 armnn::TensorInfo kernelTensorInfo({ 1, 2, 3, 3}, ArmnnType);
1168 std::vector<float> kernelNoQuantizedValues =
1169 {
1170 1, 2, 3,
1171 4, 5, 6,
1172 7, 8, 9,
1173
1174 1, 2, 3,
1175 4, 5, 6,
1176 7, 8, 9
1177 };
1178
1179 // Since the dilation rate is 3 this will dilate the kernel to be like 7x7,
1180 // therefore the output will be 4x4: (I−K+2P)/S +1 => (10-7 +0)/1 +1
1181 armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4}, ArmnnType);
1182 std::vector<float> outputExpectedNoQuantizedValues =
1183 {
1184 12., 10., 10., 10.,
1185 12., 10., 10., 10.,
1186 12., 10., 10., 10.,
1187 6., 4., 4., 4.
1188 };
1189
1190 return Convolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
1191 workloadFactory,
1192 memoryManager,
1193 inputNoQuantizedValues,
1194 inputTensorInfo,
1195 kernelNoQuantizedValues,
1196 kernelTensorInfo,
1197 outputExpectedNoQuantizedValues,
1198 outputTensorInfo,
1199 3,
1200 3,
1201 layout,
1202 biasEnabled);
1203}
1204
1205template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
1206LayerTestResult<T, 4> Convolution2d2x2Dilation2x2Padding2x2Stride3x3Test(
1207 armnn::IWorkloadFactory &workloadFactory,
1208 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
1209 bool biasEnabled,
1210 const armnn::DataLayout layout)
1211{
1212 armnn::TensorInfo inputTensorInfo({1, 1, 10, 10}, ArmnnType);
1213 std::vector<float> inputNoQuantizedValues =
1214 {
1215 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1216 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1217 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1218 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1219 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1220 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1221 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1222 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1223 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1224 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1225 };
1226
1227 armnn::TensorInfo kernelTensorInfo({ 1, 1, 2, 2}, ArmnnType);
1228 std::vector<float> kernelNoQuantizedValues =
1229 {
1230 1, 2,
1231 3, 4
1232 };
1233
1234 // Since the dilation rate is 2 this will dilate the kernel to be like 3x3: d(K-1)+1 --> 2 x (2-1) + 1 = 3,
1235 // therefore the output will be 4x4: (I − K + 2P)/S +1 => trunc ( (10 - 3 + 2x2 ) / 3 + 1 )
1236 // where, dilation size = d = 2; kernel size = K = 2; input size = I = 10; padding size = P = 2; stride = S = 3
1237 armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4}, ArmnnType);
1238 std::vector<float> outputExpectedNoQuantizedValues =
1239 {
1240 4, 7, 7, 3,
1241 6, 10, 10, 4,
1242 6, 10, 10, 4,
1243 2, 3, 3, 1
1244 };
1245 uint32_t padLeft = 1;
1246 uint32_t padTop = 1;
1247 uint32_t padRight = 1;
1248 uint32_t padBottom = 1;
1249
1250 return Convolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
1251 workloadFactory,
1252 memoryManager,
1253 inputNoQuantizedValues,
1254 inputTensorInfo,
1255 kernelNoQuantizedValues,
1256 kernelTensorInfo,
1257 outputExpectedNoQuantizedValues,
1258 outputTensorInfo,
1259 2,
1260 2,
1261 layout,
1262 padLeft,
1263 padTop,
1264 padRight,
1265 padBottom,
1266 3,
1267 3,
1268 biasEnabled
1269 );
1270}
1271
1272template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1273LayerTestResult<T,4> CompareConvolution2dTestImpl(
1274 armnn::IWorkloadFactory& workloadFactory,
1275 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1276 armnn::IWorkloadFactory& refWorkloadFactory)
1277{
1278 unsigned int inputHeight = 8;
1279 unsigned int inputWidth = 16;
1280 unsigned int inputChannels = 3;
1281 unsigned int inputNum = 5;
1282
1283 unsigned int kernelHeight = 3;
1284 unsigned int kernelWidth = 3;
1285
1286 unsigned int strideX = 2;
1287 unsigned int strideY = 3;
1288 unsigned int padX = 1;
1289 unsigned int padY = 1;
1290
1291 unsigned int outputNum = inputNum;
1292 unsigned int outputChannels = 2;
1293 unsigned int outputHeight = (inputHeight + 2 * padY - kernelHeight + strideY) / strideY;
1294 unsigned int outputWidth = (inputWidth + 2 * padX - kernelWidth + strideX) / strideX;
1295
1296 armnn::TensorInfo inputTensorInfo;
1297 armnn::TensorInfo outputTensorInfo;
1298 armnn::TensorInfo kernelDesc;
1299 armnn::TensorInfo biasDesc;
1300
1301 unsigned int inputShape[] = {inputNum, inputChannels, inputHeight, inputWidth};
1302 unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
1303 unsigned int kernelShape[] = {outputChannels, inputChannels, kernelHeight, kernelWidth};
1304 unsigned int biasShape[] = {outputChannels};
1305
1306 inputTensorInfo = armnn::TensorInfo(4, inputShape, ArmnnType);
1307 outputTensorInfo = armnn::TensorInfo(4, outputShape, ArmnnType);
1308 kernelDesc = armnn::TensorInfo(4, kernelShape, ArmnnType);
1309 biasDesc = armnn::TensorInfo(1, biasShape, ArmnnType);
1310
1311 LayerTestResult<T,4> ret(outputTensorInfo);
1312
1313 auto input = MakeRandomTensor<T, 4>(inputTensorInfo, 124908);
1314 auto kernel = MakeRandomTensor<T, 4>(kernelDesc, 891234);
1315 auto bias = MakeRandomTensor<T, 1>(biasDesc, 1028);
1316
1317 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1318 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1319
1320 armnn::Convolution2dQueueDescriptor data;
1321 armnn::WorkloadInfo info;
1322 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1323 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1324
1325 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1326 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1327
1328 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1329 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1330 data.m_Weight = &weightsTensor;
1331 data.m_Bias = &biasTensor;
1332 data.m_Parameters.m_StrideX = strideX;
1333 data.m_Parameters.m_StrideY = strideY;
1334 data.m_Parameters.m_PadLeft = padX;
1335 data.m_Parameters.m_PadRight = padX;
1336 data.m_Parameters.m_PadTop = padY;
1337 data.m_Parameters.m_PadBottom = padY;
1338 data.m_Parameters.m_BiasEnabled = true;
1339
1340 std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refWorkloadFactory.CreateTensorHandle(outputTensorInfo);
1341 std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refWorkloadFactory.CreateTensorHandle(inputTensorInfo);
1342
1343 armnn::Convolution2dQueueDescriptor refData = data;
1344 armnn::WorkloadInfo refInfo = info;
1345 SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
1346 SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
1347
1348 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
1349 std::unique_ptr<armnn::IWorkload> workloadRef = refWorkloadFactory.CreateConvolution2d(refData, refInfo);
1350
1351 outputHandleRef->Allocate();
1352 inputHandleRef->Allocate();
1353
1354 inputHandle->Allocate();
1355 outputHandle->Allocate();
1356
1357 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
1358 CopyDataToITensorHandle(inputHandleRef.get(), &input[0][0][0][0]);
1359
1360 ExecuteWorkload(*workload, memoryManager);
1361
1362 workloadRef->PostAllocationConfigure();
1363 workloadRef->Execute();
1364
1365 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1366 CopyDataFromITensorHandle(&ret.outputExpected[0][0][0][0], outputHandleRef.get());
1367
1368 return ret;
1369}
1370
1371//
1372// DepthwiseConvolution2d implementations
1373//
1374
1375template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
1376 typename T = armnn::ResolveType<ArmnnType>, typename B = armnn::ResolveType<ArmnnBType>>
1377LayerTestResult<T, 4> DepthwiseConvolution2dAsymmetricTestImpl(
1378 armnn::IWorkloadFactory& workloadFactory,
1379 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1380 const boost::multi_array<T, 4>& input,
1381 const boost::multi_array<T, 4>& kernel,
1382 const boost::multi_array<B, 1>& bias,
1383 const boost::multi_array<T, 4>& outputExpected,
1384 float qScale,
1385 int32_t qOffset,
1386 const armnn::DataLayout layout,
1387 uint32_t padLeft = 0,
1388 uint32_t padTop = 0,
1389 uint32_t padRight = 0,
1390 uint32_t padBottom = 0,
1391 uint32_t strideX = 1,
1392 uint32_t strideY = 1)
1393{
1394 unsigned int inputNum = boost::numeric_cast<unsigned int>(input.shape()[0]);
1395 unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[1]);
1396 unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[2]);
1397 unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[3]);
1398 unsigned int kernelChanMul = boost::numeric_cast<unsigned int>(kernel.shape()[0]);
1399 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(kernel.shape()[1]);
1400 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(kernel.shape()[2]);
1401 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(kernel.shape()[3]);
1402 unsigned int outputNum = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
1403 unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]);
1404 unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]);
1405 unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]);
1406
1407 // If a bias is used, its size must equal the number of output channels.
1408 bool biasEnabled = bias.size() > 0;
1409 BOOST_ASSERT(!biasEnabled || bias.size() == outputChannels);
1410
1411 // Creates the tensors.
1412 armnn::TensorInfo inputTensorInfo =
1413 armnnUtils::GetTensorInfo(inputNum, inputChannels, inputHeight, inputWidth, layout, ArmnnType);
1414 armnn::TensorInfo outputTensorInfo =
1415 armnnUtils::GetTensorInfo(outputNum, outputChannels, outputHeight, outputWidth, layout, ArmnnType);
1416 armnn::TensorInfo kernelDesc({kernelChanMul, kernelChannels, kernelHeight, kernelWidth}, ArmnnType);
1417 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, ArmnnBType);
1418
1419 // Set quantization parameters if the requested type is a quantized type.
1420 if (armnn::IsQuantizedType<T>())
1421 {
1422 inputTensorInfo.SetQuantizationScale(qScale);
1423 inputTensorInfo.SetQuantizationOffset(qOffset);
1424 outputTensorInfo.SetQuantizationScale(qScale);
1425 outputTensorInfo.SetQuantizationOffset(qOffset);
1426 kernelDesc.SetQuantizationScale(qScale);
1427 kernelDesc.SetQuantizationOffset(qOffset);
1428 biasDesc.SetQuantizationScale(qScale*qScale);
1429 biasDesc.SetQuantizationOffset(0);
1430 }
1431
1432 // Construct the input data.
1433 std::vector<T> inputData;
1434 inputData.assign(input.data(), input.data() + inputChannels*inputHeight*inputWidth);
1435
1436 // At this point if we require it permute the input data
1437 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
1438 if (layout == armnn::DataLayout::NHWC)
1439 {
1440 std::vector<T> tmp(inputData.size());
1441 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data(), sizeof(T));
1442 inputData = tmp;
1443 }
1444
1445 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
1446
1447 // Construct the output data, with bias applied, as appropriate.
1448 std::vector<T> outputData;
1449 outputData.assign(outputExpected.data(), outputExpected.data() + outputChannels*outputHeight*outputWidth);
1450 if (biasEnabled)
1451 {
1452 std::vector<T> biasV;
1453 biasV.assign(bias.data(), bias.data() + outputChannels);
1454 ApplyBias(outputData, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
1455 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
1456 outputWidth, outputHeight);
1457 }
1458
1459 LayerTestResult<T, 4> ret(outputTensorInfo);
1460
1461 // At this point if we require it permute the expected output
1462 if (layout == armnn::DataLayout::NHWC)
1463 {
1464 std::vector<T> tmp(outputData.size());
1465 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data(), sizeof(T));
1466 outputData = tmp;
1467 }
1468
1469 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
1470
1471 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1472 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1473
1474 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1475
1476 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1477
1478 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1479 if (biasEnabled)
1480 {
1481 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1482 }
1483
1484 armnn::DepthwiseConvolution2dQueueDescriptor data;
1485 data.m_Weight = &weightsTensor;
1486 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - it can be a source of bugs.
1487 data.m_Parameters.m_StrideX = strideX;
1488 data.m_Parameters.m_StrideY = strideY;
1489 data.m_Parameters.m_PadLeft = padLeft;
1490 data.m_Parameters.m_PadRight = padRight;
1491 data.m_Parameters.m_PadTop = padTop;
1492 data.m_Parameters.m_PadBottom = padBottom;
1493 data.m_Parameters.m_BiasEnabled = biasEnabled;
1494 data.m_Parameters.m_DataLayout = layout;
1495
1496 armnn::WorkloadInfo info;
1497 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1498 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1499
1500 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
1501 inputHandle->Allocate();
1502 outputHandle->Allocate();
1503
1504 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
1505
1506 ExecuteWorkload(*workload, memoryManager);
1507
1508 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1509
1510 return ret;
1511}
1512
1513template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
1514LayerTestResult<T, 4> DepthwiseConvolution2dDepthMul1TestImpl(
1515 armnn::IWorkloadFactory& workloadFactory,
1516 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1517 float qScale,
1518 int32_t qOffset,
1519 bool biasEnabled,
1520 const armnn::DataLayout layout)
1521{
1522 using B = armnn::ResolveType<ArmnnBType>;
1523
1524 unsigned int inputHeight = 3;
1525 unsigned int inputWidth = 3;
1526 unsigned int inputChannels = 2;
1527 unsigned int inputNum = 1;
1528
1529 unsigned int kernelHeight = 3;
1530 unsigned int kernelWidth = 3;
1531 unsigned int kernelChannels = inputChannels;
1532 unsigned int kernelDepthMultiplier = 1;
1533
1534 unsigned int outputHeight = 1;
1535 unsigned int outputWidth = 1;
1536 unsigned int outputChannels = kernelChannels;
1537 unsigned int outputNum = inputNum;
1538
1539 armnn::TensorInfo inputTensorInfo =
1540 armnnUtils::GetTensorInfo(inputNum, inputChannels, inputHeight, inputWidth, layout, ArmnnType);
1541 armnn::TensorInfo outputTensorInfo =
1542 armnnUtils::GetTensorInfo(outputNum, outputChannels, outputHeight, outputWidth, layout, ArmnnType);
1543 armnn::TensorInfo kernelDesc({kernelDepthMultiplier, kernelChannels, kernelHeight, kernelWidth},
1544 ArmnnType);
1545 armnn::TensorInfo biasDesc({ outputChannels }, ArmnnBType);
1546
1547 // Set quantization parameters if the requested type is a quantized type.
1548 if(armnn::IsQuantizedType<T>())
1549 {
1550 inputTensorInfo.SetQuantizationScale(qScale);
1551 inputTensorInfo.SetQuantizationOffset(qOffset);
1552 outputTensorInfo.SetQuantizationScale(qScale);
1553 outputTensorInfo.SetQuantizationOffset(qOffset);
1554 kernelDesc.SetQuantizationScale(qScale);
1555 kernelDesc.SetQuantizationOffset(qOffset);
1556 biasDesc.SetQuantizationScale(qScale*qScale);
1557 biasDesc.SetQuantizationOffset(0);
1558 }
1559 std::vector<T> inputData = std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001560 QuantizedVector<T>({
1561 1.f, 2.f, 1.f,
1562 2.f, 1.f, 2.f,
1563 1.f, 2.f, 1.f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001564
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001565 1.f, 2.f, 1.f,
1566 2.f, 1.f, 2.f,
1567 1.f, 2.f, 1.f,
1568 },
1569 inputTensorInfo.GetQuantizationScale(),
1570 inputTensorInfo.GetQuantizationOffset()));
1571
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001572 // at this point if we require it permute the input data
1573 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
1574 if (layout == armnn::DataLayout::NHWC)
1575 {
1576 std::vector<T> tmp(inputData.size());
1577 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data(), sizeof(T));
1578 inputData = tmp;
1579 }
1580 auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
1581
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001582 std::vector<B> biasV(QuantizedVector<B>({ 0, 2 },
1583 biasDesc.GetQuantizationScale(),
1584 biasDesc.GetQuantizationOffset()));
1585
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001586 auto bias = MakeTensor<B, 1>(biasDesc, biasV);
1587
1588 std::vector<T> kernelData = std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001589 QuantizedVector<T>({
1590 1.f, 0.f, 1.f,
1591 0.f, 0.f, 0.f,
1592 -1.f, 0.f, -1.f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001593
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001594 1.f, 0.f, 1.f,
1595 0.f, 0.f, 0.f,
1596 -1.f, 0.f, -1.f,
1597 },
1598 kernelDesc.GetQuantizationScale(),
1599 kernelDesc.GetQuantizationOffset()));
1600
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001601 auto kernel = MakeTensor<T, 4>(kernelDesc, kernelData);
1602
1603 // Manually calculated.
1604 std::vector<T> outputImage(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001605 QuantizedVector<T>({ 0.f, 0.f },
1606 outputTensorInfo.GetQuantizationScale(),
1607 outputTensorInfo.GetQuantizationOffset())
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001608 );
1609
1610 // Optionally apply bias to output image.
1611 if(biasEnabled)
1612 {
1613 ApplyBias(outputImage, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
1614 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
1615 outputWidth, outputHeight);
1616 }
1617
1618 LayerTestResult<T, 4> ret(outputTensorInfo);
1619 if (layout == armnn::DataLayout::NHWC)
1620 {
1621 std::vector<T> tmp(outputImage.size());
1622 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputImage.data(), tmp.data(), sizeof(T));
1623 outputImage = tmp;
1624 }
1625
1626 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputImage);
1627
1628 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1629 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1630
1631 armnn::DepthwiseConvolution2dQueueDescriptor data;
1632 armnn::WorkloadInfo info;
1633 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1634 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1635
1636 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1637 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1638
1639 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1640 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1641
1642 data.m_Weight = &weightsTensor;
1643 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled.
1644 data.m_Parameters.m_StrideX = 1;
1645 data.m_Parameters.m_StrideY = 1;
1646 data.m_Parameters.m_PadLeft = 0;
1647 data.m_Parameters.m_PadRight = 0;
1648 data.m_Parameters.m_PadTop = 0;
1649 data.m_Parameters.m_PadBottom = 0;
1650 data.m_Parameters.m_BiasEnabled = biasEnabled;
1651 data.m_Parameters.m_DataLayout = layout;
1652
1653 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
1654 inputHandle->Allocate();
1655 outputHandle->Allocate();
1656
1657 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
1658
1659 ExecuteWorkload(*workload, memoryManager);
1660
1661 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1662
1663 return ret;
1664}
1665
1666template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
1667LayerTestResult<T, 4> DepthwiseConvolution2dTestImpl(
1668 armnn::IWorkloadFactory& workloadFactory,
1669 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1670 float qScale,
1671 int32_t qOffset,
1672 bool biasEnabled,
1673 const armnn::DataLayout layout)
1674{
1675 using B = armnn::ResolveType<ArmnnBType>;
1676
1677 unsigned int depthMultiplier = 2;
1678
1679 unsigned int inputHeight = 8;
1680 unsigned int inputWidth = 16;
1681 unsigned int inputChannels = 2;
1682 unsigned int inputBatchSize = 1;
1683
1684 unsigned int kernelHeight = 5;
1685 unsigned int kernelWidth = 3;
1686
1687 unsigned int outputHeight = inputHeight - kernelHeight + 1 + 2;
1688 unsigned int outputWidth = (inputWidth - kernelWidth + 1)/2;
1689 unsigned int outputChannels = inputChannels * depthMultiplier;
1690 unsigned int outputBatchSize = inputBatchSize;
1691
1692 armnn::TensorInfo inputTensorInfo = armnnUtils::GetTensorInfo(
1693 inputBatchSize, inputChannels, inputHeight, inputWidth, layout, ArmnnType);
1694 armnn::TensorInfo outputTensorInfo = armnnUtils::GetTensorInfo(
1695 outputBatchSize, outputChannels, outputHeight, outputWidth, layout, ArmnnType);
1696 armnn::TensorInfo kernelDesc({depthMultiplier, inputChannels, kernelHeight, kernelWidth},
1697 ArmnnType);
1698 armnn::TensorInfo biasDesc({outputChannels}, ArmnnBType);
1699
1700 // Set quantization parameters if the requested type is a quantized type.
1701 if(armnn::IsQuantizedType<T>())
1702 {
1703 inputTensorInfo.SetQuantizationScale(qScale);
1704 inputTensorInfo.SetQuantizationOffset(qOffset);
1705 outputTensorInfo.SetQuantizationScale(qScale);
1706 outputTensorInfo.SetQuantizationOffset(qOffset);
1707 kernelDesc.SetQuantizationScale(qScale);
1708 kernelDesc.SetQuantizationOffset(qOffset);
1709 biasDesc.SetQuantizationScale(qScale*qScale);
1710 biasDesc.SetQuantizationOffset(0);
1711 }
1712
1713 // NOTE: originalInputData is in NCHW format
1714 std::vector<T> originalInputData = std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001715 QuantizedVector<T>({
1716 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1717 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1718 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1719 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1720 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1721 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1722 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1723 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
1724 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1725 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1726 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1727 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1728 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1729 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1730 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1731 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
1732 },
1733 inputTensorInfo.GetQuantizationScale(),
1734 inputTensorInfo.GetQuantizationOffset()));
1735
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001736 std::vector<T> inputData = originalInputData;
1737 // at this point if we require it permute the input data
1738 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
1739 if (layout == armnn::DataLayout::NHWC)
1740 {
1741 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC,
1742 originalInputData.data(), inputData.data(), sizeof(T));
1743 }
1744 auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
1745
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001746 std::vector<B> biasV = QuantizedVector<B>({ 0, 2, 1, -1 },
1747 biasDesc.GetQuantizationScale(),
1748 biasDesc.GetQuantizationOffset());
1749
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001750 auto bias = MakeTensor<B, 1>(biasDesc, biasV);
1751
1752 std::vector<T> kernelData = std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001753 QuantizedVector<T>({
1754 1, 1, 1,
1755 1, -1, 1,
1756 1, 1, 1,
1757 1, 1, 1,
1758 1, 1, 1,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001759
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001760 2, 2, 2,
1761 2, 2, 2,
1762 2, 2, 2,
1763 2, 2, 2,
1764 2, 2, 2,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001765
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001766 0, 0, 0,
1767 0, -1, 0,
1768 0, 0, 0,
1769 0, 0, 0,
1770 0, 0, 0,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001771
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001772 0, 0, 0,
1773 0, 0, 0,
1774 0, 1, 0,
1775 0, 0, 0,
1776 0, 0, 0
1777 },
1778 kernelDesc.GetQuantizationScale(),
1779 kernelDesc.GetQuantizationOffset()));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001780
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001781 auto kernel = MakeTensor<T, 4>(kernelDesc, kernelData);
1782
1783 // Manually calculated.
1784 std::vector<T> originalOutputImage = std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001785 QuantizedVector<T>({
1786 3.5f, 3.5f, 3.5f, 3.5f, 3.5f, 3.5f, 3.5f,
1787 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f,
1788 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,
1789 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f,
1790 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f,
1791 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001792
1793 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001794 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001795 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
1796 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
1797 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
1798 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
1799
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001800 8.0f, 8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001801 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1802 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1803 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1804 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001805 8.0f, 8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001806
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01001807 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1808 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1809 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1810 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1811 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1812 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
1813 },
1814 outputTensorInfo.GetQuantizationScale(),
1815 outputTensorInfo.GetQuantizationOffset()));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001816
1817 // Optionally apply bias to output image.
1818 if(biasEnabled)
1819 {
1820 ApplyBias(originalOutputImage,
1821 outputTensorInfo.GetQuantizationScale(),
1822 outputTensorInfo.GetQuantizationOffset(),
1823 biasV,
1824 biasDesc.GetQuantizationScale(),
1825 biasDesc.GetQuantizationOffset(),
1826 outputWidth,
1827 outputHeight);
1828 }
1829
1830 LayerTestResult<T, 4> ret(outputTensorInfo);
1831 std::vector<T> outputImage = originalOutputImage;
1832 if (layout == armnn::DataLayout::NHWC)
1833 {
1834 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC,
1835 originalOutputImage.data(), outputImage.data(), sizeof(T));
1836 }
1837
1838 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputImage);
1839
1840 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1841 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1842
1843 armnn::DepthwiseConvolution2dQueueDescriptor data;
1844 armnn::WorkloadInfo info;
1845 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1846 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1847
1848 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1849 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1850
1851 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1852 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1853
1854 data.m_Weight = &weightsTensor;
1855 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled.
1856 data.m_Parameters.m_StrideX = 2;
1857 data.m_Parameters.m_StrideY = 1;
1858 data.m_Parameters.m_PadLeft = 0;
1859 data.m_Parameters.m_PadRight = 0;
1860 data.m_Parameters.m_PadTop = 1;
1861 data.m_Parameters.m_PadBottom = 1;
1862 data.m_Parameters.m_BiasEnabled = biasEnabled;
1863 data.m_Parameters.m_DataLayout = layout;
1864
1865 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
1866 inputHandle->Allocate();
1867 outputHandle->Allocate();
1868
1869 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
1870
1871 ExecuteWorkload(*workload, memoryManager);
1872
1873 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1874
1875 return ret;
1876}
1877
1878template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
1879 typename T = armnn::ResolveType<ArmnnType>, typename B = armnn::ResolveType<ArmnnBType>>
1880LayerTestResult<T, 4> DepthwiseConvolution2dTestImpl(
1881 armnn::IWorkloadFactory& workloadFactory,
1882 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1883 const boost::multi_array<T, 4>& originalInput,
1884 const boost::multi_array<T, 4>& originalKernel,
1885 const boost::multi_array<B, 1>& bias,
1886 const boost::multi_array<T, 4>& originalOutputExpected,
1887 float qScale,
1888 int32_t qOffset,
1889 const armnn::DataLayout layout = armnn::DataLayout::NCHW,
1890 uint32_t padLeft = 0,
1891 uint32_t padTop = 0,
1892 uint32_t padRight = 0,
1893 uint32_t padBottom = 0,
1894 uint32_t strideX = 1,
1895 uint32_t strideY = 1,
1896 uint32_t dilationX = 1,
1897 uint32_t dilationY = 1)
1898{
1899 unsigned int inputHeight = boost::numeric_cast<unsigned int>(originalInput.shape()[2]);
1900 unsigned int inputWidth = boost::numeric_cast<unsigned int>(originalInput.shape()[3]);
1901 unsigned int inputChannels = boost::numeric_cast<unsigned int>(originalInput.shape()[1]);
1902 unsigned int inputNum = boost::numeric_cast<unsigned int>(originalInput.shape()[0]);
1903
1904 unsigned int outputHeight = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[2]);
1905 unsigned int outputWidth = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[3]);
1906 unsigned int outputChannels = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[1]);
1907 unsigned int outputNum = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[0]);
1908
1909 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(originalKernel.shape()[2]);
1910 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(originalKernel.shape()[3]);
1911 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(originalKernel.shape()[1]);
1912 unsigned int kernelDepthMul = boost::numeric_cast<unsigned int>(originalKernel.shape()[0]);
1913
1914 bool biasEnabled = bias.size() > 0;
1915
1916 // This function currently assumes 1 batch of input/output (and duplicates this into 2 batches).
1917 BOOST_ASSERT(inputNum == 1);
1918 BOOST_ASSERT(outputNum == 1);
1919
1920 // If a bias is used, its size must equal the number of output channels.
1921 BOOST_ASSERT(!biasEnabled || bias.size() == outputChannels);
1922
1923
1924 // Note these tensors will use two (identical) batches.
1925 armnn::TensorInfo inputTensorInfo =
1926 armnnUtils::GetTensorInfo(2*inputNum, inputChannels, inputHeight, inputWidth, layout, ArmnnType);
1927 armnn::TensorInfo outputTensorInfo =
1928 armnnUtils::GetTensorInfo(2*outputNum, outputChannels, outputHeight, outputWidth, layout, ArmnnType);
1929
1930 // Kernel must be NCHW layout always, independently of the layout of the input and output for depthwise convolution.
1931 armnn::TensorInfo kernelDesc({kernelDepthMul, kernelChannels, kernelHeight, kernelWidth}, ArmnnType);
1932
1933 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, ArmnnBType);
1934
1935 // Set quantization parameters if the requested type is a quantized type.
1936 if(armnn::IsQuantizedType<T>())
1937 {
1938 inputTensorInfo.SetQuantizationScale(qScale);
1939 inputTensorInfo.SetQuantizationOffset(qOffset);
1940 outputTensorInfo.SetQuantizationScale(qScale);
1941 outputTensorInfo.SetQuantizationOffset(qOffset);
1942 kernelDesc.SetQuantizationScale(qScale);
1943 kernelDesc.SetQuantizationOffset(qOffset);
1944 biasDesc.SetQuantizationScale(qScale*qScale);
1945 biasDesc.SetQuantizationOffset(0);
1946 }
1947
1948 LayerTestResult<T, 4> ret(outputTensorInfo);
1949
1950 // Construct input data
1951 std::vector<T> input;
1952 input.assign(originalInput.data(), originalInput.data() + 1*inputChannels*inputHeight*inputWidth);
1953 std::vector<T> inputData;
1954 inputData.insert(inputData.end(), input.begin(), input.end());
1955 inputData.insert(inputData.end(), input.begin(), input.end());
1956
1957 // at this point if we require it permute the input data
1958 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
1959 if (layout == armnn::DataLayout::NHWC)
1960 {
1961 std::vector<T> tmp(inputData.size());
1962 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data(), sizeof(T));
1963 inputData = tmp;
1964 }
1965
1966 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
1967
1968 std::vector<T> output;
1969 output.assign(originalOutputExpected.data(),
1970 originalOutputExpected.data() + outputChannels*outputHeight*outputWidth);
1971
1972 // Apply bias to output data if it is enabled.
1973 if(biasEnabled)
1974 {
1975 std::vector<T> biasV;
1976 biasV.assign(bias.data(), bias.data() + outputChannels);
1977 ApplyBias(output, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
1978 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
1979 outputWidth, outputHeight);
1980 }
1981
1982 // Construct expected output data
1983 std::vector<T> outputData;
1984 outputData.insert(outputData.end(), output.begin(), output.end());
1985 outputData.insert(outputData.end(), output.begin(), output.end());
1986
1987 // at this point if we require it permute the expected output
1988 if (layout == armnn::DataLayout::NHWC)
1989 {
1990 std::vector<T> tmp(outputData.size());
1991 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data(), sizeof(T));
1992 outputData = tmp;
1993 }
1994 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
1995
1996 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1997 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1998
1999 armnn::DepthwiseConvolution2dQueueDescriptor data;
2000 armnn::WorkloadInfo info;
2001 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
2002 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
2003
2004 boost::multi_array<T, 4> kernel = boost::multi_array<T, 4>(originalKernel);
2005 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
2006
2007 if(biasEnabled)
2008 {
2009 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
2010 }
2011
2012 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
2013 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2014
2015 data.m_Weight = &weightsTensor;
2016 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
2017 data.m_Parameters.m_StrideX = strideX;
2018 data.m_Parameters.m_StrideY = strideY;
2019 data.m_Parameters.m_PadLeft = padLeft;
2020 data.m_Parameters.m_PadRight = padRight;
2021 data.m_Parameters.m_PadTop = padTop;
2022 data.m_Parameters.m_PadBottom = padBottom;
2023 data.m_Parameters.m_BiasEnabled = biasEnabled;
2024 data.m_Parameters.m_DataLayout = layout;
2025 data.m_Parameters.m_DilationX = dilationX;
2026 data.m_Parameters.m_DilationY = dilationY;
2027
2028 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
2029 inputHandle->Allocate();
2030 outputHandle->Allocate();
2031
2032 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
2033
2034 ExecuteWorkload(*workload, memoryManager);
2035
2036 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
2037
2038 return ret;
2039}
2040
2041template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
2042 typename T = armnn::ResolveType<ArmnnType>>
2043LayerTestResult<T, 4> DepthwiseConvolution2dAsymmetricTestCommon(
2044 armnn::IWorkloadFactory& workloadFactory,
2045 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2046 float qScale,
2047 int32_t qOffset,
2048 bool biasEnabled,
2049 const armnn::DataLayout layout)
2050{
2051 // Use a single-batch 2-channel 5x5 image as input.
2052 armnn::TensorInfo inputTensorInfo({ 1, 2, 5, 5 }, ArmnnType);
2053 auto input = MakeTensor<T, 4>(inputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002054 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002055 0, 1, 2, 3, 4,
2056 5, 6, 7, 8, 9,
2057 10, 11, 12, 13, 14,
2058 15, 16, 17, 18, 19,
2059 20, 21, 22, 23, 24,
2060
2061 25, 26, 27, 28, 29,
2062 30, 31, 32, 33, 34,
2063 35, 36, 37, 38, 39,
2064 40, 41, 42, 43, 44,
2065 45, 46, 47, 48, 49
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002066 },
2067 inputTensorInfo.GetQuantizationScale(),
2068 inputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002069
2070 // Use a depth multiplier of 1 on a 2-channel 4x4 kernel.
2071 armnn::TensorInfo kernelTensorInfo({ 1, 2, 4, 4 }, ArmnnType);
2072 auto kernel = MakeTensor<T, 4>(kernelTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002073 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002074 32, 31, 30, 29,
2075 28, 27, 26, 25,
2076 24, 23, 22, 21,
2077 20, 19, 18, 17,
2078
2079 16, 15, 14, 13,
2080 12, 11, 10, 9,
2081 8, 7, 6, 5,
2082 4, 3, 2, 1
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002083 },
2084 kernelTensorInfo.GetQuantizationScale(),
2085 kernelTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002086
2087 // Expected output is 1 batch of a 2-channel 5x5 image.
2088 // Calculated using the python tensorflow library with strideX=1, strideY=1.
2089 armnn::TensorInfo outputTensorInfo({ 1, 2, 5, 5 }, ArmnnType);
2090 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002091 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002092 1062, 1580, 1850, 1530, 1117,
2093 2140, 3108, 3500, 2842, 2042,
2094 3580, 5068, 5460, 4342, 3062,
2095 3618, 5072, 5390, 4248, 2971,
2096 3074, 4282, 4510, 3533, 2457,
2097
2098 1550, 2284, 2362, 1955, 1428,
2099 2910, 4206, 4342, 3528, 2536,
2100 3390, 4886, 5022, 4068, 2916,
2101 3566, 5056, 5182, 4133, 2922,
2102 3100, 4352, 4452, 3517, 2465
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002103 },
2104 outputTensorInfo.GetQuantizationScale(),
2105 outputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002106
2107 return DepthwiseConvolution2dAsymmetricTestImpl<ArmnnType, ArmnnBType>(
2108 workloadFactory,
2109 memoryManager,
2110 input,
2111 kernel,
2112 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
2113 expectedOutput,
2114 qScale,
2115 qOffset,
2116 layout,
2117 1, // Padding left.
2118 1, // Padding top.
2119 2, // Padding right.
2120 2, // Padding bottom.
2121 1, // strideX
2122 1); // strideY
2123}
2124
2125template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
2126 typename T = armnn::ResolveType<ArmnnType>>
2127LayerTestResult<T, 4> DepthwiseConvolution2dNhwcTestCommon(
2128 armnn::IWorkloadFactory& workloadFactory,
2129 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2130 float qScale,
2131 int32_t qOffset,
2132 bool biasEnabled)
2133{
2134 auto layout = armnn::DataLayout::NHWC;
2135
2136 armnn::TensorInfo inputTensorInfo({ 1, 2, 5, 5}, ArmnnType);
2137 auto input = MakeTensor<T, 4>(inputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002138 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002139 0, 1, 2, 3, 4,
2140 5, 6, 7, 8, 9,
2141 10, 11, 12, 13, 14,
2142 15, 16, 17, 18, 19,
2143 20, 21, 22, 23, 24,
2144
2145 25, 26, 27, 28, 29,
2146 30, 31, 32, 33, 34,
2147 35, 36, 37, 38, 39,
2148 40, 41, 42, 43, 44,
2149 45, 46, 47, 48, 49
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002150 },
2151 inputTensorInfo.GetQuantizationScale(),
2152 inputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002153
2154 armnn::TensorInfo kernelTensorInfo({ 1, 2, 4, 4 }, ArmnnType);
2155 auto kernel = MakeTensor<T, 4>(kernelTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002156 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002157 32, 31, 30, 29,
2158 28, 27, 26, 25,
2159 24, 23, 22, 21,
2160 20, 19, 18, 17,
2161
2162 16, 15, 14, 13,
2163 12, 11, 10, 9,
2164 8, 7, 6, 5,
2165 4, 3, 2, 1
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002166 },
2167 kernelTensorInfo.GetQuantizationScale(),
2168 kernelTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002169
2170 armnn::TensorInfo outputTensorInfo({ 1, 2, 5, 5}, ArmnnType);
2171 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002172 QuantizedVector<T>({
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002173 1062, 1580, 1850, 1530, 1117,
2174 2140, 3108, 3500, 2842, 2042,
2175 3580, 5068, 5460, 4342, 3062,
2176 3618, 5072, 5390, 4248, 2971,
2177 3074, 4282, 4510, 3533, 2457,
2178
2179 1550, 2284, 2362, 1955, 1428,
2180 2910, 4206, 4342, 3528, 2536,
2181 3390, 4886, 5022, 4068, 2916,
2182 3566, 5056, 5182, 4133, 2922,
2183 3100, 4352, 4452, 3517, 2465
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002184 },
2185 outputTensorInfo.GetQuantizationScale(),
2186 outputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002187
2188 return DepthwiseConvolution2dTestImpl<ArmnnType, ArmnnBType>(
2189 workloadFactory,
2190 memoryManager,
2191 input,
2192 kernel,
2193 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
2194 expectedOutput,
2195 qScale,
2196 qOffset,
2197 layout,
2198 1, // Padding left.
2199 1, // Padding top.
2200 2, // Padding right.
2201 2, // Padding bottom.
2202 1, // strideX
2203 1); // strideY
2204}
2205
2206template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType,
2207 typename T = armnn::ResolveType<ArmnnType>>
2208LayerTestResult<T, 4> SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTestCommon(
2209 armnn::IWorkloadFactory& workloadFactory,
2210 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2211 float qScale,
2212 int32_t qOffset,
2213 bool biasEnabled)
2214{
2215 auto layout = armnn::DataLayout::NHWC;
2216
2217 armnn::TensorInfo inputTensorInfo({ 1, 1, 9, 9}, ArmnnType);
2218 auto input = MakeTensor<T, 4>(inputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002219 QuantizedVector<T>({
2220 0, 0, 0, 0, 0, 0, 0, 0, 0,
2221 0, 0, 0, 0, 0, 0, 0, 0, 0,
2222 0, 0, 0, 0, 0, 0, 0, 0, 0,
2223 0, 0, 0, 1, 1, 1, 0, 0, 0,
2224 0, 0, 0, 1, 1, 1, 0, 0, 0,
2225 0, 0, 0, 1, 1, 1, 0, 0, 0,
2226 0, 0, 0, 0, 0, 0, 0, 0, 0,
2227 0, 0, 0, 0, 0, 0, 0, 0, 0,
2228 0, 0, 0, 0, 0, 0, 0, 0, 0
2229 },
2230 inputTensorInfo.GetQuantizationScale(),
2231 inputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002232
2233 armnn::TensorInfo kernelTensorInfo({ 1, 1, 3, 3}, ArmnnType);
2234 auto kernel = MakeTensor<T, 4>(kernelTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002235 QuantizedVector<T>({
2236 1, 2, 3,
2237 4, 5, 6,
2238 7, 8, 9
2239 },
2240 kernelTensorInfo.GetQuantizationScale(),
2241 kernelTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002242
2243 uint32_t padLeft = 0;
2244 uint32_t padTop = 0;
2245 uint32_t padRight = 0;
2246 uint32_t padBottom = 0;
2247 uint32_t strideX = 1;
2248 uint32_t strideY = 1;
2249 uint32_t dilationX = 3;
2250 uint32_t dilationY = 3;
2251
2252 // Since the dilation rate is 3 this will reduce the size of the output from 9x9 to 3x3 of all 5s.
2253 armnn::TensorInfo outputTensorInfo({ 1, 1, 3, 3}, ArmnnType);
2254 boost::multi_array<T, 4> expectedOutput = MakeTensor<T, 4>(outputTensorInfo, std::vector<T>(
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002255 QuantizedVector<T>({
2256 5, 5, 5,
2257 5, 5, 5,
2258 5, 5, 5
2259 },
2260 outputTensorInfo.GetQuantizationScale(),
2261 outputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002262
2263 return DepthwiseConvolution2dTestImpl<ArmnnType, ArmnnBType>(
2264 workloadFactory,
2265 memoryManager,
2266 input,
2267 kernel,
2268 GetBias2<ArmnnBType>(biasEnabled, qScale * qScale),
2269 expectedOutput,
2270 qScale,
2271 qOffset,
2272 layout,
2273 padLeft,
2274 padTop,
2275 padRight,
2276 padBottom,
2277 strideX,
2278 strideY,
2279 dilationX,
2280 dilationY);
2281}
2282
2283template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T = armnn::ResolveType<ArmnnType>>
2284LayerTestResult<T, 4> DepthwiseConvolution2d3x3DilationTestCommon(
2285 armnn::IWorkloadFactory& workloadFactory,
2286 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2287 const std::vector<float>& inputNoQuantizedValues,
2288 armnn::TensorInfo& inputTensorInfo,
2289 const std::vector<float>& kernelNoQuantizedValues,
2290 armnn::TensorInfo& kernelTensorInfo,
2291 const std::vector<float>& outputExpectedNoQuantizedValues,
2292 armnn::TensorInfo& outputTensorInfo,
2293 uint32_t dilationX,
2294 uint32_t dilationY,
2295 armnn::DataLayout layout = armnn::DataLayout::NCHW,
2296 bool biasEnabled = false)
2297{
2298 float qScale;
2299 int32_t qOffset;
2300 switch (ArmnnType)
2301 {
2302 case armnn::DataType::QuantisedAsymm8:
2303 {
2304 qScale = 0.1f;
2305 qOffset = 128;
2306 break;
2307 }
2308 case armnn::DataType::QuantisedSymm16:
2309 {
2310 qScale = 0.1f;
2311 qOffset = 0;
2312 break;
2313 }
2314 case armnn::DataType::Float32:
2315 default:
2316 {
2317 qScale = 0.f;
2318 qOffset = 0;
2319 break;
2320 }
2321 }
2322
2323 inputTensorInfo.SetQuantizationScale(qScale);
2324 inputTensorInfo.SetQuantizationOffset(qOffset);
2325 kernelTensorInfo.SetQuantizationScale(qScale);
2326 kernelTensorInfo.SetQuantizationOffset(qOffset);
2327 outputTensorInfo.SetQuantizationScale(qScale);
2328 outputTensorInfo.SetQuantizationOffset(qOffset);
2329
2330 auto input = MakeTensor<T, 4>(inputTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002331 std::vector<T>(QuantizedVector<T>(inputNoQuantizedValues,
2332 inputTensorInfo.GetQuantizationScale(),
2333 inputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002334 auto kernel = MakeTensor<T, 4>(kernelTensorInfo,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +01002335 std::vector<T>(QuantizedVector<T>(kernelNoQuantizedValues,
2336 kernelTensorInfo.GetQuantizationScale(),
2337 kernelTensorInfo.GetQuantizationOffset())));
2338 auto expectedOutput =
2339 MakeTensor<T, 4>(outputTensorInfo,
2340 std::vector<T>(QuantizedVector<T>(outputExpectedNoQuantizedValues,
2341 outputTensorInfo.GetQuantizationScale(),
2342 outputTensorInfo.GetQuantizationOffset())));
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002343
2344 uint32_t padLeft = 0;
2345 uint32_t padTop = 0;
2346 uint32_t padRight = 0;
2347 uint32_t padBottom = 0;
2348 uint32_t strideX = 1;
2349 uint32_t strideY = 1;
2350
2351 return DepthwiseConvolution2dTestImpl<ArmnnType, ArmnnBType>(
2352 workloadFactory,
2353 memoryManager,
2354 input,
2355 kernel,
2356 GetBias<ArmnnBType>(biasEnabled, qScale * qScale, outputTensorInfo, layout),
2357 expectedOutput,
2358 qScale,
2359 qOffset,
2360 layout,
2361 padLeft,
2362 padTop,
2363 padRight,
2364 padBottom,
2365 strideX,
2366 strideY,
2367 dilationX,
2368 dilationY);
2369}
2370
2371template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
2372LayerTestResult<T, 4> DepthwiseConvolution2d3x3Dilation3x3Test(
2373 armnn::IWorkloadFactory& workloadFactory,
2374 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2375 bool biasEnabled,
2376 const armnn::DataLayout layout)
2377{
2378 armnn::TensorInfo inputTensorInfo({1, 1, 10, 10}, ArmnnType);
2379 std::vector<float> inputNoQuantizedValues =
2380 {
2381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2384 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2385 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2386 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2391 };
2392
2393 armnn::TensorInfo kernelTensorInfo({ 1, 1, 3, 3}, ArmnnType);
2394 std::vector<float> kernelNoQuantizedValues =
2395 {
2396 1, 2, 3,
2397 4, 5, 6,
2398 7, 8, 9
2399 };
2400
2401 // Since the dilation rate is 3 this will dilate the kernel to be like 7x7,
2402 // therefore the output will be 4x4: (I−K+2P)/S +1 => (10-7 +0)/1 +1
2403 armnn::TensorInfo outputTensorInfo({ 1, 1, 4, 4}, ArmnnType);
2404 std::vector<float> outputExpectedNoQuantizedValues =
2405 {
2406 6., 5., 5., 5.,
2407 6., 5., 5., 5.,
2408 6., 5., 5., 5.,
2409 3., 2., 2., 2.
2410 };
2411
2412 return DepthwiseConvolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
2413 workloadFactory,
2414 memoryManager,
2415 inputNoQuantizedValues,
2416 inputTensorInfo,
2417 kernelNoQuantizedValues,
2418 kernelTensorInfo,
2419 outputExpectedNoQuantizedValues,
2420 outputTensorInfo,
2421 3,
2422 3,
2423 layout,
2424 biasEnabled);
2425}
2426
2427template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
2428LayerTestResult<T, 4> DepthwiseConvolution2d2x3x3Dilation3x3Test(
2429 armnn::IWorkloadFactory& workloadFactory,
2430 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2431 bool biasEnabled,
2432 const armnn::DataLayout layout)
2433{
2434 armnn::TensorInfo inputTensorInfo({1, 2, 10, 10}, ArmnnType);
2435 std::vector<float> inputNoQuantizedValues =
2436 {
2437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2440 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2441 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2442 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2447
2448 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2451 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2452 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2453 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
2454 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2457 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
2458 };
2459
2460 armnn::TensorInfo kernelTensorInfo({ 1, 2, 3, 3}, ArmnnType);
2461 std::vector<float> kernelNoQuantizedValues =
2462 {
2463 1, 2, 3,
2464 4, 5, 6,
2465 7, 8, 9,
2466
2467 1, 2, 3,
2468 4, 5, 6,
2469 7, 8, 9
2470 };
2471
2472 // Since the dilation rate is 3 this will dilate the kernel to be like 7x7,
2473 // therefore the output will be 2x4x4: (I−K+2P)/S +1 => (10-7 +0)/1 +1
2474 armnn::TensorInfo outputTensorInfo({ 1, 2, 4, 4}, ArmnnType);
2475 std::vector<float> outputExpectedNoQuantizedValues =
2476 {
2477 6., 5., 5., 5.,
2478 6., 5., 5., 5.,
2479 6., 5., 5., 5.,
2480 3., 2., 2., 2.,
2481
2482 6., 5., 5., 5.,
2483 6., 5., 5., 5.,
2484 6., 5., 5., 5.,
2485 3., 2., 2., 2.
2486 };
2487
2488 return DepthwiseConvolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
2489 workloadFactory,
2490 memoryManager,
2491 inputNoQuantizedValues,
2492 inputTensorInfo,
2493 kernelNoQuantizedValues,
2494 kernelTensorInfo,
2495 outputExpectedNoQuantizedValues,
2496 outputTensorInfo,
2497 3,
2498 3,
2499 layout,
2500 biasEnabled);
2501}
2502
2503template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
2504LayerTestResult<T, 4> DepthwiseConvolution2dMult4Test(
2505 armnn::IWorkloadFactory& workloadFactory,
2506 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2507 bool biasEnabled,
2508 const armnn::DataLayout layout)
2509{
2510 armnn::TensorInfo inputTensorInfo({1, 2, 3, 3}, ArmnnType);
2511 std::vector<float> inputNoQuantizedValues =
2512 {
2513 10.0, 10.0, 10.0,
2514 10.0, 10.0, 10.0,
2515 10.0, 10.0, 10.0,
2516
2517 21.0, 22.0, 23.0,
2518 24.0, 25.0, 26.0,
2519 27.0, 28.0, 29.0
2520 };
2521
2522 armnn::TensorInfo kernelTensorInfo({ 4, 2, 2, 2}, ArmnnType);
2523
2524 std::vector<float> kernelNoQuantizedValues =
2525 {
2526 0.25f, 0.25f,
2527 0.25f, 0.25f,
2528
2529 0.25f, 0.25f,
2530 0.25f, 0.25f,
2531
2532 0.0f , 0.0f,
2533 0.0f , 0.1f,
2534
2535 0.0f , 0.0f,
2536 0.0f , 0.1f,
2537
2538 0.2f , 0.0f,
2539 0.0f , 0.0f,
2540
2541 0.2f , 0.0f,
2542 0.0f , 0.0f,
2543
2544 0.0f , 0.3f,
2545 0.0f , 0.0f,
2546
2547 0.0f , 0.3f,
2548 0.0f , 0.0f
2549 };
2550
2551 armnn::TensorInfo outputTensorInfo({ 1, 8, 2, 2}, ArmnnType);
2552 std::vector<float> outputExpectedNoQuantizedValues =
2553 {
2554 10.f, 10.f,
2555 10.f, 10.f,
2556
2557 1.f, 1.f,
2558 1.f, 1.f,
2559
2560 2.f, 2.f,
2561 2.f, 2.f,
2562
2563 3.f, 3.f,
2564 3.f, 3.f,
2565
2566 23.f, 24.f,
2567 26.f, 27.f,
2568
2569 2.5f, 2.6000001f,
2570 2.8f, 2.9f,
2571
2572 4.2000003f, 4.4f,
2573 4.8f, 5.f,
2574
2575 6.6000004f, 6.9f,
2576 7.5000005f, 7.8f
2577 };
2578
2579
2580 return DepthwiseConvolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
2581 workloadFactory,
2582 memoryManager,
2583 inputNoQuantizedValues,
2584 inputTensorInfo,
2585 kernelNoQuantizedValues,
2586 kernelTensorInfo,
2587 outputExpectedNoQuantizedValues,
2588 outputTensorInfo,
2589 1,
2590 1,
2591 layout,
2592 biasEnabled);
2593}
2594
2595template<armnn::DataType ArmnnType, armnn::DataType ArmnnBType, typename T>
2596LayerTestResult<T, 4> DepthwiseConvolution2dMult2Test(
2597 armnn::IWorkloadFactory& workloadFactory,
2598 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2599 bool biasEnabled,
2600 const armnn::DataLayout layout)
2601{
2602 armnn::TensorInfo inputTensorInfo({1, 2, 3, 3}, ArmnnType);
2603 std::vector<float> inputNoQuantizedValues =
2604 {
2605 10.0, 10.0, 10.0,
2606 10.0, 10.0, 10.0,
2607 10.0, 10.0, 10.0,
2608
2609 21.0, 22.0, 23.0,
2610 24.0, 25.0, 26.0,
2611 27.0, 28.0, 29.0
2612 };
2613
2614 armnn::TensorInfo kernelTensorInfo({ 2, 2, 2, 2}, ArmnnType);
2615
2616 std::vector<float> kernelNoQuantizedValues =
2617 {
2618 0.25f, 0.25f,
2619 0.25f, 0.25f,
2620
2621 0.2f , 0.0f,
2622 0.0f , 0.0f,
2623
2624 0.0f , 0.0f,
2625 0.0f , 0.1f,
2626
2627 0.0f , 0.3f,
2628 0.0f , 0.0f
2629
2630 };
2631
2632 armnn::TensorInfo outputTensorInfo({ 1, 4, 2, 2}, ArmnnType);
2633 std::vector<float> outputExpectedNoQuantizedValues =
2634 {
2635 10.f, 10.f,
2636 10.f, 10.f,
2637
2638 1.f, 1.f,
2639 1.f, 1.f,
2640
2641 4.2000003f, 4.4f,
2642 4.8f, 5.f,
2643
2644 6.6000004f, 6.9f,
2645 7.5000005f, 7.8f
2646 };
2647
2648
2649 return DepthwiseConvolution2d3x3DilationTestCommon<ArmnnType, ArmnnBType>(
2650 workloadFactory,
2651 memoryManager,
2652 inputNoQuantizedValues,
2653 inputTensorInfo,
2654 kernelNoQuantizedValues,
2655 kernelTensorInfo,
2656 outputExpectedNoQuantizedValues,
2657 outputTensorInfo,
2658 1,
2659 1,
2660 layout,
2661 biasEnabled);
2662}
2663
2664template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
2665LayerTestResult<T, 4> CompareDepthwiseConvolution2dTestImpl(
2666 armnn::IWorkloadFactory& workloadFactory,
2667 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2668 armnn::IWorkloadFactory& refWorkloadFactory,
2669 const armnnUtils::DataLayoutIndexed& layout)
2670{
2671 unsigned int inputHeight = 8;
2672 unsigned int inputWidth = 16;
2673 unsigned int inputChannels = 3;
2674 unsigned int inputNum = 5;
2675
2676 unsigned int kernelHeight = 3;
2677 unsigned int kernelWidth = 3;
2678 unsigned int channelMultiplier = 1;
2679
2680 unsigned int strideX = 2;
2681 unsigned int strideY = 3;
2682 unsigned int padX = 1;
2683 unsigned int padY = 1;
2684
2685 unsigned int outputNum = inputNum;
2686 unsigned int outputChannels = inputChannels * channelMultiplier;
2687 unsigned int outputHeight = (inputHeight + 2 * padY - kernelHeight + strideY) / strideY;
2688 unsigned int outputWidth = (inputWidth + 2 * padX - kernelWidth + strideX) / strideX;
2689
2690 armnn::TensorInfo inputTensorInfo;
2691 armnn::TensorInfo outputTensorInfo;
2692 armnn::TensorInfo kernelDesc;
2693 armnn::TensorInfo biasDesc;
2694
2695
2696 std::vector<unsigned int> inputShape;
2697 std::vector<unsigned int> outputShape;
2698 std::vector<unsigned int> kernelShape{ channelMultiplier, inputChannels, kernelHeight, kernelWidth };
2699 std::vector<unsigned int> biasShape{ outputChannels };
2700 switch (layout.GetDataLayout())
2701 {
2702 case armnn::DataLayout::NCHW:
2703 inputShape = { inputNum, inputChannels, inputHeight, inputWidth };
2704 outputShape = { outputNum, outputChannels, outputHeight, outputWidth };
2705 break;
2706 case armnn::DataLayout ::NHWC:
2707 inputShape = { inputNum, inputHeight, inputWidth, inputChannels };
2708 outputShape = { outputNum, outputHeight, outputWidth, outputChannels };
2709 break;
2710 default:
2711 throw armnn::InvalidArgumentException("unknown data layout ["
2712 + std::to_string(static_cast<int>(layout.GetDataLayout())) + "]");
2713 }
2714
2715 float inputsQScale = armnn::IsQuantizedType<T>() ? 1.0f : 0;
2716 float outputQScale = armnn::IsQuantizedType<T>() ? 2.0f : 0;
2717 int32_t qOffset = 0;
2718
2719 inputTensorInfo = armnn::TensorInfo(4, inputShape.data(), ArmnnType, inputsQScale, qOffset);
2720 outputTensorInfo = armnn::TensorInfo(4, outputShape.data(), ArmnnType, outputQScale, qOffset);
2721 kernelDesc = armnn::TensorInfo(4, kernelShape.data(), ArmnnType, inputsQScale, qOffset);
2722 biasDesc = armnn::TensorInfo(
2723 1, biasShape.data(), armnn::GetBiasDataType(ArmnnType), inputsQScale, qOffset);
2724
2725 LayerTestResult<T, 4> ret(outputTensorInfo);
2726
2727 auto input = MakeRandomTensor<T, 4>(inputTensorInfo, 124908, 0.0f, 255.0f);
2728 auto kernel = MakeRandomTensor<T, 4>(kernelDesc, 891234, 0.0f, 255.0f);
2729 auto bias = MakeRandomTensor<typename FullyConnectedBiasTypeForInputType<T>::Type, 1>(
2730 biasDesc, 1028, 0.0f, 255.0f);
2731
2732 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
2733 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
2734
2735 armnn::DepthwiseConvolution2dQueueDescriptor data;
2736 armnn::WorkloadInfo info;
2737 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
2738 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
2739
2740 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
2741 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
2742
2743 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
2744 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2745 data.m_Weight = &weightsTensor;
2746 data.m_Bias = &biasTensor;
2747 data.m_Parameters.m_StrideX = strideX;
2748 data.m_Parameters.m_StrideY = strideY;
2749 data.m_Parameters.m_PadLeft = padX;
2750 data.m_Parameters.m_PadRight = padX;
2751 data.m_Parameters.m_PadTop = padY;
2752 data.m_Parameters.m_PadBottom = padY;
2753 data.m_Parameters.m_BiasEnabled = true;
2754 data.m_Parameters.m_DataLayout = layout.GetDataLayout();
2755
2756 std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refWorkloadFactory.CreateTensorHandle(outputTensorInfo);
2757 std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refWorkloadFactory.CreateTensorHandle(inputTensorInfo);
2758
2759 armnn::DepthwiseConvolution2dQueueDescriptor refData = data;
2760 armnn::WorkloadInfo refInfo = info;
2761 SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
2762 SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
2763
2764 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
2765 std::unique_ptr<armnn::IWorkload> workloadRef = refWorkloadFactory.CreateDepthwiseConvolution2d(refData, refInfo);
2766
2767 outputHandleRef->Allocate();
2768 inputHandleRef->Allocate();
2769
2770 inputHandle->Allocate();
2771 outputHandle->Allocate();
2772
2773 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
2774 CopyDataToITensorHandle(inputHandleRef.get(), &input[0][0][0][0]);
2775
2776 ExecuteWorkload(*workload, memoryManager);
2777
2778 workloadRef->PostAllocationConfigure();
2779 workloadRef->Execute();
2780
2781 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
2782 CopyDataFromITensorHandle(&ret.outputExpected[0][0][0][0], outputHandleRef.get());
2783
2784 return ret;
2785}
2786
2787//
2788// Explicit template specializations
2789//
2790
2791template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2792Convolution2d3x3Dilation3x3Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2793 armnn::IWorkloadFactory&,
2794 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2795 bool,
2796 armnn::DataLayout);
2797
2798template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 4>
2799Convolution2d3x3Dilation3x3Test<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2800 armnn::IWorkloadFactory&,
2801 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2802 bool,
2803 armnn::DataLayout);
2804
2805template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 4>
2806Convolution2d3x3Dilation3x3Test<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2807 armnn::IWorkloadFactory&,
2808 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2809 bool,
2810 armnn::DataLayout);
2811
2812template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2813Convolution2d2x3x3Dilation3x3Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2814 armnn::IWorkloadFactory&,
2815 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2816 bool,
2817 armnn::DataLayout);
2818
2819template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 4>
2820Convolution2d2x3x3Dilation3x3Test<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2821 armnn::IWorkloadFactory&,
2822 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2823 bool,
2824 armnn::DataLayout);
2825
2826template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 4>
2827Convolution2d2x3x3Dilation3x3Test<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2828 armnn::IWorkloadFactory&,
2829 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2830 bool,
2831 armnn::DataLayout);
2832
2833template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2834Convolution2d2x2Dilation2x2Padding2x2Stride3x3Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2835 armnn::IWorkloadFactory &workloadFactory,
2836 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
2837 bool biasEnabled,
2838 const armnn::DataLayout layout);
2839
2840template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 4>
2841Convolution2d2x2Dilation2x2Padding2x2Stride3x3Test<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2842 armnn::IWorkloadFactory &workloadFactory,
2843 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
2844 bool biasEnabled,
2845 const armnn::DataLayout layout);
2846
2847template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 4>
2848Convolution2d2x2Dilation2x2Padding2x2Stride3x3Test<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2849 armnn::IWorkloadFactory &workloadFactory,
2850 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
2851 bool biasEnabled,
2852 const armnn::DataLayout layout);
2853
2854template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2855DepthwiseConvolution2d3x3Dilation3x3Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2856 armnn::IWorkloadFactory&,
2857 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2858 bool,
2859 armnn::DataLayout);
2860
2861template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 4>
2862DepthwiseConvolution2d3x3Dilation3x3Test<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2863 armnn::IWorkloadFactory&,
2864 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2865 bool,
2866 armnn::DataLayout);
2867
2868template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 4>
2869DepthwiseConvolution2d3x3Dilation3x3Test<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2870 armnn::IWorkloadFactory&,
2871 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2872 bool,
2873 armnn::DataLayout);
2874
2875template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2876DepthwiseConvolution2d2x3x3Dilation3x3Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2877 armnn::IWorkloadFactory&,
2878 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2879 bool,
2880 armnn::DataLayout);
2881
2882template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 4>
2883DepthwiseConvolution2d2x3x3Dilation3x3Test<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2884 armnn::IWorkloadFactory&,
2885 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2886 bool,
2887 armnn::DataLayout);
2888
2889template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 4>
2890DepthwiseConvolution2d2x3x3Dilation3x3Test<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2891 armnn::IWorkloadFactory&,
2892 const armnn::IBackendInternal::IMemoryManagerSharedPtr&,
2893 bool,
2894 armnn::DataLayout);
2895
2896template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2897DepthwiseConvolution2dMult4Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2898 armnn::IWorkloadFactory &workloadFactory,
2899 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
2900 bool biasEnabled,
2901 const armnn::DataLayout layout);
2902
2903template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
2904DepthwiseConvolution2dMult2Test<armnn::DataType::Float32, armnn::DataType::Float32>(
2905 armnn::IWorkloadFactory &workloadFactory,
2906 const armnn::IBackendInternal::IMemoryManagerSharedPtr &memoryManager,
2907 bool biasEnabled,
2908 const armnn::DataLayout layout);
2909
2910//
2911// Implementation functions
2912//
2913
2914LayerTestResult<float, 4> SimpleConvolution2d3x5Test(
2915 armnn::IWorkloadFactory& workloadFactory,
2916 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2917 bool biasEnabled,
2918 const armnn::DataLayout layout)
2919{
2920 return SimpleConvolution2d3x5TestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
2921 workloadFactory, memoryManager, 0.f, 0, biasEnabled, layout);
2922}
2923
2924LayerTestResult<uint8_t, 4> SimpleConvolution2d3x5Uint8Test(
2925 armnn::IWorkloadFactory& workloadFactory,
2926 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2927 bool biasEnabled,
2928 const armnn::DataLayout layout)
2929{
2930 return SimpleConvolution2d3x5TestCommon<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2931 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
2932}
2933
2934LayerTestResult<float, 4> SimpleConvolution2d3x3Test(
2935 armnn::IWorkloadFactory& workloadFactory,
2936 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2937 bool biasEnabled,
2938 const armnn::DataLayout layout)
2939{
2940 return SimpleConvolution2d3x3TestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
2941 workloadFactory, memoryManager, 0.f, 0, biasEnabled, layout);
2942}
2943
2944LayerTestResult<float, 4> SimpleConvolution2d3x3NhwcTest(
2945 armnn::IWorkloadFactory& workloadFactory,
2946 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2947 bool biasEnabled)
2948{
2949 return SimpleConvolution2d3x3NhwcTestCommon<armnn::DataType::Float32>(
2950 workloadFactory,
2951 memoryManager,
2952 0.f,
2953 0,
2954 biasEnabled,
2955 armnn::DataLayout::NHWC);
2956}
2957
2958LayerTestResult<float, 4> SimpleConvolution2d3x3Stride2x2Test(
2959 armnn::IWorkloadFactory& workloadFactory,
2960 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2961 bool biasEnabled,
2962 const armnn::DataLayout layout)
2963{
2964 return SimpleConvolution2d3x3Stride2x2TestCommon<armnn::DataType::Float32>(
2965 workloadFactory,
2966 memoryManager,
2967 0.f,
2968 0,
2969 biasEnabled,
2970 layout);
2971}
2972
2973LayerTestResult<uint8_t, 4> SimpleConvolution2d3x3Uint8Test(
2974 armnn::IWorkloadFactory& workloadFactory,
2975 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2976 bool biasEnabled,
2977 const armnn::DataLayout layout)
2978{
2979 return SimpleConvolution2d3x3TestCommon<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
2980 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
2981}
2982
2983LayerTestResult<int16_t, 4> SimpleConvolution2d3x5QSymm16Test(
2984 armnn::IWorkloadFactory& workloadFactory,
2985 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2986 bool biasEnabled,
2987 const armnn::DataLayout layout)
2988{
2989 return SimpleConvolution2d3x5TestCommon<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
2990 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
2991}
2992
2993LayerTestResult<int16_t, 4> SimpleConvolution2d3x3QSymm16Test(
2994 armnn::IWorkloadFactory& workloadFactory,
2995 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2996 bool biasEnabled,
2997 const armnn::DataLayout layout)
2998{
2999 return SimpleConvolution2d3x3TestCommon<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
3000 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
3001}
3002
3003LayerTestResult<float, 4> Convolution2dAsymmetricPaddingTest(
3004 armnn::IWorkloadFactory& workloadFactory,
3005 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3006 armnn::DataLayout layout)
3007{
3008 return SimpleConvolution2dAsymmetricPaddingTestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
3009 workloadFactory, memoryManager, layout, 0.0f, 0);
3010}
3011
3012LayerTestResult<float, 4> Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTest(
3013 armnn::IWorkloadFactory& workloadFactory,
3014 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3015 armnn::DataLayout layout)
3016{
3017 return Convolution2dAsymmetricPaddingLargerThanHalfKernelSizeTestCommon
3018 <armnn::DataType::Float32, armnn::DataType::Float32>(
3019 workloadFactory, memoryManager, layout, 0.0f, 0);
3020}
3021
3022LayerTestResult<float, 4> Convolution1dTest(
3023 armnn::IWorkloadFactory& workloadFactory,
3024 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3025 bool biasEnabled)
3026{
3027 return Convolution1dTestImpl<armnn::DataType::Float32, armnn::DataType::Float32>(
3028 workloadFactory, memoryManager, 0.0f, 0, biasEnabled);
3029}
3030
3031LayerTestResult<uint8_t, 4> Convolution1dUint8Test(
3032 armnn::IWorkloadFactory& workloadFactory,
3033 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3034 bool biasEnabled)
3035{
3036 return Convolution1dTestImpl<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
3037 workloadFactory, memoryManager, 0.1f, 128, biasEnabled);
3038}
3039
Aron Virginas-Tar5edc8812019-11-05 18:00:21 +00003040LayerTestResult<uint8_t, 4> Convolution2dPerAxisQuantTest(
3041 armnn::IWorkloadFactory& workloadFactory,
3042 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3043 const armnn::DataLayout layout)
3044{
3045 using namespace armnn;
3046
3047 const DataType inputType = DataType::QuantisedAsymm8;
3048 const DataType kernelType = DataType::QuantizedSymm8PerAxis;
3049 const DataType biasType = DataType::Signed32;
3050
3051 TensorInfo inputInfo ({ 1, 3, 1, 2 }, inputType, 0.5f, 128);
3052 TensorInfo outputInfo({ 1, 3, 1, 3 }, inputType, 1.0f, 128);
3053
3054 const std::vector<float> quantScales{ 0.5f, 0.75f, 1.0f };
3055 constexpr unsigned int quantDimension = 0;
3056
3057 TensorInfo kernelInfo({ 3, 1, 1, 2 }, kernelType, quantScales, quantDimension);
3058
3059 const std::vector<float> biasQuantScales{ 0.25f, 0.375f, 0.5f };
3060 TensorInfo biasInfo({ 3 }, biasType, biasQuantScales, quantDimension);
3061
3062 std::vector<uint8_t> inputData =
3063 {
3064 138, 108, 138, 108, 138, 108
3065 };
3066
3067 std::vector<int8_t> kernelData =
3068 {
3069 1, 2, 1, 2, 1, 2
3070 };
3071
3072 std::vector<int32_t> biasData =
3073 {
3074 4, 4, 4
3075 };
3076
3077 std::vector<uint8_t> expectedOutputData =
3078 {
3079 121, 118, 115, 121, 118, 115, 121, 118, 115
3080 };
3081
3082 if (layout == DataLayout::NCHW)
3083 {
3084 PermuteTensorNhwcToNchw(inputInfo, inputData);
3085 PermuteTensorNhwcToNchw(kernelInfo, kernelData);
3086 PermuteTensorNhwcToNchw(outputInfo, expectedOutputData);
3087 }
3088
3089 Convolution2dDescriptor descriptor;
3090 descriptor.m_StrideX = 1;
3091 descriptor.m_StrideY = 1;
3092 descriptor.m_PadLeft = 0;
3093 descriptor.m_PadRight = 0;
3094 descriptor.m_PadTop = 0;
3095 descriptor.m_PadBottom = 0;
3096 descriptor.m_BiasEnabled = true;
3097 descriptor.m_DataLayout = layout;
3098
3099 std::unique_ptr<ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputInfo);
3100 std::unique_ptr<ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputInfo);
3101
3102 WorkloadInfo workloadInfo;
3103 ScopedCpuTensorHandle weightTensor(kernelInfo);
3104 ScopedCpuTensorHandle biasTensor(biasInfo);
3105
3106 AllocateAndCopyDataToITensorHandle(&weightTensor, kernelData.data());
3107 AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data());
3108
3109 Convolution2dQueueDescriptor queueDescriptor;
3110 queueDescriptor.m_Parameters = descriptor;
3111 queueDescriptor.m_Weight = &weightTensor;
3112 queueDescriptor.m_Bias = &biasTensor;
3113
3114 AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get());
3115 AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get());
3116
3117 std::unique_ptr<IWorkload> workload = workloadFactory.CreateConvolution2d(queueDescriptor, workloadInfo);
3118 inputHandle->Allocate();
3119 outputHandle->Allocate();
3120
3121 CopyDataToITensorHandle(inputHandle.get(), inputData.data());
3122
3123 ExecuteWorkload(*workload, memoryManager);
3124
3125 LayerTestResult<uint8_t, 4> ret(outputInfo);
3126 CopyDataFromITensorHandle(ret.output.origin(), outputHandle.get());
3127 ret.outputExpected = MakeTensor<uint8_t, 4>(outputInfo, expectedOutputData);
3128
3129 return ret;
3130}
3131
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01003132LayerTestResult<float,4> CompareConvolution2dTest(
3133 armnn::IWorkloadFactory& workloadFactory,
3134 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3135 armnn::IWorkloadFactory& refWorkloadFactory)
3136{
3137 return CompareConvolution2dTestImpl<armnn::DataType::Float32>(
3138 workloadFactory, memoryManager, refWorkloadFactory);
3139}
3140
3141LayerTestResult<float, 4> DepthwiseConvolution2dTest(
3142 armnn::IWorkloadFactory& workloadFactory,
3143 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3144 bool biasEnabled,
3145 const armnn::DataLayout layout)
3146{
3147 return DepthwiseConvolution2dTestImpl<armnn::DataType::Float32, armnn::DataType::Float32>(
3148 workloadFactory, memoryManager, 0.0f, 0, biasEnabled, layout);
3149}
3150
3151LayerTestResult<float, 4> DepthwiseConvolution2dDepthNhwcTest(
3152 armnn::IWorkloadFactory& workloadFactory,
3153 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3154 bool biasEnabled)
3155{
3156 return DepthwiseConvolution2dNhwcTestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
3157 workloadFactory, memoryManager, 0.0f, 0, biasEnabled);
3158}
3159
3160LayerTestResult<float, 4> DepthwiseConvolution2dDepthMul1Test(
3161 armnn::IWorkloadFactory& workloadFactory,
3162 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3163 bool biasEnabled,
3164 const armnn::DataLayout layout)
3165{
3166 return DepthwiseConvolution2dDepthMul1TestImpl<armnn::DataType::Float32, armnn::DataType::Float32>(
3167 workloadFactory, memoryManager, 0.0f, 0, biasEnabled, layout);
3168}
3169
3170LayerTestResult<float, 4> DepthwiseConvolution2dDepthMul64Test(
3171 armnn::IWorkloadFactory& workloadFactory,
3172 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
3173{
3174 armnn::TensorInfo inputTensorInfo({ 1, 1, 2, 2 }, armnn::DataType::Float32);
3175 auto input = MakeTensor<float, 4>(inputTensorInfo, { 1.f, 2.f, 3.f, 4.f });
3176
3177 std::vector<float> kernelData;
3178 std::vector<float> singleDepthKernel{ 1.f, -1.f, -1.f, 1.f };
3179 for (unsigned int i = 0; i < 64; ++i)
3180 {
3181 kernelData.insert(kernelData.end(), singleDepthKernel.begin(), singleDepthKernel.end());
3182 }
3183 armnn::TensorInfo kernelTensorInfo({ 64, 1, 2, 2 }, armnn::DataType::Float32);
3184 auto kernel = MakeTensor<float, 4>(kernelTensorInfo, kernelData);
3185
3186 std::vector<float> expectedOutputData(64, 0.f);
3187 armnn::TensorInfo outputTensorInfo({ 1, 64, 1, 1 }, armnn::DataType::Float32);
3188 auto expectedOutput = MakeTensor<float, 4>(outputTensorInfo, expectedOutputData);
3189
3190 return DepthwiseConvolution2dTestImpl<armnn::DataType::Float32, armnn::DataType::Float32>(
3191 workloadFactory,
3192 memoryManager,
3193 input,
3194 kernel,
3195 boost::multi_array<float, 1>(),
3196 expectedOutput,
3197 0.f,
3198 0,
3199 armnn::DataLayout::NCHW);
3200}
3201
3202LayerTestResult<float, 4> DepthwiseConvolution2dAsymmetricTest(
3203 armnn::IWorkloadFactory& workloadFactory,
3204 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3205 bool biasEnabled,
3206 const armnn::DataLayout layout)
3207{
3208 return DepthwiseConvolution2dAsymmetricTestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
3209 workloadFactory, memoryManager, 0.0f, 0, biasEnabled, layout);
3210}
3211
3212LayerTestResult<uint8_t, 4> DepthwiseConvolution2dUint8Test(
3213 armnn::IWorkloadFactory& workloadFactory,
3214 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3215 bool biasEnabled,
3216 const armnn::DataLayout layout)
3217{
3218 return DepthwiseConvolution2dTestImpl<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
3219 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
3220}
3221
3222LayerTestResult<uint8_t, 4> DepthwiseConvolution2dDepthMul1Uint8Test(
3223 armnn::IWorkloadFactory& workloadFactory,
3224 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3225 bool biasEnabled,
3226 const armnn::DataLayout layout)
3227{
3228 return DepthwiseConvolution2dDepthMul1TestImpl<armnn::DataType::QuantisedAsymm8, armnn::DataType::Signed32>(
3229 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
3230}
3231
3232LayerTestResult<float, 4> SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTest(
3233 armnn::IWorkloadFactory& workloadFactory,
3234 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
3235{
3236 return SimpleDepthwiseConvolution2d3x3Dilation3x3NhwcTestCommon<armnn::DataType::Float32, armnn::DataType::Float32>(
3237 workloadFactory,
3238 memoryManager,
3239 0.f,
3240 0,
3241 false);
3242}
3243
3244LayerTestResult<int16_t, 4> DepthwiseConvolution2dInt16Test(
3245 armnn::IWorkloadFactory& workloadFactory,
3246 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3247 bool biasEnabled,
3248 const armnn::DataLayout layout)
3249{
3250 return DepthwiseConvolution2dTestImpl<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
3251 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
3252}
3253
3254LayerTestResult<int16_t, 4> DepthwiseConvolution2dDepthMul1Int16Test(
3255 armnn::IWorkloadFactory& workloadFactory,
3256 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3257 bool biasEnabled,
3258 const armnn::DataLayout layout)
3259{
3260 return DepthwiseConvolution2dDepthMul1TestImpl<armnn::DataType::QuantisedSymm16, armnn::DataType::Signed32>(
3261 workloadFactory, memoryManager, 0.5f, 50, biasEnabled, layout);
3262}
3263
Teresa Charlind8df0262019-11-11 12:28:15 +00003264LayerTestResult<uint8_t, 4> DepthwiseConvolution2dPerAxisQuantTest(
3265 armnn::IWorkloadFactory& workloadFactory,
3266 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3267 const armnn::DataLayout layout)
3268{
3269 using namespace armnn;
3270
3271 const DataType inputType = DataType::QuantisedAsymm8;
3272 const DataType kernelType = DataType::QuantizedSymm8PerAxis;
3273 const DataType biasType = DataType::Signed32;
3274
3275 TensorInfo inputInfo ({ 1, 3, 3, 2 }, inputType, 0.5f, 128); // N H W C
3276 TensorInfo outputInfo({ 1, 2, 2, 4 }, inputType, 1.0f, 128); // N H W C
3277
3278 const std::vector<float> quantScales{ 1.0f, 0.5f, 1.0f, 0.5f };
3279 const unsigned int quantDimension = 0;
3280 TensorInfo kernelInfo({ 2, 2, 2, 2 }, kernelType, quantScales, quantDimension); // M I H W
3281
3282 const std::vector<float> biasQuantScales{ 0.5f, 0.25f, 0.5f, 0.25f };
3283 constexpr unsigned int biasQuantDimension = 0;
3284 TensorInfo biasInfo({ 4 }, biasType, biasQuantScales, biasQuantDimension);
3285
3286 std::vector<uint8_t> inputData =
3287 {
3288 129, 130,
3289 129, 130,
3290 129, 130,
3291 129, 130,
3292 129, 130,
3293 129, 130,
3294 129, 130,
3295 129, 130,
3296 129, 130
3297 };
3298
3299 std::vector<int8_t> kernelData =
3300 {
3301 1, 1, 1, 1,
3302 1, 1, 1, 1,
3303 1, 1, 1, 1,
3304 1, 1, 1, 1
3305 };
3306
3307 std::vector<int32_t> biasData =
3308 {
3309 4, 4, 4, 4
3310 };
3311
3312 std::vector<uint8_t> expectedOutputData =
3313 {
3314 132, 130, 134, 131,
3315 132, 130, 134, 131,
3316 132, 130, 134, 131,
3317 132, 130, 134, 131
3318 };
3319
3320 if (layout == DataLayout::NCHW)
3321 {
3322 PermuteTensorNhwcToNchw(inputInfo, inputData);
3323 PermuteTensorNhwcToNchw(outputInfo, expectedOutputData);
3324 }
3325
3326 DepthwiseConvolution2dDescriptor descriptor;
3327 descriptor.m_StrideX = 1;
3328 descriptor.m_StrideY = 1;
3329 descriptor.m_PadLeft = 0;
3330 descriptor.m_PadRight = 0;
3331 descriptor.m_PadTop = 0;
3332 descriptor.m_PadBottom = 0;
3333 descriptor.m_DilationX = 1;
3334 descriptor.m_DilationY = 1;
3335 descriptor.m_BiasEnabled = true;
3336 descriptor.m_DataLayout = layout;
3337
3338 std::unique_ptr<ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputInfo);
3339 std::unique_ptr<ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputInfo);
3340
3341 WorkloadInfo workloadInfo;
3342 ScopedCpuTensorHandle weightTensor(kernelInfo);
3343 ScopedCpuTensorHandle biasTensor(biasInfo);
3344
3345 AllocateAndCopyDataToITensorHandle(&weightTensor, kernelData.data());
3346 AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data());
3347
3348 DepthwiseConvolution2dQueueDescriptor queueDescriptor;
3349 queueDescriptor.m_Parameters = descriptor;
3350 queueDescriptor.m_Weight = &weightTensor;
3351 queueDescriptor.m_Bias = &biasTensor;
3352
3353 AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get());
3354 AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get());
3355
3356 std::unique_ptr<IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(queueDescriptor, workloadInfo);
3357 inputHandle->Allocate();
3358 outputHandle->Allocate();
3359
3360 CopyDataToITensorHandle(inputHandle.get(), inputData.data());
3361
3362 ExecuteWorkload(*workload, memoryManager);
3363
3364 LayerTestResult<uint8_t, 4> ret(outputInfo);
3365
3366 CopyDataFromITensorHandle(ret.output.origin(), outputHandle.get());
3367 ret.outputExpected = MakeTensor<uint8_t, 4>(outputInfo, expectedOutputData);
3368
3369 return ret;
3370}
3371
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01003372LayerTestResult<float, 4> CompareDepthwiseConvolution2dFloatTest(
3373 armnn::IWorkloadFactory& workloadFactory,
3374 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3375 armnn::IWorkloadFactory& refWorkloadFactory,
3376 const armnn::DataLayout layout)
3377{
3378 return CompareDepthwiseConvolution2dTestImpl<armnn::DataType::Float32>(
3379 workloadFactory, memoryManager, refWorkloadFactory, layout);
3380}
3381
3382LayerTestResult<uint8_t, 4> CompareDepthwiseConvolution2dUint8Test(
3383 armnn::IWorkloadFactory& workloadFactory,
3384 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
3385 armnn::IWorkloadFactory& refWorkloadFactory,
3386 const armnn::DataLayout layout)
3387{
3388 return CompareDepthwiseConvolution2dTestImpl<armnn::DataType::QuantisedAsymm8>(
3389 workloadFactory, memoryManager, refWorkloadFactory, layout);
3390}