blob: 29476e522ade77e373334793a7e05465ca318a88 [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 "ConcatTestImpl.hpp"
7
8#include <Permute.hpp>
9#include <ResolveType.hpp>
10
11#include <armnn/ArmNN.hpp>
12
13#include <backendsCommon/test/TensorCopyUtils.hpp>
14#include <backendsCommon/test/WorkloadTestUtils.hpp>
15
16#include <test/TensorHelpers.hpp>
17
18//
19// Helper functions and templates
20//
21
22armnn::OriginsDescriptor CreateDescriptorForConcat(
23 const std::vector<armnn::TensorInfo> & inputTensorInfos,
24 unsigned int concatDim)
25{
26 std::vector<armnn::TensorShape> shapes;
27 shapes.reserve(inputTensorInfos.size());
28 for (const armnn::TensorInfo& it: inputTensorInfos)
29 {
30 shapes.push_back(it.GetShape());
31 }
32
33 return armnn::CreateDescriptorForConcatenation(shapes.begin(), shapes.end(), concatDim);
34}
35
36//
37// Concat is only supported for N and C dimensions for NCHW and the inner most dimension
38// In case of <4 dimensions we need to make sure that the concat dimensions are at least
39// the 3rd slowest iterating one or the inner most dimension.
40//
41
42bool NeedPermuteForConcat(
43 const std::vector<armnn::TensorInfo> & inputTensorInfos,
44 unsigned int concatDim)
45{
46 // See note above. Additionally we expect the input shapes to have the
47 // same number of dimensions.
48 unsigned int nDimensions = 0;
49
50 // Determine the number of dimensions as well as sanity check them
51 // agains test implementation issues.
52 for (auto && tensorInfo : inputTensorInfos)
53 {
54 if (!nDimensions)
55 {
56 nDimensions = tensorInfo.GetShape().GetNumDimensions();
57 }
58 else
59 {
60 BOOST_ASSERT_MSG(nDimensions == tensorInfo.GetShape().GetNumDimensions(),
61 "Input shapes must have the same number of dimensions");
62 }
63 }
64
65 return (nDimensions < 3 || (nDimensions == 3 && (nDimensions-concatDim) < 3 && (nDimensions-concatDim) != 1));
66}
67
68armnn::TensorShape ExpandTensorShapeTo3dForPermute(const armnn::TensorShape & inputShape)
69{
70 unsigned int numDims = inputShape.GetNumDimensions();
71 if (numDims >= 3)
72 {
73 // Nothing to do if the inputShape has at least 3 dimensions.
74 return inputShape;
75 }
76
77 std::vector<unsigned int> newDims(size_t(3), 1u);
78 unsigned int expandedBy = 3 - numDims;
79 for (unsigned int i=0; i<numDims; ++i)
80 {
81 newDims[expandedBy+i] = inputShape[i];
82 }
83 return armnn::TensorShape(3u, &newDims[0]);
84}
85
86void Generate3dPermuteVectorForConcat(
87 unsigned int numDimensions,
88 unsigned int & concatDim,
89 std::pair<armnn::PermutationVector, armnn::PermutationVector> & permutations)
90{
91 BOOST_ASSERT_MSG(numDimensions <= 3,
92 "Only dimensions 1,2 and 3 are supported by this helper");
93 unsigned int expandedBy = 3 - numDimensions;
94 unsigned int expandedConcatAxis = concatDim + expandedBy;
95
96 if (expandedConcatAxis == 2)
97 {
98 concatDim = 0;
99 armnn::PermutationVector forwardPermutation({1, 2, 0});
100 armnn::PermutationVector reversePermutation({2, 0, 1});
101 permutations = std::make_pair(forwardPermutation, reversePermutation);
102 }
103 else if (expandedConcatAxis == 1)
104 {
105 concatDim = 0;
106 armnn::PermutationVector forwardPermutation({2, 0, 1});
107 armnn::PermutationVector reversePermutation({1, 2, 0});
108 permutations = std::make_pair(forwardPermutation, reversePermutation);
109 }
110 else
111 {
112 BOOST_ASSERT(expandedConcatAxis == 0);
113 concatDim = 0;
114 }
115}
116
117template<typename T> void PermuteTensorData(
118 armnn::IWorkloadFactory& workloadFactory,
119 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
120 const armnn::PermutationVector& mappings,
121 armnn::TensorInfo & inputTensorInfo,
122 const T * inputData,
123 std::vector<T>& outputData)
124{
125 BOOST_ASSERT_MSG(inputData != nullptr, "inputData must not be null");
126 if (inputData == nullptr)
127 {
128 // Nullptr is an error in the test. By returning without doing the concatenation
129 // I expect the caller to fail the test. It still makes sense to report this as
130 // an assert for Debug builds.
131 return;
132 }
133
134 armnn::TensorInfo outputTensorInfo = armnnUtils::Permuted(inputTensorInfo, mappings);
135
136 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
137 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
138
139 armnn::PermuteQueueDescriptor queueDescriptor;
140 queueDescriptor.m_Parameters = armnn::PermuteDescriptor{mappings};
141 armnn::WorkloadInfo workloadInfo;
142 AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfo, inputHandle.get());
143 AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get());
144
145 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreatePermute(queueDescriptor, workloadInfo);
146
147 inputHandle->Allocate();
148 outputHandle->Allocate();
149
150 CopyDataToITensorHandle(inputHandle.get(), inputData);
151
152 workload->PostAllocationConfigure();
153 workload->Execute();
154
155 outputData.resize(outputTensorInfo.GetNumElements());
156 CopyDataFromITensorHandle(&outputData[0], outputHandle.get());
157 inputTensorInfo = outputTensorInfo;
158}
159
160//
161// Permute the input tensors so we can do a supported concatenation.
162// Also treat lower than 3d tensors as 3d by adding dummy 1 dimensions
163// at the front. Finally this function tells what the output shape
164// of the permuted concatenated tensor is going to be.
165//
166template<typename T> void PermuteInputsForConcat(
167 armnn::IWorkloadFactory& workloadFactory,
168 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
169 std::vector<armnn::TensorInfo> & inputTensorInfos,
170 std::vector<T *> & inputData,
171 std::vector<std::vector<T>> & inputDataStorage,
172 armnn::PermutationVector & permuteVector,
173 unsigned int & concatDim,
174 armnn::TensorInfo & outputTensorInfo)
175{
176 BOOST_ASSERT_MSG(inputTensorInfos.size() > 1,
177 "Expecting more than one tensor to be concatenated here");
178
179 unsigned int numDims = 0;
180 unsigned int nthInput = 0;
181 const armnn::PermutationVector identity({0, 1, 2});
182
183 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutations =
184 std::make_pair(identity, identity);
185
186 inputDataStorage.resize(inputData.size());
187
188 for (auto && tensorInfo : inputTensorInfos)
189 {
190 if (numDims == 0)
191 {
192 numDims = tensorInfo.GetShape().GetNumDimensions();
193 Generate3dPermuteVectorForConcat(numDims, concatDim, permutations);
194
195 // Store the reverese permutation.
196 permuteVector = permutations.second;
197 BOOST_ASSERT_MSG(!permuteVector.IsEqual(identity),
198 "Test logic error, we don't need permutation, so we shouldn't arrive here");
199 }
200 else
201 {
202 BOOST_ASSERT_MSG(numDims == tensorInfo.GetShape().GetNumDimensions(),
203 "All inputs must have the same number of dimensions");
204 }
205
206 armnn::TensorInfo newTensorInfo = tensorInfo;
207 newTensorInfo.SetShape(ExpandTensorShapeTo3dForPermute(tensorInfo.GetShape()));
208
209 PermuteTensorData<T>(workloadFactory,
210 memoryManager,
211 permutations.first,
212 newTensorInfo,
213 inputData[nthInput],
214 inputDataStorage[nthInput]);
215
216 inputData[nthInput] = inputDataStorage[nthInput].data();
217 inputTensorInfos[nthInput] = newTensorInfo;
218
219 ++nthInput;
220 }
221
222 outputTensorInfo.SetShape(
223 armnnUtils::Permuted(
224 ExpandTensorShapeTo3dForPermute(outputTensorInfo.GetShape()),
225 permutations.first));
226}
227
228//
229// This is the pair of PermuteInputsForConcat(...) which permutes back
230// the output of the concatenation so we can check it against an expected
231// output.
232//
233template <typename T> void PermuteOutputForConcat(
234 armnn::IWorkloadFactory& workloadFactory,
235 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
236 const armnn::TensorInfo & tensorInfo,
237 const armnn::PermutationVector & permuteVector,
238 std::unique_ptr<armnn::ITensorHandle> && inputDataHandle,
239 T * data)
240{
241 BOOST_ASSERT_MSG(data != nullptr, "data must not be null");
242 if (data == nullptr)
243 {
244 // Nullptr is an error in the test. By returning without doing the permutation
245 // I expect the caller to fail the test. It still makes sense to report this as
246 // an assert for Debug builds.
247 return;
248 }
249
250 armnn::TensorInfo resultTensorInfo = tensorInfo;
251 std::vector<T> inputData(tensorInfo.GetNumElements());
252 std::vector<T> outputData;
253
254 CopyDataFromITensorHandle(&inputData[0], inputDataHandle.get());
255
256 PermuteTensorData<T>(workloadFactory,
257 memoryManager,
258 permuteVector,
259 resultTensorInfo,
260 &inputData[0],
261 outputData);
262
263 ::memcpy(data, &outputData[0], sizeof(T)*outputData.size());
264}
265
266template<typename T> void Concatenate(
267 armnn::IWorkloadFactory& workloadFactory,
268 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
269 std::initializer_list<const armnn::TensorInfo> inputTensorInfosOrig,
270 std::initializer_list<T *> inputsOrig,
271 const armnn::TensorInfo& outputTensorInfoOrig,
272 T * output,
273 unsigned int concatDim,
274 bool useSubtensor)
275{
276 BOOST_ASSERT_MSG(output != nullptr, "output must not be null");
277 if (output == nullptr)
278 {
279 // Nullptr is an error in the test. By returning without doing the permutation
280 // I expect the caller to fail the test. It still makes sense to report this as
281 // an assert for Debug builds.
282 return;
283 }
284
285 // Saves a copy of the parameters which we might need to change.
286 std::vector<armnn::TensorInfo> inputTensorInfos(inputTensorInfosOrig.begin(), inputTensorInfosOrig.end());
287 std::vector<T *> inputs = inputsOrig;
288 armnn::TensorInfo outputTensorInfo = outputTensorInfoOrig;
289
290 armnn::PermutationVector permuteVector{0, 1, 2};
291
292 // Holds and automatically releases memory for the reshaped input data.
293 std::vector<std::vector<T>> tmpInputDataStorage;
294
295 const size_t inputCount = inputTensorInfos.size();
296
297 bool needPermuteForConcat = NeedPermuteForConcat(inputTensorInfos, concatDim);
298
299 if (needPermuteForConcat)
300 {
301 //
302 // We need to permute the inputs, because concatenation along
303 // the requested axis is not supported.
304 //
305 PermuteInputsForConcat<T>(workloadFactory,
306 memoryManager,
307 inputTensorInfos,
308 inputs,
309 tmpInputDataStorage,
310 permuteVector,
311 concatDim,
312 outputTensorInfo);
313 }
314
315 armnn::WorkloadInfo workloadInfo;
316
317 std::vector<std::unique_ptr<armnn::ITensorHandle>> inputHandles;
318 inputHandles.reserve(inputCount);
319
320 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
321
322 armnn::ConcatQueueDescriptor queueDescriptor;
323 armnn::OriginsDescriptor viewsDescriptor = CreateDescriptorForConcat(inputTensorInfos, concatDim);
324 queueDescriptor.m_Parameters = viewsDescriptor;
325
326 if (useSubtensor)
327 {
328 queueDescriptor.m_ViewOrigins.reserve(viewsDescriptor.GetNumViews());
329 for (unsigned int i = 0; i < viewsDescriptor.GetNumViews(); ++i)
330 {
331 queueDescriptor.m_ViewOrigins.emplace_back(std::vector<unsigned int>(viewsDescriptor.GetViewOrigin(i),
332 viewsDescriptor.GetViewOrigin(i) + viewsDescriptor.GetNumDimensions()));
333 }
334
335 outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
336
337 const bool subTensorsSupported = workloadFactory.SupportsSubTensors();
338 for (unsigned int i = 0; i < inputCount; ++i)
339 {
340 const armnn::TensorInfo& inputTensorInfo = inputTensorInfos[i];
341 std::unique_ptr<armnn::ITensorHandle> inputHandle =
342 subTensorsSupported ?
343 workloadFactory.CreateSubTensorHandle(*outputHandle,
344 inputTensorInfo.GetShape(),
345 queueDescriptor.m_ViewOrigins[i].m_Origin.data()) :
346 workloadFactory.CreateTensorHandle(inputTensorInfo);
347
348 inputHandles.emplace_back(std::move(inputHandle));
349 }
350
351 }
352 else
353 {
354 for (unsigned int i = 0; i < inputCount; ++i)
355 {
356 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfos[i]);
357 inputHandles.emplace_back(std::move(inputHandle));
358 }
359 }
360
361 for (unsigned int i = 0; i < inputCount; ++i)
362 {
363 AddInputToWorkload(queueDescriptor, workloadInfo, inputTensorInfos[i], inputHandles[i].get());
364 }
365
366 AddOutputToWorkload(queueDescriptor, workloadInfo, outputTensorInfo, outputHandle.get());
367
368 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(queueDescriptor, workloadInfo);
369
370 for (auto& inputHandle : inputHandles)
371 {
372 inputHandle->Allocate();
373 }
374
375 outputHandle->Allocate();
376
377 unsigned int nextInputId = 0;
378 for (auto& inputHandle : inputHandles)
379 {
380 CopyDataToITensorHandle(inputHandle.get(), inputs[nextInputId]);
381 ++nextInputId;
382 }
383
384 workload->PostAllocationConfigure();
385 workload->Execute();
386
387 if (needPermuteForConcat)
388 {
389 PermuteOutputForConcat<T>(workloadFactory,
390 memoryManager,
391 outputTensorInfo,
392 permuteVector,
393 std::move(outputHandle),
394 output);
395 }
396 else
397 {
398 CopyDataFromITensorHandle(output, outputHandle.get());
399 }
400}
401
402//
403// Implementation templates
404//
405
406template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
407LayerTestResult<T, 1> Concat1dTestImpl(
408 armnn::IWorkloadFactory& workloadFactory,
409 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
410 float qScale,
411 int32_t qOffset)
412{
413 armnn::TensorInfo inputTensorInfo({ 3 }, ArmnnType, qScale, qOffset);
414
415 auto input0 = MakeTensor<T, 1>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, { 1.0f, 2.0f, 3.0f }));
416 auto input1 = MakeTensor<T, 1>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, { 4.0f, 5.0f, 6.0f }));
417 auto input2 = MakeTensor<T, 1>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, { 7.0f, 8.0f, 9.0f }));
418
419 armnn::TensorInfo outputTensorInfo({ 9 }, ArmnnType, qScale, qOffset);
420
421 LayerTestResult<T, 1> result(outputTensorInfo);
422
423 std::vector<T> output;
424 output.resize(outputTensorInfo.GetNumElements());
425 Concatenate<T>(workloadFactory, memoryManager,
426 { inputTensorInfo, inputTensorInfo, inputTensorInfo },
427 { input0.data(), input1.data(), input2.data() },
428 outputTensorInfo,
429 output.data(),
430 0,
431 true);
432
433 result.output = MakeTensor<T, 1>(outputTensorInfo, output);
434 result.outputExpected = MakeTensor<T, 1>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
435 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f
436 }));
437
438 return result;
439}
440
441template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
442LayerTestResult<T, 2> Concat2dTestImpl(
443 armnn::IWorkloadFactory& workloadFactory,
444 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
445 const armnn::TensorInfo& outputTensorInfo,
446 unsigned int dimension,
447 const float qScale,
448 const int32_t qOffset)
449{
450 armnn::TensorInfo inputTensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
451
452 auto input0 = MakeTensor<T, 2>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
453 // Batch 0
454 1.0f, 2.0f, 3.0f,
455
456 // Batch 1
457 10.0f, 11.0f, 12.0f,
458 }));
459
460 auto input1 = MakeTensor<T, 2>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
461 // Batch 0
462 4.0f, 5.0f, 6.0f,
463
464 // Batch 1
465 13.0f, 14.0f, 15.0f,
466 }));
467
468 auto input2 = MakeTensor<T, 2>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
469 // Batch 0
470 7.0f, 8.0f, 9.0f,
471
472 // Batch 1
473 16.0f, 17.0f, 18.0f,
474 }));
475
476 LayerTestResult<T, 2> result(outputTensorInfo);
477
478 std::vector<T> output;
479 output.resize(outputTensorInfo.GetNumElements());
480 Concatenate<T>(workloadFactory, memoryManager,
481 { inputTensorInfo, inputTensorInfo, inputTensorInfo },
482 { input0.data(), input1.data(), input2.data() },
483 outputTensorInfo,
484 output.data(),
485 dimension,
486 true);
487
488 result.output = MakeTensor<T, 2>(outputTensorInfo, output);
489 return result;
490}
491
492template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
493LayerTestResult<T, 2> Concat2dDim0TestImpl(
494 armnn::IWorkloadFactory& workloadFactory,
495 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
496 float qScale,
497 int32_t qOffset)
498{
499 armnn::TensorInfo outputTensorInfo({ 6, 3 }, ArmnnType, qScale, qOffset);
500
501 LayerTestResult<T, 2> result = Concat2dTestImpl<ArmnnType>(
502 workloadFactory, memoryManager, outputTensorInfo, 0, qScale, qOffset);
503
504 result.outputExpected = MakeTensor<T, 2>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
505 // Batch 0
506 1.0f, 2.0f, 3.0f,
507
508 // Batch 1
509 10.0f, 11.0f, 12.0f,
510
511 // Batch 2
512 4.0f, 5.0f, 6.0f,
513
514 // Batch 3
515 13.0f, 14.0f, 15.0f,
516
517 // Batch 4
518 7.0f, 8.0f, 9.0f,
519
520 // Batch 5
521 16.0f, 17.0f, 18.0f,
522 }));
523
524 return result;
525}
526
527template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
528LayerTestResult<T, 2> Concat2dDim1TestImpl(
529 armnn::IWorkloadFactory& workloadFactory,
530 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
531 float qScale,
532 int32_t qOffset)
533{
534 armnn::TensorInfo outputTensorInfo({ 2, 9 }, ArmnnType, qScale, qOffset);
535
536 LayerTestResult<T, 2> result = Concat2dTestImpl<ArmnnType>(
537 workloadFactory, memoryManager, outputTensorInfo, 1, qScale, qOffset);
538
539 result.outputExpected = MakeTensor<T, 2>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
540 // Batch 0
541 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
542
543 // Batch 1
544 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f
545 }));
546
547 return result;
548}
549
550template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
551LayerTestResult<T, 2> Concat2dDim0DiffInputDimsTestImpl(
552 armnn::IWorkloadFactory& workloadFactory,
553 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
554 float qScale,
555 int32_t qOffset)
556{
557 armnn::TensorInfo input0TensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
558 auto input0 = MakeTensor<T, 2>(input0TensorInfo, QuantizedVector<T>(qScale, qOffset, {
559 // Batch 0
560 1.0f, 2.0f, 3.0f,
561
562 // Batch 1
563 10.0f, 11.0f, 12.0f,
564 }));
565
566 armnn::TensorInfo input1TensorInfo({ 3, 3 }, ArmnnType, qScale, qOffset);
567 auto input1 = MakeTensor<T, 2>(input1TensorInfo, QuantizedVector<T>(qScale, qOffset, {
568 // Batch 0
569 4.0f, 5.0f, 6.0f,
570
571 // Batch 1
572 13.0f, 14.0f, 15.0f,
573
574 // Batch 0
575 7.0f, 8.0f, 9.0f,
576 }));
577
578 armnn::TensorInfo input2TensorInfo({ 1, 3 }, ArmnnType, qScale, qOffset);
579 auto input2 = MakeTensor<T, 2>(input2TensorInfo, QuantizedVector<T>(qScale, qOffset, {
580 // Batch 1
581 16.0f, 17.0f, 18.0f,
582 }));
583
584 armnn::TensorInfo outputTensorInfo({ 6, 3 }, ArmnnType, qScale, qOffset);
585 LayerTestResult<T, 2> result(outputTensorInfo);
586
587 std::vector<T> output;
588 output.resize(outputTensorInfo.GetNumElements());
589 Concatenate<T>(workloadFactory, memoryManager,
590 { input0TensorInfo, input1TensorInfo, input2TensorInfo },
591 { input0.data(), input1.data(), input2.data() },
592 outputTensorInfo,
593 output.data(),
594 0,
595 true);
596
597 result.output = MakeTensor<T, 2>(outputTensorInfo, output);
598 result.outputExpected = MakeTensor<T, 2>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
599 // Batch 0
600 1.0f, 2.0f, 3.0f,
601
602 // Batch 1
603 10.0f, 11.0f, 12.0f,
604
605 // Batch 2
606 4.0f, 5.0f, 6.0f,
607
608 // Batch 3
609 13.0f, 14.0f, 15.0f,
610
611 // Batch 4
612 7.0f, 8.0f, 9.0f,
613
614 // Batch 5
615 16.0f, 17.0f, 18.0f,
616 }));
617
618 return result;
619}
620
621template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
622LayerTestResult<T, 2> Concat2dDim1DiffInputDimsTestImpl(
623 armnn::IWorkloadFactory& workloadFactory,
624 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
625 float qScale,
626 int32_t qOffset)
627{
628 armnn::TensorInfo input0TensorInfo({ 2, 3 }, ArmnnType, qScale, qOffset);
629 auto input0 = MakeTensor<T, 2>(input0TensorInfo, QuantizedVector<T>(qScale, qOffset, {
630 // Batch 0
631 1.0f, 2.0f, 3.0f,
632
633 // Batch 1
634 10.0f, 11.0f, 12.0f,
635 }));
636
637 armnn::TensorInfo input1TensorInfo({ 2, 5 }, ArmnnType, qScale, qOffset);
638 auto input1 = MakeTensor<T, 2>(input1TensorInfo, QuantizedVector<T>(qScale, qOffset, {
639 // Batch 0
640 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
641
642 // Batch 1
643 13.0f, 14.0f, 15.0f, 16.0f, 17.0f,
644 }));
645
646 armnn::TensorInfo input2TensorInfo({ 2, 1 }, ArmnnType, qScale, qOffset);
647 auto input2 = MakeTensor<T, 2>(input2TensorInfo, QuantizedVector<T>(qScale, qOffset, {
648 // Batch 0
649 9.0f,
650
651 // Batch 1
652 18.0f
653 }));
654
655 armnn::TensorInfo outputTensorInfo({ 2, 9 }, ArmnnType, qScale, qOffset);
656 LayerTestResult<T, 2> result(outputTensorInfo);
657
658 std::vector<T> output;
659 output.resize(outputTensorInfo.GetNumElements());
660 Concatenate<T>(workloadFactory, memoryManager,
661 { input0TensorInfo, input1TensorInfo, input2TensorInfo },
662 { input0.data(), input1.data(), input2.data() },
663 outputTensorInfo,
664 output.data(),
665 1,
666 true);
667
668 result.output = MakeTensor<T, 2>(outputTensorInfo, output);
669 result.outputExpected = MakeTensor<T, 2>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
670 // Batch 0
671 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
672
673 // Batch 1
674 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f,
675 }));
676
677 return result;
678}
679
680template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
681LayerTestResult<T, 3> Concat3dTestImpl(
682 armnn::IWorkloadFactory& workloadFactory,
683 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
684 const armnn::TensorInfo& outputTensorInfo,
685 unsigned int dimension,
686 bool useSubtensor,
687 float qScale,
688 int32_t qOffset)
689{
690 armnn::TensorInfo inputTensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
691
692 auto input0 = MakeTensor<T, 3>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
693 // Batch 0, Channel 0
694 1.0f, 2.0f,
695
696 // Batch 0, Channel 1
697 3.0f, 4.0f,
698
699 // Batch 0, Channel 2
700 5.0f, 6.0f,
701
702 // Batch 1, Channel 0
703 19.0f, 20.0f,
704
705 // Batch 1, Channel 1
706 21.0f, 22.0f,
707
708 // Batch 1, Channel 2
709 23.0f, 24.0f
710 }));
711
712 auto input1 = MakeTensor<T, 3>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
713 // Batch 0, Channel 0
714 7.0f, 8.0f,
715
716 // Batch 0, Channel 1
717 9.0f, 10.0f,
718
719 // Batch 0, Channel 2
720 11.0f, 12.0f,
721
722 // Batch 1, Channel 0
723 25.0f, 26.0f,
724
725 // Batch 1, Channel 1
726 27.0f, 28.0f,
727
728 // Batch 1, Channel 2
729 29.0f, 30.0f
730 }));
731
732 auto input2 = MakeTensor<T, 3>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
733 // Batch 0, Channel 0
734 13.0f, 14.0f,
735
736 // Batch 0, Channel 1
737 15.0f, 16.0f,
738
739 // Batch 0, Channel 2
740 17.0f, 18.0f,
741
742 // Batch 1, Channel 0
743 31.0f, 32.0f,
744
745 // Batch 1, Channel 1
746 33.0f, 34.0f,
747
748 // Batch 1, Channel 2
749 35.0f, 36.0f
750 }));
751
752 LayerTestResult<T, 3> result(outputTensorInfo);
753
754 std::vector<T> output;
755 output.resize(outputTensorInfo.GetNumElements());
756 Concatenate<T>(workloadFactory, memoryManager,
757 { inputTensorInfo, inputTensorInfo, inputTensorInfo },
758 { input0.data(), input1.data(), input2.data() },
759 outputTensorInfo,
760 output.data(),
761 dimension,
762 useSubtensor);
763
764 result.output = MakeTensor<T, 3>(outputTensorInfo, output);
765 return result;
766}
767
768template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
769LayerTestResult<T, 3> Concat3dDim0TestImpl(
770 armnn::IWorkloadFactory& workloadFactory,
771 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
772 float qScale,
773 int32_t qOffset)
774{
775 armnn::TensorInfo outputTensorInfo({ 6, 3, 2 }, ArmnnType, qScale, qOffset);
776
777 LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
778 workloadFactory, memoryManager, outputTensorInfo, 0, true, qScale, qOffset);
779
780 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
781 // Batch 0, Channel 0
782 1.0f, 2.0f,
783
784 // Batch 0, Channel 1
785 3.0f, 4.0f,
786
787 // Batch 0, Channel 2
788 5.0f, 6.0f,
789
790 // Batch 1, Channel 0
791 19.0f, 20.0f,
792
793 // Batch 1, Channel 1
794 21.0f, 22.0f,
795
796 // Batch 1, Channel 2
797 23.0f, 24.0f,
798
799 // Batch 2, Channel 0
800 7.0f, 8.0f,
801
802 // Batch 2, Channel 1
803 9.0f, 10.0f,
804
805 // Batch 2, Channel 2
806 11.0f, 12.0f,
807
808 // Batch 3, Channel 0
809 25.0f, 26.0f,
810
811 // Batch 3, Channel 1
812 27.0f, 28.0f,
813
814 // Batch 3, Channel 2
815 29.0f, 30.0f,
816
817 // Batch 4, Channel 0
818 13.0f, 14.0f,
819
820 // Batch 4, Channel 1
821 15.0f, 16.0f,
822
823 // Batch 4, Channel 2
824 17.0f, 18.0f,
825
826 // Batch 5, Channel 0
827 31.0f, 32.0f,
828
829 // Batch 5, Channel 1
830 33.0f, 34.0f,
831
832 // Batch 5, Channel 2
833 35.0f, 36.0f
834 }));
835
836 return result;
837}
838
839template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
840LayerTestResult<T, 3> Concat3dDim1TestImpl(
841 armnn::IWorkloadFactory& workloadFactory,
842 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
843 float qScale,
844 int32_t qOffset)
845{
846 armnn::TensorInfo outputTensorInfo({ 2, 9, 2 }, ArmnnType, qScale, qOffset);
847
848 LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
849 workloadFactory, memoryManager, outputTensorInfo, 1, true, qScale, qOffset);
850
851 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
852 // Batch 0, Channel 0
853 1.0f, 2.0f,
854
855 // Batch 0, Channel 1
856 3.0f, 4.0f,
857
858 // Batch 0, Channel 2
859 5.0f, 6.0f,
860
861 // Batch 0, Channel 3
862 7.0f, 8.0f,
863
864 // Batch 0, Channel 4
865 9.0f, 10.0f,
866
867 // Batch 0, Channel 5
868 11.0f, 12.0f,
869
870 // Batch 0, Channel 6
871 13.0f, 14.0f,
872
873 // Batch 0, Channel 7
874 15.0f, 16.0f,
875
876 // Batch 0, Channel 8
877 17.0f, 18.0f,
878
879 // Batch 1, Channel 0
880 19.0f, 20.0f,
881
882 // Batch 1, Channel 1
883 21.0f, 22.0f,
884
885 // Batch 1, Channel 2
886 23.0f, 24.0f,
887
888 // Batch 1, Channel 3
889 25.0f, 26.0f,
890
891 // Batch 1, Channel 4
892 27.0f, 28.0f,
893
894 // Batch 1, Channel 5
895 29.0f, 30.0f,
896
897 // Batch 1, Channel 6
898 31.0f, 32.0f,
899
900 // Batch 1, Channel 7
901 33.0f, 34.0f,
902
903 // Batch 1, Channel 8
904 35.0f, 36.0f
905 }));
906
907 return result;
908}
909
910template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
911LayerTestResult<T, 3> Concat3dDim2TestImpl(
912 armnn::IWorkloadFactory& workloadFactory,
913 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
914 bool useSubtensor,
915 float qScale,
916 int32_t qOffset)
917{
918 armnn::TensorInfo outputTensorInfo({ 2, 3, 6 }, ArmnnType, qScale, qOffset);
919
920 LayerTestResult<T, 3> result = Concat3dTestImpl<ArmnnType>(
921 workloadFactory, memoryManager, outputTensorInfo, 2, useSubtensor, qScale, qOffset);
922
923 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
924 // Batch 0, Channel 0
925 1.0f, 2.0f, 7.0f, 8.0f, 13.0f, 14.0f,
926
927 // Batch 0, Channel 1
928 3.0f, 4.0f, 9.0f, 10.0f, 15.0f, 16.0f,
929
930 // Batch 0, Channel 2
931 5.0f, 6.0f, 11.0f, 12.0f, 17.0f, 18.0f,
932
933 // Batch 1, Channel 0
934 19.0f, 20.0f, 25.0f, 26.0f, 31.0f, 32.0f,
935
936 // Batch 1, Channel 1
937 21.0f, 22.0f, 27.0f, 28.0f, 33.0f, 34.0f,
938
939 // Batch 1, Channel 2
940 23.0f, 24.0f, 29.0f, 30.0f, 35.0f, 36.0f,
941 }));
942
943 return result;
944}
945
946template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
947LayerTestResult<T, 3> Concat3dDim0DiffInputDimsTestImpl(
948 armnn::IWorkloadFactory& workloadFactory,
949 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
950 float qScale,
951 int32_t qOffset)
952{
953 armnn::TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType);
954 auto input0 = MakeTensor<T, 3>(input0TensorInfo, QuantizedVector<T>(qScale, qOffset, {
955 // Batch 0, Channel 0
956 1.0f, 2.0f,
957
958 // Batch 0, Channel 1
959 3.0f, 4.0f,
960
961 // Batch 0, Channel 2
962 5.0f, 6.0f,
963
964 // Batch 1, Channel 0
965 19.0f, 20.0f,
966
967 // Batch 1, Channel 1
968 21.0f, 22.0f,
969
970 // Batch 1, Channel 2
971 23.0f, 24.0f
972 }));
973
974 armnn::TensorInfo input1TensorInfo({ 1, 3, 2 }, ArmnnType);
975 auto input1 = MakeTensor<T, 3>(input1TensorInfo, QuantizedVector<T>(qScale, qOffset, {
976 // Batch 0, Channel 0
977 7.0f, 8.0f,
978
979 // Batch 0, Channel 1
980 9.0f, 10.0f,
981
982 // Batch 0, Channel 2
983 11.0f, 12.0f,
984 }));
985
986 armnn::TensorInfo input2TensorInfo({ 3, 3, 2 }, ArmnnType);
987 auto input2 = MakeTensor<T, 3>(input2TensorInfo, QuantizedVector<T>(qScale, qOffset, {
988 // Batch 0, Channel 0
989 25.0f, 26.0f,
990
991 // Batch 0, Channel 1
992 27.0f, 28.0f,
993
994 // Batch 0, Channel 2
995 29.0f, 30.0f,
996
997 // Batch 1, Channel 0
998 13.0f, 14.0f,
999
1000 // Batch 1, Channel 1
1001 15.0f, 16.0f,
1002
1003 // Batch 1, Channel 2
1004 17.0f, 18.0f,
1005
1006 // Batch 2, Channel 0
1007 31.0f, 32.0f,
1008
1009 // Batch 2, Channel 1
1010 33.0f, 34.0f,
1011
1012 // Batch 2, Channel 2
1013 35.0f, 36.0f
1014 }));
1015
1016 armnn::TensorInfo outputTensorInfo({ 6, 3, 2 }, ArmnnType);
1017 LayerTestResult<T, 3> result(outputTensorInfo);
1018
1019 std::vector<T> output;
1020 output.resize(outputTensorInfo.GetNumElements());
1021 Concatenate<T>(workloadFactory, memoryManager,
1022 { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1023 { input0.data(), input1.data(), input2.data() },
1024 outputTensorInfo,
1025 output.data(),
1026 0,
1027 true);
1028
1029 result.output = MakeTensor<T, 3>(outputTensorInfo, output);
1030 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1031 // Batch 0, Channel 0
1032 1.0f, 2.0f,
1033
1034 // Batch 0, Channel 1
1035 3.0f, 4.0f,
1036
1037 // Batch 0, Channel 2
1038 5.0f, 6.0f,
1039
1040 // Batch 1, Channel 0
1041 19.0f, 20.0f,
1042
1043 // Batch 1, Channel 1
1044 21.0f, 22.0f,
1045
1046 // Batch 1, Channel 2
1047 23.0f, 24.0f,
1048
1049 // Batch 2, Channel 0
1050 7.0f, 8.0f,
1051
1052 // Batch 2, Channel 1
1053 9.0f, 10.0f,
1054
1055 // Batch 2, Channel 2
1056 11.0f, 12.0f,
1057
1058 // Batch 3, Channel 0
1059 25.0f, 26.0f,
1060
1061 // Batch 3, Channel 1
1062 27.0f, 28.0f,
1063
1064 // Batch 3, Channel 2
1065 29.0f, 30.0f,
1066
1067 // Batch 4, Channel 0
1068 13.0f, 14.0f,
1069
1070 // Batch 4, Channel 1
1071 15.0f, 16.0f,
1072
1073 // Batch 4, Channel 2
1074 17.0f, 18.0f,
1075
1076 // Batch 5, Channel 0
1077 31.0f, 32.0f,
1078
1079 // Batch 5, Channel 1
1080 33.0f, 34.0f,
1081
1082 // Batch 5, Channel 2
1083 35.0f, 36.0f
1084 }));
1085
1086 return result;
1087}
1088
1089template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1090LayerTestResult<T, 3> Concat3dDim1DiffInputDimsTestImpl(
1091 armnn::IWorkloadFactory& workloadFactory,
1092 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1093 float qScale,
1094 int32_t qOffset)
1095{
1096 armnn::TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
1097 auto input0 = MakeTensor<T, 3>(input0TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1098 // Batch 0, Channel 0
1099 1.0f, 2.0f,
1100
1101 // Batch 0, Channel 1
1102 3.0f, 4.0f,
1103
1104 // Batch 0, Channel 2
1105 5.0f, 6.0f,
1106
1107 // Batch 1, Channel 0
1108 19.0f, 20.0f,
1109
1110 // Batch 1, Channel 1
1111 21.0f, 22.0f,
1112
1113 // Batch 1, Channel 2
1114 23.0f, 24.0f
1115 }));
1116
1117 armnn::TensorInfo input1TensorInfo({ 2, 4, 2 }, ArmnnType, qScale, qOffset);
1118 auto input1 = MakeTensor<T, 3>(input1TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1119 // Batch 0, Channel 0
1120 7.0f, 8.0f,
1121
1122 // Batch 0, Channel 1
1123 9.0f, 10.0f,
1124
1125 // Batch 0, Channel 2
1126 11.0f, 12.0f,
1127
1128 // Batch 0, Channel 3
1129 25.0f, 26.0f,
1130
1131 // Batch 1, Channel 0
1132 27.0f, 28.0f,
1133
1134 // Batch 1, Channel 1
1135 29.0f, 30.0f,
1136
1137 // Batch 1, Channel 2
1138 13.0f, 14.0f,
1139
1140 // Batch 1, Channel 3
1141 15.0f, 16.0f,
1142 }));
1143
1144 armnn::TensorInfo input2TensorInfo({ 2, 1, 2 }, ArmnnType, qScale, qOffset);
1145 auto input2 = MakeTensor<T, 3>(input2TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1146 // Batch 0, Channel 0
1147 17.0f, 18.0f,
1148
1149 // Batch 1, Channel 0
1150 31.0f, 32.0f,
1151 }));
1152
1153 armnn::TensorInfo outputTensorInfo({ 2, 8, 2 }, ArmnnType, qScale, qOffset);
1154 LayerTestResult<T, 3> result(outputTensorInfo);
1155
1156 std::vector<T> output;
1157 output.resize(outputTensorInfo.GetNumElements());
1158 Concatenate<T>(workloadFactory, memoryManager,
1159 { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1160 { input0.data(), input1.data(), input2.data() },
1161 outputTensorInfo,
1162 output.data(),
1163 1,
1164 true);
1165
1166 result.output = MakeTensor<T, 3>(outputTensorInfo, output);
1167 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1168 // Batch 0, Channel 0
1169 1.0f, 2.0f,
1170
1171 // Batch 0, Channel 1
1172 3.0f, 4.0f,
1173
1174 // Batch 0, Channel 2
1175 5.0f, 6.0f,
1176
1177 // Batch 0, Channel 3
1178 7.0f, 8.0f,
1179
1180 // Batch 0, Channel 4
1181 9.0f, 10.0f,
1182
1183 // Batch 0, Channel 5
1184 11.0f, 12.0f,
1185
1186 // Batch 0, Channel 6
1187 25.0f, 26.0f,
1188
1189 // Batch 0, Channel 7
1190 17.0f, 18.0f,
1191
1192 // Batch 1, Channel 0
1193 19.0f, 20.0f,
1194
1195 // Batch 1, Channel 1
1196 21.0f, 22.0f,
1197
1198 // Batch 1, Channel 2
1199 23.0f, 24.0f,
1200
1201 // Batch 1, Channel 3
1202 27.0f, 28.0f,
1203
1204 // Batch 1, Channel 4
1205 29.0f, 30.0f,
1206
1207 // Batch 1, Channel 5
1208 13.0f, 14.0f,
1209
1210 // Batch 1, Channel 6
1211 15.0f, 16.0f,
1212
1213 // Batch 1, Channel 7
1214 31.0f, 32.0f,
1215 }));
1216
1217 return result;
1218}
1219
1220template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1221LayerTestResult<T, 3> Concat3dDim2DiffInputDimsTestImpl(
1222 armnn::IWorkloadFactory& workloadFactory,
1223 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1224 bool useSubtensor,
1225 float qScale,
1226 int32_t qOffset)
1227{
1228 armnn::TensorInfo input0TensorInfo({ 2, 3, 2 }, ArmnnType, qScale, qOffset);
1229 auto input0 = MakeTensor<T, 3>(input0TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1230 // Batch 0, Channel 0
1231 1.0f, 2.0f,
1232
1233 // Batch 0, Channel 1
1234 3.0f, 4.0f,
1235
1236 // Batch 0, Channel 2
1237 5.0f, 6.0f,
1238
1239 // Batch 1, Channel 0
1240 19.0f, 20.0f,
1241
1242 // Batch 1, Channel 1
1243 21.0f, 22.0f,
1244
1245 // Batch 1, Channel 2
1246 23.0f, 24.0f
1247 }));
1248
1249 armnn::TensorInfo input1TensorInfo({ 2, 3, 1 }, ArmnnType, qScale, qOffset);
1250 auto input1 = MakeTensor<T, 3>(input1TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1251 // Batch 0, Channel 0
1252 7.0f,
1253
1254 // Batch 0, Channel 1
1255 9.0f,
1256
1257 // Batch 0, Channel 2
1258 11.0f,
1259
1260 // Batch 1, Channel 0
1261 25.0f,
1262
1263 // Batch 1, Channel 1
1264 27.0f,
1265
1266 // Batch 1, Channel 2
1267 29.0f
1268 }));
1269
1270 armnn::TensorInfo input2TensorInfo({ 2, 3, 3 }, ArmnnType, qScale, qOffset);
1271 auto input2 = MakeTensor<T, 3>(input2TensorInfo, QuantizedVector<T>(qScale, qOffset, {
1272 // Batch 0, Channel 0
1273 13.0f, 14.0f, 50.0f,
1274
1275 // Batch 0, Channel 1
1276 15.0f, 16.0f, 51.0f,
1277
1278 // Batch 0, Channel 2
1279 17.0f, 18.0f, 52.0f,
1280
1281 // Batch 1, Channel 0
1282 31.0f, 32.0f, 53.0f,
1283
1284 // Batch 1, Channel 1
1285 33.0f, 34.0f, 54.0f,
1286
1287 // Batch 1, Channel 2
1288 35.0f, 36.0f, 55.0f,
1289 }));
1290
1291 armnn::TensorInfo outputTensorInfo({ 2, 3, 6 }, ArmnnType, qScale, qOffset);
1292 LayerTestResult<T, 3> result(outputTensorInfo);
1293
1294 std::vector<T> output;
1295 output.resize(outputTensorInfo.GetNumElements());
1296 Concatenate<T>(workloadFactory, memoryManager,
1297 { input0TensorInfo, input1TensorInfo, input2TensorInfo },
1298 { input0.data(), input1.data(), input2.data() },
1299 outputTensorInfo,
1300 output.data(),
1301 2,
1302 useSubtensor);
1303
1304 result.output = MakeTensor<T, 3>(outputTensorInfo, output);
1305 result.outputExpected = MakeTensor<T, 3>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1306 // Batch 0, Channel 0
1307 1.0f, 2.0f, 7.0f, 13.0f, 14.0f, 50.0f,
1308
1309 // Batch 0, Channel 1
1310 3.0f, 4.0f, 9.0f, 15.0f, 16.0f, 51.0f,
1311
1312 // Batch 0, Channel 2
1313 5.0f, 6.0f, 11.0f, 17.0f, 18.0f, 52.0f,
1314
1315 // Batch 1, Channel 0
1316 19.0f, 20.0f, 25.0f, 31.0f, 32.0f, 53.0f,
1317
1318 // Batch 1, Channel 1
1319 21.0f, 22.0f, 27.0f, 33.0f, 34.0f, 54.0f,
1320
1321 // Batch 1, Channel 2
1322 23.0f, 24.0f, 29.0f, 35.0f, 36.0f, 55.0f,
1323 }));
1324
1325 return result;
1326}
1327
1328template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1329LayerTestResult<T, 4> Concat4dTestImpl(
1330 armnn::IWorkloadFactory& workloadFactory,
1331 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1332 const armnn::TensorInfo& outputTensorInfo,
1333 unsigned int dimension,
1334 bool useSubtensor,
1335 float qScale,
1336 int32_t qOffset)
1337{
1338 armnn::TensorInfo inputTensorInfo({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1339
1340 auto input0 = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1341 1.0f, 2.0f,
1342 3.0f, 4.0f,
1343 5.0f, 6.0f,
1344 7.0f, 8.0f,
1345 9.0f, 10.0f,
1346 11.0f, 12.0f
1347 }));
1348
1349 auto input1 = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1350 11.0f, 12.0f,
1351 13.0f, 14.0f,
1352 15.0f, 16.0f,
1353 17.0f, 18.0f,
1354 19.0f, 20.0f,
1355 21.0f, 22.0f
1356 }));
1357
1358 auto input2 = MakeTensor<T, 4>(inputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1359 21.0f, 22.0f,
1360 23.0f, 24.0f,
1361 25.0f, 26.0f,
1362 27.0f, 28.0f,
1363 29.0f, 30.0f,
1364 31.0f, 32.0f
1365 }));
1366
1367 LayerTestResult<T, 4> result(outputTensorInfo);
1368
1369 std::vector<T> output;
1370 output.resize(outputTensorInfo.GetNumElements());
1371
1372 Concatenate<T>(workloadFactory,
1373 memoryManager,
1374 {inputTensorInfo, inputTensorInfo, inputTensorInfo},
1375 {input0.data(), input1.data(), input2.data()},
1376 outputTensorInfo,
1377 output.data(),
1378 dimension,
1379 useSubtensor);
1380
1381 result.output = MakeTensor<T, 4>(outputTensorInfo, output);
1382 return result;
1383}
1384
1385template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1386LayerTestResult<T, 4> Concat4dDim0TestImpl(
1387 armnn::IWorkloadFactory& workloadFactory,
1388 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1389 float qScale,
1390 int32_t qOffset)
1391{
1392 armnn::TensorInfo outputTensorInfo({ 3, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1393
1394 LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1395 workloadFactory, memoryManager, outputTensorInfo, 0, true, qScale, qOffset);
1396
1397 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1398 1.0f, 2.0f,
1399 3.0f, 4.0f,
1400 5.0f, 6.0f,
1401 7.0f, 8.0f,
1402 9.0f, 10.0f,
1403 11.0f, 12.0f,
1404
1405 11.0f, 12.0f,
1406 13.0f, 14.0f,
1407 15.0f, 16.0f,
1408 17.0f, 18.0f,
1409 19.0f, 20.0f,
1410 21.0f, 22.0f,
1411
1412 21.0f, 22.0f,
1413 23.0f, 24.0f,
1414 25.0f, 26.0f,
1415 27.0f, 28.0f,
1416 29.0f, 30.0f,
1417 31.0f, 32.0f
1418 }));
1419 return result;
1420}
1421
1422template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1423LayerTestResult<T, 4> Concat4dDim1TestImpl(
1424 armnn::IWorkloadFactory& workloadFactory,
1425 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1426 float qScale,
1427 int32_t qOffset)
1428{
1429 armnn::TensorInfo outputTensorInfo({ 1, 9, 2, 2 }, ArmnnType, qScale, qOffset);
1430
1431 LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1432 workloadFactory, memoryManager, outputTensorInfo, 1, true, qScale, qOffset);
1433
1434 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1435 1.0f, 2.0f,
1436 3.0f, 4.0f,
1437 5.0f, 6.0f,
1438 7.0f, 8.0f,
1439 9.0f, 10.0f,
1440 11.0f, 12.0f,
1441
1442 11.0f, 12.0f,
1443 13.0f, 14.0f,
1444 15.0f, 16.0f,
1445 17.0f, 18.0f,
1446 19.0f, 20.0f,
1447 21.0f, 22.0f,
1448
1449 21.0f, 22.0f,
1450 23.0f, 24.0f,
1451 25.0f, 26.0f,
1452 27.0f, 28.0f,
1453 29.0f, 30.0f,
1454 31.0f, 32.0f
1455 }));
1456
1457 return result;
1458}
1459
1460template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1461LayerTestResult<T, 4> Concat4dDim2TestImpl(
1462 armnn::IWorkloadFactory& workloadFactory,
1463 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1464 float qScale,
1465 int32_t qOffset)
1466{
1467 armnn::TensorInfo outputTensorInfo({ 1, 3, 6, 2 }, ArmnnType, qScale, qOffset);
1468
1469 LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1470 workloadFactory, memoryManager, outputTensorInfo, 2, true, qScale, qOffset);
1471
1472 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1473 1.0f, 2.0f,
1474 3.0f, 4.0f,
1475 11.0f, 12.0f,
1476 13.0f, 14.0f,
1477 21.0f, 22.0f,
1478 23.0f, 24.0f,
1479
1480 5.0f, 6.0f,
1481 7.0f, 8.0f,
1482 15.0f, 16.0f,
1483 17.0f, 18.0f,
1484 25.0f, 26.0f,
1485 27.0f, 28.0f,
1486
1487 9.0f, 10.0f,
1488 11.0f, 12.0f,
1489 19.0f, 20.0f,
1490 21.0f, 22.0f,
1491 29.0f, 30.0f,
1492 31.0f, 32.0f
1493 }));
1494
1495 return result;
1496}
1497
1498template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1499LayerTestResult<T, 4> Concat4dDim3TestImpl(
1500 armnn::IWorkloadFactory& workloadFactory,
1501 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1502 float qScale,
1503 int32_t qOffset,
1504 bool useSubtensor)
1505{
1506 armnn::TensorInfo outputTensorInfo({ 1, 3, 2, 6 }, ArmnnType, qScale, qOffset);
1507
1508 LayerTestResult<T, 4> result = Concat4dTestImpl<ArmnnType>(
1509 workloadFactory, memoryManager, outputTensorInfo, 3, useSubtensor, qScale, qOffset);
1510
1511 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1512 1.0f, 2.0f,
1513 11.0f, 12.0f,
1514 21.0f, 22.0f,
1515 3.0f, 4.0f,
1516 13.0f, 14.0f,
1517 23.0f, 24.0f,
1518
1519 5.0f, 6.0f,
1520 15.0f, 16.0f,
1521 25.0f, 26.0f,
1522 7.0f, 8.0f,
1523 17.0f, 18.0f,
1524 27.0f, 28.0f,
1525
1526 9.0f, 10.0f,
1527 19.0f, 20.0f,
1528 29.0f, 30.0f,
1529 11.0f, 12.0f,
1530 21.0f, 22.0f,
1531 31.0f, 32.0f
1532 }));
1533
1534 return result;
1535}
1536
1537template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1538LayerTestResult<T, 4> Concat4dDiffShapeDim0TestImpl(
1539 armnn::IWorkloadFactory& workloadFactory,
1540 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1541 float qScale,
1542 int32_t qOffset)
1543{
1544 unsigned int dimension = 0;
1545 armnn::TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1546
1547 auto input0 = MakeTensor<T, 4>(inputTensorInfo0, QuantizedVector<T>(qScale, qOffset, {
1548 1.0f, 2.0f,
1549 3.0f, 4.0f,
1550 5.0f, 6.0f,
1551 7.0f, 8.0f,
1552 9.0f, 10.0f,
1553 11.0f, 12.0f
1554 }));
1555
1556 armnn::TensorInfo inputTensorInfo1({ 2, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1557
1558 auto input1 = MakeTensor<T, 4>(inputTensorInfo1, QuantizedVector<T>(qScale, qOffset, {
1559 11.0f, 12.0f,
1560 13.0f, 14.0f,
1561 15.0f, 16.0f,
1562 17.0f, 18.0f,
1563 19.0f, 20.0f,
1564 21.0f, 22.0f,
1565
1566 21.0f, 22.0f,
1567 23.0f, 24.0f,
1568 25.0f, 26.0f,
1569 27.0f, 28.0f,
1570 29.0f, 30.0f,
1571 31.0f, 32.0f
1572
1573 }));
1574
1575 armnn::TensorInfo outputTensorInfo({ 3, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1576
1577 LayerTestResult<T, 4> result(outputTensorInfo);
1578
1579 std::vector<T> output;
1580 output.resize(outputTensorInfo.GetNumElements());
1581 Concatenate<T>(workloadFactory,
1582 memoryManager,
1583 {inputTensorInfo0, inputTensorInfo1},
1584 {input0.data(), input1.data()},
1585 outputTensorInfo,
1586 output.data(),
1587 dimension,
1588 true);
1589
1590 result.output = MakeTensor<T, 4>(outputTensorInfo, output);
1591 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1592 1.0f, 2.0f,
1593 3.0f, 4.0f,
1594 5.0f, 6.0f,
1595 7.0f, 8.0f,
1596 9.0f, 10.0f,
1597 11.0f, 12.0f,
1598
1599 11.0f, 12.0f,
1600 13.0f, 14.0f,
1601 15.0f, 16.0f,
1602 17.0f, 18.0f,
1603 19.0f, 20.0f,
1604 21.0f, 22.0f,
1605
1606 21.0f, 22.0f,
1607 23.0f, 24.0f,
1608 25.0f, 26.0f,
1609 27.0f, 28.0f,
1610 29.0f, 30.0f,
1611 31.0f, 32.0f
1612 }));
1613
1614 return result;
1615}
1616
1617template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1618LayerTestResult<T, 4> Concat4dDiffShapeDim1TestImpl(
1619 armnn::IWorkloadFactory& workloadFactory,
1620 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1621 float qScale,
1622 int32_t qOffset)
1623{
1624 unsigned int dimension = 1;
1625 armnn::TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1626
1627 auto input0 = MakeTensor<T, 4>(inputTensorInfo0, QuantizedVector<T>(qScale, qOffset, {
1628 1.0f, 2.0f,
1629 3.0f, 4.0f,
1630 5.0f, 6.0f,
1631 7.0f, 8.0f,
1632 9.0f, 10.0f,
1633 11.0f, 12.0f
1634 }));
1635
1636 armnn::TensorInfo inputTensorInfo1({ 1, 2, 2, 2 }, ArmnnType, qScale, qOffset);
1637
1638 auto input1 = MakeTensor<T, 4>(inputTensorInfo1, QuantizedVector<T>(qScale, qOffset, {
1639 11.0f, 12.0f,
1640 13.0f, 14.0f,
1641 15.0f, 16.0f,
1642 17.0f, 18.0f,
1643
1644 }));
1645
1646 armnn::TensorInfo outputTensorInfo({ 1, 5, 2, 2 }, ArmnnType, qScale, qOffset);
1647
1648 LayerTestResult<T, 4> result(outputTensorInfo);
1649
1650 std::vector<T> output;
1651 output.resize(outputTensorInfo.GetNumElements());
1652 Concatenate<T>(workloadFactory,
1653 memoryManager,
1654 {inputTensorInfo0, inputTensorInfo1},
1655 {input0.data(), input1.data()},
1656 outputTensorInfo,
1657 output.data(),
1658 dimension,
1659 true);
1660
1661 result.output = MakeTensor<T, 4>(outputTensorInfo, output);
1662 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1663 1.0f, 2.0f,
1664 3.0f, 4.0f,
1665 5.0f, 6.0f,
1666 7.0f, 8.0f,
1667 9.0f, 10.0f,
1668 11.0f, 12.0f,
1669 11.0f, 12.0f,
1670 13.0f, 14.0f,
1671 15.0f, 16.0f,
1672 17.0f, 18.0f
1673 }));
1674
1675 return result;
1676}
1677
1678template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1679LayerTestResult<T, 4> Concat4dDiffShapeDim2TestImpl(
1680 armnn::IWorkloadFactory& workloadFactory,
1681 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1682 float qScale,
1683 int32_t qOffset)
1684{
1685 unsigned int dimension = 2;
1686 armnn::TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1687
1688 auto input0 = MakeTensor<T, 4>(inputTensorInfo0, QuantizedVector<T>(qScale, qOffset, {
1689 1.0f, 2.0f,
1690 3.0f, 4.0f,
1691 5.0f, 6.0f,
1692 7.0f, 8.0f,
1693 9.0f, 10.0f,
1694 11.0f, 12.0f
1695 }));
1696
1697 armnn::TensorInfo inputTensorInfo1({ 1, 3, 3, 2 }, ArmnnType, qScale, qOffset);
1698
1699 auto input1 = MakeTensor<T, 4>(inputTensorInfo1, QuantizedVector<T>(qScale, qOffset, {
1700 11.0f, 12.0f,
1701 13.0f, 14.0f,
1702 15.0f, 16.0f,
1703 17.0f, 18.0f,
1704 19.0f, 20.0f,
1705 21.0f, 22.0f,
1706 23.0f, 24.0f,
1707 25.0f, 26.0f,
1708 27.0f, 28.0f
1709 }));
1710
1711 armnn::TensorInfo outputTensorInfo({ 1, 3, 5, 2 }, ArmnnType, qScale, qOffset);
1712
1713 LayerTestResult<T, 4> result(outputTensorInfo);
1714
1715 std::vector<T> output;
1716 output.resize(outputTensorInfo.GetNumElements());
1717 Concatenate<T>(workloadFactory,
1718 memoryManager,
1719 {inputTensorInfo0, inputTensorInfo1},
1720 {input0.data(), input1.data()},
1721 outputTensorInfo,
1722 output.data(),
1723 dimension,
1724 true);
1725
1726 result.output = MakeTensor<T, 4>(outputTensorInfo, output);
1727 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1728 1.0f, 2.0f,
1729 3.0f, 4.0f,
1730 11.0f, 12.0f,
1731 13.0f, 14.0f,
1732 15.0f, 16.0f,
1733
1734 5.0f, 6.0f,
1735 7.0f, 8.0f,
1736 17.0f, 18.0f,
1737 19.0f, 20.0f,
1738 21.0f, 22.0f,
1739
1740 9.0f, 10.0f,
1741 11.0f, 12.0f,
1742 23.0f, 24.0f,
1743 25.0f, 26.0f,
1744 27.0f, 28.0f
1745 }));
1746
1747 return result;
1748}
1749
1750template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
1751LayerTestResult<T, 4> Concat4dDiffShapeDim3TestImpl(
1752 armnn::IWorkloadFactory& workloadFactory,
1753 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1754 float qScale,
1755 int32_t qOffset,
1756 bool useSubtensor)
1757{
1758 unsigned int dimension = 3;
1759 armnn::TensorInfo inputTensorInfo0({ 1, 3, 2, 2 }, ArmnnType, qScale, qOffset);
1760
1761 auto input0 = MakeTensor<T, 4>(inputTensorInfo0, QuantizedVector<T>(qScale, qOffset, {
1762 1.0f, 2.0f,
1763 3.0f, 4.0f,
1764 5.0f, 6.0f,
1765 7.0f, 8.0f,
1766 9.0f, 10.0f,
1767 11.0f, 12.0f
1768 }));
1769
1770 armnn::TensorInfo inputTensorInfo1({ 1, 3, 2, 3 }, ArmnnType, qScale, qOffset);
1771
1772 auto input1 = MakeTensor<T, 4>(inputTensorInfo1, QuantizedVector<T>(qScale, qOffset, {
1773 11.0f, 12.0f, 13.0f,
1774 14.0f, 15.0f, 16.0f,
1775
1776 17.0f, 18.0f, 19.0f,
1777 20.0f, 21.0f, 22.0f,
1778
1779 23.0f, 24.0f, 25.0f,
1780 26.0f, 27.0f, 28.0f
1781 }));
1782
1783 armnn::TensorInfo outputTensorInfo({ 1, 3, 2, 5 }, ArmnnType, qScale, qOffset);
1784
1785 LayerTestResult<T, 4> result(outputTensorInfo);
1786
1787 std::vector<T> output;
1788 output.resize(outputTensorInfo.GetNumElements());
1789 Concatenate<T>(workloadFactory,
1790 memoryManager,
1791 {inputTensorInfo0, inputTensorInfo1},
1792 {input0.data(), input1.data()},
1793 outputTensorInfo,
1794 output.data(),
1795 dimension,
1796 useSubtensor);
1797
1798 result.output = MakeTensor<T, 4>(outputTensorInfo, output);
1799 result.outputExpected = MakeTensor<T, 4>(outputTensorInfo, QuantizedVector<T>(qScale, qOffset, {
1800 1.0f, 2.0f, 11.0f, 12.0f, 13.0f,
1801 3.0f, 4.0f, 14.0f, 15.0f, 16.0f,
1802 5.0f, 6.0f, 17.0f, 18.0f, 19.0f,
1803 7.0f, 8.0f, 20.0f, 21.0f, 22.0f,
1804 9.0f, 10.0f, 23.0f, 24.0f, 25.0f,
1805 11.0f, 12.0f, 26.0f, 27.0f, 28.0f
1806 }));
1807
1808 return result;
1809}
1810
1811template<armnn::DataType ArmnnType, typename T>
1812LayerTestResult<T, 3> ConcatDifferentInputOutputQParamTest(
1813 armnn::IWorkloadFactory& workloadFactory,
1814 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1815 bool useSubtensor)
1816{
1817 // Defines the tensor descriptors.
1818 armnn::TensorInfo outputTensorInfo({ 3, 6, 3 }, ArmnnType);
1819 armnn::TensorInfo inputTensorInfo1({ 3, 6, 2 }, ArmnnType);
1820 armnn::TensorInfo inputTensorInfo2({ 3, 6, 1 }, ArmnnType);
1821
1822 std::vector<armnn::TensorShape> inputTensorShapes({inputTensorInfo1.GetShape(), inputTensorInfo2.GetShape()});
1823
1824 // Quantized input1 tensor.
1825 const float inputScale1 = 0.5f;
1826 const int32_t inputOffset1 = 5;
1827
1828 auto input1 = MakeTensor<T, 3>(inputTensorInfo1, std::vector<T>(
1829 {
1830 1, 2, 3,
1831 4, 5, 6,
1832 7, 8, 9,
1833 10, 11, 12,
1834 13, 14, 15,
1835 16, 17, 18,
1836
1837 19, 20, 21,
1838 22, 23, 24,
1839 25, 26, 27,
1840 28, 29, 30,
1841 31, 32, 33,
1842 34, 35, 36
1843 }));
1844
1845 // Quatized input2 tensor.
1846 const float inputScale2 = 0.2f;
1847 const int32_t inputOffset2 = 10;
1848
1849 auto input2 = MakeTensor<T, 3>(inputTensorInfo2, std::vector<T>(
1850 {
1851 37, 38, 39,
1852 40, 41, 42,
1853 43, 44, 45,
1854 46, 47, 48,
1855 49, 50, 51,
1856 52, 53, 54
1857 }));
1858
1859 // Quantized output tensor.
1860 const float outputScale = 0.1f;
1861 const int32_t outputOffset = 20;
1862
1863 LayerTestResult<T, 3> ret(outputTensorInfo);
1864
1865 ret.outputExpected = MakeTensor<T, 3>(outputTensorInfo, std::vector<T>(
1866 {
1867 0, 5, 74,
1868 10, 15, 76,
1869 20, 25, 78,
1870 30, 35, 80,
1871 40, 45, 82,
1872 50, 55, 84,
1873
1874 60, 65, 86,
1875 70, 75, 88,
1876 80, 85, 90,
1877 90, 95, 92,
1878 100, 105, 94,
1879 110, 115, 96,
1880
1881 120, 125, 98,
1882 130, 135, 100,
1883 140, 145, 102,
1884 150, 155, 104,
1885 160, 165, 106,
1886 170, 175, 108
1887 }));
1888
1889 outputTensorInfo.SetQuantizationScale(outputScale);
1890 outputTensorInfo.SetQuantizationOffset(outputOffset);
1891 inputTensorInfo1.SetQuantizationScale(inputScale1);
1892 inputTensorInfo1.SetQuantizationOffset(inputOffset1);
1893 inputTensorInfo2.SetQuantizationScale(inputScale2);
1894 inputTensorInfo2.SetQuantizationOffset(inputOffset2);
1895
1896 std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
1897 armnn::ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
1898
1899 std::vector<unsigned int> wOrigin2 = { 0, 0, 2 }; //Extent of the window is defined by size of input[1].
1900 armnn::ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
1901
1902 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
1903
1904 bool subTensorsSupported = useSubtensor && workloadFactory.SupportsSubTensors();
1905
1906 std::unique_ptr<armnn::ITensorHandle> inputHandle1 =
1907 subTensorsSupported ?
1908 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
1909 workloadFactory.CreateTensorHandle(inputTensorInfo1);
1910
1911 std::unique_ptr<armnn::ITensorHandle> inputHandle2 =
1912 subTensorsSupported ?
1913 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
1914 workloadFactory.CreateTensorHandle(inputTensorInfo2);
1915
1916 armnn::ConcatQueueDescriptor data;
1917 armnn::OriginsDescriptor desc = armnn::CreateDescriptorForConcatenation(
1918 inputTensorShapes.begin(),inputTensorShapes.end(), 2);
1919 data.m_Parameters = desc;
1920
1921 armnn::WorkloadInfo info;
1922 AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
1923 AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
1924 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
1925
1926 data.m_ViewOrigins.push_back(window1);
1927 data.m_ViewOrigins.push_back(window2);
1928
1929 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(data, info);
1930
1931 inputHandle1->Allocate();
1932 inputHandle2->Allocate();
1933 outputHandle->Allocate();
1934
1935 CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0]);
1936 CopyDataToITensorHandle(inputHandle2.get(), &input2[0][0][0]);
1937
1938 workload->PostAllocationConfigure();
1939 workload->Execute();
1940
1941 CopyDataFromITensorHandle(&ret.output[0][0][0], outputHandle.get());
1942
1943 return ret;
1944}
1945
1946//
1947// Explicit template specializations
1948//
1949
1950template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedAsymm8>, 3>
1951ConcatDifferentInputOutputQParamTest<armnn::DataType::QuantisedAsymm8>(
1952 armnn::IWorkloadFactory& workloadFactory,
1953 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1954 bool useSubtensor);
1955
1956template LayerTestResult<armnn::ResolveType<armnn::DataType::QuantisedSymm16>, 3>
1957ConcatDifferentInputOutputQParamTest<armnn::DataType::QuantisedSymm16>(
1958 armnn::IWorkloadFactory& workloadFactory,
1959 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
1960 bool useSubtensor);
1961
1962//
1963// Implementation functions
1964//
1965
1966LayerTestResult<float,3> ConcatTest(
1967 armnn::IWorkloadFactory& workloadFactory,
1968 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
1969{
1970 unsigned int outputWidth = 3;
1971 unsigned int outputHeight = 6;
1972 unsigned int outputChannels = 3;
1973
1974 unsigned int inputWidth1 = 3;
1975 unsigned int inputHeight1 = 6;
1976 unsigned int inputChannels1 = 2;
1977
1978 unsigned int inputWidth2 = 3;
1979 unsigned int inputHeight2 = 6;
1980 unsigned int inputChannels2 = 1;
1981
1982 // Define the tensor descriptors.
1983 armnn::TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, armnn::DataType::Float32);
1984 armnn::TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, armnn::DataType::Float32);
1985 armnn::TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, armnn::DataType::Float32);
1986
1987 LayerTestResult<float,3> ret(outputTensorInfo);
1988
1989 ret.outputExpected = MakeTensor<float, 3>(outputTensorInfo, std::vector<float>(
1990 {
1991 1.0f, 2.0f, 3.0f,
1992 4.0f, 5.0f, 6.0f,
1993 7.0f, 8.0f, 9.0f,
1994 10.0f, 11.0f, 12.0f,
1995 13.0f, 14.0f, 15.0f,
1996 16.0f, 17.0f, 18.0f,
1997
1998 19.0f, 20.0f, 21.0f,
1999 22.0f, 23.0f, 24.0f,
2000 25.0f, 26.0f, 27.0f,
2001 28.0f, 29.0f, 30.0f,
2002 31.0f, 32.0f, 33.0f,
2003 34.0f, 35.0f, 36.0f,
2004
2005 37.0f, 38.0f, 39.0f,
2006 40.0f, 41.0f, 42.0f,
2007 43.0f, 44.0f, 45.0f,
2008 46.0f, 47.0f, 48.0f,
2009 49.0f, 50.0f, 51.0f,
2010 52.0f, 53.0f, 54.0f,
2011 })
2012 );
2013
2014 auto input1 = MakeTensor<float, 3>(inputTensorInfo1, std::vector<float>(
2015 {
2016 1.0f, 2.0f, 3.0f,
2017 4.0f, 5.0f, 6.0f,
2018 7.0f, 8.0f, 9.0f,
2019 10.0f, 11.0f, 12.0f,
2020 13.0f, 14.0f, 15.0f,
2021 16.0f, 17.0f, 18.0f,
2022
2023 19.0f, 20.0f, 21.0f,
2024 22.0f, 23.0f, 24.0f,
2025 25.0f, 26.0f, 27.0f,
2026 28.0f, 29.0f, 30.0f,
2027 31.0f, 32.0f, 33.0f,
2028 34.0f, 35.0f, 36.0f,
2029 })
2030 );
2031
2032 auto input2 = MakeTensor<float, 3>(inputTensorInfo2, std::vector<float>(
2033 {
2034 37.0f, 38.0f, 39.0f,
2035 40.0f, 41.0f, 42.0f,
2036 43.0f, 44.0f, 45.0f,
2037 46.0f, 47.0f, 48.0f,
2038 49.0f, 50.0f, 51.0f,
2039 52.0f, 53.0f, 54.0f,
2040 })
2041 );
2042
2043 std::vector<unsigned int> wOrigin1 = {0, 0, 0}; //Extent of the window is defined by size of input[0].
2044 armnn::ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2045
2046 std::vector<unsigned int> wOrigin2 = {2, 0, 0}; //Extent of the window is defined by size of input[1].
2047 armnn::ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2048
2049 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
2050
2051 bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2052
2053 std::unique_ptr<armnn::ITensorHandle> inputHandle1 =
2054 subTensorsSupported ?
2055 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2056 workloadFactory.CreateTensorHandle(inputTensorInfo1);
2057
2058 std::unique_ptr<armnn::ITensorHandle> inputHandle2 =
2059 subTensorsSupported ?
2060 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2061 workloadFactory.CreateTensorHandle(inputTensorInfo2);
2062
2063 armnn::ConcatQueueDescriptor data;
2064 armnn::WorkloadInfo info;
2065 AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2066 AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2067 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2068
2069 data.m_ViewOrigins.push_back(window1);
2070 data.m_ViewOrigins.push_back(window2);
2071
2072 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(data, info);
2073
2074 inputHandle1->Allocate();
2075 inputHandle2->Allocate();
2076 outputHandle->Allocate();
2077
2078 CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0]);
2079 CopyDataToITensorHandle(inputHandle2.get(), &input2[0][0][0]);
2080
2081 workload->PostAllocationConfigure();
2082 workload->Execute();
2083
2084 CopyDataFromITensorHandle(&ret.output[0][0][0], outputHandle.get());
2085
2086 return ret;
2087}
2088
2089LayerTestResult<float, 1> Concat1dTest(
2090 armnn::IWorkloadFactory& workloadFactory,
2091 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2092{
2093 return Concat1dTestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2094}
2095
2096LayerTestResult<float, 2> Concat2dDim0Test(
2097 armnn::IWorkloadFactory& workloadFactory,
2098 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2099{
2100 return Concat2dDim0TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2101}
2102
2103LayerTestResult<float, 2> Concat2dDim1Test(
2104 armnn::IWorkloadFactory& workloadFactory,
2105 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2106{
2107 return Concat2dDim1TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2108}
2109
2110LayerTestResult<float, 2> Concat2dDim0DiffInputDimsTest(
2111 armnn::IWorkloadFactory& workloadFactory,
2112 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2113{
2114 return Concat2dDim0DiffInputDimsTestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2115}
2116
2117LayerTestResult<float, 2> Concat2dDim1DiffInputDimsTest(
2118 armnn::IWorkloadFactory& workloadFactory,
2119 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2120{
2121 return Concat2dDim1DiffInputDimsTestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2122}
2123
2124LayerTestResult<float, 3> Concat3dDim0Test(
2125 armnn::IWorkloadFactory& workloadFactory,
2126 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2127{
2128 return Concat3dDim0TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2129}
2130
2131LayerTestResult<float, 3> Concat3dDim1Test(
2132 armnn::IWorkloadFactory& workloadFactory,
2133 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2134{
2135 return Concat3dDim1TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2136}
2137
2138LayerTestResult<float, 3> Concat3dDim2Test(
2139 armnn::IWorkloadFactory& workloadFactory,
2140 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2141 bool useSubtensor)
2142{
2143 return Concat3dDim2TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, useSubtensor, 0.0f, 0);
2144}
2145
2146LayerTestResult<float, 3> Concat3dDim0DiffInputDimsTest(
2147 armnn::IWorkloadFactory& workloadFactory,
2148 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2149{
2150 return Concat3dDim0DiffInputDimsTestImpl<armnn::DataType::Float32>(
2151 workloadFactory, memoryManager, 0.0f, 0);
2152}
2153
2154LayerTestResult<float, 3> Concat3dDim1DiffInputDimsTest(
2155 armnn::IWorkloadFactory& workloadFactory,
2156 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2157{
2158 return Concat3dDim1DiffInputDimsTestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2159}
2160
2161LayerTestResult<float, 3> Concat3dDim2DiffInputDimsTest(
2162 armnn::IWorkloadFactory& workloadFactory,
2163 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2164 bool useSubtensor)
2165{
2166 return Concat3dDim2DiffInputDimsTestImpl<armnn::DataType::Float32>(
2167 workloadFactory, memoryManager, useSubtensor, 0.0f, 0);
2168}
2169
2170LayerTestResult<float, 4> Concat4dDim0Test(
2171 armnn::IWorkloadFactory& workloadFactory,
2172 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2173{
2174 return Concat4dDim0TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2175}
2176
2177LayerTestResult<float, 4> Concat4dDim1Test(
2178 armnn::IWorkloadFactory& workloadFactory,
2179 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2180{
2181 return Concat4dDim1TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2182}
2183
2184LayerTestResult<float, 4> Concat4dDim2Test(
2185 armnn::IWorkloadFactory& workloadFactory,
2186 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2187{
2188 return Concat4dDim2TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2189}
2190
2191LayerTestResult<float, 4> Concat4dDim3Test(
2192 armnn::IWorkloadFactory& workloadFactory,
2193 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2194 bool useSubtensor)
2195{
2196 return Concat4dDim3TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0, useSubtensor);
2197}
2198
2199LayerTestResult<float, 4> Concat4dDiffShapeDim0Test(
2200 armnn::IWorkloadFactory& workloadFactory,
2201 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2202{
2203 return Concat4dDiffShapeDim0TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2204}
2205
2206LayerTestResult<float, 4> Concat4dDiffShapeDim1Test(
2207 armnn::IWorkloadFactory& workloadFactory,
2208 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2209{
2210 return Concat4dDiffShapeDim1TestImpl<armnn::DataType::Float32>(
2211 workloadFactory, memoryManager, 0.0f, 0);
2212}
2213
2214LayerTestResult<float, 4> Concat4dDiffShapeDim2Test(
2215 armnn::IWorkloadFactory& workloadFactory,
2216 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2217{
2218 return Concat4dDiffShapeDim2TestImpl<armnn::DataType::Float32>(workloadFactory, memoryManager, 0.0f, 0);
2219}
2220
2221LayerTestResult<float, 4> Concat4dDiffShapeDim3Test(
2222 armnn::IWorkloadFactory& workloadFactory,
2223 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2224 bool useSubtensor)
2225{
2226 return Concat4dDiffShapeDim3TestImpl<armnn::DataType::Float32>(
2227 workloadFactory, memoryManager, 0.0f, 0, useSubtensor);
2228}
2229
Matthew Jackson9bff1442019-09-12 09:08:23 +01002230LayerTestResult<armnn::Half, 3> ConcatFloat16Test(
2231 armnn::IWorkloadFactory& workloadFactory,
2232 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2233{
2234 return Concat3dDim1TestImpl<armnn::DataType::Float16>(workloadFactory, memoryManager, 0.0f, 0);
2235}
2236
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01002237LayerTestResult<uint8_t, 3> ConcatUint8DifferentQParamsTest(
2238 armnn::IWorkloadFactory& workloadFactory,
2239 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2240{
2241 unsigned int outputWidth = 3;
2242 unsigned int outputHeight = 6;
2243 unsigned int outputChannels = 3;
2244
2245 unsigned int inputWidth1 = 3;
2246 unsigned int inputHeight1 = 6;
2247 unsigned int inputChannels1 = 2;
2248
2249 unsigned int inputWidth2 = 3;
2250 unsigned int inputHeight2 = 6;
2251 unsigned int inputChannels2 = 1;
2252
2253 // Defines the tensor descriptors.
2254 armnn::TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, armnn::DataType::QuantisedAsymm8);
2255 armnn::TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, armnn::DataType::QuantisedAsymm8);
2256 armnn::TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, armnn::DataType::QuantisedAsymm8);
2257
2258 // Quantized input1 tensor. Range [-3, 1]
2259 const float inputScale1 = 0.015686f;
2260 const int32_t inputOffset1 = 192;
2261
2262 auto input1 = MakeTensor<uint8_t, 3>(inputTensorInfo1, std::vector<uint8_t>(
2263 {
2264 1, 2, 3,
2265 4, 5, 6,
2266 7, 8, 9,
2267 10, 11, 12,
2268 13, 14, 15,
2269 16, 17, 18,
2270
2271 19, 20, 21,
2272 22, 23, 24,
2273 25, 26, 27,
2274 28, 29, 30,
2275 31, 32, 33,
2276 34, 35, 36,
2277 })
2278 );
2279
2280 // Quatized input2 tensor. Range [-1, 4]
2281 const float inputScale2 = 0.019608f;
2282 const int32_t inputOffset2 = 50;
2283
2284 auto input2 = MakeTensor<uint8_t, 3>(inputTensorInfo2, std::vector<uint8_t>(
2285 {
2286 37, 38, 39,
2287 40, 41, 42,
2288 43, 44, 45,
2289 46, 47, 48,
2290 49, 50, 51,
2291 52, 53, 54,
2292 })
2293 );
2294
2295 // Output has the same quantization parameters than input1,
2296 // so that only the requantization of input2 is required
2297 const float outputScale = 0.015686f;
2298 const int32_t outputOffset = 192;
2299
2300 LayerTestResult<uint8_t, 3> ret(outputTensorInfo);
2301
2302 ret.outputExpected = MakeTensor<uint8_t, 3>(outputTensorInfo, std::vector<uint8_t>(
2303 {
2304 1, 2, 3,
2305 4, 5, 6,
2306 7, 8, 9,
2307 10, 11, 12,
2308 13, 14, 15,
2309 16, 17, 18,
2310
2311 19, 20, 21,
2312 22, 23, 24,
2313 25, 26, 27,
2314 28, 29, 30,
2315 31, 32, 33,
2316 34, 35, 36,
2317
2318 176, 177, 178,
2319 179, 181, 182,
2320 183, 184, 186,
2321 187, 188, 189,
2322 191, 192, 193,
2323 195, 196, 197,
2324 })
2325 );
2326
2327 outputTensorInfo.SetQuantizationScale(outputScale);
2328 outputTensorInfo.SetQuantizationOffset(outputOffset);
2329 inputTensorInfo1.SetQuantizationScale(inputScale1);
2330 inputTensorInfo1.SetQuantizationOffset(inputOffset1);
2331 inputTensorInfo2.SetQuantizationScale(inputScale2);
2332 inputTensorInfo2.SetQuantizationOffset(inputOffset2);
2333
2334 std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2335 armnn::ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2336
2337 std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2338 armnn::ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2339
2340 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
2341
2342 bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2343
2344 std::unique_ptr<armnn::ITensorHandle> inputHandle1 =
2345 subTensorsSupported ?
2346 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2347 workloadFactory.CreateTensorHandle(inputTensorInfo1);
2348
2349 std::unique_ptr<armnn::ITensorHandle> inputHandle2 =
2350 subTensorsSupported ?
2351 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2352 workloadFactory.CreateTensorHandle(inputTensorInfo2);
2353
2354 armnn::ConcatQueueDescriptor data;
2355 armnn::WorkloadInfo info;
2356 AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2357 AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2358 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2359
2360 data.m_ViewOrigins.push_back(window1);
2361 data.m_ViewOrigins.push_back(window2);
2362
2363 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(data, info);
2364
2365 inputHandle1->Allocate();
2366 inputHandle2->Allocate();
2367 outputHandle->Allocate();
2368
2369 CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0]);
2370 CopyDataToITensorHandle(inputHandle2.get(), &input2[0][0][0]);
2371
2372 workload->PostAllocationConfigure();
2373 workload->Execute();
2374
2375 CopyDataFromITensorHandle(&ret.output[0][0][0], outputHandle.get());
2376
2377 return ret;
2378}
2379
2380LayerTestResult<uint8_t, 3> ConcatUint8Test(
2381 armnn::IWorkloadFactory& workloadFactory,
2382 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2383{
2384 unsigned int outputWidth = 3;
2385 unsigned int outputHeight = 6;
2386 unsigned int outputChannels = 3;
2387
2388 unsigned int inputWidth1 = 3;
2389 unsigned int inputHeight1 = 6;
2390 unsigned int inputChannels1 = 2;
2391
2392 unsigned int inputWidth2 = 3;
2393 unsigned int inputHeight2 = 6;
2394 unsigned int inputChannels2 = 1;
2395
2396 // Defines the tensor descriptors.
2397 armnn::TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, armnn::DataType::QuantisedAsymm8);
2398 armnn::TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, armnn::DataType::QuantisedAsymm8);
2399 armnn::TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, armnn::DataType::QuantisedAsymm8);
2400
2401 // Arbitrary scale and offsets. They don't really matter as the Concat operator doesn't dequantize/quantize them.
2402 const float scale = 0.13497836f;
2403 const int32_t offset = -7;
2404
2405 outputTensorInfo.SetQuantizationScale(scale);
2406 outputTensorInfo.SetQuantizationOffset(offset);
2407 inputTensorInfo1.SetQuantizationScale(scale);
2408 inputTensorInfo1.SetQuantizationOffset(offset);
2409 inputTensorInfo2.SetQuantizationScale(scale);
2410 inputTensorInfo2.SetQuantizationOffset(offset);
2411
2412 LayerTestResult<uint8_t, 3> ret(outputTensorInfo);
2413
2414 ret.outputExpected = MakeTensor<uint8_t, 3>(outputTensorInfo, std::vector<uint8_t>(
2415 {
2416 1, 2, 3,
2417 4, 5, 6,
2418 7, 8, 9,
2419 10, 11, 12,
2420 13, 14, 15,
2421 16, 17, 18,
2422
2423 19, 20, 21,
2424 22, 23, 24,
2425 25, 26, 27,
2426 28, 29, 30,
2427 31, 32, 33,
2428 34, 35, 36,
2429
2430 37, 38, 39,
2431 40, 41, 42,
2432 43, 44, 45,
2433 46, 47, 48,
2434 49, 50, 51,
2435 52, 53, 54,
2436 })
2437 );
2438
2439 auto input1 = MakeTensor<uint8_t, 3>(inputTensorInfo1, std::vector<uint8_t>(
2440 {
2441 1, 2, 3,
2442 4, 5, 6,
2443 7, 8, 9,
2444 10, 11, 12,
2445 13, 14, 15,
2446 16, 17, 18,
2447
2448 19, 20, 21,
2449 22, 23, 24,
2450 25, 26, 27,
2451 28, 29, 30,
2452 31, 32, 33,
2453 34, 35, 36,
2454 })
2455 );
2456
2457 auto input2 = MakeTensor<uint8_t, 3>(inputTensorInfo2, std::vector<uint8_t>(
2458 {
2459 37, 38, 39,
2460 40, 41, 42,
2461 43, 44, 45,
2462 46, 47, 48,
2463 49, 50, 51,
2464 52, 53, 54,
2465 })
2466 );
2467
2468 std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2469 armnn::ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2470
2471 std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2472 armnn::ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2473
2474
2475 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
2476
2477 bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2478
2479 std::unique_ptr<armnn::ITensorHandle> inputHandle1 =
2480 subTensorsSupported ?
2481 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2482 workloadFactory.CreateTensorHandle(inputTensorInfo1);
2483
2484 std::unique_ptr<armnn::ITensorHandle> inputHandle2 =
2485 subTensorsSupported ?
2486 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2487 workloadFactory.CreateTensorHandle(inputTensorInfo2);
2488
2489
2490 armnn::ConcatQueueDescriptor data;
2491 armnn::WorkloadInfo info;
2492 AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2493 AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2494 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2495
2496 data.m_ViewOrigins.push_back(window1);
2497 data.m_ViewOrigins.push_back(window2);
2498
2499 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(data, info);
2500
2501 inputHandle1->Allocate();
2502 inputHandle2->Allocate();
2503 outputHandle->Allocate();
2504
2505 CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0]);
2506 CopyDataToITensorHandle(inputHandle2.get(), &input2[0][0][0]);
2507
2508 workload->PostAllocationConfigure();
2509 workload->Execute();
2510
2511 CopyDataFromITensorHandle(&ret.output[0][0][0], outputHandle.get());
2512
2513 return ret;
2514}
2515
2516LayerTestResult<uint16_t, 3> ConcatUint16Test(
2517 armnn::IWorkloadFactory& workloadFactory,
2518 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2519{
2520 unsigned int outputWidth = 3;
2521 unsigned int outputHeight = 6;
2522 unsigned int outputChannels = 3;
2523
2524 unsigned int inputWidth1 = 3;
2525 unsigned int inputHeight1 = 6;
2526 unsigned int inputChannels1 = 2;
2527
2528 unsigned int inputWidth2 = 3;
2529 unsigned int inputHeight2 = 6;
2530 unsigned int inputChannels2 = 1;
2531
2532 // Defines the tensor descriptors.
2533 armnn::TensorInfo outputTensorInfo({ outputChannels, outputHeight, outputWidth }, armnn::DataType::QuantisedSymm16);
2534 armnn::TensorInfo inputTensorInfo1({ inputChannels1, inputHeight1, inputWidth1 }, armnn::DataType::QuantisedSymm16);
2535 armnn::TensorInfo inputTensorInfo2({ inputChannels2, inputHeight2, inputWidth2 }, armnn::DataType::QuantisedSymm16);
2536
2537 // Arbitrary scale and offsets. They don't really matter as the Concat operator doesn't dequantize/quantize them.
2538 const float scale = 0.13497836f;
2539 const int32_t offset = -7;
2540
2541 outputTensorInfo.SetQuantizationScale(scale);
2542 outputTensorInfo.SetQuantizationOffset(offset);
2543 inputTensorInfo1.SetQuantizationScale(scale);
2544 inputTensorInfo1.SetQuantizationOffset(offset);
2545 inputTensorInfo2.SetQuantizationScale(scale);
2546 inputTensorInfo2.SetQuantizationOffset(offset);
2547
2548 LayerTestResult<uint16_t, 3> ret(outputTensorInfo);
2549
2550 ret.outputExpected = MakeTensor<uint16_t, 3>(outputTensorInfo, std::vector<uint16_t>(
2551 {
2552 1, 2, 3,
2553 4, 5, 6,
2554 7, 8, 9,
2555 10, 11, 12,
2556 13, 14, 15,
2557 16, 17, 18,
2558
2559 19, 20, 21,
2560 22, 23, 24,
2561 25, 26, 27,
2562 28, 29, 30,
2563 31, 32, 33,
2564 34, 35, 36,
2565
2566 37, 38, 39,
2567 40, 41, 42,
2568 43, 44, 45,
2569 46, 47, 48,
2570 49, 50, 51,
2571 52, 53, 54,
2572 }));
2573
2574 auto input1 = MakeTensor<uint16_t, 3>(inputTensorInfo1, std::vector<uint16_t>(
2575 {
2576 1, 2, 3,
2577 4, 5, 6,
2578 7, 8, 9,
2579 10, 11, 12,
2580 13, 14, 15,
2581 16, 17, 18,
2582
2583 19, 20, 21,
2584 22, 23, 24,
2585 25, 26, 27,
2586 28, 29, 30,
2587 31, 32, 33,
2588 34, 35, 36,
2589 }));
2590
2591 auto input2 = MakeTensor<uint16_t, 3>(inputTensorInfo2, std::vector<uint16_t>(
2592 {
2593 37, 38, 39,
2594 40, 41, 42,
2595 43, 44, 45,
2596 46, 47, 48,
2597 49, 50, 51,
2598 52, 53, 54,
2599 }));
2600
2601 std::vector<unsigned int> wOrigin1 = { 0, 0, 0 }; //Extent of the window is defined by size of input[0].
2602 armnn::ConcatQueueDescriptor::ViewOrigin window1(wOrigin1);
2603
2604 std::vector<unsigned int> wOrigin2 = { 2, 0, 0 }; //Extent of the window is defined by size of input[1].
2605 armnn::ConcatQueueDescriptor::ViewOrigin window2(wOrigin2);
2606
2607
2608 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
2609
2610 bool subTensorsSupported = workloadFactory.SupportsSubTensors();
2611
2612 std::unique_ptr<armnn::ITensorHandle> inputHandle1 =
2613 subTensorsSupported ?
2614 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo1.GetShape(), wOrigin1.data()) :
2615 workloadFactory.CreateTensorHandle(inputTensorInfo1);
2616
2617 std::unique_ptr<armnn::ITensorHandle> inputHandle2 =
2618 subTensorsSupported ?
2619 workloadFactory.CreateSubTensorHandle(*outputHandle, inputTensorInfo2.GetShape(), wOrigin2.data()) :
2620 workloadFactory.CreateTensorHandle(inputTensorInfo2);
2621
2622
2623 armnn::ConcatQueueDescriptor data;
2624 armnn::WorkloadInfo info;
2625 AddInputToWorkload(data, info, inputTensorInfo1, inputHandle1.get());
2626 AddInputToWorkload(data, info, inputTensorInfo2, inputHandle2.get());
2627 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
2628
2629 data.m_ViewOrigins.push_back(window1);
2630 data.m_ViewOrigins.push_back(window2);
2631
2632 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateConcat(data, info);
2633
2634 inputHandle1->Allocate();
2635 inputHandle2->Allocate();
2636 outputHandle->Allocate();
2637
2638 CopyDataToITensorHandle(inputHandle1.get(), &input1[0][0][0]);
2639 CopyDataToITensorHandle(inputHandle2.get(), &input2[0][0][0]);
2640
2641 workload->PostAllocationConfigure();
2642 workload->Execute();
2643
2644 CopyDataFromITensorHandle(&ret.output[0][0][0], outputHandle.get());
2645
2646 return ret;
2647}
2648
2649LayerTestResult<uint8_t, 1> Concat1dUint8Test(
2650 armnn::IWorkloadFactory& workloadFactory,
2651 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2652{
2653 return Concat1dTestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2654}
2655
2656LayerTestResult<uint8_t, 2> Concat2dDim0Uint8Test(
2657 armnn::IWorkloadFactory& workloadFactory,
2658 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2659{
2660 return Concat2dDim0TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2661}
2662
2663LayerTestResult<uint8_t, 2> Concat2dDim1Uint8Test(
2664 armnn::IWorkloadFactory& workloadFactory,
2665 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2666{
2667 return Concat2dDim1TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2668}
2669
2670LayerTestResult<uint8_t, 2> Concat2dDim0DiffInputDimsUint8Test(
2671 armnn::IWorkloadFactory& workloadFactory,
2672 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2673{
2674 return Concat2dDim0DiffInputDimsTestImpl<armnn::DataType::QuantisedAsymm8>(
2675 workloadFactory, memoryManager, 0.5f, -1);
2676}
2677
2678LayerTestResult<uint8_t, 2> Concat2dDim1DiffInputDimsUint8Test(
2679 armnn::IWorkloadFactory& workloadFactory,
2680 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2681{
2682 return Concat2dDim1DiffInputDimsTestImpl<armnn::DataType::QuantisedAsymm8>(
2683 workloadFactory, memoryManager, 0.5f, -1);
2684}
2685
2686LayerTestResult<uint8_t, 3> Concat3dDim0Uint8Test(
2687 armnn::IWorkloadFactory& workloadFactory,
2688 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2689{
2690 return Concat3dDim0TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2691}
2692
2693LayerTestResult<uint8_t, 3> Concat3dDim1Uint8Test(
2694 armnn::IWorkloadFactory& workloadFactory,
2695 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2696{
2697 return Concat3dDim1TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2698}
2699
2700LayerTestResult<uint8_t, 3> Concat3dDim2Uint8Test(
2701 armnn::IWorkloadFactory& workloadFactory,
2702 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2703 bool useSubtensor)
2704{
2705 return Concat3dDim2TestImpl<armnn::DataType::QuantisedAsymm8>(
2706 workloadFactory, memoryManager, useSubtensor, 0.5f, -1);
2707}
2708
2709LayerTestResult<uint8_t, 3> Concat3dDim0DiffInputDimsUint8Test(
2710 armnn::IWorkloadFactory& workloadFactory,
2711 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2712{
2713 return Concat3dDim0TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2714}
2715
2716LayerTestResult<uint8_t, 3> Concat3dDim1DiffInputDimsUint8Test(
2717 armnn::IWorkloadFactory& workloadFactory,
2718 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2719{
2720 return Concat3dDim1DiffInputDimsTestImpl<armnn::DataType::QuantisedAsymm8>(
2721 workloadFactory, memoryManager, 0.5f, -1);
2722}
2723
2724LayerTestResult<uint8_t, 3> Concat3dDim2DiffInputDimsUint8Test(
2725 armnn::IWorkloadFactory& workloadFactory,
2726 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2727 bool useSubtensor)
2728{
2729 return Concat3dDim2DiffInputDimsTestImpl<armnn::DataType::QuantisedAsymm8>(
2730 workloadFactory, memoryManager, useSubtensor, 0.5f, -1);
2731}
2732
2733LayerTestResult<uint8_t, 4> Concat4dDim0Uint8Test(
2734 armnn::IWorkloadFactory& workloadFactory,
2735 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2736{
2737 return Concat4dDim0TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2738}
2739
2740LayerTestResult<uint8_t, 4> Concat4dDim1Uint8Test(
2741 armnn::IWorkloadFactory& workloadFactory,
2742 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2743{
2744 return Concat4dDim1TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2745}
2746
2747LayerTestResult<uint8_t, 4> Concat4dDim2Uint8Test(
2748 armnn::IWorkloadFactory& workloadFactory,
2749 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2750{
2751 return Concat4dDim2TestImpl<armnn::DataType::QuantisedAsymm8>(workloadFactory, memoryManager, 0.5f, -1);
2752}
2753
2754LayerTestResult<uint8_t, 4> Concat4dDim3Uint8Test(
2755 armnn::IWorkloadFactory& workloadFactory,
2756 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, bool useSubtensor)
2757{
2758 return Concat4dDim3TestImpl<armnn::DataType::QuantisedAsymm8>(
2759 workloadFactory, memoryManager, 0.5f, -1, useSubtensor);
2760}
2761
2762LayerTestResult<uint8_t, 4> Concat4dDiffShapeDim0Uint8Test(
2763 armnn::IWorkloadFactory& workloadFactory,
2764 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2765{
2766 return Concat4dDiffShapeDim0TestImpl<armnn::DataType::QuantisedAsymm8>(
2767 workloadFactory, memoryManager, 0.5f, -1);
2768}
2769
2770LayerTestResult<uint8_t, 4> Concat4dDiffShapeDim1Uint8Test(
2771 armnn::IWorkloadFactory& workloadFactory,
2772 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2773{
2774 return Concat4dDiffShapeDim1TestImpl<armnn::DataType::QuantisedAsymm8>(
2775 workloadFactory, memoryManager, 0.5f, -1);
2776}
2777
2778LayerTestResult<uint8_t, 4> Concat4dDiffShapeDim2Uint8Test(
2779 armnn::IWorkloadFactory& workloadFactory,
2780 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager)
2781{
2782 return Concat4dDiffShapeDim2TestImpl<armnn::DataType::QuantisedAsymm8>(
2783 workloadFactory, memoryManager, 0.5f, -1);
2784}
2785
2786LayerTestResult<uint8_t, 4> Concat4dDiffShapeDim3Uint8Test(
2787 armnn::IWorkloadFactory& workloadFactory,
2788 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
2789 bool useSubtensor)
2790{
2791 return Concat4dDiffShapeDim3TestImpl<armnn::DataType::QuantisedAsymm8>(
2792 workloadFactory, memoryManager, 0.5f, -1, useSubtensor);
2793}