blob: 89ea0042ce28542102f794c5432624d53eeffaa6 [file] [log] [blame]
Matthew Sloyanb63a3112021-09-08 13:05:51 +01001//
Declan-ARM7c75e332024-03-12 16:40:25 +00002// Copyright © 2021-2024 Arm Ltd and Contributors. All rights reserved.
Matthew Sloyanb63a3112021-09-08 13:05:51 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "Convolution3dLayer.hpp"
7#include "LayerCloneBase.hpp"
8
9#include <armnnUtils/DataLayoutIndexed.hpp>
10
Colm Donelan0c479742021-12-10 12:43:54 +000011#include <armnn/backends/TensorHandle.hpp>
Matthew Sloyanb63a3112021-09-08 13:05:51 +010012
13using namespace armnnUtils;
14
15namespace armnn
16{
17
18Convolution3dLayer::Convolution3dLayer(const Convolution3dDescriptor& param, const char* name)
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +010019 : LayerWithParameters(param.GetNumInputs(), 1, LayerType::Convolution3d, param, name)
Matthew Sloyanb63a3112021-09-08 13:05:51 +010020{
21}
22
23void Convolution3dLayer::SerializeLayerParameters(ParameterStringifyFunction& fn) const
24{
25 const std::vector<TensorShape>& inputShapes =
26 {
Mike Kellya9ac6ba2023-06-30 15:18:26 +010027 GetInputSlot(0).GetTensorInfo().GetShape(),
28 GetInputSlot(1).GetTensorInfo().GetShape(),
Matthew Sloyanb63a3112021-09-08 13:05:51 +010029 };
30
31 // Conv3d Filter Layout: [D,H,W,I,O]
32 const TensorShape filterShape = inputShapes[1];
Matthew Sloyanb63a3112021-09-08 13:05:51 +010033 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
48std::unique_ptr<IWorkload> Convolution3dLayer::CreateWorkload(const IWorkloadFactory& factory) const
49{
Matthew Sloyanb63a3112021-09-08 13:05:51 +010050 Convolution3dQueueDescriptor descriptor;
Matthew Sloyanb63a3112021-09-08 13:05:51 +010051 SetAdditionalInfo(descriptor);
52
Teresa Charlin611c7fb2022-01-07 09:47:29 +000053 return factory.CreateWorkload(LayerType::Convolution3d, descriptor, PrepInfoAndDesc(descriptor));
Matthew Sloyanb63a3112021-09-08 13:05:51 +010054}
55
56Convolution3dLayer* Convolution3dLayer::Clone(Graph& graph) const
57{
58 auto layer = CloneBase<Convolution3dLayer>(graph, m_Param, GetName());
Matthew Sloyanb63a3112021-09-08 13:05:51 +010059 return std::move(layer);
60}
61
62std::vector<TensorShape> Convolution3dLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
63{
Declan-ARM7c75e332024-03-12 16:40:25 +000064 if (inputShapes.size() != 2)
65 {
66 throw armnn::Exception("inputShapes' size is \"" + std::to_string(inputShapes.size()) +
67 "\" - should be \"2\".");
68 }
69
Matthew Sloyanb63a3112021-09-08 13:05:51 +010070 const TensorShape& inputShape = inputShapes[0];
71 const TensorShape& filterShape = inputShapes[1];
72
Declan-ARM7c75e332024-03-12 16:40:25 +000073 if (inputShape.GetNumDimensions() != 5)
74 {
75 throw armnn::Exception("Convolutions will always have 5D input.");
76 }
Matthew Sloyanb63a3112021-09-08 13:05:51 +010077
Declan-ARM7c75e332024-03-12 16:40:25 +000078 if (m_Param.m_StrideX == 0)
79 {
80 throw armnn::Exception("m_StrideX cannot be 0.");
81 }
82
83 if (m_Param.m_StrideY == 0)
84 {
85 throw armnn::Exception("m_StrideY cannot be 0.");
86 }
87
88 if (m_Param.m_StrideZ == 0)
89 {
90 throw armnn::Exception("m_StrideZ cannot be 0.");
91 }
Matthew Sloyanb63a3112021-09-08 13:05:51 +010092
93 DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout);
94
95 unsigned int inWidth = inputShape[dataLayoutIndex.GetWidthIndex()];
96 unsigned int inHeight = inputShape[dataLayoutIndex.GetHeightIndex()];
97 unsigned int inDepth = inputShape[dataLayoutIndex.GetDepthIndex()];
98 unsigned int inBatchSize = inputShape[0];
99
100 // Conv3d Filter Layout: [D,H,W,I,O]
101 unsigned int filterDepth = filterShape[0];
102 unsigned int dilatedFilterDepth = filterDepth + (m_Param.m_DilationZ - 1) * (filterDepth - 1);
103 unsigned int readDepth = (inDepth + m_Param.m_PadFront + m_Param.m_PadBack) - dilatedFilterDepth;
104 unsigned int outDepth = 1 + (readDepth / m_Param.m_StrideZ);
105
106 unsigned int filterHeight = filterShape[1];
107 unsigned int dilatedFilterHeight = filterHeight + (m_Param.m_DilationY - 1) * (filterHeight - 1);
108 unsigned int readHeight = (inHeight + m_Param.m_PadTop + m_Param.m_PadBottom) - dilatedFilterHeight;
109 unsigned int outHeight = 1 + (readHeight / m_Param.m_StrideY);
110
111 unsigned int filterWidth = filterShape[2];
112 unsigned int dilatedFilterWidth = filterWidth + (m_Param.m_DilationX - 1) * (filterWidth - 1);
113 unsigned int readWidth = (inWidth + m_Param.m_PadLeft + m_Param.m_PadRight) - dilatedFilterWidth;
114 unsigned int outWidth = 1 + (readWidth / m_Param.m_StrideX);
115
116 unsigned int outChannels = filterShape[4];
117 unsigned int outBatchSize = inBatchSize;
118
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +0100119 TensorShape tensorShape = m_Param.m_DataLayout == armnn::DataLayout::NDHWC ?
120 TensorShape( { outBatchSize, outDepth, outHeight, outWidth, outChannels } ) :
121 TensorShape( { outBatchSize, outChannels, outDepth, outHeight, outWidth });
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100122
123 return std::vector<TensorShape>({ tensorShape });
124}
125
126void Convolution3dLayer::ValidateTensorShapesFromInputs()
127{
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +0100128 VerifyLayerConnections(m_Param.GetNumInputs(), CHECK_LOCATION());
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100129
130 const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
131
132 VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
133
Declan-ARM7c75e332024-03-12 16:40:25 +0000134 if (!GetInputSlot(1).GetConnection())
135 {
136 throw armnn::LayerValidationException("Convolution3dLayer: Weights should be connected to input slot 1.");
137 }
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100138
139 auto inferredShapes = InferOutputShapes({
Mike Kellya9ac6ba2023-06-30 15:18:26 +0100140 GetInputSlot(0).GetTensorInfo().GetShape(),
141 GetInputSlot(1).GetTensorInfo().GetShape() });
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100142
Declan-ARM7c75e332024-03-12 16:40:25 +0000143 if (inferredShapes.size() != 1)
144 {
145 throw armnn::LayerValidationException("inferredShapes has "
146 + std::to_string(inferredShapes.size()) +
147 " elements - should only have 1.");
148 }
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100149
150 ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "Convolution3dLayer");
151}
152
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100153void Convolution3dLayer::ExecuteStrategy(IStrategy& strategy) const
154{
Matthew Sloyan5d7b0a32021-10-18 13:07:49 +0100155 strategy.ExecuteStrategy(this, GetParameters(), {}, GetName());
Matthew Sloyanb63a3112021-09-08 13:05:51 +0100156}
157
158} // namespace armnn