• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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