From b63a31170aee1d28267d83a4bc67b57708fb6b05 Mon Sep 17 00:00:00 2001 From: Matthew Sloyan Date: Wed, 8 Sep 2021 13:05:51 +0100 Subject: IVGCVSW-6163 Add Conv3d FrontEnd and Ref Implementation * Added front-end * Added Reference workload * Added Serializer & Deserializer support * Added unit tests * Added NDHWC DataLayout Signed-off-by: Matthew Sloyan Change-Id: Iec4d39e7433b5334d52fa44cf8efc6bcd39319d8 --- src/armnn/layers/Convolution3dLayer.cpp | 172 ++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/armnn/layers/Convolution3dLayer.cpp (limited to 'src/armnn/layers/Convolution3dLayer.cpp') diff --git a/src/armnn/layers/Convolution3dLayer.cpp b/src/armnn/layers/Convolution3dLayer.cpp new file mode 100644 index 0000000000..0e38c0b129 --- /dev/null +++ b/src/armnn/layers/Convolution3dLayer.cpp @@ -0,0 +1,172 @@ +// +// Copyright © 2021 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Convolution3dLayer.hpp" +#include "LayerCloneBase.hpp" + +#include + +#include + +using namespace armnnUtils; + +namespace armnn +{ + +Convolution3dLayer::Convolution3dLayer(const Convolution3dDescriptor& param, const char* name) + : LayerWithParameters(1, 1, LayerType::Convolution3d, param, name) +{ +} + +void Convolution3dLayer::SerializeLayerParameters(ParameterStringifyFunction& fn) const +{ + const std::vector& inputShapes = + { + GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), + m_Weight->GetTensorInfo().GetShape() + }; + + // Conv3d Filter Layout: [D,H,W,I,O] + const TensorShape filterShape = inputShapes[1]; + DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout); + unsigned int filterDepth = filterShape[0]; + unsigned int filterHeight = filterShape[1]; + unsigned int filterWidth = filterShape[2]; + unsigned int inChannels = filterShape[3]; + unsigned int outChannels = filterShape[4]; + + fn("FilterDepth",std::to_string(filterDepth)); + fn("FilterHeight",std::to_string(filterHeight)); + fn("FilterWidth",std::to_string(filterWidth)); + fn("InputChannels",std::to_string(inChannels)); + fn("OutputChannels",std::to_string(outChannels)); + + LayerWithParameters::SerializeLayerParameters(fn); +} + +std::unique_ptr Convolution3dLayer::CreateWorkload(const IWorkloadFactory& factory) const +{ + // At this level constant data should not be released. + ARMNN_ASSERT_MSG(m_Weight != nullptr, "Convolution3dLayer: Weights data should not be null."); + + Convolution3dQueueDescriptor descriptor; + descriptor.m_Weight = m_Weight.get(); + + if (m_Param.m_BiasEnabled) + { + ARMNN_ASSERT_MSG(m_Bias != nullptr, "Convolution3dLayer: Bias data should not be null."); + descriptor.m_Bias = m_Bias.get(); + } + + SetAdditionalInfo(descriptor); + + return factory.CreateConvolution3d(descriptor, PrepInfoAndDesc(descriptor)); +} + +Convolution3dLayer* Convolution3dLayer::Clone(Graph& graph) const +{ + auto layer = CloneBase(graph, m_Param, GetName()); + + layer->m_Weight = m_Weight ? m_Weight : nullptr; + + if (layer->m_Param.m_BiasEnabled) + { + layer->m_Bias = m_Bias ? m_Bias : nullptr; + } + + return std::move(layer); +} + +std::vector Convolution3dLayer::InferOutputShapes(const std::vector& inputShapes) const +{ + ARMNN_ASSERT(inputShapes.size() == 2); + const TensorShape& inputShape = inputShapes[0]; + const TensorShape& filterShape = inputShapes[1]; + + ARMNN_ASSERT_MSG(inputShape.GetNumDimensions() == 5, "Convolutions will always have 5D input."); + + ARMNN_ASSERT( m_Param.m_StrideX > 0); + ARMNN_ASSERT( m_Param.m_StrideY > 0); + ARMNN_ASSERT( m_Param.m_StrideZ > 0); + + DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout); + + unsigned int inWidth = inputShape[dataLayoutIndex.GetWidthIndex()]; + unsigned int inHeight = inputShape[dataLayoutIndex.GetHeightIndex()]; + unsigned int inDepth = inputShape[dataLayoutIndex.GetDepthIndex()]; + unsigned int inBatchSize = inputShape[0]; + + // Conv3d Filter Layout: [D,H,W,I,O] + unsigned int filterDepth = filterShape[0]; + unsigned int dilatedFilterDepth = filterDepth + (m_Param.m_DilationZ - 1) * (filterDepth - 1); + unsigned int readDepth = (inDepth + m_Param.m_PadFront + m_Param.m_PadBack) - dilatedFilterDepth; + unsigned int outDepth = 1 + (readDepth / m_Param.m_StrideZ); + + unsigned int filterHeight = filterShape[1]; + unsigned int dilatedFilterHeight = filterHeight + (m_Param.m_DilationY - 1) * (filterHeight - 1); + unsigned int readHeight = (inHeight + m_Param.m_PadTop + m_Param.m_PadBottom) - dilatedFilterHeight; + unsigned int outHeight = 1 + (readHeight / m_Param.m_StrideY); + + unsigned int filterWidth = filterShape[2]; + unsigned int dilatedFilterWidth = filterWidth + (m_Param.m_DilationX - 1) * (filterWidth - 1); + unsigned int readWidth = (inWidth + m_Param.m_PadLeft + m_Param.m_PadRight) - dilatedFilterWidth; + unsigned int outWidth = 1 + (readWidth / m_Param.m_StrideX); + + unsigned int outChannels = filterShape[4]; + unsigned int outBatchSize = inBatchSize; + + TensorShape tensorShape = TensorShape( { outBatchSize, outDepth, outHeight, outWidth, outChannels } ); + + return std::vector({ tensorShape }); +} + +void Convolution3dLayer::ValidateTensorShapesFromInputs() +{ + VerifyLayerConnections(1, CHECK_LOCATION()); + + const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape(); + + VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); + + // check if we m_Weight data is not nullptr + ARMNN_ASSERT_MSG(m_Weight != nullptr, "Convolution3dLayer: Weights data should not be null."); + + auto inferredShapes = InferOutputShapes({ + GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), + m_Weight->GetTensorInfo().GetShape() }); + + ARMNN_ASSERT(inferredShapes.size() == 1); + + ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "Convolution3dLayer"); +} + +Layer::ConstantTensors Convolution3dLayer::GetConstantTensorsByRef() +{ + return {m_Weight, m_Bias}; +} + +ARMNN_NO_DEPRECATE_WARN_BEGIN +void Convolution3dLayer::Accept(ILayerVisitor& visitor) const +{ + IgnoreUnused(visitor); + throw armnn::Exception("Convolution3dLayer: VisitConvolution3dLayer is not implemented"); +} +ARMNN_NO_DEPRECATE_WARN_END + +void Convolution3dLayer::ExecuteStrategy(IStrategy& strategy) const +{ + ManagedConstTensorHandle managedWeight(m_Weight); + std::vector constTensors { { managedWeight.GetTensorInfo(), managedWeight.Map() } }; + + ManagedConstTensorHandle managedBias(m_Bias); + if (GetParameters().m_BiasEnabled) + { + constTensors.emplace_back(ConstTensor(managedBias.GetTensorInfo(), managedBias.Map())); + } + + strategy.ExecuteStrategy(this, GetParameters(), constTensors, GetName()); +} + +} // namespace armnn -- cgit v1.2.1