xref: /aosp_15_r20/external/armnn/src/armnn/layers/Convolution3dLayer.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Convolution3dLayer.hpp"
7 #include "LayerCloneBase.hpp"
8 
9 #include <armnnUtils/DataLayoutIndexed.hpp>
10 
11 #include <armnn/backends/TensorHandle.hpp>
12 
13 using namespace armnnUtils;
14 
15 namespace armnn
16 {
17 
Convolution3dLayer(const Convolution3dDescriptor & param,const char * name)18 Convolution3dLayer::Convolution3dLayer(const Convolution3dDescriptor& param, const char* name)
19     : LayerWithParameters(param.GetNumInputs(), 1, LayerType::Convolution3d, param, name)
20 {
21 }
22 
SerializeLayerParameters(ParameterStringifyFunction & fn) const23 void Convolution3dLayer::SerializeLayerParameters(ParameterStringifyFunction& fn) const
24 {
25     const std::vector<TensorShape>& inputShapes =
26     {
27         GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
28         GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape(),
29     };
30 
31     // Conv3d Filter Layout: [D,H,W,I,O]
32     const TensorShape filterShape = inputShapes[1];
33     unsigned int filterDepth = filterShape[0];
34     unsigned int filterHeight = filterShape[1];
35     unsigned int filterWidth = filterShape[2];
36     unsigned int inChannels = filterShape[3];
37     unsigned int outChannels = filterShape[4];
38 
39     fn("FilterDepth",std::to_string(filterDepth));
40     fn("FilterHeight",std::to_string(filterHeight));
41     fn("FilterWidth",std::to_string(filterWidth));
42     fn("InputChannels",std::to_string(inChannels));
43     fn("OutputChannels",std::to_string(outChannels));
44 
45     LayerWithParameters<Convolution3dDescriptor>::SerializeLayerParameters(fn);
46 }
47 
CreateWorkload(const IWorkloadFactory & factory) const48 std::unique_ptr<IWorkload> Convolution3dLayer::CreateWorkload(const IWorkloadFactory& factory) const
49 {
50     Convolution3dQueueDescriptor descriptor;
51     SetAdditionalInfo(descriptor);
52 
53     return factory.CreateWorkload(LayerType::Convolution3d, descriptor, PrepInfoAndDesc(descriptor));
54 }
55 
Clone(Graph & graph) const56 Convolution3dLayer* Convolution3dLayer::Clone(Graph& graph) const
57 {
58     auto layer = CloneBase<Convolution3dLayer>(graph, m_Param, GetName());
59     return std::move(layer);
60 }
61 
InferOutputShapes(const std::vector<TensorShape> & inputShapes) const62 std::vector<TensorShape> Convolution3dLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
63 {
64     ARMNN_ASSERT(inputShapes.size() == 2);
65     const TensorShape& inputShape = inputShapes[0];
66     const TensorShape& filterShape = inputShapes[1];
67 
68     ARMNN_ASSERT_MSG(inputShape.GetNumDimensions() == 5, "Convolutions will always have 5D input.");
69 
70     ARMNN_ASSERT( m_Param.m_StrideX > 0);
71     ARMNN_ASSERT( m_Param.m_StrideY > 0);
72     ARMNN_ASSERT( m_Param.m_StrideZ > 0);
73 
74     DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout);
75 
76     unsigned int inWidth = inputShape[dataLayoutIndex.GetWidthIndex()];
77     unsigned int inHeight = inputShape[dataLayoutIndex.GetHeightIndex()];
78     unsigned int inDepth = inputShape[dataLayoutIndex.GetDepthIndex()];
79     unsigned int inBatchSize = inputShape[0];
80 
81     // Conv3d Filter Layout: [D,H,W,I,O]
82     unsigned int filterDepth = filterShape[0];
83     unsigned int dilatedFilterDepth = filterDepth + (m_Param.m_DilationZ - 1) * (filterDepth - 1);
84     unsigned int readDepth = (inDepth + m_Param.m_PadFront + m_Param.m_PadBack) - dilatedFilterDepth;
85     unsigned int outDepth = 1 + (readDepth / m_Param.m_StrideZ);
86 
87     unsigned int filterHeight = filterShape[1];
88     unsigned int dilatedFilterHeight = filterHeight + (m_Param.m_DilationY - 1) * (filterHeight - 1);
89     unsigned int readHeight = (inHeight + m_Param.m_PadTop + m_Param.m_PadBottom) - dilatedFilterHeight;
90     unsigned int outHeight = 1 + (readHeight / m_Param.m_StrideY);
91 
92     unsigned int filterWidth = filterShape[2];
93     unsigned int dilatedFilterWidth = filterWidth + (m_Param.m_DilationX - 1) * (filterWidth - 1);
94     unsigned int readWidth = (inWidth + m_Param.m_PadLeft + m_Param.m_PadRight) - dilatedFilterWidth;
95     unsigned int outWidth = 1 + (readWidth / m_Param.m_StrideX);
96 
97     unsigned int outChannels = filterShape[4];
98     unsigned int outBatchSize = inBatchSize;
99 
100     TensorShape tensorShape = m_Param.m_DataLayout == armnn::DataLayout::NDHWC ?
101             TensorShape( { outBatchSize, outDepth, outHeight, outWidth, outChannels } ) :
102             TensorShape( { outBatchSize, outChannels, outDepth, outHeight, outWidth });
103 
104     return std::vector<TensorShape>({ tensorShape });
105 }
106 
ValidateTensorShapesFromInputs()107 void Convolution3dLayer::ValidateTensorShapesFromInputs()
108 {
109     VerifyLayerConnections(m_Param.GetNumInputs(), CHECK_LOCATION());
110 
111     const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
112 
113     VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
114 
115     ARMNN_ASSERT_MSG(GetInputSlot(1).GetConnection(),
116                      "Convolution3dLayer: Weights should be connected to input slot 1.");
117 
118     auto inferredShapes = InferOutputShapes({
119         GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
120         GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape() });
121 
122     ARMNN_ASSERT(inferredShapes.size() == 1);
123 
124     ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "Convolution3dLayer");
125 }
126 
ExecuteStrategy(IStrategy & strategy) const127 void Convolution3dLayer::ExecuteStrategy(IStrategy& strategy) const
128 {
129     strategy.ExecuteStrategy(this, GetParameters(), {}, GetName());
130 }
131 
132 } // namespace armnn
133