ArmNN
 24.05
ArmComputeSubgraphUtils.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2020-2024 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
9 
12 
13 namespace armnn
14 {
15 
16 namespace
17 {
18 
19 //
20 // this helper only works if all layers where the inputs connect to are not selected
21 //
22 
23 bool checkDataTypeInputandOutput(const Layer& layer)
24 {
25  auto inputInfo = layer.GetInputSlot(0).GetTensorInfo();
26  auto outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
27  bool sameDataType = (inputInfo.GetDataType() == outputInfo.GetDataType());
28 
29  // Check is same quantization info (same scale and offset)
30  if (sameDataType)
31  {
32  if (IsQuantizedType(inputInfo.GetDataType()))
33  {
34  bool sameScale = (inputInfo.GetQuantizationScale() == outputInfo.GetQuantizationScale());
35  bool sameOffset = (inputInfo.GetQuantizationOffset() == outputInfo.GetQuantizationOffset());
36 
37  return (sameScale && sameOffset);
38  }
39  else
40  {
41  return true;
42  }
43  }
44  else
45  {
46  return false;
47  }
48 }
49 
50 } // namespace
51 
52 template<typename LayerType>
54  LayerType* baseLayer,
55  LayerType* replacementLayer,
56  ActivationLayer* activationLayer,
57  ActivationDescriptor& activationDesc)
58 {
59  replacementLayer->SetAdditionalInfoForObject(
60  std::make_shared<ActivationDescriptor>(activationDesc));
61 
62  SubgraphView substitutionSubgraph({baseLayer, activationLayer},
63  CreateIInputsFrom({baseLayer}),
64  CreateIOutputsFrom({activationLayer}));
65  SubgraphView replacementSubgraph(replacementLayer);
66 
67  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
68 
69  return replacementLayer;
70 }
71 
72 template<typename LayerType>
74  LayerType* baseLayer,
75  ActivationLayer* activationLayer,
76  ActivationDescriptor& activationDesc,
77  std::string name)
78 {
80  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
82  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
83 
84  FuseLayer(optimizationViews,
85  baseLayer,
86  replacementLayer,
87  activationLayer,
88  activationDesc);
89 
90  return replacementLayer;
91 }
92 
93 template<typename LayerType>
95  LayerType* baseLayer,
96  ActivationLayer* activationLayer,
97  ActivationDescriptor& activationDesc,
98  std::string name)
99 {
101  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
103  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
104 
105  FuseLayer(optimizationViews,
106  baseLayer,
107  replacementLayer,
108  activationLayer,
109  activationDesc);
110 
111  return replacementLayer;
112 }
113 
114 template<typename LayerType>
116  LayerType* baseLayer,
117  ActivationLayer* activationLayer,
118  ActivationDescriptor& activationDesc,
119  std::string name)
120 {
122  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
124  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
125 
126  FuseLayer(optimizationViews,
127  baseLayer,
128  replacementLayer,
129  activationLayer,
130  activationDesc);
131 
132  return replacementLayer;
133 }
134 
135 template<typename LayerType>
137  LayerType* baseLayer,
138  ActivationLayer* activationLayer,
139  ActivationDescriptor& activationDesc,
140  std::string name)
141 {
143  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
145  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
146 
147  FuseLayer(optimizationViews,
148  baseLayer,
149  replacementLayer,
150  activationLayer,
151  activationDesc);
152 
153  return replacementLayer;
154 }
155 
156 template<typename LayerType>
158  LayerType* baseLayer,
159  ActivationLayer* activationLayer,
160  ActivationDescriptor& activationDesc,
161  BinaryOperation operation,
162  std::string name)
163 {
164  IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddElementwiseBinaryLayer(operation,
165  name.c_str());
166  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
167 
168  FuseLayer(optimizationViews,
169  baseLayer,
170  replacementLayer,
171  activationLayer,
172  activationDesc);
173 
174  return replacementLayer;
175 }
176 
177 template<typename LayerType>
179  LayerType* baseLayer,
180  ActivationLayer* activationLayer,
181  ActivationDescriptor& activationDesc,
182  std::string name)
183 {
184  IConnectableLayer* replacement =
185  optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
186  ConstTensor(),
187  ConstTensor(),
188  ConstTensor(),
189  ConstTensor(),
190  name.c_str());
191  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
192 
193  FuseLayer(optimizationViews,
194  baseLayer,
195  replacementLayer,
196  activationLayer,
197  activationDesc);
198 
199  SubgraphView substitutionSubgraph({baseLayer, activationLayer},
200  CreateIInputsFrom({baseLayer}),
201  CreateIOutputsFrom({activationLayer}));
202  SubgraphView replacementSubgraph(replacementLayer);
203 
204  return replacementLayer;
205 }
206 
207 template<typename LayerType>
209  LayerType* baseLayer,
210  ActivationLayer* activationLayer,
211  ActivationDescriptor& activationDesc,
212  std::string name)
213 {
214  IConnectableLayer* replacement = optimizationViews.GetINetwork()
215  ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
216 
217  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
218 
219 
220  FuseLayer(optimizationViews,
221  baseLayer,
222  replacementLayer,
223  activationLayer,
224  activationDesc);
225 
226  return replacementLayer;
227 }
228 
229 template<typename LayerType>
231  LayerType* baseLayer,
232  ActivationLayer* activationLayer,
233  ActivationDescriptor& activationDesc,
234  std::string name)
235 {
236  IConnectableLayer* replacement =
237  optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
238 
239  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
240 
241 
242  FuseLayer(optimizationViews,
243  baseLayer,
244  replacementLayer,
245  activationLayer,
246  activationDesc);
247 
248  return replacementLayer;
249 }
250 
251 template<typename LayerType>
253  LayerType* baseLayer,
254  ActivationLayer* activationLayer,
255  ActivationDescriptor& activationDesc,
256  std::string name)
257 {
258  IConnectableLayer* replacement =
259  optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
260  name.c_str());
261  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
262 
263  FuseLayer(optimizationViews,
264  baseLayer,
265  replacementLayer,
266  activationLayer,
267  activationDesc);
268 
269 
270  return replacementLayer;
271 }
272 
273 //
274 // If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
275 // as currently only one axis is supported.
276 //
277 template<typename LayerType>
278 std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
279  LayerType* baseLayer,
280  ReduceDescriptor& desc)
281 {
282  // Vector of new chained layers, used for substitution.
283  std::vector<IConnectableLayer*> layers;
284 
285  // Vector of axes so each layer is reshaped correctly.
286  std::vector<uint32_t> axes;
287  unsigned int recalulatedAxis = 0;
288 
289  for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
290  {
291  // Get TensorInfo from base layer and reduce shape using axis.
292  TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
293 
294  axes.emplace_back(desc.m_vAxis[i]);
295 
296  const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
297  axes,
298  desc.m_KeepDims);
299 
300  // Create a vector for the single axis to be assigned to the descriptor.
301  // Update axis if keepDims is set reduce layers correctly.
302  std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
303 
304  // Create a descriptor and assign single axis.
305  ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
306  newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
307 
308  // Add new layer to graph.
309  std::string layerName = "reduce_layer_" + std::to_string(i);
310 
311  Layer* replacementLayer = PolymorphicDowncast<Layer*>(
312  optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
313  layerName.c_str()));
314 
315  // Connect previous layer with new layer.
316  // The first and last layer will be connected when the subgraph is replaced.
317  if (!layers.empty())
318  {
319  layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
320  }
321 
322  // Set updated tensorInfo for new layer.
323  replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
324 
325  if (!desc.m_KeepDims)
326  {
327  recalulatedAxis++;
328  }
329 
330  layers.emplace_back(replacementLayer);
331  }
332  return layers;
333 }
334 
335 //
336 // Substitute baseLayer with new subgraph
337 //
338 template<typename LayerType>
339 void ReplaceLayers(OptimizationViews& optimizationViews,
340  LayerType* baseLayer,
341  std::vector<IConnectableLayer*>& layers)
342 {
343  std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
344 
345  SubgraphView substitutionSubgraph(baseLayer);
346  SubgraphView replacementSubgraph(std::move(replacementLayers),
347  CreateIInputsFrom({replacementLayers.front()}),
348  CreateIOutputsFrom({replacementLayers.back()}));
349 
350  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
351 }
352 
353 //
354 // Substitute a multi-layer subgraph with one new layer
355 //
356 template<typename LayerType>
357 void ReplaceMultipleLayers(OptimizationViews& optimizationViews,
358  std::vector<IConnectableLayer*>& originalLayers,
359  LayerType* baseLayer,
360  const std::vector<SlotList> inputLayersSlotLists,
361  const std::vector<SlotList> outputLayersSlotLists)
362 {
363  std::list<IConnectableLayer*> originalLayerList(originalLayers.begin(), originalLayers.end());
364 
365  SubgraphView substitutionSubgraph(
366  std::move(originalLayerList),
367  CreateIInputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, inputLayersSlotLists),
368  CreateIOutputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, outputLayersSlotLists));
369  SubgraphView replacementSubgraph(baseLayer);
370 
371  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
372 }
373 
374 } // namespace armnn
armnn::ChainReduceLayers
std::vector< IConnectableLayer * > ChainReduceLayers(OptimizationViews &optimizationViews, LayerType *baseLayer, ReduceDescriptor &desc)
Definition: ArmComputeSubgraphUtils.hpp:278
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:230
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:95
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:208
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:339
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:73
armnn::Layer
Definition: Layer.hpp:230
armnn::FuseMultiplicationLayer
LayerType * FuseMultiplicationLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, ActivationLayer *activationLayer, ActivationDescriptor &activationDesc, std::string name)
Definition: ArmComputeSubgraphUtils.hpp:136
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:178
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:115
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:252
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:157
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:94
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:320
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:53
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:357