ArmNN
 24.02
ArmComputeSubgraphUtils.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
10 
13 
14 namespace armnn
15 {
16 
17 namespace
18 {
19 
20 //
21 // this helper only works if all layers where the inputs connect to are not selected
22 //
23 
24 bool checkDataTypeInputandOutput(const Layer& layer)
25 {
26  auto inputInfo = layer.GetInputSlot(0).GetTensorInfo();
27  auto outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
28  bool sameDataType = (inputInfo.GetDataType() == outputInfo.GetDataType());
29 
30  // Check is same quantization info (same scale and offset)
31  if (sameDataType)
32  {
33  if (IsQuantizedType(inputInfo.GetDataType()))
34  {
35  bool sameScale = (inputInfo.GetQuantizationScale() == outputInfo.GetQuantizationScale());
36  bool sameOffset = (inputInfo.GetQuantizationOffset() == outputInfo.GetQuantizationOffset());
37 
38  return (sameScale && sameOffset);
39  }
40  else
41  {
42  return true;
43  }
44  }
45  else
46  {
47  return false;
48  }
49 }
50 
51 } // namespace
52 
53 template<typename LayerType>
55  LayerType* baseLayer,
56  LayerType* replacementLayer,
57  ActivationLayer* activationLayer,
58  ActivationDescriptor& activationDesc)
59 {
60  replacementLayer->SetAdditionalInfoForObject(
61  std::make_shared<ActivationDescriptor>(activationDesc));
62 
63  SubgraphView substitutionSubgraph({baseLayer, activationLayer},
64  CreateIInputsFrom({baseLayer}),
65  CreateIOutputsFrom({activationLayer}));
66  SubgraphView replacementSubgraph(replacementLayer);
67 
68  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
69 
70  return replacementLayer;
71 }
72 
73 template<typename LayerType>
75  LayerType* baseLayer,
76  ActivationLayer* activationLayer,
77  ActivationDescriptor& activationDesc,
78  std::string name)
79 {
81  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
83  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
84 
85  FuseLayer(optimizationViews,
86  baseLayer,
87  replacementLayer,
88  activationLayer,
89  activationDesc);
90 
91  return replacementLayer;
92 }
93 
94 template<typename LayerType>
96  LayerType* baseLayer,
97  ActivationLayer* activationLayer,
98  ActivationDescriptor& activationDesc,
99  std::string name)
100 {
102  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
104  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
105 
106  FuseLayer(optimizationViews,
107  baseLayer,
108  replacementLayer,
109  activationLayer,
110  activationDesc);
111 
112  return replacementLayer;
113 }
114 
115 template<typename LayerType>
117  LayerType* baseLayer,
118  ActivationLayer* activationLayer,
119  ActivationDescriptor& activationDesc,
120  std::string name)
121 {
123  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
125  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
126 
127  FuseLayer(optimizationViews,
128  baseLayer,
129  replacementLayer,
130  activationLayer,
131  activationDesc);
132 
133  return replacementLayer;
134 }
135 
136 template<typename LayerType>
138  LayerType* baseLayer,
139  ActivationLayer* activationLayer,
140  ActivationDescriptor& activationDesc,
141  std::string name)
142 {
144  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
146  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
147 
148  FuseLayer(optimizationViews,
149  baseLayer,
150  replacementLayer,
151  activationLayer,
152  activationDesc);
153 
154  return replacementLayer;
155 }
156 
157 template<typename LayerType>
159  LayerType* baseLayer,
160  ActivationLayer* activationLayer,
161  ActivationDescriptor& activationDesc,
162  BinaryOperation operation,
163  std::string name)
164 {
165  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddElementwiseBinaryLayer(operation,
166  name.c_str());
167  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
168 
169  FuseLayer(optimizationViews,
170  baseLayer,
171  replacementLayer,
172  activationLayer,
173  activationDesc);
174 
175  return replacementLayer;
176 }
177 
178 template<typename LayerType>
180  LayerType* baseLayer,
181  ActivationLayer* activationLayer,
182  ActivationDescriptor& activationDesc,
183  std::string name)
184 {
185  IConnectableLayer* replacement =
186  optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
187  ConstTensor(),
188  ConstTensor(),
189  ConstTensor(),
190  ConstTensor(),
191  name.c_str());
192  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
193 
194  FuseLayer(optimizationViews,
195  baseLayer,
196  replacementLayer,
197  activationLayer,
198  activationDesc);
199 
200  SubgraphView substitutionSubgraph({baseLayer, activationLayer},
201  CreateIInputsFrom({baseLayer}),
202  CreateIOutputsFrom({activationLayer}));
203  SubgraphView replacementSubgraph(replacementLayer);
204 
205  return replacementLayer;
206 }
207 
208 template<typename LayerType>
210  LayerType* baseLayer,
211  ActivationLayer* activationLayer,
212  ActivationDescriptor& activationDesc,
213  std::string name)
214 {
215  IConnectableLayer* replacement = optimizationViews.GetINetwork()
216  ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
217 
218  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
219 
220 
221  FuseLayer(optimizationViews,
222  baseLayer,
223  replacementLayer,
224  activationLayer,
225  activationDesc);
226 
227  return replacementLayer;
228 }
229 
230 template<typename LayerType>
232  LayerType* baseLayer,
233  ActivationLayer* activationLayer,
234  ActivationDescriptor& activationDesc,
235  std::string name)
236 {
237  IConnectableLayer* replacement =
238  optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
239 
240  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
241 
242 
243  FuseLayer(optimizationViews,
244  baseLayer,
245  replacementLayer,
246  activationLayer,
247  activationDesc);
248 
249  return replacementLayer;
250 }
251 
252 template<typename LayerType>
254  LayerType* baseLayer,
255  ActivationLayer* activationLayer,
256  ActivationDescriptor& activationDesc,
257  std::string name)
258 {
259  IConnectableLayer* replacement =
260  optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
261  name.c_str());
262  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
263 
264  FuseLayer(optimizationViews,
265  baseLayer,
266  replacementLayer,
267  activationLayer,
268  activationDesc);
269 
270 
271  return replacementLayer;
272 }
273 
274 //
275 // If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
276 // as currently only one axis is supported.
277 //
278 template<typename LayerType>
279 std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
280  LayerType* baseLayer,
281  ReduceDescriptor& desc)
282 {
283  // Vector of new chained layers, used for substitution.
284  std::vector<IConnectableLayer*> layers;
285 
286  // Vector of axes so each layer is reshaped correctly.
287  std::vector<uint32_t> axes;
288  unsigned int recalulatedAxis = 0;
289 
290  for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
291  {
292  // Get TensorInfo from base layer and reduce shape using axis.
293  TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
294 
295  axes.emplace_back(desc.m_vAxis[i]);
296 
297  const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
298  axes,
299  desc.m_KeepDims);
300 
301  // Create a vector for the single axis to be assigned to the descriptor.
302  // Update axis if keepDims is set reduce layers correctly.
303  std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
304 
305  // Create a descriptor and assign single axis.
306  ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
307  newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
308 
309  // Add new layer to graph.
310  std::string layerName = "reduce_layer_" + std::to_string(i);
311 
312  Layer* replacementLayer = PolymorphicDowncast<Layer*>(
313  optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
314  layerName.c_str()));
315 
316  // Connect previous layer with new layer.
317  // The first and last layer will be connected when the subgraph is replaced.
318  if (!layers.empty())
319  {
320  layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
321  }
322 
323  // Set updated tensorInfo for new layer.
324  replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
325 
326  if (!desc.m_KeepDims)
327  {
328  recalulatedAxis++;
329  }
330 
331  layers.emplace_back(replacementLayer);
332  }
333 
334  // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
335  ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
336  PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
337 
338  return layers;
339 }
340 
341 //
342 // Substitute baseLayer with new subgraph
343 //
344 template<typename LayerType>
345 void ReplaceLayers(OptimizationViews& optimizationViews,
346  LayerType* baseLayer,
347  std::vector<IConnectableLayer*>& layers)
348 {
349  std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
350 
351  SubgraphView substitutionSubgraph(baseLayer);
352  SubgraphView replacementSubgraph(std::move(replacementLayers),
353  CreateIInputsFrom({replacementLayers.front()}),
354  CreateIOutputsFrom({replacementLayers.back()}));
355 
356  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
357 }
358 
359 //
360 // Substitute a multi-layer subgraph with one new layer
361 //
362 template<typename LayerType>
363 void ReplaceMultipleLayers(OptimizationViews& optimizationViews,
364  std::vector<IConnectableLayer*>& originalLayers,
365  LayerType* baseLayer,
366  const std::vector<SlotList> inputLayersSlotLists,
367  const std::vector<SlotList> outputLayersSlotLists)
368 {
369  std::list<IConnectableLayer*> originalLayerList(originalLayers.begin(), originalLayers.end());
370 
371  SubgraphView substitutionSubgraph(
372  std::move(originalLayerList),
373  CreateIInputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, inputLayersSlotLists),
374  CreateIOutputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, outputLayersSlotLists));
375  SubgraphView replacementSubgraph(baseLayer);
376 
377  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
378 }
379 
380 } // namespace armnn
ARMNN_ASSERT
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
armnn::ChainReduceLayers
std::vector< IConnectableLayer * > ChainReduceLayers(OptimizationViews &optimizationViews, LayerType *baseLayer, ReduceDescriptor &desc)
Definition: ArmComputeSubgraphUtils.hpp:279
armnn::ActivationDescriptor
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:36
armnn::INetwork::AddReduceLayer
IConnectableLayer * AddReduceLayer(const ReduceDescriptor &reduceDescriptor, const char *name=nullptr)
Adds a reduce layer to the network.
Definition: Network.cpp:444
armnn::FuseDepthwiseConvolution2dLayer
LayerType * FuseDepthwiseConvolution2dLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:231
armnn::INetwork::AddAdditionLayer
IConnectableLayer * AddAdditionLayer(const char *name=nullptr)
Adds an addition layer to the network.
Definition: Network.cpp:409
armnn::OutputSlot::SetTensorInfo
void SetTensorInfo(const TensorInfo &tensorInfo) override
Definition: Layer.cpp:87
armnn::TensorInfo
Definition: Tensor.hpp:152
armnn::INetwork::AddFullyConnectedLayer
IConnectableLayer * AddFullyConnectedLayer(const FullyConnectedDescriptor &fullyConnectedDescriptor, const char *name=nullptr)
Adds a fully connected layer to the network.
Definition: Network.cpp:332
armnn::FuseConvolution2dLayer
LayerType * FuseConvolution2dLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:209
armnn::Layer::GetOutputSlot
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:339
ARMNN_NO_DEPRECATE_WARN_BEGIN
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
armnn::ReplaceLayers
void ReplaceLayers(OptimizationViews &optimizationViews, LayerType *baseLayer, std::vector< IConnectableLayer * > &layers)
Definition: ArmComputeSubgraphUtils.hpp:345
armnn::Layer::GetInputSlot
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:337
OptimizationViews.hpp
armnn::FuseAdditionLayer
LayerType * FuseAdditionLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:74
armnn::Layer
Definition: Layer.hpp:230
Assert.hpp
armnn::FuseMultiplicationLayer
LayerType * FuseMultiplicationLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:137
armnn::INetwork::AddBatchNormalizationLayer
IConnectableLayer * AddBatchNormalizationLayer(const BatchNormalizationDescriptor &desc, const ConstTensor &mean, const ConstTensor &variance, const ConstTensor &beta, const ConstTensor &gamma, const char *name=nullptr)
Adds a batch normalization layer to the network.
Definition: Network.cpp:423
armnn::FuseBatchNormalizationLayer
LayerType * FuseBatchNormalizationLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:179
armnn::INetwork::AddConvolution2dLayer
IConnectableLayer * AddConvolution2dLayer(const Convolution2dDescriptor &convolution2dDescriptor, const char *name=nullptr)
Adds a 2D convolution layer to the network.
Definition: Network.cpp:272
armnn::FuseDivisionLayer
LayerType * FuseDivisionLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:116
armnn::SubgraphView
The SubgraphView class represents a subgraph of a Graph.
Definition: SubgraphView.hpp:31
armnn::OptimizationViews
Definition: OptimizationViews.hpp:17
armnn::INetwork::AddDivisionLayer
IConnectableLayer * AddDivisionLayer(const char *name=nullptr)
Adds a division layer to the network.
Definition: Network.cpp:508
ArmComputeUtils.hpp
armnn::FuseFullyConnectedLayer
LayerType * FuseFullyConnectedLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:253
armnn::OptimizationViews::AddSubstitution
void AddSubstitution(SubstitutionPair &&substitution)
Definition: OptimizationViews.hpp:38
armnn::FuseElementwiseBinaryLayer
LayerType * FuseElementwiseBinaryLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, BinaryOperation operation, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:158
armnn::INetwork::AddElementwiseBinaryLayer
IConnectableLayer * AddElementwiseBinaryLayer(const ElementwiseBinaryDescriptor &elementwiseBinaryDescriptor, const char *name=nullptr)
Add an ElementwiseBinary layer to the network.
Definition: Network.cpp:314
armnn::ReduceDescriptor::m_KeepDims
bool m_KeepDims
if true then output shape has no change.
Definition: Descriptors.hpp:1554
armnn::INetwork::AddSubtractionLayer
IConnectableLayer * AddSubtractionLayer(const char *name=nullptr)
Adds a subtraction layer to the network.
Definition: Network.cpp:515
armnn::BinaryOperation
BinaryOperation
Definition: Types.hpp:138
armnn::ActivationLayer
This layer represents an activation operation with the specified activation function.
Definition: ActivationLayer.hpp:12
ARMNN_NO_DEPRECATE_WARN_END
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
armnn::INetwork::AddDepthwiseConvolution2dLayer
IConnectableLayer * AddDepthwiseConvolution2dLayer(const DepthwiseConvolution2dDescriptor &convolution2dDescriptor, const char *name=nullptr)
Adds a 2D depthwise convolution layer to the network.
Definition: Network.cpp:292
armnn::ReduceDescriptor::m_vAxis
std::vector< uint32_t > m_vAxis
The indices of the dimensions to reduce.
Definition: Descriptors.hpp:1556
armnn::FuseSubtractionLayer
LayerType * FuseSubtractionLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:95
armnn::IsQuantizedType
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:311
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
armnn::OptimizationViews::GetINetwork
INetwork * GetINetwork()
Definition: OptimizationViews.hpp:69
armnn::INetwork::AddMultiplicationLayer
IConnectableLayer * AddMultiplicationLayer(const char *name=nullptr)
Adds a multiplication layer to the network.
Definition: Network.cpp:416
armnn::ConstTensor
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:329
armnn::ComputeReductionTensorShape
const TensorInfo ComputeReductionTensorShape(const armnn::TensorInfo &input, const std::vector< uint32_t > &vAxis, const bool keepDims)
Function to compute the output tensor shape based on the axes and if keepDims is set.
Definition: ArmComputeUtils.hpp:347
armnn::IConnectableLayer
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:80
armnn::FuseLayer
LayerType * FuseLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, LayerType *replacementLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc)
Definition: ArmComputeSubgraphUtils.hpp:54
armnn::ReduceDescriptor
A ReduceDescriptor for the REDUCE operators.
Definition: Descriptors.hpp:1538
SubgraphUtils.hpp
armnn::LayerType
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
Definition: Types.hpp:491
armnn::ReplaceMultipleLayers
void ReplaceMultipleLayers(OptimizationViews &optimizationViews, std::vector< IConnectableLayer * > &originalLayers, LayerType *baseLayer, const std::vector< SlotList > inputLayersSlotLists, const std::vector< SlotList > outputLayersSlotLists)
Definition: ArmComputeSubgraphUtils.hpp:363