From 07810fc2fcdd34db74222d90cc73ef12a88e7b78 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Thu, 12 Nov 2020 10:58:48 +0000 Subject: IVGCVSW-5328-5329 Fuse Activation * Added Fused Activation Optimization to both CL and Neon backends. * Added Fused Activation support to all the CL and Neon workloads that support it. * Changed ProfilingTest network to be a Convolution layer followed by an Abs layer rather than an Activation layer. * Added IBackendInternal::OptimizeSubgraphView function that can accept a ModelOptions. * Network will now call OptimizeSubgraphView passing in the ModelOptions. Signed-off-by: Keith Davis Signed-off-by: Mike Kelly Signed-off-by: Teresa Charlin Change-Id: Ib536ac3cbafc7d9b35c139ad9a65b7735262cd9d --- src/backends/neon/NeonBackend.cpp | 246 +++++++++++++++++++++++++++++++++++++- 1 file changed, 245 insertions(+), 1 deletion(-) (limited to 'src/backends/neon/NeonBackend.cpp') diff --git a/src/backends/neon/NeonBackend.cpp b/src/backends/neon/NeonBackend.cpp index 9862ddbd70..150bc345db 100644 --- a/src/backends/neon/NeonBackend.cpp +++ b/src/backends/neon/NeonBackend.cpp @@ -11,7 +11,10 @@ #include "NeonTensorHandleFactory.hpp" #include +#include +#include +#include #include #include @@ -19,8 +22,18 @@ #include +#include "workloads/NeonAdditionWorkload.hpp" +#include "workloads/NeonBatchNormalizationWorkload.hpp" +#include "workloads/NeonConvolution2dWorkload.hpp" +#include "workloads/NeonDepthwiseConvolutionWorkload.hpp" +#include "workloads/NeonDivisionWorkload.hpp" +#include "workloads/NeonFullyConnectedWorkload.hpp" +#include "workloads/NeonMultiplicationWorkload.hpp" +#include "workloads/NeonSubtractionWorkload.hpp" + #include +#include #include namespace armnn @@ -122,7 +135,238 @@ OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph { OptimizationViews optimizationViews; - optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph)); + auto it = subgraph.end(); + + while (it != subgraph.begin()) + { + --it; + Layer& base = **it; + + if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d + || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected + || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication + || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division) + && (base.GetAdditionalInformation() == nullptr)) + { + for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output) + { + if (output->GetNumConnections() == 1) + { + for (auto&& childInput : output->GetConnections()) + { + if (childInput->GetOwningLayer().GetType() == LayerType::Activation) + { + Layer& child = childInput->GetOwningLayer(); + + auto* activationLayer = PolymorphicDowncast(&child); + + const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") + + base.GetName(); + + // Get params from activation layer + ActivationDescriptor activationDesc = activationLayer->GetParameters(); + + if (base.GetType() == LayerType::Convolution2d) + { + Convolution2dLayer* baseLayer = PolymorphicDowncast(&base); + + Optional biases; + + if (baseLayer->GetParameters().m_BiasEnabled) + { + biases = GetOverriddenDataType(baseLayer->m_Bias->GetTensorInfo(), + GetOptionalBiasTypeFromWeightsType( + baseLayer->m_Weight->GetTensorInfo().GetDataType())); + } + + arm_compute::Status status = NeonConvolution2dWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetParameters(), + baseLayer->m_Weight->GetTensorInfo(), + biases, + false, + &activationDesc); + + if (status) + { + FuseLayerWithWeightsAndBiases(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::DepthwiseConvolution2d) + { + DepthwiseConvolution2dLayer* baseLayer = + PolymorphicDowncast(&base); + + Optional biases; + + if (baseLayer->GetParameters().m_BiasEnabled) + { + biases = GetOverriddenDataType(baseLayer->m_Bias->GetTensorInfo(), + GetOptionalBiasTypeFromWeightsType( + baseLayer->m_Weight->GetTensorInfo().GetDataType())); + } + + arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetParameters(), + baseLayer->m_Weight->GetTensorInfo(), + biases, + &activationDesc); + + if (status) + { + FuseLayerWithWeightsAndBiases(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::FullyConnected) + { + FullyConnectedLayer* baseLayer = PolymorphicDowncast(&base); + + arm_compute::Status status = NeonFullyConnectedWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->m_Weight->GetTensorInfo(), + baseLayer->m_Bias->GetTensorInfo(), + baseLayer->GetParameters(), + &activationDesc); + + if (status) + { + FuseLayerWithWeightsAndBiases(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::BatchNormalization) + { + BatchNormalizationLayer* baseLayer = + PolymorphicDowncast(&base); + + arm_compute::Status status = NeonBatchNormalizationValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->m_Mean->GetTensorInfo(), + baseLayer->m_Variance->GetTensorInfo(), + baseLayer->m_Beta->GetTensorInfo(), + baseLayer->m_Gamma->GetTensorInfo(), + baseLayer->GetParameters(), + &activationDesc); + + if (status) + { + BatchNormalizationLayer* replacementLayer = + FuseLayerWithParameters( + optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + + replacementLayer->m_Beta = std::move(baseLayer->m_Beta); + replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma); + replacementLayer->m_Mean = std::move(baseLayer->m_Mean); + replacementLayer->m_Variance = std::move(baseLayer->m_Variance); + } + } + else if (base.GetType() == LayerType::Addition) + { + AdditionLayer* baseLayer = PolymorphicDowncast(&base); + + arm_compute::Status status = NeonAdditionWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + &activationDesc); + + if (status) + { + FuseLayerWithoutParameters(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::Division) + { + DivisionLayer* baseLayer = PolymorphicDowncast(&base); + + arm_compute::Status status = NeonDivisionWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + &activationDesc); + + if (status) + { + FuseLayerWithoutParameters(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::Multiplication) + { + MultiplicationLayer* baseLayer = PolymorphicDowncast(&base); + + arm_compute::Status status = NeonMultiplicationWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + &activationDesc); + + if (status) + { + FuseLayerWithoutParameters(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + else if (base.GetType() == LayerType::Subtraction) + { + SubtractionLayer* baseLayer = PolymorphicDowncast(&base); + + arm_compute::Status status = NeonSubtractionWorkloadValidate( + baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(), + activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(), + &activationDesc); + + if (status) + { + FuseLayerWithoutParameters(optimizationViews, + baseLayer, + activationLayer, + activationDesc, + name); + } + } + } + } + } + } + } + } + + if (optimizationViews.GetSubstitutions().empty()) + { + optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph)); + } return optimizationViews; } -- cgit v1.2.1