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