blob: c8986f5d4dfd435906f70a57af655d9ae2ae9572 [file] [log] [blame]
Aron Virginas-Tar70104002018-10-24 15:33:28 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
Aron Virginas-Tar70104002018-10-24 15:33:28 +01006
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +00007#include <Graph.hpp>
8#include <Network.hpp>
9
10#include <reference/RefWorkloadFactory.hpp>
Aron Virginas-Tar70104002018-10-24 15:33:28 +010011
12#include <boost/test/unit_test.hpp>
13
14BOOST_AUTO_TEST_SUITE(OptimizedNetwork)
15
16BOOST_AUTO_TEST_CASE(SerializeToDot)
17{
18 armnn::Network net;
19
20 //Defines layers.
21 auto input = net.AddInputLayer(0);
22 auto add = net.AddAdditionLayer();
23 auto output = net.AddOutputLayer(0);
24
25 // Connects layers.
26 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
27 input->GetOutputSlot(0).Connect(add->GetInputSlot(1));
28 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
29
30 armnn::TensorShape shape({4});
31 armnn::TensorInfo info(shape, armnn::DataType::Float32);
32 input->GetOutputSlot(0).SetTensorInfo(info);
33 add->GetOutputSlot(0).SetTensorInfo(info);
34
35 armnn::IRuntime::CreationOptions options;
36 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
37
38 std::vector<armnn::BackendId> backends = {armnn::Compute::CpuRef};
39 armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec());
40
41 std::ostringstream ss;
42 optimizedNet->SerializeToDot(ss);
43
44 auto inputId = input->GetGuid();
45 auto addId = add->GetGuid();
46 auto outputId = output->GetGuid();
47
48 std::stringstream expected;
49 expected <<
50 "digraph Optimized {\n"
51 " node [shape=\"record\"];\n"
52 " edge [fontsize=8 fontcolor=\"blue\" fontname=\"arial-bold\"];\n"
Andre Ghattas23ae2ea2019-08-07 12:18:38 +010053 " " << inputId << " [label=\"{Input|LayerType : Input\\lBackendID : CpuRef\\l}\"];\n"
54 " " << addId << " [label=\"{Addition|LayerType : Addition\\lBackendID : CpuRef\\l}\"];\n"
55 " " << outputId << " [label=\"{Output|LayerType : Output\\lBackendID : CpuRef\\l}\"];\n"
Aron Virginas-Tar70104002018-10-24 15:33:28 +010056 " " << inputId << " -> " << addId << " [label=< [4] >];\n"
57 " " << inputId << " -> " << addId << " [label=< [4] >];\n"
58 " " << addId << " -> " << outputId << " [label=< [4] >];\n"
59 "}\n";
60
61 BOOST_TEST(ss.str() == expected.str());
62}
63
64BOOST_AUTO_TEST_CASE(OptimizeValidateDeviceNonSupportLayerNoFallback)
65{
66 // build up the structure of the network
67 armnn::INetworkPtr net(armnn::INetwork::Create());
68
69 armnn::IConnectableLayer* input = net->AddInputLayer(0);
70
71 // This layer configuration isn't supported by CpuAcc and isn't allowed to fall back, so Optimize will return null.
72 armnn::NormalizationDescriptor descriptor;
73 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
74
75 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
76
77 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
78 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
79
80 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
81 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
82
83 armnn::IRuntime::CreationOptions options;
84 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
85
86 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc };
Mike Kelly3a613cc2020-09-29 20:50:35 +010087 std::vector<std::string> errMessages;
88
89 try
90 {
91 Optimize(*net, backends, runtime->GetDeviceSpec(), armnn::OptimizerOptions(), errMessages);
92 BOOST_FAIL("Should have thrown an exception.");
93 }
94 catch (const armnn::InvalidArgumentException& e)
95 {
96 // Different exceptions are thrown on different backends
97 }
98 BOOST_CHECK(errMessages.size() > 0);
Aron Virginas-Tar70104002018-10-24 15:33:28 +010099}
100
101BOOST_AUTO_TEST_CASE(OptimizeValidateDeviceNonSupportLayerWithFallback)
102{
103 // build up the structure of the network
104 armnn::INetworkPtr net(armnn::INetwork::Create());
105
106 armnn::IConnectableLayer* input = net->AddInputLayer(0);
107
108 // This layer configuration isn't supported by CpuAcc but it allows to fallback to CpuRef.
109 armnn::NormalizationDescriptor descriptor;
110 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
111
112 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
113
114 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
115 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
116
117 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
118 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
119
120 armnn::IRuntime::CreationOptions options;
121 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
122
123 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc, armnn::Compute::CpuRef };
124 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
125 BOOST_REQUIRE(optNet);
126
127 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
128 {
129 // If NEON is enabled, Input and Output layers are supported by CpuAcc,
130 // the other layers are supported by CpuRef.
131 // If NEON is not enabled, all layers are supported by CpuRef.
Matteo Martincighd95e9062019-01-31 15:35:59 +0000132#if defined(ARMCOMPUTENEON_ENABLED)
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100133 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
134 {
135 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuAcc);
136 }
137 else if (layer->GetType() == armnn::LayerType::Normalization)
138 {
139 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
140 }
141#else
142 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
143#endif
144 }
145}
146
147BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsUndefinedComputeDevice)
148{
149 const armnn::TensorInfo desc({3, 5}, armnn::DataType::Float32);
150
151 armnn::Network net;
152
153 armnn::NormalizationDescriptor nmDesc;
154 armnn::ActivationDescriptor acDesc;
155
156 // in
157 // |
158 // nm
159 // / |
160 // ac |
161 // \ |
162 // ml
163 // |
164 // sm
165 // |
166 // ot
167 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "in");
168 layer->GetOutputSlot(0).SetTensorInfo(desc);
169
170 armnn::IConnectableLayer* const normLayer = net.AddNormalizationLayer(nmDesc, "nm");
171
172 layer->GetOutputSlot(0).Connect(normLayer->GetInputSlot(0));
173 normLayer->GetOutputSlot(0).SetTensorInfo(desc);
174
175 layer = net.AddActivationLayer(acDesc, "ac");
176
177 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
178 layer->GetOutputSlot(0).SetTensorInfo(desc);
179
180 armnn::IConnectableLayer* prevLayer = layer;
181 layer = net.AddMultiplicationLayer("ml");
182
183 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
184 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
185 layer->GetOutputSlot(0).SetTensorInfo(desc);
186
187 prevLayer = layer;
188 armnn::SoftmaxDescriptor softmaxDescriptor;
189 layer = net.AddSoftmaxLayer(softmaxDescriptor, "sm");
190
191 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
192 layer->GetOutputSlot(0).SetTensorInfo(desc);
193
194 prevLayer = layer;
195 layer = net.AddOutputLayer(0, "ot");
196
197 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
198
199 armnn::IRuntime::CreationOptions options;
200 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
201
202 std::vector<armnn::BackendId> backends = { armnn::Compute::Undefined };
Mike Kelly3a613cc2020-09-29 20:50:35 +0100203 std::vector<std::string> errMessages;
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100204
Mike Kelly3a613cc2020-09-29 20:50:35 +0100205 try
206 {
207 Optimize(net, backends, runtime->GetDeviceSpec(), armnn::OptimizerOptions(), errMessages);
208 BOOST_FAIL("Should have thrown an exception.");
209 }
210 catch (const armnn::InvalidArgumentException& e)
211 {
212 // Different exceptions are thrown on different backends
213 }
214 BOOST_CHECK(errMessages.size() > 0);
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100215}
216
217BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsUndefinedComputeDeviceWithFallback)
218{
219 const armnn::TensorInfo desc({3, 5}, armnn::DataType::Float32);
220
221 armnn::Network net;
222
223 armnn::NormalizationDescriptor nmDesc;
224 armnn::ActivationDescriptor acDesc;
225
226 // in
227 // |
228 // nm
229 // / |
230 // ac |
231 // \ |
232 // ml
233 // |
234 // sm
235 // |
236 // ot
237 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "in");
238 layer->GetOutputSlot(0).SetTensorInfo(desc);
239
240 armnn::IConnectableLayer* const normLayer = net.AddNormalizationLayer(nmDesc, "nm");
241
242 layer->GetOutputSlot(0).Connect(normLayer->GetInputSlot(0));
243 normLayer->GetOutputSlot(0).SetTensorInfo(desc);
244
245 layer = net.AddActivationLayer(acDesc, "ac");
246
247 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
248 layer->GetOutputSlot(0).SetTensorInfo(desc);
249
250 armnn::IConnectableLayer* prevLayer = layer;
251 layer = net.AddMultiplicationLayer("ml");
252
253 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
254 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
255 layer->GetOutputSlot(0).SetTensorInfo(desc);
256
257 prevLayer = layer;
258 armnn::SoftmaxDescriptor softmaxDescriptor;
259 layer = net.AddSoftmaxLayer(softmaxDescriptor, "sm");
260
261 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
262 layer->GetOutputSlot(0).SetTensorInfo(desc);
263
264 prevLayer = layer;
265 layer = net.AddOutputLayer(0, "ot");
266
267 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
268
269 armnn::IRuntime::CreationOptions options;
270 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
271
272 std::vector<armnn::BackendId> backends = { armnn::Compute::Undefined, armnn::Compute::CpuRef };
273
274 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec());
275 BOOST_CHECK(optNet);
276
277 // validate workloads
278 armnn::RefWorkloadFactory fact;
279 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
280 {
281 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
282 BOOST_CHECK_NO_THROW(
Derek Lamberti94a88d22019-12-10 21:12:59 +0000283 layer->CreateWorkload(fact));
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100284 }
285}
286
287BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsDuplicateComputeDeviceWithFallback)
288{
289 // build up the structure of the network
290 armnn::INetworkPtr net(armnn::INetwork::Create());
291
292 armnn::IConnectableLayer* input = net->AddInputLayer(0);
293
294 // This layer configuration isn't supported by CpuAcc but it allows to fallback to CpuRef.
295 armnn::NormalizationDescriptor descriptor;
296 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
297
298 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
299
300 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
301 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
302
303 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
304 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
305
306 armnn::IRuntime::CreationOptions options;
307 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
308
309 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc,
310 armnn::Compute::GpuAcc,
311 armnn::Compute::CpuRef };
312
313 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
314 BOOST_REQUIRE(optNet);
315
316 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
317 {
318 // If NEON is enabled, Input and Output layers are supported by CpuAcc,
319 // the other layers are supported by CpuRef.
320 // If only CL is enabled, Input and Output layers are supported by GpuAcc,
321 // the other layers are supported by CpuRef.
322 // If neither NEON, nor CL is enabled, all layers are supported by CpuRef.
Matteo Martincighd95e9062019-01-31 15:35:59 +0000323#if defined(ARMCOMPUTENEON_ENABLED)
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100324 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
325 {
326 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuAcc);
327 }
328 else if (layer->GetType() == armnn::LayerType::Normalization)
329 {
330 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
331 }
Matteo Martincighd95e9062019-01-31 15:35:59 +0000332#elif defined(ARMCOMPUTECL_ENABLED)
Aron Virginas-Tar70104002018-10-24 15:33:28 +0100333 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
334 {
335 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::GpuAcc);
336 }
337 else if (layer->GetType() == armnn::LayerType::Normalization)
338 {
339 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
340 }
341#else
342 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
343#endif
344 }
345}
346
347BOOST_AUTO_TEST_SUITE_END()