2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
5 #include <boost/test/unit_test.hpp>
7 #include "armnn/ArmNN.hpp"
10 #include "backends/RefWorkloadFactory.hpp"
12 #include "GraphUtils.hpp"
17 bool AreAllLayerInputSlotsConnected(const armnn::IConnectableLayer& layer)
19 bool allConnected = true;
20 for (unsigned int i = 0; i < layer.GetNumInputSlots(); ++i)
22 const bool inputConnected = layer.GetInputSlot(i).GetConnection() != nullptr;
23 allConnected &= inputConnected;
30 BOOST_AUTO_TEST_SUITE(Network)
32 BOOST_AUTO_TEST_CASE(NetworkBasic)
35 BOOST_TEST(net.PrintGraph() == armnn::Status::Success);
38 BOOST_AUTO_TEST_CASE(LayerNamesAreOptionalForINetwork)
41 armnn::INetwork& inet = net;
42 inet.AddInputLayer(0);
43 inet.AddAdditionLayer();
44 inet.AddActivationLayer(armnn::ActivationDescriptor());
45 inet.AddOutputLayer(0);
48 BOOST_AUTO_TEST_CASE(LayerNamesAreOptionalForNetwork)
52 net.AddAdditionLayer();
53 net.AddActivationLayer(armnn::ActivationDescriptor());
54 net.AddOutputLayer(0);
57 BOOST_AUTO_TEST_CASE(NetworkModification)
61 armnn::IConnectableLayer* const inputLayer = net.AddInputLayer(0, "input layer");
62 BOOST_TEST(inputLayer);
64 unsigned int dims[] = { 10,1,1,1 };
65 std::vector<float> convWeightsData(10);
66 armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32), convWeightsData);
68 armnn::Convolution2dDescriptor convDesc2d;
69 armnn::IConnectableLayer* const convLayer = net.AddConvolution2dLayer(convDesc2d, weights, "conv layer");
70 BOOST_TEST(convLayer);
72 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
74 armnn::FullyConnectedDescriptor fullyConnectedDesc;
75 armnn::IConnectableLayer* const fullyConnectedLayer = net.AddFullyConnectedLayer(fullyConnectedDesc,
78 BOOST_TEST(fullyConnectedLayer);
80 convLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
82 armnn::Pooling2dDescriptor pooling2dDesc;
83 armnn::IConnectableLayer* const poolingLayer = net.AddPooling2dLayer(pooling2dDesc, "pooling2d");
84 BOOST_TEST(poolingLayer);
86 fullyConnectedLayer->GetOutputSlot(0).Connect(poolingLayer->GetInputSlot(0));
88 armnn::ActivationDescriptor activationDesc;
89 armnn::IConnectableLayer* const activationLayer = net.AddActivationLayer(activationDesc, "activation");
90 BOOST_TEST(activationLayer);
92 poolingLayer->GetOutputSlot(0).Connect(activationLayer->GetInputSlot(0));
94 armnn::NormalizationDescriptor normalizationDesc;
95 armnn::IConnectableLayer* const normalizationLayer = net.AddNormalizationLayer(normalizationDesc, "normalization");
96 BOOST_TEST(normalizationLayer);
98 activationLayer->GetOutputSlot(0).Connect(normalizationLayer->GetInputSlot(0));
100 armnn::SoftmaxDescriptor softmaxDesc;
101 armnn::IConnectableLayer* const softmaxLayer = net.AddSoftmaxLayer(softmaxDesc, "softmax");
102 BOOST_TEST(softmaxLayer);
104 normalizationLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0));
106 armnn::BatchNormalizationDescriptor batchNormDesc;
108 armnn::TensorInfo tensorInfo({ 1 }, armnn::DataType::Float32);
109 std::vector<float> data(tensorInfo.GetNumBytes() / sizeof(float));
110 armnn::ConstTensor invalidTensor(tensorInfo, data);
112 armnn::IConnectableLayer* const batchNormalizationLayer = net.AddBatchNormalizationLayer(batchNormDesc,
118 BOOST_TEST(batchNormalizationLayer);
120 softmaxLayer->GetOutputSlot(0).Connect(batchNormalizationLayer->GetInputSlot(0));
122 armnn::IConnectableLayer* const additionLayer = net.AddAdditionLayer("addition");
123 BOOST_TEST(additionLayer);
125 batchNormalizationLayer->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(0));
126 batchNormalizationLayer->GetOutputSlot(0).Connect(additionLayer->GetInputSlot(1));
128 armnn::IConnectableLayer* const multiplicationLayer = net.AddMultiplicationLayer("multiplication");
129 BOOST_TEST(multiplicationLayer);
131 additionLayer->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(0));
132 additionLayer->GetOutputSlot(0).Connect(multiplicationLayer->GetInputSlot(1));
134 armnn::IConnectableLayer* const outputLayer = net.AddOutputLayer(0, "output layer");
135 BOOST_TEST(outputLayer);
137 multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
139 //Test that all layers are present in the graph
140 BOOST_TEST(net.GetGraph().GetNumLayers() == 11);
142 //Test that the vertices exist and have correct names
143 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "input layer"));
144 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "conv layer"));
145 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "fully connected"));
146 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "pooling2d"));
147 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "activation"));
148 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "normalization"));
149 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "softmax"));
150 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "batch norm"));
151 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "addition"));
152 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "multiplication"));
153 BOOST_TEST(GraphHasNamedLayer(net.GetGraph(), "output layer"));
155 auto checkOneOutputToOneInputConnection = []
156 (const armnn::IConnectableLayer* const srcLayer,
157 const armnn::IConnectableLayer* const tgtLayer,
158 int expectedSrcNumInputs = 1,
159 int expectedDstNumOutputs = 1)
161 BOOST_TEST(srcLayer->GetNumInputSlots() == expectedSrcNumInputs);
162 BOOST_TEST(srcLayer->GetNumOutputSlots() == 1);
163 BOOST_TEST(tgtLayer->GetNumInputSlots() == 1);
164 BOOST_TEST(tgtLayer->GetNumOutputSlots() == expectedDstNumOutputs);
166 BOOST_TEST(srcLayer->GetOutputSlot(0).GetNumConnections() == 1);
167 BOOST_TEST(srcLayer->GetOutputSlot(0).GetConnection(0) == &tgtLayer->GetInputSlot(0));
168 BOOST_TEST(&srcLayer->GetOutputSlot(0) == tgtLayer->GetInputSlot(0).GetConnection());
170 auto checkOneOutputToTwoInputsConnections = []
171 (const armnn::IConnectableLayer* const srcLayer,
172 const armnn::IConnectableLayer* const tgtLayer,
173 int expectedSrcNumInputs,
174 int expectedDstNumOutputs = 1)
176 BOOST_TEST(srcLayer->GetNumInputSlots() == expectedSrcNumInputs);
177 BOOST_TEST(srcLayer->GetNumOutputSlots() == 1);
178 BOOST_TEST(tgtLayer->GetNumInputSlots() == 2);
179 BOOST_TEST(tgtLayer->GetNumOutputSlots() == expectedDstNumOutputs);
181 BOOST_TEST(srcLayer->GetOutputSlot(0).GetNumConnections() == 2);
182 for (unsigned int i = 0; i < srcLayer->GetOutputSlot(0).GetNumConnections(); ++i)
184 BOOST_TEST(srcLayer->GetOutputSlot(0).GetConnection(i) == &tgtLayer->GetInputSlot(i));
185 BOOST_TEST(&srcLayer->GetOutputSlot(0) == tgtLayer->GetInputSlot(i).GetConnection());
189 BOOST_TEST(AreAllLayerInputSlotsConnected(*convLayer));
190 BOOST_TEST(AreAllLayerInputSlotsConnected(*fullyConnectedLayer));
191 BOOST_TEST(AreAllLayerInputSlotsConnected(*poolingLayer));
192 BOOST_TEST(AreAllLayerInputSlotsConnected(*activationLayer));
193 BOOST_TEST(AreAllLayerInputSlotsConnected(*normalizationLayer));
194 BOOST_TEST(AreAllLayerInputSlotsConnected(*softmaxLayer));
195 BOOST_TEST(AreAllLayerInputSlotsConnected(*batchNormalizationLayer));
196 BOOST_TEST(AreAllLayerInputSlotsConnected(*additionLayer));
197 BOOST_TEST(AreAllLayerInputSlotsConnected(*multiplicationLayer));
198 BOOST_TEST(AreAllLayerInputSlotsConnected(*outputLayer));
200 // Check connectivity
201 checkOneOutputToOneInputConnection(inputLayer, convLayer, 0);
202 checkOneOutputToOneInputConnection(convLayer, fullyConnectedLayer);
203 checkOneOutputToOneInputConnection(fullyConnectedLayer, poolingLayer);
204 checkOneOutputToOneInputConnection(poolingLayer, activationLayer);
205 checkOneOutputToOneInputConnection(activationLayer, normalizationLayer);
206 checkOneOutputToOneInputConnection(normalizationLayer, softmaxLayer);
207 checkOneOutputToOneInputConnection(softmaxLayer, batchNormalizationLayer);
208 checkOneOutputToTwoInputsConnections(batchNormalizationLayer, additionLayer, 1);
209 checkOneOutputToTwoInputsConnections(additionLayer, multiplicationLayer, 2);
210 checkOneOutputToOneInputConnection(multiplicationLayer, outputLayer, 2, 0);
213 BOOST_AUTO_TEST_CASE(NetworkModification_SplitterMerger)
217 // Add an input layer and an input tensor descriptor.
218 armnn::IConnectableLayer* inputLayer = net.AddInputLayer(0, "input layer");
219 BOOST_TEST(inputLayer);
221 // Add a splitter layer
222 armnn::ViewsDescriptor splitterDesc(2,4);
224 armnn::IConnectableLayer* splitterLayer = net.AddSplitterLayer(splitterDesc, "splitter layer");
225 BOOST_TEST(splitterLayer);
227 inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
229 // Add a softmax layer 1
230 armnn::SoftmaxDescriptor softmaxDescriptor;
231 armnn::IConnectableLayer* softmaxLayer1 = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_1");
232 BOOST_TEST(softmaxLayer1);
234 splitterLayer->GetOutputSlot(0).Connect(softmaxLayer1->GetInputSlot(0));
236 // Add a softmax layer 2
237 armnn::IConnectableLayer* softmaxLayer2 = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_2");
238 BOOST_TEST(softmaxLayer2);
240 splitterLayer->GetOutputSlot(1).Connect(softmaxLayer2->GetInputSlot(0));
242 // Add a merger layer
243 armnn::OriginsDescriptor mergerDesc(2, 4);
245 armnn::IConnectableLayer* mergerLayer = net.AddMergerLayer(mergerDesc, "merger layer");
246 BOOST_TEST(mergerLayer);
248 softmaxLayer1->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0));
249 softmaxLayer2->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1));
251 // Add an output layer
252 armnn::IConnectableLayer* outputLayer = net.AddOutputLayer(0, "output layer");
253 BOOST_TEST(outputLayer);
255 mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
257 BOOST_TEST(splitterLayer->GetNumOutputSlots() == 2);
258 BOOST_TEST(splitterLayer->GetOutputSlot(0).GetConnection(0) == &softmaxLayer1->GetInputSlot(0));
259 BOOST_TEST(&splitterLayer->GetOutputSlot(0) == softmaxLayer1->GetInputSlot(0).GetConnection());
260 BOOST_TEST(splitterLayer->GetOutputSlot(1).GetConnection(0) == &softmaxLayer2->GetInputSlot(0));
261 BOOST_TEST(&splitterLayer->GetOutputSlot(1) == softmaxLayer2->GetInputSlot(0).GetConnection());
263 BOOST_TEST(mergerLayer->GetNumInputSlots() == 2);
264 BOOST_TEST(softmaxLayer1->GetOutputSlot(0).GetConnection(0) == &mergerLayer->GetInputSlot(0));
265 BOOST_TEST(&softmaxLayer1->GetOutputSlot(0) == mergerLayer->GetInputSlot(0).GetConnection());
266 BOOST_TEST(softmaxLayer2->GetOutputSlot(0).GetConnection(0) == &mergerLayer->GetInputSlot(1));
267 BOOST_TEST(&softmaxLayer2->GetOutputSlot(0) == mergerLayer->GetInputSlot(1).GetConnection());
270 BOOST_AUTO_TEST_CASE(NetworkModification_SplitterAddition)
274 // Add an input layer and an input tensor descriptor.
275 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "input layer");
278 // Add a splitter layer
279 armnn::ViewsDescriptor splitterDesc(2,4);
281 armnn::IConnectableLayer* const splitterLayer = net.AddSplitterLayer(splitterDesc, "splitter layer");
282 BOOST_TEST(splitterLayer);
284 layer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
286 // Add a softmax layer 1
287 armnn::SoftmaxDescriptor softmaxDescriptor;
288 armnn::IConnectableLayer* const softmax1Layer = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_1");
289 BOOST_TEST(softmax1Layer);
291 splitterLayer->GetOutputSlot(0).Connect(softmax1Layer->GetInputSlot(0));
293 // Add a softmax layer 2
294 armnn::IConnectableLayer* const softmax2Layer = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_2");
295 BOOST_TEST(softmax2Layer);
297 splitterLayer->GetOutputSlot(1).Connect(softmax2Layer->GetInputSlot(0));
299 // Add addition layer
300 layer = net.AddAdditionLayer("add layer");
303 softmax1Layer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
304 softmax2Layer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
306 // Add an output layer
307 armnn::IConnectableLayer* prevLayer = layer;
308 layer = net.AddOutputLayer(0, "output layer");
310 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
315 BOOST_AUTO_TEST_CASE(NetworkModification_SplitterMultiplication)
319 // Add an input layer and an input tensor descriptor.
320 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "input layer");
323 // Add a splitter layer
324 armnn::ViewsDescriptor splitterDesc(2,4);
325 armnn::IConnectableLayer* const splitterLayer = net.AddSplitterLayer(splitterDesc, "splitter layer");
326 BOOST_TEST(splitterLayer);
328 layer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0));
330 // Add a softmax layer 1
331 armnn::SoftmaxDescriptor softmaxDescriptor;
332 armnn::IConnectableLayer* const softmax1Layer = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_1");
333 BOOST_TEST(softmax1Layer);
335 splitterLayer->GetOutputSlot(0).Connect(softmax1Layer->GetInputSlot(0));
337 // Add a softmax layer 2
338 armnn::IConnectableLayer* const softmax2Layer = net.AddSoftmaxLayer(softmaxDescriptor, "softmax_2");
339 BOOST_TEST(softmax2Layer);
341 splitterLayer->GetOutputSlot(1).Connect(softmax2Layer->GetInputSlot(0));
343 // Add multiplication layer
344 layer = net.AddMultiplicationLayer("multiplication layer");
347 softmax1Layer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
348 softmax2Layer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
350 // Add an output layer
351 armnn::IConnectableLayer* prevLayer = layer;
352 layer = net.AddOutputLayer(0, "output layer");
355 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
358 BOOST_AUTO_TEST_CASE(ValidateWorkloads)
360 const armnn::TensorInfo desc({3, 5}, armnn::DataType::Float32);
364 armnn::NormalizationDescriptor nmDesc;
365 armnn::ActivationDescriptor acDesc;
378 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "in");
379 layer->GetOutputSlot(0).SetTensorInfo(desc);
381 armnn::IConnectableLayer* const normLayer = net.AddNormalizationLayer(nmDesc, "nm");
383 layer->GetOutputSlot(0).Connect(normLayer->GetInputSlot(0));
384 normLayer->GetOutputSlot(0).SetTensorInfo(desc);
386 layer = net.AddActivationLayer(acDesc, "ac");
388 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
389 layer->GetOutputSlot(0).SetTensorInfo(desc);
391 armnn::IConnectableLayer* prevLayer = layer;
392 layer = net.AddMultiplicationLayer("ml");
394 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
395 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
396 layer->GetOutputSlot(0).SetTensorInfo(desc);
399 armnn::SoftmaxDescriptor softmaxDescriptor;
400 layer = net.AddSoftmaxLayer(softmaxDescriptor, "sm");
402 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
403 layer->GetOutputSlot(0).SetTensorInfo(desc);
406 layer = net.AddOutputLayer(0, "ot");
408 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
410 armnn::DeviceSpec spec;
411 spec.DefaultComputeDevice = armnn::Compute::CpuRef;
413 armnn::IOptimizedNetworkPtr optNet = Optimize(net, spec);
414 static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph().AllocateDynamicBuffers();
416 // validate workloads
417 armnn::RefWorkloadFactory fact;
418 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
420 BOOST_CHECK_NO_THROW(
421 layer->CreateWorkload(static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph(), fact));
425 BOOST_AUTO_TEST_SUITE_END()