diff options
author | Chunseok Lee <chunseok.lee@samsung.com> | 2020-04-23 14:45:49 +0900 |
---|---|---|
committer | Chunseok Lee <chunseok.lee@samsung.com> | 2020-04-23 14:45:49 +0900 |
commit | e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (patch) | |
tree | 44a1a7951d168dd4370e13593ed03f4bc6d920c5 /compiler/moco/import | |
parent | 302e6564a7a76109e1178207e44e45a58631c477 (diff) | |
download | nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.gz nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.tar.bz2 nnfw-e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e.zip |
Imported Upstream version 1.4.0upstream/1.4.0submit/tizen/20200423.054851
Diffstat (limited to 'compiler/moco/import')
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 |