blob: 9bb36fb34494b043428c2c226b0ce4ad7bf584b3 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5#pragma once
6
jimfly010a088a62018-10-25 17:05:05 +01007#include <string>
telsoa014fcda012018-03-09 14:13:49 +00008#include <armnn/ArmNN.hpp>
9#include <armnn/Tensor.hpp>
10#include <armnn/TypesUtils.hpp>
telsoa014fcda012018-03-09 14:13:49 +000011
David Beckac42efd2018-09-26 17:41:13 +010012#include <test/TensorHelpers.hpp>
telsoa014fcda012018-03-09 14:13:49 +000013#include "QuantizeHelper.hpp"
14
David Beckac42efd2018-09-26 17:41:13 +010015#include <backends/CpuTensorHandle.hpp>
16#include <backends/WorkloadFactory.hpp>
jimfly010a088a62018-10-25 17:05:05 +010017#include "Permute.hpp"
18#include <boost/numeric/conversion/cast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000019
20// Mapping from input type to bias type for fully connected layers.
21// float => float, uint8_t => int32_t
22template<typename T>
23struct FullyConnectedBiasTypeForInputType;
24
25template<>
26struct FullyConnectedBiasTypeForInputType<float>
27{
28 using Type = float;
29};
30
31template<>
32struct FullyConnectedBiasTypeForInputType<uint8_t>
33{
34 using Type = int32_t;
35};
36
telsoa01c577f2c2018-08-31 09:22:23 +010037// Modifies a std::vector in-place using a specified bias.
telsoa014fcda012018-03-09 14:13:49 +000038template<typename T, typename B>
39void ApplyBias(std::vector<T>& v, float vScale, int32_t vOffset,
40 const std::vector<B>& bias, float bScale, int32_t bOffset, uint32_t w, uint32_t h)
41{
42 BOOST_ASSERT_MSG((armnn::IsQuantizedType<T>() && vScale != 0.0f) || (!armnn::IsQuantizedType<T>()),
43 "Invalid type and parameter combination.");
44 BOOST_ASSERT_MSG((armnn::IsQuantizedType<B>() && bScale != 0.0f) || (!armnn::IsQuantizedType<B>()),
45 "Invalid type and parameter combination.");
46
telsoa01c577f2c2018-08-31 09:22:23 +010047 // Note we need to dequantize and re-quantize the image value and the bias.
telsoa014fcda012018-03-09 14:13:49 +000048 for (uint32_t i = 0; i < bias.size(); ++i)
49 {
50 float dBias = SelectiveDequantize(bias[i], bScale, bOffset);
51 for (uint32_t y = 0; y < h; ++y)
52 {
53 for (uint32_t x = 0; x < w; ++x)
54 {
55 uint32_t offset = (i * h + y) * w + x;
56 BOOST_ASSERT(offset < v.size());
57 T& outRef = v[offset];
58 float dOutput = SelectiveDequantize(outRef, vScale, vOffset);
59 outRef = SelectiveQuantize<T>(dOutput + dBias, vScale, vOffset);
60 }
61 }
62 }
63}
64
telsoa014fcda012018-03-09 14:13:49 +000065template<typename T, typename B>
66LayerTestResult<T, 4> SimpleConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
jimfly010a088a62018-10-25 17:05:05 +010067 const boost::multi_array<T, 4>& originalInput,
68 const boost::multi_array<T, 4>& originalKernel,
telsoa014fcda012018-03-09 14:13:49 +000069 const boost::multi_array<B, 1>& bias,
jimfly010a088a62018-10-25 17:05:05 +010070 const boost::multi_array<T, 4>& originalOutputExpected,
telsoa014fcda012018-03-09 14:13:49 +000071 float qScale,
72 int32_t qOffset,
jimfly010a088a62018-10-25 17:05:05 +010073 const armnn::DataLayoutIndexed& layout = armnn::DataLayout::NCHW,
telsoa014fcda012018-03-09 14:13:49 +000074 uint32_t padLeft = 0,
75 uint32_t padTop = 0,
76 uint32_t padRight = 0,
77 uint32_t padBottom = 0)
78{
jimfly010a088a62018-10-25 17:05:05 +010079 unsigned int inputHeight = boost::numeric_cast<unsigned int>(originalInput.shape()[2]);
80 unsigned int inputWidth = boost::numeric_cast<unsigned int>(originalInput.shape()[3]);
81 unsigned int inputChannels = boost::numeric_cast<unsigned int>(originalInput.shape()[1]);
82 unsigned int inputNum = boost::numeric_cast<unsigned int>(originalInput.shape()[0]);
telsoa014fcda012018-03-09 14:13:49 +000083
jimfly010a088a62018-10-25 17:05:05 +010084 unsigned int outputHeight = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[2]);
85 unsigned int outputWidth = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[3]);
86 unsigned int outputChannels = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[1]);
87 unsigned int outputNum = boost::numeric_cast<unsigned int>(originalOutputExpected.shape()[0]);
telsoa014fcda012018-03-09 14:13:49 +000088
jimfly010a088a62018-10-25 17:05:05 +010089 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(originalKernel.shape()[2]);
90 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(originalKernel.shape()[3]);
91 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(originalKernel.shape()[1]);
92 unsigned int kernelDepthMul = boost::numeric_cast<unsigned int>(originalKernel.shape()[0]);
telsoa014fcda012018-03-09 14:13:49 +000093
94 bool biasEnabled = bias.size() > 0;
95
telsoa01c577f2c2018-08-31 09:22:23 +010096 // This function currently assumes 1 batch of input/output (and duplicates this into 2 batches).
telsoa014fcda012018-03-09 14:13:49 +000097 BOOST_ASSERT(inputNum == 1);
98 BOOST_ASSERT(outputNum == 1);
99
telsoa01c577f2c2018-08-31 09:22:23 +0100100 // If a bias is used, its size must equal the number of output channels.
telsoa014fcda012018-03-09 14:13:49 +0000101 BOOST_ASSERT(!biasEnabled || bias.size() == outputChannels);
102
103
telsoa01c577f2c2018-08-31 09:22:23 +0100104 // Note these tensors will use two (identical) batches.
jimfly010a088a62018-10-25 17:05:05 +0100105 armnn::TensorInfo inputTensorInfo = GetTensorInfo<T>(2*inputNum, inputChannels, inputHeight, inputWidth, layout);
106 armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(
107 2*outputNum, outputChannels, outputHeight, outputWidth, layout);
108 armnn::TensorInfo kernelDesc = GetTensorInfo<T>(kernelDepthMul, kernelChannels, kernelHeight, kernelWidth, layout);
telsoa014fcda012018-03-09 14:13:49 +0000109 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, armnn::GetDataType<B>());
110
111 // Set quantization parameters if the requested type is a quantized type.
112 if(armnn::IsQuantizedType<T>())
113 {
114 inputTensorInfo.SetQuantizationScale(qScale);
115 inputTensorInfo.SetQuantizationOffset(qOffset);
116 outputTensorInfo.SetQuantizationScale(qScale);
117 outputTensorInfo.SetQuantizationOffset(qOffset);
118 kernelDesc.SetQuantizationScale(qScale);
119 kernelDesc.SetQuantizationOffset(qOffset);
120 biasDesc.SetQuantizationScale(qScale*qScale);
121 biasDesc.SetQuantizationOffset(0);
122 }
123
124 LayerTestResult<T, 4> ret(outputTensorInfo);
125
telsoa01c577f2c2018-08-31 09:22:23 +0100126 // Construct input data - two batches of the same input image.
telsoa014fcda012018-03-09 14:13:49 +0000127 std::vector<T> inputImage;
jimfly010a088a62018-10-25 17:05:05 +0100128 inputImage.assign(originalInput.data(), originalInput.data() + 1*inputChannels*inputHeight*inputWidth);
telsoa014fcda012018-03-09 14:13:49 +0000129 std::vector<T> inputData;
130 inputData.insert(inputData.end(), inputImage.begin(), inputImage.end());
131 inputData.insert(inputData.end(), inputImage.begin(), inputImage.end());
jimfly010a088a62018-10-25 17:05:05 +0100132
133 // at this point if we require it permute the input data
134 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
135 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
136 {
137 std::vector<T> tmp(inputData.size());
138 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data());
139 inputData = tmp;
140 }
141
telsoa014fcda012018-03-09 14:13:49 +0000142 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
143
144 std::vector<T> outputImage;
jimfly010a088a62018-10-25 17:05:05 +0100145 outputImage.assign(originalOutputExpected.data(),
146 originalOutputExpected.data() + outputChannels*outputHeight*outputWidth);
telsoa014fcda012018-03-09 14:13:49 +0000147
telsoa01c577f2c2018-08-31 09:22:23 +0100148 // Apply bias to output image if it is enabled.
telsoa014fcda012018-03-09 14:13:49 +0000149 if(biasEnabled)
150 {
151 std::vector<T> biasV;
152 biasV.assign(bias.data(), bias.data() + outputChannels);
153 ApplyBias(outputImage, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
154 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
155 outputWidth, outputHeight);
156 }
157
telsoa01c577f2c2018-08-31 09:22:23 +0100158 // Construct expected output data - two identical images.
telsoa014fcda012018-03-09 14:13:49 +0000159 std::vector<T> outputData;
160 outputData.insert(outputData.end(), outputImage.begin(), outputImage.end());
161 outputData.insert(outputData.end(), outputImage.begin(), outputImage.end());
162
jimfly010a088a62018-10-25 17:05:05 +0100163 // at this point if we require it permute the expected output
164 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
165 {
166 std::vector<T> tmp(outputData.size());
167 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data());
168 outputData = tmp;
169 }
telsoa014fcda012018-03-09 14:13:49 +0000170 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
171
telsoa01c577f2c2018-08-31 09:22:23 +0100172 // Todo: nontrivial padding and strides.
telsoa014fcda012018-03-09 14:13:49 +0000173 uint32_t strideX = 1;
174 uint32_t strideY = 1;
175
176 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
177 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
178
179 armnn::Convolution2dQueueDescriptor data;
180 armnn::WorkloadInfo info;
181 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
182 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
jimfly010a088a62018-10-25 17:05:05 +0100183 // Permute the kernel if necessary
184 boost::multi_array<T, 4> kernel = boost::multi_array<T, 4>(originalKernel);
185 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
186 {
187 armnnUtils::Permute(kernelDesc.GetShape(), NCHWToNHWC, originalKernel.data(), kernel.data());
188 }
telsoa014fcda012018-03-09 14:13:49 +0000189 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
190
191 if(biasEnabled)
192 {
193 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
194 }
195
196 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
197 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
198
199 data.m_Weight = &weightsTensor;
telsoa01c577f2c2018-08-31 09:22:23 +0100200 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
telsoa014fcda012018-03-09 14:13:49 +0000201 data.m_Parameters.m_StrideX = strideX;
202 data.m_Parameters.m_StrideY = strideY;
203 data.m_Parameters.m_PadLeft = padLeft;
204 data.m_Parameters.m_PadRight = padRight;
205 data.m_Parameters.m_PadTop = padTop;
206 data.m_Parameters.m_PadBottom = padBottom;
207 data.m_Parameters.m_BiasEnabled = biasEnabled;
jimfly010a088a62018-10-25 17:05:05 +0100208 data.m_Parameters.m_DataLayout = layout.GetDataLayout();
telsoa014fcda012018-03-09 14:13:49 +0000209
210 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
211 inputHandle->Allocate();
212 outputHandle->Allocate();
213
214 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
215
surmeh013537c2c2018-05-18 16:31:43 +0100216 workloadFactory.Finalize();
217 workload->Execute();
218
219 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
220
221 return ret;
222}
223
224template<typename T, typename B>
Francis Murtaghd59116e2018-10-04 16:03:07 +0100225LayerTestResult<T, 4> SimpleConvolution2dNhwcTestImpl(armnn::IWorkloadFactory& workloadFactory,
226 const boost::multi_array<T, 4>& input,
227 const boost::multi_array<T, 4>& kernel,
228 const boost::multi_array<B, 1>& bias,
229 const boost::multi_array<T, 4>& outputExpected,
230 armnn::DataLayout dataLayout,
231 float qScale,
232 int32_t qOffset,
233 uint32_t padLeft = 1,
234 uint32_t padTop = 1,
235 uint32_t padRight = 1,
236 uint32_t padBottom = 1,
237 uint32_t strideX = 1,
238 uint32_t strideY = 1)
239{
240 unsigned int inputNum = boost::numeric_cast<unsigned int>(input.shape()[0]);
241 unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[3]);
242 unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[1]);
243 unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[2]);
244
245 unsigned int kernelChanMul = boost::numeric_cast<unsigned int>(kernel.shape()[0]);
246 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(kernel.shape()[3]);
247 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(kernel.shape()[1]);
248 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(kernel.shape()[2]);
249
250 unsigned int outputNum = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
251 unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]);
252 unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]);
253 unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]);
254
255 bool biasEnabled = bias.size() > 0;
256
257 // Creates the tensors.
258 armnn::TensorInfo inputTensorInfo({inputNum, inputHeight, inputWidth, inputChannels}, armnn::GetDataType<T>());
259 armnn::TensorInfo outputTensorInfo({outputNum, outputHeight, outputWidth, outputChannels},
260 armnn::GetDataType<T>());
261 armnn::TensorInfo kernelDesc({kernelChanMul, kernelHeight, kernelWidth, kernelChannels}, armnn::GetDataType<T>());
262 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, armnn::GetDataType<B>());
263
264 // Construct the input data.
265 std::vector<T> inputData;
266 inputData.assign(input.data(), input.data() + inputHeight*inputWidth*inputChannels);
267 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
268
269 // Construct the output data, with bias applied, as appropriate.
270 std::vector<T> outputData;
271 outputData.assign(outputExpected.data(), outputExpected.data() + outputHeight*outputWidth*outputChannels);
272
273 LayerTestResult<T, 4> ret(outputTensorInfo);
274 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
275
276 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
277 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
278
279 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
280 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
281
282 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
283
284 armnn::Convolution2dQueueDescriptor data;
285
286 data.m_Weight = &weightsTensor;
287 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
288 data.m_Parameters.m_StrideX = strideX;
289 data.m_Parameters.m_StrideY = strideY;
290 data.m_Parameters.m_PadLeft = padLeft;
291 data.m_Parameters.m_PadRight = padRight;
292 data.m_Parameters.m_PadTop = padTop;
293 data.m_Parameters.m_PadBottom = padBottom;
294 data.m_Parameters.m_BiasEnabled = biasEnabled;
295 data.m_Parameters.m_DataLayout = dataLayout;
296
297 armnn::WorkloadInfo info;
298 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
299 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
300
301 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
302 inputHandle->Allocate();
303 outputHandle->Allocate();
304
305 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
306
307 workloadFactory.Finalize();
308 workload->Execute();
309
310 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
311
312 return ret;
313}
314
315template<typename T, typename B>
surmeh013537c2c2018-05-18 16:31:43 +0100316LayerTestResult<T, 4> DepthwiseConvolution2dAsymmetricTestImpl(armnn::IWorkloadFactory& workloadFactory,
317 const boost::multi_array<T, 4>& input,
jimfly01382a91d2018-10-26 15:55:50 +0100318 const boost::multi_array<T, 4>& originalKernel,
surmeh013537c2c2018-05-18 16:31:43 +0100319 const boost::multi_array<B, 1>& bias,
320 const boost::multi_array<T, 4>& outputExpected,
321 float qScale,
322 int32_t qOffset,
jimfly01382a91d2018-10-26 15:55:50 +0100323 const armnn::DataLayoutIndexed& layout,
surmeh013537c2c2018-05-18 16:31:43 +0100324 uint32_t padLeft = 0,
325 uint32_t padTop = 0,
326 uint32_t padRight = 0,
327 uint32_t padBottom = 0,
328 uint32_t strideX = 1,
329 uint32_t strideY = 1)
330{
331 unsigned int inputNum = boost::numeric_cast<unsigned int>(input.shape()[0]);
332 unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[1]);
333 unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[2]);
334 unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[3]);
jimfly01382a91d2018-10-26 15:55:50 +0100335 unsigned int kernelChanMul = boost::numeric_cast<unsigned int>(originalKernel.shape()[0]);
336 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(originalKernel.shape()[1]);
337 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(originalKernel.shape()[2]);
338 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(originalKernel.shape()[3]);
surmeh013537c2c2018-05-18 16:31:43 +0100339 unsigned int outputNum = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
340 unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]);
341 unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]);
342 unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]);
343
telsoa01c577f2c2018-08-31 09:22:23 +0100344 // If a bias is used, its size must equal the number of output channels.
surmeh013537c2c2018-05-18 16:31:43 +0100345 bool biasEnabled = bias.size() > 0;
346 BOOST_ASSERT(!biasEnabled || bias.size() == outputChannels);
347
telsoa01c577f2c2018-08-31 09:22:23 +0100348 // Creates the tensors.
jimfly01382a91d2018-10-26 15:55:50 +0100349 armnn::TensorInfo inputTensorInfo = GetTensorInfo<T>(inputNum, inputChannels, inputHeight, inputWidth, layout);
350 armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(outputNum, outputChannels, outputHeight, outputWidth, layout);
351 armnn::TensorInfo kernelDesc = GetTensorInfo<T>(kernelChanMul, kernelChannels, kernelHeight, kernelWidth, layout);
surmeh013537c2c2018-05-18 16:31:43 +0100352 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, armnn::GetDataType<B>());
353
354 // Set quantization parameters if the requested type is a quantized type.
355 if (armnn::IsQuantizedType<T>())
356 {
357 inputTensorInfo.SetQuantizationScale(qScale);
358 inputTensorInfo.SetQuantizationOffset(qOffset);
359 outputTensorInfo.SetQuantizationScale(qScale);
360 outputTensorInfo.SetQuantizationOffset(qOffset);
361 kernelDesc.SetQuantizationScale(qScale);
362 kernelDesc.SetQuantizationOffset(qOffset);
363 biasDesc.SetQuantizationScale(qScale*qScale);
364 biasDesc.SetQuantizationOffset(0);
365 }
366
telsoa01c577f2c2018-08-31 09:22:23 +0100367 // Construct the input data.
surmeh013537c2c2018-05-18 16:31:43 +0100368 std::vector<T> inputData;
369 inputData.assign(input.data(), input.data() + inputChannels*inputHeight*inputWidth);
jimfly01382a91d2018-10-26 15:55:50 +0100370
371 // At this point if we require it permute the input data
372 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
373 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
374 {
375 std::vector<T> tmp(inputData.size());
376 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, inputData.data(), tmp.data());
377 inputData = tmp;
378 }
379
surmeh013537c2c2018-05-18 16:31:43 +0100380 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
381
telsoa01c577f2c2018-08-31 09:22:23 +0100382 // Construct the output data, with bias applied, as appropriate.
surmeh013537c2c2018-05-18 16:31:43 +0100383 std::vector<T> outputData;
384 outputData.assign(outputExpected.data(), outputExpected.data() + outputChannels*outputHeight*outputWidth);
385 if (biasEnabled)
386 {
387 std::vector<T> biasV;
388 biasV.assign(bias.data(), bias.data() + outputChannels);
389 ApplyBias(outputData, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
390 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
391 outputWidth, outputHeight);
392 }
393
394 LayerTestResult<T, 4> ret(outputTensorInfo);
jimfly01382a91d2018-10-26 15:55:50 +0100395
396 // At this point if we require it permute the expected output
397 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
398 {
399 std::vector<T> tmp(outputData.size());
400 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, outputData.data(), tmp.data());
401 outputData = tmp;
402 }
403
surmeh013537c2c2018-05-18 16:31:43 +0100404 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
405
406 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
407 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
408
409 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
jimfly01382a91d2018-10-26 15:55:50 +0100410
411 // Permute the kernel if necessary
412 boost::multi_array<T, 4> kernel = boost::multi_array<T, 4>(originalKernel);
413 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
414 {
415 armnnUtils::Permute(kernelDesc.GetShape(), NCHWToNHWC, originalKernel.data(), kernel.data());
416 }
417
surmeh013537c2c2018-05-18 16:31:43 +0100418 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
419
420 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
421 if (biasEnabled)
422 {
423 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
424 }
425
426 armnn::DepthwiseConvolution2dQueueDescriptor data;
427 data.m_Weight = &weightsTensor;
telsoa01c577f2c2018-08-31 09:22:23 +0100428 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - it can be a source of bugs.
surmeh013537c2c2018-05-18 16:31:43 +0100429 data.m_Parameters.m_StrideX = strideX;
430 data.m_Parameters.m_StrideY = strideY;
431 data.m_Parameters.m_PadLeft = padLeft;
432 data.m_Parameters.m_PadRight = padRight;
433 data.m_Parameters.m_PadTop = padTop;
434 data.m_Parameters.m_PadBottom = padBottom;
435 data.m_Parameters.m_BiasEnabled = biasEnabled;
jimfly01382a91d2018-10-26 15:55:50 +0100436 data.m_Parameters.m_DataLayout = layout.GetDataLayout();
surmeh013537c2c2018-05-18 16:31:43 +0100437
438 armnn::WorkloadInfo info;
439 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
440 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
441
442 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
443 inputHandle->Allocate();
444 outputHandle->Allocate();
445
446 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
447
448 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +0000449 workload->Execute();
450
451 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
452
453 return ret;
454}
455
456template<typename T, typename B>
457LayerTestResult<T, 4> DepthwiseConvolution2dDepthMul1TestImpl(armnn::IWorkloadFactory& workloadFactory,
458 float qScale,
459 int32_t qOffset,
460 bool biasEnabled)
461{
462 unsigned int inputHeight = 3;
463 unsigned int inputWidth = 3;
464 unsigned int inputChannels = 2;
465 unsigned int inputNum = 1;
466
467 unsigned int kernelHeight = 3;
468 unsigned int kernelWidth = 3;
469 unsigned int kernelChannels = inputChannels;
470
471 unsigned int outputHeight = 1;
472 unsigned int outputWidth = 1;
473 unsigned int outputChannels = kernelChannels;
474 unsigned int outputNum = inputNum;
475
476 armnn::TensorInfo inputTensorInfo({ inputNum, inputChannels, inputHeight, inputWidth }, armnn::GetDataType<T>());
477 armnn::TensorInfo outputTensorInfo({ outputNum, outputChannels, outputHeight, outputWidth },
478 armnn::GetDataType<T>());
479 armnn::TensorInfo kernelDesc({ 1, outputChannels, kernelHeight, kernelWidth }, armnn::GetDataType<T>());
480 armnn::TensorInfo biasDesc({ outputChannels }, armnn::GetDataType<B>());
481
482 // Set quantization parameters if the requested type is a quantized type.
483 if(armnn::IsQuantizedType<T>())
484 {
485 inputTensorInfo.SetQuantizationScale(qScale);
486 inputTensorInfo.SetQuantizationOffset(qOffset);
487 outputTensorInfo.SetQuantizationScale(qScale);
488 outputTensorInfo.SetQuantizationOffset(qOffset);
489 kernelDesc.SetQuantizationScale(qScale);
490 kernelDesc.SetQuantizationOffset(qOffset);
491 biasDesc.SetQuantizationScale(qScale*qScale);
492 biasDesc.SetQuantizationOffset(0);
493 }
494
495 auto input = MakeTensor<T, 4>(inputTensorInfo, std::vector<T>(
496 QuantizedVector<T>(inputTensorInfo.GetQuantizationScale(), inputTensorInfo.GetQuantizationOffset(), {
497 1.f, 2.f, 1.f,
498 2.f, 1.f, 2.f,
499 1.f, 2.f, 1.f,
500
501 1.f, 2.f, 1.f,
502 2.f, 1.f, 2.f,
503 1.f, 2.f, 1.f,
504 })));
505
506 std::vector<B> biasV(QuantizedVector<B>(biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
507 {0, 2}));
508 auto bias = MakeTensor<B, 1>(biasDesc, biasV);
509
510 auto kernel = MakeTensor<T, 4>(kernelDesc, std::vector<T>(
511 QuantizedVector<T>(kernelDesc.GetQuantizationScale(), kernelDesc.GetQuantizationOffset(), {
512 1.f, 0.f, 1.f,
513 0.f, 0.f, 0.f,
514 -1.f, 0.f, -1.f,
515
516 1.f, 0.f, 1.f,
517 0.f, 0.f, 0.f,
518 -1.f, 0.f, -1.f,
519 })));
520
telsoa01c577f2c2018-08-31 09:22:23 +0100521 // Manually calculated.
telsoa014fcda012018-03-09 14:13:49 +0000522 std::vector<T> outputImage(
523 QuantizedVector<T>(outputTensorInfo.GetQuantizationScale(),
524 outputTensorInfo.GetQuantizationOffset(),
525 {0.f, 0.f})
526 );
527
telsoa01c577f2c2018-08-31 09:22:23 +0100528 // Optionally apply bias to output image.
telsoa014fcda012018-03-09 14:13:49 +0000529 if(biasEnabled)
530 {
531 ApplyBias(outputImage, outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(),
532 biasV, biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
533 outputWidth, outputHeight);
534 }
535
536 LayerTestResult<T, 4> ret(outputTensorInfo);
537 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputImage);
538
539 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
540 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
541
542 armnn::DepthwiseConvolution2dQueueDescriptor data;
543 armnn::WorkloadInfo info;
544 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
545 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
546
547 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
548 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
549
550 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
551 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
552
553 data.m_Weight = &weightsTensor;
telsoa01c577f2c2018-08-31 09:22:23 +0100554 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled.
telsoa014fcda012018-03-09 14:13:49 +0000555 data.m_Parameters.m_StrideX = 1;
556 data.m_Parameters.m_StrideY = 1;
557 data.m_Parameters.m_PadLeft = 0;
558 data.m_Parameters.m_PadRight = 0;
559 data.m_Parameters.m_PadTop = 0;
560 data.m_Parameters.m_PadBottom = 0;
561 data.m_Parameters.m_BiasEnabled = biasEnabled;
562
563 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
564 inputHandle->Allocate();
565 outputHandle->Allocate();
566
567 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
568
surmeh013537c2c2018-05-18 16:31:43 +0100569 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +0000570 workload->Execute();
571
572 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
573
574 return ret;
575}
576
577template<typename T, typename B>
578LayerTestResult<T, 4> DepthwiseConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
579 float qScale,
580 int32_t qOffset,
jimfly01d84216a2018-10-26 12:56:21 +0100581 bool biasEnabled,
582 const armnn::DataLayoutIndexed& layout)
telsoa014fcda012018-03-09 14:13:49 +0000583{
584 unsigned int depthMultiplier = 2;
585
586 unsigned int inputHeight = 8;
587 unsigned int inputWidth = 16;
588 unsigned int inputChannels = 2;
589 unsigned int inputBatchSize = 1;
590
591 unsigned int kernelHeight = 5;
592 unsigned int kernelWidth = 3;
593
594 unsigned int outputHeight = inputHeight - kernelHeight + 1 + 2;
595 unsigned int outputWidth = (inputWidth - kernelWidth + 1)/2;
596 unsigned int outputChannels = inputChannels * depthMultiplier;
597 unsigned int outputBatchSize = inputBatchSize;
598
jimfly01d84216a2018-10-26 12:56:21 +0100599 armnn::TensorInfo inputTensorInfo = GetTensorInfo<T>(
600 inputBatchSize, inputChannels, inputHeight, inputWidth, layout);
601 armnn::TensorInfo outputTensorInfo = GetTensorInfo<T>(
602 outputBatchSize, outputChannels, outputHeight, outputWidth, layout);
603 armnn::TensorInfo kernelDesc = GetTensorInfo<T>(
604 depthMultiplier, inputChannels, kernelHeight, kernelWidth, layout);
telsoa014fcda012018-03-09 14:13:49 +0000605 armnn::TensorInfo biasDesc({outputChannels}, armnn::GetDataType<B>());
606
607 // Set quantization parameters if the requested type is a quantized type.
608 if(armnn::IsQuantizedType<T>())
609 {
610 inputTensorInfo.SetQuantizationScale(qScale);
611 inputTensorInfo.SetQuantizationOffset(qOffset);
612 outputTensorInfo.SetQuantizationScale(qScale);
613 outputTensorInfo.SetQuantizationOffset(qOffset);
614 kernelDesc.SetQuantizationScale(qScale);
615 kernelDesc.SetQuantizationOffset(qOffset);
616 biasDesc.SetQuantizationScale(qScale*qScale);
617 biasDesc.SetQuantizationOffset(0);
618 }
619
jimfly01d84216a2018-10-26 12:56:21 +0100620 // NOTE: originalInputData is in NCHW format
621 std::vector<T> originalInputData = std::vector<T>(
622 QuantizedVector<T>(inputTensorInfo.GetQuantizationScale(), inputTensorInfo.GetQuantizationOffset(), {
623 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,
624 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,
625 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,
626 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,
627 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,
628 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,
629 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,
630 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,
631 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
632 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
633 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
634 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
635 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
636 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
637 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
638 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
639 }));
640 std::vector<T> inputData = originalInputData;
641 // at this point if we require it permute the input data
642 const armnn::PermutationVector NCHWToNHWC = { 0, 3, 1, 2 };
643 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
644 {
645 armnnUtils::Permute(inputTensorInfo.GetShape(), NCHWToNHWC, originalInputData.data(), inputData.data());
646 }
647 auto input = MakeTensor<T, 4>(inputTensorInfo, inputData);
telsoa014fcda012018-03-09 14:13:49 +0000648
649 std::vector<B> biasV(QuantizedVector<B>(biasDesc.GetQuantizationScale(), biasDesc.GetQuantizationOffset(),
650 {0, 2, 1, -1}));
651 auto bias = MakeTensor<B, 1>(biasDesc, biasV);
652
jimfly01d84216a2018-10-26 12:56:21 +0100653 std::vector<T> originalKernelData = std::vector<T>(
654 QuantizedVector<T>(kernelDesc.GetQuantizationScale(), kernelDesc.GetQuantizationOffset(), {
655 1, 1, 1,
656 1, -1, 1,
657 1, 1, 1,
658 1, 1, 1,
659 1, 1, 1,
telsoa014fcda012018-03-09 14:13:49 +0000660
jimfly01d84216a2018-10-26 12:56:21 +0100661 2, 2, 2,
662 2, 2, 2,
663 2, 2, 2,
664 2, 2, 2,
665 2, 2, 2,
telsoa014fcda012018-03-09 14:13:49 +0000666
jimfly01d84216a2018-10-26 12:56:21 +0100667 0, 0, 0,
668 0, -1, 0,
669 0, 0, 0,
670 0, 0, 0,
671 0, 0, 0,
telsoa014fcda012018-03-09 14:13:49 +0000672
jimfly01d84216a2018-10-26 12:56:21 +0100673 0, 0, 0,
674 0, 0, 0,
675 0, 1, 0,
676 0, 0, 0,
677 0, 0, 0
678 }));
679 std::vector<T> kernelData = originalKernelData;
680 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
681 {
682 armnnUtils::Permute(kernelDesc.GetShape(), NCHWToNHWC, originalKernelData.data(), kernelData.data());
683 }
684 auto kernel = MakeTensor<T, 4>(kernelDesc, kernelData);
telsoa014fcda012018-03-09 14:13:49 +0000685
telsoa01c577f2c2018-08-31 09:22:23 +0100686 // Manually calculated.
jimfly01d84216a2018-10-26 12:56:21 +0100687 std::vector<T> originalOutputImage = std::vector<T>(
telsoa014fcda012018-03-09 14:13:49 +0000688 QuantizedVector<T>(outputTensorInfo.GetQuantizationScale(), outputTensorInfo.GetQuantizationOffset(), {
689 3.5f, 3.5f, 3.5f, 3.5f, 3.5f, 3.5f, 3.5f,
690 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f, 6.0f,
691 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,
692 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f,
693 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f,
694 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f,
695
696 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
697 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
698 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
699 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
700 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
701 -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f,
702
703 8.0f, 8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
704 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
705 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
706 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
707 10.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
708 8.0f, 8.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
709
710 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
711 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
712 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
713 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
714 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
715 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
716 }));
717
telsoa01c577f2c2018-08-31 09:22:23 +0100718 // Optionally apply bias to output image.
telsoa014fcda012018-03-09 14:13:49 +0000719 if(biasEnabled)
720 {
jimfly01d84216a2018-10-26 12:56:21 +0100721 ApplyBias(originalOutputImage,
722 outputTensorInfo.GetQuantizationScale(),
723 outputTensorInfo.GetQuantizationOffset(),
724 biasV,
725 biasDesc.GetQuantizationScale(),
726 biasDesc.GetQuantizationOffset(),
727 outputWidth,
728 outputHeight);
telsoa014fcda012018-03-09 14:13:49 +0000729 }
730
731 LayerTestResult<T, 4> ret(outputTensorInfo);
jimfly01d84216a2018-10-26 12:56:21 +0100732 std::vector<T> outputImage = originalOutputImage;
733 if (layout.GetDataLayout() == armnn::DataLayout::NHWC)
734 {
735 armnnUtils::Permute(outputTensorInfo.GetShape(), NCHWToNHWC, originalOutputImage.data(), outputImage.data());
736 }
737
telsoa014fcda012018-03-09 14:13:49 +0000738 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputImage);
739
740 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
741 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
742
743 armnn::DepthwiseConvolution2dQueueDescriptor data;
744 armnn::WorkloadInfo info;
745 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
746 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
747
748 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
749 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
750
751 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
752 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
753
754 data.m_Weight = &weightsTensor;
telsoa01c577f2c2018-08-31 09:22:23 +0100755 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled.
telsoa014fcda012018-03-09 14:13:49 +0000756 data.m_Parameters.m_StrideX = 2;
757 data.m_Parameters.m_StrideY = 1;
758 data.m_Parameters.m_PadLeft = 0;
759 data.m_Parameters.m_PadRight = 0;
760 data.m_Parameters.m_PadTop = 1;
761 data.m_Parameters.m_PadBottom = 1;
762 data.m_Parameters.m_BiasEnabled = biasEnabled;
jimfly01d84216a2018-10-26 12:56:21 +0100763 data.m_Parameters.m_DataLayout = layout.GetDataLayout();
telsoa014fcda012018-03-09 14:13:49 +0000764
765 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
766 inputHandle->Allocate();
767 outputHandle->Allocate();
768
769 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
770
surmeh013537c2c2018-05-18 16:31:43 +0100771 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +0000772 workload->Execute();
773
774 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
775
776 return ret;
777}
778
Nikhil Rajcec6b652018-10-12 13:51:57 +0100779template<typename T, typename B>
780LayerTestResult<T, 4> DepthwiseConvolution2dNhwcTestImpl(armnn::IWorkloadFactory& workloadFactory,
781 const boost::multi_array<T, 4>& input,
782 const boost::multi_array<T, 4>& kernel,
783 const boost::multi_array<B, 1>& bias,
784 const boost::multi_array<T, 4>& outputExpected,
785 float qScale,
786 int32_t qOffset,
787 uint32_t padLeft = 0,
788 uint32_t padTop = 0,
789 uint32_t padRight = 0,
790 uint32_t padBottom = 0,
791 uint32_t strideX = 1,
792 uint32_t strideY = 1)
793{
794 unsigned int inputNum = boost::numeric_cast<unsigned int>(input.shape()[0]);
795 unsigned int inputChannels = boost::numeric_cast<unsigned int>(input.shape()[3]);
796 unsigned int inputHeight = boost::numeric_cast<unsigned int>(input.shape()[1]);
797 unsigned int inputWidth = boost::numeric_cast<unsigned int>(input.shape()[2]);
798
799 unsigned int kernelChanMul = boost::numeric_cast<unsigned int>(kernel.shape()[0]);
800 unsigned int kernelChannels = boost::numeric_cast<unsigned int>(kernel.shape()[3]);
801 unsigned int kernelHeight = boost::numeric_cast<unsigned int>(kernel.shape()[1]);
802 unsigned int kernelWidth = boost::numeric_cast<unsigned int>(kernel.shape()[2]);
803
804 unsigned int outputNum = boost::numeric_cast<unsigned int>(outputExpected.shape()[0]);
805 unsigned int outputChannels = boost::numeric_cast<unsigned int>(outputExpected.shape()[3]);
806 unsigned int outputHeight = boost::numeric_cast<unsigned int>(outputExpected.shape()[1]);
807 unsigned int outputWidth = boost::numeric_cast<unsigned int>(outputExpected.shape()[2]);
808
809 // Creates the tensors.
810 armnn::TensorInfo inputTensorInfo({inputNum, inputHeight, inputWidth, inputChannels}, armnn::GetDataType<T>());
811 armnn::TensorInfo outputTensorInfo({outputNum, outputHeight, outputWidth, outputChannels},
812 armnn::GetDataType<T>());
813 armnn::TensorInfo kernelDesc({kernelChanMul, kernelHeight, kernelWidth, kernelChannels}, armnn::GetDataType<T>());
814 armnn::TensorInfo biasDesc({static_cast<unsigned int>(bias.size())}, armnn::GetDataType<B>());
815
816 // Set quantization parameters if the requested type is a quantized type.
817 if (armnn::IsQuantizedType<T>())
818 {
819 inputTensorInfo.SetQuantizationScale(qScale);
820 inputTensorInfo.SetQuantizationOffset(qOffset);
821 outputTensorInfo.SetQuantizationScale(qScale);
822 outputTensorInfo.SetQuantizationOffset(qOffset);
823 kernelDesc.SetQuantizationScale(qScale);
824 kernelDesc.SetQuantizationOffset(qOffset);
825 biasDesc.SetQuantizationScale(qScale*qScale);
826 biasDesc.SetQuantizationOffset(0);
827 }
828
829 // Construct the input data.
830 std::vector<T> inputData;
831 inputData.assign(input.data(), input.data() + inputHeight*inputWidth*inputChannels);
832 auto batchedInput = MakeTensor<T, 4>(inputTensorInfo, inputData);
833
834 // Construct the output data, with bias applied, as appropriate.
835 std::vector<T> outputData;
836 outputData.assign(outputExpected.data(), outputExpected.data() + outputHeight*outputWidth*outputChannels);
837
838 LayerTestResult<T, 4> ret(outputTensorInfo);
839 ret.outputExpected = MakeTensor<T, 4>(outputTensorInfo, outputData);
840
841 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
842 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
843
844 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
845 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
846
847 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
848
849 armnn::DepthwiseConvolution2dQueueDescriptor data;
850 data.m_Weight = &weightsTensor;
851 data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - it can be a source of bugs.
852 data.m_Parameters.m_StrideX = strideX;
853 data.m_Parameters.m_StrideY = strideY;
854 data.m_Parameters.m_PadLeft = padLeft;
855 data.m_Parameters.m_PadRight = padRight;
856 data.m_Parameters.m_PadTop = padTop;
857 data.m_Parameters.m_PadBottom = padBottom;
858 data.m_Parameters.m_DataLayout = armnn::DataLayout::NHWC;
859
860 armnn::WorkloadInfo info;
861 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
862 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
863
864 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
865
866 inputHandle->Allocate();
867 outputHandle->Allocate();
868
869 CopyDataToITensorHandle(inputHandle.get(), &batchedInput[0][0][0][0]);
870
871 workloadFactory.Finalize();
872 workload->Execute();
873
874 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
875
876 return ret;
877}
878
telsoa014fcda012018-03-09 14:13:49 +0000879template<typename T>
880LayerTestResult<T,4> Convolution1dTestImpl(armnn::IWorkloadFactory& workloadFactory,
881 float qScale,
882 int32_t qOffset,
883 bool biasEnabled)
884{
885 using B = typename FullyConnectedBiasTypeForInputType<T>::Type;
886
telsoa01c577f2c2018-08-31 09:22:23 +0100887 // Until we have a specialist 1D convolution layer, we can fake one using
telsoa014fcda012018-03-09 14:13:49 +0000888 // 2D convolution with the final dimension set to 1.
889 // I don't anticipate this being particularly slow, given that convolution is implemented
890 // as a matrix multiplication, at which point dimension doesn't matter.
891
892 unsigned int batchSize = 1;
893 unsigned int inputChannels = 2;
894 unsigned int outputChannels = 3;
telsoa01c577f2c2018-08-31 09:22:23 +0100895 unsigned int inputSize = 5; // The 1D size (could view as 'width' or 'height').
telsoa014fcda012018-03-09 14:13:49 +0000896 unsigned int kernelSize = 3;
897 unsigned int padSize = 2;
898 unsigned int stride = 1;
telsoa01c577f2c2018-08-31 09:22:23 +0100899 unsigned int outputSize = 7; // (inputSize + 2 * padSize - kernelSize + 1) / stride.
telsoa014fcda012018-03-09 14:13:49 +0000900
901 armnn::TensorInfo inputInfo({batchSize, inputChannels, inputSize, 1}, armnn::GetDataType<T>());
902 armnn::TensorInfo outputInfo({batchSize, outputChannels, outputSize, 1}, armnn::GetDataType<T>());
903 armnn::TensorInfo kernelInfo({outputChannels, inputChannels, kernelSize, 1}, armnn::GetDataType<T>());
904 armnn::TensorInfo biasInfo({outputChannels}, armnn::GetDataType<B>());
905
906 // Set quantization parameters if the requested type is a quantized type.
907 if(armnn::IsQuantizedType<T>())
908 {
909 inputInfo.SetQuantizationScale(qScale);
910 inputInfo.SetQuantizationOffset(qOffset);
911 outputInfo.SetQuantizationScale(qScale);
912 outputInfo.SetQuantizationOffset(qOffset);
913 kernelInfo.SetQuantizationScale(qScale);
914 kernelInfo.SetQuantizationOffset(qOffset);
915 biasInfo.SetQuantizationScale(inputInfo.GetQuantizationScale()*kernelInfo.GetQuantizationScale());
916 biasInfo.SetQuantizationOffset(0);
917 }
918
919 std::vector<T> inputData(
920 QuantizedVector<T>(inputInfo.GetQuantizationScale(), inputInfo.GetQuantizationOffset(), {
921 5.0f, -2.0f, 2.5f, 0.0f, 1.0f,
922 -3.0f, 3.2f, 5.0f, 2.0f, 3.0f,
923 }));
924
925 std::vector<T> kernelData(
926 QuantizedVector<T>(kernelInfo.GetQuantizationScale(), kernelInfo.GetQuantizationOffset(), {
927 1.0f, 0.0f, 0.0f,
928 0.0f, 2.0f, -1.5f,
929
930 0.0f, 0.0f, 0.0f,
931 0.2f, 0.2f, 0.2f,
932
933 0.5f, 0.0f, 0.5f,
934 0.0f, -1.0f, 0.0f
935 }));
936
937 std::vector<B> biasData(
938 QuantizedVector<B>(biasInfo.GetQuantizationScale(), biasInfo.GetQuantizationOffset(), {
939 1.0f, 0.0f, 0.0f
940 }));
941
942 std::vector<T> outputData(
943 QuantizedVector<T>(outputInfo.GetQuantizationScale(), outputInfo.GetQuantizationOffset(), {
944 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,
945 -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,
946 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
947 }));
948
telsoa01c577f2c2018-08-31 09:22:23 +0100949 // Optionally apply bias to output image.
telsoa014fcda012018-03-09 14:13:49 +0000950 if(biasEnabled)
951 {
952 ApplyBias(outputData, outputInfo.GetQuantizationScale(), outputInfo.GetQuantizationOffset(),
953 biasData, biasInfo.GetQuantizationScale(), biasInfo.GetQuantizationOffset(),
954 1, outputSize);
955 }
956
957 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputInfo);
958 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputInfo);
959
960 armnn::Convolution2dQueueDescriptor data;
961 armnn::WorkloadInfo info;
962 armnn::ScopedCpuTensorHandle weightsTensor(kernelInfo);
963 armnn::ScopedCpuTensorHandle biasTensor(biasInfo);
964
965 AllocateAndCopyDataToITensorHandle(&weightsTensor, kernelData.data());
966 AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data());
967
968 AddInputToWorkload(data, info, inputInfo, inputHandle.get());
969 AddOutputToWorkload(data, info, outputInfo, outputHandle.get());
970
971 data.m_Weight = &weightsTensor;
972 data.m_Bias = &biasTensor;
973 data.m_Parameters.m_StrideX = 1;
974 data.m_Parameters.m_StrideY = stride;
975 data.m_Parameters.m_PadLeft = 0;
976 data.m_Parameters.m_PadRight = 0;
977 data.m_Parameters.m_PadTop = padSize;
978 data.m_Parameters.m_PadBottom = padSize;
979 data.m_Parameters.m_BiasEnabled = biasEnabled;
980
981 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
982 inputHandle->Allocate();
983 outputHandle->Allocate();
984
985 CopyDataToITensorHandle(inputHandle.get(), inputData.data());
986
surmeh013537c2c2018-05-18 16:31:43 +0100987 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +0000988 workload->Execute();
989
telsoa01c577f2c2018-08-31 09:22:23 +0100990 // Output
telsoa014fcda012018-03-09 14:13:49 +0000991 LayerTestResult<T,4> ret(outputInfo);
992 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
993 ret.outputExpected = MakeTensor<T, 4>(outputInfo, outputData);
994 return ret;
995}
996
997
998
999template<typename T>
1000LayerTestResult<T,4> CompareConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
1001 armnn::IWorkloadFactory& refWorkloadFactory)
1002{
1003 unsigned int inputHeight = 8;
1004 unsigned int inputWidth = 16;
1005 unsigned int inputChannels = 3;
1006 unsigned int inputNum = 5;
1007
1008 unsigned int kernelHeight = 3;
1009 unsigned int kernelWidth = 3;
1010
1011 unsigned int strideX = 2;
1012 unsigned int strideY = 3;
1013 unsigned int padX = 1;
1014 unsigned int padY = 1;
1015
1016 unsigned int outputNum = inputNum;
1017 unsigned int outputChannels = 2;
1018 unsigned int outputHeight = (inputHeight + 2 * padY - kernelHeight + strideY) / strideY;
1019 unsigned int outputWidth = (inputWidth + 2 * padX - kernelWidth + strideX) / strideX;
1020
1021 armnn::TensorInfo inputTensorInfo;
1022 armnn::TensorInfo outputTensorInfo;
1023 armnn::TensorInfo kernelDesc;
1024 armnn::TensorInfo biasDesc;
1025
1026 unsigned int inputShape[] = {inputNum, inputChannels, inputHeight, inputWidth};
1027 unsigned int outputShape[] = {outputNum, outputChannels, outputHeight, outputWidth};
1028 unsigned int kernelShape[] = {outputChannels, inputChannels, kernelHeight, kernelWidth};
1029 unsigned int biasShape[] = {outputChannels};
1030
1031 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::GetDataType<T>());
1032 outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::GetDataType<T>());
1033 kernelDesc = armnn::TensorInfo(4, kernelShape, armnn::GetDataType<T>());
1034 biasDesc = armnn::TensorInfo(1, biasShape, armnn::GetDataType<T>());
1035
1036 LayerTestResult<T,4> ret(outputTensorInfo);
1037
1038 auto input = MakeRandomTensor<T, 4>(inputTensorInfo, 124908);
1039 auto kernel = MakeRandomTensor<T, 4>(kernelDesc, 891234);
1040 auto bias = MakeRandomTensor<T, 1>(biasDesc, 1028);
1041
1042 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1043 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1044
1045 armnn::Convolution2dQueueDescriptor data;
1046 armnn::WorkloadInfo info;
1047 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1048 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1049
1050 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1051 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1052
1053 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1054 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1055 data.m_Weight = &weightsTensor;
1056 data.m_Bias = &biasTensor;
1057 data.m_Parameters.m_StrideX = strideX;
1058 data.m_Parameters.m_StrideY = strideY;
1059 data.m_Parameters.m_PadLeft = padX;
1060 data.m_Parameters.m_PadRight = padX;
1061 data.m_Parameters.m_PadTop = padY;
1062 data.m_Parameters.m_PadBottom = padY;
1063 data.m_Parameters.m_BiasEnabled = true;
1064
1065 std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refWorkloadFactory.CreateTensorHandle(outputTensorInfo);
1066 std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refWorkloadFactory.CreateTensorHandle(inputTensorInfo);
1067
1068 armnn::Convolution2dQueueDescriptor refData = data;
1069 armnn::WorkloadInfo refInfo = info;
1070 SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
1071 SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
1072
1073 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConvolution2d(data, info);
1074 std::unique_ptr<armnn::IWorkload> workloadRef = refWorkloadFactory.CreateConvolution2d(refData, refInfo);
1075
1076 outputHandleRef->Allocate();
1077 inputHandleRef->Allocate();
1078
1079 inputHandle->Allocate();
1080 outputHandle->Allocate();
1081
1082 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
1083 CopyDataToITensorHandle(inputHandleRef.get(), &input[0][0][0][0]);
1084
surmeh013537c2c2018-05-18 16:31:43 +01001085 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +00001086 workload->Execute();
surmeh013537c2c2018-05-18 16:31:43 +01001087 refWorkloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +00001088 workloadRef->Execute();
1089
1090 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1091 CopyDataFromITensorHandle(&ret.outputExpected[0][0][0][0], outputHandleRef.get());
1092
1093 return ret;
1094}
1095
1096template<typename T>
1097LayerTestResult<T, 4> CompareDepthwiseConvolution2dTestImpl(armnn::IWorkloadFactory& workloadFactory,
jimfly017af00da2018-10-31 14:43:53 +00001098 armnn::IWorkloadFactory& refWorkloadFactory,
1099 const armnn::DataLayoutIndexed& layout)
telsoa014fcda012018-03-09 14:13:49 +00001100{
1101 unsigned int inputHeight = 8;
1102 unsigned int inputWidth = 16;
1103 unsigned int inputChannels = 3;
1104 unsigned int inputNum = 5;
1105
1106 unsigned int kernelHeight = 3;
1107 unsigned int kernelWidth = 3;
1108 unsigned int channelMultiplier = 1;
1109
1110 unsigned int strideX = 2;
1111 unsigned int strideY = 3;
1112 unsigned int padX = 1;
1113 unsigned int padY = 1;
1114
1115 unsigned int outputNum = inputNum;
1116 unsigned int outputChannels = inputChannels * channelMultiplier;
1117 unsigned int outputHeight = (inputHeight + 2 * padY - kernelHeight + strideY) / strideY;
1118 unsigned int outputWidth = (inputWidth + 2 * padX - kernelWidth + strideX) / strideX;
1119
1120 armnn::TensorInfo inputTensorInfo;
1121 armnn::TensorInfo outputTensorInfo;
1122 armnn::TensorInfo kernelDesc;
1123 armnn::TensorInfo biasDesc;
1124
jimfly017af00da2018-10-31 14:43:53 +00001125
1126 std::vector<unsigned int> inputShape;
1127 std::vector<unsigned int> outputShape;
1128 std::vector<unsigned int> kernelShape;
1129 std::vector<unsigned int> biasShape= { outputChannels };
1130 switch (layout.GetDataLayout())
1131 {
1132 case armnn::DataLayout::NCHW:
1133 inputShape = { inputNum, inputChannels, inputHeight, inputWidth };
1134 outputShape = { outputNum, outputChannels, outputHeight, outputWidth };
1135 kernelShape = { channelMultiplier, inputChannels, kernelHeight, kernelWidth };
1136 break;
1137 case armnn::DataLayout ::NHWC:
1138 inputShape = { inputNum, inputHeight, inputWidth, inputChannels };
1139 outputShape = { outputNum, outputHeight, outputWidth, outputChannels };
1140 kernelShape = { channelMultiplier, kernelHeight, kernelWidth, inputChannels };
1141 break;
1142 default:
1143 throw armnn::InvalidArgumentException("unknown data layout ["
1144 + std::to_string(static_cast<int>(layout.GetDataLayout())) + "]");
1145 }
telsoa014fcda012018-03-09 14:13:49 +00001146
1147 float inputsQScale = armnn::IsQuantizedType<T>() ? 1.0f : 0;
1148 float outputQScale = armnn::IsQuantizedType<T>() ? 2.0f : 0;
1149 int32_t qOffset = 0;
1150
jimfly017af00da2018-10-31 14:43:53 +00001151 inputTensorInfo = armnn::TensorInfo(4, inputShape.data(), armnn::GetDataType<T>(), inputsQScale, qOffset);
1152 outputTensorInfo = armnn::TensorInfo(4, outputShape.data(), armnn::GetDataType<T>(), outputQScale, qOffset);
1153 kernelDesc = armnn::TensorInfo(4, kernelShape.data(), armnn::GetDataType<T>(), inputsQScale, qOffset);
1154 biasDesc = armnn::TensorInfo(
1155 1, biasShape.data(), armnn::GetBiasDataType(armnn::GetDataType<T>()), inputsQScale, qOffset);
telsoa014fcda012018-03-09 14:13:49 +00001156
1157 LayerTestResult<T, 4> ret(outputTensorInfo);
1158
1159 auto input = MakeRandomTensor<T, 4>(inputTensorInfo, 124908, 0.0f, 255.0f);
1160 auto kernel = MakeRandomTensor<T, 4>(kernelDesc, 891234, 0.0f, 255.0f);
jimfly01d84216a2018-10-26 12:56:21 +01001161 auto bias = MakeRandomTensor<typename FullyConnectedBiasTypeForInputType<T>::Type, 1>(
1162 biasDesc, 1028, 0.0f, 255.0f);
telsoa014fcda012018-03-09 14:13:49 +00001163
1164 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
1165 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1166
1167 armnn::DepthwiseConvolution2dQueueDescriptor data;
1168 armnn::WorkloadInfo info;
1169 armnn::ScopedCpuTensorHandle weightsTensor(kernelDesc);
1170 armnn::ScopedCpuTensorHandle biasTensor(biasDesc);
1171
1172 AllocateAndCopyDataToITensorHandle(&weightsTensor, &kernel[0][0][0][0]);
1173 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
1174
1175 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
1176 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1177 data.m_Weight = &weightsTensor;
1178 data.m_Bias = &biasTensor;
1179 data.m_Parameters.m_StrideX = strideX;
1180 data.m_Parameters.m_StrideY = strideY;
1181 data.m_Parameters.m_PadLeft = padX;
1182 data.m_Parameters.m_PadRight = padX;
1183 data.m_Parameters.m_PadTop = padY;
1184 data.m_Parameters.m_PadBottom = padY;
1185 data.m_Parameters.m_BiasEnabled = true;
jimfly017af00da2018-10-31 14:43:53 +00001186 data.m_Parameters.m_DataLayout = layout.GetDataLayout();
telsoa014fcda012018-03-09 14:13:49 +00001187
1188 std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refWorkloadFactory.CreateTensorHandle(outputTensorInfo);
1189 std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refWorkloadFactory.CreateTensorHandle(inputTensorInfo);
1190
1191 armnn::DepthwiseConvolution2dQueueDescriptor refData = data;
1192 armnn::WorkloadInfo refInfo = info;
1193 SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
1194 SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
1195
1196 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateDepthwiseConvolution2d(data, info);
1197 std::unique_ptr<armnn::IWorkload> workloadRef = refWorkloadFactory.CreateDepthwiseConvolution2d(refData, refInfo);
1198
1199 outputHandleRef->Allocate();
1200 inputHandleRef->Allocate();
1201
1202 inputHandle->Allocate();
1203 outputHandle->Allocate();
1204
1205 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
1206 CopyDataToITensorHandle(inputHandleRef.get(), &input[0][0][0][0]);
1207
surmeh013537c2c2018-05-18 16:31:43 +01001208 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +00001209 workload->Execute();
surmeh013537c2c2018-05-18 16:31:43 +01001210 refWorkloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +00001211 workloadRef->Execute();
1212
1213 CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
1214 CopyDataFromITensorHandle(&ret.outputExpected[0][0][0][0], outputHandleRef.get());
1215
1216 return ret;
1217}