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