• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 
11 #include <armnn/utility/NumericCast.hpp>
12 
13 #include <CommonTestUtils.hpp>
14 
15 #include <doctest/doctest.h>
16 
17 #include <vector>
18 
19 namespace
20 {
21 
22 template<typename armnn::DataType DataType>
CreateSplitterNetwork(const TensorShape & inputShape,const std::vector<TensorShape> & outputShapes,unsigned int splitAxis,unsigned int numSplit,const float qScale=1.0f,const int32_t qOffset=0)23 INetworkPtr 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, true);
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 
50     SplitterDescriptor splitDesc(numSplit, inputShape.GetNumDimensions());
51     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);
68         IConnectableLayer* output = net->AddOutputLayer(armnn::numeric_cast<LayerBindingId>(i));
69         Connect(splitter, output, outputTensorInfo, i, 0);
70     }
71 
72     return net;
73 }
74 
75 template<armnn::DataType ArmnnType>
Splitter1dEndToEnd(const std::vector<BackendId> & backends)76 void 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 
89     CHECK(net);
90 
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 
103 template<armnn::DataType ArmnnType>
Splitter2dDim0EndToEnd(const std::vector<BackendId> & backends)104 void 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 
117     CHECK(net);
118 
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 
138 template<armnn::DataType ArmnnType>
Splitter2dDim1EndToEnd(const std::vector<BackendId> & backends)139 void 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 
152     CHECK(net);
153 
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 
176 template<armnn::DataType ArmnnType>
Splitter3dDim0EndToEnd(const std::vector<BackendId> & backends)177 void 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 
190     CHECK(net);
191 
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 
224 template<armnn::DataType ArmnnType>
Splitter3dDim1EndToEnd(const std::vector<BackendId> & backends)225 void 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 
238     CHECK(net);
239 
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 
272 template<armnn::DataType ArmnnType>
Splitter3dDim2EndToEnd(const std::vector<BackendId> & backends)273 void 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 
286     CHECK(net);
287 
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 
312 template<armnn::DataType ArmnnType>
Splitter4dDim0EndToEnd(const std::vector<BackendId> & backends)313 void Splitter4dDim0EndToEnd(const std::vector<BackendId>& backends)
314 {
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 
326     CHECK(net);
327 
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 
392 template<armnn::DataType ArmnnType>
Splitter4dDim1EndToEnd(const std::vector<BackendId> & backends)393 void Splitter4dDim1EndToEnd(const std::vector<BackendId>& backends)
394 {
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 
406     CHECK(net);
407 
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 
472 template<armnn::DataType ArmnnType>
Splitter4dDim2EndToEnd(const std::vector<BackendId> & backends)473 void Splitter4dDim2EndToEnd(const std::vector<BackendId>& backends)
474 {
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 
486     CHECK(net);
487 
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 
552 template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
Splitter4dDim3EndToEnd(const std::vector<BackendId> & backends)553 void Splitter4dDim3EndToEnd(const std::vector<BackendId>& backends)
554 {
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 
565     CHECK(net);
566 
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
620