From: 채성우/On-Device Lab(SR)/Engineer/삼성전자 Date: Thu, 1 Aug 2019 01:50:47 +0000 (+0000) Subject: [moco/tf] Introduce DepthwiseConv2D Canonicalizer (#6047) X-Git-Tag: submit/tizen/20190809.050447~280 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ba3d675ac7aff90b8bd1b3d9124b81ec42e1bf88;p=platform%2Fcore%2Fml%2Fnnfw.git [moco/tf] Introduce DepthwiseConv2D Canonicalizer (#6047) * [moco/tf] Introduce DepthwiseConv2D Canonicalizer This commit introcude DepthwiseConv2D Canonicalizer to moco-tf. Signed-off-by: seongwoo * apply comment. * add codes for log. --- diff --git a/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp new file mode 100644 index 0000000..10d33c5 --- /dev/null +++ b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. 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 "DepthwiseConv2dNativeCanonicalizer.h" + +#include "Annotations/PadData.h" +#include "Annotations/ShapeInferenceData.h" +#include "Annotations/StrideData.h" + +#include "Dialect/TFDialect.h" +#include "Dialect/TFNodes.h" +#include "Dialect/TFNodeVisitor.h" +#include "Dialect/TFNodeImpl.h" + +#include +#include + +#include + +namespace +{ + +using plier::tf::DataLayout; + +void set_feature_enc(loco::FeatureEncode *feature_enc, DataLayout data_layout) +{ + auto enc = stdex::make_unique>(); + + if (data_layout == DataLayout::NHWC) + { + enc->perm()->axis(loco::FeatureAxis::Count) = 0; + enc->perm()->axis(loco::FeatureAxis::Height) = 1; + enc->perm()->axis(loco::FeatureAxis::Width) = 2; + enc->perm()->axis(loco::FeatureAxis::Depth) = 3; + } + else if (data_layout == DataLayout::NCHW) + { + enc->perm()->axis(loco::FeatureAxis::Count) = 0; + enc->perm()->axis(loco::FeatureAxis::Depth) = 1; + enc->perm()->axis(loco::FeatureAxis::Height) = 2; + enc->perm()->axis(loco::FeatureAxis::Width) = 3; + } + + feature_enc->encoder(std::move(enc)); +} + +void set_filter_enc(loco::DepthwiseFilterEncode *filter_enc) +{ + auto enc = stdex::make_unique>(); + + // In TensorFlow, depthwiseconv2dnative filter is a 4-D tensor of following shape: + // [filter_height, filter_width, in_channels, channel_multiplier] -> HWCM + enc->perm()->axis(loco::DepthwiseFilterAxis::Height) = 0; + enc->perm()->axis(loco::DepthwiseFilterAxis::Width) = 1; + enc->perm()->axis(loco::DepthwiseFilterAxis::Depth) = 2; + enc->perm()->axis(loco::DepthwiseFilterAxis::Multiplier) = 3; + + filter_enc->encoder(std::move(enc)); +} + +void set_feature_dec(loco::FeatureDecode *feature_dec, DataLayout data_layout) +{ + auto dec = stdex::make_unique>(); + + if (data_layout == DataLayout::NHWC) + { + dec->perm()->axis(loco::FeatureAxis::Count) = 0; + dec->perm()->axis(loco::FeatureAxis::Height) = 1; + dec->perm()->axis(loco::FeatureAxis::Width) = 2; + dec->perm()->axis(loco::FeatureAxis::Depth) = 3; + } + else if (data_layout == DataLayout::NCHW) + { + dec->perm()->axis(loco::FeatureAxis::Count) = 0; + dec->perm()->axis(loco::FeatureAxis::Depth) = 1; + dec->perm()->axis(loco::FeatureAxis::Height) = 2; + dec->perm()->axis(loco::FeatureAxis::Width) = 3; + } + + feature_dec->decoder(std::move(dec)); +} + +bool canonicalize_depthwiseconv2dnative(loco::Graph *graph, moco::tf::TFDepthwiseConv2dNative *node) +{ + LOGGER(l); + + /** + * @note This will replace TFDepthwiseConv2dNative node with Canonical FeatureEncode + + * DepthwiseFilterEncode + DepthwiseConv2D + FeatureDecode + * + * Before + * A -+- TFDepthwiseConv2dNative - C + * | + * B -+ + * + * After + * + * A -+ FeatureEncode ----------------+- DepthwiseConv2D - FeatureDecode - C + * | | + * +-(TFDepthwiseConv2dNative) | + * | | + * B -+ DepthwiseFilterEncode --------+ + * + * Where + * A : ifm of TFDepthwiseConv2dNative + * B : ker of TFDepthwiseConv2dNative + * C : a node that uses TFDepthwiseConv2dNative as an input + * TFDepthwiseConv2dNative is disconnected from other nodes + */ + + INFO(l) << "TFNodeCanonicalize TFDepthwiseConv2dNative begin"; + + auto data_layout = plier::tf::as_data_layout(node->data_layout()); + + auto feature_enc = graph->nodes()->create(); + auto filter_enc = graph->nodes()->create(); + auto depthwiseconv2d = graph->nodes()->create(); + auto feature_dec = graph->nodes()->create(); + + set_feature_enc(feature_enc, data_layout); + set_filter_enc(filter_enc); + set_feature_dec(feature_dec, data_layout); + + // Set DetphwiseConv2D attributes from TFDepthwiseConv2dNative + auto pad_data = node->annot(); + assert(pad_data != nullptr); + + depthwiseconv2d->pad()->top(pad_data->pad()->top()); + depthwiseconv2d->pad()->bottom(pad_data->pad()->bottom()); + depthwiseconv2d->pad()->left(pad_data->pad()->left()); + depthwiseconv2d->pad()->right(pad_data->pad()->right()); + + auto stride_data = node->annot(); + assert(stride_data != nullptr); + + depthwiseconv2d->stride()->vertical(stride_data->stride()->vertical()); + depthwiseconv2d->stride()->horizontal(stride_data->stride()->horizontal()); + + // update graph + auto node_A = node->ifm(); + auto node_B = node->ker(); + + // update connections + feature_enc->input(node_A); + filter_enc->input(node_B); + depthwiseconv2d->ifm(feature_enc); + depthwiseconv2d->ker(filter_enc); + feature_dec->input(depthwiseconv2d); + + // replace and disconnect old node + replace(node).with(feature_dec); + + INFO(l) << "TFNodeCanonicalize TFDepthwiseConv2dNative done"; + + return true; +} + +} // namespace + +namespace moco +{ +namespace tf +{ + +bool DepthwiseConv2dNativeCanonicalizer::run(loco::Graph *graph) +{ + auto active_nodes = loco::active_nodes(loco::output_nodes(graph)); + bool changed = false; + + for (auto node : active_nodes) + { + if (node->dialect() == TFDialect::get()) + { + auto tf_node = dynamic_cast(node); + if (tf_node != nullptr) + { + if (canonicalize_depthwiseconv2dnative(graph, tf_node)) + changed = true; + } + } + } + + return changed; +} + +} // namespace tf +} // namespace moco diff --git a/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.h new file mode 100644 index 0000000..9bb8c5a --- /dev/null +++ b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. 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. + */ + +#ifndef __MOCO_TF_DEPTHWISE_CONV2D_NATIVE_CANONICALIZER_H__ +#define __MOCO_TF_DEPTHWISE_CONV2D_NATIVE_CANONICALIZER_H__ + +#include "Transform.h" + +namespace moco +{ +namespace tf +{ + +/** + * @brief Convert TFDepthwiseConv2dNative to Canonical DepthwiseConv2D + */ +class DepthwiseConv2dNativeCanonicalizer : public Transform +{ +public: + const char *name(void) const final { return "DepthwiseConv2dNativeCanonicalizer"; } + +public: + bool run(loco::Graph *graph) override; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_DEPTHWISE_CONV2D_NATIVE_CANONICALIZER_H__ diff --git a/compiler/moco-tf/src/Canonicalizer.cpp b/compiler/moco-tf/src/Canonicalizer.cpp index f56e27e..56c3aa6 100644 --- a/compiler/moco-tf/src/Canonicalizer.cpp +++ b/compiler/moco-tf/src/Canonicalizer.cpp @@ -24,6 +24,7 @@ #include "Canonicalization/BiasAddCanonicalizer.h" #include "Canonicalization/ConstCanonicalizer.h" #include "Canonicalization/Conv2DCanonicalizer.h" +#include "Canonicalization/DepthwiseConv2dNativeCanonicalizer.h" #include "Canonicalization/IdentityCanonicalizer.h" #include "Canonicalization/MaxPoolCanonicalizer.h" @@ -69,6 +70,7 @@ void Canonicalizer::canonicalize(loco::Graph *g) const phase.emplace_back(stdex::make_unique()); phase.emplace_back(stdex::make_unique()); phase.emplace_back(stdex::make_unique()); + phase.emplace_back(stdex::make_unique()); phase.emplace_back(stdex::make_unique()); phase.emplace_back(stdex::make_unique()); /* TRANSFORM DECLARATION END */