blob: b2a2ba43ed998336b9b8a3750e42babb15e2d6ce [file] [log] [blame]
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//
#pragma once
#include "Optimization.hpp"
namespace armnn
{
namespace optimizations
{
class FoldPadIntoConvolution2dImpl
{
public:
void Run(Graph& graph, InputSlot& connection) const
{
Layer& base = connection.GetConnectedOutputSlot()->GetOwningLayer();
Layer& child = connection.GetOwningLayer();
BOOST_ASSERT(base.GetType() == LayerType::Pad);
BOOST_ASSERT(child.GetType() == LayerType::Convolution2d);
PadLayer* padLayer = boost::polymorphic_downcast<PadLayer*>(&base);
Convolution2dLayer* convolution2dLayer = boost::polymorphic_downcast<Convolution2dLayer*>(&child);
OutputSlot* parentOut = base.GetInputSlot(0).GetConnectedOutputSlot();
const TensorInfo& outInfo = child.GetOutputHandler().GetTensorInfo();
const std::string name = std::string("folded-") + base.GetName() + std::string("-into-") + child.GetName();
Convolution2dDescriptor descriptor = convolution2dLayer->GetParameters();
auto padList = padLayer->GetParameters().m_PadList;
armnn::DataLayout dataLayout = descriptor.m_DataLayout;
// In Convolution2dDescriptor, padLeft and padRight are defined as paddings on width dimension
// whereas padTop and padBottom - paddings on height dimension, so setting these according to data layout
if(dataLayout == armnn::DataLayout::NHWC)
{
descriptor.m_PadLeft = padList[2].first;
descriptor.m_PadRight = padList[2].second;
descriptor.m_PadTop = padList[1].first;
descriptor.m_PadBottom = padList[1].second;
}
else
{
descriptor.m_PadLeft = padList[3].first;
descriptor.m_PadRight = padList[3].second;
descriptor.m_PadTop = padList[2].first;
descriptor.m_PadBottom = padList[2].second;
}
auto& newConv2dLayer = *graph.InsertNewLayer<Convolution2dLayer>(base.GetInputSlot(0),
descriptor,
name.c_str());
newConv2dLayer.GetOutputHandler().SetTensorInfo(outInfo);
// Copy weights and bias to the new convolution layer
BOOST_ASSERT_MSG(convolution2dLayer->m_Weight != nullptr,
"FoldPadIntoConvolution2d: Weights data should not be null.");
newConv2dLayer.m_Weight = std::move(convolution2dLayer->m_Weight);
if (descriptor.m_BiasEnabled)
{
BOOST_ASSERT_MSG(convolution2dLayer->m_Bias != nullptr,
"FoldPadIntoConvolution2d: Bias data should not be null if bias is enabled.");
newConv2dLayer.m_Bias = std::move(convolution2dLayer->m_Bias);
}
// Reconnects with original parent.
newConv2dLayer.GetOutputSlot().MoveAllConnections(*parentOut);
// Parent is now the new convolution2d layer.
parentOut = &newConv2dLayer.GetOutputSlot();
// Moves connections in child output to parent layer.
// Child layer will be removed as it's left unconnected.
// Base layer will be removed if left unconnected.
child.GetOutputSlot().MoveAllConnections(*parentOut);
}
protected:
FoldPadIntoConvolution2dImpl() = default;
~FoldPadIntoConvolution2dImpl() = default;
};
using FoldPadIntoConvolution2d = OptimizeForConnection<PadLayer, Convolution2dLayer, FoldPadIntoConvolution2dImpl>;
} // namespace optimizations
} // namespace armnn