blob: 639e1fd59ecbaa5da8a66e4605adfcf195b1ca15 [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>
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000011#include <armnn/backends/OptimizationViews.hpp>
David Monahan005288d2019-05-14 10:42:38 +010012#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;
Narumol Prangnawarat60a20fb2019-12-09 17:24:41 +000028 BOOST_TEST((layer->GetName() == std::string("inLayer0") ||
29 layer->GetName() == std::string("inLayer1")));
David Monahan41f00f12019-05-27 09:44:52 +010030 break;
31 // The Addition layer should become a PreCompiled Layer after Optimisation
32 case LayerType::PreCompiled:
33 ++m_addLayerCount;
34 BOOST_TEST(layer->GetName() == "pre-compiled");
35 break;
36 case LayerType::Output:
37 ++m_outputLayerCount;
38 BOOST_TEST(layer->GetName() == "outLayer");
39 break;
40 default:
41 //Fail for anything else
42 BOOST_TEST(false);
43 }
44 }
45 BOOST_TEST(m_inputLayerCount == 2);
46 BOOST_TEST(m_outputLayerCount == 1);
47 BOOST_TEST(m_addLayerCount == 1);
48}
49
David Monahan005288d2019-05-14 10:42:38 +010050BOOST_AUTO_TEST_SUITE(OptimizationViewsTestSuite)
51
52BOOST_AUTO_TEST_CASE(OptimizedViewsSubgraphLayerCount)
53{
54 OptimizationViews view;
55 // Construct a graph with 3 layers
56 Graph& baseGraph = view.GetGraph();
57
58 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
59
60 Convolution2dDescriptor convDescriptor;
61 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
62 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
63 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
64 Layer* const substitutableCompiledLayer =
65 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
66
67 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
68
69 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
70 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
71 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
72
73 // Subgraph for a failed layer
74 SubgraphViewSelector::SubgraphViewPtr failedSubgraph =
75 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
76 CreateOutputsFrom({convLayer1}),
77 {convLayer1});
78 // Subgraph for an untouched layer
79 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
80 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
81 CreateOutputsFrom({convLayer2}),
82 {convLayer2});
83 // Subgraph for a substitutable layer
84 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
85 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
86 CreateOutputsFrom({convLayer2}),
87 {substitutableCompiledLayer});
88 // Create a Graph containing a layer to substitute in
89 Graph substitutableGraph;
90 Layer* const substitutionpreCompiledLayer =
91 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
92
93 // Subgraph for a substitution layer
94 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
95 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
96 CreateOutputsFrom({substitutionpreCompiledLayer}),
97 {substitutionpreCompiledLayer});
98
99 // Sub in the graph
100 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
101
102 view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
103 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
104
105 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
106 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
107 CreateOutputsFrom({convLayer2}),
108 {substitutionpreCompiledLayer});
109 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
110
111 // Construct original subgraph to compare against
112 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
113 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
114 CreateOutputsFrom({convLayer2}),
115 {convLayer1, convLayer2, substitutionpreCompiledLayer});
116
117 BOOST_CHECK(view.Validate(*originalSubgraph));
118}
119
120BOOST_AUTO_TEST_CASE(OptimizedViewsSubgraphLayerCountFailValidate)
121{
122 OptimizationViews view;
123 // Construct a graph with 3 layers
124 Graph& baseGraph = view.GetGraph();
125
126 Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
127
128 Convolution2dDescriptor convDescriptor;
129 PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
130 Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
131 Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
132 Layer* const substitutableCompiledLayer =
133 baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
134
135 Layer* const outputLayer = baseGraph.AddLayer<OutputLayer>(0, "output");
136
137 inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0));
138 convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0));
139 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
140
141 // Subgraph for an untouched layer
142 SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
143 CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
144 CreateOutputsFrom({convLayer2}),
145 {convLayer2});
146 // Subgraph for a substitutable layer
147 SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
148 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
149 CreateOutputsFrom({convLayer2}),
150 {substitutableCompiledLayer});
151 // Create a Graph containing a layer to substitute in
152 Graph substitutableGraph;
153 Layer* const substitutionpreCompiledLayer =
154 substitutableGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
155
156 // Subgraph for a substitution layer
157 SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
158 CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
159 CreateOutputsFrom({substitutionpreCompiledLayer}),
160 {substitutionpreCompiledLayer});
161
162 // Sub in the graph
163 baseGraph.SubstituteSubgraph(*substitutableSubgraph, *substitutionSubgraph);
164
165 view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
166
167 SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
168 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
169 CreateOutputsFrom({convLayer2}),
170 {substitutionpreCompiledLayer});
171 view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
172
173 // Construct original subgraph to compare against
174 SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
175 CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
176 CreateOutputsFrom({convLayer2}),
177 {convLayer1, convLayer2, substitutionpreCompiledLayer});
178
179 // Validate should fail as convLayer1 is not counted
180 BOOST_CHECK(!view.Validate(*originalSubgraph));
181}
182
David Monahan41f00f12019-05-27 09:44:52 +0100183BOOST_AUTO_TEST_CASE(OptimizeViewsValidateDeviceMockBackend)
184{
185 // build up the structure of the network
186 armnn::INetworkPtr net(armnn::INetwork::Create());
187
188 armnn::IConnectableLayer* input = net->AddInputLayer(0, "inLayer0");
189 armnn::IConnectableLayer* input1 = net->AddInputLayer(1, "inLayer1");
190
191 armnn::IConnectableLayer* addition = net->AddAdditionLayer("addLayer");
192
193 armnn::IConnectableLayer* output = net->AddOutputLayer(0, "outLayer");
194
195 input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
196 input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
197 addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
198
199 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
200 input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
201 addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
202
203 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()