xref: /aosp_15_r20/external/armnn/src/armnn/layers/Pooling3dLayer.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Pooling3dLayer.hpp"
7 
8 #include "LayerCloneBase.hpp"
9 
10 #include <armnn/TypesUtils.hpp>
11 
12 #include <armnnUtils/DataLayoutIndexed.hpp>
13 
14 #include <armnn/backends/WorkloadData.hpp>
15 #include <armnn/backends/WorkloadFactory.hpp>
16 
17 using namespace armnnUtils;
18 
19 namespace armnn
20 {
21 
Pooling3dLayer(const Pooling3dDescriptor & param,const char * name)22 Pooling3dLayer::Pooling3dLayer(const Pooling3dDescriptor& param, const char* name)
23     : LayerWithParameters(1, 1, LayerType::Pooling3d, param, name)
24 {
25 }
26 
CreateWorkload(const IWorkloadFactory & factory) const27 std::unique_ptr<IWorkload> Pooling3dLayer::CreateWorkload(const IWorkloadFactory& factory) const
28 {
29     Pooling3dQueueDescriptor descriptor;
30     SetAdditionalInfo(descriptor);
31 
32     return factory.CreateWorkload(LayerType::Pooling3d, descriptor, PrepInfoAndDesc(descriptor));
33 }
34 
Clone(Graph & graph) const35 Pooling3dLayer* Pooling3dLayer::Clone(Graph& graph) const
36 {
37     return CloneBase<Pooling3dLayer>(graph, m_Param, GetName());
38 }
39 
InferOutputShapes(const std::vector<TensorShape> & inputShapes) const40 std::vector<TensorShape> Pooling3dLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
41 {
42     ARMNN_ASSERT(inputShapes.size() == 1);
43     const TensorShape& inputShape = inputShapes[0];
44     const DataLayoutIndexed dimensionIndices = m_Param.m_DataLayout;
45 
46     // If we support multiple batch dimensions in the future, then this assert will need to change.
47     ARMNN_ASSERT_MSG(inputShape.GetNumDimensions() == 5, "Pooling3dLayer will always have 5D input.");
48 
49     unsigned int inWidth = inputShape[dimensionIndices.GetWidthIndex()];
50     unsigned int inHeight = inputShape[dimensionIndices.GetHeightIndex()];
51     unsigned int inDepth = inputShape[dimensionIndices.GetDepthIndex()];
52     unsigned int inChannels = inputShape[dimensionIndices.GetChannelsIndex()];
53     unsigned int inBatchSize = inputShape[0];
54 
55     bool isGlobalPooling = (m_Param.m_StrideX==0 && m_Param.m_StrideY==0 && m_Param.m_StrideZ==0);
56     unsigned int outWidth = 1;
57     unsigned int outHeight = 1;
58     unsigned int outDepth = 1;
59     if (!isGlobalPooling)
60     {
61         ARMNN_ASSERT_MSG(m_Param.m_StrideX!=0 && m_Param.m_StrideY!=0 && m_Param.m_StrideZ!=0,
62                          "Stride can only be zero when performing global pooling");
63 
64         auto CalcSize = [](auto inSize, auto lowPad, auto highPad, auto poolSize, auto stride, auto outputShapeRounding)
65             {
66                 unsigned int readSize = inSize + lowPad + highPad - poolSize;
67                 float div = static_cast<float>(readSize) / static_cast<float>(stride);
68 
69                 unsigned int size = 0;
70                 switch (outputShapeRounding)
71                 {
72                     case OutputShapeRounding::Ceiling:
73                         size = static_cast<unsigned int>(ceil(div)) + 1;
74                         break;
75                     case OutputShapeRounding ::Floor:
76                         size = static_cast<unsigned int>(floor(div)) + 1;
77                         break;
78                     default:
79                         ARMNN_ASSERT_MSG(false, "Unsupported Output Shape Rounding");
80                 }
81 
82                 // Makes sure that border operations will start from inside the input and not the padded area.
83                 // This is what CL does...
84                 if ((size - 1)*stride >= inSize + lowPad)
85                 {
86                     --size;
87                 }
88 
89                 return size;
90             };
91 
92         outWidth = CalcSize(inWidth, m_Param.m_PadLeft, m_Param.m_PadRight, m_Param.m_PoolWidth, m_Param.m_StrideX,
93                             m_Param.m_OutputShapeRounding);
94         outHeight = CalcSize(inHeight, m_Param.m_PadTop, m_Param.m_PadBottom, m_Param.m_PoolHeight, m_Param.m_StrideY,
95                             m_Param.m_OutputShapeRounding);
96         outDepth = CalcSize(inDepth, m_Param.m_PadFront, m_Param.m_PadBack, m_Param.m_PoolDepth, m_Param.m_StrideZ,
97                             m_Param.m_OutputShapeRounding);
98     }
99     unsigned int outChannels = inChannels;
100     unsigned int outBatchSize = inBatchSize;
101 
102     TensorShape tensorShape = m_Param.m_DataLayout == armnn::DataLayout::NDHWC ?
103         TensorShape( { outBatchSize, outDepth, outHeight, outWidth, outChannels } ) :
104         TensorShape( { outBatchSize, outChannels, outDepth, outHeight, outWidth });
105 
106     return std::vector<TensorShape>({ tensorShape });
107 }
108 
ValidateTensorShapesFromInputs()109 void Pooling3dLayer::ValidateTensorShapesFromInputs()
110 {
111     VerifyLayerConnections(1, CHECK_LOCATION());
112 
113     const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
114 
115     VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
116 
117     auto inferredShapes = InferOutputShapes({ GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape() });
118 
119     ARMNN_ASSERT(inferredShapes.size() == 1);
120 
121     ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "Pooling3dLayer");
122 }
123 
ExecuteStrategy(IStrategy & strategy) const124 void Pooling3dLayer::ExecuteStrategy(IStrategy& strategy) const
125 {
126     strategy.ExecuteStrategy(this, GetParameters(), {}, GetName());
127 }
128 
129 } // namespace armnn
130