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