diff options
author | Chunseok Lee <chunseok.lee@samsung.com> | 2020-04-23 14:45:49 +0900 |
---|---|---|
committer | Chunseok Lee <chunseok.lee@samsung.com> | 2020-04-23 14:45:49 +0900 |
commit | e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (patch) | |
tree | 44a1a7951d168dd4370e13593ed03f4bc6d920c5 /compiler/moco-tf/src/Canonicalization | |
parent | 302e6564a7a76109e1178207e44e45a58631c477 (diff) | |
download | nnfw-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')
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__ |