blob: 8036b41fb29ef87438480112db1ae65ced923312 [file] [log] [blame]
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
Sadik Armagana097d2a2021-11-24 15:47:28 +00006#include <CommonTestUtils.hpp>
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01007#include "MockBackend.hpp"
8#include "MockBackendId.hpp"
9
10#include <Graph.hpp>
11#include <Network.hpp>
12
Matteo Martincighc601aa62019-10-29 15:03:22 +000013#include <armnn/BackendRegistry.hpp>
Matteo Martincighf02e6cd2019-05-17 12:15:30 +010014
Sadik Armagan1625efc2021-06-10 18:24:34 +010015#include <doctest/doctest.h>
Matteo Martincighf02e6cd2019-05-17 12:15:30 +010016#include <unordered_map>
17
18using namespace armnn;
19
20namespace
21{
22
23// The expected number of layers, input and output slots in a subgraph after a test
24struct ExpectedSubgraphSize
25{
26 size_t m_NumInputSlots = 0;
27 size_t m_NumOutputSlots = 0;
28 size_t m_NumLayers = 0;
29};
30
31// Keep the layers organized by layer name
32using LayerNameToLayerMap = std::unordered_map<std::string, Layer*>;
33
34// Used to convert input and output slots from reference type (as stored in graphs) to
35// pointer type (as stored in subgraphs)
36template <typename SlotType>
37SlotType* ConvertReferenceTypeToPointerType(const SlotType& input)
38{
39 return const_cast<SlotType*>(&input);
40}
41
42// Used to convert input and output slots from reference type (as stored in graphs) to
43// pointer type (as stored in subgraphs), array version
44template <typename SlotType>
45std::vector<SlotType*> ConvertReferenceTypeToPointerType(const std::vector<SlotType>& input)
46{
47 std::vector<SlotType*> output;
48 std::transform(input.begin(),
49 input.end(),
50 std::back_inserter(output),
51 [](const SlotType& inputItem)
52 {
53 return ConvertReferenceTypeToPointerType(inputItem);
54 });
55
56 return output;
57}
58
Francis Murtagh56ccf682021-12-13 18:48:12 +000059// Convert from vector of Slots* (Input/Output) to vector of ISlots* (IInput/IOutput)
60template <typename SlotType, typename ResultSlotType>
61std::vector<ResultSlotType*> ConvertSlotsToISlots(const std::vector<SlotType*> input)
62{
63 std::vector<ResultSlotType*> output;
64 for (auto slot : input)
65 {
66 output.push_back(PolymorphicDowncast<ResultSlotType*>(slot));
67 }
68 return output;
69}
70
Matteo Martincighf02e6cd2019-05-17 12:15:30 +010071// Convenience function to add an input layer to a graph
72Layer* AddInputLayer(Graph& graph,
73 const std::string& layerName,
74 const TensorInfo& inputInfo,
75 LayerBindingId inputId = 0)
76{
77 Layer* const inputLayer = graph.AddLayer<InputLayer>(inputId, layerName.c_str());
Sadik Armagan1625efc2021-06-10 18:24:34 +010078 CHECK(inputLayer);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +010079 inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
80 return inputLayer;
81}
82
83// Convenience function to add an output layer to a graph
84Layer* AddOutputLayer(Graph& graph,
85 const std::string& layerName)
86{
87 Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, layerName.c_str());
Sadik Armagan1625efc2021-06-10 18:24:34 +010088 CHECK(outputLayer);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +010089 return outputLayer;
90}
91
92// Convenience function to add a convolution layer to a graph
93Convolution2dLayer* AddConvolutionLayer(Graph& graph,
94 LayerNameToLayerMap& layersInGraph,
95 const Convolution2dDescriptor& convolutionDescriptor,
96 const std::string& layerName,
97 const TensorInfo& weightInfo,
98 const TensorInfo& biasInfo,
99 const TensorInfo& outputInfo)
100{
101 Convolution2dLayer* const convLayer = graph.AddLayer<Convolution2dLayer>(convolutionDescriptor, layerName.c_str());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100102 CHECK(convLayer);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100103 SetWeightAndBias(convLayer, weightInfo, biasInfo);
104 convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
105 layersInGraph.insert(std::make_pair(convLayer->GetName(), convLayer));
106 return convLayer;
107}
108
109// Convenience function to add a pooling layer to a graph
110Pooling2dLayer* AddPoolingLayer(Graph& graph,
111 LayerNameToLayerMap& layersInGraph,
112 const Pooling2dDescriptor& poolingDescriptor,
113 const std::string& layerName,
114 const TensorInfo& outputInfo)
115{
116 Pooling2dLayer* const poolingLayer = graph.AddLayer<Pooling2dLayer>(poolingDescriptor, layerName.c_str());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100117 CHECK(poolingLayer);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100118 poolingLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
119 layersInGraph.insert(std::make_pair(poolingLayer->GetName(), poolingLayer));
120 return poolingLayer;
121}
122
123// Convenience function to add an addition layer to a graph
124AdditionLayer* AddAdditionaLayer(Graph& graph,
125 LayerNameToLayerMap& layersInGraph,
126 const std::string& layerName,
127 const TensorInfo& outputInfo)
128{
129 AdditionLayer* const additionLayer = graph.AddLayer<AdditionLayer>(layerName.c_str());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100130 CHECK(additionLayer);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100131 additionLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
132 layersInGraph.insert(std::make_pair(additionLayer->GetName(), additionLayer));
133 return additionLayer;
134}
135
136// Convenience function to check that the given substitution matches the specified expected values
137void CheckSubstitution(const OptimizationViews::SubstitutionPair& substitution,
138 const ExpectedSubgraphSize& expectedSubstitutableSubgraphSize,
139 const ExpectedSubgraphSize& expectedReplacementSubgraphSize,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000140 const SubgraphView::IInputSlots& expectedSubstitutableInputSlots,
141 const SubgraphView::IOutputSlots& expectedSubstitutableOutputSlots,
142 const SubgraphView::IConnectableLayers& expectedSubstitutableLayers)
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100143{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000144 const SubgraphView& substitutableSubgraph = substitution.m_SubstitutableSubgraph;
145 const SubgraphView::IInputSlots& substitutableSubgraphInputSlots = substitutableSubgraph.GetIInputSlots();
146 const SubgraphView::IOutputSlots& substitutableSubgraphOutputSlots = substitutableSubgraph.GetIOutputSlots();
147 const SubgraphView::IConnectableLayers& substitutableSubgraphLayers =
148 substitutableSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100149
Francis Murtagh56ccf682021-12-13 18:48:12 +0000150 const SubgraphView& replacementSubgraph = substitution.m_ReplacementSubgraph;
151 const SubgraphView::IInputSlots& replacementSubgraphInputSlots = replacementSubgraph.GetIInputSlots();
152 const SubgraphView::IOutputSlots& replacementSubgraphOutputSlots = replacementSubgraph.GetIOutputSlots();
153 const SubgraphView::IConnectableLayers& replacementSubgraphLayers = replacementSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100154
Sadik Armagan1625efc2021-06-10 18:24:34 +0100155 CHECK(substitutableSubgraphInputSlots.size() == expectedSubstitutableSubgraphSize.m_NumInputSlots);
156 CHECK(substitutableSubgraphOutputSlots.size() == expectedSubstitutableSubgraphSize.m_NumOutputSlots);
157 CHECK(substitutableSubgraphLayers.size() == expectedSubstitutableSubgraphSize.m_NumLayers);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100158
Sadik Armagan1625efc2021-06-10 18:24:34 +0100159 CHECK(AreEqual(substitutableSubgraphInputSlots, expectedSubstitutableInputSlots));
160 CHECK(AreEqual(substitutableSubgraphOutputSlots, expectedSubstitutableOutputSlots));
161 CHECK(AreEqual(substitutableSubgraphLayers, expectedSubstitutableLayers));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100162
Sadik Armagan1625efc2021-06-10 18:24:34 +0100163 CHECK(replacementSubgraphInputSlots.size() == expectedReplacementSubgraphSize.m_NumInputSlots);
164 CHECK(replacementSubgraphOutputSlots.size() == expectedReplacementSubgraphSize.m_NumOutputSlots);
165 CHECK(replacementSubgraphLayers.size() == expectedReplacementSubgraphSize.m_NumLayers);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100166
Sadik Armagan1625efc2021-06-10 18:24:34 +0100167 CHECK(!AreEqual(replacementSubgraphInputSlots, expectedSubstitutableInputSlots));
168 CHECK(!AreEqual(replacementSubgraphOutputSlots, expectedSubstitutableOutputSlots));
169 CHECK(!AreEqual(replacementSubgraphLayers, expectedSubstitutableLayers));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100170
Sadik Armagan1625efc2021-06-10 18:24:34 +0100171 CHECK(std::all_of(replacementSubgraphLayers.begin(),
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100172 replacementSubgraphLayers.end(),
Francis Murtagh56ccf682021-12-13 18:48:12 +0000173 [](const IConnectableLayer* layer)
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100174 {
175 return layer->GetType() == LayerType::PreCompiled;
176 }));
177}
178
179// Convenience function to check that the given failed subgraph matches the specified expected values
180void CheckFailedSubgraph(const SubgraphView& failedSubgraph,
181 const ExpectedSubgraphSize& expectedFailedSubgraphSize,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000182 const SubgraphView::IInputSlots& expectedFailedInputSlots,
183 const SubgraphView::IOutputSlots& expectedFailedOutputSlots,
184 const SubgraphView::IConnectableLayers& expectedFailedLayers)
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100185{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000186 const SubgraphView::IInputSlots& failedSubgraphInputSlots = failedSubgraph.GetIInputSlots();
187 const SubgraphView::IOutputSlots& failedSubgraphOutputSlots = failedSubgraph.GetIOutputSlots();
188 const SubgraphView::IConnectableLayers& failedSubgraphLayers = failedSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100189
Sadik Armagan1625efc2021-06-10 18:24:34 +0100190 CHECK(failedSubgraphInputSlots.size() == expectedFailedSubgraphSize.m_NumInputSlots);
191 CHECK(failedSubgraphOutputSlots.size() == expectedFailedSubgraphSize.m_NumOutputSlots);
192 CHECK(failedSubgraphLayers.size() == expectedFailedSubgraphSize.m_NumLayers);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100193
Sadik Armagan1625efc2021-06-10 18:24:34 +0100194 CHECK(AreEqual(failedSubgraphInputSlots, expectedFailedInputSlots));
195 CHECK(AreEqual(failedSubgraphOutputSlots, expectedFailedOutputSlots));
196 CHECK(AreEqual(failedSubgraphLayers, expectedFailedLayers));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100197}
198
199// Convenience function to check that the given untouched subgraph matches the specified expected values
200void CheckUntouchedSubgraph(const SubgraphView& untouchedSubgraph,
201 const ExpectedSubgraphSize& expectedUntouchedSubgraphSize,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000202 const SubgraphView::IInputSlots& expectedUntouchedInputSlots,
203 const SubgraphView::IOutputSlots& expectedUntouchedOutputSlots,
204 const SubgraphView::IConnectableLayers& expectedUntouchedLayers)
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100205{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000206 const SubgraphView::IInputSlots& untouchedSubgraphInputSlots = untouchedSubgraph.GetIInputSlots();
207 const SubgraphView::IOutputSlots& untouchedSubgraphOutputSlots = untouchedSubgraph.GetIOutputSlots();
208 const SubgraphView::IConnectableLayers& untouchedSubgraphLayers = untouchedSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100209
Sadik Armagan1625efc2021-06-10 18:24:34 +0100210 CHECK(untouchedSubgraphInputSlots.size() == expectedUntouchedSubgraphSize.m_NumInputSlots);
211 CHECK(untouchedSubgraphOutputSlots.size() == expectedUntouchedSubgraphSize.m_NumOutputSlots);
212 CHECK(untouchedSubgraphLayers.size() == expectedUntouchedSubgraphSize.m_NumLayers);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100213
Sadik Armagan1625efc2021-06-10 18:24:34 +0100214 CHECK(AreEqual(untouchedSubgraphInputSlots, expectedUntouchedInputSlots));
215 CHECK(AreEqual(untouchedSubgraphOutputSlots, expectedUntouchedOutputSlots));
216 CHECK(AreEqual(untouchedSubgraphLayers, expectedUntouchedLayers));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100217}
218
219// Creates a subgraph containing only a single unsupported layer (only convolutions are unsupported by the mock backend)
220SubgraphView::SubgraphViewPtr BuildFullyUnsupportedSubgraph1(Graph& graph, LayerNameToLayerMap& layersInGraph)
221{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000222 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
223 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100224
225 Pooling2dDescriptor poolingDescriptor;
226 poolingDescriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
227 poolingDescriptor.m_PoolWidth = 2;
228 poolingDescriptor.m_PoolHeight = 2;
229 poolingDescriptor.m_StrideX = 2;
230 poolingDescriptor.m_StrideY = 2;
231 poolingDescriptor.m_PadLeft = 1;
232 poolingDescriptor.m_PadRight = 1;
233 poolingDescriptor.m_PadTop = 1;
234 poolingDescriptor.m_PadBottom = 1;
235 poolingDescriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
236 poolingDescriptor.m_DataLayout = DataLayout::NHWC;
237
238 // Construct the graph
239 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
240 Pooling2dLayer* const poolingLayer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
241 "pooling layer", outputInfo);
242 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
243
244 // Connect the network
245 inputLayer->GetOutputSlot(0).Connect(poolingLayer->GetInputSlot(0));
246 poolingLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
247
248 // Create the subgraph view for the whole network
249 return CreateSubgraphViewFrom(CreateInputsFrom({poolingLayer}),
250 CreateOutputsFrom({poolingLayer}),
251 {poolingLayer});
252}
253
254// Creates a subgraph containing only unsupported layers (only convolutions are unsupported by the mock backend)
255SubgraphView::SubgraphViewPtr BuildFullyUnsupportedSubgraph2(Graph& graph, LayerNameToLayerMap& layersInGraph)
256{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000257 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
258 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100259
260 Pooling2dDescriptor poolingDescriptor;
261 poolingDescriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
262 poolingDescriptor.m_PoolWidth = 2;
263 poolingDescriptor.m_PoolHeight = 2;
264 poolingDescriptor.m_StrideX = 2;
265 poolingDescriptor.m_StrideY = 2;
266 poolingDescriptor.m_PadLeft = 1;
267 poolingDescriptor.m_PadRight = 1;
268 poolingDescriptor.m_PadTop = 1;
269 poolingDescriptor.m_PadBottom = 1;
270 poolingDescriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
271 poolingDescriptor.m_DataLayout = DataLayout::NHWC;
272
273 // Construct the graph
274 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
275 Pooling2dLayer* const pooling1Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
276 "pooling1 layer", outputInfo);
277 Pooling2dLayer* const pooling2Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
278 "pooling2 layer", outputInfo);
279 Pooling2dLayer* const pooling3Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
280 "pooling3 layer", outputInfo);
281 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
282
283 // Connect the network
284 inputLayer->GetOutputSlot(0).Connect(pooling1Layer->GetInputSlot(0));
285 pooling1Layer->GetOutputSlot(0).Connect(pooling2Layer->GetInputSlot(0));
286 pooling2Layer->GetOutputSlot(0).Connect(pooling3Layer->GetInputSlot(0));
287 pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
288
289 // Create the subgraph view for the whole network
290 return CreateSubgraphViewFrom(CreateInputsFrom({pooling1Layer}),
291 CreateOutputsFrom({pooling3Layer}),
292 {pooling1Layer,
293 pooling2Layer,
294 pooling3Layer});
295}
296
297// Creates a simple subgraph with only one convolution layer, supported by the mock backend
298SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph1(Graph& graph, LayerNameToLayerMap& layersInGraph)
299{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000300 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
301 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
302 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100303 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
304
305 Convolution2dDescriptor convolutionDescriptor;
306 convolutionDescriptor.m_StrideX = 1;
307 convolutionDescriptor.m_StrideY = 1;
308 convolutionDescriptor.m_BiasEnabled = true;
309 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
310
311 // Construct the graph
312 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
313 Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
314 "conv layer", weightInfo, biasInfo, outputInfo);
315 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
316
317 // Connect the network
318 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
319 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
320
321 // Create the subgraph view for the whole network
322 return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}),
323 CreateOutputsFrom({convLayer}),
324 {convLayer});
325}
326
327// Creates a subgraph with five convolutions layers, all supported by the mock backend
328SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph2(Graph& graph, LayerNameToLayerMap& layersInGraph)
329{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000330 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
331 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
332 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100333 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
334
335 Convolution2dDescriptor convolutionDescriptor;
336 convolutionDescriptor.m_StrideX = 1;
337 convolutionDescriptor.m_StrideY = 1;
338 convolutionDescriptor.m_BiasEnabled = true;
339 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
340
341 // Construct the graph
342 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
343 Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
344 "conv1 layer", weightInfo, biasInfo, outputInfo);
345 Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
346 "conv2 layer", weightInfo, biasInfo, outputInfo);
347 Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
348 "conv3 layer", weightInfo, biasInfo, outputInfo);
349 Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
350 "conv4 layer", weightInfo, biasInfo, outputInfo);
351 Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
352 "conv5 layer", weightInfo, biasInfo, outputInfo);
353 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
354
355 // Connect the network
356 inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
357 conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
358 conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
359 conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0));
360 conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0));
361 conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
362
363 // Create the subgraph view for the whole network
364 return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
365 CreateOutputsFrom({conv5Layer}),
366 {conv1Layer,
367 conv2Layer,
368 conv3Layer,
369 conv4Layer,
370 conv5Layer});
371}
372
373// Creates a subgraph with both supported and unsupported layers
374// (only convolutions are unsupported by the mock backend)
375SubgraphView::SubgraphViewPtr BuildPartiallySupportedSubgraph(Graph& graph, LayerNameToLayerMap& layersInGraph)
376{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000377 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
378 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
379 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100380 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
381
382 Convolution2dDescriptor convolutionDescriptor;
383 convolutionDescriptor.m_StrideX = 1;
384 convolutionDescriptor.m_StrideY = 1;
385 convolutionDescriptor.m_BiasEnabled = true;
386 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
387
388 Pooling2dDescriptor poolingDescriptor;
389 poolingDescriptor.m_PoolType = armnn::PoolingAlgorithm::Average;
390 poolingDescriptor.m_PoolWidth = 2;
391 poolingDescriptor.m_PoolHeight = 2;
392 poolingDescriptor.m_StrideX = 2;
393 poolingDescriptor.m_StrideY = 2;
394 poolingDescriptor.m_PadLeft = 1;
395 poolingDescriptor.m_PadRight = 1;
396 poolingDescriptor.m_PadTop = 1;
397 poolingDescriptor.m_PadBottom = 1;
398 poolingDescriptor.m_PaddingMethod = armnn::PaddingMethod::Exclude;
399 poolingDescriptor.m_DataLayout = DataLayout::NHWC;
400
401 // Construct the graph
402 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
403 Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
404 "conv1 layer", weightInfo, biasInfo, outputInfo);
405 Pooling2dLayer* const pooling1Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
406 "pooling1 layer", outputInfo);
407 Pooling2dLayer* const pooling2Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
408 "pooling2 layer", outputInfo);
409 Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
410 "conv2 layer", weightInfo, biasInfo, outputInfo);
411 Pooling2dLayer* const pooling3Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
412 "pooling3 layer", outputInfo);
413 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
414
415 // Connect the network
416 inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
417 conv1Layer->GetOutputSlot(0).Connect(pooling1Layer->GetInputSlot(0));
418 pooling1Layer->GetOutputSlot(0).Connect(pooling2Layer->GetInputSlot(0));
419 pooling2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
420 conv2Layer->GetOutputSlot(0).Connect(pooling3Layer->GetInputSlot(0));
421 pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
422
423 // Create the subgraph view for the whole network
424 return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
425 CreateOutputsFrom({pooling3Layer}),
426 {conv1Layer,
427 pooling1Layer,
428 pooling2Layer,
429 conv2Layer,
430 pooling3Layer});
431}
432
433// Creates a subgraph with only unoptimizable layers ("unoptimizable" is added to the layer's name)
434SubgraphView::SubgraphViewPtr BuildFullyUnoptimizableSubgraph1(Graph& graph, LayerNameToLayerMap& layersInGraph)
435{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000436 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
437 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
438 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100439 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
440
441 Convolution2dDescriptor convolutionDescriptor;
442 convolutionDescriptor.m_StrideX = 1;
443 convolutionDescriptor.m_StrideY = 1;
444 convolutionDescriptor.m_BiasEnabled = true;
445 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
446
447 // Construct the graph
448 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
449 Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
450 "conv layer unoptimizable", weightInfo, biasInfo,
451 outputInfo);
452 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
453
454 // Connect the network
455 inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
456 convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
457
458 // Create the subgraph view for the whole network
459 return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}),
460 CreateOutputsFrom({convLayer}),
461 {convLayer});
462}
463
464// Creates a subgraph with some unoptimizable layers ("unoptimizable" is added to the layer's name)
465SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph1(Graph& graph, LayerNameToLayerMap& layersInGraph)
466{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000467 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
468 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
469 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100470 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
471
472 Convolution2dDescriptor convolutionDescriptor;
473 convolutionDescriptor.m_StrideX = 1;
474 convolutionDescriptor.m_StrideY = 1;
475 convolutionDescriptor.m_BiasEnabled = true;
476 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
477
478 // Construct the graph
479 Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
480 Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
481 "conv1 layer", weightInfo, biasInfo, outputInfo);
482 Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
483 "conv2 layer unoptimizable", weightInfo, biasInfo,
484 outputInfo);
485 Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
486 "conv3 layer", weightInfo, biasInfo, outputInfo);
487 Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
488 "conv4 layer unoptimizable", weightInfo, biasInfo,
489 outputInfo);
490 Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
491 "conv5 layer", weightInfo, biasInfo, outputInfo);
492 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
493
494 // Connect the network
495 inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
496 conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
497 conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
498 conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0));
499 conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0));
500 conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
501
502 // Create the subgraph view for the whole network
503 return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
504 CreateOutputsFrom({conv5Layer}),
505 {conv1Layer,
506 conv2Layer,
507 conv3Layer,
508 conv4Layer,
509 conv5Layer});
510}
511
512// Creates a subgraph with some input unoptimizable layers ("unoptimizable" is added to the layer's name),
513// this is meant to test input slots coming from different layers
514SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph2(Graph& graph, LayerNameToLayerMap& layersInGraph)
515{
Derek Lambertif90c56d2020-01-10 17:14:08 +0000516 const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
517 const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
518 const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100519 const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0);
520
521 Convolution2dDescriptor convolutionDescriptor;
522 convolutionDescriptor.m_StrideX = 1;
523 convolutionDescriptor.m_StrideY = 1;
524 convolutionDescriptor.m_BiasEnabled = true;
525 convolutionDescriptor.m_DataLayout = DataLayout::NHWC;
526
527 // Construct the graph
528 Layer* const input1Layer = AddInputLayer(graph, "input1 layer", inputInfo, 0);
529 Layer* const input2Layer = AddInputLayer(graph, "input2 layer", inputInfo, 1);
530 Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
531 "conv1 layer", weightInfo, biasInfo, outputInfo);
532 Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
533 "conv2 layer unoptimizable", weightInfo, biasInfo,
534 outputInfo);
535 Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
536 "conv3 layer", weightInfo, biasInfo, outputInfo);
537 AdditionLayer* const addLayer = AddAdditionaLayer(graph, layersInGraph, "add layer", outputInfo);
538 Layer* const outputLayer = AddOutputLayer(graph, "output layer");
539
540 // Connect the network
541 input1Layer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
542 input2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
543 conv1Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(0));
544 conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
545 conv3Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(1));
546 addLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
547
548 // Create the subgraph view for the whole network
549 return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer,
550 conv2Layer}),
551 CreateOutputsFrom({addLayer}),
552 {conv1Layer,
553 conv2Layer,
554 conv3Layer,
555 addLayer});
556}
557
558// The input subgraph contains only a single unsupported layer (only convolutions are unsupported by the mock backend)
559void FullyUnsupporteSubgraphTestImpl1()
560{
561 Graph graph;
562 LayerNameToLayerMap layersInGraph;
563
564 // Create an unsupported subgraph
565 SubgraphView::SubgraphViewPtr subgraphPtr = BuildFullyUnsupportedSubgraph1(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100566 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100567
Francis Murtagh56ccf682021-12-13 18:48:12 +0000568 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
569 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
570 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100571
Sadik Armagan1625efc2021-06-10 18:24:34 +0100572 CHECK(subgraphInputSlots.size() == 1);
573 CHECK(subgraphOutputSlots.size() == 1);
574 CHECK(subgraphLayers.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100575
Sadik Armagan1625efc2021-06-10 18:24:34 +0100576 CHECK(Contains(layersInGraph, "pooling layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100577
578 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +0000579 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100580 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100581 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100582
583 // Optimize the subgraph
584 OptimizationViews optimizationViews;
585
586 // Check that the optimization is carried out correctly, but no optimization is performed
Sadik Armagan1625efc2021-06-10 18:24:34 +0100587 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100588
589 // =======================================================================
590 // The expected results are:
591 // - No substitutions
592 // - Exactly one failed subgraph, corresponding to the whole original one
593 // - No untouched subgraphs
594 // =======================================================================
595
596 // -----------------------
597 // Check the substitutions
598 // -----------------------
599
Sadik Armagan1625efc2021-06-10 18:24:34 +0100600 CHECK(optimizationViews.GetSubstitutions().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100601
602 // --------------------------
603 // Check the failed subgraphs
604 // --------------------------
605
606 const OptimizationViews::Subgraphs& failedSubgraphs = optimizationViews.GetFailedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100607 CHECK(failedSubgraphs.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100608
609 CheckFailedSubgraph(failedSubgraphs.at(0),
610 { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
611 subgraphInputSlots,
612 subgraphOutputSlots,
613 subgraphLayers);
614
615 // -----------------------------
616 // Check the untouched subgraphs
617 // -----------------------------
618
Sadik Armagan1625efc2021-06-10 18:24:34 +0100619 CHECK(optimizationViews.GetUntouchedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100620}
621
622// The input subgraph contains only unsupported layers (only convolutions are unsupported by the mock backend)
623void FullyUnsupporteSubgraphTestImpl2()
624{
625 Graph graph;
626 LayerNameToLayerMap layersInGraph;
627
628 // Create an unsupported subgraph
629 SubgraphView::SubgraphViewPtr subgraphPtr = BuildFullyUnsupportedSubgraph2(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100630 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100631
Francis Murtagh56ccf682021-12-13 18:48:12 +0000632 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
633 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
634 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100635
Sadik Armagan1625efc2021-06-10 18:24:34 +0100636 CHECK(subgraphInputSlots.size() == 1);
637 CHECK(subgraphOutputSlots.size() == 1);
638 CHECK(subgraphLayers.size() == 3);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100639
Sadik Armagan1625efc2021-06-10 18:24:34 +0100640 CHECK(Contains(layersInGraph, "pooling1 layer"));
641 CHECK(Contains(layersInGraph, "pooling2 layer"));
642 CHECK(Contains(layersInGraph, "pooling3 layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100643
644 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +0000645 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100646 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100647 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100648
649 // Optimize the subgraph
650 OptimizationViews optimizationViews;
651
652 // Check that the optimization is carried out correctly, but no optimization is performed
Sadik Armagan1625efc2021-06-10 18:24:34 +0100653 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100654
655 // =======================================================================
656 // The expected results are:
657 // - No substitutions
658 // - Exactly one failed subgraph, corresponding to the whole original one
659 // - No untouched subgraphs
660 // =======================================================================
661
662 // -----------------------
663 // Check the substitutions
664 // -----------------------
665
Sadik Armagan1625efc2021-06-10 18:24:34 +0100666 CHECK(optimizationViews.GetSubstitutions().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100667
668 // --------------------------
669 // Check the failed subgraphs
670 // --------------------------
671
672 const OptimizationViews::Subgraphs& failedSubgraphs = optimizationViews.GetFailedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100673 CHECK(failedSubgraphs.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100674
Francis Murtagh56ccf682021-12-13 18:48:12 +0000675 std::list<IConnectableLayer*> expectedFailedLayers{ layersInGraph.at("pooling1 layer"),
Sadik Armagan1625efc2021-06-10 18:24:34 +0100676 layersInGraph.at("pooling2 layer"),
677 layersInGraph.at("pooling3 layer") };
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100678
679 const SubgraphView& failedSubgraph = failedSubgraphs.at(0);
680
681 CheckFailedSubgraph(failedSubgraph,
682 { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
683 subgraphInputSlots,
684 subgraphOutputSlots,
685 subgraphLayers);
686
Francis Murtagh56ccf682021-12-13 18:48:12 +0000687 const SubgraphView::IConnectableLayers& failedSubgraphLayers = failedSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100688
Sadik Armagan1625efc2021-06-10 18:24:34 +0100689 CHECK_EQ(failedSubgraphLayers.front() + 0, expectedFailedLayers.front() + 0);
690 CHECK_EQ(failedSubgraphLayers.front() + 1, expectedFailedLayers.front() + 1);
691 CHECK_EQ(failedSubgraphLayers.front() + 2, expectedFailedLayers.front() + 2);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100692
693 // -----------------------------
694 // Check the untouched subgraphs
695 // -----------------------------
696
Sadik Armagan1625efc2021-06-10 18:24:34 +0100697 CHECK(optimizationViews.GetUntouchedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100698}
699
700// A simple case with only one layer (convolution) to optimize, supported by the mock backend
701void FullyOptimizableSubgraphTestImpl1()
702{
703 Graph graph;
704 LayerNameToLayerMap layersInGraph;
705
706 // Create a fully optimizable subgraph
707 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyOptimizableSubgraph1(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100708 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100709
Francis Murtagh56ccf682021-12-13 18:48:12 +0000710 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
711 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
712 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100713
Sadik Armagan1625efc2021-06-10 18:24:34 +0100714 CHECK(subgraphInputSlots.size() == 1);
715 CHECK(subgraphOutputSlots.size() == 1);
716 CHECK(subgraphLayers.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100717
Sadik Armagan1625efc2021-06-10 18:24:34 +0100718 CHECK(Contains(layersInGraph, "conv layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100719
720 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +0000721 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100722 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100723 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100724
725 // Optimize the subgraph
726 OptimizationViews optimizationViews;
727
728 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +0100729 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100730
731 // ===========================================================================================
732 // The expected results are:
733 // - Exactly one substitution, mapping the whole input subgraph to a new replacement subgraph
734 // - No failed subgraphs
735 // - No untouched subgraphs
736 // ===========================================================================================
737
738 // -----------------------
739 // Check the substitutions
740 // -----------------------
741
742 const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100743 CHECK(substitutions.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100744
745 CheckSubstitution(substitutions.at(0),
746 { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
747 { subgraphInputSlots.size(), subgraphOutputSlots.size(), 1 },
748 subgraphInputSlots,
749 subgraphOutputSlots,
750 subgraphLayers);
751
752 // --------------------------
753 // Check the failed subgraphs
754 // --------------------------
755
Sadik Armagan1625efc2021-06-10 18:24:34 +0100756 CHECK(optimizationViews.GetFailedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100757
758 // -----------------------------
759 // Check the untouched subgraphs
760 // -----------------------------
761
Sadik Armagan1625efc2021-06-10 18:24:34 +0100762 CHECK(optimizationViews.GetUntouchedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100763}
764
765// A case with five layers (all convolutions) to optimize, all supported by the mock backend
766void FullyOptimizableSubgraphTestImpl2()
767{
768 Graph graph;
769 LayerNameToLayerMap layersInGraph;
770
771 // Create a fully optimizable subgraph
772 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyOptimizableSubgraph2(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100773 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100774
Francis Murtagh56ccf682021-12-13 18:48:12 +0000775 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
776 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
777 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100778
Francis Murtagh56ccf682021-12-13 18:48:12 +0000779 CHECK(subgraphPtr->GetIInputSlots().size() == 1);
780 CHECK(subgraphPtr->GetIOutputSlots().size() == 1);
781 CHECK(subgraphPtr->GetIConnectableLayers().size() == 5);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100782
Sadik Armagan1625efc2021-06-10 18:24:34 +0100783 CHECK(Contains(layersInGraph, "conv1 layer"));
784 CHECK(Contains(layersInGraph, "conv2 layer"));
785 CHECK(Contains(layersInGraph, "conv3 layer"));
786 CHECK(Contains(layersInGraph, "conv4 layer"));
787 CHECK(Contains(layersInGraph, "conv5 layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100788
789 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +0000790 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100791 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100792 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100793
794 // Optimize the subgraph
795 OptimizationViews optimizationViews;
796
797 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +0100798 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100799
800 // ===========================================================================================
801 // The expected results are:
802 // - Exactly one substitution, mapping the whole input subgraph to a new replacement subgraph
803 // - No failed subgraphs
804 // - No untouched subgraphs
805 // ===========================================================================================
806
807 // -----------------------
808 // Check the substitutions
809 // -----------------------
810
811 const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100812 CHECK(substitutions.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100813
Francis Murtagh56ccf682021-12-13 18:48:12 +0000814 std::list<IConnectableLayer*> expectedSubstitutableLayers{ layersInGraph.at("conv1 layer"),
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100815 layersInGraph.at("conv2 layer"),
816 layersInGraph.at("conv3 layer"),
817 layersInGraph.at("conv4 layer"),
818 layersInGraph.at("conv5 layer") };
819
820 const OptimizationViews::SubstitutionPair& substitution = substitutions.at(0);
821
822 CheckSubstitution(substitution,
823 { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
824 { subgraphInputSlots.size(), subgraphOutputSlots.size(), 1 },
825 subgraphInputSlots,
826 subgraphOutputSlots,
827 expectedSubstitutableLayers);
828
Francis Murtagh56ccf682021-12-13 18:48:12 +0000829 const SubgraphView::IConnectableLayers& substitutableSubgraphLayers =
830 substitution.m_SubstitutableSubgraph.GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100831
Sadik Armagan1625efc2021-06-10 18:24:34 +0100832 CHECK_EQ(substitutableSubgraphLayers.front() + 0, expectedSubstitutableLayers.front() + 0);
833 CHECK_EQ(substitutableSubgraphLayers.front() + 1, expectedSubstitutableLayers.front() + 1);
834 CHECK_EQ(substitutableSubgraphLayers.front() + 2, expectedSubstitutableLayers.front() + 2);
835 CHECK_EQ(substitutableSubgraphLayers.front() + 3, expectedSubstitutableLayers.front() + 3);
836 CHECK_EQ(substitutableSubgraphLayers.front() + 4, expectedSubstitutableLayers.front() + 4);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100837
838 // --------------------------
839 // Check the failed subgraphs
840 // --------------------------
841
Sadik Armagan1625efc2021-06-10 18:24:34 +0100842 CHECK(optimizationViews.GetFailedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100843
844 // -----------------------------
845 // Check the untouched subgraphs
846 // -----------------------------
847
Sadik Armagan1625efc2021-06-10 18:24:34 +0100848 CHECK(optimizationViews.GetUntouchedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100849}
850
851// The input subgraph contaions both supported and unsupported layers
852// (but only convolutions are unsupported by the mock backend)
853void PartiallySupportedSubgraphTestImpl()
854{
855 Graph graph;
856 LayerNameToLayerMap layersInGraph;
857
858 // Create a fully optimizable subgraph
859 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallySupportedSubgraph(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +0100860 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100861
Francis Murtagh56ccf682021-12-13 18:48:12 +0000862 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
863 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
864 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100865
Sadik Armagan1625efc2021-06-10 18:24:34 +0100866 CHECK(subgraphInputSlots.size() == 1);
867 CHECK(subgraphOutputSlots.size() == 1);
868 CHECK(subgraphLayers.size() == 5);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100869
Sadik Armagan1625efc2021-06-10 18:24:34 +0100870 CHECK(Contains(layersInGraph, "conv1 layer"));
871 CHECK(Contains(layersInGraph, "pooling1 layer"));
872 CHECK(Contains(layersInGraph, "pooling2 layer"));
873 CHECK(Contains(layersInGraph, "conv2 layer"));
874 CHECK(Contains(layersInGraph, "pooling3 layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100875
876 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +0000877 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100878 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +0100879 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100880
881 // Optimize the subgraph
882 OptimizationViews optimizationViews;
883
884 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +0100885 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100886
887 // ========================================================================
888 // The expected results are:
889 // - Exactly two substitution, corresponding to the supported layers
890 // - Exactly two failed subgraphs, corresponding to the unsupported layers
891 // - No untouched subgraphs
892 // ========================================================================
893
894 // -----------------------
895 // Check the substitutions
896 // -----------------------
897
Rob Hughes30db8ad2019-11-08 15:50:10 +0000898 OptimizationViews::Substitutions substitutions = optimizationViews.GetSubstitutions();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100899 CHECK(substitutions.size() == 2);
Rob Hughes30db8ad2019-11-08 15:50:10 +0000900 // Sort into a consistent order
901 std::sort(substitutions.begin(), substitutions.end(), [](auto s1, auto s2) {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000902 return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(),
903 s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0;
Rob Hughes30db8ad2019-11-08 15:50:10 +0000904 });
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100905
906 std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
907 { 1, 1, 1 } };
908 std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
909 { 1, 1, 1 } };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000910 std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100911 {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000912 ConvertSlotsToISlots<InputSlot, IInputSlot>(
913 ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
914 ConvertSlotsToISlots<InputSlot, IInputSlot>(
915 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100916 };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000917
918 std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100919 {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000920 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
921 ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots())),
922 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
923 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetOutputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100924 };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000925 std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100926 {
927 { layersInGraph.at("conv1 layer") },
928 { layersInGraph.at("conv2 layer") }
929 };
930
931 for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++)
932 {
933 CheckSubstitution(substitutions.at(substitutionIndex),
934 expectedSubstitutableSubgraphSizes.at(substitutionIndex),
935 expectedReplacementSubgraphSizes.at(substitutionIndex),
936 expectedSubstitutableInputSlots.at(substitutionIndex),
937 expectedSubstitutableOutputSlots.at(substitutionIndex),
938 expectedSubstitutableLayers.at(substitutionIndex));
939 }
940
941 // --------------------------
942 // Check the failed subgraphs
943 // --------------------------
944
Rob Hughes30db8ad2019-11-08 15:50:10 +0000945 OptimizationViews::Subgraphs failedSubgraphs = optimizationViews.GetFailedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +0100946 CHECK(failedSubgraphs.size() == 2);
Rob Hughes30db8ad2019-11-08 15:50:10 +0000947 // Sort into a consistent order
948 std::sort(failedSubgraphs.begin(), failedSubgraphs.end(), [](auto s1, auto s2) {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000949 return strcmp(s1.GetIConnectableLayers().front()->GetName(),
950 s2.GetIConnectableLayers().front()->GetName()) < 0;
Rob Hughes30db8ad2019-11-08 15:50:10 +0000951 });
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100952
953 std::vector<ExpectedSubgraphSize> expectedFailedSubgraphSizes{ { 1, 1, 2 },
954 { 1, 1, 1 } };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000955 std::vector<SubgraphView::IInputSlots> expectedFailedInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100956 {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000957 ConvertSlotsToISlots<InputSlot, IInputSlot>(
958 ConvertReferenceTypeToPointerType(layersInGraph.at("pooling1 layer")->GetInputSlots())),
959 ConvertSlotsToISlots<InputSlot, IInputSlot>(
960 ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetInputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100961 };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000962 std::vector<SubgraphView::IOutputSlots> expectedFailedOutputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100963 {
Francis Murtagh56ccf682021-12-13 18:48:12 +0000964 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
965 ConvertReferenceTypeToPointerType(layersInGraph.at("pooling2 layer")->GetOutputSlots())),
966 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
967 ConvertReferenceTypeToPointerType(layersInGraph.at("pooling3 layer")->GetOutputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100968 };
Francis Murtagh56ccf682021-12-13 18:48:12 +0000969 std::vector<SubgraphView::IConnectableLayers> expectedFailedLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100970 {
971 { layersInGraph.at("pooling1 layer"),
972 layersInGraph.at("pooling2 layer") },
973 { layersInGraph.at("pooling3 layer") }
974 };
975
976 for (size_t failedIndex = 0; failedIndex < failedSubgraphs.size(); failedIndex++)
977 {
978 CheckFailedSubgraph(failedSubgraphs.at(failedIndex),
979 expectedFailedSubgraphSizes.at(failedIndex),
980 expectedFailedInputSlots.at(failedIndex),
981 expectedFailedOutputSlots.at(failedIndex),
982 expectedFailedLayers.at(failedIndex));
983 }
984
985 // -----------------------------
986 // Check the untouched subgraphs
987 // -----------------------------
988
Sadik Armagan1625efc2021-06-10 18:24:34 +0100989 CHECK(optimizationViews.GetUntouchedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +0100990}
991
992// The input subgraph contains only unoptimizable layers ("unoptimizable" is added to the layer's name)
993void FullyUnoptimizableSubgraphTestImpl1()
994{
995 Graph graph;
996 LayerNameToLayerMap layersInGraph;
997
998 // Create a fully optimizable subgraph
999 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildFullyUnoptimizableSubgraph1(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +01001000 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001001
Francis Murtagh56ccf682021-12-13 18:48:12 +00001002 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
1003 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
1004 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001005
Sadik Armagan1625efc2021-06-10 18:24:34 +01001006 CHECK(subgraphInputSlots.size() == 1);
1007 CHECK(subgraphOutputSlots.size() == 1);
1008 CHECK(subgraphLayers.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001009
Sadik Armagan1625efc2021-06-10 18:24:34 +01001010 CHECK(Contains(layersInGraph, "conv layer unoptimizable"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001011
1012 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +00001013 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001014 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +01001015 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001016
1017 // Optimize the subgraph
1018 OptimizationViews optimizationViews;
1019
1020 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +01001021 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001022
1023 // ============================================================================
1024 // The expected results are:
1025 // - No substitutions
1026 // - No failed subgraphs
1027 // - Exactly one untouched subgraph, corresponding to the whole input subgraph
1028 // ============================================================================
1029
1030 // -----------------------
1031 // Check the substitutions
1032 // -----------------------
1033
Sadik Armagan1625efc2021-06-10 18:24:34 +01001034 CHECK(optimizationViews.GetSubstitutions().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001035
1036 // --------------------------
1037 // Check the failed subgraphs
1038 // --------------------------
1039
Sadik Armagan1625efc2021-06-10 18:24:34 +01001040 CHECK(optimizationViews.GetFailedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001041
1042 // -----------------------------
1043 // Check the untouched subgraphs
1044 // -----------------------------
1045
1046 const OptimizationViews::Subgraphs& untouchedSubgraphs = optimizationViews.GetUntouchedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +01001047 CHECK(untouchedSubgraphs.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001048
1049 CheckUntouchedSubgraph(untouchedSubgraphs.at(0),
1050 { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
1051 subgraphInputSlots,
1052 subgraphOutputSlots,
1053 subgraphLayers);
1054}
1055
1056// The input subgraph contains some unoptimizable layers ("unoptimizable" is added to the layer's name)
1057void PartiallyOptimizableSubgraphTestImpl1()
1058{
1059 Graph graph;
1060 LayerNameToLayerMap layersInGraph;
1061
1062 // Create a fully optimizable subgraph
1063 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallyOptimizableSubgraph1(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +01001064 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001065
Francis Murtagh56ccf682021-12-13 18:48:12 +00001066 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
1067 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
1068 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001069
Sadik Armagan1625efc2021-06-10 18:24:34 +01001070 CHECK(subgraphInputSlots.size() == 1);
1071 CHECK(subgraphOutputSlots.size() == 1);
1072 CHECK(subgraphLayers.size() == 5);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001073
Sadik Armagan1625efc2021-06-10 18:24:34 +01001074 CHECK(Contains(layersInGraph, "conv1 layer"));
1075 CHECK(Contains(layersInGraph, "conv2 layer unoptimizable"));
1076 CHECK(Contains(layersInGraph, "conv3 layer"));
1077 CHECK(Contains(layersInGraph, "conv4 layer unoptimizable"));
1078 CHECK(Contains(layersInGraph, "conv5 layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001079
1080 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +00001081 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001082 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +01001083 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001084
1085 // Optimize the subgraph
1086 OptimizationViews optimizationViews;
1087
1088 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +01001089 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001090
1091 // ===============================================================================
1092 // The expected results are:
1093 // - Exactly three substitutions, corresponding to the optimizable layers
1094 // - No failed subgraphs
1095 // - Exactly two untouched subgraphs, corresponding to the non-optimizable layers
1096 // ===============================================================================
1097
1098 // -----------------------
1099 // Check the substitutions
1100 // -----------------------
1101
Rob Hughes30db8ad2019-11-08 15:50:10 +00001102 OptimizationViews::Substitutions substitutions = optimizationViews.GetSubstitutions();
Sadik Armagan1625efc2021-06-10 18:24:34 +01001103 CHECK(substitutions.size() == 3);
Rob Hughes30db8ad2019-11-08 15:50:10 +00001104 // Sort into a consistent order
1105 std::sort(substitutions.begin(), substitutions.end(),
Francis Murtagh56ccf682021-12-13 18:48:12 +00001106 [](auto s1, auto s2)
1107 { return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(),
1108 s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0; });
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001109
1110 std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
1111 { 1, 1, 1 },
1112 { 1, 1, 1 } };
1113 std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
1114 { 1, 1, 1 },
1115 { 1, 1, 1 } };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001116 std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001117 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001118 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1119 ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
1120 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1121 ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots())),
1122 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1123 ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001124 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001125 std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001126 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001127 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1128 ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetOutputSlots())),
1129 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1130 ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetOutputSlots())),
1131 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1132 ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetOutputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001133 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001134 std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001135 {
1136 { layersInGraph.at("conv1 layer") },
1137 { layersInGraph.at("conv3 layer") },
1138 { layersInGraph.at("conv5 layer") }
1139 };
1140
1141 for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++)
1142 {
1143 CheckSubstitution(substitutions.at(substitutionIndex),
1144 expectedSubstitutableSubgraphSizes.at(substitutionIndex),
1145 expectedReplacementSubgraphSizes.at(substitutionIndex),
1146 expectedSubstitutableInputSlots.at(substitutionIndex),
1147 expectedSubstitutableOutputSlots.at(substitutionIndex),
1148 expectedSubstitutableLayers.at(substitutionIndex));
1149 }
1150
1151 // --------------------------
1152 // Check the failed subgraphs
1153 // --------------------------
1154
Sadik Armagan1625efc2021-06-10 18:24:34 +01001155 CHECK(optimizationViews.GetFailedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001156
1157 // -----------------------------
1158 // Check the untouched subgraphs
1159 // -----------------------------
1160
Rob Hughes30db8ad2019-11-08 15:50:10 +00001161 OptimizationViews::Subgraphs untouchedSubgraphs = optimizationViews.GetUntouchedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +01001162 CHECK(untouchedSubgraphs.size() == 2);
Rob Hughes30db8ad2019-11-08 15:50:10 +00001163 // Sort into a consistent order
1164 std::sort(untouchedSubgraphs.begin(), untouchedSubgraphs.end(), [](auto s1, auto s2) {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001165 return strcmp(s1.GetIConnectableLayers().front()->GetName(),
1166 s2.GetIConnectableLayers().front()->GetName()) < 0;
Rob Hughes30db8ad2019-11-08 15:50:10 +00001167 });
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001168
1169 std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 },
1170 { 1, 1, 1 } };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001171 std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001172 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001173 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1174 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())),
1175 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1176 ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetInputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001177 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001178 std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001179 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001180 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1181 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())),
1182 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1183 ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001184 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001185 std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001186 {
1187 { layersInGraph.at("conv2 layer unoptimizable") },
1188 { layersInGraph.at("conv4 layer unoptimizable") }
1189 };
1190
1191 for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++)
1192 {
1193 CheckUntouchedSubgraph(untouchedSubgraphs.at(untouchedIndex),
1194 expectedUntouchedSubgraphSizes.at(untouchedIndex),
1195 expectedUntouchedInputSlots.at(untouchedIndex),
1196 expectedUntouchedOutputSlots.at(untouchedIndex),
1197 expectedUntouchedLayers.at(untouchedIndex));
1198 }
1199}
1200
1201// The input subgraph contains some unoptimizable layers ("unoptimizable" is added to the layer's name),
1202// this is meant to test input slots coming from different layers
1203void PartiallyOptimizableSubgraphTestImpl2()
1204{
1205 Graph graph;
1206 LayerNameToLayerMap layersInGraph;
1207
Rob Hughes30db8ad2019-11-08 15:50:10 +00001208 // Create a partially optimizable subgraph
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001209 SubgraphViewSelector::SubgraphViewPtr subgraphPtr = BuildPartiallyOptimizableSubgraph2(graph, layersInGraph);
Sadik Armagan1625efc2021-06-10 18:24:34 +01001210 CHECK((subgraphPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001211
Francis Murtagh56ccf682021-12-13 18:48:12 +00001212 const SubgraphView::IInputSlots& subgraphInputSlots = subgraphPtr->GetIInputSlots();
1213 const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
1214 const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001215
Sadik Armagan1625efc2021-06-10 18:24:34 +01001216 CHECK(subgraphInputSlots.size() == 2);
1217 CHECK(subgraphOutputSlots.size() == 1);
1218 CHECK(subgraphLayers.size() == 4);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001219
Sadik Armagan1625efc2021-06-10 18:24:34 +01001220 CHECK(Contains(layersInGraph, "conv1 layer"));
1221 CHECK(Contains(layersInGraph, "conv2 layer unoptimizable"));
1222 CHECK(Contains(layersInGraph, "conv3 layer"));
1223 CHECK(Contains(layersInGraph, "add layer"));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001224
1225 // Create a mock backend object
David Monahanc1536d62020-02-12 15:52:35 +00001226 MockBackendInitialiser initialiser; // Register the Mock Backend
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001227 auto backendObjPtr = CreateBackendObject(MockBackendId());
Sadik Armagan1625efc2021-06-10 18:24:34 +01001228 CHECK((backendObjPtr != nullptr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001229
1230 // Optimize the subgraph
1231 OptimizationViews optimizationViews;
1232
1233 // Check that the optimization is carried out correctly
Sadik Armagan1625efc2021-06-10 18:24:34 +01001234 CHECK_NOTHROW(optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraphPtr));
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001235
1236 // ==============================================================================
1237 // The expected results are:
1238 // - Exactly one substitution, corresponding to the optimizable layers
1239 // - No failed subgraphs
1240 // - Exactly two untouched subgraphs, corresponding to the non-optimizable layer
1241 // ==============================================================================
1242
1243 // -----------------------
1244 // Check the substitutions
1245 // -----------------------
1246
1247 const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
Sadik Armagan1625efc2021-06-10 18:24:34 +01001248 CHECK(substitutions.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001249
Rob Hughes30db8ad2019-11-08 15:50:10 +00001250 ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 3 };
1251 ExpectedSubgraphSize expectedReplacementSubgraphSizes{ 2, 1, 1 };
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001252
Francis Murtagh56ccf682021-12-13 18:48:12 +00001253 SubgraphView::IInputSlots expectedSubstitutableInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001254 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001255 ConvertSlotsToISlots<InputSlot, IInputSlot>({
1256 ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots()[0])})[0],
1257 ConvertSlotsToISlots<InputSlot, IInputSlot>({
1258 ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots()[0])})[0]
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001259 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001260
1261 SubgraphView::IOutputSlots expectedSubstitutableOutputSlots
1262 {
1263 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1264 ConvertReferenceTypeToPointerType(layersInGraph.at("add layer")->GetOutputSlots()))
1265 };
1266
1267 SubgraphView::IConnectableLayers expectedSubstitutableLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001268 {
Rob Hughes30db8ad2019-11-08 15:50:10 +00001269 layersInGraph.at("conv1 layer"),
1270 layersInGraph.at("conv3 layer"),
1271 layersInGraph.at("add layer")
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001272 };
1273
Rob Hughes30db8ad2019-11-08 15:50:10 +00001274 CheckSubstitution(substitutions[0],
1275 expectedSubstitutableSubgraphSizes,
1276 expectedReplacementSubgraphSizes,
1277 expectedSubstitutableInputSlots,
1278 expectedSubstitutableOutputSlots,
1279 expectedSubstitutableLayers);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001280
1281 // --------------------------
1282 // Check the failed subgraphs
1283 // --------------------------
1284
Sadik Armagan1625efc2021-06-10 18:24:34 +01001285 CHECK(optimizationViews.GetFailedSubgraphs().empty());
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001286
1287 // -----------------------------
1288 // Check the untouched subgraphs
1289 // -----------------------------
1290
1291 const OptimizationViews::Subgraphs& untouchedSubgraphs = optimizationViews.GetUntouchedSubgraphs();
Sadik Armagan1625efc2021-06-10 18:24:34 +01001292 CHECK(untouchedSubgraphs.size() == 1);
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001293
1294 std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 } };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001295 std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001296 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001297 ConvertSlotsToISlots<InputSlot, IInputSlot>(
1298 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001299 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001300 std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001301 {
Francis Murtagh56ccf682021-12-13 18:48:12 +00001302 ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
1303 ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots()))
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001304 };
Francis Murtagh56ccf682021-12-13 18:48:12 +00001305 std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001306 {
1307 { layersInGraph.at("conv2 layer unoptimizable") }
1308 };
1309
1310 for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++)
1311 {
1312 CheckUntouchedSubgraph(untouchedSubgraphs.at(untouchedIndex),
1313 expectedUntouchedSubgraphSizes.at(untouchedIndex),
1314 expectedUntouchedInputSlots.at(untouchedIndex),
1315 expectedUntouchedOutputSlots.at(untouchedIndex),
1316 expectedUntouchedLayers.at(untouchedIndex));
1317 }
1318}
1319
1320} // Anonymous namespace
1321
Sadik Armagan1625efc2021-06-10 18:24:34 +01001322TEST_SUITE("OptimizeSubGraph")
1323{
1324TEST_CASE("FullyUnsupportedSubgraph1") { FullyUnsupporteSubgraphTestImpl1(); }
1325TEST_CASE("FullyUnsupportedSubgraph2") { FullyUnsupporteSubgraphTestImpl2(); }
1326TEST_CASE("FullyOptimizableSubgraph1") { FullyOptimizableSubgraphTestImpl1(); }
1327TEST_CASE("FullyOptimizableSubgraph2") { FullyOptimizableSubgraphTestImpl2(); }
1328TEST_CASE("PartiallySupportedSubgraph") { PartiallySupportedSubgraphTestImpl(); }
1329TEST_CASE("FullyUnoptimizableSubgraph") { FullyUnoptimizableSubgraphTestImpl1(); }
1330TEST_CASE("PartiallyOptimizableSubgraph1") { PartiallyOptimizableSubgraphTestImpl1(); }
1331TEST_CASE("PartiallyOptimizableSubgraph2") { PartiallyOptimizableSubgraphTestImpl2(); }
Matteo Martincighf02e6cd2019-05-17 12:15:30 +01001332
Sadik Armagan1625efc2021-06-10 18:24:34 +01001333}