1 // 2 // Copyright © 2017 Arm Ltd. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #pragma once 7 8 #include "Optimization.hpp" 9 10 #include <armnn/utility/PolymorphicDowncast.hpp> 11 12 namespace armnn 13 { 14 namespace optimizations 15 { 16 17 class FoldPadIntoConvolution2dImpl 18 { 19 public: 20 Run(Graph & graph,InputSlot & connection) const21 void Run(Graph& graph, InputSlot& connection) const 22 { 23 Layer& base = connection.GetConnectedOutputSlot()->GetOwningLayer(); 24 Layer& child = connection.GetOwningLayer(); 25 26 ARMNN_ASSERT(base.GetType() == LayerType::Pad); 27 ARMNN_ASSERT(child.GetType() == LayerType::Convolution2d); 28 29 PadLayer* padLayer = PolymorphicDowncast<PadLayer*>(&base); 30 Convolution2dLayer* convolution2dLayer = PolymorphicDowncast<Convolution2dLayer*>(&child); 31 32 OutputSlot* parentOut = base.GetInputSlot(0).GetConnectedOutputSlot(); 33 34 const std::string name = std::string("folded-") + base.GetName() + std::string("-into-") + child.GetName(); 35 Convolution2dDescriptor descriptor = convolution2dLayer->GetParameters(); 36 37 auto padList = padLayer->GetParameters().m_PadList; 38 39 armnn::DataLayout dataLayout = descriptor.m_DataLayout; 40 41 // In Convolution2dDescriptor, padLeft and padRight are defined as paddings on width dimension 42 // whereas padTop and padBottom - paddings on height dimension, so setting these according to data layout 43 if(dataLayout == armnn::DataLayout::NHWC) 44 { 45 descriptor.m_PadLeft = padList[2].first; 46 descriptor.m_PadRight = padList[2].second; 47 descriptor.m_PadTop = padList[1].first; 48 descriptor.m_PadBottom = padList[1].second; 49 } 50 else 51 { 52 descriptor.m_PadLeft = padList[3].first; 53 descriptor.m_PadRight = padList[3].second; 54 descriptor.m_PadTop = padList[2].first; 55 descriptor.m_PadBottom = padList[2].second; 56 } 57 58 auto& newConv2dLayer = *graph.InsertNewLayer<Convolution2dLayer>(base.GetInputSlot(0), 59 descriptor, 60 name.c_str()); 61 62 // Copy weights and bias to the new convolution layer 63 ARMNN_ASSERT_MSG(convolution2dLayer->m_Weight != nullptr, 64 "FoldPadIntoConvolution2d: Weights data should not be null."); 65 newConv2dLayer.m_Weight = std::move(convolution2dLayer->m_Weight); 66 if (descriptor.m_BiasEnabled) 67 { 68 ARMNN_ASSERT_MSG(convolution2dLayer->m_Bias != nullptr, 69 "FoldPadIntoConvolution2d: Bias data should not be null if bias is enabled."); 70 newConv2dLayer.m_Bias = std::move(convolution2dLayer->m_Bias); 71 } 72 73 // Reconnects with original parent. 74 newConv2dLayer.GetOutputSlot().MoveAllConnections(*parentOut); 75 // Parent is now the new convolution2d layer. 76 parentOut = &newConv2dLayer.GetOutputSlot(); 77 78 // Moves connections in child output to parent layer. 79 // Child layer will be removed as it's left unconnected. 80 // Base layer will be removed if left unconnected. 81 child.GetOutputSlot().MoveAllConnections(*parentOut); 82 } 83 protected: 84 FoldPadIntoConvolution2dImpl() = default; 85 ~FoldPadIntoConvolution2dImpl() = default; 86 }; 87 88 using FoldPadIntoConvolution2d = OptimizeForConnection<PadLayer, Convolution2dLayer, FoldPadIntoConvolution2dImpl>; 89 90 } // namespace optimizations 91 } // namespace armnn 92 93 94