2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "luci/Pass/FuseAddWithTConvPass.h"
19 #include <luci/IR/CircleNodes.h>
20 #include <luci/Profile/CircleNodeOrigin.h>
25 * Fuse Add to TransposeConv if possible
29 * [CircleConst] [CircleTransposeConv]
38 * [CircleTransposeConv] [CircleAdd]
40 * ([CircleRelu/Relu6])
43 * Note: CircleRelu/Relu6 is inserted if Add activation is ReLU6
45 bool fuse_add_with_tconv(luci::CircleTransposeConv *tconv)
47 // check whether it has bias or not. This optimization works only if it doesn't.
48 auto bias = dynamic_cast<luci::CircleOutputExclude *>(tconv->bias());
52 // get weight of tconv
53 auto filter = dynamic_cast<luci::CircleConst *>(tconv->filter());
56 if (filter->dtype() != loco::DataType::FLOAT32)
60 auto tconv_output = loco::succs(tconv);
61 assert(tconv_output.size() == 1);
62 auto add = dynamic_cast<luci::CircleAdd *>(*tconv_output.begin());
65 if (add->dtype() != loco::DataType::FLOAT32)
67 if (add->fusedActivationFunction() != luci::FusedActFunc::NONE &&
68 add->fusedActivationFunction() != luci::FusedActFunc::RELU6 &&
69 add->fusedActivationFunction() != luci::FusedActFunc::RELU)
73 luci::CircleConst *addition = nullptr;
74 if (add->x() == tconv)
75 addition = dynamic_cast<luci::CircleConst *>(add->y());
77 addition = dynamic_cast<luci::CircleConst *>(add->x());
82 // addition dim(0) == tconv filter channel dim
83 if (addition->rank() != 1)
85 auto addition_dim = addition->dim(0).value();
86 auto filter_channel_dim = filter->dim(0).value();
87 if (filter_channel_dim != addition_dim)
90 // fuse addition with transposed conv
91 tconv->bias(addition);
93 if (add->fusedActivationFunction() == luci::FusedActFunc::RELU6)
95 auto name = addition->name();
96 assert(name.length() > 0);
97 // separate relu op from add op
98 auto relu = add->graph()->nodes()->create<luci::CircleRelu6>();
99 relu->features(tconv);
100 relu->name(name + "/Relu6");
101 luci::add_origin(relu, luci::get_origin(add));
104 replace(add).with(relu);
106 else if (add->fusedActivationFunction() == luci::FusedActFunc::RELU)
108 auto name = addition->name();
109 assert(name.length() > 0);
110 // separate relu op from add op
111 auto relu = add->graph()->nodes()->create<luci::CircleRelu>();
112 relu->features(tconv);
113 relu->name(name + "/Relu");
114 luci::add_origin(relu, luci::get_origin(add));
117 replace(add).with(relu);
121 replace(add).with(tconv);
125 luci::add_origin(tconv, luci::get_origin(add));
135 bool FuseAddWithTConvPass::run(loco::Graph *g)
137 bool changed = false;
138 for (auto node : loco::active_nodes(loco::output_nodes(g)))
140 auto tconv = dynamic_cast<luci::CircleTransposeConv *>(node);
144 if (fuse_add_with_tconv(tconv))