ArmNN
 24.02
armnn::optimizations::pad_fold Namespace Reference

Classes

class  FoldPadIntoConvolution2dImpl
 
class  FoldPadIntoDepthwiseConvolution2dImpl
 
class  FoldPadIntoPooling2dImpl
 

Functions

float GetZeroElement (const TensorInfo &tensorInfo)
 
float GetLowestElement (const TensorInfo &tensorInfo)
 
bool IsNeutralElement (const Convolution2dDescriptor &, const TensorInfo &tensorInfo, const float tensorValue)
 
bool IsNeutralElement (const DepthwiseConvolution2dDescriptor &, const TensorInfo &tensorInfo, const float tensorValue)
 
bool IsNeutralElement (const Pooling2dDescriptor &descriptor, const TensorInfo &tensorInfo, const float tensorValue)
 
bool IsPooling2dPadded (const Pooling2dDescriptor &poolDescriptor)
 
template<typename Descriptor >
bool TryFoldPadIntoLayer2d (const PadDescriptor &padDescriptor, Descriptor &layerDescriptor, const TensorInfo &tensorInfo)
 
bool TryFoldPadIntoLayer2d (const PadDescriptor &padDescriptor, Pooling2dDescriptor &poolDescriptor, const TensorInfo &tensorInfo, bool isBackendOptimization=false)
 
template<typename Layer2dT >
Layer2dT * FoldPadIntoLayer2dImpl (Graph &graph, InputSlot &connection)
 

Function Documentation

◆ FoldPadIntoLayer2dImpl()

Layer2dT* armnn::optimizations::pad_fold::FoldPadIntoLayer2dImpl ( Graph graph,
InputSlot connection 
)

Definition at line 144 of file FoldPadIntoLayer2d.hpp.

145 {
146  PadLayer& padLayer = *PolymorphicDowncast<PadLayer*>(&connection.GetConnectedOutputSlot()->GetOwningLayer());
147  Layer2dT& layer2d = *PolymorphicDowncast<Layer2dT*>(&connection.GetOwningLayer());
148 
149  const PadDescriptor& padDescriptor = padLayer.GetParameters();
150  auto newLayer2dDescriptor = layer2d.GetParameters();
151 
152  if (!TryFoldPadIntoLayer2d(padDescriptor, newLayer2dDescriptor, padLayer.GetOutputSlot().GetTensorInfo()))
153  {
154  return nullptr;
155  }
156 
157  // Workaround an issue in the compute library. The conv2d algorithm that the
158  // compute library is choosing is not handling the 1x1 filter case when
159  // the padding size >= filter size
160  if (layer2d.GetType() == armnn::LayerType::Convolution2d)
161  {
162  // Get filter width and height
163  armnnUtils::DataLayoutIndexed dataLayoutIndex(newLayer2dDescriptor.m_DataLayout);
164  const TensorShape& filterShape = layer2d.GetInputSlot(1).GetTensorInfo().GetShape();
165  unsigned int filterWidth = filterShape[dataLayoutIndex.GetWidthIndex()];
166  unsigned int filterHeight = filterShape[dataLayoutIndex.GetHeightIndex()];
167  // Calculate total padding and check conditions
168  auto horizontalPadding = newLayer2dDescriptor.m_PadLeft + newLayer2dDescriptor.m_PadRight;
169  auto verticalPadding = newLayer2dDescriptor.m_PadTop + newLayer2dDescriptor.m_PadBottom;
170  if ((filterWidth == 1) && (horizontalPadding >= filterWidth))
171  {
172  return nullptr;
173  }
174  else if ((filterHeight == 1) && (verticalPadding >= filterHeight))
175  {
176  return nullptr;
177  }
178  }
179 
180  // Save original parent output slot of the pad layer
181  OutputSlot& parentSlot = *padLayer.GetInputSlot(0).GetConnectedOutputSlot();
182 
183  // Insert new layer2d layer between the pad layer and its parent layer.
184  const std::string name = std::string("folded-") + padLayer.GetName() + "-into-" + layer2d.GetName();
185  auto& newLayer2d = *graph.InsertNewLayer<Layer2dT>(padLayer.GetInputSlot(0), newLayer2dDescriptor, name.c_str());
186 
187  newLayer2d.GetOutputSlot().MoveAllConnections(parentSlot);
188  // Start at 1 to connect only weights and bias
189  for (unsigned int i = 1; i < layer2d.GetNumInputSlots(); ++i)
190  {
191  if (layer2d.GetInputSlot(i).GetConnectedOutputSlot() != nullptr)
192  {
193  Layer& tgtLayer = layer2d.GetInputSlot(i).GetConnectedOutputSlot()->GetOwningLayer();
194  // Remove old connection and connect to new layer2d
195  tgtLayer.GetOutputSlot(0).Disconnect(layer2d.GetInputSlot(i));
196  tgtLayer.GetOutputSlot(0).Connect(newLayer2d.GetInputSlot(i));
197  }
198  }
199 
200  // Moves connections in old layer2d layer output to new layer.
201  // Old layer2d layer will be removed as it's left unconnected.
202  // Pad layer will be removed if left unconnected.
203  layer2d.GetOutputSlot().MoveAllConnections(newLayer2d.GetOutputSlot());
204 
205  return &newLayer2d;
206 }

References OutputSlot::Connect(), armnn::Convolution2d, OutputSlot::Disconnect(), InputSlot::GetConnectedOutputSlot(), DataLayoutIndexed::GetHeightIndex(), Layer::GetInputSlot(), Layer::GetName(), Layer::GetOutputSlot(), InputSlot::GetOwningLayer(), OutputSlot::GetOwningLayer(), LayerWithParameters< Parameters >::GetParameters(), OutputSlot::GetTensorInfo(), DataLayoutIndexed::GetWidthIndex(), Graph::InsertNewLayer(), and TryFoldPadIntoLayer2d().

◆ GetLowestElement()

float armnn::optimizations::pad_fold::GetLowestElement ( const TensorInfo tensorInfo)
inline

Definition at line 26 of file FoldPadIntoLayer2d.hpp.

27 {
28  constexpr float negativeInfinity = -std::numeric_limits<float>::infinity();
29  const float scale = tensorInfo.GetQuantizationScale();
30  const int32_t offset = tensorInfo.GetQuantizationOffset();
31 
32  switch (tensorInfo.GetDataType())
33  {
34  case DataType::Float16:
35  return armnnUtils::SelectiveQuantize<armnn::Half>(negativeInfinity, scale, offset);
36  case DataType::Float32:
37  return armnnUtils::SelectiveQuantize<float>(negativeInfinity, scale, offset);
38  case DataType::QAsymmU8:
39  return armnnUtils::SelectiveQuantize<uint8_t>(negativeInfinity, scale, offset);
40  case DataType::QSymmS16:
41  return armnnUtils::SelectiveQuantize<int16_t>(negativeInfinity, scale, offset);
42  case DataType::QSymmS8:
43  // Fall-through
44  case DataType::QAsymmS8:
45  return armnnUtils::SelectiveQuantize<int8_t>(negativeInfinity, scale, offset);
46  case DataType::BFloat16:
47  return armnnUtils::SelectiveQuantize<armnn::BFloat16>(negativeInfinity, scale, offset);
48  default:
49  {
50  ARMNN_ASSERT_MSG(false, "Unsupported DataType");
51  return NAN;
52  }
53  }
54 }

References ARMNN_ASSERT_MSG, armnn::BFloat16, armnn::Float16, armnn::Float32, TensorInfo::GetDataType(), TensorInfo::GetQuantizationOffset(), TensorInfo::GetQuantizationScale(), armnn::QAsymmS8, armnn::QAsymmU8, armnn::QSymmS16, and armnn::QSymmS8.

Referenced by IsNeutralElement().

◆ GetZeroElement()

float armnn::optimizations::pad_fold::GetZeroElement ( const TensorInfo tensorInfo)
inline

Definition at line 21 of file FoldPadIntoLayer2d.hpp.

22 {
23  return static_cast<float>(tensorInfo.IsQuantized() ? tensorInfo.GetQuantizationOffset() : 0);
24 }

References TensorInfo::GetQuantizationOffset(), and TensorInfo::IsQuantized().

Referenced by IsNeutralElement().

◆ IsNeutralElement() [1/3]

bool armnn::optimizations::pad_fold::IsNeutralElement ( const Convolution2dDescriptor ,
const TensorInfo tensorInfo,
const float  tensorValue 
)
inline

Definition at line 56 of file FoldPadIntoLayer2d.hpp.

57 {
58  return tensorValue == GetZeroElement(tensorInfo);
59 }

References GetZeroElement().

Referenced by TryFoldPadIntoLayer2d().

◆ IsNeutralElement() [2/3]

bool armnn::optimizations::pad_fold::IsNeutralElement ( const DepthwiseConvolution2dDescriptor ,
const TensorInfo tensorInfo,
const float  tensorValue 
)
inline

Definition at line 61 of file FoldPadIntoLayer2d.hpp.

64 {
65  return tensorValue == GetZeroElement(tensorInfo);
66 }

References GetZeroElement().

◆ IsNeutralElement() [3/3]

bool armnn::optimizations::pad_fold::IsNeutralElement ( const Pooling2dDescriptor descriptor,
const TensorInfo tensorInfo,
const float  tensorValue 
)
inline

Definition at line 68 of file FoldPadIntoLayer2d.hpp.

70 {
71  return (descriptor.m_PoolType == PoolingAlgorithm::Max)
72  ? tensorValue <= GetLowestElement(tensorInfo)
73  : tensorValue == GetZeroElement(tensorInfo);
74 }

References GetLowestElement(), GetZeroElement(), Pooling2dDescriptor::m_PoolType, and armnn::Max.

◆ IsPooling2dPadded()

bool armnn::optimizations::pad_fold::IsPooling2dPadded ( const Pooling2dDescriptor poolDescriptor)
inline

Definition at line 76 of file FoldPadIntoLayer2d.hpp.

77 {
78  const auto poolingPadValues = std::make_tuple(poolDescriptor.m_PadLeft, poolDescriptor.m_PadRight,
79  poolDescriptor.m_PadTop, poolDescriptor.m_PadBottom);
80  if (poolingPadValues != std::make_tuple(0U, 0U, 0U, 0U))
81  {
82  return true;
83  }
84  return false;
85 }

References Pooling2dDescriptor::m_PadBottom, Pooling2dDescriptor::m_PadLeft, Pooling2dDescriptor::m_PadRight, and Pooling2dDescriptor::m_PadTop.

Referenced by TryFoldPadIntoLayer2d().

◆ TryFoldPadIntoLayer2d() [1/2]

bool armnn::optimizations::pad_fold::TryFoldPadIntoLayer2d ( const PadDescriptor padDescriptor,
Descriptor &  layerDescriptor,
const TensorInfo tensorInfo 
)

Definition at line 88 of file FoldPadIntoLayer2d.hpp.

90 {
91  armnnUtils::DataLayoutIndexed layout = armnnUtils::DataLayoutIndexed(layerDescriptor.m_DataLayout);
92  constexpr unsigned int batchIndex = 0;
93 
94  constexpr auto noPad = std::make_pair(0U, 0U);
95 
96  if ((!IsNeutralElement(layerDescriptor, tensorInfo, padDescriptor.m_PadValue)) ||
97  (padDescriptor.m_PadList[batchIndex] != noPad) || (padDescriptor.m_PadList[layout.GetChannelsIndex()] != noPad))
98  {
99  return false;
100  }
101 
102  const auto& padList = padDescriptor.m_PadList;
103 
104  // In Convolution2dDescriptor/Pooling2dDescriptor, padLeft and padRight are defined as paddings
105  // on width dimension whereas padTop and padBottom - paddings on height dimension, so updating
106  // these according to data layout
107  layerDescriptor.m_PadLeft += padList[layout.GetWidthIndex()].first;
108  layerDescriptor.m_PadRight += padList[layout.GetWidthIndex()].second;
109  layerDescriptor.m_PadTop += padList[layout.GetHeightIndex()].first;
110  layerDescriptor.m_PadBottom += padList[layout.GetHeightIndex()].second;
111 
112  return true;
113 }

References DataLayoutIndexed::GetChannelsIndex(), DataLayoutIndexed::GetHeightIndex(), DataLayoutIndexed::GetWidthIndex(), IsNeutralElement(), PadDescriptor::m_PadList, and PadDescriptor::m_PadValue.

Referenced by FoldPadIntoLayer2dImpl(), RefBackend::OptimizeSubgraphView(), and ClBackend::OptimizeSubgraphView().

◆ TryFoldPadIntoLayer2d() [2/2]

bool armnn::optimizations::pad_fold::TryFoldPadIntoLayer2d ( const PadDescriptor padDescriptor,
Pooling2dDescriptor poolDescriptor,
const TensorInfo tensorInfo,
bool  isBackendOptimization = false 
)
inline

Definition at line 115 of file FoldPadIntoLayer2d.hpp.

119 {
120  // Cannot fold Average or L2 pooling if padding exists and the padding method is Exclude.
121  if (poolDescriptor.m_PoolType != PoolingAlgorithm::Max &&
122  IsPooling2dPadded(poolDescriptor) &&
123  poolDescriptor.m_PaddingMethod == PaddingMethod::Exclude)
124  {
125  return false;
126  }
127 
128  // Cannot fold Average pooling if data type is quantized and layout is NHWC in Neon backend.
129  // Therefore, this specific case will become a backend specific optimization.
130  if (!isBackendOptimization &&
131  tensorInfo.IsQuantized() &&
132  poolDescriptor.m_PoolType == PoolingAlgorithm::Average &&
133  poolDescriptor.m_DataLayout == DataLayout::NHWC)
134  {
135  return false;
136  }
137 
138  poolDescriptor.m_PaddingMethod = PaddingMethod::IgnoreValue;
139 
140  return TryFoldPadIntoLayer2d<Pooling2dDescriptor>(padDescriptor, poolDescriptor, tensorInfo);
141 }

References armnn::Average, armnn::Exclude, armnn::IgnoreValue, IsPooling2dPadded(), TensorInfo::IsQuantized(), Pooling2dDescriptor::m_DataLayout, Pooling2dDescriptor::m_PaddingMethod, Pooling2dDescriptor::m_PoolType, armnn::Max, and armnn::NHWC.

armnn::optimizations::pad_fold::IsPooling2dPadded
bool IsPooling2dPadded(const Pooling2dDescriptor &poolDescriptor)
Definition: FoldPadIntoLayer2d.hpp:76
armnnUtils::DataLayoutIndexed
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout.
Definition: DataLayoutIndexed.hpp:17
ARMNN_ASSERT_MSG
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
armnnUtils::DataLayoutIndexed::GetHeightIndex
unsigned int GetHeightIndex() const
Definition: DataLayoutIndexed.hpp:24
armnn::optimizations::pad_fold::GetLowestElement
float GetLowestElement(const TensorInfo &tensorInfo)
Definition: FoldPadIntoLayer2d.hpp:26
armnnUtils::DataLayoutIndexed::GetWidthIndex
unsigned int GetWidthIndex() const
Definition: DataLayoutIndexed.hpp:25
armnnUtils::DataLayoutIndexed::GetChannelsIndex
unsigned int GetChannelsIndex() const
Definition: DataLayoutIndexed.hpp:23
armnn::optimizations::pad_fold::TryFoldPadIntoLayer2d
bool TryFoldPadIntoLayer2d(const PadDescriptor &padDescriptor, Pooling2dDescriptor &poolDescriptor, const TensorInfo &tensorInfo, bool isBackendOptimization=false)
Definition: FoldPadIntoLayer2d.hpp:115
armnn::LayerType::Convolution2d
@ Convolution2d
armnn::optimizations::pad_fold::GetZeroElement
float GetZeroElement(const TensorInfo &tensorInfo)
Definition: FoldPadIntoLayer2d.hpp:21
armnn::optimizations::pad_fold::IsNeutralElement
bool IsNeutralElement(const Pooling2dDescriptor &descriptor, const TensorInfo &tensorInfo, const float tensorValue)
Definition: FoldPadIntoLayer2d.hpp:68