xref: /aosp_15_r20/external/armnn/src/backends/backendsCommon/test/OptimizationViewsTests.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017, 2019-2023  Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 
7 #include <CommonTestUtils.hpp>
8 
9 #include <Graph.hpp>
10 #include <Network.hpp>
11 #include <SubgraphViewSelector.hpp>
12 
13 #include <armnn/backends/OptimizationViews.hpp>
14 #include <armnn/backends/SubgraphView.hpp>
15 #include <armnn/utility/PolymorphicDowncast.hpp>
16 #include <armnnTestUtils/MockBackend.hpp>
17 
18 #include <doctest/doctest.h>
19 
20 using namespace armnn;
21 
CheckLayers(Graph & graph)22 void 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;
31                 CHECK((layer->GetName() == std::string("inLayer0") ||
32                             layer->GetName() == std::string("inLayer1")));
33                 break;
34             // The Addition layer should become a PreCompiled Layer after Optimisation
35             case LayerType::PreCompiled:
36                 ++m_addLayerCount;
37                 CHECK(std::string(layer->GetName()) == "pre-compiled");
38                 break;
39             case LayerType::Output:
40                 ++m_outputLayerCount;
41                 CHECK(std::string(layer->GetName()) == "outLayer");
42                 break;
43             default:
44                 //Fail for anything else
45                 CHECK(false);
46         }
47     }
48     CHECK(m_inputLayerCount == 2);
49     CHECK(m_outputLayerCount == 1);
50     CHECK(m_addLayerCount == 1);
51 }
52 
53 TEST_SUITE("OptimizationViewsTestSuite")
54 {
55 TEST_CASE("OptimizedViewsSubgraphLayerCount")
56 {
57     OptimizationViews view;
58     // Construct a graph with 3 layers
59     Graph baseGraph;
60 
61     Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
62 
63     Convolution2dDescriptor convDescriptor;
64     PreCompiledDescriptor substitutionLayerDescriptor(2, 1);
65     Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
66     Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
67     Layer* const weightsLayer1 = baseGraph.AddLayer<ConstantLayer>("weights1");
68     Layer* const weightsLayer2 = baseGraph.AddLayer<ConstantLayer>("weights2");
69     Layer* const substitutableCompiledLayer =
70             baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
71 
72     Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
73 
74     inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
75     weightsLayer1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1));
76     convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
77     weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1));
78     convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
79 
80     // Subgraph for a failed layer
81     SubgraphView::SubgraphViewPtr failedSubgraph =
82         CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
83                                CreateOutputsFrom({convLayer1}),
84                                {convLayer1});
85     // Subgraph for an untouched layer
86     SubgraphView::SubgraphViewPtr untouchedSubgraph =
87             CreateSubgraphViewFrom(CreateInputsFrom(convLayer2),
88                                    CreateOutputsFrom({convLayer2}),
89                                    {convLayer2});
90     // Subgraph for a substitutable layer
91     SubgraphView::SubgraphViewPtr substitutableSubgraph =
92             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
93                                    CreateOutputsFrom({convLayer2}),
94                                    {substitutableCompiledLayer});
95     // Create a Graph containing a layer to substitute in
96     Graph substitutableGraph;
97     Layer* const substitutionpreCompiledLayer =
98             substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
99 
100     // Subgraph for a substitution layer
101     SubgraphView::SubgraphViewPtr substitutionSubgraph =
102             CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
103                                    CreateOutputsFrom({substitutionpreCompiledLayer}),
104                                    {substitutionpreCompiledLayer});
105 
106     // Sub in the graph
107     baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
108 
109     view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
110     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
111 
112     SubgraphView::SubgraphViewPtr baseSubgraph =
113             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
114                                    CreateOutputsFrom({convLayer2}),
115                                    {substitutionpreCompiledLayer});
116     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
117 
118     // Construct original subgraph to compare against
119     SubgraphView::SubgraphViewPtr originalSubgraph =
120             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
121             CreateOutputsFrom({convLayer2}),
122             {convLayer1, convLayer2, substitutionpreCompiledLayer});
123 
124     CHECK(view.Validate(*originalSubgraph));
125 }
126 
127 
128 TEST_CASE("OptimizedViewsSubgraphLayerCountUsingGetINetwork")
129 {
130     OptimizationViews view;
131 
132     IConnectableLayer* const inputLayer = view.GetINetwork()->AddInputLayer(0, "input");
133 
134     DepthwiseConvolution2dDescriptor convDescriptor;
135     PreCompiledDescriptor substitutionLayerDescriptor(2, 1);
136     CompiledBlobPtr blobPtr;
137     BackendId backend = Compute::CpuRef;
138 
139     Layer* convLayer1 = PolymorphicDowncast<Layer*>(
140         view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
141                                                            "conv1"));
142 
143     Layer* convLayer2 = PolymorphicDowncast<Layer*>(
144         view.GetINetwork()->AddDepthwiseConvolution2dLayer(convDescriptor,
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     SubgraphView::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
155                                                                                   CreateOutputsFrom({convLayer1}),
156                                                                                   {convLayer1});
157     // Subgraph for an untouched layer
158     SubgraphView::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*>(
165         net.AddPrecompiledLayer(substitutionLayerDescriptor, std::move(blobPtr), backend));
166 
167     // Subgraph for a substitution layer
168     SubgraphView::SubgraphViewPtr substitutionSubgraph =
169         CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
170                                                 CreateOutputsFrom({substitutionpreCompiledLayer}),
171                                                 {substitutionpreCompiledLayer});
172 
173     view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
174     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
175 
176     SubgraphView::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
177                                                                                 CreateOutputsFrom({convLayer2}),
178                                                                                 {substitutionpreCompiledLayer});
179     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
180 
181     // Construct original subgraph to compare against
182     SubgraphView::SubgraphViewPtr originalSubgraph =
183         CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
184                                                 CreateOutputsFrom({convLayer2}),
185                                                 {convLayer1, convLayer2, substitutionpreCompiledLayer});
186 
187     CHECK(view.Validate(*originalSubgraph));
188 }
189 
190 TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate")
191 {
192     OptimizationViews view;
193     // Construct a graph with 3 layers
194     Graph baseGraph;
195 
196     Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
197 
198     Convolution2dDescriptor convDescriptor;
199     PreCompiledDescriptor substitutionLayerDescriptor(2, 1);
200     Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
201     Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
202     Layer* const weightsLayer1 = baseGraph.AddLayer<ConstantLayer>("weights1");
203     Layer* const weightsLayer2 = baseGraph.AddLayer<ConstantLayer>("weights2");
204     Layer* const substitutableCompiledLayer =
205             baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
206 
207     Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
208 
209 
210     inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
211     weightsLayer1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1));
212     convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
213     weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1));
214     convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
215 
216     // Subgraph for an untouched layer
217     SubgraphView::SubgraphViewPtr untouchedSubgraph =
218             CreateSubgraphViewFrom(CreateInputsFrom(convLayer2),
219                                    CreateOutputsFrom({convLayer2}),
220                                    {convLayer2});
221     // Subgraph for a substitutable layer
222     SubgraphView::SubgraphViewPtr substitutableSubgraph =
223             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
224                                    CreateOutputsFrom({convLayer2}),
225                                    {substitutableCompiledLayer});
226     // Create a Graph containing a layer to substitute in
227     Graph substitutableGraph;
228     Layer* const substitutionpreCompiledLayer =
229             substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
230 
231     // Subgraph for a substitution layer
232     SubgraphView::SubgraphViewPtr substitutionSubgraph =
233             CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
234                                    CreateOutputsFrom({substitutionpreCompiledLayer}),
235                                    {substitutionpreCompiledLayer});
236 
237     // Sub in the graph
238     baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
239 
240     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
241 
242     SubgraphView::SubgraphViewPtr baseSubgraph =
243             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
244                                    CreateOutputsFrom({convLayer2}),
245                                    {substitutionpreCompiledLayer});
246     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
247 
248     // Construct original subgraph to compare against
249     SubgraphView::SubgraphViewPtr originalSubgraph =
250             CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
251                                    CreateOutputsFrom({convLayer2}),
252                                    {convLayer1, convLayer2, substitutionpreCompiledLayer});
253 
254     // Validate should fail as convLayer1 is not counted
255     CHECK(!view.Validate(*originalSubgraph));
256 }
257 
258 TEST_CASE("OptimizeViewsValidateDeviceMockBackend")
259 {
260     // build up the structure of the network
261     armnn::INetworkPtr net(armnn::INetwork::Create());
262 
263     armnn::IConnectableLayer* input = net->AddInputLayer(0, "inLayer0");
264     armnn::IConnectableLayer* input1 = net->AddInputLayer(1, "inLayer1");
265 
266     ARMNN_NO_DEPRECATE_WARN_BEGIN
267     armnn::IConnectableLayer* addition = net->AddAdditionLayer("addLayer");
268     ARMNN_NO_DEPRECATE_WARN_END
269 
270     armnn::IConnectableLayer* output = net->AddOutputLayer(0, "outLayer");
271 
272     input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
273     input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
274     addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
275 
276     input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
277     input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
278     addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
279 
280     armnn::MockBackendInitialiser initialiser;
281     armnn::IRuntime::CreationOptions options;
282     armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
283 
284     std::vector<armnn::BackendId> backends = { MockBackend().GetIdStatic() };
285     armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec());
286     CHECK(optNet);
287 
288     // Check the optimised graph
289     armnn::Graph& graph = GetGraphForTesting(optNet.get());
290     CheckLayers(graph);
291 }
292 
293 TEST_CASE("OptimizedViewsReturnsINetworkReference")
294 {
295     OptimizationViews view;
296 
297     auto layer = view.GetINetworkRef().AddInputLayer(0, "input");
298 
299     // Check layer has been added to the referenced INetwork
300     CHECK(layer);
301 }
302 
303 
304 }
305