blob: b472a0321d44796385fcdf903a272937a39d7dfc [file] [log] [blame]
David Monahan005288d2019-05-14 10:42:38 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
David Monahan005288d2019-05-14 10:42:38 +01006
7#include "CommonTestUtils.hpp"
David Monahan41f00f12019-05-27 09:44:52 +01008#include "MockBackend.hpp"
David Monahan005288d2019-05-14 10:42:38 +01009
Jan Eilersbb446e52020-04-02 13:56:54 +010010#include <armnn/backends/OptimizationViews.hpp>
11#include <armnn/utility/PolymorphicDowncast.hpp>
12#include <Graph.hpp>
13#include <Network.hpp>
14#include <SubgraphView.hpp>
15#include <SubgraphViewSelector.hpp>
16
17#include <boost/test/unit_test.hpp>
18
19
David Monahan005288d2019-05-14 10:42:38 +010020using namespace armnn;
21
David Monahan41f00f12019-05-27 09:44:52 +010022void CheckLayers(Graph& graph)
23{
24 unsigned int m_inputLayerCount = 0, m_outputLayerCount = 0, m_addLayerCount = 0;
25 for(auto layer : graph)
26 {
27 switch(layer->GetType())
28 {
29 case LayerType::Input:
30 ++m_inputLayerCount;
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +000031 BOOST_TEST((layer->GetName() == std::string("inLayer0") ||
32 layer->GetName() == std::string("inLayer1")));
David Monahan41f00f12019-05-27 09:44:52 +010033 break;
34 // The Addition layer should become a PreCompiled Layer after Optimisation
35 case LayerType::PreCompiled:
36 ++m_addLayerCount;
37 BOOST_TEST(layer->GetName() == "pre-compiled");
38 break;
39 case LayerType::Output:
40 ++m_outputLayerCount;
41 BOOST_TEST(layer->GetName() == "outLayer");
42 break;
43 default:
44 //Fail for anything else
45 BOOST_TEST(false);
46 }
47 }
48 BOOST_TEST(m_inputLayerCount == 2);
49 BOOST_TEST(m_outputLayerCount == 1);
50 BOOST_TEST(m_addLayerCount == 1);
51}
52
David Monahan005288d2019-05-14 10:42:38 +010053BOOST_AUTO_TEST_SUITE(OptimizationViewsTestSuite)
54
55BOOST_AUTO_TEST_CASE(OptimizedViewsSubgraphLayerCount)
56{
57 OptimizationViews view;
58 // Construct a graph with 3 layers
59 Graph& baseGraph = view.GetGraph();
60
61 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
62
63 Convolution2dDescriptor convDescriptor;
64 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
65 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
66 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
67 Layer* const substitutableCompiledLayer =
68 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
69
70 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
71
72 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
73 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
74 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
75
76 // Subgraph for a failed layer
77 SubgraphViewSelector::SubgraphViewPtr failedSubgraph =
78 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
79 CreateOutputsFrom({convLayer1}),
80 {convLayer1});
81 // Subgraph for an untouched layer
82 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
83 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
84 CreateOutputsFrom({convLayer2}),
85 {convLayer2});
86 // Subgraph for a substitutable layer
87 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
88 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
89 CreateOutputsFrom({convLayer2}),
90 {substitutableCompiledLayer});
91 // Create a Graph containing a layer to substitute in
92 Graph substitutableGraph;
93 Layer* const substitutionpreCompiledLayer =
94 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
95
96 // Subgraph for a substitution layer
97 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
98 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
99 CreateOutputsFrom({substitutionpreCompiledLayer}),
100 {substitutionpreCompiledLayer});
101
102 // Sub in the graph
103 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
104
105 view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
106 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
107
108 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
109 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
110 CreateOutputsFrom({convLayer2}),
111 {substitutionpreCompiledLayer});
112 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
113
114 // Construct original subgraph to compare against
115 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
116 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
117 CreateOutputsFrom({convLayer2}),
118 {convLayer1, convLayer2, substitutionpreCompiledLayer});
119
120 BOOST_CHECK(view.Validate(*originalSubgraph));
121}
122
123BOOST_AUTO_TEST_CASE(OptimizedViewsSubgraphLayerCountFailValidate)
124{
125 OptimizationViews view;
126 // Construct a graph with 3 layers
127 Graph& baseGraph = view.GetGraph();
128
129 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
130
131 Convolution2dDescriptor convDescriptor;
132 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
133 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
134 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
135 Layer* const substitutableCompiledLayer =
136 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
137
138 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
139
140 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
141 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
142 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
143
144 // Subgraph for an untouched layer
145 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
146 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
147 CreateOutputsFrom({convLayer2}),
148 {convLayer2});
149 // Subgraph for a substitutable layer
150 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
151 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
152 CreateOutputsFrom({convLayer2}),
153 {substitutableCompiledLayer});
154 // Create a Graph containing a layer to substitute in
155 Graph substitutableGraph;
156 Layer* const substitutionpreCompiledLayer =
157 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
158
159 // Subgraph for a substitution layer
160 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
161 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
162 CreateOutputsFrom({substitutionpreCompiledLayer}),
163 {substitutionpreCompiledLayer});
164
165 // Sub in the graph
166 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
167
168 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
169
170 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
171 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
172 CreateOutputsFrom({convLayer2}),
173 {substitutionpreCompiledLayer});
174 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
175
176 // Construct original subgraph to compare against
177 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
178 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
179 CreateOutputsFrom({convLayer2}),
180 {convLayer1, convLayer2, substitutionpreCompiledLayer});
181
182 // Validate should fail as convLayer1 is not counted
183 BOOST_CHECK(!view.Validate(*originalSubgraph));
184}
185
David Monahan41f00f12019-05-27 09:44:52 +0100186BOOST_AUTO_TEST_CASE(OptimizeViewsValidateDeviceMockBackend)
187{
188 // build up the structure of the network
189 armnn::INetworkPtr net(armnn::INetwork::Create());
190
191 armnn::IConnectableLayer* input = net->AddInputLayer(0, "inLayer0");
192 armnn::IConnectableLayer* input1 = net->AddInputLayer(1, "inLayer1");
193
194 armnn::IConnectableLayer* addition = net->AddAdditionLayer("addLayer");
195
196 armnn::IConnectableLayer* output = net->AddOutputLayer(0, "outLayer");
197
198 input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
199 input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
200 addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
201
202 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
203 input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
204 addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
205
David Monahanc1536d62020-02-12 15:52:35 +0000206 armnn::MockBackendInitialiser initialiser;
David Monahan41f00f12019-05-27 09:44:52 +0100207 armnn::IRuntime::CreationOptions options;
208 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
209
210 std::vector<armnn::BackendId> backends = { MockBackend().GetIdStatic() };
211 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
212 BOOST_CHECK(optNet);
213
214 // Check the optimised graph
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000215 armnn::Graph& graph = GetGraphForTesting(optNet.get());
216 CheckLayers(graph);
David Monahan41f00f12019-05-27 09:44:52 +0100217}
218
David Monahan005288d2019-05-14 10:42:38 +0100219BOOST_AUTO_TEST_SUITE_END()