conv_elementwise_add2_act_fuse_pass.cc 4.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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_elementwise_add2_act_fuse_pass.h"
15

16
#include <string>
17

H
haozech 已提交
18
#include "paddle/fluid/framework/op_version_registry.h"
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

namespace paddle {
namespace framework {
namespace ir {

#define GET_IR_NODE(node__) GET_IR_NODE_FROM_SUBGRAPH(node__, node__, pattern);
#define GET_NODES                      \
  GET_IR_NODE(conv_op);                \
  GET_IR_NODE(conv_out);               \
  GET_IR_NODE(conv_filter);            \
  GET_IR_NODE(elementwise_add_op);     \
  GET_IR_NODE(elementwise_add_in_y);   \
  GET_IR_NODE(elementwise_add_out);    \
  GET_IR_NODE(elementwise_add_op_1);   \
  GET_IR_NODE(elementwise_add_in_y_1); \
  GET_IR_NODE(elementwise_add_out_1);  \
  GET_IR_NODE(act_op);                 \
  GET_IR_NODE(act_out);

T
tianshuo78520a 已提交
38
// Inherient the basic information from `base_desc`, and modify some fields.
39 40 41 42 43 44
framework::proto::OpDesc PrepareOpDesc(
    const framework::proto::OpDesc& base_desc, const std::string& bias,
    const std::string& bias1, const std::string& activation,
    const std::string& output) {
  auto proto = base_desc;
  framework::OpDesc desc(proto, nullptr);
H
hjchen2 已提交
45
  desc.SetType("conv2d_fusion");
46 47 48 49 50
  desc.SetInput("Bias", {bias});
  desc.SetInput("ResidualData", {bias1});
  desc.SetAttr("activation", activation);
  desc.SetOutput("Output", {output});
  desc.SetAttr("is_test", true);
H
hjchen2 已提交
51 52
  desc.SetAttr("use_cudnn", false);
  desc.Flush();
53 54 55
  return *desc.Proto();
}

56
void ConvElementwiseAdd2ActFusePass::ApplyImpl(ir::Graph* graph) const {
H
hjchen2 已提交
57
  const std::string pattern_name = "conv_elementwise_add2_act_fuse";
58
  FusePassBase::Init(pattern_name, graph);
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

  GraphPatternDetector gpd;
  auto* x = gpd.mutable_pattern()->NewNode("x")->AsInput()->assert_is_op_input(
      "conv2d", "Input");

  patterns::ConvElementwiseadd2Act pattern(gpd.mutable_pattern(), pattern_name);
  pattern(x);

  auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph,
                     Graph* g) {
    GET_NODES;

    auto base_op_desc = *conv_op->Op()->Proto();
    std::string bias_name = elementwise_add_in_y->Name();
    std::string bias1_name = elementwise_add_in_y_1->Name();
    std::string act_op_type = act_op->Op()->Type();
    std::string act_op_out = act_out->Name();

77 78 79 80 81 82 83 84 85 86 87
    auto elementwise_add_out_shape = elementwise_add_out->Var()->GetShape();
    auto add_in_y_1_shape = elementwise_add_in_y_1->Var()->GetShape();

    if (elementwise_add_out_shape != add_in_y_1_shape) {
      VLOG(3)
          << "The inputs X and Y's shapes of elementwise_add op are different.";
      VLOG(3) << "conv_elementwise_add2_act_fuse_pass doesn't support this "
                 "pattern. Fusion will not apply.";
      return;
    }

88 89 90 91 92
    auto new_op_proto = PrepareOpDesc(base_op_desc, bias_name, bias1_name,
                                      act_op_type, act_op_out);
    framework::OpDesc new_op_desc(new_op_proto, nullptr);

    // Create a new node for the fused op.
H
hjchen2 已提交
93
    auto* new_conv_op = graph->CreateOpNode(&new_op_desc);
94 95

    // Link inputs and outputs.
96 97 98
    PADDLE_ENFORCE_NE(
        subgraph.count(x), 0,
        platform::errors::NotFound("Detector did not find input x of conv2d."));
99 100
    auto* conv_in_node = subgraph.at(x);

H
hjchen2 已提交
101 102 103 104 105
    IR_NODE_LINK_TO(conv_in_node, new_conv_op);            // Input
    IR_NODE_LINK_TO(conv_filter, new_conv_op);             // Filter
    IR_NODE_LINK_TO(elementwise_add_in_y, new_conv_op);    // Bias
    IR_NODE_LINK_TO(elementwise_add_in_y_1, new_conv_op);  // Bias
    IR_NODE_LINK_TO(new_conv_op, act_out);                 // Output
106 107

    // Delete the unneeded nodes.
H
hjchen2 已提交
108
    GraphSafeRemoveNodes(
109 110
        graph, {conv_op, conv_out, elementwise_add_op, elementwise_add_op_1,
                elementwise_add_out, elementwise_add_out_1, act_op});
111
  };
112
  gpd(graph, handler);
113 114 115 116 117 118 119 120
}

}  // namespace ir
}  // namespace framework
}  // namespace paddle

REGISTER_PASS(conv_elementwise_add2_act_fuse_pass,
              paddle::framework::ir::ConvElementwiseAdd2ActFusePass);
H
haozech 已提交
121 122 123
REGISTER_PASS_CAPABILITY(conv_elementwise_add2_act_fuse_pass)
    .AddCombination(
        paddle::framework::compatible::OpVersionComparatorCombination()
124
            .LE("conv2d", 1)
125
            .LE("elementwise_add", 1)
H
haozech 已提交
126 127
            .EQ("relu", 0)
            .EQ("identity", 0));