2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
5 #include "DepthwiseConvolution2dLayer.hpp"
7 #include "LayerCloneBase.hpp"
9 #include <armnn/TypesUtils.hpp>
10 #include <backendsCommon/CpuTensorHandle.hpp>
11 #include <backendsCommon/WorkloadFactory.hpp>
16 DepthwiseConvolution2dLayer::DepthwiseConvolution2dLayer(const DepthwiseConvolution2dDescriptor& param,
18 : LayerWithParameters(1, 1, LayerType::DepthwiseConvolution2d, param, name)
22 std::unique_ptr<IWorkload> DepthwiseConvolution2dLayer::CreateWorkload(const Graph& graph,
23 const IWorkloadFactory& factory) const
25 // on this level constant data should not be released..
26 BOOST_ASSERT_MSG(m_Weight != nullptr, "DepthwiseConvolution2dLayer: Weights data should not be null.");
28 DepthwiseConvolution2dQueueDescriptor descriptor;
30 descriptor.m_Weight = m_Weight.get();
32 if (m_Param.m_BiasEnabled)
34 BOOST_ASSERT_MSG(m_Bias != nullptr, "DepthwiseConvolution2dLayer: Bias data should not be null.");
35 descriptor.m_Bias = m_Bias.get();
37 return factory.CreateDepthwiseConvolution2d(descriptor, PrepInfoAndDesc(descriptor, graph));
40 DepthwiseConvolution2dLayer* DepthwiseConvolution2dLayer::Clone(Graph& graph) const
42 auto layer = CloneBase<DepthwiseConvolution2dLayer>(graph, m_Param, GetName());
43 layer->m_Weight = m_Weight ? std::make_unique<ScopedCpuTensorHandle>(*m_Weight) : nullptr;
45 if (layer->m_Param.m_BiasEnabled)
47 layer->m_Bias = m_Bias ? std::make_unique<ScopedCpuTensorHandle>(*m_Bias) : nullptr;
50 return std::move(layer);
53 std::vector<TensorShape>
54 DepthwiseConvolution2dLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
56 BOOST_ASSERT(inputShapes.size() == 2);
57 const TensorShape& inputShape = inputShapes[0];
58 const TensorShape filterShape = inputShapes[1];
60 BOOST_ASSERT_MSG(inputShape.GetNumDimensions() == 4, "Convolutions will always have 4D input.");
62 DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout);
64 unsigned int inWidth = inputShape[dataLayoutIndex.GetWidthIndex()];
65 unsigned int inHeight = inputShape[dataLayoutIndex.GetHeightIndex()];
66 unsigned int inBatchSize = inputShape[0];
68 unsigned int filterWidth = filterShape[dataLayoutIndex.GetWidthIndex()];
69 unsigned int readWidth = (inWidth + m_Param.m_PadLeft + m_Param.m_PadRight) - (filterWidth);
70 unsigned int outWidth = 1 + (readWidth / m_Param.m_StrideX);
72 unsigned int filterHeight = filterShape[dataLayoutIndex.GetHeightIndex()];
73 unsigned int readHeight = (inHeight + m_Param.m_PadTop + m_Param.m_PadBottom) - (filterHeight);
74 unsigned int outHeight = 1 + (readHeight / m_Param.m_StrideY);
75 unsigned int depthMultiplier = filterShape[0];
77 unsigned int outChannels = filterShape[dataLayoutIndex.GetChannelsIndex()] * depthMultiplier;
78 unsigned int outBatchSize = inBatchSize;
80 TensorShape tensorShape = m_Param.m_DataLayout == armnn::DataLayout::NHWC ?
81 TensorShape( { outBatchSize, outHeight, outWidth, outChannels } ) :
82 TensorShape( { outBatchSize, outChannels, outHeight, outWidth });
84 return std::vector<TensorShape>({ tensorShape });
87 void DepthwiseConvolution2dLayer::ValidateTensorShapesFromInputs()
89 VerifyLayerConnections(1, CHECK_LOCATION());
91 // on this level constant data should not be released..
92 BOOST_ASSERT_MSG(m_Weight != nullptr, "DepthwiseConvolution2dLayer: Weights data should not be null.");
94 auto inferredShapes = InferOutputShapes({
95 GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
96 m_Weight->GetTensorInfo().GetShape()
99 BOOST_ASSERT(inferredShapes.size() == 1);
101 ConditionalThrowIfNotEqual<LayerValidationException>(
102 "DepthwiseConvolution2dLayer: TensorShape set on OutputSlot[0] does not match the inferred shape.",
103 GetOutputSlot(0).GetTensorInfo().GetShape(),
107 Layer::ConstantTensors DepthwiseConvolution2dLayer::GetConstantTensorsByRef()
109 return {m_Weight, m_Bias};