blob: 64e24e54aae4de5f898459b0db23954b9d072de0 [file] [log] [blame]
Narumol Prangnawarat0be43382019-05-27 11:29:59 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
7#include <ResolveType.hpp>
8
9#include <armnn/INetwork.hpp>
10
Matthew Sloyan171214c2020-09-09 09:07:37 +010011#include <armnn/utility/NumericCast.hpp>
12
Narumol Prangnawarat0be43382019-05-27 11:29:59 +010013#include <backendsCommon/test/CommonTestUtils.hpp>
14
Sadik Armagan1625efc2021-06-10 18:24:34 +010015#include <doctest/doctest.h>
Narumol Prangnawarat0be43382019-05-27 11:29:59 +010016
17#include <vector>
18
19namespace
20{
21
22template<typename armnn::DataType DataType>
23INetworkPtr CreateSplitterNetwork(const TensorShape& inputShape,
24 const std::vector<TensorShape>& outputShapes,
25 unsigned int splitAxis,
26 unsigned int numSplit,
27 const float qScale = 1.0f,
28 const int32_t qOffset = 0)
29{
30 using namespace armnn;
31 // Builds up the structure of the network.
32 INetworkPtr net(INetwork::Create());
33
34 TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset);
35
36 std::vector<unsigned int> splitterDimSizes(inputShape.GetNumDimensions());
37
38 // Add current input shape to splitterDimSizes
39 for (unsigned int i = 0; i < inputShape.GetNumDimensions(); ++i)
40 {
41 splitterDimSizes[i] = inputTensorInfo.GetShape()[i];
42 }
43
44 if (splitterDimSizes[splitAxis] % numSplit != 0)
45 {
46 throw ParseException("Number of splits must evenly divide the dimension");
47 }
48 splitterDimSizes[splitAxis] /= numSplit;
49
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +010050 SplitterDescriptor splitDesc(numSplit, inputShape.GetNumDimensions());
Narumol Prangnawarat0be43382019-05-27 11:29:59 +010051 for (unsigned int g = 0; g < numSplit; ++g)
52 {
53 // Set the size of the views.
54 for (unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
55 {
56 splitDesc.SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
57 }
58 splitDesc.SetViewOriginCoord(g, splitAxis, splitterDimSizes[splitAxis] * g);
59 }
60
61 IConnectableLayer* splitter = net->AddSplitterLayer(splitDesc, "splitter");
62 IConnectableLayer* input = net->AddInputLayer(0, "input");
63 Connect(input, splitter, inputTensorInfo, 0, 0);
64
65 for (unsigned int i = 0; i < outputShapes.size(); ++i)
66 {
67 TensorInfo outputTensorInfo(outputShapes[i], DataType, qScale, qOffset);
Matthew Sloyan171214c2020-09-09 09:07:37 +010068 IConnectableLayer* output = net->AddOutputLayer(armnn::numeric_cast<LayerBindingId>(i));
Narumol Prangnawarat0be43382019-05-27 11:29:59 +010069 Connect(splitter, output, outputTensorInfo, i, 0);
70 }
71
72 return net;
73}
74
75template<armnn::DataType ArmnnType>
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +010076void Splitter1dEndToEnd(const std::vector<BackendId>& backends)
77{
78 using namespace armnn;
79 using T = ResolveType<ArmnnType>;
80
81 unsigned int splitAxis = 0;
82 unsigned int numSplit = 2;
83 const TensorShape& inputShape = { 4 };
84 const std::vector<TensorShape> outputShapes{{ 2 }, { 2 }};
85
86 // Builds up the structure of the network
87 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
88
Sadik Armagan1625efc2021-06-10 18:24:34 +010089 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +010090
91 // Creates structures for input & output.
92 std::vector<T> inputData{ 1, 2, 3, 4 };
93
94 std::vector<T> expectedOutput0{ 1, 2 };
95 std::vector<T> expectedOutput1{ 3, 4 };
96
97 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
98 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 }, {1, expectedOutput1} };
99
100 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
101}
102
103template<armnn::DataType ArmnnType>
104void Splitter2dDim0EndToEnd(const std::vector<BackendId>& backends)
105{
106 using namespace armnn;
107 using T = ResolveType<ArmnnType>;
108
109 unsigned int splitAxis = 0;
110 unsigned int numSplit = 2;
111 const TensorShape& inputShape = { 4, 3 };
112 const std::vector<TensorShape> outputShapes{{ 2, 3 }, { 2, 3 }};
113
114 // Builds up the structure of the network
115 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
116
Sadik Armagan1625efc2021-06-10 18:24:34 +0100117 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100118
119 // Creates structures for input & output.
120 std::vector<T> inputData{
121 1, 2,
122 3, 4,
123 5, 6,
124 7, 8,
125 9, 10,
126 11, 12
127 };
128
129 std::vector<T> expectedOutput0{ 1, 2, 3, 4, 5, 6 };
130 std::vector<T> expectedOutput1{ 7, 8, 9, 10, 11, 12 };
131
132 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
133 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 }, {1, expectedOutput1} };
134
135 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
136}
137
138template<armnn::DataType ArmnnType>
139void Splitter2dDim1EndToEnd(const std::vector<BackendId>& backends)
140{
141 using namespace armnn;
142 using T = ResolveType<ArmnnType>;
143
144 unsigned int splitAxis = 1;
145 unsigned int numSplit = 3;
146 const TensorShape& inputShape = { 4, 3 };
147 const std::vector<TensorShape> outputShapes{{ 4, 1 }, { 4, 1 }, { 4, 1 }};
148
149 // Builds up the structure of the network
150 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
151
Sadik Armagan1625efc2021-06-10 18:24:34 +0100152 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100153
154 // Creates structures for input & output.
155 std::vector<T> inputData{
156 1, 2,
157 3, 4,
158 5, 6,
159 7, 8,
160 9, 10,
161 11, 12
162 };
163
164 std::vector<T> expectedOutput0{ 1, 4, 7, 10 };
165 std::vector<T> expectedOutput1{ 2, 5, 8, 11 };
166 std::vector<T> expectedOutput2{ 3, 6, 9, 12 };
167
168 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
169 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 },
170 { 1, expectedOutput1 },
171 { 2, expectedOutput2 } };
172
173 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
174}
175
176template<armnn::DataType ArmnnType>
177void Splitter3dDim0EndToEnd(const std::vector<BackendId>& backends)
178{
179 using namespace armnn;
180 using T = ResolveType<ArmnnType>;
181
182 unsigned int splitAxis = 0;
183 unsigned int numSplit = 2;
184 const TensorShape& inputShape = { 2, 4, 3 };
185 const std::vector<TensorShape> outputShapes{{ 1, 4, 3 }, { 1, 4, 3 }};
186
187 // Builds up the structure of the network
188 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
189
Sadik Armagan1625efc2021-06-10 18:24:34 +0100190 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100191
192 // Creates structures for input & output.
193 std::vector<T> inputData{
194 1, 2, 3,
195 4, 5, 6,
196 7, 8, 9,
197 10, 11, 12,
198 13, 14, 15,
199 16, 17, 18,
200 19, 20, 21,
201 22, 23, 24
202 };
203
204 std::vector<T> expectedOutput0{
205 1, 2, 3,
206 4, 5, 6,
207 7, 8, 9,
208 10, 11, 12
209 };
210 std::vector<T> expectedOutput1{
211 13, 14, 15,
212 16, 17, 18,
213 19, 20, 21,
214 22, 23, 24
215 };
216
217 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
218 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 },
219 { 1, expectedOutput1 } };
220
221 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
222}
223
224template<armnn::DataType ArmnnType>
225void Splitter3dDim1EndToEnd(const std::vector<BackendId>& backends)
226{
227 using namespace armnn;
228 using T = ResolveType<ArmnnType>;
229
230 unsigned int splitAxis = 1;
231 unsigned int numSplit = 2;
232 const TensorShape& inputShape = { 2, 4, 3 };
233 const std::vector<TensorShape> outputShapes{{ 2, 2, 3 }, { 2, 2, 3 }};
234
235 // Builds up the structure of the network
236 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
237
Sadik Armagan1625efc2021-06-10 18:24:34 +0100238 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100239
240 // Creates structures for input & output.
241 std::vector<T> inputData{
242 1, 2, 3,
243 4, 5, 6,
244 7, 8, 9,
245 10, 11, 12,
246 13, 14, 15,
247 16, 17, 18,
248 19, 20, 21,
249 22, 23, 24
250 };
251
252 std::vector<T> expectedOutput0{
253 1, 2, 3,
254 4, 5, 6,
255 13, 14, 15,
256 16, 17, 18
257 };
258 std::vector<T> expectedOutput1{
259 7, 8, 9,
260 10, 11, 12,
261 19, 20, 21,
262 22, 23, 24
263 };
264
265 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
266 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 },
267 { 1, expectedOutput1 } };
268
269 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
270}
271
272template<armnn::DataType ArmnnType>
273void Splitter3dDim2EndToEnd(const std::vector<BackendId>& backends)
274{
275 using namespace armnn;
276 using T = ResolveType<ArmnnType>;
277
278 unsigned int splitAxis = 2;
279 unsigned int numSplit = 3;
280 const TensorShape& inputShape = { 2, 4, 3 };
281 const std::vector<TensorShape> outputShapes{{ 2, 4, 1 }, { 2, 4, 1 }, { 2, 4, 1 }};
282
283 // Builds up the structure of the network
284 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
285
Sadik Armagan1625efc2021-06-10 18:24:34 +0100286 CHECK(net);
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100287
288 // Creates structures for input & output.
289 std::vector<T> inputData{
290 1, 2, 3,
291 4, 5, 6,
292 7, 8, 9,
293 10, 11, 12,
294 13, 14, 15,
295 16, 17, 18,
296 19, 20, 21,
297 22, 23, 24
298 };
299
300 std::vector<T> expectedOutput0{ 1, 4, 7, 10, 13, 16, 19, 22 };
301 std::vector<T> expectedOutput1{ 2, 5, 8, 11, 14, 17, 20, 23 };
302 std::vector<T> expectedOutput2{ 3, 6, 9, 12, 15, 18, 21, 24 };
303
304 std::map<int, std::vector<T>> inputTensorData = { { 0, inputData } };
305 std::map<int, std::vector<T>> expectedOutputData = { { 0, expectedOutput0 },
306 { 1, expectedOutput1 },
307 { 2, expectedOutput2 } };
308
309 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
310}
311
312template<armnn::DataType ArmnnType>
313void Splitter4dDim0EndToEnd(const std::vector<BackendId>& backends)
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100314{
315 using namespace armnn;
316 using T = ResolveType<ArmnnType>;
317
318 unsigned int splitAxis = 0;
319 unsigned int numSplit = 2;
320 const TensorShape& inputShape = { 4, 3, 2, 2 };
321 const std::vector<TensorShape> outputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
322
323 // Builds up the structure of the network
324 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
325
Sadik Armagan1625efc2021-06-10 18:24:34 +0100326 CHECK(net);
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100327
328 // Creates structures for input & output.
329 std::vector<T> inputData{
330 1, 2,
331 3, 4,
332 5, 6,
333 7, 8,
334 9, 10,
335 11, 12,
336 13, 14,
337 15, 16,
338 17, 18,
339 19, 20,
340 21, 22,
341 23, 24,
342 25, 26,
343 27, 28,
344 29, 30,
345 31, 32,
346 33, 34,
347 35, 36,
348 37, 38,
349 39, 40,
350 41, 42,
351 43, 44,
352 45, 46,
353 47, 48
354 };
355
356 std::vector<T> expectedOutput0{
357 1, 2,
358 3, 4,
359 5, 6,
360 7, 8,
361 9, 10,
362 11, 12,
363 13, 14,
364 15, 16,
365 17, 18,
366 19, 20,
367 21, 22,
368 23, 24
369 };
370
371 std::vector<T> expectedOutput1{
372 25, 26,
373 27, 28,
374 29, 30,
375 31, 32,
376 33, 34,
377 35, 36,
378 37, 38,
379 39, 40,
380 41, 42,
381 43, 44,
382 45, 46,
383 47, 48
384 };
385
386 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }};
387 std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
388
389 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
390}
391
392template<armnn::DataType ArmnnType>
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100393void Splitter4dDim1EndToEnd(const std::vector<BackendId>& backends)
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100394{
395 using namespace armnn;
396 using T = ResolveType<ArmnnType>;
397
398 unsigned int splitAxis = 1;
399 unsigned int numSplit = 2;
400 const TensorShape& inputShape = { 2, 6, 2, 2 };
401 const std::vector<TensorShape> outputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
402
403 // Builds up the structure of the network
404 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
405
Sadik Armagan1625efc2021-06-10 18:24:34 +0100406 CHECK(net);
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100407
408 // Creates structures for input & output.
409 std::vector<T> inputData{
410 1, 2,
411 3, 4,
412 5, 6,
413 7, 8,
414 9, 10,
415 11, 12,
416 13, 14,
417 15, 16,
418 17, 18,
419 19, 20,
420 21, 22,
421 23, 24,
422 25, 26,
423 27, 28,
424 29, 30,
425 31, 32,
426 33, 34,
427 35, 36,
428 37, 38,
429 39, 40,
430 41, 42,
431 43, 44,
432 45, 46,
433 47, 48
434 };
435
436 std::vector<T> expectedOutput0{
437 1, 2,
438 3, 4,
439 5, 6,
440 7, 8,
441 9, 10,
442 11, 12,
443 25, 26,
444 27, 28,
445 29, 30,
446 31, 32,
447 33, 34,
448 35, 36
449 };
450
451 std::vector<T> expectedOutput1{
452 13, 14,
453 15, 16,
454 17, 18,
455 19, 20,
456 21, 22,
457 23, 24,
458 37, 38,
459 39, 40,
460 41, 42,
461 43, 44,
462 45, 46,
463 47, 48
464 };
465
466 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }};
467 std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
468
469 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
470}
471
472template<armnn::DataType ArmnnType>
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100473void Splitter4dDim2EndToEnd(const std::vector<BackendId>& backends)
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100474{
475 using namespace armnn;
476 using T = ResolveType<ArmnnType>;
477
478 unsigned int splitAxis = 2;
479 unsigned int numSplit = 2;
480 const TensorShape& inputShape = { 2, 3, 4, 2 };
481 const std::vector<TensorShape> outputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
482
483 // Builds up the structure of the network
484 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
485
Sadik Armagan1625efc2021-06-10 18:24:34 +0100486 CHECK(net);
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100487
488 // Creates structures for input & output.
489 std::vector<T> inputData{
490 1, 2,
491 3, 4,
492 5, 6,
493 7, 8,
494 9, 10,
495 11, 12,
496 13, 14,
497 15, 16,
498 17, 18,
499 19, 20,
500 21, 22,
501 23, 24,
502 25, 26,
503 27, 28,
504 29, 30,
505 31, 32,
506 33, 34,
507 35, 36,
508 37, 38,
509 39, 40,
510 41, 42,
511 43, 44,
512 45, 46,
513 47, 48
514 };
515
516 std::vector<T> expectedOutput0{
517 1, 2,
518 3, 4,
519 9, 10,
520 11, 12,
521 17, 18,
522 19, 20,
523 25, 26,
524 27, 28,
525 33, 34,
526 35, 36,
527 41, 42,
528 43, 44
529 };
530
531 std::vector<T> expectedOutput1{
532 5, 6,
533 7, 8,
534 13, 14,
535 15, 16,
536 21, 22,
537 23, 24,
538 29, 30,
539 31, 32,
540 37, 38,
541 39, 40,
542 45, 46,
543 47, 48
544 };
545
546 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }};
547 std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
548
549 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
550}
551
552template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Narumol Prangnawarat0f072ab2019-05-29 14:12:46 +0100553void Splitter4dDim3EndToEnd(const std::vector<BackendId>& backends)
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100554{
555 using namespace armnn;
556
557 unsigned int splitAxis = 3;
558 unsigned int numSplit = 2;
559 const TensorShape& inputShape = { 2, 3, 4, 2 };
560 const std::vector<TensorShape> outputShapes{{ 2, 3, 4, 1 }, { 2, 3, 4, 1 }};
561
562 // Builds up the structure of the network
563 INetworkPtr net = CreateSplitterNetwork<ArmnnType>(inputShape, outputShapes, splitAxis, numSplit);
564
Sadik Armagan1625efc2021-06-10 18:24:34 +0100565 CHECK(net);
Narumol Prangnawarat0be43382019-05-27 11:29:59 +0100566
567 // Creates structures for input & output.
568 std::vector<T> inputData{
569 1, 2,
570 3, 4,
571 5, 6,
572 7, 8,
573 9, 10,
574 11, 12,
575 13, 14,
576 15, 16,
577 17, 18,
578 19, 20,
579 21, 22,
580 23, 24,
581 25, 26,
582 27, 28,
583 29, 30,
584 31, 32,
585 33, 34,
586 35, 36,
587 37, 38,
588 39, 40,
589 41, 42,
590 43, 44,
591 45, 46,
592 47, 48
593 };
594
595 std::vector<T> expectedOutput0{
596 1, 3, 5, 7,
597 9, 11, 13, 15,
598 17, 19, 21, 23,
599 25, 27, 29, 31,
600 33, 35, 37, 39,
601 41, 43, 45, 47
602 };
603
604 std::vector<T> expectedOutput1{
605 2, 4, 6, 8,
606 10, 12, 14, 16,
607 18, 20, 22, 24,
608 26, 28, 30, 32,
609 34, 36, 38, 40,
610 42, 44, 46, 48
611 };
612
613 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }};
614 std::map<int, std::vector<T>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
615
616 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(net), inputTensorData, expectedOutputData, backends);
617}
618
619} // anonymous namespace