ArmNN
 25.11
Loading...
Searching...
No Matches
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()

template<typename Layer2dT>
Layer2dT * FoldPadIntoLayer2dImpl ( Graph & graph,
InputSlot & connection )

Definition at line 144 of file FoldPadIntoLayer2d.hpp.

145{
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 // Copy the backend
206 newLayer2d.SetBackendId(layer2d.GetBackendId());
207
208 return &newLayer2d;
209}
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
Definition Graph.hpp:481
Layer & GetOwningLayer() const
Definition Layer.hpp:53
const OutputSlot * GetConnectedOutputSlot() const
Definition Layer.hpp:56
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition Layer.hpp:337
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition Layer.hpp:339
const char * GetName() const override
Returns the name of the layer.
Definition Layer.hpp:332
const Parameters & GetParameters() const override
If the layer has a descriptor return it.
Layer & GetOwningLayer() const
Definition Layer.hpp:132
const TensorInfo & GetTensorInfo() const override
Definition Layer.cpp:100
This layer represents a pad operation.
Definition PadLayer.hpp:15
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout.
bool TryFoldPadIntoLayer2d(const PadDescriptor &padDescriptor, Descriptor &layerDescriptor, const TensorInfo &tensorInfo)
DestType PolymorphicDowncast(SourceType *value)
Polymorphic downcast for build in pointers only.
A PadDescriptor for the PadLayer.

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(), armnn::PolymorphicDowncast(), and TryFoldPadIntoLayer2d().

Referenced by FoldPadIntoConvolution2dImpl::Run(), FoldPadIntoDepthwiseConvolution2dImpl::Run(), and FoldPadIntoPooling2dImpl::Run().

◆ GetLowestElement()

float 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 {
35 return armnnUtils::SelectiveQuantize<armnn::Half>(negativeInfinity, scale, offset);
37 return armnnUtils::SelectiveQuantize<float>(negativeInfinity, scale, offset);
39 return armnnUtils::SelectiveQuantize<uint8_t>(negativeInfinity, scale, offset);
41 return armnnUtils::SelectiveQuantize<int16_t>(negativeInfinity, scale, offset);
43 // Fall-through
45 return armnnUtils::SelectiveQuantize<int8_t>(negativeInfinity, scale, offset);
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}
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition Assert.hpp:15
float GetQuantizationScale() const
Definition Tensor.cpp:461
int32_t GetQuantizationOffset() const
Definition Tensor.cpp:482
DataType GetDataType() const
Definition Tensor.hpp:200
T SelectiveQuantize(float value, float scale, int32_t offset)

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

Referenced by IsNeutralElement().

◆ GetZeroElement()

float 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}
bool IsQuantized() const
Definition Tensor.cpp:508

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

Referenced by IsNeutralElement(), IsNeutralElement(), and IsNeutralElement().

◆ IsNeutralElement() [1/3]

bool 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}
float GetZeroElement(const TensorInfo &tensorInfo)

References GetZeroElement().

Referenced by TryFoldPadIntoLayer2d().

◆ IsNeutralElement() [2/3]

bool 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 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}
float GetLowestElement(const TensorInfo &tensorInfo)
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).

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

◆ IsPooling2dPadded()

bool 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}
uint32_t m_PadRight
Padding right value in the width dimension.
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
uint32_t m_PadLeft
Padding left value in the width dimension.

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

Referenced by TryFoldPadIntoLayer2d().

◆ TryFoldPadIntoLayer2d() [1/2]

template<typename Descriptor>
bool 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}
unsigned int GetHeightIndex() const
unsigned int GetChannelsIndex() const
bool IsNeutralElement(const Convolution2dDescriptor &, const TensorInfo &tensorInfo, const float tensorValue)
float m_PadValue
Optional value to use for padding, defaults to 0.
std::vector< std::pair< unsigned int, unsigned int > > m_PadList
Specifies the padding for input dimension.

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

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

◆ TryFoldPadIntoLayer2d() [2/2]

bool 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
139
140 return TryFoldPadIntoLayer2d<Pooling2dDescriptor>(padDescriptor, poolDescriptor, tensorInfo);
141}
bool IsPooling2dPadded(const Pooling2dDescriptor &poolDescriptor)
@ Exclude
The padding fields don't count and are ignored.
Definition Types.hpp:194
@ IgnoreValue
The padding fields count, but are ignored.
Definition Types.hpp:192
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).

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