2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
6 #include <armnn/ArmNN.hpp>
11 #include <reference/RefWorkloadFactory.hpp>
13 #include <boost/test/unit_test.hpp>
15 BOOST_AUTO_TEST_SUITE(OptimizedNetwork)
17 BOOST_AUTO_TEST_CASE(SerializeToDot)
22 auto input = net.AddInputLayer(0);
23 auto add = net.AddAdditionLayer();
24 auto output = net.AddOutputLayer(0);
27 input->GetOutputSlot(0).Connect(add->GetInputSlot(0));
28 input->GetOutputSlot(0).Connect(add->GetInputSlot(1));
29 add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
31 armnn::TensorShape shape({4});
32 armnn::TensorInfo info(shape, armnn::DataType::Float32);
33 input->GetOutputSlot(0).SetTensorInfo(info);
34 add->GetOutputSlot(0).SetTensorInfo(info);
36 armnn::IRuntime::CreationOptions options;
37 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
39 std::vector<armnn::BackendId> backends = {armnn::Compute::CpuRef};
40 armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec());
42 std::ostringstream ss;
43 optimizedNet->SerializeToDot(ss);
45 auto inputId = input->GetGuid();
46 auto addId = add->GetGuid();
47 auto outputId = output->GetGuid();
49 std::stringstream expected;
51 "digraph Optimized {\n"
52 " node [shape=\"record\"];\n"
53 " edge [fontsize=8 fontcolor=\"blue\" fontname=\"arial-bold\"];\n"
54 " " << inputId << " [label=\"{Input}\"];\n"
55 " " << addId << " [label=\"{Addition}\"];\n"
56 " " << outputId << " [label=\"{Output}\"];\n"
57 " " << inputId << " -> " << addId << " [label=< [4] >];\n"
58 " " << inputId << " -> " << addId << " [label=< [4] >];\n"
59 " " << addId << " -> " << outputId << " [label=< [4] >];\n"
62 BOOST_TEST(ss.str() == expected.str());
65 BOOST_AUTO_TEST_CASE(OptimizeValidateDeviceNonSupportLayerNoFallback)
67 // build up the structure of the network
68 armnn::INetworkPtr net(armnn::INetwork::Create());
70 armnn::IConnectableLayer* input = net->AddInputLayer(0);
72 // This layer configuration isn't supported by CpuAcc and isn't allowed to fall back, so Optimize will return null.
73 armnn::NormalizationDescriptor descriptor;
74 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
76 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
78 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
79 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
81 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
82 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
84 armnn::IRuntime::CreationOptions options;
85 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
87 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc };
88 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
92 BOOST_AUTO_TEST_CASE(OptimizeValidateDeviceNonSupportLayerWithFallback)
94 // build up the structure of the network
95 armnn::INetworkPtr net(armnn::INetwork::Create());
97 armnn::IConnectableLayer* input = net->AddInputLayer(0);
99 // This layer configuration isn't supported by CpuAcc but it allows to fallback to CpuRef.
100 armnn::NormalizationDescriptor descriptor;
101 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
103 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
105 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
106 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
108 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
109 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
111 armnn::IRuntime::CreationOptions options;
112 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
114 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc, armnn::Compute::CpuRef };
115 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
116 BOOST_REQUIRE(optNet);
118 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
120 // If NEON is enabled, Input and Output layers are supported by CpuAcc,
121 // the other layers are supported by CpuRef.
122 // If NEON is not enabled, all layers are supported by CpuRef.
123 #if ARMCOMPUTENEON_ENABLED
124 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
126 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuAcc);
128 else if (layer->GetType() == armnn::LayerType::Normalization)
130 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
133 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
138 BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsUndefinedComputeDevice)
140 const armnn::TensorInfo desc({3, 5}, armnn::DataType::Float32);
144 armnn::NormalizationDescriptor nmDesc;
145 armnn::ActivationDescriptor acDesc;
158 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "in");
159 layer->GetOutputSlot(0).SetTensorInfo(desc);
161 armnn::IConnectableLayer* const normLayer = net.AddNormalizationLayer(nmDesc, "nm");
163 layer->GetOutputSlot(0).Connect(normLayer->GetInputSlot(0));
164 normLayer->GetOutputSlot(0).SetTensorInfo(desc);
166 layer = net.AddActivationLayer(acDesc, "ac");
168 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
169 layer->GetOutputSlot(0).SetTensorInfo(desc);
171 armnn::IConnectableLayer* prevLayer = layer;
172 layer = net.AddMultiplicationLayer("ml");
174 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
175 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
176 layer->GetOutputSlot(0).SetTensorInfo(desc);
179 armnn::SoftmaxDescriptor softmaxDescriptor;
180 layer = net.AddSoftmaxLayer(softmaxDescriptor, "sm");
182 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
183 layer->GetOutputSlot(0).SetTensorInfo(desc);
186 layer = net.AddOutputLayer(0, "ot");
188 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
190 armnn::IRuntime::CreationOptions options;
191 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
193 std::vector<armnn::BackendId> backends = { armnn::Compute::Undefined };
195 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec());
196 BOOST_CHECK(!optNet);
200 BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsUndefinedComputeDeviceWithFallback)
202 const armnn::TensorInfo desc({3, 5}, armnn::DataType::Float32);
206 armnn::NormalizationDescriptor nmDesc;
207 armnn::ActivationDescriptor acDesc;
220 armnn::IConnectableLayer* layer = net.AddInputLayer(0, "in");
221 layer->GetOutputSlot(0).SetTensorInfo(desc);
223 armnn::IConnectableLayer* const normLayer = net.AddNormalizationLayer(nmDesc, "nm");
225 layer->GetOutputSlot(0).Connect(normLayer->GetInputSlot(0));
226 normLayer->GetOutputSlot(0).SetTensorInfo(desc);
228 layer = net.AddActivationLayer(acDesc, "ac");
230 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
231 layer->GetOutputSlot(0).SetTensorInfo(desc);
233 armnn::IConnectableLayer* prevLayer = layer;
234 layer = net.AddMultiplicationLayer("ml");
236 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
237 normLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1));
238 layer->GetOutputSlot(0).SetTensorInfo(desc);
241 armnn::SoftmaxDescriptor softmaxDescriptor;
242 layer = net.AddSoftmaxLayer(softmaxDescriptor, "sm");
244 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
245 layer->GetOutputSlot(0).SetTensorInfo(desc);
248 layer = net.AddOutputLayer(0, "ot");
250 prevLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(0));
252 armnn::IRuntime::CreationOptions options;
253 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
255 std::vector<armnn::BackendId> backends = { armnn::Compute::Undefined, armnn::Compute::CpuRef };
257 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec());
260 // validate workloads
261 armnn::RefWorkloadFactory fact;
262 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
264 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
265 BOOST_CHECK_NO_THROW(
266 layer->CreateWorkload(static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph(), fact));
270 BOOST_AUTO_TEST_CASE(OptimizeValidateWorkloadsDuplicateComputeDeviceWithFallback)
272 // build up the structure of the network
273 armnn::INetworkPtr net(armnn::INetwork::Create());
275 armnn::IConnectableLayer* input = net->AddInputLayer(0);
277 // This layer configuration isn't supported by CpuAcc but it allows to fallback to CpuRef.
278 armnn::NormalizationDescriptor descriptor;
279 armnn::IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
281 armnn::IConnectableLayer* output = net->AddOutputLayer(0);
283 input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
284 normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
286 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
287 normalize->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
289 armnn::IRuntime::CreationOptions options;
290 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
292 std::vector<armnn::BackendId> backends = { armnn::Compute::CpuAcc,
293 armnn::Compute::GpuAcc,
294 armnn::Compute::CpuRef };
296 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
297 BOOST_REQUIRE(optNet);
299 for (auto&& layer : static_cast<armnn::OptimizedNetwork*>(optNet.get())->GetGraph())
301 // If NEON is enabled, Input and Output layers are supported by CpuAcc,
302 // the other layers are supported by CpuRef.
303 // If only CL is enabled, Input and Output layers are supported by GpuAcc,
304 // the other layers are supported by CpuRef.
305 // If neither NEON, nor CL is enabled, all layers are supported by CpuRef.
306 #if ARMCOMPUTENEON_ENABLED
307 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
309 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuAcc);
311 else if (layer->GetType() == armnn::LayerType::Normalization)
313 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
315 #elif ARMCOMPUTECL_ENABLED
316 if (layer->GetType() == armnn::LayerType::Input || layer->GetType() == armnn::LayerType::Output)
318 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::GpuAcc);
320 else if (layer->GetType() == armnn::LayerType::Normalization)
322 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
325 BOOST_CHECK(layer->GetBackendId() == armnn::Compute::CpuRef);
330 BOOST_AUTO_TEST_SUITE_END()