1 //
2 // Copyright © 2017,2022 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6
7 #include <CommonTestUtils.hpp>
8
9 #include <ResolveType.hpp>
10
11 #include <armnn/INetwork.hpp>
12
13 #include <armnn/utility/NumericCast.hpp>
14
15 #include <doctest/doctest.h>
16
17 #include <vector>
18
19 namespace
20 {
21
22 template<typename armnn::DataType DataType>
CreateConcatNetwork(const std::vector<TensorShape> & inputShapes,const TensorShape & outputShape,unsigned int concatAxis,const float qScale=1.0f,const int32_t qOffset=0)23 INetworkPtr CreateConcatNetwork(const std::vector<TensorShape>& inputShapes,
24 const TensorShape &outputShape,
25 unsigned int concatAxis,
26 const float qScale = 1.0f,
27 const int32_t qOffset = 0)
28 {
29 using namespace armnn;
30 // Builds up the structure of the network.
31 INetworkPtr net(INetwork::Create());
32
33 OriginsDescriptor descriptor;
34
35 descriptor = CreateDescriptorForConcatenation(inputShapes.begin(),
36 inputShapes.end(),
37 concatAxis);
38 IConnectableLayer* concat = net->AddConcatLayer(descriptor, "concat");
39
40 for (unsigned int i = 0; i < inputShapes.size(); ++i)
41 {
42 TensorInfo inputTensorInfo(inputShapes[i], DataType, qScale, qOffset, true);
43 IConnectableLayer* input = net->AddInputLayer(armnn::numeric_cast<LayerBindingId>(i));
44 Connect(input, concat, inputTensorInfo, 0, i);
45 }
46
47 TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
48 IConnectableLayer* output = net->AddOutputLayer(0, "output");
49 Connect(concat, output, outputTensorInfo, 0, 0);
50
51 return net;
52 }
53
54 template<armnn::DataType ArmnnType>
ConcatDim0EndToEnd(const std::vector<BackendId> & backends)55 void ConcatDim0EndToEnd(const std::vector<BackendId>& backends)
56 {
57 using namespace armnn;
58 using T = ResolveType<ArmnnType>;
59
60 unsigned int concatAxis = 0;
61 const std::vector<TensorShape> inputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
62 const TensorShape& outputShape = { 4, 3, 2, 2 };
63
64 // Builds up the structure of the network
65 INetworkPtr net = CreateConcatNetwork<ArmnnType>(inputShapes, outputShape, concatAxis);
66
67 CHECK(net);
68
69 // Creates structures for input & output.
70 std::vector<T> inputData{
71 1, 2,
72 3, 4,
73 5, 6,
74 7, 8,
75 9, 10,
76 11, 12,
77 1, 2,
78 3, 4,
79 5, 6,
80 7, 8,
81 9, 10,
82 11, 12
83 };
84
85 std::vector<T> expectedOutput{
86 1, 2,
87 3, 4,
88 5, 6,
89 7, 8,
90 9, 10,
91 11, 12,
92 1, 2,
93 3, 4,
94 5, 6,
95 7, 8,
96 9, 10,
97 11, 12,
98 1, 2,
99 3, 4,
100 5, 6,
101 7, 8,
102 9, 10,
103 11, 12,
104 1, 2,
105 3, 4,
106 5, 6,
107 7, 8,
108 9, 10,
109 11, 12
110 };
111
112 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }, { 1,inputData }};
113 std::map<int, std::vector<T>> expectedOutputData = {{ 0,expectedOutput }};
114
115 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(net), inputTensorData, expectedOutputData, backends);
116 }
117
118 template<armnn::DataType ArmnnType>
ConcatDim1EndToEnd(const std::vector<BackendId> & backends)119 void ConcatDim1EndToEnd(const std::vector<BackendId>& backends)
120 {
121 using namespace armnn;
122 using T = ResolveType<ArmnnType>;
123
124 unsigned int concatAxis = 1;
125 const std::vector<TensorShape> inputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
126 const TensorShape& outputShape = { 2, 6, 2, 2 };
127
128 // Builds up the structure of the network
129 INetworkPtr net = CreateConcatNetwork<ArmnnType>(inputShapes, outputShape, concatAxis);
130
131 // Creates structures for input & output.
132 std::vector<T> inputData{
133 1, 2,
134 3, 4,
135 5, 6,
136 7, 8,
137 9, 10,
138 11, 12,
139 1, 2,
140 3, 4,
141 5, 6,
142 7, 8,
143 9, 10,
144 11, 12
145 };
146
147 std::vector<T> expectedOutput{
148 1, 2,
149 3, 4,
150 5, 6,
151 7, 8,
152 9, 10,
153 11, 12,
154 1, 2,
155 3, 4,
156 5, 6,
157 7, 8,
158 9, 10,
159 11, 12,
160 1, 2,
161 3, 4,
162 5, 6,
163 7, 8,
164 9, 10,
165 11, 12,
166 1, 2,
167 3, 4,
168 5, 6,
169 7, 8,
170 9, 10,
171 11, 12
172 };
173
174 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }, { 1,inputData }};
175 std::map<int, std::vector<T>> expectedOutputData = {{ 0,expectedOutput }};
176
177 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(net), inputTensorData, expectedOutputData, backends);
178 }
179
180 template<armnn::DataType ArmnnType>
ConcatDim2EndToEnd(const std::vector<BackendId> & backends)181 void ConcatDim2EndToEnd(const std::vector<BackendId>& backends)
182 {
183 using namespace armnn;
184 using T = ResolveType<ArmnnType>;
185
186 unsigned int concatAxis = 2;
187 const std::vector<TensorShape> inputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
188 const TensorShape& outputShape = { 2, 3, 4, 2 };
189
190 // Builds up the structure of the network
191 INetworkPtr net = CreateConcatNetwork<ArmnnType>(inputShapes, outputShape, concatAxis);
192
193 // Creates structures for input & output.
194 std::vector<T> inputData{
195 1, 2,
196 3, 4,
197 5, 6,
198 7, 8,
199 9, 10,
200 11, 12,
201 1, 2,
202 3, 4,
203 5, 6,
204 7, 8,
205 9, 10,
206 11, 12
207 };
208
209 std::vector<T> expectedOutput{
210 1, 2,
211 3, 4,
212 1, 2,
213 3, 4,
214 5, 6,
215 7, 8,
216 5, 6,
217 7, 8,
218 9, 10,
219 11, 12,
220 9, 10,
221 11, 12,
222 1, 2,
223 3, 4,
224 1, 2,
225 3, 4,
226 5, 6,
227 7, 8,
228 5, 6,
229 7, 8,
230 9, 10,
231 11, 12,
232 9, 10,
233 11, 12
234 };
235
236 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }, { 1,inputData }};
237 std::map<int, std::vector<T>> expectedOutputData = {{ 0,expectedOutput }};
238
239 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(net), inputTensorData, expectedOutputData, backends);
240 }
241
242 template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
ConcatDim3EndToEnd(const std::vector<BackendId> & backends)243 void ConcatDim3EndToEnd(const std::vector<BackendId>& backends)
244 {
245 using namespace armnn;
246
247 unsigned int concatAxis = 3;
248 const std::vector<TensorShape> inputShapes{{ 2, 3, 2, 2 }, { 2, 3, 2, 2 }};
249 const TensorShape& outputShape = { 2, 3, 2, 4 };
250
251 // Builds up the structure of the network
252 INetworkPtr net = CreateConcatNetwork<ArmnnType>(inputShapes, outputShape, concatAxis);
253
254 // Creates structures for input & output.
255 std::vector<T> inputData{
256 1, 2,
257 3, 4,
258 5, 6,
259 7, 8,
260 9, 10,
261 11, 12,
262 1, 2,
263 3, 4,
264 5, 6,
265 7, 8,
266 9, 10,
267 11, 12
268 };
269
270 std::vector<T> expectedOutput{
271 1, 2,
272 1, 2,
273 3, 4,
274 3, 4,
275 5, 6,
276 5, 6,
277 7, 8,
278 7, 8,
279 9, 10,
280 9, 10,
281 11, 12,
282 11, 12,
283 1, 2,
284 1, 2,
285 3, 4,
286 3, 4,
287 5, 6,
288 5, 6,
289 7, 8,
290 7, 8,
291 9, 10,
292 9, 10,
293 11, 12,
294 11, 12
295 };
296
297 std::map<int, std::vector<T>> inputTensorData = {{ 0,inputData }, { 1,inputData }};
298 std::map<int, std::vector<T>> expectedOutputData = {{ 0,expectedOutput }};
299
300 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(std::move(net), inputTensorData, expectedOutputData, backends);
301 }
302
303 } // anonymous namespace
304