summaryrefslogtreecommitdiff
path: root/compiler/moco-tf/src/Canonicalization
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2020-04-23 14:45:49 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2020-04-23 14:45:49 +0900
commite2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (patch)
tree44a1a7951d168dd4370e13593ed03f4bc6d920c5 /compiler/moco-tf/src/Canonicalization
parent302e6564a7a76109e1178207e44e45a58631c477 (diff)
downloadnnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.gz
nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.bz2
nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.zip
Imported Upstream version 1.4.0upstream/1.4.0submit/tizen/20200423.054851
Diffstat (limited to 'compiler/moco-tf/src/Canonicalization')
-rw-r--r--compiler/moco-tf/src/Canonicalization/AddCanonicalizer.cpp35
-rw-r--r--compiler/moco-tf/src/Canonicalization/AddCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.cpp114
-rw-r--r--compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.cpp109
-rw-r--r--compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.cpp160
-rw-r--r--compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.cpp127
-rw-r--r--compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.cpp371
-rw-r--r--compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.h45
-rw-r--r--compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.cpp132
-rw-r--r--compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp137
-rw-r--r--compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.h45
-rw-r--r--compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.cpp78
-rw-r--r--compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.cpp111
-rw-r--r--compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.cpp34
-rw-r--r--compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.cpp31
-rw-r--r--compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/MulCanonicalizer.cpp34
-rw-r--r--compiler/moco-tf/src/Canonicalization/MulCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/PadCanonicalizer.cpp100
-rw-r--r--compiler/moco-tf/src/Canonicalization/PadCanonicalizer.h45
-rw-r--r--compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.cpp102
-rw-r--r--compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.cpp34
-rw-r--r--compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.cpp70
-rw-r--r--compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.cpp70
-rw-r--r--compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.cpp169
-rw-r--r--compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.cpp150
-rw-r--r--compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.cpp78
-rw-r--r--compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.cpp68
-rw-r--r--compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.cpp86
-rw-r--r--compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.h49
-rw-r--r--compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.cpp71
-rw-r--r--compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/SubCanonicalizer.cpp34
-rw-r--r--compiler/moco-tf/src/Canonicalization/SubCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.cpp74
-rw-r--r--compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.h47
-rw-r--r--compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.cpp70
-rw-r--r--compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.h47
54 files changed, 3914 insertions, 0 deletions
diff --git a/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.cpp
new file mode 100644
index 000000000..8028a870c
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "AddCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/IR/TFNodes.h>
+
+#include "TFEltwiseBinaryCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool AddCanonicalizer::transform(TFAdd *node) const
+{
+ return canonicalize_eltwise_binary_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.h
new file mode 100644
index 000000000..53ba9ed58
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/AddCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_ADD_CANONICALIZER_H__
+#define __MOCO_TF_ADD_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFAdd to Canonical EltwiseAdd
+ */
+class AddCanonicalizer : public SimpleNodeTransform<TFAdd>
+{
+public:
+ const char *name(void) const final { return "AddCanonicalizer"; }
+
+public:
+ bool transform(TFAdd *node) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_ADD_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.cpp
new file mode 100644
index 000000000..e07a4f64f
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "AvgPoolCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include "CodecHelper.h"
+
+#include <loco/IR/NodeShape.h>
+
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_avgpool2d(loco::Graph *graph, moco::TFAvgPool *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFAvgPool node with Canonical FeatureEncode +
+ * AvgPool2D + FeatureDecode
+ *
+ * Before
+ * A -- TFAvgPool -- C
+ *
+ * After
+ * +- TFAvgPool --
+ * |
+ * A -+- FeatureEncode -- AvgPool2D -- FeatureDecode -- C
+ *
+ * Where
+ * A : value of TFAvgPool
+ * C : a node that uses TFAvgPool as an input
+ * TFAvgPool is disconnected from other nodes
+ */
+
+ auto data_layout = plier::tf::as_data_layout(node->data_layout());
+
+ auto feature_enc = graph->nodes()->create<loco::FeatureEncode>();
+ auto avgPool2d_node = graph->nodes()->create<loco::AvgPool2D>();
+ auto feature_dec = graph->nodes()->create<loco::FeatureDecode>();
+
+ set_feature_enc(feature_enc, data_layout);
+ set_feature_dec(feature_dec, data_layout);
+
+ avgPool2d_node->convention(loco::AvgPool2D::Convention::Valid);
+
+ auto value_shape = moco::node_shape(node->value());
+ assert(value_shape.domain() != loco::Domain::Unknown);
+
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(node->ksize(), node->data_layout());
+
+ moco::Padding2DInference infer_padding2d;
+
+ infer_padding2d.padding(node->padding());
+ infer_padding2d.stride(node_stride);
+ infer_padding2d.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(value_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+
+ *avgPool2d_node->pad() = infer_padding2d(input_plane_shape);
+ *avgPool2d_node->stride() = node_stride;
+ *avgPool2d_node->window() = node_window;
+
+ INFO(l) << "Canonicalize TFAvgPool pad = T " << avgPool2d_node->pad()->top() << ", L "
+ << avgPool2d_node->pad()->left() << ", B " << avgPool2d_node->pad()->bottom() << ", R "
+ << avgPool2d_node->pad()->right() << std::endl;
+
+ // update graph
+ auto node_A = node->value();
+
+ // update connections
+ feature_enc->input(node_A);
+ avgPool2d_node->ifm(feature_enc);
+ feature_dec->input(avgPool2d_node);
+
+ // replace node
+ replace(node).with(feature_dec);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool AvgPoolCanonicalizer::transform(TFAvgPool *node) const
+{
+ return canonicalize_avgpool2d(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.h
new file mode 100644
index 000000000..e9c56c868
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/AvgPoolCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_AVGPOOL_CANONICALIZER_H__
+#define __MOCO_TF_AVGPOOL_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFAvgPool to Canonical AvgPool2D
+ */
+class AvgPoolCanonicalizer : public SimpleNodeTransform<moco::TFAvgPool>
+{
+public:
+ const char *name(void) const final { return "AvgPoolCanonicalizer"; }
+
+public:
+ bool transform(TFAvgPool *node) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_AVGPOOL_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.cpp
new file mode 100644
index 000000000..a5568ce1a
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 "BiasAddCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Names.h>
+#include <moco/Log.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using plier::tf::DataLayout;
+
+bool canonicalize_biasadd(loco::Graph *graph, moco::TFBiasAdd *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFBiasAdd node with Canonical BiasEncode + TensorBiasAdd
+ *
+ * Before
+ * A -- TFBiasAdd - C
+ * B -/
+ *
+ * After
+ * A -- TFBiasAdd -
+ * B -/
+ * A --------------- TensorBiasAdd - C
+ * B - BiasEncode -/
+ *
+ * Where
+ * A : value of TFBiasAdd
+ * B : bias of TFBiasAdd
+ * C : a node that uses TFBiasAdd as an input
+ * TFBiasAdd is disconnected from node C
+ * A and B are drawn twice to simplify the diagram
+ */
+
+ INFO(l) << "TFNodeCanonicalize TFBiasAdd begin";
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = plier::tf::as_data_layout(node->data_layout());
+
+ // creating loco nodes
+ auto bias_enc = graph->nodes()->create<loco::BiasEncode>();
+
+ auto bias_add = graph->nodes()->create<loco::TensorBiasAdd>();
+ {
+ if (data_layout == DataLayout::NHWC)
+ {
+ INFO(l) << "TFNodeCanonicalize TFBiasAdd axis 3";
+ bias_add->axis(3);
+ }
+ else if (data_layout == DataLayout::NCHW)
+ {
+ INFO(l) << "TFNodeCanonicalize TFBiasAdd axis 1";
+ bias_add->axis(1); // Channel
+ // Note: the following descrition of TF 1.13 at
+ // https://www.tensorflow.org/api_docs/python/tf/nn/bias_add seems wrong:
+ // "bias: A 1-D Tensor with size matching the last dimension of value."
+ // because providing the size of W (last dimension) to bias throws an error with TensorFlow
+ }
+ }
+
+ auto node_A = node->value();
+ auto node_B = node->bias();
+
+ // update connections
+ bias_add->value(node_A);
+ bias_add->bias(bias_enc);
+ bias_enc->input(node_B);
+
+ // replace old with new : about C in above note
+ replace(node).with(bias_add);
+
+ INFO(l) << "TFNodeCanonicalize TFBiasAdd done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool BiasAddCanonicalizer::transform(TFBiasAdd *node) const
+{
+ return canonicalize_biasadd(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.h
new file mode 100644
index 000000000..ff4032ca9
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/BiasAddCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_BIASADD_CANONICALIZER_H__
+#define __MOCO_TF_BIASADD_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFBiasAdd to Canonical BiasAdd
+ */
+class BiasAddCanonicalizer final : public SimpleNodeTransform<moco::TFBiasAdd>
+{
+public:
+ const char *name(void) const final { return "BiasAddCanonicalizer"; }
+
+public:
+ bool transform(TFBiasAdd *node) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_BIASADD_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.cpp
new file mode 100644
index 000000000..b59a3f3d7
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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 "ConcatV2Canonicalizer.h"
+#include "LogHelper.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <moco/Log.h>
+
+#include <loco/Service/ShapeInference.h>
+
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+
+using namespace moco::tf;
+
+bool scalar_value(moco::TFConst *node, int32_t &ret)
+{
+ auto nodeshape = node_shape(node);
+ if (!(node->dtype() == loco::DataType::S32))
+ return false;
+
+ auto tensor_shape = nodeshape.as<loco::TensorShape>();
+ if (!(tensor_shape.rank() == 0 || tensor_shape.rank() == 1))
+ return false;
+
+ ret = node->at<loco::DataType::S32>(0);
+
+ return true;
+}
+
+bool canonicalize_concat(loco::Graph *graph, moco::TFConcatV2 *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFConcatV2 node with (series of) Canonical
+ * TensorConcat. Below diagram is an example of three inputs
+ *
+ * Before
+ * A --- TFConcatV2 -- C
+ * B --/
+ * N --/
+ * X --/
+ * After
+ * A --- TFConcatV2
+ * B --/
+ * N --/
+ * X --/
+ * A --- TensorConcat -- TensorConcat -- C
+ * B --/ /
+ * N -----------------/
+ *
+ * Where
+ * A : first value of TFConcatV2
+ * B : second value of TFConcatV2
+ * N : third or N'th value of TFConcatV2
+ * X : axis node of TFConcatV2
+ * C : a node that uses TFConcatV2 as an input
+ * TFConcatV2 is disconnected from C
+ * To simplify the diagram in 'After', A, B, N are drawn
+ * multiple times but they are same nodes.
+ */
+
+ const int num_values = node->num_values();
+ assert(num_values >= 2);
+
+ // get axis absolute value
+ auto value_a = node->values(0);
+ if (!loco::shape_known(value_a))
+ return false;
+
+ uint32_t node_rank = 0;
+ {
+ auto value_a_shape = moco::node_shape(value_a);
+ assert(value_a_shape.domain() == loco::Domain::Tensor);
+
+ auto value_a_tensor_shape = value_a_shape.as<loco::TensorShape>();
+ node_rank = value_a_tensor_shape.rank();
+ }
+
+ int32_t axis_value = 0;
+ {
+ // axis should be TFConst
+ auto axis_node = node->axis();
+ auto tfconst = dynamic_cast<moco::TFConst *>(axis_node);
+ if (tfconst == nullptr)
+ {
+ // TODO Check this: this error can be from TFOptimizatier.
+ throw oops::UserExn("ConcatV2 node has invalid input for axis", node->name());
+ }
+ auto result = scalar_value(tfconst, axis_value);
+ if (!result)
+ {
+ // TODO Check this: this error can be from TFOptimizatier.
+ throw oops::UserExn("ConcatV2 node has invalid input for axis", node->name());
+ }
+ }
+ uint32_t axis_absolute = (axis_value >= 0) ? axis_value : (int32_t)node_rank + axis_value;
+
+ INFO(l) << "canonicalize_concat axis(" << axis_absolute << "), value(" << axis_value << "), rank("
+ << node_rank << ")";
+
+ // Convert series of TensorConcat if num_values > 2
+ auto concat_node = graph->nodes()->create<loco::TensorConcat>();
+ concat_node->lhs(node->values(0));
+ concat_node->rhs(node->values(1));
+ concat_node->axis(axis_absolute);
+
+ loco::TensorConcat *last_concat = concat_node;
+ for (int ni = 2; ni < num_values; ++ni)
+ {
+ auto concat_node_next = graph->nodes()->create<loco::TensorConcat>();
+
+ concat_node_next->lhs(last_concat);
+ concat_node_next->rhs(node->values(ni));
+ concat_node_next->axis(axis_absolute);
+
+ // update last concat node
+ last_concat = concat_node_next;
+ }
+
+ // replace node
+ replace(node).with(last_concat);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool ConcatV2Canonicalizer::transform(TFConcatV2 *node) const
+{
+ return canonicalize_concat(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.h b/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.h
new file mode 100644
index 000000000..e6b471b89
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ConcatV2Canonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_CONCATV2_CANONICALIZER_H__
+#define __MOCO_TF_CONCATV2_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFConcatV2 to Canonical TensorConcat
+ */
+class ConcatV2Canonicalizer : public SimpleNodeTransform<moco::TFConcatV2>
+{
+public:
+ const char *name(void) const final { return "ConcatV2Canonicalizer"; }
+
+public:
+ bool transform(moco::TFConcatV2 *node) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_CONCATV2_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.cpp
new file mode 100644
index 000000000..60629cd5a
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "ConstCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Names.h>
+#include <moco/Log.h>
+
+#include <oops/UserExn.h>
+
+namespace
+{
+
+bool canonicalize_const(loco::Graph *graph, moco::TFConst *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFConst node with Canonical Const
+ *
+ * Before
+ * TFConst -- C
+ *
+ * After
+ * TFConst -
+ * ConstGen -- C
+ *
+ * Where
+ * C : a node that uses TFConst as an input
+ * TFConst is disconnected from other nodes
+ */
+
+ INFO(l) << "TFNodeCanonicalize TFConst begin";
+
+ auto const_node = graph->nodes()->create<loco::ConstGen>();
+
+ // copy properties
+ auto dtype = node->dtype();
+ const_node->dtype(dtype);
+
+ auto rank = node->rank();
+
+ if (rank == 0)
+ {
+ // This routine implements a workaround that converts a scalar constant (rank-0 tensor)
+ // into a rank-1 tensor of shape [1].
+ //
+ // TODO Revise this implementation later
+ const_node->rank(1);
+ const_node->dim(0) = 1;
+ }
+ else
+ {
+ const_node->rank(rank);
+
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ if (node->dim(r).known())
+ const_node->dim(r) = node->dim(r);
+ else
+ const_node->dim(r).unset();
+ }
+ }
+
+ switch (dtype)
+ {
+ case loco::DataType::S32:
+ {
+ uint32_t input_elements = node->size<loco::DataType::S32>();
+ const_node->size<loco::DataType::S32>(input_elements);
+ for (uint32_t i = 0; i < input_elements; ++i)
+ {
+ const_node->at<loco::DataType::S32>(i) = node->at<loco::DataType::S32>(i);
+ }
+ break;
+ }
+ case loco::DataType::FLOAT32:
+ {
+ uint32_t input_elements = node->size<loco::DataType::FLOAT32>();
+ const_node->size<loco::DataType::FLOAT32>(input_elements);
+ for (uint32_t i = 0; i < input_elements; ++i)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = node->at<loco::DataType::FLOAT32>(i);
+ }
+ break;
+ }
+ default:
+ throw oops::UserExn("Const has unsupported data type", node->name());
+ }
+
+ // update graph
+ replace(node).with(const_node);
+
+ INFO(l) << "TFNodeCanonicalize TFConst done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool ConstCanonicalizer::transform(TFConst *node) const
+{
+ return canonicalize_const(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.h
new file mode 100644
index 000000000..1b0b2b867
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ConstCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_CONST_CANONICALIZER_H__
+#define __MOCO_TF_CONST_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFConst to Canonical ConstGen
+ */
+class ConstCanonicalizer : public SimpleNodeTransform<moco::TFConst>
+{
+public:
+ const char *name(void) const final { return "ConstCanonicalizer"; }
+
+public:
+ bool transform(moco::TFConst *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_CONST_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.cpp
new file mode 100644
index 000000000..d3cbd4ab3
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.cpp
@@ -0,0 +1,371 @@
+/*
+ * 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 "Conv2DBackpropInputCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "CodecHelper.h"
+
+#include <loco/IR/Stride.h>
+#include <loco/IR/Padding2D.h>
+#include <loco/Service/ShapeInference.h>
+
+#include <oops/UserExn.h>
+
+namespace
+{
+using plier::tf::DataLayout;
+
+void set_filter_enc(loco::FilterEncode *filter_enc)
+{
+ auto enc = stdex::make_unique<loco::PermutingEncoder<loco::Domain::Filter>>();
+
+ // In TensorFlow, Conv2dBackpropInput's filter is a 4-D tensor of following shape:
+ // [filter_height, filter_width, out_channels, in_channels] or HWOI or HWNC (in/out in loco sense)
+ enc->perm()->axis(loco::FilterAxis::Height) = 0;
+ enc->perm()->axis(loco::FilterAxis::Width) = 1;
+ enc->perm()->axis(loco::FilterAxis::Count) = 2;
+ enc->perm()->axis(loco::FilterAxis::Depth) = 3;
+
+ filter_enc->encoder(std::move(enc));
+}
+
+} // namespace
+
+namespace
+{
+
+bool stride_2d_from_4d(loco::Stride<2> &ret, const std::vector<int64_t> &strides_4d,
+ const DataLayout data_layout)
+{
+ if (!(strides_4d.size() == 4))
+ return false;
+
+ switch (data_layout)
+ {
+ case DataLayout::NHWC:
+ ret.vertical(strides_4d.at(1));
+ ret.horizontal(strides_4d.at(2));
+ break;
+ case DataLayout::NCHW:
+ ret.vertical(strides_4d.at(2));
+ ret.horizontal(strides_4d.at(3));
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+struct PlaneShape
+{
+ loco::Dimension vertical;
+ loco::Dimension horizontal;
+};
+
+class Padding2DInference final
+{
+public:
+ Padding2DInference(const moco::TFNode *node) { _node = node; }
+
+public:
+ loco::Padding2D operator()(void);
+
+public:
+ PlaneShape &input() { return _input; }
+ PlaneShape &output() { return _output; }
+ loco::Stride<2> &stride() { return _stride; }
+ loco::Window<2> &window() { return _window; }
+ moco::TFPadding &padding() { return _padding; }
+
+private:
+ /// @brief Check whether ingredients set by non-default values
+ bool ready()
+ {
+ if (not input().vertical.known())
+ return false;
+ if (not input().horizontal.known())
+ return false;
+ if (not output().vertical.known())
+ return false;
+ if (not output().horizontal.known())
+ return false;
+ if (stride().vertical() == 0)
+ return false;
+ if (stride().horizontal() == 0)
+ return false;
+ if (window().vertical() == 0)
+ return false;
+ if (window().horizontal() == 0)
+ return false;
+ if (padding().empty())
+ return false;
+
+ return true;
+ }
+
+ inline uint32_t tight_output_for_valid_padding(uint32_t input, uint32_t stride, uint32_t filter)
+ {
+ return stride * (input - 1) + filter;
+ }
+
+ /**
+ * @note For Conv2DBackpropInput SAME padding, TensorFlow requires this condition to hold
+ *
+ * Reference: `::tensorflow::GetWindowedOutputSizeVerboseV2()` from TensorFlow project
+ */
+ inline bool same_padding_applicable(uint32_t input, uint32_t output, uint32_t stride)
+ {
+ // Here 'input' and 'output' means Conv2DBackpropInput's actual node input and output.
+ // Then these three conditions are equivalent:
+ //
+ // input == floor((output + stride - 1) / stride)
+ // input == ceil(output / stride)
+ // (stride * (input - 1) < output) and (output <= stride * input)
+ return (stride * (input - 1) < output) and (output <= stride * input);
+ }
+
+ inline uint32_t padding_needed(uint32_t input, uint32_t output, uint32_t stride, uint32_t filter)
+ {
+ return stride * (input - 1) + filter - output;
+ }
+
+private:
+ const moco::TFNode *_node;
+ PlaneShape _input;
+ PlaneShape _output;
+ loco::Stride<2> _stride;
+ loco::Window<2> _window;
+ moco::TFPadding _padding;
+};
+
+loco::Padding2D Padding2DInference::operator()(void)
+{
+ assert(ready());
+
+ if (padding() == "VALID")
+ {
+ // In case of VALID padding, TensorFlow accepts any size same or larger than
+ // 'tight fit' output. When output size (set by 'input sizes' node input) is
+ // larger than tight fit, extra spaces filled with zero.
+ auto tight_output_vertical = tight_output_for_valid_padding(
+ input().vertical.value(), stride().vertical(), window().vertical());
+ auto tight_output_horizontal = tight_output_for_valid_padding(
+ input().horizontal.value(), stride().horizontal(), window().horizontal());
+
+ if (output().vertical.value() < tight_output_vertical or
+ output().horizontal.value() < tight_output_horizontal)
+ throw oops::UserExn("input_sizes is too small", _node->name());
+
+ // Currently, only accept tight fit.
+ // TODO Support non-tight case by adding zero padding operation
+ assert(output().vertical.value() == tight_output_vertical);
+ assert(output().horizontal.value() == tight_output_horizontal);
+
+ return loco::Padding2D(0, 0, 0, 0);
+ }
+
+ if (padding() == "SAME")
+ {
+ // This condition is required by TensorFlow
+ if (not same_padding_applicable(input().vertical.value(), output().vertical.value(),
+ stride().vertical()) or
+ not same_padding_applicable(input().horizontal.value(), output().horizontal.value(),
+ stride().horizontal()))
+ throw oops::UserExn("Size mismatch for SAME padding", _node->name());
+
+ auto whole_pad_vertical = padding_needed(input().vertical.value(), output().vertical.value(),
+ stride().vertical(), window().vertical());
+ auto whole_pad_horizontal =
+ padding_needed(input().horizontal.value(), output().horizontal.value(),
+ stride().horizontal(), window().horizontal());
+
+ loco::Padding2D res;
+
+ res.top(whole_pad_vertical / 2);
+ res.bottom(whole_pad_vertical - res.top());
+ res.left(whole_pad_horizontal / 2);
+ res.right(whole_pad_horizontal - res.left());
+
+ return res;
+ }
+
+ throw oops::UserExn("Usupported padding " + padding(), _node->name());
+}
+
+/**
+ * @param[out] ret PlaneShape extracted from 'node' with given 'data_layout'
+ * @param[in] node
+ * @param[in] data_layout
+ *
+ * @return true on success
+ */
+bool set_plane_shape(PlaneShape &ret, const loco::Node *node, const DataLayout data_layout)
+{
+ auto tensor_shape = loco::shape_get(node).as<loco::TensorShape>();
+ if (!(tensor_shape.rank() == 4))
+ return false;
+
+ switch (data_layout)
+ {
+ case DataLayout::NHWC:
+ ret.vertical = tensor_shape.dim(1).value();
+ ret.horizontal = tensor_shape.dim(2).value();
+ break;
+ case DataLayout::NCHW:
+ ret.vertical = tensor_shape.dim(2).value();
+ ret.horizontal = tensor_shape.dim(3).value();
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @param[out] ret 2D Window extracted from HW** filter node
+ * @param[in] filter_node
+ *
+ * @return true on success
+ */
+bool set_window(loco::Window<2> &ret, const loco::Node *filter_node)
+{
+ auto tensor_shape = loco::shape_get(filter_node).as<loco::TensorShape>();
+ assert(tensor_shape.rank() == 4);
+
+ ret.vertical(tensor_shape.dim(0).value());
+ ret.horizontal(tensor_shape.dim(1).value());
+
+ return true;
+}
+
+} // namespace
+
+namespace
+{
+
+bool canonicalize_conv2d_backprop_input(loco::Graph *graph,
+ moco::TFConv2DBackpropInput *conv2d_backprop)
+{
+ /**
+ * @note This will replace TFConv2DBackpropInput node with canonical
+ * FeatureEncode + FilterEncode + TransposedConv2D + FeatureDecode
+ *
+ * Before
+ * input_sizes ----
+ * \
+ * filter -------- TFConv2DBackpropInput --- output(s)
+ * /
+ * out_backprop ---
+ *
+ * After
+ * input_sizes ----
+ * \
+ * filter -------- TFConv2DBackpropInput ---
+ * /
+ * out_backprop ---
+ *
+ * filter ------ FilterEncode ------ TransposedConv2D --- FeatureDecode --- output(s)
+ * (as ker) /
+ * out_backprop --- FeatureEncode ---
+ * (as ifm)
+ */
+
+ if (!loco::shape_known(conv2d_backprop->out_backprop()))
+ return false;
+ if (!loco::shape_known(conv2d_backprop))
+ return false;
+ if (!loco::shape_known(conv2d_backprop->filter()))
+ return false;
+
+ auto data_layout = plier::tf::as_data_layout(conv2d_backprop->data_layout());
+
+ // Nodes to replace
+ auto feature_enc = graph->nodes()->create<loco::FeatureEncode>();
+ auto filter_enc = graph->nodes()->create<loco::FilterEncode>();
+ auto tr_conv2d = graph->nodes()->create<loco::TransposedConv2D>();
+ auto feature_dec = graph->nodes()->create<loco::FeatureDecode>();
+
+ set_feature_enc(feature_enc, data_layout);
+ set_filter_enc(filter_enc);
+ set_feature_dec(feature_dec, data_layout);
+
+ // Attributes for new TransposedConv2D
+ loco::Stride<2> stride;
+ loco::Padding2D pad;
+
+ // Get attributes
+ {
+ if (!stride_2d_from_4d(stride, conv2d_backprop->strides(), data_layout))
+ throw oops::UserExn("Unsupported strides", conv2d_backprop->name());
+
+ Padding2DInference infer_pad(conv2d_backprop);
+
+ if (!set_plane_shape(infer_pad.input(), conv2d_backprop->out_backprop(), data_layout))
+ throw oops::UserExn("Unsupported out_backprop data_format", conv2d_backprop->name());
+ if (!set_plane_shape(infer_pad.output(), conv2d_backprop, data_layout))
+ throw oops::UserExn("Unsupported data_format", conv2d_backprop->name());
+ if (!set_window(infer_pad.window(), conv2d_backprop->filter()))
+ throw oops::UserExn("Unsupported filter shape", conv2d_backprop->name());
+ infer_pad.stride() = stride;
+ infer_pad.padding() = conv2d_backprop->padding();
+
+ // Run padding infer_pad
+ pad = infer_pad();
+ }
+
+ // Set attributes
+ tr_conv2d->pad()->top(pad.top());
+ tr_conv2d->pad()->bottom(pad.bottom());
+ tr_conv2d->pad()->left(pad.left());
+ tr_conv2d->pad()->right(pad.right());
+
+ tr_conv2d->stride()->vertical(stride.vertical());
+ tr_conv2d->stride()->horizontal(stride.horizontal());
+
+ // Update graph
+ auto input_node = conv2d_backprop->out_backprop();
+ auto filter_node = conv2d_backprop->filter();
+
+ // Update connections
+ feature_enc->input(input_node);
+ filter_enc->input(filter_node);
+ tr_conv2d->ifm(feature_enc);
+ tr_conv2d->ker(filter_enc);
+ feature_dec->input(tr_conv2d);
+
+ // Replace old conv2d_backprop
+ replace(conv2d_backprop).with(feature_dec);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool Conv2DBackpropInputCanonicalizer::transform(TFConv2DBackpropInput *node) const
+{
+ return canonicalize_conv2d_backprop_input(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.h
new file mode 100644
index 000000000..bc37bb9cb
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Conv2DBackpropInputCanonicalizer.h
@@ -0,0 +1,45 @@
+/*
+ * 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_CONV2DBACKPROPINPUT_CANONICALIZER_H__
+#define __MOCO_TF_CONV2DBACKPROPINPUT_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/// @brief Convert TFConv2DBackpropInput to Canonical TransposedConv2D
+class Conv2DBackpropInputCanonicalizer : public SimpleNodeTransform<moco::TFConv2DBackpropInput>
+{
+public:
+ const char *name(void) const final { return "Conv2DBackpropInputCanonicalizer"; }
+
+public:
+ bool transform(moco::TFConv2DBackpropInput *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_CONV2DBACKPROPINPUT_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.cpp
new file mode 100644
index 000000000..a955793a8
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "Conv2DCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include "CodecHelper.h"
+
+#include <moco/Log.h>
+
+namespace
+{
+using plier::tf::DataLayout;
+
+void set_filter_enc(loco::FilterEncode *filter_enc)
+{
+ auto enc = stdex::make_unique<loco::PermutingEncoder<loco::Domain::Filter>>();
+
+ // In TensorFlow, conv2d filter is a 4-D tensor of following shape:
+ // [filter_height, filter_width, in_channels, out_channels] -> HWIO (HWCN)
+ enc->perm()->axis(loco::FilterAxis::Height) = 0;
+ enc->perm()->axis(loco::FilterAxis::Width) = 1;
+ enc->perm()->axis(loco::FilterAxis::Depth) = 2;
+ enc->perm()->axis(loco::FilterAxis::Count) = 3;
+
+ filter_enc->encoder(std::move(enc));
+}
+
+bool canonicalize_conv2d(loco::Graph *graph, moco::TFConv2D *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFCon2D node with Canonical FeatureEncode +
+ * FilterEncode + Conv2D + FeatureDecode
+ *
+ * Before
+ * A -- TFConv2D - C
+ * B -/
+ *
+ * After
+ * A -- TFConv2D -
+ * B -/
+ * A -- FeatureEncode - Conv2D - FeatureDecode - C
+ * B -- FilterEncode -/
+ *
+ * Where
+ * A : ifm of TFConv2D
+ * B : ker of TFConv2D
+ * C : a node that uses TFConv2D as an input
+ * TFConv2D is disconnected from other nodes
+ * A and B are drawn twice to simplify the diagram
+ */
+
+ auto data_layout = plier::tf::as_data_layout(node->data_layout());
+
+ auto feature_enc = graph->nodes()->create<loco::FeatureEncode>();
+ auto filter_enc = graph->nodes()->create<loco::FilterEncode>();
+ auto conv2d = graph->nodes()->create<loco::Conv2D>();
+ auto feature_dec = graph->nodes()->create<loco::FeatureDecode>();
+
+ set_feature_enc(feature_enc, data_layout);
+ set_filter_enc(filter_enc);
+ set_feature_dec(feature_dec, data_layout);
+
+ auto input_shape = moco::node_shape(node->input());
+ assert(input_shape.domain() != loco::Domain::Unknown);
+
+ auto ker_shape = moco::node_shape(node->filter());
+ auto ker_tensor_shape = ker_shape.as<loco::TensorShape>(); // in HWIO
+
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(ker_tensor_shape, "HWIO");
+
+ moco::Padding2DInference infer_padding2d;
+
+ infer_padding2d.padding(node->padding());
+ infer_padding2d.stride(node_stride);
+ infer_padding2d.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+
+ *conv2d->pad() = infer_padding2d(input_plane_shape);
+ *conv2d->stride() = node_stride;
+
+ // update graph
+ auto node_A = node->input();
+ auto node_B = node->filter();
+
+ // update connections
+ feature_enc->input(node_A);
+ filter_enc->input(node_B);
+ conv2d->ifm(feature_enc);
+ conv2d->ker(filter_enc);
+ feature_dec->input(conv2d);
+
+ // replace old node
+ replace(node).with(feature_dec);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool Conv2DCanonicalizer::transform(TFConv2D *node) const
+{
+ return canonicalize_conv2d(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.h
new file mode 100644
index 000000000..ea39667f3
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Conv2DCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_CONV2D_CANONICALIZER_H__
+#define __MOCO_TF_CONV2D_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFConv2D to Canonical Conv2D
+ */
+class Conv2DCanonicalizer : public SimpleNodeTransform<TFConv2D>
+{
+public:
+ const char *name(void) const final { return "Conv2DCanonicalizer"; }
+
+public:
+ bool transform(TFConv2D *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_CONV2D_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp
new file mode 100644
index 000000000..50dddf637
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include "CodecHelper.h"
+
+#include <moco/Log.h>
+
+namespace
+{
+
+using plier::tf::DataLayout;
+
+void set_filter_enc(loco::DepthwiseFilterEncode *filter_enc)
+{
+ auto enc = stdex::make_unique<loco::PermutingEncoder<loco::Domain::DepthwiseFilter>>();
+
+ // 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));
+}
+
+bool canonicalize_depthwiseconv2dnative(loco::Graph *graph, moco::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<loco::FeatureEncode>();
+ auto filter_enc = graph->nodes()->create<loco::DepthwiseFilterEncode>();
+ auto depthwiseconv2d = graph->nodes()->create<loco::DepthwiseConv2D>();
+ auto feature_dec = graph->nodes()->create<loco::FeatureDecode>();
+
+ set_feature_enc(feature_enc, data_layout);
+ set_filter_enc(filter_enc);
+ set_feature_dec(feature_dec, data_layout);
+
+ // Calculate Pad and Stride from inference
+ auto input_shape = moco::node_shape(node->input());
+ auto ker_shape = moco::node_shape(node->filter());
+ auto ker_tensor_shape = ker_shape.as<loco::TensorShape>();
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(ker_tensor_shape, "HWCM");
+
+ moco::Padding2DInference infer_padding2d;
+
+ infer_padding2d.padding(node->padding());
+ infer_padding2d.stride(node_stride);
+ infer_padding2d.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+
+ *depthwiseconv2d->pad() = infer_padding2d(input_plane_shape);
+ *depthwiseconv2d->stride() = node_stride;
+
+ // update graph
+ auto node_A = node->input();
+ auto node_B = node->filter();
+
+ // 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::transform(TFDepthwiseConv2dNative *node) const
+{
+ return canonicalize_depthwiseconv2dnative(node->graph(), node);
+}
+
+} // 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 000000000..704e1ade9
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/DepthwiseConv2dNativeCanonicalizer.h
@@ -0,0 +1,45 @@
+/*
+ * 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"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFDepthwiseConv2dNative to Canonical DepthwiseConv2D
+ */
+class DepthwiseConv2dNativeCanonicalizer : public SimpleNodeTransform<moco::TFDepthwiseConv2dNative>
+{
+public:
+ const char *name(void) const final { return "DepthwiseConv2dNativeCanonicalizer"; }
+
+public:
+ bool transform(moco::TFDepthwiseConv2dNative *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_DEPTHWISE_CONV2D_NATIVE_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.cpp
new file mode 100644
index 000000000..3b680cf04
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "IdentityCanonicalizer.h"
+
+#include "Convert.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Names.h>
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_identity(loco::Graph *graph, moco::TFIdentity *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFIdentity node with Canonical Forward
+ *
+ * Before
+ * A -- TFIdentity -- C
+ *
+ * After
+ * /- TFIdentity --
+ * A -- Forward -- C
+ *
+ * Where
+ * A : input of TFIdentity
+ * C : a node that uses TFIdentity as an input
+ * TFIdentity is disconnected from the output
+ */
+
+ INFO(l) << "TFNodeCanonicalize TFIdentity begin";
+
+ auto forward_node = graph->nodes()->create<loco::Forward>();
+
+ auto node_A = node->input();
+
+ forward_node->input(node_A);
+
+ // update graph
+ replace(node).with(forward_node);
+
+ INFO(l) << "TFNodeCanonicalize TFIdentity done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool IdentityCanonicalizer::transform(TFIdentity *node) const
+{
+ return canonicalize_identity(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.h
new file mode 100644
index 000000000..59b2894c5
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/IdentityCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_IDENTITY_CANONICALIZER_H__
+#define __MOCO_TF_IDENTITY_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFIdentity to Canonical Forward
+ */
+class IdentityCanonicalizer : public SimpleNodeTransform<moco::TFIdentity>
+{
+public:
+ const char *name(void) const final { return "IdentityCanonicalizer"; }
+
+public:
+ bool transform(moco::TFIdentity *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_IDENTITY_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.cpp
new file mode 100644
index 000000000..06a605717
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 "MaxPoolCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include "CodecHelper.h"
+
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_maxpool2d(loco::Graph *graph, moco::TFMaxPool *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFMaxPool node with Canonical FeatureEncode +
+ * MaxPool2D + FeatureDecode
+ *
+ * Before
+ * A -- TFMaxPool -- C
+ *
+ * After
+ * +- TFMaxPool --
+ * |
+ * A -+- FeatureEncode -- MaxPool2D -- FeatureDecode -- C
+ *
+ * Where
+ * A : value of TFMaxPool
+ * C : a node that uses TFMaxPool as an input
+ * TFMaxPool is disconnected from other nodes
+ */
+
+ auto data_layout = plier::tf::as_data_layout(node->data_layout());
+
+ auto feature_enc = graph->nodes()->create<loco::FeatureEncode>();
+ auto maxPool2d_node = graph->nodes()->create<loco::MaxPool2D>();
+ auto feature_dec = graph->nodes()->create<loco::FeatureDecode>();
+
+ set_feature_enc(feature_enc, data_layout);
+ set_feature_dec(feature_dec, data_layout);
+
+ // paddata to pad
+ auto input_shape = moco::node_shape(node->input());
+ assert(input_shape.domain() != loco::Domain::Unknown);
+
+ auto node_stride = moco::stride_of(node->strides(), node->data_layout());
+ auto node_window = moco::window_of(node->ksize(), node->data_layout());
+
+ moco::Padding2DInference infer_padding2d;
+
+ infer_padding2d.padding(node->padding());
+ infer_padding2d.stride(node_stride);
+ infer_padding2d.window(node_window);
+
+ auto input_feature_shape = moco::as_feature_shape(input_shape, node->data_layout());
+ auto input_plane_shape = moco::make_plane_shape(input_feature_shape);
+
+ *maxPool2d_node->pad() = infer_padding2d(input_plane_shape);
+ *maxPool2d_node->stride() = node_stride;
+ *maxPool2d_node->window() = node_window;
+
+ INFO(l) << "Canonicalize TFMaxPool pad = T " << maxPool2d_node->pad()->top() << ", L "
+ << maxPool2d_node->pad()->left() << ", B " << maxPool2d_node->pad()->bottom() << ", R "
+ << maxPool2d_node->pad()->right() << std::endl;
+
+ // update graph
+ auto node_A = node->input();
+
+ // update connections
+ feature_enc->input(node_A);
+ maxPool2d_node->ifm(feature_enc);
+ feature_dec->input(maxPool2d_node);
+
+ // replace node
+ replace(node).with(feature_dec);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool MaxPoolCanonicalizer::transform(TFMaxPool *node) const
+{
+ return canonicalize_maxpool2d(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.h
new file mode 100644
index 000000000..c58ade528
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MaxPoolCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_MAXPOOL_CANONICALIZER_H__
+#define __MOCO_TF_MAXPOOL_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFMaxPool to Canonical MaxPool2D
+ */
+class MaxPoolCanonicalizer : public SimpleNodeTransform<moco::TFMaxPool>
+{
+public:
+ const char *name(void) const final { return "MaxPoolCanonicalizer"; }
+
+public:
+ bool transform(moco::TFMaxPool *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_MAXPOOL_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.cpp
new file mode 100644
index 000000000..92634d01f
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 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 "MaximumCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "TFEltwiseBinaryCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool MaximumCanonicalizer::transform(moco::TFMaximum *node) const
+{
+ return canonicalize_eltwise_binary_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.h
new file mode 100644
index 000000000..baff4d7ad
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MaximumCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 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_MAXIMUM_CANONICALIZER_H__
+#define __MOCO_TF_MAXIMUM_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFMaximum to Canonical EltwiseMax
+ */
+class MaximumCanonicalizer : public SimpleNodeTransform<moco::TFMaximum>
+{
+public:
+ const char *name(void) const final { return "MaximumCanonicalizer"; }
+
+public:
+ bool transform(moco::TFMaximum *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_MAXIMUM_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.cpp
new file mode 100644
index 000000000..69eaf7900
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 "MeanCanonicalizer.h"
+#include "TFReduceCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool MeanCanonicalizer::transform(moco::TFMean *node) const
+{
+ return canonicalize_reduce_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.h
new file mode 100644
index 000000000..469d7e3cd
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MeanCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_MEAN_CANONICALIZER_H__
+#define __MOCO_TF_MEAN_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Canonicalize TF-dialect TFMean into canonical TensorReduce(Mean) node
+ */
+class MeanCanonicalizer : public SimpleNodeTransform<moco::TFMean>
+{
+public:
+ const char *name(void) const final { return "MeanCanonicalizer"; }
+
+public:
+ bool transform(moco::TFMean *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_MEAN_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.cpp
new file mode 100644
index 000000000..d02f71361
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "MulCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "TFEltwiseBinaryCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool MulCanonicalizer::transform(moco::TFMul *node) const
+{
+ return canonicalize_eltwise_binary_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.h
new file mode 100644
index 000000000..480eec700
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/MulCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_MUL_CANONICALIZER_H__
+#define __MOCO_TF_MUL_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFMul to Canonical EltwiseMul
+ */
+class MulCanonicalizer : public SimpleNodeTransform<moco::TFMul>
+{
+public:
+ const char *name(void) const final { return "MulCanonicalizer"; }
+
+public:
+ bool transform(moco::TFMul *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_MUL_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.cpp
new file mode 100644
index 000000000..10816f47c
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 "PadCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "loco/Service/TypeInference.h"
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool canonicalize_pad(loco::Graph *graph, moco::TFPad *node)
+{
+ /**
+ * @note This will replace TFPad node with Canonical TensorConstantPad
+ *
+ * Before
+ * input --- TFPad -- C
+ * paddings --/
+ * After
+ * paddings ------- TFPad --
+ * /
+ * input ----------- TensorConstantPad -- C
+ * ConstGen --------/
+ * Where
+ * input : input of TFPad
+ * paddings : paddings of TFPad. it becomes TensorConstantPad's attribute.
+ * C : a node that uses TFPad as an input. TFPad is disconnected from C.
+ * ConstGen : constant value of Pad. TFPad has zero value by default.
+ */
+
+ auto pad_node = graph->nodes()->create<loco::TensorConstantPad>();
+
+ auto constant_node = graph->nodes()->create<loco::ConstGen>();
+
+ auto input_node = node->input();
+ // TODO: support other dtype.
+ assert(loco::dtype_get(input_node) == loco::DataType::FLOAT32);
+ constant_node->dtype(loco::DataType::FLOAT32);
+ // TODO: constant node changes to scalar when it is implemented.
+ constant_node->shape({1});
+ constant_node->size<loco::DataType::FLOAT32>(1);
+ constant_node->at<loco::DataType::FLOAT32>(0) = 0.0f;
+
+ auto const_paddings_node = dynamic_cast<loco::ConstGen *>(node->paddings());
+ // TODO: support S64 type.
+ assert(const_paddings_node->dtype() == loco::DataType::S32);
+ assert(const_paddings_node->rank() == 2);
+ assert(const_paddings_node->dim(1).value() == 2);
+
+ auto padding = pad_node->padding();
+ uint32_t padding_rank = const_paddings_node->dim(0).value();
+ padding->rank(padding_rank);
+
+ for (uint32_t i = 0; i < padding_rank; i++)
+ {
+ padding->front(i) = const_paddings_node->at<loco::DataType::S32>(i << 1);
+ padding->back(i) = const_paddings_node->at<loco::DataType::S32>((i << 1) + 1);
+ }
+
+ // update connections
+ pad_node->input(input_node);
+ pad_node->constant(constant_node);
+
+ // replace node
+ replace(node).with(pad_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool PadCanonicalizer::transform(TFPad *node) const
+{
+ return canonicalize_pad(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.h
new file mode 100644
index 000000000..64bb6041a
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/PadCanonicalizer.h
@@ -0,0 +1,45 @@
+/*
+ * 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_PAD_CANONICALIZER_H__
+#define __MOCO_TF_PAD_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFPad to Canonical TensorConstantPad
+ */
+class PadCanonicalizer final : public SimpleNodeTransform<moco::TFPad>
+{
+public:
+ const char *name(void) const final { return "PadCanonicalizer"; }
+
+public:
+ bool transform(moco::TFPad *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_PAD_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.cpp
new file mode 100644
index 000000000..f568e909f
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "PlaceholderCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Names.h>
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_placeholder(loco::Graph *graph, moco::TFPlaceholder *node)
+{
+ LOGGER(l);
+
+ /**
+ * @note This will replace TFPlaceholder node with Canonical Pull
+ *
+ * Before
+ * TFPlaceholder -- C
+ *
+ * After
+ * TFPlaceholder -
+ * Pull -- C
+ *
+ * Where
+ * C : a node that uses TFPlaceholder as an input
+ * TFPlaceholder is disconnected from other nodes
+ */
+
+ INFO(l) << "PlaceholderCanonicalizer begin";
+
+ auto pull_node = graph->nodes()->create<loco::Pull>();
+
+ // copy properties
+ auto dtype = node->dtype();
+ pull_node->dtype(dtype);
+
+ auto rank = node->rank();
+
+ if (rank == 0)
+ {
+ // This routine implements a workaround that converts a scalar constant (rank-0 tensor)
+ // into a rank-1 tensor of shape [1].
+ //
+ // TODO Revise this implementation later
+ pull_node->rank(1);
+ pull_node->dim(0) = 1;
+ }
+ else
+ {
+ pull_node->rank(rank);
+
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ if (node->dim(r).known())
+ pull_node->dim(r) = node->dim(r);
+ else
+ pull_node->dim(r).unset();
+ }
+ }
+
+ // set loco::Pull GraphInputIndex
+ pull_node->index(moco::index(node));
+
+ // update graph
+ replace(node).with(pull_node);
+
+ INFO(l) << "PlaceholderCanonicalizer done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool PlaceholderCanonicalizer::transform(TFPlaceholder *node) const
+{
+ return canonicalize_placeholder(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.h
new file mode 100644
index 000000000..66eafe6af
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/PlaceholderCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_PLACEHOLDER_CANONICALIZER_H__
+#define __MOCO_TF_PLACEHOLDER_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/Nodes/TFPlaceholder.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFPlaceholder to Canonical Pull
+ *
+ * @note GraphInputIndex is copied to Pull
+ */
+class PlaceholderCanonicalizer : public SimpleNodeTransform<::moco::TFPlaceholder>
+{
+public:
+ const char *name(void) const final { return "PlaceholderCanonicalizer"; }
+
+public:
+ bool transform(moco::TFPlaceholder *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_PLACEHOLDER_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.cpp
new file mode 100644
index 000000000..a448d85fa
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "RealDivCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "TFEltwiseBinaryCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool RealDivCanonicalizer::transform(moco::TFRealDiv *node) const
+{
+ return canonicalize_eltwise_binary_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.h
new file mode 100644
index 000000000..76e1bd377
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/RealDivCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_REALDIV_CANONICALIZER_H__
+#define __MOCO_TF_REALDIV_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFRealDiv to Canonical EltwiseDiv
+ */
+class RealDivCanonicalizer : public SimpleNodeTransform<moco::TFRealDiv>
+{
+public:
+ const char *name(void) const final { return "RealDivCanonicalizer"; }
+
+public:
+ bool transform(moco::TFRealDiv *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_REALDIV_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.cpp
new file mode 100644
index 000000000..c53a880a8
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "Relu6Canonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool canonicalize_relu6(loco::Graph *graph, moco::TFRelu6 *node)
+{
+ /**
+ * @note This will replace TFRelu6 node with Canonical ReLU6
+ *
+ * Before
+ * A --- TFRelu6 -- C
+ * After
+ * +- TFRelu6 --
+ * |
+ * A -+- ReLU6 -- C
+ *
+ * Where
+ * A : features of TFRelu6
+ * C : a node that uses TFRelu6 as an input
+ * TFRelu6 is disconnected from C
+ */
+
+ auto relu6_node = graph->nodes()->create<loco::ReLU6>();
+
+ auto node_A = node->features();
+
+ // update connections
+ relu6_node->input(node_A);
+
+ // replace node
+ replace(node).with(relu6_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool Relu6Canonicalizer::transform(TFRelu6 *node) const
+{
+ return canonicalize_relu6(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.h b/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.h
new file mode 100644
index 000000000..d8ad5db8e
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/Relu6Canonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_RELU6_CANONICALIZER_H__
+#define __MOCO_TF_RELU6_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFRelu6 to Canonical ReLU6
+ */
+class Relu6Canonicalizer : public SimpleNodeTransform<moco::TFRelu6>
+{
+public:
+ const char *name(void) const final { return "Relu6Canonicalizer"; }
+
+public:
+ bool transform(moco::TFRelu6 *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_RELU6_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.cpp
new file mode 100644
index 000000000..7965dc931
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "ReluCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool canonicalize_relu(loco::Graph *graph, moco::TFRelu *node)
+{
+ /**
+ * @note This will replace TFRelu node with Canonical ReLU
+ *
+ * Before
+ * A --- TFRelu -- C
+ * After
+ * +- TFRelu --
+ * |
+ * A -+- ReLU -- C
+ *
+ * Where
+ * A : features of TFRelu
+ * C : a node that uses TFRelu as an input
+ * TFRelu is disconnected from C
+ */
+
+ auto relu_node = graph->nodes()->create<loco::ReLU>();
+
+ auto node_A = node->features();
+
+ // update connections
+ relu_node->input(node_A);
+
+ // replace node
+ replace(node).with(relu_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool ReluCanonicalizer::transform(TFRelu *node) const
+{
+ return canonicalize_relu(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.h
new file mode 100644
index 000000000..e27abe158
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ReluCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_RELU_CANONICALIZER_H__
+#define __MOCO_TF_RELU_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFRelu to Canonical ReLU
+ */
+class ReluCanonicalizer : public SimpleNodeTransform<moco::TFRelu>
+{
+public:
+ const char *name(void) const final { return "ReluCanonicalizer"; }
+
+public:
+ bool transform(moco::TFRelu *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_RELU_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.cpp
new file mode 100644
index 000000000..b944568e0
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 "ReshapeCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Log.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+
+namespace
+{
+using plier::tf::DataLayout;
+
+/**
+ * @brief Check whether given 'new shape' arg is a fixed shape input for Reshape
+ *
+ * ConstNode can be moco::TFConst or loco::ConstGen
+ */
+template <typename ConstNode> bool is_fixed_shape_input(ConstNode *const_shape_input)
+{
+ if (const_shape_input == nullptr)
+ return false;
+
+ // Shape input should be integer tensor of rank 1, e.g. [2, 3, 4] or [3, -1]
+ // TODO Support other possible data types, e.g. S64
+ assert(const_shape_input->dtype() == loco::DataType::S32);
+ assert(const_shape_input->rank() == 1);
+
+ auto shape_rank = const_shape_input->dim(0).value();
+ assert(shape_rank > 0);
+
+ for (uint32_t axis = 0; axis < shape_rank; ++axis)
+ {
+ auto shape_dim = const_shape_input->template at<loco::DataType::S32>(axis);
+ if (shape_dim == -1)
+ {
+ // has wildcard dimension, i.e. dynamic reshape
+ return false;
+ }
+ if (!(shape_dim >= 1))
+ {
+ throw oops::UserExn("New shape of Reshape has invalid dimension");
+ }
+ }
+ return true;
+}
+
+/// @note Currently only supports to canonicalize Fixed Reshape
+bool canonicalize_reshape(loco::Graph *graph, moco::TFReshape *node)
+{
+ LOGGER(l);
+ INFO(l) << "TFNodeCanonicalize TFReshape begin";
+
+ /**
+ * This rule canonicalizes TFReshape only when its output shape is known at
+ * compile time, i.e. fixed reshape case.
+ * TODO Support other cases like dynamic reshape
+ *
+ * This will replace TFReshape + TFConst or Canonical ConstGen(as shape input)
+ * node pair into Canonical Reshape<ReshapeType::Fixed>, or 'FixedReshape'.
+ * Shape input (TFConst or Canonical ConstGen) should not have wildcard
+ * dimension to be converted to FixedReshape.
+ *
+ * Before
+ * TFConst (shape)
+ * or ---
+ * ConstGen \
+ * \
+ * In --------- TFReshape ------- Out(s)
+ * (tensor)
+ *
+ * After
+ * TFConst
+ * or ---
+ * ConstGen \
+ * \
+ * ---------- TFReshape
+ * /
+ * In -------- FixedReshape ----- Out(s)
+ */
+
+ // create loco node to replace
+ auto fixed_reshape = graph->nodes()->create<loco::FixedReshape>();
+
+ // Supports 2 cases for Reshape's shape input:
+ // TF-dialect TFConst or Canonical ConstGen
+ loco::Node *shape_input = node->shape();
+ auto tfconst_shape_input = dynamic_cast<moco::TFConst *>(shape_input);
+ auto constgen_shape_input = dynamic_cast<loco::ConstGen *>(shape_input);
+
+ if (tfconst_shape_input)
+ {
+ // Only support fixed reshape
+ // TODO support dynamic reshape
+ if (!(is_fixed_shape_input(tfconst_shape_input)))
+ {
+ throw oops::UserExn("Supports only fixed reshape", node->name());
+ }
+
+ auto rank = tfconst_shape_input->dim(0).value();
+ fixed_reshape->rank(rank);
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ fixed_reshape->dim(axis) = tfconst_shape_input->at<loco::DataType::S32>(axis);
+ }
+ }
+ else if (constgen_shape_input)
+ {
+ // ditto
+ if (!(is_fixed_shape_input(constgen_shape_input)))
+ {
+ throw oops::UserExn("Supports only fixed reshape", node->name());
+ }
+
+ auto rank = constgen_shape_input->dim(0).value();
+ fixed_reshape->rank(rank);
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ fixed_reshape->dim(axis) = constgen_shape_input->at<loco::DataType::S32>(axis);
+ }
+ }
+ else
+ {
+ // TODO support dynamic reshape from not const node
+ throw oops::UserExn("Supports only const node as input shape", node->name());
+ }
+
+ // replace
+ auto in = node->tensor();
+ fixed_reshape->input(in);
+
+ replace(node).with(fixed_reshape);
+
+ INFO(l) << "TFNodeCanonicalize TFReshape done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool ReshapeCanonicalizer::transform(TFReshape *node) const
+{
+ return canonicalize_reshape(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.h
new file mode 100644
index 000000000..1a792024e
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/ReshapeCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_RESHAPE_CANONICALIZER_H__
+#define __MOCO_TF_RESHAPE_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFReshape to Canonical Reshape
+ */
+class ReshapeCanonicalizer : public SimpleNodeTransform<moco::TFReshape>
+{
+public:
+ const char *name(void) const final { return "ReshapeCanonicalizer"; }
+
+public:
+ bool transform(moco::TFReshape *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_RESHAPE_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.cpp
new file mode 100644
index 000000000..c31dbf6d6
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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 "RsqrtCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <moco/Log.h>
+
+#include <loco/Service/TypeInference.h>
+
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+
+template <typename T>
+bool prepare_const_gen(loco::ConstGen *const_node, const loco::TensorShape &tensorshape, T value);
+
+template <>
+bool prepare_const_gen<float>(loco::ConstGen *const_node, const loco::TensorShape &tensorshape,
+ float value)
+{
+ LOGGER(l);
+
+ uint32_t const_num_elements = 1;
+
+ auto dtype = loco::DataType::FLOAT32;
+ const_node->dtype(dtype);
+
+ auto rank = tensorshape.rank();
+ const_node->rank(rank);
+ for (uint32_t r = 0; r < rank; ++r)
+ {
+ if (tensorshape.dim(r).known())
+ const_node->dim(r) = tensorshape.dim(r);
+ else
+ return false;
+
+ assert(tensorshape.dim(r).value() > 0);
+
+ const_num_elements *= tensorshape.dim(r).value();
+ }
+
+ INFO(l) << "prepare_const_gen : Elements = " << const_num_elements;
+
+ const_node->size<loco::DataType::FLOAT32>(const_num_elements);
+ for (uint32_t i = 0; i < const_num_elements; ++i)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = value;
+ }
+
+ return true;
+}
+
+bool canonicalize_rsqrt(loco::Graph *graph, moco::TFRsqrt *node)
+{
+ /**
+ * @note This will replace TFRsqrt node with Canonical EltwiseSqrt + EltwiseRealDiv
+ *
+ * Before
+ * A --- TFRsqrt -- C
+ * After
+ * +- TFRsqrt --
+ * |
+ * | ConstGen --+
+ * | \
+ * A -+- EltwiseSqrt -- EltwiseDiv -- C
+ *
+ * Where
+ * A : features of TFRsqrt
+ * C : a node that uses TFSqrt as an input
+ * TFRsqrt is disconnected from C
+ * TFRsqrt is converted to 1 / EltwiseSqrt
+ */
+
+ auto nodeshape = moco::node_shape(node);
+ if (nodeshape.domain() == loco::Domain::Unknown)
+ {
+ // We need this shape information
+ assert(false); // this shouldn't happen, let's add an alarm
+ return false;
+ }
+ auto tensorshape = nodeshape.as<loco::TensorShape>();
+
+ if (!loco::dtype_known(node))
+ {
+ // We need type of this node
+ return false;
+ }
+
+ auto sqrt_node = graph->nodes()->create<loco::EltwiseSqrt>();
+ auto eltdiv_node = graph->nodes()->create<loco::EltwiseDiv>();
+ auto const_node = graph->nodes()->create<loco::ConstGen>();
+
+ auto dtype = loco::dtype_get(node);
+
+ switch (dtype)
+ {
+ case loco::DataType::FLOAT32:
+ if (!prepare_const_gen<float>(const_node, tensorshape, 1.0f))
+ throw oops::UserExn("Cannot handle unknown shape", node->name());
+ break;
+
+ default:
+ throw oops::UserExn("Unsupported data type", node->name());
+ }
+
+ auto node_A = node->x();
+
+ // update connections
+ sqrt_node->input(node_A);
+ eltdiv_node->lhs(const_node);
+ eltdiv_node->rhs(sqrt_node);
+
+ // replace node
+ replace(node).with(eltdiv_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool RsqrtCanonicalizer::transform(TFRsqrt *node) const
+{
+ return canonicalize_rsqrt(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.h
new file mode 100644
index 000000000..7fd4ff697
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/RsqrtCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_RSQRT_CANONICALIZER_H__
+#define __MOCO_TF_RSQRT_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFRsqrt to Canonical EltwiseDiv + EltwiseSqrt
+ */
+class RsqrtCanonicalizer : public SimpleNodeTransform<moco::TFRsqrt>
+{
+public:
+ const char *name(void) const final { return "RsqrtCanonicalizer"; }
+
+public:
+ bool transform(moco::TFRsqrt *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_RSQRT_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.cpp
new file mode 100644
index 000000000..98af7b693
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "SoftmaxCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_softmax(loco::Graph *graph, moco::TFSoftmax *node)
+{
+ LOGGER(l);
+
+ INFO(l) << "TFNodeCanonicalize TFSoftmax begin";
+
+ /**
+ * This will replace shape inferred TFSoftmax node into canonical TensorSoftmax
+ *
+ * Before
+ * In ---- TFSoftmax ---- Out(s)
+ *
+ * After
+ * ------ TFSoftmax
+ * /
+ * In ---- TensorSoftmax ----- Out(s)
+ */
+
+ auto nodeshape = moco::node_shape(node);
+ // Canonicalization into TensorSoftmax is valid when softmax has shape info
+ assert(nodeshape.domain() != loco::Domain::Unknown);
+
+ auto softmax_tensor_shape = nodeshape.as<loco::TensorShape>();
+
+ // Create loco node to replace
+ auto softmax = graph->nodes()->create<loco::TensorSoftmax>();
+
+ // replace
+ auto in = node->logits();
+ softmax->input(in);
+ softmax->axis(softmax_tensor_shape.rank() - 1);
+ replace(node).with(softmax);
+
+ INFO(l) << "TFNodeCanonicalize TFSoftmax done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool SoftmaxCanonicalizer::transform(TFSoftmax *node) const
+{
+ return canonicalize_softmax(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.h
new file mode 100644
index 000000000..ebaf04cfe
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SoftmaxCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_SOFTMAX_CANONICALIZER_H__
+#define __MOCO_TF_SOFTMAx_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+* @brief Canonicalize TF-dialect TFSoftmax into canonical Softmax node
+*/
+class SoftmaxCanonicalizer : public SimpleNodeTransform<moco::TFSoftmax>
+{
+public:
+ const char *name(void) const final { return "SoftmaxCanonicalizer"; }
+
+public:
+ bool transform(moco::TFSoftmax *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_SOFTMAX_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.cpp
new file mode 100644
index 000000000..89b9b8a44
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "SqrtCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+namespace
+{
+
+bool canonicalize_sqrt(loco::Graph *graph, moco::TFSqrt *node)
+{
+ /**
+ * @note This will replace TFSqrt node with Canonical EltwiseSqrt
+ *
+ * Before
+ * A --- TFSqrt -- C
+ * After
+ * +- TFSqrt --
+ * |
+ * A -+- EltwiseSqrt -- C
+ *
+ * Where
+ * A : features of TFSqrt
+ * C : a node that uses TFSqrt as an input
+ * TFSqrt is disconnected from C
+ */
+
+ auto sqrt_node = graph->nodes()->create<loco::EltwiseSqrt>();
+
+ auto node_A = node->x();
+
+ // update connections
+ sqrt_node->input(node_A);
+
+ // replace node
+ replace(node).with(sqrt_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool SqrtCanonicalizer::transform(TFSqrt *node) const
+{
+ return canonicalize_sqrt(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.h
new file mode 100644
index 000000000..3f7ffead8
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SqrtCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_SQRT_CANONICALIZER_H__
+#define __MOCO_TF_SQRT_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFsqrt to Canonical EltwiseSqrt
+ */
+class SqrtCanonicalizer : public SimpleNodeTransform<moco::TFSqrt>
+{
+public:
+ const char *name(void) const final { return "SqrtCanonicalizer"; }
+
+public:
+ bool transform(moco::TFSqrt *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_SQRT_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.cpp
new file mode 100644
index 000000000..f5b991206
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "SqueezeCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+#include <moco/Support/TFShapeInferenceHelper.h>
+
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_squeeze_to_reshape(loco::Graph *graph, moco::TFSqueeze *node)
+{
+ LOGGER(l);
+
+ INFO(l) << "TFNodeCanonicalize TFSqueeze begin";
+
+ /**
+ * This will replace shape inferred TFSqueeze node into canonical FixedReshape
+ *
+ * Before
+ * In ---- TFSqueeze ---- Out(s)
+ *
+ * After
+ * ------ TFSqueeze
+ * /
+ * In ---- FixedReshape ----- Out(s)
+ */
+
+ auto nodeshape = moco::node_shape(node);
+ // canonicalize into FixedReshape is valid when squeeze has shape info
+ // TODO Support general Squeeze case
+ assert(nodeshape.domain() != loco::Domain::Unknown);
+
+ auto squeeze_tensor_shape = nodeshape.as<loco::TensorShape>();
+
+ // Create loco node to replace
+ auto reshape = graph->nodes()->create<loco::FixedReshape>();
+
+ // Copy shape
+ reshape->rank(squeeze_tensor_shape.rank());
+ for (uint32_t axis = 0; axis < squeeze_tensor_shape.rank(); ++axis)
+ {
+ assert(squeeze_tensor_shape.dim(axis).known());
+ reshape->dim(axis) = squeeze_tensor_shape.dim(axis);
+ }
+
+ // replace
+ auto in = node->input();
+ reshape->input(in);
+ replace(node).with(reshape);
+
+ INFO(l) << "TFNodeCanonicalize TFSqueeze done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool SqueezeCanonicalizer::transform(TFSqueeze *node) const
+{
+ return canonicalize_squeeze_to_reshape(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.h
new file mode 100644
index 000000000..28a1442bd
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SqueezeCanonicalizer.h
@@ -0,0 +1,49 @@
+/*
+ * 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_SQUEEZE_CANONICALIZER_H__
+#define __MOCO_TF_SQUEEZE_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Canonicalize TF-dialect TFSqueeze into canonical FixedReshape node
+ *
+ * @note There is no canonical Squeeze node
+ */
+class SqueezeCanonicalizer : public SimpleNodeTransform<moco::TFSqueeze>
+{
+public:
+ const char *name(void) const final { return "SqueezeCanonicalizer"; }
+
+public:
+ bool transform(moco::TFSqueeze *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_SQUEEZE_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.cpp
new file mode 100644
index 000000000..574fa3993
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "StopGradientCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <moco/Log.h>
+
+namespace
+{
+
+bool canonicalize_stopgradient(loco::Graph *graph, moco::TFStopGradient *node)
+{
+ LOGGER(l);
+
+ INFO(l) << "TFNodeCanonicalize TFStopGradient begin";
+
+ /**
+ * This will replace shape inferred TFStopGradient node into canonical Forward
+ *
+ * Before
+ * In --- TFStopGradient --- Out(s)
+ *
+ * After
+ * -- TFStopGradient
+ * /
+ * In --- Forward --- Out(s)
+ */
+
+ // Create loco node to replace
+ auto forward_node = graph->nodes()->create<loco::Forward>();
+
+ // update connection
+ forward_node->input(node->input());
+
+ // replace node
+ replace(node).with(forward_node);
+
+ INFO(l) << "TFNodeCanonicalize TFStopGradient done";
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool StopGradientCanonicalizer::transform(TFStopGradient *node) const
+{
+ return canonicalize_stopgradient(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.h
new file mode 100644
index 000000000..6a17728a6
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/StopGradientCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_STOPGRADIENT_CANONICALIZER_H__
+#define __MOCO_TF_STOPGRADIENT_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+* @brief Canonicalize TF-dialect TFStopGradient into canonical Forward node
+*/
+class StopGradientCanonicalizer : public SimpleNodeTransform<moco::TFStopGradient>
+{
+public:
+ const char *name(void) const final { return "StopGradientCanonicalizer"; }
+
+public:
+ bool transform(moco::TFStopGradient *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_STOPGRADIENT_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.cpp
new file mode 100644
index 000000000..c518b7d64
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "SubCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include "TFEltwiseBinaryCanonicalzeHelper.h"
+
+namespace moco
+{
+namespace tf
+{
+
+bool SubCanonicalizer::transform(moco::TFSub *node) const
+{
+ return canonicalize_eltwise_binary_node(node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.h
new file mode 100644
index 000000000..f715cc86c
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/SubCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_SUB_CANONICALIZER_H__
+#define __MOCO_TF_SUB_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFSub to Canonical EltwiseSub
+ */
+class SubCanonicalizer : public SimpleNodeTransform<moco::TFSub>
+{
+public:
+ const char *name(void) const final { return "SubCanonicalizer"; }
+
+public:
+ bool transform(moco::TFSub *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_SUB_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.cpp
new file mode 100644
index 000000000..081e0e5f9
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "TFPushCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool canonicalize_push(loco::Graph *graph, moco::TFPush *node)
+{
+ /**
+ * @note This will replace TFRelu node with Canonical ReLU
+ *
+ * Before
+ * A --- TFPush
+ * After
+ * +- TFPush
+ * |
+ * A -+- Push
+ *
+ * Where
+ * A : from of TFPush
+ * TFPush will have no GraphOutputIndex
+ * Push will have GraphOutputIndex that from TFPush
+ */
+
+ auto push_node = graph->nodes()->create<loco::Push>();
+
+ auto node_A = node->from();
+
+ // update connections
+ push_node->from(node_A);
+
+ // update output index
+ push_node->index(node->index());
+ node->index_reset();
+
+ // replace node
+ replace(node).with(push_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool TFPushCanonicalizer::transform(TFPush *node) const
+{
+ return canonicalize_push(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.h
new file mode 100644
index 000000000..569a71f82
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/TFPushCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_PUSH_CANONICALIZER_H__
+#define __MOCO_TF_PUSH_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFPush to Canonical Push
+ */
+class TFPushCanonicalizer : public SimpleNodeTransform<moco::TFPush>
+{
+public:
+ const char *name(void) const final { return "TFPushCanonicalizer"; }
+
+public:
+ bool transform(moco::TFPush *) const final;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_PUSH_CANONICALIZER_H__
diff --git a/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.cpp b/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.cpp
new file mode 100644
index 000000000..3f48a50fc
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "TanhCanonicalizer.h"
+
+#include <moco/IR/TFDialect.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+bool canonicalize_tanh(loco::Graph *graph, moco::TFTanh *node)
+{
+ /**
+ * @note This will replace TFTanh node with Canonical Tanh
+ *
+ * Before
+ * A --- TFTanh -- C
+ * After
+ * +- TFTanh --
+ * |
+ * A -+-- Tanh --- C
+ *
+ * Where
+ * A : x of TFTanh
+ * C : a node that uses TFTanh as an input
+ * TFTanh is disconnected from C
+ */
+
+ auto tanh_node = graph->nodes()->create<loco::Tanh>();
+
+ auto node_A = node->x();
+
+ // update connections
+ tanh_node->input(node_A);
+
+ // replace node
+ replace(node).with(tanh_node);
+
+ return true;
+}
+
+} // namespace
+
+namespace moco
+{
+namespace tf
+{
+
+bool TanhCanonicalizer::transform(TFTanh *node) const
+{
+ return canonicalize_tanh(node->graph(), node);
+}
+
+} // namespace tf
+} // namespace moco
diff --git a/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.h b/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.h
new file mode 100644
index 000000000..af5e79fb5
--- /dev/null
+++ b/compiler/moco-tf/src/Canonicalization/TanhCanonicalizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_TANH_CANONICALIZER_H__
+#define __MOCO_TF_TANH_CANONICALIZER_H__
+
+#include "Transform.h"
+#include "SimpleNodeTransform.h"
+
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+
+namespace moco
+{
+namespace tf
+{
+
+/**
+ * @brief Convert TFTanh to Canonical Tanh
+ */
+class TanhCanonicalizer : public SimpleNodeTransform<moco::TFTanh>
+{
+public:
+ const char *name(void) const final { return "TanhCanonicalizer"; }
+
+public:
+ bool transform(moco::TFTanh *) const override;
+};
+
+} // namespace tf
+} // namespace moco
+
+#endif // __MOCO_TF_TANH_CANONICALIZER_H__