ArmNN
 23.08
SubgraphUtils.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <armnn/StrategyBase.hpp>
9 #include <armnn/Descriptors.hpp>
11 
12 namespace armnn
13 {
14 
15 namespace
16 {
17 
18 /// Checks if a Layer has a DataLayout that is either NCHW or NCDHW.
19 class CheckForNCHW : public StrategyBase<NoThrowStrategy>
20 {
21 public:
22  CheckForNCHW()
23  {}
24 
25  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
26  const armnn::BaseDescriptor& descriptor,
27  const std::vector<armnn::ConstTensor>& constants,
28  const char* name,
29  const armnn::LayerBindingId id = 0) override
30  {
31  armnn::IgnoreUnused(layer, constants, id, name);
32  switch (layer->GetType())
33  {
35  {
36  auto desc = static_cast<const armnn::BatchMatMulDescriptor&>(descriptor);
37  m_Result = desc.m_DataLayoutX == DataLayout::NCHW || desc.m_DataLayoutY == DataLayout::NCHW;
38  break;
39  }
41  {
42  CheckDescForNCHW(static_cast<const armnn::BatchNormalizationDescriptor&>(descriptor));
43  break;
44  }
46  {
47  CheckDescForNCHW(static_cast<const armnn::BatchToSpaceNdDescriptor&>(descriptor));
48  break;
49  }
51  {
52  CheckDescForNCHW(static_cast<const armnn::Convolution2dDescriptor&>(descriptor));
53  break;
54  }
56  {
57  CheckDescForNCHW(static_cast<const armnn::Convolution3dDescriptor&>(descriptor));
58  break;
59  }
61  {
62  CheckDescForNCHW(static_cast<const armnn::DepthwiseConvolution2dDescriptor&>(descriptor));
63  break;
64  }
66  {
67  CheckDescForNCHW(static_cast<const armnn::InstanceNormalizationDescriptor&>(descriptor));
68  break;
69  }
71  {
72  CheckDescForNCHW(static_cast<const armnn::L2NormalizationDescriptor&>(descriptor));
73  break;
74  }
76  {
77  CheckDescForNCHW(static_cast<const armnn::NormalizationDescriptor&>(descriptor));
78  break;
79  }
81  {
82  CheckDescForNCHW(static_cast<const armnn::Pooling2dDescriptor&>(descriptor));
83  break;
84  }
86  {
87  CheckDescForNCHW(static_cast<const armnn::Pooling3dDescriptor&>(descriptor));
88  break;
89  }
91  {
92  CheckDescForNCHW(static_cast<const armnn::SpaceToBatchNdDescriptor&>(descriptor));
93  break;
94  }
96  {
97  CheckDescForNCHW(static_cast<const armnn::SpaceToDepthDescriptor&>(descriptor));
98  break;
99  }
101  {
102  CheckDescForNCHW(static_cast<const armnn::StridedSliceDescriptor&>(descriptor));
103  break;
104  }
105  default:
106  {
107  m_Result = false;
108  }
109  }
110  }
111 
112  /// Returns true if the Layer had a DataLayout and it was NCHW or NCDHW.
113  /// Returns false if the Layer either doesn't have a DataLayout or if it
114  /// had a DataLayout that was neither NCHW nor NCDHW.
115  bool Result()
116  {
117  return m_Result;
118  }
119 
120 private:
121  template<typename Descriptor>
122  void CheckDescForNCHW(const Descriptor& descriptor)
123  {
124  m_Result = (descriptor.m_DataLayout == DataLayout::NCHW) || (descriptor.m_DataLayout == DataLayout::NCDHW);
125  }
126 
127  bool m_Result = false;
128 };
129 
130 //
131 // this helper only works if all layers where the inputs connect to are not selected
132 //
133 
134 SubgraphView::IInputSlots CreateIInputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
135 {
137  for (auto&& layer : layers)
138  {
139  for (unsigned int i = 0 ; i < layer->GetNumInputSlots(); ++i)
140  {
141  result.push_back(&(layer->GetInputSlot(i)));
142  }
143  }
144  return result;
145 }
146 
147 //
148 // this helper only works if all layers where the outputs connect to are not selected
149 //
150 
151 SubgraphView::IOutputSlots CreateIOutputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
152 {
154  for (auto &&layer: layers)
155  {
156  for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
157  {
158  result.push_back(&(layer->GetOutputSlot(i)));
159  }
160  }
161  return result;
162 }
163 
164 }
165 
166 inline bool IsNCHW(armnn::Layer& layer)
167 {
168  CheckForNCHW check;
169  layer.ExecuteStrategy(check);
170  return check.Result();
171 }
172 
173 inline void ReportUntouchedLayers(OptimizationViews& optimizationViews, std::map<LayerGuid, Layer*> untouched)
174 {
175  std::vector<Layer*> untouchedVector;
176  for (const auto& pair : untouched)
177  {
178  Layer* layer = pair.second;
179  SubgraphView subgraphView({layer},
180  CreateIInputsFrom({layer}),
181  CreateIOutputsFrom({layer}));
182  optimizationViews.AddUntouchedSubgraph(std::move(subgraphView));
183  }
184 }
185 
186 template<typename LayerType>
188  LayerType* baseLayer,
189  LayerType* replacementLayer,
190  PadLayer* padLayer)
191 {
192  SubgraphView substitutionSubgraph({padLayer, baseLayer},
193  CreateIInputsFrom({padLayer}),
194  CreateIOutputsFrom({baseLayer}));
195  SubgraphView replacementSubgraph(replacementLayer);
196 
197  optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
198 
199  return replacementLayer;
200 }
201 
202 /// Checks if the Layer is connected to any Layer that has an NCHW layout.
203 inline bool ConnectedToLayerWithNCHW(Layer* baseLayer)
204 {
205  Layer& parentLayer = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
206 
207  if (IsNCHW(parentLayer))
208  {
209  return true;
210  }
211  for (unsigned int i = 0; i < baseLayer->GetOutputSlot(0).GetNumConnections(); ++i)
212  {
213  Layer& nextLayer = baseLayer->GetOutputSlot(0).GetConnection(i)->GetOwningLayer();
214  if (IsNCHW(nextLayer))
215  {
216  return true;
217  }
218  }
219  return false;
220 }
221 
222 /// Checks the Layer's Connections to see if it's connected to a Layer with the provided layerType. If dimSize is
223 /// provided will also check if the connecting Tensor has more than that number of dimensions
224 inline bool ConnectedToLayerType(Layer* baseLayer, LayerType layerType, unsigned int dimSize = 0)
225 {
226  Layer& parentLayer = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
227  TensorInfo parentTensorInfo = baseLayer->GetInputSlot(0).GetTensorInfo();
228 
229  if (parentTensorInfo.GetNumDimensions() > dimSize && parentLayer.GetType() == layerType)
230  {
231  return true;
232  }
233  for (unsigned int i = 0; i < baseLayer->GetOutputSlot(0).GetNumConnections(); ++i)
234  {
235  Layer& nextLayer = baseLayer->GetOutputSlot(0).GetConnection(i)->GetOwningLayer();
236  TensorInfo nextTensorInfo = baseLayer->GetOutputSlot(0).GetConnection(i)->GetTensorInfo();
237 
238  if (nextTensorInfo.GetNumDimensions() > dimSize && nextLayer.GetType() == layerType)
239  {
240  return true;
241  }
242  }
243  return false;
244 }
245 
246 inline void RemoveReshapeLayer(ReshapeLayer* baseLayer,
247  std::map<LayerGuid, Layer*>& untouched,
248  OptimizationViews& optimizationViews)
249 {
250  if (baseLayer == nullptr)
251  {
252  return;
253  }
254  ReshapeDescriptor reshapeDescriptor = baseLayer->GetParameters();
255  Layer& parentLayer = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
256 
257  // Cannot currently remove the Reshape if it's connected to an Input, Constant or Splitter
258  if (parentLayer.GetType() == LayerType::Input || parentLayer.GetType() == LayerType::Constant)
259  {
260  return;
261  }
262 
263  // Cannot currently remove the Reshape if it's connected to an OutputSlot or Concat
264  for (unsigned int i = 0; i < baseLayer->GetOutputSlot(0).GetNumConnections(); ++i)
265  {
266  Layer& nextLayer = baseLayer->GetOutputSlot(0).GetConnection(i)->GetOwningLayer();
267 
268  if (nextLayer.GetType() == LayerType::Output)
269  {
270  return;
271  }
272  }
273  auto it = untouched.find(baseLayer->GetGuid());
274  if (it == untouched.end())
275  {
276  // Already removed from map
277  return;
278  }
279  untouched.erase(it);
280 
281  // Override the InputSlot TensorInfos for all the layers connected to the Reshape's OutputSlot
282  for (unsigned int i = 0; i < baseLayer->GetOutputSlot(0).GetNumConnections(); ++i)
283  {
284  Layer& nextLayer = baseLayer->GetOutputSlot(0).GetConnection(i)->GetOwningLayer();
285  auto inputIndex = baseLayer->GetOutputSlot(0).GetConnection(i)->GetSlotIndex();
286  TensorInfo reshapeInfo(baseLayer->GetOutputSlot(0).GetTensorInfo());
287  reshapeInfo.SetShape(reshapeDescriptor.m_TargetShape);
288  nextLayer.GetInputSlot(inputIndex).SetTensorInfo(reshapeInfo);
289  }
290  optimizationViews.AddDeletedSubgraph(baseLayer);
291 }
292 
293 template<typename LayerType>
295  Pooling2dLayer* baseLayer,
296  Pooling2dDescriptor& poolDescriptor,
297  PadLayer* padLayer)
298 {
299  IConnectableLayer* replacement =
300  optimizationViews.GetINetwork()->AddPooling2dLayer(poolDescriptor, "folded-pad-into-pool2d");
301  LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
302 
303  FoldPadLayer(optimizationViews,
304  baseLayer,
305  replacementLayer,
306  padLayer);
307 
308  return replacementLayer;
309 }
310 
311 } // namespace armnn
armnn::BatchNormalizationDescriptor
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
Definition: Descriptors.hpp:828
armnn::LayerType::SpaceToDepth
@ SpaceToDepth
armnn::OptimizationViews::AddUntouchedSubgraph
void AddUntouchedSubgraph(SubgraphView &&subgraph)
Definition: OptimizationViews.hpp:48
armnn::InputSlot::SetTensorInfo
void SetTensorInfo(const TensorInfo tensorInfo) override
Sets the TensorInfo for this InputSlot.
Definition: Layer.cpp:587
armnn::SubgraphView::IOutputSlots
std::vector< IOutputSlot * > IOutputSlots
Definition: SubgraphView.hpp:60
armnn::LayerType::BatchNormalization
@ BatchNormalization
armnn::DataLayout::NCDHW
@ NCDHW
armnn::IConnectableLayer::GetNumInputSlots
virtual unsigned int GetNumInputSlots() const =0
Returns the number of connectable input slots.
armnn::InputSlot::GetOwningLayer
Layer & GetOwningLayer() const
Definition: Layer.hpp:53
Descriptors.hpp
armnn::OutputSlot::GetTensorInfo
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:92
armnn::Pooling3dDescriptor
A Pooling3dDescriptor for the Pooling3dLayer.
Definition: Descriptors.hpp:431
armnn::InstanceNormalizationDescriptor
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
Definition: Descriptors.hpp:847
armnn::ConnectedToLayerType
bool ConnectedToLayerType(Layer *baseLayer, LayerType layerType, unsigned int dimSize=0)
Checks the Layer's Connections to see if it's connected to a Layer with the provided layerType.
Definition: SubgraphUtils.hpp:224
armnn::LayerType::InstanceNormalization
@ InstanceNormalization
armnn::TensorInfo
Definition: Tensor.hpp:152
armnn::L2NormalizationDescriptor
A L2NormalizationDescriptor for the L2NormalizationLayer.
Definition: Descriptors.hpp:809
armnn::NormalizationDescriptor
A NormalizationDescriptor for the NormalizationLayer.
Definition: Descriptors.hpp:769
armnn::TensorInfo::GetNumDimensions
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:195
armnn::LayerType::StridedSlice
@ StridedSlice
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::LayerType::Normalization
@ Normalization
armnn::FoldPadLayer
LayerType * FoldPadLayer(OptimizationViews &optimizationViews, LayerType *baseLayer, LayerType *replacementLayer, PadLayer *padLayer)
Definition: SubgraphUtils.hpp:187
armnn::IsNCHW
bool IsNCHW(armnn::Layer &layer)
Definition: SubgraphUtils.hpp:166
armnn::IConnectableLayer::GetNumOutputSlots
virtual unsigned int GetNumOutputSlots() const =0
Returns the number of connectable output slots.
armnn::Layer::GetInputSlot
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:337
armnn::LayerWithParameters::GetParameters
const Parameters & GetParameters() const override
If the layer has a descriptor return it.
Definition: LayerWithParameters.hpp:19
armnn::Layer
Definition: Layer.hpp:230
armnn::InputSlot::GetTensorInfo
const TensorInfo & GetTensorInfo() const override
Gets the TensorInfo for this InputSlot.
Definition: Layer.cpp:592
armnn::InputSlot::GetSlotIndex
unsigned int GetSlotIndex() const override
Definition: Layer.hpp:54
FoldPadIntoLayer2d.hpp
armnn::OutputSlot::GetOwningLayer
Layer & GetOwningLayer() const
Definition: Layer.hpp:132
armnn::ReshapeLayer
This layer represents a reshape operation.
Definition: ReshapeLayer.hpp:15
armnn::RemoveReshapeLayer
void RemoveReshapeLayer(ReshapeLayer *baseLayer, std::map< LayerGuid, Layer * > &untouched, OptimizationViews &optimizationViews)
Definition: SubgraphUtils.hpp:246
armnn::FoldPadIntoAveragePool2d
LayerType * FoldPadIntoAveragePool2d(OptimizationViews &optimizationViews, Pooling2dLayer *baseLayer, Pooling2dDescriptor &poolDescriptor, PadLayer *padLayer)
Definition: SubgraphUtils.hpp:294
armnn::ReshapeDescriptor
A ReshapeDescriptor for the ReshapeLayer.
Definition: Descriptors.hpp:1002
armnn::SubgraphView::IInputSlots
std::vector< IInputSlot * > IInputSlots
Definition: SubgraphView.hpp:58
armnn::LayerBindingId
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:303
armnn::Layer::GetGuid
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:343
armnn::BatchMatMulDescriptor
A BatchMatMulDescriptor for the BatchMatMul operator.
Definition: Descriptors.hpp:1563
armnn::IConnectableLayer::GetType
virtual LayerType GetType() const =0
Returns the armnn::LayerType of this layer.
armnn::SubgraphView
The SubgraphView class represents a subgraph of a Graph.
Definition: SubgraphView.hpp:31
armnn::OptimizationViews
Definition: OptimizationViews.hpp:17
armnn::SpaceToBatchNdDescriptor
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
Definition: Descriptors.hpp:1022
armnn::Convolution3dDescriptor
A Convolution3dDescriptor for the Convolution3dLayer.
Definition: Descriptors.hpp:588
armnn::ReshapeDescriptor::m_TargetShape
TensorShape m_TargetShape
Target shape value.
Definition: Descriptors.hpp:1018
armnn::Pooling2dLayer
This layer represents a pooling 2d operation.
Definition: Pooling2dLayer.hpp:13
armnn::BaseDescriptor
Base class for all descriptors.
Definition: Descriptors.hpp:22
armnn::OptimizationViews::AddSubstitution
void AddSubstitution(SubstitutionPair &&substitution)
Definition: OptimizationViews.hpp:38
armnn::LayerType::Pooling2d
@ Pooling2d
armnn::BatchToSpaceNdDescriptor
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
Definition: Descriptors.hpp:875
armnn::Convolution2dDescriptor
A Convolution2dDescriptor for the Convolution2dLayer.
Definition: Descriptors.hpp:534
armnn::LayerType::Pooling3d
@ Pooling3d
armnn::LayerType::BatchMatMul
@ BatchMatMul
armnn::LayerType::DepthwiseConvolution2d
@ DepthwiseConvolution2d
armnn::LayerType::BatchToSpaceNd
@ BatchToSpaceNd
armnn::Layer::GetType
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Definition: Layer.hpp:286
armnn::StridedSliceDescriptor
A StridedSliceDescriptor for the StridedSliceLayer.
Definition: Descriptors.hpp:1282
armnn::Layer::ExecuteStrategy
void ExecuteStrategy(IStrategy &strategy) const override
Apply a visitor to this layer.
Definition: Layer.cpp:549
armnn::INetwork::AddPooling2dLayer
IConnectableLayer * AddPooling2dLayer(const Pooling2dDescriptor &pooling2dDescriptor, const char *name=nullptr)
Adds a 2D pooling layer to the network.
Definition: Network.cpp:350
armnn::LayerType::SpaceToBatchNd
@ SpaceToBatchNd
armnn::LayerType::L2Normalization
@ L2Normalization
armnn::OptimizationViews::AddDeletedSubgraph
void AddDeletedSubgraph(SubgraphView &&subgraph)
Definition: OptimizationViews.hpp:53
armnn::IgnoreUnused
void IgnoreUnused(Ts &&...)
Definition: IgnoreUnused.hpp:14
armnn::InputSlot::GetConnectedOutputSlot
const OutputSlot * GetConnectedOutputSlot() const
Definition: Layer.hpp:56
armnn::TensorInfo::SetShape
void SetShape(const TensorShape &newShape)
Definition: Tensor.hpp:193
armnn::IConnectableLayer::GetOutputSlot
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
armnn::IConnectableLayer::GetInputSlot
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
armnn::OptimizationViews::GetINetwork
INetwork * GetINetwork()
Definition: OptimizationViews.hpp:69
armnn::IConnectableLayer
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:80
armnn::LayerType::Input
@ Input
armnn::ReportUntouchedLayers
void ReportUntouchedLayers(OptimizationViews &optimizationViews, std::map< LayerGuid, Layer * > untouched)
Definition: SubgraphUtils.hpp:173
armnn::ConnectedToLayerWithNCHW
bool ConnectedToLayerWithNCHW(Layer *baseLayer)
Checks if the Layer is connected to any Layer that has an NCHW layout.
Definition: SubgraphUtils.hpp:203
armnn::LayerType::Convolution2d
@ Convolution2d
armnn::Pooling2dDescriptor
A Pooling2dDescriptor for the Pooling2dLayer.
Definition: Descriptors.hpp:371
armnn::DepthwiseConvolution2dDescriptor
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
Definition: Descriptors.hpp:659
armnn::LayerType::Convolution3d
@ Convolution3d
StrategyBase.hpp
armnn::LayerType
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
Definition: Types.hpp:483
armnn::OutputSlot::GetConnection
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:75
armnn::PadLayer
This layer represents a pad operation.
Definition: PadLayer.hpp:14
armnn::SpaceToDepthDescriptor
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
Definition: Descriptors.hpp:1054
armnn::LayerType::Output
@ Output
armnn::LayerType::Constant
@ Constant
armnn::DataLayout::NCHW
@ NCHW