blob: 8e51a527b91c0c039d78e561b109d549d1626409 [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 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
Sadik Armagan1625efc2021-06-10 18:24:34 +010017#include <doctest/doctest.h>
Jan Eilersbb446e52020-04-02 13:56:54 +010018
David Monahan005288d2019-05-14 10:42:38 +010019using namespace armnn;
20
David Monahan41f00f12019-05-27 09:44:52 +010021void CheckLayers(Graph& graph)
22{
23 unsigned int m_inputLayerCount = 0, m_outputLayerCount = 0, m_addLayerCount = 0;
24 for(auto layer : graph)
25 {
26 switch(layer->GetType())
27 {
28 case LayerType::Input:
29 ++m_inputLayerCount;
Sadik Armagan1625efc2021-06-10 18:24:34 +010030 CHECK((layer->GetName() == std::string("inLayer0") ||
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +000031 layer->GetName() == std::string("inLayer1")));
David Monahan41f00f12019-05-27 09:44:52 +010032 break;
33 // The Addition layer should become a PreCompiled Layer after Optimisation
34 case LayerType::PreCompiled:
35 ++m_addLayerCount;
Sadik Armagan1625efc2021-06-10 18:24:34 +010036 CHECK(std::string(layer->GetName()) == "pre-compiled");
David Monahan41f00f12019-05-27 09:44:52 +010037 break;
38 case LayerType::Output:
39 ++m_outputLayerCount;
Sadik Armagan1625efc2021-06-10 18:24:34 +010040 CHECK(std::string(layer->GetName()) == "outLayer");
David Monahan41f00f12019-05-27 09:44:52 +010041 break;
42 default:
43 //Fail for anything else
Sadik Armagan1625efc2021-06-10 18:24:34 +010044 CHECK(false);
David Monahan41f00f12019-05-27 09:44:52 +010045 }
46 }
Sadik Armagan1625efc2021-06-10 18:24:34 +010047 CHECK(m_inputLayerCount == 2);
48 CHECK(m_outputLayerCount == 1);
49 CHECK(m_addLayerCount == 1);
David Monahan41f00f12019-05-27 09:44:52 +010050}
51
Sadik Armagan1625efc2021-06-10 18:24:34 +010052TEST_SUITE("OptimizationViewsTestSuite")
53{
54TEST_CASE("OptimizedViewsSubgraphLayerCount")
David Monahan005288d2019-05-14 10:42:38 +010055{
56 OptimizationViews view;
57 // Construct a graph with 3 layers
Cathal Corbettcbfd7182021-12-15 17:12:59 +000058 Graph baseGraph;
David Monahan005288d2019-05-14 10:42:38 +010059
60 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
61
62 Convolution2dDescriptor convDescriptor;
63 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
64 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
65 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
66 Layer* const substitutableCompiledLayer =
67 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
68
69 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
70
71 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
72 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
73 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
74
75 // Subgraph for a failed layer
76 SubgraphViewSelector::SubgraphViewPtr failedSubgraph =
77 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
78 CreateOutputsFrom({convLayer1}),
79 {convLayer1});
80 // Subgraph for an untouched layer
81 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
82 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
83 CreateOutputsFrom({convLayer2}),
84 {convLayer2});
85 // Subgraph for a substitutable layer
86 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
87 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
88 CreateOutputsFrom({convLayer2}),
89 {substitutableCompiledLayer});
90 // Create a Graph containing a layer to substitute in
91 Graph substitutableGraph;
92 Layer* const substitutionpreCompiledLayer =
93 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
94
95 // Subgraph for a substitution layer
96 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
97 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
98 CreateOutputsFrom({substitutionpreCompiledLayer}),
99 {substitutionpreCompiledLayer});
100
101 // Sub in the graph
102 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
103
104 view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
105 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
106
107 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
108 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
109 CreateOutputsFrom({convLayer2}),
110 {substitutionpreCompiledLayer});
111 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
112
113 // Construct original subgraph to compare against
114 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
115 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
116 CreateOutputsFrom({convLayer2}),
117 {convLayer1, convLayer2, substitutionpreCompiledLayer});
118
Sadik Armagan1625efc2021-06-10 18:24:34 +0100119 CHECK(view.Validate(*originalSubgraph));
David Monahan005288d2019-05-14 10:42:38 +0100120}
121
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000122
123TEST_CASE("OptimizedViewsSubgraphLayerCountUsingGetINetwork")
124{
125 OptimizationViews view;
126
127 IConnectableLayer* const inputLayer = view.GetINetwork()->AddInputLayer(0, "input");
128
129 DepthwiseConvolution2dDescriptor convDescriptor;
130 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
131 CompiledBlobPtr blobPtr;
132 BackendId backend = Compute::CpuRef;
133
134 Layer* convLayer1 = PolymorphicDowncast<Layer*>(
135 view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
136 ConstTensor(),
137 Optional<ConstTensor>(),
138 "conv1"));
139
140 Layer* convLayer2 = PolymorphicDowncast<Layer*>(
141 view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
142 ConstTensor(),
143 Optional<ConstTensor>(),
144 "conv2"));
145
146 IConnectableLayer* const outputLayer = view.GetINetwork()->AddOutputLayer(0, "output");
147
148 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
149 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
150 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
151
152 // Subgraph for a failed layer
153 SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
154 CreateOutputsFrom({convLayer1}),
155 {convLayer1});
156 // Subgraph for an untouched layer
157 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
158 CreateOutputsFrom({convLayer2}),
159 {convLayer2});
160
161 // Create a Network containing a layer to substitute in
162 NetworkImpl net;
163 Layer* substitutionpreCompiledLayer = PolymorphicDowncast<Layer*>(
Cathal Corbett3ea01072022-01-06 10:29:43 +0000164 net.AddPrecompiledLayer(substitutionLayerDescriptor, std::move(blobPtr), backend));
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000165
166 // Subgraph for a substitution layer
167 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
168 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
169 CreateOutputsFrom({substitutionpreCompiledLayer}),
170 {substitutionpreCompiledLayer});
171
172 view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
173 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
174
175 SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
176 CreateOutputsFrom({convLayer2}),
177 {substitutionpreCompiledLayer});
178 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
179
180 // Construct original subgraph to compare against
181 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
182 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
183 CreateOutputsFrom({convLayer2}),
184 {convLayer1, convLayer2, substitutionpreCompiledLayer});
185
186 CHECK(view.Validate(*originalSubgraph));
187}
188
Sadik Armagan1625efc2021-06-10 18:24:34 +0100189TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate")
David Monahan005288d2019-05-14 10:42:38 +0100190{
191 OptimizationViews view;
192 // Construct a graph with 3 layers
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000193 Graph baseGraph;
David Monahan005288d2019-05-14 10:42:38 +0100194
195 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
196
197 Convolution2dDescriptor convDescriptor;
198 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
199 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
200 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
201 Layer* const substitutableCompiledLayer =
202 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
203
204 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
205
206 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
207 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
208 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
209
210 // Subgraph for an untouched layer
211 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
212 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
213 CreateOutputsFrom({convLayer2}),
214 {convLayer2});
215 // Subgraph for a substitutable layer
216 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
217 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
218 CreateOutputsFrom({convLayer2}),
219 {substitutableCompiledLayer});
220 // Create a Graph containing a layer to substitute in
221 Graph substitutableGraph;
222 Layer* const substitutionpreCompiledLayer =
223 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
224
225 // Subgraph for a substitution layer
226 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
227 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
228 CreateOutputsFrom({substitutionpreCompiledLayer}),
229 {substitutionpreCompiledLayer});
230
231 // Sub in the graph
232 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
233
234 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
235
236 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
237 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
238 CreateOutputsFrom({convLayer2}),
239 {substitutionpreCompiledLayer});
240 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
241
242 // Construct original subgraph to compare against
243 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
244 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
245 CreateOutputsFrom({convLayer2}),
246 {convLayer1, convLayer2, substitutionpreCompiledLayer});
247
248 // Validate should fail as convLayer1 is not counted
Sadik Armagan1625efc2021-06-10 18:24:34 +0100249 CHECK(!view.Validate(*originalSubgraph));
David Monahan005288d2019-05-14 10:42:38 +0100250}
251
Sadik Armagan1625efc2021-06-10 18:24:34 +0100252TEST_CASE("OptimizeViewsValidateDeviceMockBackend")
David Monahan41f00f12019-05-27 09:44:52 +0100253{
254 // build up the structure of the network
255 armnn::INetworkPtr net(armnn::INetwork::Create());
256
257 armnn::IConnectableLayer* input = net->AddInputLayer(0, "inLayer0");
258 armnn::IConnectableLayer* input1 = net->AddInputLayer(1, "inLayer1");
259
260 armnn::IConnectableLayer* addition = net->AddAdditionLayer("addLayer");
261
262 armnn::IConnectableLayer* output = net->AddOutputLayer(0, "outLayer");
263
264 input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
265 input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
266 addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
267
268 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
269 input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
270 addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
271
David Monahanc1536d62020-02-12 15:52:35 +0000272 armnn::MockBackendInitialiser initialiser;
David Monahan41f00f12019-05-27 09:44:52 +0100273 armnn::IRuntime::CreationOptions options;
274 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
275
276 std::vector<armnn::BackendId> backends = { MockBackend().GetIdStatic() };
277 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100278 CHECK(optNet);
David Monahan41f00f12019-05-27 09:44:52 +0100279
280 // Check the optimised graph
Francis Murtagh3d2b4b22021-02-15 18:23:17 +0000281 armnn::Graph& graph = GetGraphForTesting(optNet.get());
282 CheckLayers(graph);
David Monahan41f00f12019-05-27 09:44:52 +0100283}
284
Sadik Armagan1625efc2021-06-10 18:24:34 +0100285}