blob: f0f5b632de78d8f16c10cf59aeda4abdca423f33 [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
Sadik Armagana097d2a2021-11-24 15:47:28 +00007#include <CommonTestUtils.hpp>
David Monahan005288d2019-05-14 10:42:38 +01008
Jan Eilersbb446e52020-04-02 13:56:54 +01009#include <Graph.hpp>
10#include <Network.hpp>
Jan Eilersbb446e52020-04-02 13:56:54 +010011#include <SubgraphViewSelector.hpp>
12
Francis Murtagha49ff082022-01-17 17:08:01 +000013#include <armnn/backends/OptimizationViews.hpp>
14#include <armnn/backends/SubgraphView.hpp>
15#include <armnn/utility/PolymorphicDowncast.hpp>
Cathal Corbett3464ba12022-03-04 11:36:39 +000016#include <armnnTestUtils/MockBackend.hpp>
Francis Murtagha49ff082022-01-17 17:08:01 +000017
Sadik Armagan1625efc2021-06-10 18:24:34 +010018#include <doctest/doctest.h>
Jan Eilersbb446e52020-04-02 13:56:54 +010019
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;
Sadik Armagan1625efc2021-06-10 18:24:34 +010031 CHECK((layer->GetName() == std::string("inLayer0") ||
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +000032 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;
Sadik Armagan1625efc2021-06-10 18:24:34 +010037 CHECK(std::string(layer->GetName()) == "pre-compiled");
David Monahan41f00f12019-05-27 09:44:52 +010038 break;
39 case LayerType::Output:
40 ++m_outputLayerCount;
Sadik Armagan1625efc2021-06-10 18:24:34 +010041 CHECK(std::string(layer->GetName()) == "outLayer");
David Monahan41f00f12019-05-27 09:44:52 +010042 break;
43 default:
44 //Fail for anything else
Sadik Armagan1625efc2021-06-10 18:24:34 +010045 CHECK(false);
David Monahan41f00f12019-05-27 09:44:52 +010046 }
47 }
Sadik Armagan1625efc2021-06-10 18:24:34 +010048 CHECK(m_inputLayerCount == 2);
49 CHECK(m_outputLayerCount == 1);
50 CHECK(m_addLayerCount == 1);
David Monahan41f00f12019-05-27 09:44:52 +010051}
52
Sadik Armagan1625efc2021-06-10 18:24:34 +010053TEST_SUITE("OptimizationViewsTestSuite")
54{
55TEST_CASE("OptimizedViewsSubgraphLayerCount")
David Monahan005288d2019-05-14 10:42:38 +010056{
57 OptimizationViews view;
58 // Construct a graph with 3 layers
Cathal Corbettcbfd7182021-12-15 17:12:59 +000059 Graph baseGraph;
David Monahan005288d2019-05-14 10:42:38 +010060
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
Sadik Armagan1625efc2021-06-10 18:24:34 +0100120 CHECK(view.Validate(*originalSubgraph));
David Monahan005288d2019-05-14 10:42:38 +0100121}
122
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000123
124TEST_CASE("OptimizedViewsSubgraphLayerCountUsingGetINetwork")
125{
126 OptimizationViews view;
127
128 IConnectableLayer* const inputLayer = view.GetINetwork()->AddInputLayer(0, "input");
129
130 DepthwiseConvolution2dDescriptor convDescriptor;
131 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
132 CompiledBlobPtr blobPtr;
133 BackendId backend = Compute::CpuRef;
134
135 Layer* convLayer1 = PolymorphicDowncast<Layer*>(
136 view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
137 ConstTensor(),
138 Optional<ConstTensor>(),
139 "conv1"));
140
141 Layer* convLayer2 = PolymorphicDowncast<Layer*>(
142 view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
143 ConstTensor(),
144 Optional<ConstTensor>(),
145 "conv2"));
146
147 IConnectableLayer* const outputLayer = view.GetINetwork()->AddOutputLayer(0, "output");
148
149 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
150 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
151 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
152
153 // Subgraph for a failed layer
154 SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
155 CreateOutputsFrom({convLayer1}),
156 {convLayer1});
157 // Subgraph for an untouched layer
158 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
159 CreateOutputsFrom({convLayer2}),
160 {convLayer2});
161
162 // Create a Network containing a layer to substitute in
163 NetworkImpl net;
164 Layer* substitutionpreCompiledLayer = PolymorphicDowncast<Layer*>(
Cathal Corbett3ea01072022-01-06 10:29:43 +0000165 net.AddPrecompiledLayer(substitutionLayerDescriptor, std::move(blobPtr), backend));
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000166
167 // Subgraph for a substitution layer
168 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
169 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
170 CreateOutputsFrom({substitutionpreCompiledLayer}),
171 {substitutionpreCompiledLayer});
172
173 view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
174 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
175
176 SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
177 CreateOutputsFrom({convLayer2}),
178 {substitutionpreCompiledLayer});
179 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
180
181 // Construct original subgraph to compare against
182 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
183 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
184 CreateOutputsFrom({convLayer2}),
185 {convLayer1, convLayer2, substitutionpreCompiledLayer});
186
187 CHECK(view.Validate(*originalSubgraph));
188}
189
Sadik Armagan1625efc2021-06-10 18:24:34 +0100190TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate")
David Monahan005288d2019-05-14 10:42:38 +0100191{
192 OptimizationViews view;
193 // Construct a graph with 3 layers
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000194 Graph baseGraph;
David Monahan005288d2019-05-14 10:42:38 +0100195
196 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
197
198 Convolution2dDescriptor convDescriptor;
199 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
200 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
201 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
202 Layer* const substitutableCompiledLayer =
203 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
204
205 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
206
207 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
208 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
209 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
210
211 // Subgraph for an untouched layer
212 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
213 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
214 CreateOutputsFrom({convLayer2}),
215 {convLayer2});
216 // Subgraph for a substitutable layer
217 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
218 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
219 CreateOutputsFrom({convLayer2}),
220 {substitutableCompiledLayer});
221 // Create a Graph containing a layer to substitute in
222 Graph substitutableGraph;
223 Layer* const substitutionpreCompiledLayer =
224 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
225
226 // Subgraph for a substitution layer
227 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
228 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
229 CreateOutputsFrom({substitutionpreCompiledLayer}),
230 {substitutionpreCompiledLayer});
231
232 // Sub in the graph
233 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
234
235 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
236
237 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
238 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
239 CreateOutputsFrom({convLayer2}),
240 {substitutionpreCompiledLayer});
241 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
242
243 // Construct original subgraph to compare against
244 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
245 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
246 CreateOutputsFrom({convLayer2}),
247 {convLayer1, convLayer2, substitutionpreCompiledLayer});
248
249 // Validate should fail as convLayer1 is not counted
Sadik Armagan1625efc2021-06-10 18:24:34 +0100250 CHECK(!view.Validate(*originalSubgraph));
David Monahan005288d2019-05-14 10:42:38 +0100251}
252
Sadik Armagan1625efc2021-06-10 18:24:34 +0100253TEST_CASE("OptimizeViewsValidateDeviceMockBackend")
David Monahan41f00f12019-05-27 09:44:52 +0100254{
255 // build up the structure of the network
256 armnn::INetworkPtr net(armnn::INetwork::Create());
257
258 armnn::IConnectableLayer* input = net->AddInputLayer(0, "inLayer0");
259 armnn::IConnectableLayer* input1 = net->AddInputLayer(1, "inLayer1");
260
261 armnn::IConnectableLayer* addition = net->AddAdditionLayer("addLayer");
262
263 armnn::IConnectableLayer* output = net->AddOutputLayer(0, "outLayer");
264
265 input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
266 input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
267 addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
268
269 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
270 input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
271 addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
272
David Monahanc1536d62020-02-12 15:52:35 +0000273 armnn::MockBackendInitialiser initialiser;
David Monahan41f00f12019-05-27 09:44:52 +0100274 armnn::IRuntime::CreationOptions options;
275 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
276
277 std::vector<armnn::BackendId> backends = { MockBackend().GetIdStatic() };
278 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100279 CHECK(optNet);
David Monahan41f00f12019-05-27 09:44:52 +0100280
281 // Check the optimised graph
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000282 armnn::Graph& graph = GetGraphForTesting(optNet.get());
283 CheckLayers(graph);
David Monahan41f00f12019-05-27 09:44:52 +0100284}
285
Sadik Armagan1625efc2021-06-10 18:24:34 +0100286}