commit
086f892225
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,222 @@
|
|||||||
|
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "paddle/fluid/framework/ir/conv_affine_channel_fuse_pass.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "paddle/fluid/framework/lod_tensor.h"
|
||||||
|
#include "paddle/fluid/operators/math/cpu_vec.h"
|
||||||
|
#include "paddle/fluid/platform/enforce.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace framework {
|
||||||
|
namespace ir {
|
||||||
|
|
||||||
|
#define GET_CONV_BN_NODES(pattern_name) \
|
||||||
|
/* OPERATORS */ \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(conv, conv, pattern_name); \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(affine_channel, affine_channel, pattern_name); \
|
||||||
|
/* CONV inputs */ \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(conv_weight, conv_weight, pattern_name); \
|
||||||
|
/* CONV outputs */ \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(conv_out, conv_out, pattern_name); \
|
||||||
|
/* Affine Channel inputs */ \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(ac_scale, ac_scale, pattern_name); \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(ac_bias, ac_bias, pattern_name); \
|
||||||
|
/* Affine channel outputs */ \
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(ac_out, ac_out, pattern_name); /* Out */
|
||||||
|
|
||||||
|
void recompute_bias_and_weights(const Scope* scope, ir::Node* conv_weight,
|
||||||
|
const ir::Node& ac_scale,
|
||||||
|
const LoDTensor& ac_bias_tensor,
|
||||||
|
LoDTensor* eltwise_y_in_tensor) {
|
||||||
|
using EigenVectorArrayMap =
|
||||||
|
Eigen::Map<Eigen::Array<float, Eigen::Dynamic, 1>>;
|
||||||
|
using ConstEigenVectorArrayMap =
|
||||||
|
Eigen::Map<const Eigen::Array<float, Eigen::Dynamic, 1>>;
|
||||||
|
using EigenMatrixArrayMap = Eigen::Map<
|
||||||
|
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>;
|
||||||
|
|
||||||
|
// Re-compute bias of conv2d from AffineChannel
|
||||||
|
PADDLE_ENFORCE_EQ(eltwise_y_in_tensor->dims(), ac_bias_tensor.dims());
|
||||||
|
|
||||||
|
auto* scale_tensor = scope->FindVar(ac_scale.Name())->GetMutable<LoDTensor>();
|
||||||
|
|
||||||
|
ConstEigenVectorArrayMap scale_array(scale_tensor->data<float>(),
|
||||||
|
scale_tensor->numel(), 1);
|
||||||
|
ConstEigenVectorArrayMap ac_bias_array(ac_bias_tensor.data<float>(),
|
||||||
|
ac_bias_tensor.numel(), 1);
|
||||||
|
|
||||||
|
EigenVectorArrayMap eltwise_y_in_array(
|
||||||
|
eltwise_y_in_tensor->mutable_data<float>(platform::CPUPlace()),
|
||||||
|
eltwise_y_in_tensor->numel(), 1);
|
||||||
|
|
||||||
|
eltwise_y_in_array = (eltwise_y_in_array * scale_array) + ac_bias_array;
|
||||||
|
|
||||||
|
// Re-compute weight of conv2d from AffineChannel
|
||||||
|
auto* weights = scope->FindVar(conv_weight->Name())->GetMutable<LoDTensor>();
|
||||||
|
auto weights_shape = weights->dims();
|
||||||
|
auto weights_shape_2d = flatten_to_2d(weights_shape, 1);
|
||||||
|
|
||||||
|
EigenMatrixArrayMap weights_array_2d(
|
||||||
|
weights->mutable_data<float>(platform::CPUPlace()), weights_shape_2d[0],
|
||||||
|
weights_shape_2d[1]);
|
||||||
|
|
||||||
|
weights_array_2d.colwise() *= scale_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ir::Graph> ConvAffineChannelFusePass::ApplyImpl(
|
||||||
|
std::unique_ptr<ir::Graph> graph) const {
|
||||||
|
PADDLE_ENFORCE(graph.get());
|
||||||
|
FusePassBase::Init(name_scope_, graph.get());
|
||||||
|
|
||||||
|
auto* scope = param_scope();
|
||||||
|
PADDLE_ENFORCE(scope);
|
||||||
|
|
||||||
|
GraphPatternDetector gpd;
|
||||||
|
auto* conv_input =
|
||||||
|
gpd.mutable_pattern()
|
||||||
|
->NewNode(patterns::PDNodeName(name_scope_, "conv_input"))
|
||||||
|
->AsInput()
|
||||||
|
->assert_is_op_input("conv2d", "Input");
|
||||||
|
patterns::ConvAffineChannel conv_ac_pattern(gpd.mutable_pattern(),
|
||||||
|
name_scope_);
|
||||||
|
conv_ac_pattern(conv_input, false /*with_eltwise_add*/);
|
||||||
|
|
||||||
|
int found_conv_ac_count = 0;
|
||||||
|
auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph,
|
||||||
|
Graph* g) {
|
||||||
|
VLOG(4) << "handle ConvAffineChannel fuse";
|
||||||
|
|
||||||
|
GET_CONV_BN_NODES(conv_ac_pattern);
|
||||||
|
|
||||||
|
// check if fuse can be done and if MKL-DNN should be used
|
||||||
|
FuseOptions fuse_option = FindFuseOption(*conv, *affine_channel);
|
||||||
|
if (fuse_option == DO_NOT_FUSE) {
|
||||||
|
VLOG(3) << "do not perform conv+affinechannel fuse";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create eltwise_y (conv bias) variable
|
||||||
|
VarDesc eltwise_y_in_desc(
|
||||||
|
patterns::PDNodeName(name_scope_, "eltwise_y_in"));
|
||||||
|
eltwise_y_in_desc.SetPersistable(true);
|
||||||
|
auto* eltwise_y_in_node = g->CreateVarNode(&eltwise_y_in_desc);
|
||||||
|
auto* eltwise_y_in_tensor =
|
||||||
|
scope->Var(eltwise_y_in_node->Name())->GetMutable<LoDTensor>();
|
||||||
|
|
||||||
|
// Get affine_channel bias
|
||||||
|
auto* ac_bias_tensor =
|
||||||
|
scope->FindVar(ac_bias->Name())->GetMutable<LoDTensor>();
|
||||||
|
|
||||||
|
// Initialize eltwise_y
|
||||||
|
eltwise_y_in_tensor->Resize(ac_bias_tensor->dims());
|
||||||
|
std::fill_n(eltwise_y_in_tensor->mutable_data<float>(platform::CPUPlace()),
|
||||||
|
eltwise_y_in_tensor->numel(), 0.0f);
|
||||||
|
|
||||||
|
// update weights and biases
|
||||||
|
recompute_bias_and_weights(scope, conv_weight, *ac_scale, *ac_bias_tensor,
|
||||||
|
eltwise_y_in_tensor);
|
||||||
|
|
||||||
|
// create an elementwise add node.
|
||||||
|
OpDesc desc;
|
||||||
|
desc.SetInput("X", std::vector<std::string>({conv_out->Name()}));
|
||||||
|
desc.SetInput("Y", std::vector<std::string>({eltwise_y_in_node->Name()}));
|
||||||
|
desc.SetOutput("Out", std::vector<std::string>({ac_out->Name()}));
|
||||||
|
desc.SetType("elementwise_add");
|
||||||
|
desc.SetAttr("axis", 1);
|
||||||
|
auto eltwise_op = g->CreateOpNode(&desc); // OpDesc will be copied.
|
||||||
|
|
||||||
|
GraphSafeRemoveNodes(graph.get(), {ac_scale, ac_bias, affine_channel});
|
||||||
|
|
||||||
|
IR_NODE_LINK_TO(conv_out, eltwise_op);
|
||||||
|
IR_NODE_LINK_TO(eltwise_y_in_node, eltwise_op);
|
||||||
|
IR_NODE_LINK_TO(eltwise_op, ac_out);
|
||||||
|
found_conv_ac_count++;
|
||||||
|
};
|
||||||
|
|
||||||
|
gpd(graph.get(), handler);
|
||||||
|
|
||||||
|
AddStatis(found_conv_ac_count);
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ir::Graph> ConvEltwiseAddAffineChannelFusePass::ApplyImpl(
|
||||||
|
std::unique_ptr<ir::Graph> graph) const {
|
||||||
|
PADDLE_ENFORCE(graph.get());
|
||||||
|
FusePassBase::Init(name_scope_, graph.get());
|
||||||
|
|
||||||
|
auto* scope = param_scope();
|
||||||
|
PADDLE_ENFORCE(scope);
|
||||||
|
|
||||||
|
GraphPatternDetector gpd;
|
||||||
|
auto* conv_input =
|
||||||
|
gpd.mutable_pattern()
|
||||||
|
->NewNode(patterns::PDNodeName(name_scope_, "conv_input"))
|
||||||
|
->AsInput()
|
||||||
|
->assert_is_op_input("conv2d", "Input");
|
||||||
|
patterns::ConvAffineChannel conv_ac_pattern(gpd.mutable_pattern(),
|
||||||
|
name_scope_);
|
||||||
|
conv_ac_pattern(conv_input, true /*with_eltwise_add*/);
|
||||||
|
|
||||||
|
int found_conv_ac_count = 0;
|
||||||
|
auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph,
|
||||||
|
Graph* g) {
|
||||||
|
VLOG(4) << "handle ConvBN fuse";
|
||||||
|
|
||||||
|
GET_CONV_BN_NODES(conv_ac_pattern);
|
||||||
|
// OPERATORS
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(eltwise, eltwise, conv_ac_pattern);
|
||||||
|
// BIAS inputs
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(eltwise_y_in, eltwise_y_in, conv_ac_pattern);
|
||||||
|
// BIAS outputs
|
||||||
|
GET_IR_NODE_FROM_SUBGRAPH(eltwise_out, eltwise_out, conv_ac_pattern);
|
||||||
|
|
||||||
|
// Get eltwise_y (conv bias) variable
|
||||||
|
auto* eltwise_y_in_tensor =
|
||||||
|
scope->FindVar(eltwise_y_in->Name())->GetMutable<LoDTensor>();
|
||||||
|
|
||||||
|
// Get batch norm bias
|
||||||
|
auto* ac_bias_tensor =
|
||||||
|
scope->FindVar(ac_bias->Name())->GetMutable<LoDTensor>();
|
||||||
|
|
||||||
|
recompute_bias_and_weights(scope, conv_weight, *ac_scale, *ac_bias_tensor,
|
||||||
|
eltwise_y_in_tensor);
|
||||||
|
|
||||||
|
// Update the elementwise_add node
|
||||||
|
eltwise->Op()->SetAttr("axis", 1);
|
||||||
|
eltwise->Op()->SetOutput("Out", std::vector<std::string>({ac_out->Name()}));
|
||||||
|
|
||||||
|
GraphSafeRemoveNodes(graph.get(),
|
||||||
|
{ac_scale, ac_bias, affine_channel, eltwise_out});
|
||||||
|
|
||||||
|
IR_NODE_LINK_TO(eltwise, ac_out);
|
||||||
|
|
||||||
|
found_conv_ac_count++;
|
||||||
|
};
|
||||||
|
|
||||||
|
gpd(graph.get(), handler);
|
||||||
|
AddStatis(found_conv_ac_count);
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ir
|
||||||
|
} // namespace framework
|
||||||
|
} // namespace paddle
|
||||||
|
|
||||||
|
REGISTER_PASS(conv_affine_channel_fuse_pass,
|
||||||
|
paddle::framework::ir::ConvAffineChannelFusePass);
|
||||||
|
REGISTER_PASS(conv_eltwiseadd_affine_channel_fuse_pass,
|
||||||
|
paddle::framework::ir::ConvEltwiseAddAffineChannelFusePass);
|
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "paddle/fluid/framework/ir/fuse_pass_base.h"
|
||||||
|
#include "paddle/fluid/framework/ir/graph.h"
|
||||||
|
#include "paddle/fluid/framework/ir/graph_pattern_detector.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace framework {
|
||||||
|
namespace ir {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fuse the Conv and ConvAffineChannel.
|
||||||
|
*/
|
||||||
|
class ConvAffineChannelFusePass : public FusePassBase {
|
||||||
|
public:
|
||||||
|
virtual ~ConvAffineChannelFusePass() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<ir::Graph> ApplyImpl(std::unique_ptr<ir::Graph> graph) const;
|
||||||
|
const std::string name_scope_{"conv_affine_channel_fuse"};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvEltwiseAddAffineChannelFusePass : public FusePassBase {
|
||||||
|
public:
|
||||||
|
virtual ~ConvEltwiseAddAffineChannelFusePass() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<ir::Graph> ApplyImpl(std::unique_ptr<ir::Graph> graph) const;
|
||||||
|
const std::string name_scope_{"conv_eltwiseadd_affine_channel_fuse"};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ir
|
||||||
|
} // namespace framework
|
||||||
|
} // namespace paddle
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue