summaryrefslogtreecommitdiff
path: root/compiler/moco/import
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2020-04-23 14:45:49 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2020-04-23 14:45:49 +0900
commite2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (patch)
tree44a1a7951d168dd4370e13593ed03f4bc6d920c5 /compiler/moco/import
parent302e6564a7a76109e1178207e44e45a58631c477 (diff)
downloadnnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.gz
nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.bz2
nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.zip
Imported Upstream version 1.4.0upstream/1.4.0submit/tizen/20200423.054851
Diffstat (limited to 'compiler/moco/import')
-rw-r--r--compiler/moco/import/CMakeLists.txt26
-rw-r--r--compiler/moco/import/README.md3
-rw-r--r--compiler/moco/import/include/moco/GraphHelper.h59
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilder.h40
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilderContext.h144
-rw-r--r--compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h87
-rw-r--r--compiler/moco/import/include/moco/Import/ModelSignature.h80
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes.h53
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Add.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/AvgPool.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Concat.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Const.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Conv2D.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Identity.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/MaxPool.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Maximum.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Mean.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Mul.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Pack.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Pad.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Placeholder.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/RealDiv.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Relu.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Relu6.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Reshape.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Shape.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Softmax.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Sqrt.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Squeeze.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/StopGradient.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h34
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Sub.h37
-rw-r--r--compiler/moco/import/include/moco/Import/Nodes/Tanh.h37
-rw-r--r--compiler/moco/import/include/moco/Importer.h54
-rw-r--r--compiler/moco/import/src/Convert.cpp34
-rw-r--r--compiler/moco/import/src/Convert.h31
-rw-r--r--compiler/moco/import/src/GraphBuilderContext.cpp80
-rw-r--r--compiler/moco/import/src/GraphBuilderContext.test.cpp77
-rw-r--r--compiler/moco/import/src/GraphBuilderRegistry.cpp63
-rw-r--r--compiler/moco/import/src/Importer.cpp197
-rw-r--r--compiler/moco/import/src/Importer.test.cpp223
-rw-r--r--compiler/moco/import/src/ModelSignature.cpp66
-rw-r--r--compiler/moco/import/src/Nodes/Add.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Add.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/AvgPool.cpp140
-rw-r--r--compiler/moco/import/src/Nodes/AvgPool.test.cpp99
-rw-r--r--compiler/moco/import/src/Nodes/BiasAdd.cpp122
-rw-r--r--compiler/moco/import/src/Nodes/BiasAdd.test.cpp112
-rw-r--r--compiler/moco/import/src/Nodes/Concat.cpp109
-rw-r--r--compiler/moco/import/src/Nodes/Concat.test.cpp134
-rw-r--r--compiler/moco/import/src/Nodes/Const.cpp242
-rw-r--r--compiler/moco/import/src/Nodes/Const.test.cpp465
-rw-r--r--compiler/moco/import/src/Nodes/Conv2D.cpp139
-rw-r--r--compiler/moco/import/src/Nodes/Conv2D.test.cpp119
-rw-r--r--compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp140
-rw-r--r--compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp98
-rw-r--r--compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp148
-rw-r--r--compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp97
-rw-r--r--compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp123
-rw-r--r--compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/FusedBatchNorm.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp88
-rw-r--r--compiler/moco/import/src/Nodes/Identity.cpp95
-rw-r--r--compiler/moco/import/src/Nodes/MaxPool.cpp145
-rw-r--r--compiler/moco/import/src/Nodes/MaxPool.test.cpp98
-rw-r--r--compiler/moco/import/src/Nodes/Maximum.cpp87
-rw-r--r--compiler/moco/import/src/Nodes/Maximum.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Mean.cpp99
-rw-r--r--compiler/moco/import/src/Nodes/Mean.test.cpp120
-rw-r--r--compiler/moco/import/src/Nodes/Mul.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Mul.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Pack.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/Pack.test.cpp84
-rw-r--r--compiler/moco/import/src/Nodes/Pad.cpp91
-rw-r--r--compiler/moco/import/src/Nodes/Pad.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/Placeholder.cpp90
-rw-r--r--compiler/moco/import/src/Nodes/Placeholder.test.cpp71
-rw-r--r--compiler/moco/import/src/Nodes/RealDiv.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/RealDiv.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Relu.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/Relu.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Relu6.cpp80
-rw-r--r--compiler/moco/import/src/Nodes/Relu6.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Reshape.cpp102
-rw-r--r--compiler/moco/import/src/Nodes/Reshape.test.cpp61
-rw-r--r--compiler/moco/import/src/Nodes/Rsqrt.cpp82
-rw-r--r--compiler/moco/import/src/Nodes/Rsqrt.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/Shape.cpp100
-rw-r--r--compiler/moco/import/src/Nodes/Shape.test.cpp65
-rw-r--r--compiler/moco/import/src/Nodes/Softmax.cpp86
-rw-r--r--compiler/moco/import/src/Nodes/Softmax.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Sqrt.cpp81
-rw-r--r--compiler/moco/import/src/Nodes/Sqrt.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/SquaredDifference.cpp92
-rw-r--r--compiler/moco/import/src/Nodes/SquaredDifference.test.cpp59
-rw-r--r--compiler/moco/import/src/Nodes/Squeeze.cpp112
-rw-r--r--compiler/moco/import/src/Nodes/Squeeze.test.cpp109
-rw-r--r--compiler/moco/import/src/Nodes/StopGradient.cpp87
-rw-r--r--compiler/moco/import/src/Nodes/StopGradient.test.cpp57
-rw-r--r--compiler/moco/import/src/Nodes/StridedSlice.cpp187
-rw-r--r--compiler/moco/import/src/Nodes/StridedSlice.test.cpp107
-rw-r--r--compiler/moco/import/src/Nodes/Sub.cpp85
-rw-r--r--compiler/moco/import/src/Nodes/Sub.test.cpp58
-rw-r--r--compiler/moco/import/src/Nodes/Tanh.cpp81
-rw-r--r--compiler/moco/import/src/Nodes/Tanh.test.cpp57
-rw-r--r--compiler/moco/import/src/TestHelper.h83
-rw-r--r--compiler/moco/import/src/TestHelper.test.cpp101
114 files changed, 8957 insertions, 0 deletions
diff --git a/compiler/moco/import/CMakeLists.txt b/compiler/moco/import/CMakeLists.txt
new file mode 100644
index 000000000..43107776e
--- /dev/null
+++ b/compiler/moco/import/CMakeLists.txt
@@ -0,0 +1,26 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(moco_import SHARED ${SOURCES})
+target_include_directories(moco_import PRIVATE src)
+target_include_directories(moco_import PUBLIC include)
+target_link_libraries(moco_import PUBLIC moco_lang)
+target_link_libraries(moco_import PUBLIC mio_tf)
+target_link_libraries(moco_import PUBLIC stdex)
+target_link_libraries(moco_import PRIVATE nncc_common)
+target_link_libraries(moco_import PRIVATE plier_tf)
+target_link_libraries(moco_import PRIVATE oops)
+install(TARGETS moco_import DESTINATION lib) # moco_tf_frontend requires moco_import
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(moco_import_test ${TESTS})
+target_include_directories(moco_import_test PRIVATE src)
+target_link_libraries(moco_import_test moco_import)
+target_link_libraries(moco_import_test plier_tf)
+target_link_libraries(moco_import_test oops)
diff --git a/compiler/moco/import/README.md b/compiler/moco/import/README.md
new file mode 100644
index 000000000..2704d35d6
--- /dev/null
+++ b/compiler/moco/import/README.md
@@ -0,0 +1,3 @@
+# moco-import
+
+_moco-import_ provides importing TensorFlow model file to _moco_ TensorFlow Dialect IR
diff --git a/compiler/moco/import/include/moco/GraphHelper.h b/compiler/moco/import/include/moco/GraphHelper.h
new file mode 100644
index 000000000..fad62af4e
--- /dev/null
+++ b/compiler/moco/import/include/moco/GraphHelper.h
@@ -0,0 +1,59 @@
+/*
+ * 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_GRAPH_HELPER_H__
+#define __MOCO_GRAPH_HELPER_H__
+
+#include <moco/IR/TFNode.h>
+
+#include <loco.h>
+
+namespace moco
+{
+
+/**
+ * @brief find_node_byname() will return a node with type T with given name
+ * in graph g
+ *
+ * @note this uses simple linear search, but can speed up with better
+ * algorithms when needed.
+ */
+template <typename T> T *find_node_byname(loco::Graph *g, const char *name)
+{
+ T *first_node = nullptr;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ auto tfnode = dynamic_cast<TFNode *>(nodes->at(i));
+ if (tfnode != nullptr)
+ {
+ if (tfnode->name() == name)
+ {
+ // if tfnode is NOT type of T then return will be nullptr
+ // this is OK cause the user wanted to get type T but it isn't
+ return dynamic_cast<T *>(tfnode);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace moco
+
+#endif // __MOCO_GRAPH_HELPER_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilder.h b/compiler/moco/import/include/moco/Import/GraphBuilder.h
new file mode 100644
index 000000000..c19918def
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilder.h
@@ -0,0 +1,40 @@
+/*
+ * 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_IMPORT_GRAPH_BUILDER_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_H__
+
+#include "GraphBuilderContext.h"
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+namespace moco
+{
+
+/**
+ * @brief Interface of convert TF NodeDef to loco::Node (e.g., Conv2DGraphBuilder)
+ */
+class GraphBuilder
+{
+public:
+ virtual bool validate(const tensorflow::NodeDef &) const = 0;
+ virtual void build(const tensorflow::NodeDef &, GraphBuilderContext *) const = 0;
+ virtual ~GraphBuilder() {}
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilderContext.h b/compiler/moco/import/include/moco/Import/GraphBuilderContext.h
new file mode 100644
index 000000000..ae4f02c2a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilderContext.h
@@ -0,0 +1,144 @@
+/*
+ * 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_IMPORT_GRAPH_BUILDER_CONTEXT_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_CONTEXT_H__
+
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace moco
+{
+
+/**
+ * @brief Class to store and query tensorflow::NodeDef* with string name key
+ */
+class NodeDefTable
+{
+public:
+ /**
+ * @brief Registers a name with corresponding tensorflow::NodeDef*
+ */
+ void enroll(const std::string &node_name, const tensorflow::NodeDef *node);
+ /**
+ * @brief Queries enrolled(registered) with name and return node if found
+ * Will throw runtime_error if not found
+ */
+ const tensorflow::NodeDef *node(const std::string &node_name) const;
+
+private:
+ using MapNameNode_t = std::map<std::string, const tensorflow::NodeDef *>;
+
+ MapNameNode_t _table;
+};
+
+/**
+ * @brief Class to store and query loco::Node* with string name key
+ */
+class SymbolTable
+{
+public:
+ /**
+ * @brief Registers a name with corresponding loco::Node *
+ */
+ void enroll(const TensorName &tensor_name, loco::Node *node);
+ /**
+ * @brief Queries enrolled(registered) with name and return node if found
+ * Will throw runtime_error if not found
+ */
+ loco::Node *node(const TensorName &tensor_name) const;
+
+private:
+ using MapNameNode_t = std::map<TensorName, loco::Node *, TensorNameCompare>;
+
+ MapNameNode_t _table;
+};
+
+/**
+ * @brief Interface to connect the graph
+ */
+class GraphUpdate
+{
+public:
+ virtual ~GraphUpdate() = default;
+
+public:
+ /**
+ * @brief Do the graph input connections using the SymbolTable
+ */
+ virtual void input(const SymbolTable *) const = 0;
+};
+
+/**
+ * @brief Class to store GraphUpdate objects
+ */
+class UpdateQueue final
+{
+public:
+ /**
+ * @brief Registers GraphUpdate objects
+ */
+ void enroll(std::unique_ptr<GraphUpdate> &&update);
+
+public:
+ using Queue = std::vector<std::unique_ptr<GraphUpdate>>;
+
+ const Queue &queue() const { return _queue; }
+
+private:
+ Queue _queue;
+};
+
+/**
+ * @brief Class to store context to build loco graph IR from TensorFlow
+ */
+class GraphBuilderContext
+{
+public:
+ GraphBuilderContext(loco::Graph *g, NodeDefTable *nodedef, SymbolTable *tensor_names,
+ UpdateQueue *updates)
+ : _g(g), _nodedef(nodedef), _tensor_names(tensor_names), _updates(updates)
+ {
+ // DO NOTHING
+ }
+
+ GraphBuilderContext(const GraphBuilderContext &) = delete;
+ GraphBuilderContext(GraphBuilderContext &&) = delete;
+
+public:
+ loco::Graph *graph() { return _g; }
+ NodeDefTable *nodedef() { return _nodedef; }
+ SymbolTable *tensor_names() { return _tensor_names; }
+ UpdateQueue *updates() { return _updates; }
+
+private:
+ loco::Graph *_g;
+ NodeDefTable *_nodedef;
+ SymbolTable *_tensor_names;
+ UpdateQueue *_updates;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_CONTEXT_H__
diff --git a/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h b/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h
new file mode 100644
index 000000000..da65cffb8
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/GraphBuilderRegistry.h
@@ -0,0 +1,87 @@
+/*
+ * 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_IMPORT_GRAPH_BUILDER_REGISTRY_H__
+#define __MOCO_IMPORT_GRAPH_BUILDER_REGISTRY_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+namespace moco
+{
+
+struct GraphBuilderSource
+{
+ virtual ~GraphBuilderSource() = default;
+
+ /**
+ * @brief Returns registered GraphBuilder pointer for operator (nullptr if not present)
+ */
+ virtual const GraphBuilder *lookup(const std::string &op) const = 0;
+};
+
+/**
+ * @brief Class to return graph builder for TF nodes
+ */
+class GraphBuilderRegistry final : public GraphBuilderSource
+{
+public:
+ GraphBuilderRegistry();
+
+public:
+ GraphBuilderRegistry(const GraphBuilderSource *parent) : _parent{parent}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Returns registered GraphBuilder pointer for operator or
+ * nullptr if not registered
+ */
+ const GraphBuilder *lookup(const std::string &op) const final
+ {
+ if (_builder_map.find(op) == _builder_map.end())
+ return (_parent == nullptr) ? nullptr : _parent->lookup(op);
+
+ return _builder_map.at(op).get();
+ }
+
+ static GraphBuilderRegistry &get()
+ {
+ static GraphBuilderRegistry me;
+ return me;
+ }
+
+public:
+ void add(const std::string op, std::unique_ptr<GraphBuilder> &&builder)
+ {
+ _builder_map[op] = std::move(builder);
+ }
+
+private:
+ const GraphBuilderSource *_parent = nullptr;
+
+private:
+ std::map<const std::string, std::unique_ptr<GraphBuilder>> _builder_map;
+};
+
+} // namespace mono
+
+#endif // __MOCO_IMPORT_GRAPH_BUILDER_REGISTRY_H__
diff --git a/compiler/moco/import/include/moco/Import/ModelSignature.h b/compiler/moco/import/include/moco/Import/ModelSignature.h
new file mode 100644
index 000000000..0db7c2795
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/ModelSignature.h
@@ -0,0 +1,80 @@
+/*
+ * 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_IMPORT_MODELSIGNATURE_H__
+#define __MOCO_IMPORT_MODELSIGNATURE_H__
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <angkor/TensorShape.h>
+
+#include <string>
+#include <vector>
+
+namespace moco
+{
+
+/**
+ * @brief Class to store information to run a model. Normally this info comes from users
+ * via CLI params or configuration file.
+ */
+struct ModelSignature
+{
+public:
+ void add_input(const TensorName &input) { _inputs.push_back(input); }
+ void add_input(const TensorName &&input) { _inputs.push_back(input); }
+ void add_output(const TensorName &output) { _outputs.push_back(output); }
+ void add_output(const TensorName &&output) { _outputs.push_back(output); }
+
+ const std::vector<TensorName> &inputs() const { return _inputs; }
+ const std::vector<TensorName> &outputs() const { return _outputs; }
+
+ /**
+ * @brief Adds customop op type (not name of node) provided from user
+ */
+ void add_customop(const std::string &op);
+ const std::vector<std::string> &customops() const { return _customops; }
+
+ /**
+ * @brief Adds node name and its shape provided from user
+ */
+ void shape(const std::string &node_name, const angkor::TensorShape &shape);
+ const angkor::TensorShape *shape(const std::string &node_name) const;
+
+ /**
+ * @brief Adds node name and its dtype provided from user
+ */
+ void dtype(const std::string &node_name, loco::DataType dtype);
+ loco::DataType dtype(const std::string &node_name) const;
+
+private:
+ std::vector<TensorName> _inputs; // graph inputs
+ std::vector<TensorName> _outputs; // graph outputs
+
+ // For custom op types passed from user (e.g., via CLI)
+ std::vector<std::string> _customops;
+
+ // For and node names and shapes passed from user (e.g., via CLI)
+ std::map<std::string, angkor::TensorShape> _shapes;
+
+ // For and node names and dtype passed from user (e.g., via CLI)
+ std::map<std::string, loco::DataType> _dtypes;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_MODELSIGNATURE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes.h b/compiler/moco/import/include/moco/Import/Nodes.h
new file mode 100644
index 000000000..8c940a28c
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes.h
@@ -0,0 +1,53 @@
+/*
+ * 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_IMPORT_NODES_H__
+#define __MOCO_IMPORT_NODES_H__
+
+#include "Nodes/Add.h"
+#include "Nodes/AvgPool.h"
+#include "Nodes/BiasAdd.h"
+#include "Nodes/Concat.h"
+#include "Nodes/Const.h"
+#include "Nodes/Conv2DBackpropInput.h"
+#include "Nodes/Conv2D.h"
+#include "Nodes/DepthwiseConv2dNative.h"
+#include "Nodes/FakeQuantWithMinMaxVars.h"
+#include "Nodes/FusedBatchNorm.h"
+#include "Nodes/Identity.h"
+#include "Nodes/Maximum.h"
+#include "Nodes/MaxPool.h"
+#include "Nodes/Mean.h"
+#include "Nodes/Mul.h"
+#include "Nodes/Pack.h"
+#include "Nodes/Pad.h"
+#include "Nodes/Placeholder.h"
+#include "Nodes/RealDiv.h"
+#include "Nodes/Relu6.h"
+#include "Nodes/Relu.h"
+#include "Nodes/Reshape.h"
+#include "Nodes/Rsqrt.h"
+#include "Nodes/Shape.h"
+#include "Nodes/Softmax.h"
+#include "Nodes/Sqrt.h"
+#include "Nodes/SquaredDifference.h"
+#include "Nodes/Squeeze.h"
+#include "Nodes/StopGradient.h"
+#include "Nodes/StridedSlice.h"
+#include "Nodes/Sub.h"
+#include "Nodes/Tanh.h"
+
+#endif // __MOCO_IMPORT_NODES_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Add.h b/compiler/moco/import/include/moco/Import/Nodes/Add.h
new file mode 100644
index 000000000..3d0d0f30f
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Add.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_ADD_H__
+#define __MOCO_IMPORT_OP_ADD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Add node
+ */
+class AddGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_ADD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/AvgPool.h b/compiler/moco/import/include/moco/Import/Nodes/AvgPool.h
new file mode 100644
index 000000000..4c8087afe
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/AvgPool.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_AVG_POOL_H__
+#define __MOCO_IMPORT_OP_AVG_POOL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class AvgPoolGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_AVG_POOL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h b/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h
new file mode 100644
index 000000000..214df03de
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/BiasAdd.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_BIAS_ADD_H__
+#define __MOCO_IMPORT_OP_BIAS_ADD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class BiasAddGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_BIAS_ADD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Concat.h b/compiler/moco/import/include/moco/Import/Nodes/Concat.h
new file mode 100644
index 000000000..2341fb00c
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Concat.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_CONCAT_H__
+#define __MOCO_IMPORT_OP_CONCAT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class ConcatV2GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONCAT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Const.h b/compiler/moco/import/include/moco/Import/Nodes/Const.h
new file mode 100644
index 000000000..1ce378219
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Const.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_CONST_H__
+#define __MOCO_IMPORT_OP_CONST_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class ConstGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONST_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Conv2D.h b/compiler/moco/import/include/moco/Import/Nodes/Conv2D.h
new file mode 100644
index 000000000..3bd3dc74a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Conv2D.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_CONV_2D_H__
+#define __MOCO_IMPORT_OP_CONV_2D_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class Conv2DGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONV_2D_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h b/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h
new file mode 100644
index 000000000..262a443fe
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Conv2DBackpropInput.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
+#define __MOCO_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Conv2DBackpropInput node
+ */
+class Conv2DBackpropInputGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_CONV_2D_BACKPROP_INPUT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h b/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h
new file mode 100644
index 000000000..1dcbba1eb
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/DepthwiseConv2dNative.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
+#define __MOCO_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for DepthwiseConv2dNative node
+ */
+class DepthwiseConv2dNativeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_DEPTHWISE_CONV_2D_NATIVE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h b/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h
new file mode 100644
index 000000000..9e223c18e
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/FakeQuantWithMinMaxVars.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
+#define __MOCO_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for FakeQuantWithMinMaxVars node
+ */
+class FakeQuantWithMinMaxVarsGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_FAKE_QUANT_WITH_MINMAX_VARS_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h b/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h
new file mode 100644
index 000000000..38d1d5682
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/FusedBatchNorm.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_FUSED_BATCH_NORM_H__
+#define __MOCO_IMPORT_OP_FUSED_BATCH_NORM_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for FusedBatchNorm node
+ */
+class FusedBatchNormGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_FUSED_BATCH_NORM_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Identity.h b/compiler/moco/import/include/moco/Import/Nodes/Identity.h
new file mode 100644
index 000000000..29e04800f
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Identity.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_IDENTITY_H__
+#define __MOCO_IMPORT_OP_IDENTITY_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class IdentityGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_IDENTITY_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/MaxPool.h b/compiler/moco/import/include/moco/Import/Nodes/MaxPool.h
new file mode 100644
index 000000000..696fa71e6
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/MaxPool.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_MAX_POOL_H__
+#define __MOCO_IMPORT_OP_MAX_POOL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class MaxPoolGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MAX_POOL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Maximum.h b/compiler/moco/import/include/moco/Import/Nodes/Maximum.h
new file mode 100644
index 000000000..69d897742
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Maximum.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_MAXIMUM_H__
+#define __MOCO_IMPORT_OP_MAXIMUM_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Maximum node
+ */
+class MaximumGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MAXIMUM_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Mean.h b/compiler/moco/import/include/moco/Import/Nodes/Mean.h
new file mode 100644
index 000000000..7bae1bb39
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Mean.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_MEAN_H__
+#define __MOCO_IMPORT_OP_MEAN_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Mean node
+ */
+class MeanGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MEAN_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Mul.h b/compiler/moco/import/include/moco/Import/Nodes/Mul.h
new file mode 100644
index 000000000..667c81954
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Mul.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_MUL_H__
+#define __MOCO_IMPORT_OP_MUL_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Mul node
+ */
+class MulGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_MUL_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Pack.h b/compiler/moco/import/include/moco/Import/Nodes/Pack.h
new file mode 100644
index 000000000..94666ad51
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Pack.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_PACK_H__
+#define __MOCO_IMPORT_OP_PACK_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class PackGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PACK_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Pad.h b/compiler/moco/import/include/moco/Import/Nodes/Pad.h
new file mode 100644
index 000000000..22eab32ac
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Pad.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_PAD_H__
+#define __MOCO_IMPORT_OP_PAD_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Pad node
+ */
+class PadGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PAD_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h b/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h
new file mode 100644
index 000000000..458600915
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Placeholder.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_PLACEHOLDER_H__
+#define __MOCO_IMPORT_OP_PLACEHOLDER_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Placeholder node
+ */
+class PlaceholderGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_PLACEHOLDER_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h b/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h
new file mode 100644
index 000000000..142e8b5f8
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/RealDiv.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_REALDIV_H__
+#define __MOCO_IMPORT_OP_REALDIV_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for RealDiv node
+ */
+class RealDivGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_REALDIV_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Relu.h b/compiler/moco/import/include/moco/Import/Nodes/Relu.h
new file mode 100644
index 000000000..0bd9cff04
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Relu.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_RELU_H__
+#define __MOCO_IMPORT_OP_RELU_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Relu node
+ */
+class ReluGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RELU_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Relu6.h b/compiler/moco/import/include/moco/Import/Nodes/Relu6.h
new file mode 100644
index 000000000..d211b0543
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Relu6.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_RELU6_H__
+#define __MOCO_IMPORT_OP_RELU6_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Relu6 node
+ */
+class Relu6GraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RELU6_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Reshape.h b/compiler/moco/import/include/moco/Import/Nodes/Reshape.h
new file mode 100644
index 000000000..e8bfeee23
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Reshape.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_RESHAPE_H__
+#define __MOCO_IMPORT_OP_RESHAPE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Reshape node
+ */
+class ReshapeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RESHAPE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h b/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h
new file mode 100644
index 000000000..dedc52323
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Rsqrt.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_RSQRT_H__
+#define __MOCO_IMPORT_OP_RSQRT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Rsqrt node
+ */
+class RsqrtGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_RSQRT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Shape.h b/compiler/moco/import/include/moco/Import/Nodes/Shape.h
new file mode 100644
index 000000000..e36e1d546
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Shape.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SHAPE_H__
+#define __MOCO_IMPORT_OP_SHAPE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Shape node
+ */
+class ShapeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SHAPE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Softmax.h b/compiler/moco/import/include/moco/Import/Nodes/Softmax.h
new file mode 100644
index 000000000..43fbb8852
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Softmax.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SOFTMAX_H__
+#define __MOCO_IMPORT_OP_SOFTMAX_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+* @brief GraphBuilder for Softmax node
+*/
+class SoftmaxGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SOFTMAX_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h b/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h
new file mode 100644
index 000000000..d17dc3494
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Sqrt.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SQRT_H__
+#define __MOCO_IMPORT_OP_SQRT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Sqrt node
+ */
+class SqrtGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQRT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h b/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h
new file mode 100644
index 000000000..501464d65
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/SquaredDifference.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SQUARED_DIFFERENCE_H__
+#define __MOCO_IMPORT_OP_SQUARED_DIFFERENCE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for SquaredDifference node
+ */
+class SquaredDifferenceGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQUARED_DIFFERENCE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h b/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h
new file mode 100644
index 000000000..64ead074b
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Squeeze.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SQUEEZE_H__
+#define __MOCO_IMPORT_OP_SQUEEZE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Squeeze node
+ */
+class SqueezeGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SQUEEZE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h b/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h
new file mode 100644
index 000000000..e547a8a8b
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/StopGradient.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_STOP_GRADIENT_H__
+#define __MOCO_IMPORT_OP_STOP_GRADIENT_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for StopGradient node
+ */
+class StopGradientGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_STOP_GRADIENT_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h b/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h
new file mode 100644
index 000000000..61170ebbf
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/StridedSlice.h
@@ -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.
+ */
+
+#ifndef __MOCO_IMPORT_OP_STRIDEDSLICE_H__
+#define __MOCO_IMPORT_OP_STRIDEDSLICE_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+class StridedSliceGraphBuilder : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const final;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const final;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_STRIDEDSLICE_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Sub.h b/compiler/moco/import/include/moco/Import/Nodes/Sub.h
new file mode 100644
index 000000000..d6351e34a
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Sub.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_SUB_H__
+#define __MOCO_IMPORT_OP_SUB_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Sub node
+ */
+class SubGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_SUB_H__
diff --git a/compiler/moco/import/include/moco/Import/Nodes/Tanh.h b/compiler/moco/import/include/moco/Import/Nodes/Tanh.h
new file mode 100644
index 000000000..183e117ef
--- /dev/null
+++ b/compiler/moco/import/include/moco/Import/Nodes/Tanh.h
@@ -0,0 +1,37 @@
+/*
+ * 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_IMPORT_OP_TANH_H__
+#define __MOCO_IMPORT_OP_TANH_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+namespace moco
+{
+
+/**
+ * @brief GraphBuilder for Tanh node
+ */
+class TanhGraphBuilder final : public GraphBuilder
+{
+public:
+ bool validate(const tensorflow::NodeDef &) const override;
+ void build(const tensorflow::NodeDef &, GraphBuilderContext *) const override;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORT_OP_TANH_H__
diff --git a/compiler/moco/import/include/moco/Importer.h b/compiler/moco/import/include/moco/Importer.h
new file mode 100644
index 000000000..ee0660c52
--- /dev/null
+++ b/compiler/moco/import/include/moco/Importer.h
@@ -0,0 +1,54 @@
+/*
+ * 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_IMPORTER_H__
+#define __MOCO_IMPORTER_H__
+
+#include "moco/Import/ModelSignature.h"
+#include "moco/Import/GraphBuilderRegistry.h"
+
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#include <memory>
+
+namespace moco
+{
+
+class Importer final
+{
+public:
+ Importer();
+
+public:
+ explicit Importer(const GraphBuilderSource *source) : _source{source}
+ {
+ // DO NOTHING
+ }
+
+public:
+ std::unique_ptr<loco::Graph> import(const ModelSignature &, tensorflow::GraphDef &) const;
+
+private:
+ const GraphBuilderSource *_source = nullptr;
+};
+
+} // namespace moco
+
+#endif // __MOCO_IMPORTER_H__
diff --git a/compiler/moco/import/src/Convert.cpp b/compiler/moco/import/src/Convert.cpp
new file mode 100644
index 000000000..6285f5eab
--- /dev/null
+++ b/compiler/moco/import/src/Convert.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Convert.h"
+
+#include <algorithm>
+#include <cctype>
+
+// TODO move to some common file
+namespace moco
+{
+
+std::string str_toupper(std::string s)
+{
+ // from https://en.cppreference.com/w/cpp/string/byte/toupper
+ std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
+ return s;
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Convert.h b/compiler/moco/import/src/Convert.h
new file mode 100644
index 000000000..77dab3700
--- /dev/null
+++ b/compiler/moco/import/src/Convert.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONVERT_H__
+#define __CONVERT_H__
+
+#include <string>
+
+// TODO move to some common file
+namespace moco
+{
+
+std::string str_toupper(std::string s);
+
+} // namespace moco
+
+#endif // __CONVERT_H__
diff --git a/compiler/moco/import/src/GraphBuilderContext.cpp b/compiler/moco/import/src/GraphBuilderContext.cpp
new file mode 100644
index 000000000..bbc1d8bd0
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderContext.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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 "moco/Import/GraphBuilderContext.h"
+
+#include <oops/UserExn.h>
+
+#include <stdexcept>
+#include <string>
+
+namespace moco
+{
+
+void NodeDefTable::enroll(const std::string &node_name, const tensorflow::NodeDef *node)
+{
+ MapNameNode_t::iterator iter = _table.find(node_name);
+
+ if (iter != _table.end())
+ {
+ throw oops::UserExn("Duplicate node name in GraphDef", node_name);
+ }
+
+ _table[node_name] = node;
+}
+
+const tensorflow::NodeDef *NodeDefTable::node(const std::string &node_name) const
+{
+ MapNameNode_t::const_iterator iter = _table.find(node_name);
+
+ if (iter == _table.end())
+ {
+ throw oops::UserExn("Cannot find node with name in GraphDef", node_name);
+ }
+
+ return iter->second;
+}
+
+void SymbolTable::enroll(const TensorName &tensor_name, loco::Node *node)
+{
+ MapNameNode_t::iterator iter = _table.find(tensor_name);
+
+ if (iter != _table.end())
+ {
+ throw oops::UserExn("Duplicate node name in GraphDef", tensor_name.name());
+ }
+
+ _table[tensor_name] = node;
+}
+
+loco::Node *SymbolTable::node(const TensorName &tensor_name) const
+{
+ MapNameNode_t::const_iterator iter = _table.find(tensor_name);
+
+ if (iter == _table.end())
+ {
+ throw oops::UserExn("Cannot find node with name in GraphDef", tensor_name.name());
+ }
+
+ return iter->second;
+}
+
+void UpdateQueue::enroll(std::unique_ptr<GraphUpdate> &&update)
+{
+ _queue.push_back(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/GraphBuilderContext.test.cpp b/compiler/moco/import/src/GraphBuilderContext.test.cpp
new file mode 100644
index 000000000..51f6db245
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderContext.test.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "moco/Import/GraphBuilderContext.h"
+#include <moco/Names.h>
+
+#include <loco.h>
+
+#include <oops/UserExn.h>
+
+#include <gtest/gtest.h>
+
+TEST(GraphBuilderContext, ctor)
+{
+ auto graph = loco::make_graph();
+ moco::NodeDefTable nodedef;
+ moco::SymbolTable nodes;
+ moco::UpdateQueue updates;
+
+ moco::GraphBuilderContext context(graph.get(), &nodedef, &nodes, &updates);
+
+ ASSERT_EQ(context.graph(), graph.get());
+ ASSERT_EQ(context.nodedef(), &nodedef);
+ ASSERT_EQ(context.tensor_names(), &nodes);
+ ASSERT_EQ(context.updates(), &updates);
+}
+
+TEST(SymbolTable, node_name)
+{
+ moco::SymbolTable table;
+ loco::Pull pull_node;
+ moco::TensorName name("input", 0);
+ moco::TensorName invalid("invalid", 0);
+
+ table.enroll(name, &pull_node);
+ ASSERT_EQ(table.node(name), &pull_node);
+ // duplicate name should throw
+ EXPECT_THROW(table.enroll(name, &pull_node), oops::UserExn);
+ // unregistered name should throw
+ EXPECT_THROW(table.node(invalid), oops::UserExn);
+}
+
+namespace
+{
+
+class TestGraphUpdate final : public moco::GraphUpdate
+{
+public:
+ void input(const moco::SymbolTable *) const override;
+};
+
+void TestGraphUpdate::input(const moco::SymbolTable *) const {}
+
+} // namespace
+
+TEST(GraphUpdateQueue, queue)
+{
+ std::unique_ptr<TestGraphUpdate> update(new TestGraphUpdate());
+ moco::UpdateQueue updates;
+
+ updates.enroll(std::move(update));
+ auto &queue = updates.queue();
+ ASSERT_EQ(queue.size(), 1);
+}
diff --git a/compiler/moco/import/src/GraphBuilderRegistry.cpp b/compiler/moco/import/src/GraphBuilderRegistry.cpp
new file mode 100644
index 000000000..3a028513f
--- /dev/null
+++ b/compiler/moco/import/src/GraphBuilderRegistry.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 "moco/Import/GraphBuilderRegistry.h"
+#include "moco/Import/Nodes.h"
+
+#include <stdex/Memory.h>
+
+namespace moco
+{
+
+GraphBuilderRegistry::GraphBuilderRegistry()
+{
+ add("Add", stdex::make_unique<AddGraphBuilder>());
+ add("AvgPool", stdex::make_unique<AvgPoolGraphBuilder>());
+ add("BiasAdd", stdex::make_unique<BiasAddGraphBuilder>());
+ add("ConcatV2", stdex::make_unique<ConcatV2GraphBuilder>());
+ add("Const", stdex::make_unique<ConstGraphBuilder>());
+ add("Conv2D", stdex::make_unique<Conv2DGraphBuilder>());
+ add("Conv2DBackpropInput", stdex::make_unique<Conv2DBackpropInputGraphBuilder>());
+ add("DepthwiseConv2dNative", stdex::make_unique<DepthwiseConv2dNativeGraphBuilder>());
+ add("FakeQuantWithMinMaxVars", stdex::make_unique<FakeQuantWithMinMaxVarsGraphBuilder>());
+ add("FusedBatchNorm", stdex::make_unique<FusedBatchNormGraphBuilder>());
+ add("Identity", stdex::make_unique<IdentityGraphBuilder>());
+ add("Maximum", stdex::make_unique<MaximumGraphBuilder>());
+ add("MaxPool", stdex::make_unique<MaxPoolGraphBuilder>());
+ add("Mean", stdex::make_unique<MeanGraphBuilder>());
+ add("Mul", stdex::make_unique<MulGraphBuilder>());
+ add("Pack", stdex::make_unique<PackGraphBuilder>());
+ add("Pad", stdex::make_unique<PadGraphBuilder>());
+ add("Placeholder", stdex::make_unique<PlaceholderGraphBuilder>());
+ add("RealDiv", stdex::make_unique<RealDivGraphBuilder>());
+ add("Relu", stdex::make_unique<ReluGraphBuilder>());
+ add("Relu6", stdex::make_unique<Relu6GraphBuilder>());
+ add("Reshape", stdex::make_unique<ReshapeGraphBuilder>());
+ add("Rsqrt", stdex::make_unique<RsqrtGraphBuilder>());
+ add("Shape", stdex::make_unique<ShapeGraphBuilder>());
+ add("Softmax", stdex::make_unique<SoftmaxGraphBuilder>());
+ add("Sqrt", stdex::make_unique<SqrtGraphBuilder>());
+ add("SquaredDifference", stdex::make_unique<SquaredDifferenceGraphBuilder>());
+ add("Squeeze", stdex::make_unique<SqueezeGraphBuilder>());
+ add("StopGradient", stdex::make_unique<StopGradientGraphBuilder>());
+ add("StridedSlice", stdex::make_unique<StridedSliceGraphBuilder>());
+ add("Sub", stdex::make_unique<SubGraphBuilder>());
+ add("Tanh", stdex::make_unique<TanhGraphBuilder>());
+
+ // Virtual node like `TFPush` need not to be added here
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Importer.cpp b/compiler/moco/import/src/Importer.cpp
new file mode 100644
index 000000000..8d3ca6cfc
--- /dev/null
+++ b/compiler/moco/import/src/Importer.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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 "moco/Importer.h"
+#include "moco/Import/GraphBuilder.h"
+#include "moco/Import/GraphBuilderContext.h"
+
+#include "moco/Import/GraphBuilderRegistry.h"
+
+#include <moco/IR/Nodes/TFPlaceholder.h>
+#include <moco/IR/TFNode.h>
+
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <sstream>
+#include <stdexcept>
+
+namespace
+{
+
+void convert_graph(const moco::GraphBuilderSource &source, const moco::ModelSignature &signature,
+ tensorflow::GraphDef &tf_graph_def, loco::Graph *graph)
+{
+ auto nodedef = stdex::make_unique<moco::NodeDefTable>();
+ auto tensor_names = stdex::make_unique<moco::SymbolTable>();
+ auto updates = stdex::make_unique<moco::UpdateQueue>();
+
+ moco::GraphBuilderContext gb_context(graph, nodedef.get(), tensor_names.get(), updates.get());
+
+ // Building a loco graph
+ // 1. Convert all the nodes to moco::TFNode
+ // 2. Connect inputs: set all node input(from a string) to actual node object
+ // 3. Set graph input
+ // 4. Create moco::TFPush node and set graph output
+
+ /**
+ * @brief Prepare tensorflow::NodeDef search table from name
+ */
+ for (const auto &n : tf_graph_def.node())
+ {
+ nodedef->enroll(n.name(), &n);
+ }
+
+ /**
+ * @brief 1. Convert all the nodes to moco::TFNode
+ *
+ * @note In each build for a TF node, four things happen
+ * 1) create corresponding moco::TFNode(s)
+ * 2) read and set the attributes to created moco::TFNode(s)
+ * 3) register name-moco::TFNode(last one of Nodes) that will be used as the output
+ * 4) queue a task to set the input of the moco::TFNode(first one of the Nodes)
+ * this is done only for required nodes depending on the operator
+ *
+ * @example Placeholder("in") - Identity("out")
+ * %1 = Placeholder --> 0x1001 (moco::TFNode* object address)
+ * (symboltable: register %1, after the registeration table will contain as below;
+ * "in" : 0x1001
+ * )
+ * (queue: this will be empty as Pull does not queue a task to set input;
+ * )
+ *
+ * %2 = Forward --> 0x1002
+ * (symboltable: register %2 and table will look like below;
+ * "in" : 0x1001
+ * "out" : 0x1002
+ * )
+ * (queue: Forward will queue a task with input "in";
+ * 0x1002: {"in"}
+ * )
+ */
+ for (const auto &n : tf_graph_def.node())
+ {
+ if (const auto *graph_builder = source.lookup(n.op()))
+ {
+ if (!graph_builder->validate(n))
+ {
+ throw oops::UserExn("Invalid operator", n.op());
+ }
+
+ graph_builder->build(n, &gb_context);
+ }
+ else
+ {
+ throw oops::UserExn("Not supported", n.op());
+ }
+ }
+
+ /**
+ * @brief 2. Connect inputs: Iterate updates and call each update input method
+ *
+ * @note Continue from above example graph, connecting inputs is done in following steps
+ * a) iterate queue
+ * b) call the input method for each update
+ * c) each update has the moco::TFNode *node and names of the input to connect
+ * node = 0x1002 and names = {"in"}
+ * d) from symbol table, "in" will return 0x1001
+ * e) set input of 0x1002 with 0x1001
+ */
+ for (auto &update : updates->queue())
+ {
+ update->input(tensor_names.get());
+ }
+
+ /**
+ * @brief 3. Set graph input
+ */
+ for (auto input : signature.inputs())
+ {
+ auto node = tensor_names->node(input);
+ assert(node != nullptr);
+
+ auto graph_input = graph->inputs()->create();
+
+ auto placeholder_node = dynamic_cast<moco::TFPlaceholder *>(node);
+ assert(placeholder_node != nullptr);
+
+ graph_input->name(input.nodeName());
+
+ // annotate index that should be passed to loco::Pull
+ moco::index(placeholder_node, graph_input->index());
+
+ // This implementation works as "PlaceholderGraphBuilder in Nodes/Placeholder.cpp"
+ // accepts only TF_FLOAT32 as of now.
+ //
+ // TODO Support other types
+ graph_input->dtype(loco::DataType::FLOAT32);
+ }
+
+ /**
+ * @brief 4. Create moco::TFPush node and set graph output
+ */
+ for (auto output : signature.outputs())
+ {
+ auto output_node = tensor_names->node(output);
+ assert(output_node);
+
+ // create moco::TFPush for output of graph
+ auto push_node = graph->nodes()->create<moco::TFPush>();
+ push_node->from(output_node); // set input of TFPush to output node
+
+ // set the graph output name and node object
+ auto graph_output = graph->outputs()->create();
+ graph_output->name(output.nodeName());
+ push_node->index(graph_output->index());
+
+ // TODO Support other types
+ graph_output->dtype(loco::DataType::FLOAT32);
+ }
+
+ // validate graph
+ assert(loco::valid(graph));
+}
+
+} // namespace
+
+namespace moco
+{
+
+Importer::Importer()
+{
+ // DO NOTHING
+}
+
+std::unique_ptr<loco::Graph> Importer::import(const ModelSignature &signature,
+ tensorflow::GraphDef &tf_graph_def) const
+{
+ auto graph = loco::make_graph();
+
+ const GraphBuilderSource *source_ptr = &moco::GraphBuilderRegistry::get();
+
+ if (_source != nullptr)
+ {
+ // Use user-defined GraphBuilderSource
+ source_ptr = _source;
+ }
+
+ convert_graph(*source_ptr, signature, tf_graph_def, graph.get());
+
+ return std::move(graph);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Importer.test.cpp b/compiler/moco/import/src/Importer.test.cpp
new file mode 100644
index 000000000..23873390c
--- /dev/null
+++ b/compiler/moco/import/src/Importer.test.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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 "moco/Importer.h"
+#include "moco/GraphHelper.h"
+
+#include <moco/IR/Nodes/TFIdentity.h>
+
+#include "TestHelper.h"
+#include <loco.h>
+#include <plier/tf/TestHelper.h>
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+TEST(TensorFlowImport, Dummy) { moco::Importer import; }
+
+namespace
+{
+
+// clang-format off
+const char *basic_pbtxtdata = STRING_CONTENT(
+node {
+ name: "Placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ }
+ }
+ }
+}
+node {
+ name: "output/identity"
+ op: "Identity"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, load_model_withio_tf)
+{
+ moco::ModelSignature signature;
+
+ signature.add_input(moco::TensorName("Placeholder", 0));
+ signature.add_output(moco::TensorName("output/identity", 0));
+
+ tensorflow::GraphDef graph_def;
+ EXPECT_TRUE(plier::tf::parse_graphdef(basic_pbtxtdata, graph_def));
+
+ moco::Importer importer;
+
+ std::unique_ptr<loco::Graph> graph = importer.import(signature, graph_def);
+
+ // what to test:
+ // - import reads Placeholder
+ // - import reads Identity
+ // - attribute values should match
+
+ auto tfidentity = find_first_node_bytype<moco::TFIdentity>(graph.get());
+ ASSERT_NE(tfidentity, nullptr);
+ ASSERT_NE(tfidentity->input(), nullptr);
+}
+
+namespace
+{
+
+// clang-format off
+const char *query_pbtxtdata = STRING_CONTENT(
+node {
+ name: "Placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ dim {
+ size: 1
+ }
+ dim {
+ size: 2
+ }
+ }
+ }
+ }
+}
+node {
+ name: "Foo/w_min"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape { }
+ float_val: -1.0
+ }
+ }
+ }
+}
+node {
+ name: "output/identity"
+ op: "Identity"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+}
+node {
+ name: "Foo/w_max"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape { }
+ float_val: -1.0
+ }
+ }
+ }
+}
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, find_node_by_name)
+{
+ moco::ModelSignature signature;
+
+ signature.add_input(moco::TensorName("Placeholder", 0));
+ signature.add_output(moco::TensorName("output/identity", 0));
+
+ tensorflow::GraphDef graph_def;
+ EXPECT_TRUE(plier::tf::parse_graphdef(query_pbtxtdata, graph_def));
+
+ moco::Importer importer;
+
+ std::unique_ptr<loco::Graph> graph = importer.import(signature, graph_def);
+
+ // what to test:
+ // - get name of first Identity node
+ // - find node by name `Foo/w_min`
+ // - find node by name `Foo/w_max`
+
+ auto tfidentity = find_first_node_bytype<moco::TFIdentity>(graph.get());
+ ASSERT_NE(tfidentity, nullptr);
+ ASSERT_NE(tfidentity->input(), nullptr);
+ ASSERT_STREQ(tfidentity->name().c_str(), "output/identity");
+
+ auto query_node = moco::find_node_byname<moco::TFConst>(graph.get(), "Foo/w_min");
+ ASSERT_NE(query_node, nullptr);
+ ASSERT_STREQ(query_node->name().c_str(), "Foo/w_min");
+
+ auto query_node2 = moco::find_node_byname<moco::TFConst>(graph.get(), "Foo/w_max");
+ ASSERT_NE(query_node2, nullptr);
+ ASSERT_STREQ(query_node2->name().c_str(), "Foo/w_max");
+}
diff --git a/compiler/moco/import/src/ModelSignature.cpp b/compiler/moco/import/src/ModelSignature.cpp
new file mode 100644
index 000000000..d4c7e5085
--- /dev/null
+++ b/compiler/moco/import/src/ModelSignature.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "moco/Import/ModelSignature.h"
+
+#include <oops/UserExn.h>
+
+namespace moco
+{
+
+void ModelSignature::add_customop(const std::string &op)
+{
+ if (std::find(_customops.begin(), _customops.end(), op) == _customops.end())
+ _customops.emplace_back(op);
+ else
+ throw oops::UserExn("Duplicate custom operator", op);
+}
+
+void ModelSignature::shape(const std::string &node_name, const angkor::TensorShape &shape)
+{
+ if (_shapes.find(node_name) != _shapes.end())
+ throw oops::UserExn("Duplicate node name", node_name);
+
+ _shapes[node_name] = shape;
+}
+
+const angkor::TensorShape *ModelSignature::shape(const std::string &node_name) const
+{
+ auto res = _shapes.find(node_name);
+ if (res == _shapes.end())
+ return nullptr;
+ else
+ return &res->second;
+}
+
+void ModelSignature::dtype(const std::string &node_name, loco::DataType dtype)
+{
+ if (_dtypes.find(node_name) != _dtypes.end())
+ throw oops::UserExn("Duplicate node name", node_name);
+
+ _dtypes[node_name] = dtype;
+}
+
+loco::DataType ModelSignature::dtype(const std::string &node_name) const
+{
+ auto res = _dtypes.find(node_name);
+ if (res == _dtypes.end())
+ return loco::DataType::Unknown;
+ else
+ return res->second;
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Add.cpp b/compiler/moco/import/src/Nodes/Add.cpp
new file mode 100644
index 000000000..6981a55e1
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Add.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "moco/Import/Nodes/Add.h"
+
+#include <moco/IR/Nodes/TFAdd.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Add node
+ */
+class TFAddGraphUpdate final : public GraphUpdate
+{
+public:
+ TFAddGraphUpdate(TFAdd *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFAdd *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFAddGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool AddGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void AddGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Add node
+ auto tf_add = graph->nodes()->create<TFAdd>();
+ tf_add->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_add);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_add_update = stdex::make_unique<TFAddGraphUpdate>(tf_add, add_input_names);
+ updates->enroll(std::move(tf_add_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Add.test.cpp b/compiler/moco/import/src/Nodes/Add.test.cpp
new file mode 100644
index 000000000..ace2b0801
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Add.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Add.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *add_basic_pbtxt = STRING_CONTENT(
+ name: "ADD_01"
+ op: "Add"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_add_basic)
+{
+ TFNodeBuildTester tester;
+ moco::AddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(add_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFAdd node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("ADD_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/AvgPool.cpp b/compiler/moco/import/src/Nodes/AvgPool.cpp
new file mode 100644
index 000000000..6d7fd36bb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/AvgPool.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "moco/Import/Nodes/AvgPool.h"
+
+#include <moco/IR/Nodes/TFAvgPool.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+
+using namespace plier::tf;
+
+namespace
+{
+
+using namespace moco;
+
+class TFAvgPoolGraphUpdate final : public GraphUpdate
+{
+public:
+ TFAvgPoolGraphUpdate(TFAvgPool *node, const TensorName &name)
+ : _avgpool_node(node), _value_name(name)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFAvgPool *_avgpool_node;
+ const TensorName _value_name;
+};
+
+void TFAvgPoolGraphUpdate::input(const SymbolTable *node_table) const
+{
+ loco::Node *value_node = node_table->node(_value_name);
+ _avgpool_node->value(value_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool AvgPoolGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "ksize", "padding", "strides"}))
+ return false;
+
+ auto tf_ksize = get_list_attr(node, "ksize");
+ auto ksize = as_int64_list(tf_ksize);
+ if (ksize.size() != 4)
+ {
+ // TODO support ksize length for 1 and 2
+ throw oops::UserExn("AvgPool only supports ksize length 4", node.name());
+ }
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ if (strides.size() != 4)
+ {
+ // TODO support strides length for 1 and 2
+ throw oops::UserExn("AvgPool only supports strides length 4", node.name());
+ }
+
+ return true;
+}
+
+void AvgPoolGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ ::std::string avgPool2d_name = node.name();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = get_string_attr(node, "data_format");
+ auto avgPool_node = graph->nodes()->create<TFAvgPool>();
+ avgPool_node->name(node.name());
+ avgPool_node->data_layout(data_layout);
+
+ // padding
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ avgPool_node->padding(padding);
+
+ // ksize
+ auto tf_ksize = get_list_attr(node, "ksize");
+ auto ksize = as_int64_list(tf_ksize);
+ avgPool_node->ksize(ksize);
+
+ // strides
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ avgPool_node->strides(strides);
+
+ // To set the input node of encode_node with avgPool2d_name
+ TensorName output_name(avgPool2d_name, 0);
+ tensor_names->enroll(output_name, avgPool_node);
+
+ // Record ifm inputs to featureEncode_node
+ auto update = stdex::make_unique<TFAvgPoolGraphUpdate>(avgPool_node, TensorName(node.input(0)));
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
+
+// TODO Consider a case when TF AvgPool is for 3D.
+// AvgPool works for 2D and other Dimensions, such as 3D
+// So, in future, some other GraphBuilder decide if AvgPoolGraphBuilder is used or
+// other GraphBuilder is used for TF AvgPool
diff --git a/compiler/moco/import/src/Nodes/AvgPool.test.cpp b/compiler/moco/import/src/Nodes/AvgPool.test.cpp
new file mode 100644
index 000000000..7d62f0eaa
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/AvgPool.test.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "moco/Import/Nodes/AvgPool.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *avgpool_01_pbtxtdata = STRING_CONTENT(
+ name: "avgpool"
+ op: "AvgPool"
+ input: "const/float"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 3
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 3
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, AvgPool_01)
+{
+ TFNodeBuildTester tester;
+ moco::AvgPoolGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(avgpool_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFAvgPool
+ // - input should exist
+ // - attributes value should match
+
+ tester.inputs({"const/float"});
+ tester.output("avgpool");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFAvgPool *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->ksize(), std::vector<int64_t>({1, 2, 3, 1}));
+ ASSERT_EQ(test_node->strides(), std::vector<int64_t>({1, 3, 2, 1}));
+}
diff --git a/compiler/moco/import/src/Nodes/BiasAdd.cpp b/compiler/moco/import/src/Nodes/BiasAdd.cpp
new file mode 100644
index 000000000..a3eb91116
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/BiasAdd.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "moco/Import/Nodes/BiasAdd.h"
+
+#include <moco/IR/Nodes/TFBiasAdd.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <vector>
+
+namespace
+{
+using namespace moco;
+
+class TFBiasAddGraphUpdate final : public GraphUpdate
+{
+public:
+ TFBiasAddGraphUpdate(TFBiasAdd *biasadd, std::vector<TensorName> &names)
+ : _biasadd(biasadd), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFBiasAdd *_biasadd;
+ std::vector<TensorName> _names;
+};
+
+void TFBiasAddGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto value_node = node_table->node(_names[0]);
+ auto bias_node = node_table->node(_names[1]);
+ assert(value_node != nullptr);
+ assert(bias_node != nullptr);
+
+ _biasadd->value(value_node);
+ _biasadd->bias(bias_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool BiasAddGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format"}))
+ return false;
+
+ // TODO add type check
+ // type of input and bias should be same (except using quantization)
+
+ // Note In case of TF.nn.bias_add,
+ // "value may have any number of dimensions." ...
+ // but "data_format: A string. 'NHWC' and 'NCHW' are supported."
+ // Not sure if value should be 4-D tensor. Let's skip this check for now.
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("BiasAdd Unsupported data_format", node.name());
+ }
+
+ return true;
+}
+
+void BiasAddGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ auto tf_bias_add = graph->nodes()->create<TFBiasAdd>();
+ tf_bias_add->name(node.name());
+ tf_bias_add->data_layout(data_layout);
+
+ // To set the input node of encode_node with biasAdd_name
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_bias_add);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0)));
+ input_names.push_back(TensorName(node.input(1)));
+
+ auto update = stdex::make_unique<TFBiasAddGraphUpdate>(tf_bias_add, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/BiasAdd.test.cpp b/compiler/moco/import/src/Nodes/BiasAdd.test.cpp
new file mode 100644
index 000000000..626456d30
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/BiasAdd.test.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "moco/Import/Nodes/BiasAdd.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *bias_add_01_pbtxtdata = STRING_CONTENT(
+ name: "out"
+ op: "BiasAdd"
+ input: "val"
+ input: "bias"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NHWC" }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, bias_add_01)
+{
+ TFNodeBuildTester tester;
+ moco::BiasAddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(bias_add_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFBiasAdd
+ // - value() should not be nullptr
+ // - bias() should not be nullptr
+ // - data_layout should match
+
+ tester.inputs({"val", "bias"});
+ tester.output("out");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFBiasAdd *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_TRUE(test_node->data_layout() == "NHWC");
+}
+
+namespace
+{
+
+// clang-format off
+const char *bias_add_NCHW_pbtxtdata = STRING_CONTENT(
+ name: "out"
+ op: "BiasAdd"
+ input: "val"
+ input: "bias"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NCHW" }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, bias_add_NCHW_axis)
+{
+ TFNodeBuildTester tester;
+ moco::BiasAddGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(bias_add_NCHW_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFBiasAdd
+ // - value() should not be nullptr
+ // - bias() should not be nullptr
+ // - data_layout should match
+
+ tester.inputs({"val", "bias"});
+ tester.output("out");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFBiasAdd *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_TRUE(test_node->data_layout() == "NCHW");
+}
diff --git a/compiler/moco/import/src/Nodes/Concat.cpp b/compiler/moco/import/src/Nodes/Concat.cpp
new file mode 100644
index 000000000..8bf8a84b5
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Concat.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 "moco/Import/Nodes/Concat.h"
+
+#include <moco/IR/Nodes/TFConcatV2.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+
+namespace
+{
+
+using namespace moco;
+
+class TFConcatV2GraphUpdate final : public GraphUpdate
+{
+public:
+ TFConcatV2GraphUpdate(TFConcatV2 *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConcatV2 *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFConcatV2GraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ uint32_t num_values = _names.size() - 1; // exclude axis
+ assert(num_values >= 1);
+
+ for (uint32_t i = 0; i < num_values; ++i)
+ {
+ auto input_node = tensor_names->node(_names[i]);
+ assert(input_node != nullptr);
+ _node->values(i, input_node);
+ }
+ auto axis_node = tensor_names->node(_names[num_values]);
+ assert(axis_node != nullptr);
+ _node->axis(axis_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ConcatV2GraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"T", "N", "Tidx"}))
+ return false;
+
+ // Concat node SHOULD have 3 or more inputs, that is 2 + axis
+ const int num_inputs = node.input_size() - 1;
+ return (num_inputs >= 2) && (num_inputs == plier::tf::get_int_attr(node, "N"));
+}
+
+void ConcatV2GraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+ auto tensor_names = context->tensor_names();
+ auto updates = context->updates();
+
+ const int num_inputs = node.input_size() - 1;
+ std::vector<TensorName> input_names;
+ auto concat_node = graph->nodes()->create<TFConcatV2>(num_inputs);
+ concat_node->name(node.name());
+
+ for (int ni = 0; ni < num_inputs; ++ni)
+ {
+ input_names.push_back(TensorName(node.input(ni)));
+ }
+ // last one is the axis
+ input_names.push_back(TensorName(node.input(num_inputs)));
+
+ // register string-name to the last node as output of concat(s)
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, concat_node);
+
+ auto update = stdex::make_unique<TFConcatV2GraphUpdate>(concat_node, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Concat.test.cpp b/compiler/moco/import/src/Nodes/Concat.test.cpp
new file mode 100644
index 000000000..c0986578b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Concat.test.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "moco/Import/Nodes/Concat.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *concat_01_pbtxtdata = STRING_CONTENT(
+ name: "Concat"
+ op: "ConcatV2"
+ input: "Input01"
+ input: "Input02"
+ input: "Axis"
+ attr {
+ key: "N"
+ value {
+ i: 2
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, concat_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConcatV2GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(concat_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConcatV2
+ // - there should be two values
+ // - values(idx) should not be nullptr
+ // - axis() should not be nullptr
+
+ tester.inputs({"Input01", "Input02", "Axis"});
+ tester.output("Concat");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConcatV2 *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->num_values(), 2);
+}
+
+namespace
+{
+
+// clang-format off
+const char *concat_02_pbtxtdata = STRING_CONTENT(
+ name: "Concat"
+ op: "ConcatV2"
+ input: "Input01"
+ input: "Input02"
+ input: "Input03"
+ input: "Axis"
+ attr {
+ key: "N"
+ value {
+ i: 3
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tidx"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, concat_02)
+{
+ TFNodeBuildTester tester;
+ moco::ConcatV2GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(concat_02_pbtxtdata, nodedef));
+
+ // what to test: TFConcatV2 has 3 inputs
+ // - there should exist TFConcatV2
+ // - values(idx) should not be nullptr
+ // - axis() should not be nullptr
+
+ tester.inputs({"Input01", "Input02", "Input03", "Axis"});
+ tester.output("Concat");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConcatV2 *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->num_values(), 3);
+}
diff --git a/compiler/moco/import/src/Nodes/Const.cpp b/compiler/moco/import/src/Nodes/Const.cpp
new file mode 100644
index 000000000..15ea717db
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Const.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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 "moco/Import/Nodes/Const.h"
+
+#include <moco/Names.h>
+#include <moco/IR/TFNodes.h>
+
+#include <loco.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+#include <string>
+
+namespace
+{
+
+using namespace moco;
+
+void read_value_int8(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::S8>(num_elements);
+
+ int32_t input_elements = input_tensor.int_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(int8_t))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const int8_t *s8_ptr = reinterpret_cast<const int8_t *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = *(s8_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = input_tensor.int_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S8>(i) = input_tensor.int_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+void read_value_int32(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::S32>(num_elements);
+
+ int32_t input_elements = input_tensor.int_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(int32_t))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const int32_t *s32_ptr = reinterpret_cast<const int32_t *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = *(s32_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = input_tensor.int_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::S32>(i) = input_tensor.int_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+void read_value_float32(TFConst *const_node, int num_elements,
+ const tensorflow::TensorProto &input_tensor)
+{
+ const_node->size<loco::DataType::FLOAT32>(num_elements);
+
+ int32_t input_elements = input_tensor.float_val_size();
+
+ if (input_tensor.tensor_content().size() == num_elements * sizeof(float))
+ {
+ const std::string &str_content = input_tensor.tensor_content();
+ const float *float_ptr = reinterpret_cast<const float *>(str_content.c_str());
+ for (int32_t i = 0; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = *(float_ptr + i);
+ }
+ }
+ else if (0 < input_elements && input_elements <= num_elements)
+ {
+ for (int32_t i = 0; i < input_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = input_tensor.float_val(i);
+ }
+
+ for (int32_t i = input_elements; i < num_elements; i++)
+ {
+ const_node->at<loco::DataType::FLOAT32>(i) = input_tensor.float_val(input_elements - 1);
+ }
+ }
+ else
+ {
+ throw oops::UserExn("Invalid Const values", const_node->name());
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ConstGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"dtype", "value"}))
+ return false;
+
+ const auto &input_tensor = plier::tf::get_tensor_attr(node, "value");
+ const auto &input_shape = input_tensor.tensor_shape();
+ const auto &input_dims = input_shape.dim();
+
+ if (!(input_shape.dim_size() <= 6))
+ return false;
+
+ for (auto &d : input_dims)
+ {
+ if (d.size() > std::numeric_limits<int>::max())
+ throw oops::UserExn("Const Shape element overflows", node.name());
+
+ if (d.size() < 0)
+ throw oops::UserExn("Unknown dim size", node.name());
+ }
+
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ if (!(dtype == loco::DataType::S32 || dtype == loco::DataType::FLOAT32 ||
+ dtype == loco::DataType::S8))
+ return false;
+ // TODO support other dtype
+
+ return true;
+}
+
+void ConstGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+
+ // Create a "TFConstant" node for Const
+ auto const_node = graph->nodes()->create<TFConst>();
+ const_node->name(node.name());
+
+ // set dtype
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ const_node->dtype(dtype);
+
+ // import shape and value
+ const auto &input_tensor = plier::tf::get_tensor_attr(node, "value");
+ const auto &input_shape = input_tensor.tensor_shape();
+ const auto &input_dims = input_shape.dim();
+ assert(input_shape.dim_size() <= 6);
+ const_node->rank(input_shape.dim_size());
+ int index = 0;
+ bool zero_sized_shape = false;
+ for (auto &d : input_dims)
+ {
+ assert(d.size() <= std::numeric_limits<int>::max());
+ if (d.size() == 0)
+ zero_sized_shape = true;
+
+ assert(d.size() >= 0);
+ const_node->dim(index++) = d.size();
+ }
+
+ int num_elements = 1;
+ if (zero_sized_shape)
+ {
+ const_node->rank(0);
+ num_elements = 0;
+ }
+ else
+ {
+ for (uint32_t d = 0; d < const_node->rank(); d++)
+ {
+ num_elements *= const_node->dim(d).value();
+ }
+ }
+
+ switch (dtype)
+ {
+ case loco::DataType::S8:
+ read_value_int8(const_node, num_elements, input_tensor);
+ break;
+
+ case loco::DataType::S32:
+ read_value_int32(const_node, num_elements, input_tensor);
+ break;
+
+ case loco::DataType::FLOAT32:
+ read_value_float32(const_node, num_elements, input_tensor);
+ break;
+
+ // TODO support other types
+
+ default:
+ assert(false);
+ }
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, const_node);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Const.test.cpp b/compiler/moco/import/src/Nodes/Const.test.cpp
new file mode 100644
index 000000000..854499fe6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Const.test.cpp
@@ -0,0 +1,465 @@
+/*
+ * 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 "moco/Import/Nodes/Const.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// Test case for "input_tensor.float_val_size() == num_elements"
+
+// clang-format off
+const char *const_float_01_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ float_val: 2.2
+ float_val: 3.3
+ float_val: 4.4
+ float_val: 5.5
+ float_val: 6.6
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 3.3f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 4.4f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 5.5f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 6.6f);
+}
+
+namespace
+{
+// Test case for "input_tensor.float_val_size() == 1"
+
+// clang-format off
+const char *const_float_02_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_02)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_02_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 1.1f);
+}
+
+namespace
+{
+// Test case for "input_tensor.tensor_content().size() == num_elements * sizeof(float)"
+// Generated with tfkit tool: "cat ./test.pbtxt | ./tfkit pack"
+
+// clang-format off
+const char *const_float_03_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ tensor_content: "\315\314\214?\315\314\014@33S@\315\314\214@\000\000\260@33\323@"
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_03)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_03_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 3.3f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 4.4f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 5.5f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 6.6f);
+}
+
+namespace
+{
+// Test case for "input_tensor.float_val_size() < num_elements"
+
+// clang-format off
+const char *const_float_04_pbtxtdata = STRING_CONTENT(
+ name: "const/float"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_FLOAT
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ float_val: 1.1
+ float_val: 2.2
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_float_04)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_float_04_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/float");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::FLOAT32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(0), 1.1f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(1), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(2), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(3), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(4), 2.2f);
+ ASSERT_EQ(test_node->at<loco::DataType::FLOAT32>(5), 2.2f);
+}
+
+namespace
+{
+// Test case for "input_tensor.int_val_size() < num_elements"
+
+// clang-format off
+const char *const_int32_04_pbtxtdata = STRING_CONTENT(
+ name: "const/int"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ int_val: 1
+ int_val: 2
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int32_04)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int32_04_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/int");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S32>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(0), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(1), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(2), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(3), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(4), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(5), 2);
+}
+
+namespace
+{
+// Test case for "scalar"
+
+// clang-format off
+const char *const_int32_scalar_pbtxtdata = STRING_CONTENT(
+ name: "const/int"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT32
+ tensor_shape {
+ }
+ int_val: 3
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int32_scalar)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int32_scalar_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - there should be one element and value should be 3
+
+ tester.inputs({});
+ tester.output("const/int");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S32>(), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S32>(0), 3);
+}
+
+namespace
+{
+
+// clang-format off
+const char *const_int8_01_pbtxtdata = STRING_CONTENT(
+ name: "const/int8"
+ op: "Const"
+ attr {
+ key: "dtype"
+ value {
+ type: DT_INT8
+ }
+ }
+ attr {
+ key: "value"
+ value {
+ tensor {
+ dtype: DT_INT8
+ tensor_shape {
+ dim {
+ size: 2
+ }
+ dim {
+ size: 3
+ }
+ }
+ int_val: 0
+ int_val: -1
+ int_val: 1
+ int_val: 2
+ int_val: 3
+ int_val: 4
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, const_int8_01)
+{
+ TFNodeBuildTester tester;
+ moco::ConstGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(const_int8_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFConst
+ // - values should match
+
+ tester.inputs({});
+ tester.output("const/int8");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConst *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->size<loco::DataType::S8>(), 6);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(0), 0);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(1), -1);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(2), 1);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(3), 2);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(4), 3);
+ ASSERT_EQ(test_node->at<loco::DataType::S8>(5), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/Conv2D.cpp b/compiler/moco/import/src/Nodes/Conv2D.cpp
new file mode 100644
index 000000000..e6b98dcd1
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2D.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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 "moco/Import/Nodes/Conv2D.h"
+
+#include <moco/IR/Nodes/TFConv2D.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+#include <algorithm>
+
+namespace
+{
+using namespace moco;
+
+class TFConv2DGraphUpdate final : public GraphUpdate
+{
+public:
+ TFConv2DGraphUpdate(TFConv2D *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConv2D *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFConv2DGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto input_node = node_table->node(_names[0]);
+ auto filter_node = node_table->node(_names[1]);
+ assert(input_node != nullptr);
+ assert(filter_node != nullptr);
+
+ _node->input(input_node);
+ _node->filter(filter_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Conv2DGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("Conv2D Unsupported data_format", node.name());
+ }
+
+ // dilation attribute is not fully supported
+ if (plier::tf::has_attr(node, "dilations"))
+ {
+ // TODO Support non-default dilations
+ auto dilation = plier::tf::get_list_attr(node, "dilations").i();
+ if (!std::all_of(dilation.begin(), dilation.end(), [](std::int64_t dil) { return dil == 1; }))
+ return false;
+ }
+ // Else, dilations are automatically set to default [1,1,1,1] which we assumes now
+
+ return true;
+}
+
+void Conv2DGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string conv2d_name = node.name();
+
+ auto conv2d = graph->nodes()->create<TFConv2D>();
+ conv2d->name(node.name());
+
+ // read attributes
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ assert(data_layout == "NHWC" || data_layout == "NCHW");
+ conv2d->data_layout(data_layout);
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ conv2d->strides(strides);
+
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ assert(padding == "VALID" || padding == "SAME");
+ conv2d->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(conv2d_name, 0);
+ tensor_names->enroll(output_name, conv2d);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // kernel
+
+ // Record ifm inputs to featureEncode_node
+ auto tfconv2d_update = stdex::make_unique<TFConv2DGraphUpdate>(conv2d, input_names);
+
+ updates->enroll(std::move(tfconv2d_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Conv2D.test.cpp b/compiler/moco/import/src/Nodes/Conv2D.test.cpp
new file mode 100644
index 000000000..ba006f489
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2D.test.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "moco/Import/Nodes/Conv2D.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *conv2d_01_pbtxtdata = STRING_CONTENT(
+ name: "conv2d"
+ op: "Conv2D"
+ input: "ifm"
+ input: "ker"
+ attr { key: "T" value { type: DT_FLOAT } }
+ attr { key: "data_format" value { s: "NHWC" } }
+ attr { key: "dilations" value { list { i: 1 i: 1 i: 1 i: 1 } } }
+ attr { key: "padding" value { s: "VALID" } }
+ attr { key: "strides" value { list { i: 1 i: 2 i: 3 i: 1 } } }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, Conv2D_01)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - Conv2D node should exist
+ // - ifm() should not be nullptr
+ // - ker() should not be nullptr
+ // - attribute values should match
+
+ tester.inputs({"ifm", "ker"});
+ tester.output("conv2d");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConv2D *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ auto strides = test_node->strides();
+ ASSERT_EQ(strides.size(), 4);
+ // TODO add verify dilation
+}
+
+namespace
+{
+// clang-format off
+const char *conv2d_inception_pbtxtdata = STRING_CONTENT(
+ name: "InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D"
+ op: "Conv2D"
+ input: "input:0"
+ input: "InceptionV3/Conv2d_1a_3x3/weights/read/_3__cf__3"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "data_format"
+ value { s: "NHWC" }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list { i: 1 i: 1 i: 1 i: 1 }
+ }
+ }
+ attr {
+ key: "padding"
+ value { s: "VALID" }
+ }
+ attr {
+ key: "strides"
+ value {
+ list { i: 1 i: 2 i: 2 i: 1 }
+ }
+ }
+);
+} // namespace
+
+TEST(TensorFlowImport, Conv2D_inception_indexed_tensor_name)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_inception_pbtxtdata, nodedef));
+
+ // what to test: name with ':0' should be treated correctly
+ // - Conv2D node should exist
+ // - ifm() should not be nullptr
+ // - ker() should not be nullptr
+
+ tester.inputs({"input", "InceptionV3/Conv2d_1a_3x3/weights/read/_3__cf__3"});
+ tester.output("InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp
new file mode 100644
index 000000000..74c6605ab
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "moco/Import/Nodes/Conv2DBackpropInput.h"
+
+#include <moco/IR/Nodes/TFConv2DBackpropInput.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+/// @brief GraphUpdate for Conv2DBackpropInput node
+class Conv2DBackpropInputGraphUpdate final : public GraphUpdate
+{
+public:
+ Conv2DBackpropInputGraphUpdate(TFConv2DBackpropInput *node, std::vector<TensorName> names)
+ : _node(node), _input_names(names)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFConv2DBackpropInput *_node;
+ std::vector<TensorName> _input_names;
+};
+
+void Conv2DBackpropInputGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_input_names.size() == 3);
+
+ auto input_sizes_node = table->node(_input_names[0]);
+ auto filter_node = table->node(_input_names[1]);
+ auto out_backprop_node = table->node(_input_names[2]);
+
+ assert(input_sizes_node != nullptr);
+ assert(filter_node != nullptr);
+ assert(out_backprop_node != nullptr);
+
+ _node->input_sizes(input_sizes_node);
+ _node->filter(filter_node);
+ _node->out_backprop(out_backprop_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Conv2DBackpropInputGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 3)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("Conv2DBackprop Unsupported data_format", node.name());
+ }
+
+ // dilation attribute is not fully supported
+ if (plier::tf::has_attr(node, "dilations"))
+ {
+ // TODO Support non-default dilations
+ auto dilation = plier::tf::get_list_attr(node, "dilations").i();
+ if (!std::all_of(dilation.begin(), dilation.end(), [](std::int64_t dil) { return dil == 1; }))
+ return false;
+ }
+ // Else, dilations are automatically set to default [1,1,1,1] which we assumes now
+
+ return true;
+}
+
+void Conv2DBackpropInputGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string conv2d_backprop_name = node.name();
+
+ auto conv2d_backprop = graph->nodes()->create<TFConv2DBackpropInput>();
+ conv2d_backprop->name(node.name());
+
+ // read attributes
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ assert(data_layout == "NHWC" || data_layout == "NCHW");
+ conv2d_backprop->data_layout(data_layout);
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ conv2d_backprop->strides(strides);
+
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ assert(padding == "VALID" || padding == "SAME");
+ conv2d_backprop->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(conv2d_backprop_name, 0);
+ tensor_names->enroll(output_name, conv2d_backprop);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input_sizes
+ input_names.push_back(TensorName(node.input(1))); // filter
+ input_names.push_back(TensorName(node.input(2))); // out_backprop
+
+ // update
+ auto conv2d_backprop_update =
+ stdex::make_unique<Conv2DBackpropInputGraphUpdate>(conv2d_backprop, input_names);
+
+ updates->enroll(std::move(conv2d_backprop_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp
new file mode 100644
index 000000000..8c462bc3b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Conv2DBackpropInput.test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "moco/Import/Nodes/Conv2DBackpropInput.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *conv2d_backprop_input_01_pbtxtdata = STRING_CONTENT(
+ name: "ofm"
+ op: "Conv2DBackpropInput"
+ input: "outshape"
+ input: "weights"
+ input: "ifm"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "SAME"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, conv2d_backprop_input_01)
+{
+ TFNodeBuildTester tester;
+ moco::Conv2DBackpropInputGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(conv2d_backprop_input_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"outshape", "weights", "ifm"});
+ tester.output("ofm");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFConv2DBackpropInput *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "SAME");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->strides().size(), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp
new file mode 100644
index 000000000..3991a4d51
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 "moco/Import/Nodes/DepthwiseConv2dNative.h"
+
+#include <moco/IR/Nodes/TFDepthwiseConv2dNative.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <plier/tf/Convert.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+
+using namespace plier::tf;
+
+namespace
+{
+using namespace moco;
+
+class TFDepthwiseConv2dNativeGraphUpdate final : public GraphUpdate
+{
+public:
+ TFDepthwiseConv2dNativeGraphUpdate(TFDepthwiseConv2dNative *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFDepthwiseConv2dNative *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFDepthwiseConv2dNativeGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto input_node = node_table->node(_names[0]);
+ auto filter_node = node_table->node(_names[1]);
+ assert(input_node != nullptr);
+ assert(filter_node != nullptr);
+
+ _node->input(input_node);
+ _node->filter(filter_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool DepthwiseConv2dNativeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ // note: even though "data_format" and "dilations" are not entered when a model is written,
+ // TF seems to generate those field into a pb file.
+ if (!has_attrs(node, {"T", "data_format", "dilations", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("DepthwiseConv2dNative Unsupported data_format", node.name());
+ }
+
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ if (!(padding == "VALID" || padding == "SAME"))
+ return false;
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ if (!(strides.size() == 4))
+ {
+ throw oops::UserExn("DepthwiseConv2dNative strides requires rank 4", node.name());
+ }
+ auto stride_n = strides.at(0);
+ auto stride_h = strides.at(1);
+ auto stride_w = strides.at(2);
+ auto stride_c = strides.at(3);
+ if (!(stride_n == 1 && stride_c == 1) || !(stride_h == stride_w))
+ {
+ // TODO this message may need to be refined
+ throw oops::UserExn("DepthwiseConv2dNative strides requires N=C=1, H=W", node.name());
+ }
+
+ return true;
+}
+
+void DepthwiseConv2dNativeGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ auto depthwiseconv2d_native_node = graph->nodes()->create<TFDepthwiseConv2dNative>();
+ depthwiseconv2d_native_node->name(node.name());
+
+ // read attributes
+ auto data_layout = get_string_attr(node, "data_format");
+ depthwiseconv2d_native_node->data_layout(data_layout);
+
+ auto tf_strides = get_list_attr(node, "strides");
+ auto strides = as_int64_list(tf_strides);
+ depthwiseconv2d_native_node->strides(strides);
+
+ auto padding = moco::str_toupper(get_string_attr(node, "padding"));
+ depthwiseconv2d_native_node->padding(padding);
+
+ // save the name for graph link updates
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, depthwiseconv2d_native_node);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // kernel
+
+ // Record ifm inputs to featureEncode_node
+ auto tfdepthwiseconv2dnative_update = stdex::make_unique<TFDepthwiseConv2dNativeGraphUpdate>(
+ depthwiseconv2d_native_node, input_names);
+
+ updates->enroll(std::move(tfdepthwiseconv2dnative_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp
new file mode 100644
index 000000000..c65283c1b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/DepthwiseConv2dNative.test.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "moco/Import/Nodes/DepthwiseConv2dNative.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *depthwise_conv2d_native_01_pbtxtdata = STRING_CONTENT(
+ name: "depthwise"
+ op: "DepthwiseConv2dNative"
+ input: "input"
+ input: "filter"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "dilations"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 1
+ i: 1
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, Depthwise_conv2d_native)
+{
+ TFNodeBuildTester tester;
+ moco::DepthwiseConv2dNativeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(depthwise_conv2d_native_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"input", "filter"});
+ tester.output("depthwise");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFDepthwiseConv2dNative *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->strides().size(), 4);
+}
diff --git a/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp
new file mode 100644
index 000000000..d2fa3d1eb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 "moco/Import/Nodes/FakeQuantWithMinMaxVars.h"
+
+#include <moco/IR/Nodes/TFFakeQuantWithMinMaxVars.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <plier/tf/Convert.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+
+using namespace plier::tf;
+
+namespace
+{
+using namespace moco;
+
+class TFFakeQuantWithMinMaxVarsGraphUpdate final : public GraphUpdate
+{
+public:
+ TFFakeQuantWithMinMaxVarsGraphUpdate(TFFakeQuantWithMinMaxVars *node,
+ std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFFakeQuantWithMinMaxVars *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFFakeQuantWithMinMaxVarsGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 3);
+
+ auto inputs_node = node_table->node(_names[0]);
+ auto min_node = node_table->node(_names[1]);
+ auto max_node = node_table->node(_names[2]);
+ assert(inputs_node != nullptr);
+ assert(min_node != nullptr);
+ assert(max_node != nullptr);
+
+ _node->inputs(inputs_node);
+ _node->min(min_node);
+ _node->max(max_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool FakeQuantWithMinMaxVarsGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 3)
+ return false;
+
+ // attrs "narrow_range", "num_bits" are optional
+ return true;
+}
+
+void FakeQuantWithMinMaxVarsGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ auto fakequant_node = graph->nodes()->create<TFFakeQuantWithMinMaxVars>();
+ fakequant_node->name(node.name());
+
+ // read optional attributes
+ if (has_attr(node, "num_bits"))
+ {
+ auto num_bits = get_int_attr(node, "num_bits");
+ fakequant_node->num_bits(num_bits);
+ }
+ if (has_attr(node, "narrow_range"))
+ {
+ auto narrow_range = get_bool_attr(node, "narrow_range");
+ fakequant_node->narrow_range(narrow_range);
+ }
+
+ // save the name for graph link updates
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, fakequant_node);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // inputs
+ input_names.push_back(TensorName(node.input(1))); // min
+ input_names.push_back(TensorName(node.input(2))); // max
+
+ // Record ifm inputs to featureEncode_node
+ auto tffakequant_update =
+ stdex::make_unique<TFFakeQuantWithMinMaxVarsGraphUpdate>(fakequant_node, input_names);
+
+ updates->enroll(std::move(tffakequant_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp
new file mode 100644
index 000000000..40c494bb0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FakeQuantWithMinMaxVars.test.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 "moco/Import/Nodes/FakeQuantWithMinMaxVars.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *fakequant_01_pbtxtdata = STRING_CONTENT(
+ name: "FakeQuant"
+ op: "FakeQuantWithMinMaxVars"
+ input: "Input"
+ input: "FakeMin"
+ input: "FakeMax"
+ attr {
+ key: "narrow_range"
+ value { b: true }
+ }
+ attr {
+ key: "num_bits"
+ value { i: 16 }
+ }
+);
+// clang-format on
+} // namespace
+
+TEST(TensorFlowImport, FakeQuantWithMinMaxVars)
+{
+ TFNodeBuildTester tester;
+ moco::FakeQuantWithMinMaxVarsGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(fakequant_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - All node inputs are valid
+ // - All attributes are as expected
+
+ tester.inputs({"Input", "FakeMin", "FakeMax"});
+ tester.output("FakeQuant");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFFakeQuantWithMinMaxVars *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->narrow_range(), true);
+ ASSERT_EQ(test_node->num_bits(), 16);
+}
diff --git a/compiler/moco/import/src/Nodes/FusedBatchNorm.cpp b/compiler/moco/import/src/Nodes/FusedBatchNorm.cpp
new file mode 100644
index 000000000..59f98017c
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FusedBatchNorm.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 "moco/Import/Nodes/FusedBatchNorm.h"
+
+#include <moco/IR/Nodes/TFFusedBatchNorm.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for FusedBatchNorm node
+ */
+class FusedBatchNormGraphUpdate final : public GraphUpdate
+{
+public:
+ FusedBatchNormGraphUpdate(TFFusedBatchNorm *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFFusedBatchNorm *_node;
+ std::vector<TensorName> _names;
+};
+
+void FusedBatchNormGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 5);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->scale(tensor_names->node(_names[1]));
+ _node->offset(tensor_names->node(_names[2]));
+ _node->mean(tensor_names->node(_names[3]));
+ _node->variance(tensor_names->node(_names[4]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool FusedBatchNormGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 5)
+ return false;
+
+ return plier::tf::has_attrs(node, {"epsilon"});
+}
+
+void FusedBatchNormGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ float epsilon = plier::tf::get_float_attr(node, "epsilon");
+
+ // creating TF dialect FusedBatchNorm node
+ auto tf_fbn = graph->nodes()->create<TFFusedBatchNorm>();
+ tf_fbn->name(node.name());
+ tf_fbn->epsilon(epsilon);
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_fbn);
+
+ std::vector<TensorName> fbn_input_names;
+ fbn_input_names.push_back(TensorName(node.input(0))); // input
+ fbn_input_names.push_back(TensorName(node.input(1))); // scale
+ fbn_input_names.push_back(TensorName(node.input(2))); // offset
+ fbn_input_names.push_back(TensorName(node.input(3))); // mean
+ fbn_input_names.push_back(TensorName(node.input(4))); // variance
+
+ auto tf_fbn_update = stdex::make_unique<FusedBatchNormGraphUpdate>(tf_fbn, fbn_input_names);
+ updates->enroll(std::move(tf_fbn_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp b/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp
new file mode 100644
index 000000000..0f2e037b8
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/FusedBatchNorm.test.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "moco/Import/Nodes/FusedBatchNorm.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *fbn_basic_pbtxt = STRING_CONTENT(
+ name: "FBN_01"
+ op: "FusedBatchNorm"
+ input: "input"
+ input: "gamma"
+ input: "beta"
+ input: "FBN_01/mean"
+ input: "FBN_01/variance"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "epsilon"
+ value {
+ f: 0.001
+ }
+ }
+ attr {
+ key: "is_training"
+ value {
+ b: false
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_fbn_basic)
+{
+ TFNodeBuildTester tester;
+ moco::FusedBatchNormGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(fbn_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - there should exist a TFFusedBatchNorm
+ // - input() should not be nullptr
+ // - gamma() should not be nullptr
+ // - beta() should not be nullptr
+ // - mean() should not be nullptr
+ // - variance() should not be nullptr
+ // - epsilon() value should match
+
+ tester.inputs({"input", "gamma", "beta", "FBN_01/mean", "FBN_01/variance"});
+ tester.output("FBN_01");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFFusedBatchNorm *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->epsilon(), 0.001f);
+}
diff --git a/compiler/moco/import/src/Nodes/Identity.cpp b/compiler/moco/import/src/Nodes/Identity.cpp
new file mode 100644
index 000000000..8ca0e2d01
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Identity.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "moco/Import/Nodes/Identity.h"
+
+#include <moco/IR/Nodes/TFIdentity.h>
+
+#include <moco/Names.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <vector>
+
+namespace
+{
+
+using namespace moco;
+
+class TFIdentityGraphUpdate final : public GraphUpdate
+{
+public:
+ TFIdentityGraphUpdate(TFIdentity *node, const std::vector<TensorName> &names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFIdentity *_node;
+ const std::vector<TensorName> _names;
+};
+
+void TFIdentityGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ for (auto &name : _names)
+ {
+ loco::Node *target = tensor_names->node(name);
+ _node->input(target);
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool IdentityGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() < 1) // from TensorFlow lite toco
+ return false;
+
+ return true;
+}
+
+void IdentityGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a Identity node
+ auto identity_node = graph->nodes()->create<TFIdentity>();
+ identity_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, identity_node);
+
+ // Queue node input update
+ // TODO: Check if we really need multiple input handlings
+ std::vector<TensorName> names;
+ for (int i = 0; i < node.input_size(); ++i)
+ {
+ names.emplace_back(TensorName(node.input(i)));
+ }
+ auto update = stdex::make_unique<TFIdentityGraphUpdate>(identity_node, names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/MaxPool.cpp b/compiler/moco/import/src/Nodes/MaxPool.cpp
new file mode 100644
index 000000000..63275a3b8
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/MaxPool.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "moco/Import/Nodes/MaxPool.h"
+
+#include <moco/IR/Nodes/TFMaxPool.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <loco/IR/PermutingCodec.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+using namespace moco;
+
+class TFMaxPoolGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMaxPoolGraphUpdate(TFMaxPool *node, const TensorName &name)
+ : _maxpool_node(node), _input_name(name)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMaxPool *_maxpool_node;
+ const TensorName _input_name;
+};
+
+void TFMaxPoolGraphUpdate::input(const SymbolTable *node_table) const
+{
+ loco::Node *input_node = node_table->node(_input_name);
+ _maxpool_node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MaxPoolGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // note: even though "data_format" is not entered when a model is written,
+ // TF seems to generate "data_format" field into a pb file
+ if (!plier::tf::has_attrs(node, {"T", "data_format", "ksize", "padding", "strides"}))
+ return false;
+
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ if (!(data_layout == "NHWC" || data_layout == "NCHW"))
+ {
+ throw oops::UserExn("MaxPool Unsupported data_format", node.name());
+ }
+
+ auto tf_ksize = plier::tf::get_list_attr(node, "ksize");
+ auto ksize = plier::tf::as_int64_list(tf_ksize);
+ if (ksize.size() != 4)
+ {
+ // TODO support ksize length for 1 and 2
+ throw oops::UserExn("MaxPool ksize requires rank 4", node.name());
+ }
+
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ if (strides.size() != 4)
+ {
+ // TODO support strides length for 1 and 2
+ throw oops::UserExn("MaxPool strides requires rank 4", node.name());
+ }
+
+ return true;
+}
+
+void MaxPoolGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ ::std::string node_name = node.name();
+
+ // tensorflow data_format: one of NHWC or NCHW.
+ auto data_layout = plier::tf::get_string_attr(node, "data_format");
+ auto maxPool_node = graph->nodes()->create<TFMaxPool>();
+ maxPool_node->name(node.name());
+ maxPool_node->data_layout(data_layout);
+
+ // padding
+ auto padding = moco::str_toupper(plier::tf::get_string_attr(node, "padding"));
+ maxPool_node->padding(padding);
+
+ // ksize
+ auto tf_ksize = plier::tf::get_list_attr(node, "ksize");
+ auto ksize = plier::tf::as_int64_list(tf_ksize);
+ assert(ksize.size() == 4);
+ maxPool_node->ksize(ksize);
+
+ // strides
+ auto tf_strides = plier::tf::get_list_attr(node, "strides");
+ auto strides = plier::tf::as_int64_list(tf_strides);
+ assert(strides.size() == 4);
+ maxPool_node->strides(strides);
+
+ // To set the input node of encode_node with node_name
+ TensorName output_name(node_name, 0);
+ tensor_names->enroll(output_name, maxPool_node);
+
+ // Record ifm inputs to featureEncode_node
+ auto update = stdex::make_unique<TFMaxPoolGraphUpdate>(maxPool_node, TensorName(node.input(0)));
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
+
+// TODO Consider a case when TF MaxPool is for 3D.
+// MaxPool works for 2D and other Dimensions, such as 3D
+// So, in future, some other GraphBuilder decide if MaxPoolGraphBuilder is used or
+// other GraphBuilder is used for TF MaxPool
diff --git a/compiler/moco/import/src/Nodes/MaxPool.test.cpp b/compiler/moco/import/src/Nodes/MaxPool.test.cpp
new file mode 100644
index 000000000..a85e2027b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/MaxPool.test.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "moco/Import/Nodes/MaxPool.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *maxpool_01_pbtxtdata = STRING_CONTENT(
+ name: "maxpool"
+ op: "MaxPool"
+ input: "const/float"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "data_format"
+ value {
+ s: "NHWC"
+ }
+ }
+ attr {
+ key: "ksize"
+ value {
+ list {
+ i: 1
+ i: 2
+ i: 3
+ i: 1
+ }
+ }
+ }
+ attr {
+ key: "padding"
+ value {
+ s: "VALID"
+ }
+ }
+ attr {
+ key: "strides"
+ value {
+ list {
+ i: 1
+ i: 3
+ i: 2
+ i: 1
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, MaxPool_01)
+{
+ TFNodeBuildTester tester;
+ moco::MaxPoolGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(maxpool_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMaxPool
+ // - attributes value should match
+
+ tester.inputs({"const/float"});
+ tester.output("maxpool");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMaxPool *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->data_layout(), "NHWC");
+ ASSERT_EQ(test_node->padding(), "VALID");
+ ASSERT_EQ(test_node->ksize(), std::vector<int64_t>({1, 2, 3, 1}));
+ ASSERT_EQ(test_node->strides(), std::vector<int64_t>({1, 3, 2, 1}));
+}
diff --git a/compiler/moco/import/src/Nodes/Maximum.cpp b/compiler/moco/import/src/Nodes/Maximum.cpp
new file mode 100644
index 000000000..43bbbabe6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Maximum.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "moco/Import/Nodes/Maximum.h"
+
+#include <moco/IR/Nodes/TFMaximum.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Maximum node
+ */
+class TFMaximumGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMaximumGraphUpdate(TFMaximum *node, std::vector<TensorName> names) : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMaximum *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFMaximumGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MaximumGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void MaximumGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Maximum node
+ auto tf_maximum = graph->nodes()->create<TFMaximum>();
+ tf_maximum->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_maximum);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_maximum_update = stdex::make_unique<TFMaximumGraphUpdate>(tf_maximum, add_input_names);
+ updates->enroll(std::move(tf_maximum_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Maximum.test.cpp b/compiler/moco/import/src/Nodes/Maximum.test.cpp
new file mode 100644
index 000000000..2a8b63622
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Maximum.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Maximum.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *maximum_basic_pbtxt = STRING_CONTENT(
+ name: "MAXIMUM_01"
+ op: "Maximum"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_maximum_basic)
+{
+ TFNodeBuildTester tester;
+ moco::MaximumGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(maximum_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFMaximum node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("MAXIMUM_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Mean.cpp b/compiler/moco/import/src/Nodes/Mean.cpp
new file mode 100644
index 000000000..30fb0f1f7
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mean.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "moco/Import/Nodes/Mean.h"
+
+#include <moco/IR/Nodes/TFMean.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Mean node
+ */
+class MeanGraphUpdate final : public GraphUpdate
+{
+public:
+ MeanGraphUpdate(TFMean *node, const TensorName &&input_name,
+ const TensorName &&reduction_indices_name)
+ : _node(node), _input_name(input_name), _reduction_indices_name(reduction_indices_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMean *_node;
+ const TensorName _input_name;
+ const TensorName _reduction_indices_name;
+};
+
+void MeanGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ loco::Node *reduction_indices_node = table->node(_reduction_indices_name);
+ _node->input(input_node);
+ _node->reduction_indices(reduction_indices_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MeanGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "Tidx", "keep_dims"}))
+ return false;
+
+ auto dtype = plier::tf::get_datatype_attr(node, "Tidx");
+ if (dtype != tensorflow::DataType::DT_INT32 && dtype != tensorflow::DataType::DT_INT64)
+ return false;
+
+ return true;
+}
+
+void MeanGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Mean node
+ auto tf_mean = graph->nodes()->create<TFMean>();
+ tf_mean->name(node.name());
+ tf_mean->keep_dims(plier::tf::get_bool_attr(node, "keep_dims"));
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_mean);
+
+ auto update = stdex::make_unique<MeanGraphUpdate>(tf_mean, TensorName(node.input(0)),
+ TensorName(node.input(1)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Mean.test.cpp b/compiler/moco/import/src/Nodes/Mean.test.cpp
new file mode 100644
index 000000000..6321fad16
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mean.test.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 "moco/Import/Nodes/Mean.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *mean_true_pbtxtdata = STRING_CONTENT(
+ name: "Mean"
+ op: "Mean"
+ input: "Placeholder"
+ input: "Const"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tidx"
+ value { type: DT_INT32 }
+ }
+ attr {
+ key: "keep_dims"
+ value { b: true }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, mean_true)
+{
+ TFNodeBuildTester tester;
+ moco::MeanGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mean_true_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMean
+ // - input node should not be nullptr
+ // - reduction_indeces node should not be nullptr
+ // - keep_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder", "Const"});
+ tester.output("Mean");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMean *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->keep_dims(), true);
+}
+
+namespace
+{
+
+// clang-format off
+const char *mean_false_pbtxtdata = STRING_CONTENT(
+ name: "Mean"
+ op: "Mean"
+ input: "Placeholder"
+ input: "Const"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tidx"
+ value { type: DT_INT32 }
+ }
+ attr {
+ key: "keep_dims"
+ value { b: false }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, mean_false)
+{
+ TFNodeBuildTester tester;
+ moco::MeanGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mean_false_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFMean
+ // - input node should not be nullptr
+ // - reduction_indeces node should not be nullptr
+ // - keep_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder", "Const"});
+ tester.output("Mean");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFMean *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->keep_dims(), false);
+}
diff --git a/compiler/moco/import/src/Nodes/Mul.cpp b/compiler/moco/import/src/Nodes/Mul.cpp
new file mode 100644
index 000000000..ab926b59e
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mul.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "moco/Import/Nodes/Mul.h"
+
+#include <moco/IR/Nodes/TFMul.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Mul node
+ */
+class TFMulGraphUpdate final : public GraphUpdate
+{
+public:
+ TFMulGraphUpdate(TFMul *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFMul *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFMulGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool MulGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void MulGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Mul node
+ auto tf_mul = graph->nodes()->create<TFMul>();
+ tf_mul->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_mul);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_mul_update = stdex::make_unique<TFMulGraphUpdate>(tf_mul, add_input_names);
+ updates->enroll(std::move(tf_mul_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Mul.test.cpp b/compiler/moco/import/src/Nodes/Mul.test.cpp
new file mode 100644
index 000000000..92730b377
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Mul.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Mul.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *mul_basic_pbtxt = STRING_CONTENT(
+ name: "MUL_01"
+ op: "Mul"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_mul_basic)
+{
+ TFNodeBuildTester tester;
+ moco::MulGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(mul_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFMul node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("MUL_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Pack.cpp b/compiler/moco/import/src/Nodes/Pack.cpp
new file mode 100644
index 000000000..45815a30e
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pack.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 "moco/Import/Nodes/Pack.h"
+
+#include <moco/IR/Nodes/TFPack.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <loco/IR/NodeShape.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+
+namespace
+{
+
+using namespace moco;
+
+class TFPackGraphUpdate final : public GraphUpdate
+{
+public:
+ TFPackGraphUpdate(TFPack *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFPack *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFPackGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ uint32_t num_values = _names.size();
+ assert(num_values >= 1);
+
+ for (uint32_t i = 0; i < num_values; ++i)
+ {
+ auto input_node = tensor_names->node(_names[i]);
+ assert(input_node != nullptr);
+ _node->values(i, input_node);
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool PackGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"T", "N", "axis"}))
+ return false;
+
+ const int num_inputs = node.input_size();
+ return (num_inputs >= 1) && (num_inputs == plier::tf::get_int_attr(node, "N"));
+}
+
+void PackGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ auto graph = context->graph();
+ auto tensor_names = context->tensor_names();
+ auto updates = context->updates();
+
+ const int num_inputs = node.input_size();
+ std::vector<TensorName> input_names;
+ auto pack_node = graph->nodes()->create<TFPack>(num_inputs);
+ pack_node->name(node.name());
+
+ for (int ni = 0; ni < num_inputs; ++ni)
+ {
+ input_names.push_back(TensorName(node.input(ni)));
+ }
+
+ pack_node->axis(plier::tf::get_int_attr(node, "axis"));
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, pack_node);
+
+ auto update = stdex::make_unique<TFPackGraphUpdate>(pack_node, input_names);
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Pack.test.cpp b/compiler/moco/import/src/Nodes/Pack.test.cpp
new file mode 100644
index 000000000..01774a906
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pack.test.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "moco/Import/Nodes/Pack.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *pack_01_pbtxtdata = STRING_CONTENT(
+ name: "Pack"
+ op: "Pack"
+ input: "input_1"
+ input: "input_2"
+ input: "input_3"
+ input: "input_4"
+ attr {
+ key: "N"
+ value {
+ i: 4
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "axis"
+ value {
+ i: 0
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_pack_basic)
+{
+ TFNodeBuildTester tester;
+ moco::PackGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(pack_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFPack
+ // - there should be four values
+ // - values(idx) should not be nullptr
+ // - axis() should be 0
+
+ tester.inputs({"input_1", "input_2", "input_3", "input_4"});
+ tester.output("Pack");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFPack *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->N(), 4);
+ ASSERT_NE(test_node->values(0), nullptr);
+ ASSERT_NE(test_node->values(1), nullptr);
+ ASSERT_NE(test_node->values(2), nullptr);
+ ASSERT_NE(test_node->values(3), nullptr);
+ ASSERT_EQ(test_node->axis(), 0);
+}
diff --git a/compiler/moco/import/src/Nodes/Pad.cpp b/compiler/moco/import/src/Nodes/Pad.cpp
new file mode 100644
index 000000000..262a68fa0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pad.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 "moco/Import/Nodes/Pad.h"
+
+#include <moco/IR/Nodes/TFPad.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Pad node
+ */
+class TFPadGraphUpdate final : public GraphUpdate
+{
+public:
+ TFPadGraphUpdate(TFPad *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFPad *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFPadGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_names.size() == 2);
+
+ _node->input(table->node(_names[0]));
+ _node->paddings(table->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool PadGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 2)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T", "Tpaddings"});
+}
+
+void PadGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Pad node
+ auto tf_pad = graph->nodes()->create<TFPad>();
+ tf_pad->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_pad);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // input
+ add_input_names.push_back(TensorName(node.input(1))); // paddings
+
+ // Queue node input update
+ auto tf_pad_update = stdex::make_unique<TFPadGraphUpdate>(tf_pad, add_input_names);
+ updates->enroll(std::move(tf_pad_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Pad.test.cpp b/compiler/moco/import/src/Nodes/Pad.test.cpp
new file mode 100644
index 000000000..19769cf6b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Pad.test.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 "moco/Import/Nodes/Pad.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *pad_basic_pbtxt = STRING_CONTENT(
+ name: "Pad"
+ op: "Pad"
+ input: "input"
+ input: "paddings"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+ attr {
+ key: "Tpaddings"
+ value {
+ type: DT_INT32
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_pad_basic)
+{
+ TFNodeBuildTester tester;
+ moco::PadGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(pad_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFPad node should exist
+ // - input input() should not be null
+ // - input paddings() should not be null
+
+ tester.inputs({"input", "paddings"});
+ tester.output("Pad");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Placeholder.cpp b/compiler/moco/import/src/Nodes/Placeholder.cpp
new file mode 100644
index 000000000..0033f664b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Placeholder.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "moco/Import/Nodes/Placeholder.h"
+
+#include <moco/IR/Nodes/TFPlaceholder.h>
+
+#include <moco/Names.h>
+#include <plier/tf/Convert.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace moco
+{
+
+bool PlaceholderGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (!plier::tf::has_attrs(node, {"dtype", "shape"}))
+ return false;
+
+ loco::DataType dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ if (dtype != loco::DataType::FLOAT32)
+ return false;
+ // TODO support other types
+
+ return true;
+}
+
+void PlaceholderGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+
+ loco::DataType dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "dtype"));
+ const auto &shape = plier::tf::get_shape_attr(node, "shape");
+ // TODO handle for unknown rank
+ assert(!shape.unknown_rank());
+ int64_t num_dims = shape.dim_size();
+
+ // TODO support other types
+ assert(dtype == loco::DataType::FLOAT32);
+
+ // Create a "Placeholder" node as an input
+ auto placeholder_node = graph->nodes()->create<moco::TFPlaceholder>();
+ placeholder_node->name(node.name());
+ placeholder_node->dtype(dtype);
+
+ // Setting shape info.
+ placeholder_node->rank(num_dims);
+ for (int64_t d = 0; d < num_dims; d++)
+ {
+ assert(shape.dim(d).size() < std::numeric_limits<uint32_t>::max());
+ int64_t dim_value = shape.dim(d).size();
+ if (dim_value >= 0)
+ {
+ uint32_t dim_value32 = static_cast<uint32_t>(dim_value);
+ placeholder_node->dim(d) = dim_value32;
+ }
+ else
+ {
+ placeholder_node->dim(d).unset();
+ // TODO Remove assert() and do implement
+ // NOTE Current implementation assumes dim is all know
+ assert(false);
+ }
+ }
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, placeholder_node);
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Placeholder.test.cpp b/compiler/moco/import/src/Nodes/Placeholder.test.cpp
new file mode 100644
index 000000000..80488ce39
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Placeholder.test.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 "moco/Import/Nodes/Placeholder.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *known_batch_pbtxt = STRING_CONTENT(
+ name: "placeholder"
+ op: "Placeholder"
+ attr {
+ key: "dtype" value { type: DT_FLOAT }
+ }
+ attr {
+ key: "shape"
+ value {
+ shape {
+ dim { size: 1024 }
+ dim { size: 2 }
+ dim { size: 3 }
+ dim { size: 4 }
+ }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, placeholder_knwon_batch)
+{
+ TFNodeBuildTester tester;
+ moco::PlaceholderGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(known_batch_pbtxt, nodedef));
+
+ // what to test:
+ // - TFPlaceholder node should exist
+ // - shape attribute should match
+
+ tester.inputs({});
+ tester.output("placeholder");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFPlaceholder *>(tester.output());
+ assert(test_node != nullptr);
+ ASSERT_TRUE(test_node->dim(0).known() && test_node->dim(0).value() == 1024);
+ ASSERT_TRUE(test_node->dim(1).known() && test_node->dim(1).value() == 2);
+ ASSERT_TRUE(test_node->dim(2).known() && test_node->dim(2).value() == 3);
+ ASSERT_TRUE(test_node->dim(3).known() && test_node->dim(3).value() == 4);
+}
diff --git a/compiler/moco/import/src/Nodes/RealDiv.cpp b/compiler/moco/import/src/Nodes/RealDiv.cpp
new file mode 100644
index 000000000..de3d57673
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/RealDiv.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 "moco/Import/Nodes/RealDiv.h"
+
+#include <moco/IR/Nodes/TFRealDiv.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF RealDiv node
+ */
+class TFRealDivGraphUpdate final : public GraphUpdate
+{
+public:
+ TFRealDivGraphUpdate(TFRealDiv *node, std::vector<TensorName> names) : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRealDiv *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFRealDivGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+bool RealDivGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void RealDivGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect RealDiv node
+ auto tf_div = graph->nodes()->create<TFRealDiv>();
+ tf_div->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_div);
+
+ std::vector<TensorName> div_input_names;
+ div_input_names.push_back(TensorName(node.input(0))); // x
+ div_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_div_update = stdex::make_unique<TFRealDivGraphUpdate>(tf_div, div_input_names);
+ updates->enroll(std::move(tf_div_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/RealDiv.test.cpp b/compiler/moco/import/src/Nodes/RealDiv.test.cpp
new file mode 100644
index 000000000..cda2d3738
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/RealDiv.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/RealDiv.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *div_basic_pbtxt = STRING_CONTENT(
+ name: "DIV_01"
+ op: "RealDiv"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_div_basic)
+{
+ TFNodeBuildTester tester;
+ moco::RealDivGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(div_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFRealDiv node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("DIV_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Relu.cpp b/compiler/moco/import/src/Nodes/Relu.cpp
new file mode 100644
index 000000000..eedc8155d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu.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 "moco/Import/Nodes/Relu.h"
+
+#include <moco/IR/Nodes/TFRelu.h>
+
+#include <moco/Names.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+
+using namespace moco;
+
+class TFReluGraphUpdate final : public GraphUpdate
+{
+public:
+ TFReluGraphUpdate(TFRelu *node, const TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRelu *_node;
+ const TensorName _name;
+};
+
+void TFReluGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->features(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ReluGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // ReLU node SHOULD have only one input
+ if (node.input_size() != 1)
+ return false;
+
+ return true;
+}
+
+void ReluGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a "TFRelu" node for Relu
+ auto relu_node = graph->nodes()->create<TFRelu>();
+ relu_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, relu_node);
+
+ // Queue node input update
+ auto update = stdex::make_unique<TFReluGraphUpdate>(relu_node, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Relu.test.cpp b/compiler/moco/import/src/Nodes/Relu.test.cpp
new file mode 100644
index 000000000..a20ee081d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Relu.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *relu_01_pbtxtdata = STRING_CONTENT(
+ name: "ReLU"
+ op: "Relu"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, relu_01)
+{
+ TFNodeBuildTester tester;
+ moco::ReluGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(relu_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFRelu
+ // - features node should not be nullptr
+
+ tester.inputs({"Placeholder"});
+ tester.output("ReLU");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Relu6.cpp b/compiler/moco/import/src/Nodes/Relu6.cpp
new file mode 100644
index 000000000..4700ba408
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu6.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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 "moco/Import/Nodes/Relu6.h"
+
+#include <moco/IR/Nodes/TFRelu6.h>
+
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+class TFRelu6GraphUpdate final : public GraphUpdate
+{
+public:
+ TFRelu6GraphUpdate(TFRelu6 *node, const TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRelu6 *_node;
+ const TensorName _name;
+};
+
+void TFRelu6GraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->features(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool Relu6GraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // ReLU6 node SHOULD have only one input
+ if (node.input_size() != 1)
+ return false;
+ return true;
+}
+
+void Relu6GraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // Create a "TFRelu6" node for Relu
+ auto relu_node = graph->nodes()->create<TFRelu6>();
+ relu_node->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, relu_node);
+
+ // Queue node input update
+ auto update = stdex::make_unique<TFRelu6GraphUpdate>(relu_node, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Relu6.test.cpp b/compiler/moco/import/src/Nodes/Relu6.test.cpp
new file mode 100644
index 000000000..26beb6c17
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Relu6.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Relu6.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *relu6_01_pbtxtdata = STRING_CONTENT(
+ name: "ReLU6"
+ op: "Relu6"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, relu6_01)
+{
+ TFNodeBuildTester tester;
+ moco::Relu6GraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(relu6_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFRelu6
+ // - features node should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("ReLU6");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Reshape.cpp b/compiler/moco/import/src/Nodes/Reshape.cpp
new file mode 100644
index 000000000..26e22513f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Reshape.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 "moco/Import/Nodes/Reshape.h"
+
+#include <moco/IR/Nodes/TFReshape.h>
+
+#include <moco/Names.h>
+#include <plier/tf/Convert.h>
+#include <loco.h>
+#include <stdex/Memory.h>
+
+#include <cassert>
+#include <stdexcept>
+
+namespace
+{
+using namespace moco;
+
+class ReshapeGraphUpdate final : public GraphUpdate
+{
+public:
+ ReshapeGraphUpdate(TFReshape *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFReshape *_node;
+ std::vector<TensorName> _names;
+};
+
+void ReshapeGraphUpdate::input(const SymbolTable *node_table) const
+{
+ assert(_names.size() == 2);
+
+ auto tensor_node = node_table->node(_names[0]);
+ auto shape_node = node_table->node(_names[1]);
+
+ assert(tensor_node != nullptr);
+ assert(shape_node != nullptr);
+
+ _node->tensor(tensor_node);
+ _node->shape(shape_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ReshapeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // Tensorflow Reshape has 2 inputs: tensor & shape
+ if (node.input_size() != 2)
+ return false;
+
+ // TODO Assert Tshape value is DT_INT32?
+ return plier::tf::has_attrs(node, {"T", "Tshape"});
+}
+
+void ReshapeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // name of loco nodes
+ std::string reshape_name = node.name();
+
+ auto reshape = graph->nodes()->create<TFReshape>();
+ reshape->name(node.name());
+
+ // save the name for graph link updates
+ TensorName output_name(reshape_name, 0);
+ tensor_names->enroll(output_name, reshape);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // tensor
+ input_names.push_back(TensorName(node.input(1))); // shape
+
+ // Queue node input update
+ auto update = stdex::make_unique<ReshapeGraphUpdate>(reshape, input_names);
+
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Reshape.test.cpp b/compiler/moco/import/src/Nodes/Reshape.test.cpp
new file mode 100644
index 000000000..c406bf47b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Reshape.test.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "moco/Import/Nodes/Reshape.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *reshape_01_pbtxtdata = STRING_CONTENT(
+ name: "reshape"
+ op: "Reshape"
+ input: "placeholder"
+ input: "shape"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "Tshape"
+ value { type: DT_INT32 }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, reshape_01)
+{
+ TFNodeBuildTester tester;
+ moco::ReshapeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(reshape_01_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFReshape
+ // - input nodes should not be null
+
+ tester.inputs({"placeholder", "shape"});
+ tester.output("reshape");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Rsqrt.cpp b/compiler/moco/import/src/Nodes/Rsqrt.cpp
new file mode 100644
index 000000000..979ac90c9
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Rsqrt.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "moco/Import/Nodes/Rsqrt.h"
+
+#include <moco/IR/Nodes/TFRsqrt.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Rsqrt node
+ */
+class TFRsqrtGraphUpdate final : public GraphUpdate
+{
+public:
+ TFRsqrtGraphUpdate(TFRsqrt *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFRsqrt *_node;
+ TensorName _name;
+};
+
+void TFRsqrtGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool RsqrtGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void RsqrtGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Rsqrt node
+ auto tf_rsqrt = graph->nodes()->create<TFRsqrt>();
+ tf_rsqrt->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_rsqrt);
+
+ // Queue node input update
+ auto tf_rsqrt_update =
+ stdex::make_unique<TFRsqrtGraphUpdate>(tf_rsqrt, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_rsqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Rsqrt.test.cpp b/compiler/moco/import/src/Nodes/Rsqrt.test.cpp
new file mode 100644
index 000000000..2750725bc
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Rsqrt.test.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "moco/Import/Nodes/Rsqrt.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *rsqrt_basic_pbtxt = STRING_CONTENT(
+ name: "RSQRT_01"
+ op: "Rsqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_rsqrt_basic)
+{
+ TFNodeBuildTester tester;
+ moco::RsqrtGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(rsqrt_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFRsqrt node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("RSQRT_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Shape.cpp b/compiler/moco/import/src/Nodes/Shape.cpp
new file mode 100644
index 000000000..1e112ebb0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Shape.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 "moco/Import/Nodes/Shape.h"
+
+#include <moco/IR/Nodes/TFShape.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Shape node
+ */
+class ShapeGraphUpdate final : public GraphUpdate
+{
+public:
+ ShapeGraphUpdate(TFShape *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFShape *_node;
+ const TensorName _input_name;
+};
+
+void ShapeGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool ShapeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void ShapeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // create TF dialect Shape node
+ auto tf_shape = graph->nodes()->create<TFShape>();
+ tf_shape->name(node.name());
+
+ if (plier::tf::has_attrs(node, {"out_type"}))
+ {
+ auto dtype = plier::tf::as_loco_datatype(plier::tf::get_datatype_attr(node, "out_type"));
+ // TODO Support other dtype like S64
+ assert(dtype == loco::DataType::S32);
+
+ tf_shape->dtype(dtype);
+ }
+ else
+ {
+ // Set to S32, TF-documented default value for 'out_type'
+ tf_shape->dtype(loco::DataType::S32);
+ }
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_shape);
+
+ auto update = stdex::make_unique<ShapeGraphUpdate>(tf_shape, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Shape.test.cpp b/compiler/moco/import/src/Nodes/Shape.test.cpp
new file mode 100644
index 000000000..4aaf66c6f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Shape.test.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 "moco/Import/Nodes/Shape.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *shape_000_pbtxtdata = STRING_CONTENT(
+ name: "Shape"
+ op: "Shape"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "out_type"
+ value { type: DT_INT32 }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, shape_000)
+{
+ TFNodeBuildTester tester;
+ moco::ShapeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(shape_000_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFShape
+ // - input node should not be null
+ // - dtype attribute is set same as out_type attribute of pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Shape");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFShape *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->dtype(), loco::DataType::S32);
+}
diff --git a/compiler/moco/import/src/Nodes/Softmax.cpp b/compiler/moco/import/src/Nodes/Softmax.cpp
new file mode 100644
index 000000000..6f2c609ff
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Softmax.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 "moco/Import/Nodes/Softmax.h"
+
+#include <moco/IR/Nodes/TFSoftmax.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+* @brief GraphUpdate for Softmax node
+*/
+class SoftmaxGraphUpdate final : public GraphUpdate
+{
+public:
+ SoftmaxGraphUpdate(TFSoftmax *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSoftmax *_node;
+ const TensorName _input_name;
+};
+
+void SoftmaxGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->logits(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SoftmaxGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void SoftmaxGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Softmax node
+ auto tf_softmax = graph->nodes()->create<TFSoftmax>();
+ tf_softmax->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_softmax);
+
+ auto update = stdex::make_unique<SoftmaxGraphUpdate>(tf_softmax, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Softmax.test.cpp b/compiler/moco/import/src/Nodes/Softmax.test.cpp
new file mode 100644
index 000000000..b7c0797bb
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Softmax.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Softmax.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *softmax_2d_pbtxtdata = STRING_CONTENT(
+ name: "Softmax"
+ op: "Softmax"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, softmax_2d)
+{
+ TFNodeBuildTester tester;
+ moco::SoftmaxGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(softmax_2d_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSoftmax
+ // - logits node should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("Softmax");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Sqrt.cpp b/compiler/moco/import/src/Nodes/Sqrt.cpp
new file mode 100644
index 000000000..f891e48f6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sqrt.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "moco/Import/Nodes/Sqrt.h"
+
+#include <moco/IR/Nodes/TFSqrt.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Sqrt node
+ */
+class TFSqrtGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSqrtGraphUpdate(TFSqrt *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSqrt *_node;
+ TensorName _name;
+};
+
+void TFSqrtGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SqrtGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void SqrtGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Sqrt node
+ auto tf_sqrt = graph->nodes()->create<TFSqrt>();
+ tf_sqrt->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sqrt);
+
+ // Queue node input update
+ auto tf_sqrt_update = stdex::make_unique<TFSqrtGraphUpdate>(tf_sqrt, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_sqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Sqrt.test.cpp b/compiler/moco/import/src/Nodes/Sqrt.test.cpp
new file mode 100644
index 000000000..427d4df0f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sqrt.test.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "moco/Import/Nodes/Sqrt.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sqrt_basic_pbtxt = STRING_CONTENT(
+ name: "SQRT_01"
+ op: "Sqrt"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_sqrt_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SqrtGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sqrt_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSqrt node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("SQRT_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/SquaredDifference.cpp b/compiler/moco/import/src/Nodes/SquaredDifference.cpp
new file mode 100644
index 000000000..17a1fe93d
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/SquaredDifference.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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 "moco/Import/Nodes/SquaredDifference.h"
+
+#include <moco/IR/Nodes/TFSquaredDifference.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF SquaredDifference node
+ */
+class TFSquaredDifferenceGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSquaredDifferenceGraphUpdate(TFSquaredDifference *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSquaredDifference *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFSquaredDifferenceGraphUpdate::input(const SymbolTable *table) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(table->node(_names[0]));
+ _node->y(table->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SquaredDifferenceGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void SquaredDifferenceGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect SquaredDifference node
+ auto tf_sqdiff = graph->nodes()->create<TFSquaredDifference>();
+ tf_sqdiff->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sqdiff);
+
+ std::vector<TensorName> add_input_names;
+ add_input_names.push_back(TensorName(node.input(0))); // x
+ add_input_names.push_back(TensorName(node.input(1))); // y
+
+ // Queue node input update
+ auto tf_sqrt_update =
+ stdex::make_unique<TFSquaredDifferenceGraphUpdate>(tf_sqdiff, add_input_names);
+ updates->enroll(std::move(tf_sqrt_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp b/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp
new file mode 100644
index 000000000..336ab1358
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/SquaredDifference.test.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "moco/Import/Nodes/SquaredDifference.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sqdiff_basic_pbtxt = STRING_CONTENT(
+ name: "squared_difference"
+ op: "SquaredDifference"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_squdiff_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SquaredDifferenceGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sqdiff_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSquaredDifference node should exist
+ // - input x() should not be null
+ // - input y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("squared_difference");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Squeeze.cpp b/compiler/moco/import/src/Nodes/Squeeze.cpp
new file mode 100644
index 000000000..1b4ebae6f
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Squeeze.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "moco/Import/Nodes/Squeeze.h"
+
+#include <moco/IR/Nodes/TFSqueeze.h>
+
+#include <moco/Names.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for Squeeze node
+ */
+class SqueezeGraphUpdate final : public GraphUpdate
+{
+public:
+ SqueezeGraphUpdate(TFSqueeze *node, const TensorName &&input_name)
+ : _node(node), _input_name(input_name)
+ {
+ // DO NOTHING
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSqueeze *_node;
+ const TensorName _input_name;
+};
+
+void SqueezeGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *input_node = table->node(_input_name);
+ _node->input(input_node);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SqueezeGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T"}))
+ return false;
+
+ if (plier::tf::has_attrs(node, {"axis"}))
+ {
+ // TODO support 'axis' attribute
+ oops::UserExn("Squeeze: Unsupported 'axis' attribute", node.name());
+ }
+
+ return true;
+}
+
+void SqueezeGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // TODO support 'axis' attribute
+ assert(!plier::tf::has_attrs(node, {"axis"}));
+
+ std::vector<int64_t> squeeze_dims;
+ if (plier::tf::has_attrs(node, {"squeeze_dims"}))
+ {
+ auto squeeze_dim_list = plier::tf::get_list_attr(node, {"squeeze_dims"});
+ // TODO assert squeeze_dims are mutually different?
+ squeeze_dims = plier::tf::as_int64_list(squeeze_dim_list);
+ }
+ // Note that it is possible that NodeDef does not have squeeze_dims attribute.
+ // In that case, TFSqueeze also has empty squeeze_dims,
+
+ // creating TF dialect Squeeze node
+ auto tf_squeeze = graph->nodes()->create<TFSqueeze>();
+ tf_squeeze->name(node.name());
+ tf_squeeze->squeeze_dims(squeeze_dims);
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_squeeze);
+
+ auto update = stdex::make_unique<SqueezeGraphUpdate>(tf_squeeze, TensorName(node.input(0)));
+ updates->enroll(std::move(update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Squeeze.test.cpp b/compiler/moco/import/src/Nodes/Squeeze.test.cpp
new file mode 100644
index 000000000..e8188f98b
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Squeeze.test.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 "moco/Import/Nodes/Squeeze.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+
+// clang-format off
+const char *squeeze_all_pbtxtdata = STRING_CONTENT(
+ name: "Squeeze"
+ op: "Squeeze"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, squeeze_all)
+{
+ TFNodeBuildTester tester;
+ moco::SqueezeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(squeeze_all_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSqueeze
+ // - input node should not be null
+ // - squeeze_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Squeeze");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFSqueeze *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->squeeze_dims().size(), 0);
+}
+
+namespace
+{
+
+// clang-format off
+const char *squeeze_some_pbtxtdata = STRING_CONTENT(
+ name: "Squeeze"
+ op: "Squeeze"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value { type: DT_FLOAT }
+ }
+ attr {
+ key: "squeeze_dims"
+ value {
+ list { i: 1 }
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, squeeze_some)
+{
+ TFNodeBuildTester tester;
+ moco::SqueezeGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(squeeze_some_pbtxtdata, nodedef));
+
+ // what to test:
+ // - there should exist TFSqueeze
+ // - input node should not be null
+ // - squeeze_dims attribute is set same as pbtxt
+
+ tester.inputs({"Placeholder"});
+ tester.output("Squeeze");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFSqueeze *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->squeeze_dims().size(), 1);
+ ASSERT_EQ(test_node->squeeze_dims().at(0), 1);
+}
+
+// TODO Add test case for negative squeeze dim
diff --git a/compiler/moco/import/src/Nodes/StopGradient.cpp b/compiler/moco/import/src/Nodes/StopGradient.cpp
new file mode 100644
index 000000000..9caec6943
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StopGradient.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "moco/Import/Nodes/StopGradient.h"
+
+#include <moco/IR/Nodes/TFStopGradient.h>
+
+#include <loco.h>
+#include <plier/tf/Convert.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF StopGradient node
+ */
+class TFStopGradientGraphUpdate final : public GraphUpdate
+{
+public:
+ TFStopGradientGraphUpdate(TFStopGradient *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFStopGradient *_node;
+ TensorName _name;
+};
+
+void TFStopGradientGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->input(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool StopGradientGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ if (node.input_size() != 1)
+ return false;
+
+ return plier::tf::has_attrs(node, {"T"});
+}
+
+void StopGradientGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect StopGradient node
+ auto tf_stopgradient = graph->nodes()->create<TFStopGradient>();
+ tf_stopgradient->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_stopgradient);
+
+ // Queue node input update
+ auto tf_stopgradient_update =
+ stdex::make_unique<TFStopGradientGraphUpdate>(tf_stopgradient, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_stopgradient_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/StopGradient.test.cpp b/compiler/moco/import/src/Nodes/StopGradient.test.cpp
new file mode 100644
index 000000000..0bf70ebcc
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StopGradient.test.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "moco/Import/Nodes/StopGradient.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *stopgradient_basic_pbtxt = STRING_CONTENT(
+ name: "StopGradient_01"
+ op: "StopGradient"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_stopgradient_basic)
+{
+ TFNodeBuildTester tester;
+ moco::StopGradientGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(stopgradient_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFStopGradient node should exist
+ // - input() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("StopGradient_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/StridedSlice.cpp b/compiler/moco/import/src/Nodes/StridedSlice.cpp
new file mode 100644
index 000000000..06d388be0
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StridedSlice.cpp
@@ -0,0 +1,187 @@
+/*
+ * 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 "moco/Import/Nodes/StridedSlice.h"
+
+#include <moco/IR/Nodes/TFStridedSlice.h>
+#include <moco/IR/Nodes/TFConst.h>
+
+#include <moco/Names.h>
+
+#include "Convert.h"
+
+#include <loco.h>
+#include <stdex/Memory.h>
+#include <plier/tf/Convert.h>
+#include <oops/UserExn.h>
+
+namespace
+{
+using namespace moco;
+
+class TFStridedSliceGraphUpdate final : public GraphUpdate
+{
+public:
+ TFStridedSliceGraphUpdate(TFStridedSlice *node, std::vector<TensorName> names)
+ : _node(node), _names(names)
+ {
+ }
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFStridedSlice *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFStridedSliceGraphUpdate::input(const SymbolTable *node_table) const
+{
+ // TODO support size 3 where strides is None
+ assert(_names.size() == 4);
+
+ auto input_node = node_table->node(_names[0]);
+ auto begin_node = node_table->node(_names[1]);
+ auto end_node = node_table->node(_names[2]);
+ auto strides_node = node_table->node(_names[3]);
+ assert(input_node != nullptr);
+ assert(begin_node != nullptr);
+ assert(end_node != nullptr);
+ assert(strides_node != nullptr);
+
+ _node->input(input_node);
+ _node->begin(begin_node);
+ _node->end(end_node);
+ _node->strides(strides_node);
+
+ // TODO move validation codes to some suitable place
+ // Run basic validation
+
+ // TODO support full mask features
+ if (_node->begin_mask() != 0 || _node->end_mask() != 0 || _node->ellipsis_mask() != 0 ||
+ _node->new_axis_mask() != 0 || _node->shrink_axis_mask() != 1)
+ {
+ throw oops::UserExn("Mask attributes are not supported for now: ", _node->name());
+ }
+
+ // Only Const are supported for now
+ auto const_input = dynamic_cast<moco::TFConst *>(_node->input());
+ auto const_begin = dynamic_cast<moco::TFConst *>(_node->begin());
+ auto const_end = dynamic_cast<moco::TFConst *>(_node->end());
+ auto const_strides = dynamic_cast<moco::TFConst *>(_node->strides());
+ if (const_input == nullptr || const_begin == nullptr || const_end == nullptr ||
+ const_strides == nullptr)
+ {
+ throw oops::UserExn("Only Const inputs are supported for now: ", _node->name());
+ }
+
+ // TODO support S64
+ if (const_begin->dtype() != loco::DataType::S32 || const_end->dtype() != loco::DataType::S32 ||
+ const_strides->dtype() != loco::DataType::S32)
+ {
+ throw oops::UserExn("Only Const types of INT32 are supported for begin/end/strides for now: ",
+ _node->name());
+ }
+
+ // Input Rank should match number of elements of the begin/end/strides
+ auto rin = const_input->rank();
+ if (rin != const_begin->size<loco::DataType::S32>() ||
+ rin != const_end->size<loco::DataType::S32>() ||
+ rin != const_strides->size<loco::DataType::S32>())
+ {
+ throw oops::UserExn("Ranks for inputs should be same: ", _node->name());
+ }
+
+ // TODO support strides type of S64
+ // TODO support other strides value
+ // Only support stride 1 for now
+ uint32_t elements = const_strides->size<loco::DataType::S32>();
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ if (const_strides->at<loco::DataType::S32>(e) != 1)
+ {
+ throw oops::UserExn("Only stride 1 is supported for now: ", _node->name());
+ }
+ }
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool StridedSliceGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ // TODO support node.input_size() == 3 where strides is None
+ if (node.input_size() != 4)
+ return false;
+
+ if (!plier::tf::has_attrs(node, {"T", "Index", "begin_mask", "end_mask", "ellipsis_mask",
+ "new_axis_mask", "shrink_axis_mask"}))
+ return false;
+
+ return true;
+}
+
+void StridedSliceGraphBuilder::build(const tensorflow::NodeDef &node,
+ GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ std::string node_name = node.name();
+
+ auto stridedslice = graph->nodes()->create<TFStridedSlice>();
+ stridedslice->name(node_name);
+
+ // read attributes
+ auto begin_mask = plier::tf::get_int_attr(node, "begin_mask");
+ auto end_mask = plier::tf::get_int_attr(node, "end_mask");
+ auto ellipsis_mask = plier::tf::get_int_attr(node, "ellipsis_mask");
+ auto new_axis_mask = plier::tf::get_int_attr(node, "new_axis_mask");
+ auto shrink_axis_mask = plier::tf::get_int_attr(node, "shrink_axis_mask");
+
+ stridedslice->begin_mask(begin_mask);
+ stridedslice->end_mask(end_mask);
+ stridedslice->ellipsis_mask(ellipsis_mask);
+ stridedslice->new_axis_mask(new_axis_mask);
+ stridedslice->shrink_axis_mask(shrink_axis_mask);
+
+ // TODO support general mask values: we support only this limited case for now
+ assert(begin_mask == 0);
+ assert(end_mask == 0);
+ assert(ellipsis_mask == 0);
+ assert(new_axis_mask == 0);
+ assert(shrink_axis_mask == 1);
+
+ // save the name for graph link updates
+ TensorName output_name(node_name, 0);
+ tensor_names->enroll(output_name, stridedslice);
+
+ std::vector<TensorName> input_names;
+ input_names.push_back(TensorName(node.input(0))); // input
+ input_names.push_back(TensorName(node.input(1))); // begin
+ input_names.push_back(TensorName(node.input(2))); // end
+ input_names.push_back(TensorName(node.input(3))); // strides
+
+ auto tfconv2d_update = stdex::make_unique<TFStridedSliceGraphUpdate>(stridedslice, input_names);
+
+ updates->enroll(std::move(tfconv2d_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/StridedSlice.test.cpp b/compiler/moco/import/src/Nodes/StridedSlice.test.cpp
new file mode 100644
index 000000000..b6959d7ab
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/StridedSlice.test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "moco/Import/Nodes/StridedSlice.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *stridedslice_basic_pbtxt = STRING_CONTENT(
+ name: "StridedSlice"
+ op: "StridedSlice"
+ input: "input"
+ input: "begin"
+ input: "end"
+ input: "strides"
+ attr {
+ key: "Index"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "T"
+ value {
+ type: DT_INT32
+ }
+ }
+ attr {
+ key: "begin_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "ellipsis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "end_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "new_axis_mask"
+ value {
+ i: 0
+ }
+ }
+ attr {
+ key: "shrink_axis_mask"
+ value {
+ i: 1
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_stridedslice_basic)
+{
+ TFNodeBuildTester tester;
+ moco::StridedSliceGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(stridedslice_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFStridedSlice node should exist
+ // - inputs should not be nullptr
+ // - attributes should match the values
+
+ tester.inputs({"input", "begin", "end", "strides"}, loco::DataType::S32);
+ tester.output("StridedSlice");
+ tester.run(nodedef, graphbuilder);
+
+ auto test_node = dynamic_cast<moco::TFStridedSlice *>(tester.output());
+ ASSERT_NE(test_node, nullptr);
+ ASSERT_EQ(test_node->begin_mask(), 0);
+ ASSERT_EQ(test_node->end_mask(), 0);
+ ASSERT_EQ(test_node->ellipsis_mask(), 0);
+ ASSERT_EQ(test_node->new_axis_mask(), 0);
+ ASSERT_EQ(test_node->shrink_axis_mask(), 1);
+}
+
+// TODO add test where strides is None
diff --git a/compiler/moco/import/src/Nodes/Sub.cpp b/compiler/moco/import/src/Nodes/Sub.cpp
new file mode 100644
index 000000000..bdad81d67
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sub.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "moco/Import/Nodes/Sub.h"
+
+#include <moco/IR/Nodes/TFSub.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Sub node
+ */
+class TFSubGraphUpdate final : public GraphUpdate
+{
+public:
+ TFSubGraphUpdate(TFSub *node, std::vector<TensorName> names) : _node(node), _names(names) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFSub *_node;
+ std::vector<TensorName> _names;
+};
+
+void TFSubGraphUpdate::input(const SymbolTable *tensor_names) const
+{
+ assert(_names.size() == 2);
+
+ _node->x(tensor_names->node(_names[0]));
+ _node->y(tensor_names->node(_names[1]));
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool SubGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 2;
+}
+
+void SubGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Sub node
+ auto tf_sub = graph->nodes()->create<TFSub>();
+ tf_sub->name(node.name());
+
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_sub);
+
+ std::vector<TensorName> sub_input_names;
+ sub_input_names.push_back(TensorName(node.input(0))); // x
+ sub_input_names.push_back(TensorName(node.input(1))); // y
+
+ auto tf_sub_update = stdex::make_unique<TFSubGraphUpdate>(tf_sub, sub_input_names);
+ updates->enroll(std::move(tf_sub_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Sub.test.cpp b/compiler/moco/import/src/Nodes/Sub.test.cpp
new file mode 100644
index 000000000..05f1fb0d6
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Sub.test.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "moco/Import/Nodes/Sub.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *sub_basic_pbtxt = STRING_CONTENT(
+ name: "SUB_01"
+ op: "Sub"
+ input: "input_01"
+ input: "input_02"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_sub_basic)
+{
+ TFNodeBuildTester tester;
+ moco::SubGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(sub_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFSub node should exist
+ // - both inputs x() and y() should not be null
+
+ tester.inputs({"input_01", "input_02"});
+ tester.output("SUB_01");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/Nodes/Tanh.cpp b/compiler/moco/import/src/Nodes/Tanh.cpp
new file mode 100644
index 000000000..c89fa862a
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Tanh.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "moco/Import/Nodes/Tanh.h"
+
+#include <moco/IR/Nodes/TFTanh.h>
+
+#include <loco.h>
+#include <stdex/Memory.h>
+
+namespace
+{
+
+using namespace moco;
+
+/**
+ * @brief GraphUpdate for TF Tanh node
+ */
+class TFTanhGraphUpdate final : public GraphUpdate
+{
+public:
+ TFTanhGraphUpdate(TFTanh *node, TensorName &&name) : _node(node), _name(name) {}
+
+ void input(const SymbolTable *) const override;
+
+private:
+ TFTanh *_node;
+ TensorName _name;
+};
+
+void TFTanhGraphUpdate::input(const SymbolTable *table) const
+{
+ loco::Node *target = table->node(_name);
+ _node->x(target);
+}
+
+} // namespace
+
+namespace moco
+{
+
+bool TanhGraphBuilder::validate(const tensorflow::NodeDef &node) const
+{
+ return node.input_size() == 1;
+}
+
+void TanhGraphBuilder::build(const tensorflow::NodeDef &node, GraphBuilderContext *context) const
+{
+ assert(context != nullptr);
+
+ loco::Graph *graph = context->graph();
+ SymbolTable *tensor_names = context->tensor_names();
+ UpdateQueue *updates = context->updates();
+
+ // creating TF dialect Tanh node
+ auto tf_tanh = graph->nodes()->create<TFTanh>();
+ tf_tanh->name(node.name());
+
+ // register string-name to node
+ TensorName output_name(node.name(), 0);
+ tensor_names->enroll(output_name, tf_tanh);
+
+ // Queue node input update
+ auto tf_tanh_update = stdex::make_unique<TFTanhGraphUpdate>(tf_tanh, TensorName(node.input(0)));
+ updates->enroll(std::move(tf_tanh_update));
+}
+
+} // namespace moco
diff --git a/compiler/moco/import/src/Nodes/Tanh.test.cpp b/compiler/moco/import/src/Nodes/Tanh.test.cpp
new file mode 100644
index 000000000..20ebd15b2
--- /dev/null
+++ b/compiler/moco/import/src/Nodes/Tanh.test.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "moco/Import/Nodes/Tanh.h"
+#include "TestHelper.h"
+
+#include <gtest/gtest.h>
+
+using namespace moco::test;
+
+namespace
+{
+// clang-format off
+const char *tanh_basic_pbtxt = STRING_CONTENT(
+ name: "output/tanh"
+ op: "Tanh"
+ input: "Placeholder"
+ attr {
+ key: "T"
+ value {
+ type: DT_FLOAT
+ }
+ }
+);
+// clang-format on
+
+} // namespace
+
+TEST(TensorFlowImport, tf_tanh_basic)
+{
+ TFNodeBuildTester tester;
+ moco::TanhGraphBuilder graphbuilder;
+ tensorflow::NodeDef nodedef;
+
+ EXPECT_TRUE(plier::tf::parse_nodedef(tanh_basic_pbtxt, nodedef));
+
+ // what to test:
+ // - TFTanh node should exist
+ // - input x() should not be null
+
+ tester.inputs({"Placeholder"});
+ tester.output("output/tanh");
+ tester.run(nodedef, graphbuilder);
+}
diff --git a/compiler/moco/import/src/TestHelper.h b/compiler/moco/import/src/TestHelper.h
new file mode 100644
index 000000000..54ca45b4a
--- /dev/null
+++ b/compiler/moco/import/src/TestHelper.h
@@ -0,0 +1,83 @@
+/*
+ * 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 __TEST_HELPER_H__
+#define __TEST_HELPER_H__
+
+#include "moco/Import/GraphBuilder.h"
+
+#include <moco/IR/TFNode.h>
+#include <loco.h>
+#include <plier/tf/TestHelper.h>
+
+#include <tensorflow/core/framework/graph.pb.h>
+
+#define STRING_CONTENT(content) #content
+
+namespace moco
+{
+namespace test
+{
+
+template <typename T> T *find_first_node_bytype(loco::Graph *g)
+{
+ T *first_node = nullptr;
+ loco::Graph::NodeContext *nodes = g->nodes();
+ uint32_t count = nodes->size();
+
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ first_node = dynamic_cast<T *>(nodes->at(i));
+ if (first_node != nullptr)
+ break;
+ }
+
+ return first_node;
+}
+
+} // namespace test
+} // namespace moco
+
+namespace moco
+{
+namespace test
+{
+
+class TFNodeBuildTester
+{
+public:
+ TFNodeBuildTester();
+
+public:
+ void inputs(const std::vector<std::string> &names);
+ void inputs(const std::vector<std::string> &names, const loco::DataType dtype);
+ void output(const char *name);
+ moco::TFNode *output(void);
+
+ void run(tensorflow::NodeDef &node_def, moco::GraphBuilder &graph_builder);
+
+private:
+ std::unique_ptr<moco::SymbolTable> _tensor_names;
+ std::unique_ptr<loco::Graph> _graph;
+
+ std::vector<moco::TFNode *> _inputs;
+ const char *_output{nullptr};
+};
+
+} // namespace test
+} // namespace moco
+
+#endif // __TEST_HELPER_H__
diff --git a/compiler/moco/import/src/TestHelper.test.cpp b/compiler/moco/import/src/TestHelper.test.cpp
new file mode 100644
index 000000000..06c3dd372
--- /dev/null
+++ b/compiler/moco/import/src/TestHelper.test.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "TestHelper.h"
+
+#include <moco/IR/Nodes/TFConst.h>
+#include <stdex/Memory.h>
+
+#include <gtest/gtest.h>
+
+namespace moco
+{
+namespace test
+{
+
+TFNodeBuildTester::TFNodeBuildTester()
+{
+ _graph = loco::make_graph();
+ _tensor_names = stdex::make_unique<moco::SymbolTable>();
+}
+
+void TFNodeBuildTester::inputs(const std::vector<std::string> &names)
+{
+ for (auto name : names)
+ {
+ auto input = _graph->nodes()->create<moco::TFConst>();
+ moco::TensorName name_01(name, 0);
+ _tensor_names->enroll(name_01, input);
+
+ _inputs.push_back(input);
+ }
+}
+
+void TFNodeBuildTester::inputs(const std::vector<std::string> &names, const loco::DataType dtype)
+{
+ for (auto name : names)
+ {
+ auto input = _graph->nodes()->create<moco::TFConst>();
+ input->dtype(dtype);
+ moco::TensorName name_01(name, 0);
+ _tensor_names->enroll(name_01, input);
+
+ _inputs.push_back(input);
+ }
+}
+
+void TFNodeBuildTester::output(const char *name) { _output = name; }
+
+moco::TFNode *TFNodeBuildTester::output(void)
+{
+ assert(_output != nullptr);
+
+ moco::TensorName tname(_output, 0);
+ return static_cast<moco::TFNode *>(_tensor_names->node(tname));
+}
+
+void TFNodeBuildTester::run(tensorflow::NodeDef &nodedef, moco::GraphBuilder &graphbuilder)
+{
+ assert(_output != nullptr);
+
+ auto node_defs = stdex::make_unique<moco::NodeDefTable>();
+ auto updates = stdex::make_unique<moco::UpdateQueue>();
+
+ moco::GraphBuilderContext gb_context(_graph.get(), node_defs.get(), _tensor_names.get(),
+ updates.get());
+
+ EXPECT_TRUE(graphbuilder.validate(nodedef));
+ graphbuilder.build(nodedef, &gb_context);
+
+ for (auto &update : updates->queue())
+ {
+ update->input(_tensor_names.get());
+ }
+
+ auto tfnode = output();
+ ASSERT_NE(tfnode, nullptr);
+ ASSERT_STREQ(tfnode->name().c_str(), _output);
+
+ int idx = 0;
+ ASSERT_EQ(tfnode->arity(), _inputs.size());
+ for (auto input : _inputs)
+ {
+ ASSERT_EQ(tfnode->arg(idx++), input);
+ }
+}
+
+} // namespace test
+} // namespace moco