summaryrefslogtreecommitdiff
path: root/compiler/circlechef
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2020-07-30 11:32:26 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2020-07-30 11:32:26 +0900
commit05e0ec30a632339a8533082476f27bda31ccde16 (patch)
tree5f220ac83084fe133ffb08a6a17e99f9bb36ec1c /compiler/circlechef
parente2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (diff)
downloadnnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.gz
nnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.bz2
nnfw-05e0ec30a632339a8533082476f27bda31ccde16.zip
Imported Upstream version 1.7.0upstream/1.7.0
Diffstat (limited to 'compiler/circlechef')
-rw-r--r--compiler/circlechef/CMakeLists.txt21
-rw-r--r--compiler/circlechef/README.md8
-rw-r--r--compiler/circlechef/circle/CMakeLists.txt9
-rw-r--r--compiler/circlechef/circle/include/circlechef/RecipeChef.h41
-rw-r--r--compiler/circlechef/circle/src/CircleImport.cpp145
-rw-r--r--compiler/circlechef/circle/src/CircleImport.h140
-rw-r--r--compiler/circlechef/circle/src/CircleOpChef.h44
-rw-r--r--compiler/circlechef/circle/src/CircleOpChefs.h26
-rw-r--r--compiler/circlechef/circle/src/CircleOpRegistry.h71
-rw-r--r--compiler/circlechef/circle/src/Convert.cpp78
-rw-r--r--compiler/circlechef/circle/src/Convert.h58
-rw-r--r--compiler/circlechef/circle/src/Op/BCQFullyConnected.cpp64
-rw-r--r--compiler/circlechef/circle/src/Op/BCQFullyConnected.h39
-rw-r--r--compiler/circlechef/circle/src/Op/BCQGather.cpp68
-rw-r--r--compiler/circlechef/circle/src/Op/BCQGather.h39
-rw-r--r--compiler/circlechef/circle/src/Op/BatchMatMul.cpp48
-rw-r--r--compiler/circlechef/circle/src/Op/BatchMatMul.h39
-rw-r--r--compiler/circlechef/circle/src/Op/InstanceNorm.cpp53
-rw-r--r--compiler/circlechef/circle/src/Op/InstanceNorm.h39
-rw-r--r--compiler/circlechef/circle/src/RecipeChef.cpp248
-rw-r--r--compiler/circlechef/core/CMakeLists.txt9
-rw-r--r--compiler/circlechef/core/include/circlechef/ModelChef.h56
-rw-r--r--compiler/circlechef/core/src/Arguments.h34
-rw-r--r--compiler/circlechef/core/src/Convert.cpp72
-rw-r--r--compiler/circlechef/core/src/Convert.h31
-rw-r--r--compiler/circlechef/core/src/ModelChef.cpp631
-rw-r--r--compiler/circlechef/core/src/Op/BCQFullyConnected.cpp40
-rw-r--r--compiler/circlechef/core/src/Op/BCQFullyConnected.h52
-rw-r--r--compiler/circlechef/core/src/Op/BCQGather.cpp36
-rw-r--r--compiler/circlechef/core/src/Op/BCQGather.h49
-rw-r--r--compiler/circlechef/core/src/Op/BatchMatMul.cpp37
-rw-r--r--compiler/circlechef/core/src/Op/BatchMatMul.h49
-rw-r--r--compiler/circlechef/core/src/Op/InstanceNorm.cpp39
-rw-r--r--compiler/circlechef/core/src/Op/InstanceNorm.h52
-rw-r--r--compiler/circlechef/core/src/OpChef.def10
-rw-r--r--compiler/circlechef/core/src/OpChef.h48
-rw-r--r--compiler/circlechef/core/src/OpChefs.h25
-rw-r--r--compiler/circlechef/log/CMakeLists.txt7
-rw-r--r--compiler/circlechef/log/include/Log.h75
-rw-r--r--compiler/circlechef/log/include/LoggingContext.h35
-rw-r--r--compiler/circlechef/log/src/Log.cpp87
-rw-r--r--compiler/circlechef/log/src/LoggingContext.cpp41
-rw-r--r--compiler/circlechef/proto/CMakeLists.txt5
-rw-r--r--compiler/circlechef/proto/circlechef.proto110
-rw-r--r--compiler/circlechef/requires.cmake9
-rw-r--r--compiler/circlechef/tests/CMakeLists.txt70
-rwxr-xr-xcompiler/circlechef/tests/runvalidate.sh56
-rw-r--r--compiler/circlechef/tools/CMakeLists.txt6
-rw-r--r--compiler/circlechef/tools/console/CMakeLists.txt3
-rw-r--r--compiler/circlechef/tools/console/Driver.cpp58
-rw-r--r--compiler/circlechef/tools/file/CMakeLists.txt4
-rw-r--r--compiler/circlechef/tools/file/Driver.cpp85
-rw-r--r--compiler/circlechef/tools/reverse/CMakeLists.txt5
-rw-r--r--compiler/circlechef/tools/reverse/Driver.cpp72
54 files changed, 3276 insertions, 0 deletions
diff --git a/compiler/circlechef/CMakeLists.txt b/compiler/circlechef/CMakeLists.txt
new file mode 100644
index 000000000..cba7d0a4e
--- /dev/null
+++ b/compiler/circlechef/CMakeLists.txt
@@ -0,0 +1,21 @@
+nnas_find_package(Protobuf QUIET)
+
+if(NOT Protobuf_FOUND)
+ return()
+endif(NOT Protobuf_FOUND)
+
+if(NOT TARGET mio_circle)
+ return()
+endif(NOT TARGET mio_circle)
+
+# Recipe Parser
+add_subdirectory(proto)
+# Log
+add_subdirectory(log)
+# Core Library
+add_subdirectory(core)
+# Circle Library
+add_subdirectory(circle)
+# Tools
+add_subdirectory(tools)
+add_subdirectory(tests)
diff --git a/compiler/circlechef/README.md b/compiler/circlechef/README.md
new file mode 100644
index 000000000..1871a0660
--- /dev/null
+++ b/compiler/circlechef/README.md
@@ -0,0 +1,8 @@
+# circlechef
+
+## What is circlechef?
+
+Do you need a circle model for testing? Ask it to _circlechef_.
+Given a recipe, _circlechef_ will cook a circle model for you.
+
+**NOTE** _circlechef_ covers only what _tflchef_ does not cover. This is to support ops that exist only in circle shema, and other things can be made using _tflchef_ and _tflite2circle_.
diff --git a/compiler/circlechef/circle/CMakeLists.txt b/compiler/circlechef/circle/CMakeLists.txt
new file mode 100644
index 000000000..75165ada3
--- /dev/null
+++ b/compiler/circlechef/circle/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(circlechef_circle STATIC ${SOURCES})
+target_include_directories(circlechef_circle PUBLIC include)
+target_include_directories(circlechef_circle PRIVATE src)
+target_link_libraries(circlechef_circle circlechef_proto)
+target_link_libraries(circlechef_circle mio_circle)
+target_link_libraries(circlechef_circle stdex)
+target_link_libraries(circlechef_circle cwrap)
diff --git a/compiler/circlechef/circle/include/circlechef/RecipeChef.h b/compiler/circlechef/circle/include/circlechef/RecipeChef.h
new file mode 100644
index 000000000..d3cafa282
--- /dev/null
+++ b/compiler/circlechef/circle/include/circlechef/RecipeChef.h
@@ -0,0 +1,41 @@
+/*
+ * 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 __RECIPE_CHEF_H__
+#define __RECIPE_CHEF_H__
+
+#include <mio/circle/schema_generated.h>
+#include <circlechef.pb.h>
+
+#include <memory>
+#include <string>
+
+namespace circlechef
+{
+
+/**
+ * @brief Create ModelRecipe from circle::Model
+ */
+std::unique_ptr<ModelRecipe> generate_recipe(const circle::Model *model);
+
+/**
+ * @brief Write ModelRecipe to file with given name
+ */
+bool write_recipe(const std::string &filename, std::unique_ptr<ModelRecipe> &recipe);
+
+} // namespace circlechef
+
+#endif // __RECIPE_CHEF_H__
diff --git a/compiler/circlechef/circle/src/CircleImport.cpp b/compiler/circlechef/circle/src/CircleImport.cpp
new file mode 100644
index 000000000..e970fbce3
--- /dev/null
+++ b/compiler/circlechef/circle/src/CircleImport.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "CircleImport.h"
+
+#include "Convert.h"
+
+#include <sstream>
+
+namespace circlechef
+{
+
+const char *kEmptyTensorName = "(noname)";
+
+const char *tensor_type(const circle::Tensor *tensor)
+{
+ return circle::EnumNameTensorType(tensor->type());
+}
+
+const char *tensor_name(const circle::Tensor *tensor)
+{
+ auto name = tensor->name();
+ if (name)
+ return name->c_str();
+ return kEmptyTensorName;
+}
+
+bool is_valid(const circle::OperatorCode *opcode)
+{
+ circle::BuiltinOperator code = opcode->builtin_code();
+ return (circle::BuiltinOperator_MIN <= code && code <= circle::BuiltinOperator_MAX);
+}
+
+bool is_custom(const circle::OperatorCode *opcode)
+{
+ circle::BuiltinOperator code = opcode->builtin_code();
+ return (code == circle::BuiltinOperator_CUSTOM);
+}
+
+CircleImport::CircleImport(const circle::Model *model)
+{
+ _subgraphs = model->subgraphs();
+ _buffers = model->buffers();
+
+ auto opcodes = model->operator_codes();
+ for (const ::circle::OperatorCode *opcode : *opcodes)
+ {
+ _op_codes.push_back(opcode);
+ }
+}
+
+bool CircleImport::select_sub_graph(uint32_t sgindex)
+{
+ _tensors = nullptr;
+ _operators = nullptr;
+ _inputs.clear();
+ _outputs.clear();
+
+ if (_subgraphs->Length() <= sgindex)
+ {
+ assert(false);
+ return false;
+ }
+
+ const circle::SubGraph *subgraph = (*_subgraphs)[sgindex];
+
+ _tensors = subgraph->tensors();
+ _operators = subgraph->operators();
+
+ _inputs = as_index_vector(subgraph->inputs());
+ _outputs = as_index_vector(subgraph->outputs());
+
+ return true;
+}
+
+circle::BuiltinOperator CircleImport::builtin_code(const circle::Operator *op) const
+{
+ uint32_t index = op->opcode_index();
+ assert(index < _op_codes.size());
+ const circle::OperatorCode *opcode = _op_codes.at(index);
+
+ return opcode->builtin_code();
+}
+
+std::string CircleImport::opcode_name(const circle::Operator *op) const
+{
+ uint32_t index = op->opcode_index();
+ assert(index < _op_codes.size());
+ const circle::OperatorCode *opcode = _op_codes.at(index);
+
+ if (!is_valid(opcode))
+ {
+ std::ostringstream oss;
+ oss << "(invalid: " << index << ")";
+ return oss.str();
+ }
+
+ if (is_custom(opcode))
+ {
+ if (!opcode->custom_code())
+ return "(invalid custom)";
+
+ return opcode->custom_code()->c_str();
+ }
+
+ circle::BuiltinOperator code = opcode->builtin_code();
+ return EnumNameBuiltinOperator(code);
+}
+
+size_t CircleImport::buffer_info(const circle::Tensor *tensor, const uint8_t **buff_data)
+{
+ *buff_data = nullptr;
+
+ if (tensor->buffer() == 0)
+ return 0;
+
+ if (auto *buffer = (*_buffers)[tensor->buffer()])
+ {
+ if (auto *array = buffer->data())
+ {
+ if (size_t size = array->size())
+ {
+ *buff_data = reinterpret_cast<const uint8_t *>(array->data());
+ return size;
+ }
+ }
+ }
+
+ return 0;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/CircleImport.h b/compiler/circlechef/circle/src/CircleImport.h
new file mode 100644
index 000000000..a8ef3ee44
--- /dev/null
+++ b/compiler/circlechef/circle/src/CircleImport.h
@@ -0,0 +1,140 @@
+/*
+ * 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 __CIRCLE_IMPORT_H__
+#define __CIRCLE_IMPORT_H__
+
+#include <mio/circle/schema_generated.h>
+
+#include <circlechef.pb.h>
+
+#include <map>
+#include <vector>
+
+namespace circlechef
+{
+
+using CircleSubGraphs_t = flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>>;
+using CircleTensors_t = flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>>;
+using CircleBuffers_t = flatbuffers::Vector<flatbuffers::Offset<circle::Buffer>>;
+using CircleOperators_t = flatbuffers::Vector<flatbuffers::Offset<circle::Operator>>;
+
+const char *tensor_type(const circle::Tensor *tensor);
+const char *tensor_name(const circle::Tensor *tensor);
+bool is_valid(const circle::OperatorCode *opcode);
+bool is_custom(const circle::OperatorCode *opcode);
+
+/**
+ * @brief Loads TF lite file and provides helpers to access attributes
+ */
+class CircleImport
+{
+public:
+ CircleImport(const circle::Model *model);
+
+ CircleImport() = delete;
+
+public:
+ bool select_sub_graph(uint32_t subgraph);
+
+public:
+ const CircleBuffers_t *buffers() { return _buffers; }
+ const CircleTensors_t *tensors() { return _tensors; }
+ const CircleOperators_t *operators() { return _operators; }
+ const std::vector<int32_t> &inputs() const { return _inputs; }
+ const std::vector<int32_t> &outputs() const { return _outputs; }
+
+ uint32_t num_subgraph() const { return _subgraphs->Length(); }
+
+ circle::BuiltinOperator builtin_code(const circle::Operator *op) const;
+ std::string opcode_name(const circle::Operator *op) const;
+ size_t buffer_info(const circle::Tensor *tensor, const uint8_t **buff_data);
+
+ /**
+ * @brief This will record the tensor by index, if it needs filler option,
+ * such as kernel, bias.
+ */
+ void set_tensor_filler(uint32_t tensor_index) { _tensor_filler[tensor_index] = true; }
+
+ /**
+ * @brief This will store int32 filler values such as reshape information for the tensor
+ */
+ void set_tensor_filler(uint32_t tensor_index, std::vector<int32_t> &expvalues)
+ {
+ _tensor_filler_vint32[tensor_index] = expvalues;
+ }
+
+ void set_tensor_filler(uint32_t tensor_index, std::vector<float> &expvalues)
+ {
+ _tensor_filler_vfloat[tensor_index] = expvalues;
+ }
+
+ /**
+ * @brief This will return true if the tensor by index, needs a filler option.
+ */
+ bool get_tensor_filler(uint32_t tensor_index)
+ {
+ auto it = _tensor_filler.find(tensor_index);
+ if (it != _tensor_filler.end())
+ {
+ return it->second;
+ }
+ return false;
+ }
+
+ /**
+ * @brief This will return true if the tensor by index, needs a int array filler option.
+ */
+ bool get_tensor_filler(uint32_t tensor_index, std::vector<int32_t> &expvalues)
+ {
+ auto it = _tensor_filler_vint32.find(tensor_index);
+ if (it != _tensor_filler_vint32.end())
+ {
+ expvalues = it->second;
+ return true;
+ }
+ return false;
+ }
+
+ bool get_tensor_filler(uint32_t tensor_index, std::vector<float> &expvalues)
+ {
+ auto it = _tensor_filler_vfloat.find(tensor_index);
+ if (it != _tensor_filler_vfloat.end())
+ {
+ expvalues = it->second;
+ return true;
+ }
+ return false;
+ }
+
+private:
+ const CircleSubGraphs_t *_subgraphs{nullptr};
+ const CircleBuffers_t *_buffers{nullptr};
+ const CircleTensors_t *_tensors{nullptr};
+ const CircleOperators_t *_operators{nullptr};
+
+ std::vector<const circle::OperatorCode *> _op_codes{};
+ std::vector<int32_t> _inputs{};
+ std::vector<int32_t> _outputs{};
+
+ std::map<uint32_t, bool> _tensor_filler{};
+ std::map<uint32_t, std::vector<int32_t>> _tensor_filler_vint32{};
+ std::map<uint32_t, std::vector<float>> _tensor_filler_vfloat{};
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_IMPORT_H__
diff --git a/compiler/circlechef/circle/src/CircleOpChef.h b/compiler/circlechef/circle/src/CircleOpChef.h
new file mode 100644
index 000000000..a3bcd97d4
--- /dev/null
+++ b/compiler/circlechef/circle/src/CircleOpChef.h
@@ -0,0 +1,44 @@
+/*
+ * 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 __CIRCLE_OP_CHEF_H__
+#define __CIRCLE_OP_CHEF_H__
+
+#include <mio/circle/schema_generated.h>
+
+#include <circlechef.pb.h>
+
+#include "CircleImport.h"
+
+namespace circlechef
+{
+
+/**
+ * @brief Interface for each operators to build circlechef
+ */
+class CircleOpChef
+{
+public:
+ virtual void filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const = 0;
+ virtual ::circlechef::Operation *build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const = 0;
+ virtual ~CircleOpChef() {}
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_CHEF_H__
diff --git a/compiler/circlechef/circle/src/CircleOpChefs.h b/compiler/circlechef/circle/src/CircleOpChefs.h
new file mode 100644
index 000000000..6a0ce5dc3
--- /dev/null
+++ b/compiler/circlechef/circle/src/CircleOpChefs.h
@@ -0,0 +1,26 @@
+/*
+ * 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 __CIRCLE_OP_CHEFS_H__
+#define __CIRCLE_OP_CHEFS_H__
+
+// In alphabet order
+#include "Op/BatchMatMul.h"
+#include "Op/BCQFullyConnected.h"
+#include "Op/BCQGather.h"
+#include "Op/InstanceNorm.h"
+
+#endif // __CIRCLE_OP_CHEFS_H__
diff --git a/compiler/circlechef/circle/src/CircleOpRegistry.h b/compiler/circlechef/circle/src/CircleOpRegistry.h
new file mode 100644
index 000000000..2bf1e19ed
--- /dev/null
+++ b/compiler/circlechef/circle/src/CircleOpRegistry.h
@@ -0,0 +1,71 @@
+/*
+ * 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 __CIRCLE_OP_REGISTRY_H__
+#define __CIRCLE_OP_REGISTRY_H__
+
+#include "CircleOpChef.h"
+#include "CircleOpChefs.h"
+
+#include <memory>
+
+namespace circlechef
+{
+
+/**
+ * @brief circlechef operator registry
+ */
+class CircleOpRegistry
+{
+public:
+ /**
+ * @brief Returns registered CircleOpChef pointer for BuiltinOperator or
+ * nullptr if not registered
+ */
+ const CircleOpChef *lookup(circle::BuiltinOperator op) const
+ {
+ if (_circleop_map.find(op) == _circleop_map.end())
+ return nullptr;
+
+ return _circleop_map.at(op).get();
+ }
+
+ static CircleOpRegistry &get()
+ {
+ static CircleOpRegistry me;
+ return me;
+ }
+
+private:
+ CircleOpRegistry()
+ {
+#define REG_TFL_OP(OPCODE, CLASS) \
+ _circleop_map[circle::BuiltinOperator_##OPCODE] = std::make_unique<CLASS>()
+
+ REG_TFL_OP(BATCH_MATMUL, CircleOpBatchMatMul);
+ REG_TFL_OP(BCQ_FULLY_CONNECTED, CircleOpBCQFullyConnected);
+ REG_TFL_OP(BCQ_GATHER, CircleOpBCQGather);
+ REG_TFL_OP(INSTANCE_NORM, CircleOpInstanceNorm);
+#undef REG_TFL_OP
+ }
+
+private:
+ std::map<circle::BuiltinOperator, std::unique_ptr<CircleOpChef>> _circleop_map;
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_REGISTRY_H__
diff --git a/compiler/circlechef/circle/src/Convert.cpp b/compiler/circlechef/circle/src/Convert.cpp
new file mode 100644
index 000000000..77614d9b5
--- /dev/null
+++ b/compiler/circlechef/circle/src/Convert.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "Convert.h"
+
+namespace circlechef
+{
+
+circlechef::TensorType as_circlechef_type(const circle::TensorType type)
+{
+ switch (type)
+ {
+ case circle::TensorType_FLOAT32:
+ return circlechef::FLOAT32;
+ case circle::TensorType_INT32:
+ return circlechef::INT32;
+ case circle::TensorType_INT64:
+ return circlechef::INT64;
+ case circle::TensorType_UINT8:
+ return circlechef::UINT8;
+ case circle::TensorType_BOOL:
+ return circlechef::BOOL;
+ // TODO handle other types
+ // TensorType_FLOAT16
+ // TensorType_STRING
+ // TensorType_INT16
+ // TensorType_COMPLEX64
+ default:
+ throw std::runtime_error{"unsupported tensor type"};
+ }
+}
+
+circlechef::Activation as_circlechef_activation(const circle::ActivationFunctionType type)
+{
+ switch (type)
+ {
+ case circle::ActivationFunctionType_NONE:
+ return circlechef::NONE;
+ case circle::ActivationFunctionType_RELU:
+ return circlechef::RELU;
+ case circle::ActivationFunctionType_RELU6:
+ return circlechef::RELU6;
+ // TODO handle other types
+ // ActivationFunctionType_RELU_N1_TO_1
+ // ActivationFunctionType_TANH
+ // ActivationFunctionType_SIGN_BIT
+ default:
+ throw std::runtime_error{"unsupported activation type"};
+ }
+}
+
+circlechef::Padding as_circlechef_padding(const circle::Padding padding)
+{
+ switch (padding)
+ {
+ case circle::Padding_SAME:
+ return circlechef::SAME;
+ case circle::Padding_VALID:
+ return circlechef::VALID;
+ default:
+ throw std::runtime_error{"unsupported padding"};
+ }
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/Convert.h b/compiler/circlechef/circle/src/Convert.h
new file mode 100644
index 000000000..7842c4b01
--- /dev/null
+++ b/compiler/circlechef/circle/src/Convert.h
@@ -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.
+ */
+
+#ifndef __CONVERT_H__
+#define __CONVERT_H__
+
+#include <mio/circle/schema_generated.h>
+
+#include <circlechef.pb.h>
+
+namespace circlechef
+{
+
+circlechef::TensorType as_circlechef_type(const circle::TensorType type);
+circlechef::Activation as_circlechef_activation(const circle::ActivationFunctionType type);
+circlechef::Padding as_circlechef_padding(const circle::Padding padding);
+
+/**
+ * @brief extract buffer data to std::vector<DT>
+ */
+template <typename DT> std::vector<DT> extract_buffer(const circle::Buffer *buffer)
+{
+ auto buffer_length = buffer->data()->size();
+ auto num_elements = buffer_length / sizeof(DT);
+ std::vector<DT> result(num_elements);
+ std::memcpy(result.data(), buffer->data()->data(), buffer_length);
+ return result;
+}
+
+template <typename T> std::vector<T> as_index_vector(const flatbuffers::Vector<T> *flat_array)
+{
+ if (flat_array == nullptr)
+ throw std::runtime_error("flat_array is nullptr");
+
+ std::vector<T> ret(flat_array->Length());
+ for (uint32_t i = 0; i < flat_array->Length(); i++)
+ {
+ ret[i] = flat_array->Get(i);
+ }
+ return ret;
+}
+
+} // namespace circlechef
+
+#endif // __CONVERT_H__
diff --git a/compiler/circlechef/circle/src/Op/BCQFullyConnected.cpp b/compiler/circlechef/circle/src/Op/BCQFullyConnected.cpp
new file mode 100644
index 000000000..0e85f3969
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BCQFullyConnected.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "BCQFullyConnected.h"
+
+#include "Convert.h"
+
+namespace circlechef
+{
+
+void CircleOpBCQFullyConnected::filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ const std::vector<int32_t> &inputs = as_index_vector(op->inputs());
+
+ import->set_tensor_filler(inputs[1]);
+ import->set_tensor_filler(inputs[3]);
+
+ const circle::Tensor *tensor2 = import->tensors()->Get(inputs[2]);
+ assert(tensor2->type() == circle::TensorType::TensorType_INT32);
+ const circle::Buffer *buffer2 = import->buffers()->Get(tensor2->buffer());
+ auto vec2 = extract_buffer<int32_t>(buffer2);
+ import->set_tensor_filler(inputs[2], vec2);
+
+ const circle::Tensor *tensor4 = import->tensors()->Get(inputs[4]);
+ assert(tensor4->type() == circle::TensorType::TensorType_INT32);
+ const circle::Buffer *buffer4 = import->buffers()->Get(tensor4->buffer());
+ auto vec4 = extract_buffer<int32_t>(buffer4);
+ import->set_tensor_filler(inputs[4], vec4);
+}
+
+circlechef::Operation *CircleOpBCQFullyConnected::build(const circle::Operator *op,
+ CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ auto op_params = op->builtin_options_as_BCQFullyConnectedOptions();
+ assert(op_params != nullptr);
+
+ auto operation = model_recipe->add_operation();
+
+ operation->set_type("BCQFullyConnected");
+
+ auto op_options = operation->mutable_bcq_fully_connected_options();
+
+ op_options->set_weights_hidden_size(op_params->weights_hidden_size());
+ op_options->set_activation(as_circlechef_activation(op_params->fused_activation_function()));
+
+ return operation;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/Op/BCQFullyConnected.h b/compiler/circlechef/circle/src/Op/BCQFullyConnected.h
new file mode 100644
index 000000000..c0ea581d9
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BCQFullyConnected.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __CIRCLE_OP_BCQFULLYCONNECTED_H__
+#define __CIRCLE_OP_BCQFULLYCONNECTED_H__
+
+#include "CircleOpChef.h"
+
+namespace circlechef
+{
+
+/**
+ * @brief circlechef operator builder for BCQFullyConnected
+ */
+class CircleOpBCQFullyConnected : public CircleOpChef
+{
+public:
+ void filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+ circlechef::Operation *build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_BCQFULLYCONNECTED_H__
diff --git a/compiler/circlechef/circle/src/Op/BCQGather.cpp b/compiler/circlechef/circle/src/Op/BCQGather.cpp
new file mode 100644
index 000000000..cde345a34
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BCQGather.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "BCQGather.h"
+
+#include "Convert.h"
+
+namespace circlechef
+{
+
+void CircleOpBCQGather::filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ const std::vector<int32_t> &inputs = as_index_vector(op->inputs());
+
+ import->set_tensor_filler(inputs[0]);
+
+ const circle::Tensor *tensor1 = import->tensors()->Get(inputs[1]);
+ assert(tensor1->type() == circle::TensorType::TensorType_INT32);
+ const circle::Buffer *buffer1 = import->buffers()->Get(tensor1->buffer());
+ auto vec1 = extract_buffer<int32_t>(buffer1);
+ import->set_tensor_filler(inputs[1], vec1);
+
+ const circle::Tensor *tensor2 = import->tensors()->Get(inputs[2]);
+ assert(tensor2->type() == circle::TensorType::TensorType_INT32);
+ const circle::Buffer *buffer2 = import->buffers()->Get(tensor2->buffer());
+ auto vec2 = extract_buffer<int32_t>(buffer2);
+ import->set_tensor_filler(inputs[2], vec2);
+
+ const circle::Tensor *tensor3 = import->tensors()->Get(inputs[3]);
+ assert(tensor3->type() == circle::TensorType::TensorType_INT32);
+ const circle::Buffer *buffer3 = import->buffers()->Get(tensor3->buffer());
+ auto vec3 = extract_buffer<int32_t>(buffer3);
+ import->set_tensor_filler(inputs[3], vec3);
+}
+
+circlechef::Operation *CircleOpBCQGather::build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ auto op_params = op->builtin_options_as_BCQGatherOptions();
+ assert(op_params != nullptr);
+
+ auto operation = model_recipe->add_operation();
+
+ operation->set_type("BCQGather");
+
+ auto op_options = operation->mutable_bcq_gather_options();
+
+ op_options->set_input_hidden_size(op_params->input_hidden_size());
+ op_options->set_axis(op_params->axis());
+
+ return operation;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/Op/BCQGather.h b/compiler/circlechef/circle/src/Op/BCQGather.h
new file mode 100644
index 000000000..0ff040551
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BCQGather.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __CIRCLE_OP_BCQGATHER_H__
+#define __CIRCLE_OP_BCQGATHER_H__
+
+#include "CircleOpChef.h"
+
+namespace circlechef
+{
+
+/**
+ * @brief circlechef operator builder for BCQGather
+ */
+class CircleOpBCQGather : public CircleOpChef
+{
+public:
+ void filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+ circlechef::Operation *build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_BCQGATHER_H__
diff --git a/compiler/circlechef/circle/src/Op/BatchMatMul.cpp b/compiler/circlechef/circle/src/Op/BatchMatMul.cpp
new file mode 100644
index 000000000..bcf218865
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BatchMatMul.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "BatchMatMul.h"
+
+#include "Convert.h"
+
+namespace circlechef
+{
+
+void CircleOpBatchMatMul::filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ // Nothing to do with filler
+}
+
+circlechef::Operation *CircleOpBatchMatMul::build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ auto op_params = op->builtin_options_as_BatchMatMulOptions();
+ assert(op_params != nullptr);
+
+ auto operation = model_recipe->add_operation();
+
+ operation->set_type("BatchMatMul");
+
+ auto op_options = operation->mutable_batch_matmul_options();
+
+ op_options->set_adjoint_lhs(op_params->adjoint_lhs());
+ op_options->set_adjoint_rhs(op_params->adjoint_rhs());
+
+ return operation;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/Op/BatchMatMul.h b/compiler/circlechef/circle/src/Op/BatchMatMul.h
new file mode 100644
index 000000000..3d4036877
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/BatchMatMul.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __CIRCLE_OP_BATCHMATMUL_H__
+#define __CIRCLE_OP_BATCHMATMUL_H__
+
+#include "CircleOpChef.h"
+
+namespace circlechef
+{
+
+/**
+ * @brief circlechef operator builder for batchmatmul
+ */
+class CircleOpBatchMatMul : public CircleOpChef
+{
+public:
+ void filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+ circlechef::Operation *build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_BATCHMATMUL_H__
diff --git a/compiler/circlechef/circle/src/Op/InstanceNorm.cpp b/compiler/circlechef/circle/src/Op/InstanceNorm.cpp
new file mode 100644
index 000000000..a1395a578
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/InstanceNorm.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "InstanceNorm.h"
+
+#include "Convert.h"
+
+namespace circlechef
+{
+
+void CircleOpInstanceNorm::filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ // index 1 and 2 maybe constant
+ const std::vector<int32_t> &inputs = as_index_vector(op->inputs());
+ assert(inputs.size() == 3);
+
+ import->set_tensor_filler(inputs[1]); // set gaussian filler
+ import->set_tensor_filler(inputs[2]);
+}
+
+circlechef::Operation *CircleOpInstanceNorm::build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const
+{
+ auto operation = model_recipe->add_operation();
+
+ operation->set_type("InstanceNorm");
+
+ auto op_options = operation->mutable_instance_norm_options();
+
+ auto op_params = op->builtin_options_as_InstanceNormOptions();
+ assert(op_params != nullptr);
+
+ op_options->set_epsilon(op_params->epsilon());
+ op_options->set_activation(as_circlechef_activation(op_params->fused_activation_function()));
+
+ return operation;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/circle/src/Op/InstanceNorm.h b/compiler/circlechef/circle/src/Op/InstanceNorm.h
new file mode 100644
index 000000000..9cb48e184
--- /dev/null
+++ b/compiler/circlechef/circle/src/Op/InstanceNorm.h
@@ -0,0 +1,39 @@
+/*
+ * 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 __CIRCLE_OP_INSTANCE_NORM_H__
+#define __CIRCLE_OP_INSTANCE_NORM_H__
+
+#include "CircleOpChef.h"
+
+namespace circlechef
+{
+
+/**
+ * @brief circlechef operator builder for INSTANCE_NORM
+ */
+class CircleOpInstanceNorm : public CircleOpChef
+{
+public:
+ void filler(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+ circlechef::Operation *build(const circle::Operator *op, CircleImport *import,
+ circlechef::ModelRecipe *model_recipe) const override;
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLE_OP_INSTANCE_NORM_H__
diff --git a/compiler/circlechef/circle/src/RecipeChef.cpp b/compiler/circlechef/circle/src/RecipeChef.cpp
new file mode 100644
index 000000000..17ef1be6e
--- /dev/null
+++ b/compiler/circlechef/circle/src/RecipeChef.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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 <circlechef/RecipeChef.h>
+
+#include "Convert.h"
+#include "CircleImport.h"
+#include "CircleOpChef.h"
+#include "CircleOpChefs.h"
+#include "CircleOpRegistry.h"
+
+#include <fstream>
+#include <sstream>
+
+namespace circlechef
+{
+
+void set_inputs(CircleImport *import, circlechef::Operation *operation, const circle::Operator *op)
+{
+ auto tensors = import->tensors();
+ const std::vector<int32_t> &inputs = as_index_vector(op->inputs());
+
+ for (auto input : inputs)
+ {
+ if (input == -1)
+ {
+ operation->add_input("");
+ }
+ else
+ {
+ auto tensor = tensors->Get(input);
+ std::string name = tensor_name(tensor);
+ operation->add_input(name);
+ }
+ }
+}
+
+void set_outputs(CircleImport *import, circlechef::Operation *operation, const circle::Operator *op)
+{
+ auto tensors = import->tensors();
+ const std::vector<int32_t> &outputs = as_index_vector(op->outputs());
+
+ for (auto output : outputs)
+ {
+ auto tensor = tensors->Get(output);
+ std::string name = tensor_name(tensor);
+ operation->add_output(name);
+ }
+}
+
+/**
+ * @brief This will build ModelRecipe from circle::Model
+ * First to check operand filler options by scanning all operators,
+ * then translate all operands and operators.
+ * Last will set network inputs and outputs.
+ */
+std::unique_ptr<ModelRecipe> generate_recipe(const circle::Model *model)
+{
+ std::unique_ptr<ModelRecipe> model_recipe{new ModelRecipe()};
+
+ CircleImport circle_import(model);
+
+ assert(circle_import.num_subgraph() == 1);
+ circle_import.select_sub_graph(0);
+
+ auto tensors = circle_import.tensors();
+ auto buffers = circle_import.buffers();
+ auto operators = circle_import.operators();
+
+ // operand fillers for adding all operators
+ for (uint32_t i = 0; i < operators->Length(); ++i)
+ {
+ const auto *op = operators->Get(i);
+ circle::BuiltinOperator builtincode = circle_import.builtin_code(op);
+
+ if (const auto *graph_builder = CircleOpRegistry::get().lookup(builtincode))
+ {
+ graph_builder->filler(op, &circle_import, model_recipe.get());
+ }
+ else
+ {
+ std::string opcodename = circle_import.opcode_name(op);
+ throw std::runtime_error{"Not supported: " + opcodename};
+ }
+ }
+
+ // add all operands(tensors)
+ for (uint32_t i = 0; i < tensors->Length(); ++i)
+ {
+ auto tensor = tensors->Get(i);
+
+ // check buffer
+ if (tensor->buffer() >= buffers->size())
+ throw std::runtime_error{"file load failed"};
+
+ ::circlechef::Operand *operand = model_recipe->add_operand();
+
+ operand->set_name(tensor_name(tensor));
+ operand->set_type(as_circlechef_type(tensor->type()));
+
+ std::vector<int32_t> dims = as_index_vector(tensor->shape());
+ ::circlechef::TensorShape *shape = operand->mutable_shape();
+ for (auto dim : dims)
+ {
+ shape->add_dim(dim);
+ }
+
+ // filler for weights, bias and so on
+ std::vector<int32_t> expvalues;
+ std::vector<float> expfvalues;
+ if (circle_import.get_tensor_filler(i))
+ {
+ circlechef::TensorFiller *filler = operand->mutable_filler();
+ // Note: it is OK to use random weights for functionality validation
+ filler->set_tag("gaussian");
+ filler->add_arg("0.0"); // average
+ filler->add_arg("0.1"); // standard deviation
+ }
+ else if (circle_import.get_tensor_filler(i, expvalues))
+ {
+ circlechef::TensorFiller *filler = operand->mutable_filler();
+ filler->set_tag("explicit");
+ for (auto value : expvalues)
+ {
+ std::ostringstream ss;
+ ss << value;
+ filler->add_arg(ss.str());
+ }
+ }
+ else if (circle_import.get_tensor_filler(i, expfvalues))
+ {
+ circlechef::TensorFiller *filler = operand->mutable_filler();
+ filler->set_tag("explicit");
+ for (auto value : expfvalues)
+ {
+ std::ostringstream ss;
+ ss << value;
+ filler->add_arg(ss.str());
+ }
+ }
+
+ auto quant = tensor->quantization();
+ if (quant != nullptr)
+ {
+ // Note: Calling 'operand->mutable_quant()' will create empty 'quant' node
+ // in the recipe file. We want this only when valid parameter exist.
+ if (quant->min() != nullptr && quant->min()->size() > 0)
+ {
+ circlechef::TensorQuantization *chef_quant = operand->mutable_quant();
+ for (uint32_t idx = 0; idx < quant->min()->size(); ++idx)
+ chef_quant->add_min(quant->min()->Get(idx));
+ }
+ if (quant->max() != nullptr && quant->max()->size() > 0)
+ {
+ circlechef::TensorQuantization *chef_quant = operand->mutable_quant();
+ for (uint32_t idx = 0; idx < quant->max()->size(); idx++)
+ chef_quant->add_max(quant->max()->Get(idx));
+ }
+ if (quant->scale() != nullptr && quant->scale()->size() > 0)
+ {
+ circlechef::TensorQuantization *chef_quant = operand->mutable_quant();
+ for (uint32_t idx = 0; idx < quant->scale()->size(); ++idx)
+ chef_quant->add_scale(quant->scale()->Get(idx));
+ }
+ if (quant->zero_point() != nullptr && quant->zero_point()->size() > 0)
+ {
+ circlechef::TensorQuantization *chef_quant = operand->mutable_quant();
+ for (uint32_t idx = 0; idx < quant->zero_point()->size(); ++idx)
+ chef_quant->add_zero_point(quant->zero_point()->Get(idx));
+ }
+ }
+ }
+
+ // add all operators
+ for (uint32_t i = 0; i < operators->Length(); ++i)
+ {
+ const auto *op = operators->Get(i);
+ circle::BuiltinOperator builtincode = circle_import.builtin_code(op);
+
+ if (const auto *graph_builder = CircleOpRegistry::get().lookup(builtincode))
+ {
+ auto operation = graph_builder->build(op, &circle_import, model_recipe.get());
+
+ // common for all operators: inputs, outputs
+ set_inputs(&circle_import, operation, op);
+ set_outputs(&circle_import, operation, op);
+ }
+ else
+ {
+ std::string opcodename = circle_import.opcode_name(op);
+ throw std::runtime_error{"Not supported: " + opcodename};
+ }
+ }
+
+ // network inputs/outputs
+ const std::vector<int32_t> &inputs = circle_import.inputs();
+ const std::vector<int32_t> &outputs = circle_import.outputs();
+
+ for (const auto input : inputs)
+ {
+ auto tensor = tensors->Get(input);
+ std::string name = tensor_name(tensor);
+
+ model_recipe->add_input(name);
+ }
+ for (const auto output : outputs)
+ {
+ auto tensor = tensors->Get(output);
+ std::string name = tensor_name(tensor);
+
+ model_recipe->add_output(name);
+ }
+
+ return std::move(model_recipe);
+}
+
+bool write_recipe(const std::string &filename, std::unique_ptr<ModelRecipe> &recipe)
+{
+ std::fstream fo(filename, std::ios::binary | std::ios::out);
+
+ if (!fo.is_open())
+ {
+ throw std::runtime_error{"file store failed"};
+ }
+
+ // Note: SerializeToString() or SerializeToOstream() writes in binary mode
+ // DebugString() and Utf8DebugString() will print as a human readable text
+ fo << recipe->Utf8DebugString();
+
+ fo.close();
+
+ return true;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/core/CMakeLists.txt b/compiler/circlechef/core/CMakeLists.txt
new file mode 100644
index 000000000..54b3ea53d
--- /dev/null
+++ b/compiler/circlechef/core/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(circlechef_core STATIC ${SOURCES})
+target_include_directories(circlechef_core PUBLIC include)
+target_include_directories(circlechef_core PRIVATE src)
+target_link_libraries(circlechef_core circlechef_proto)
+target_link_libraries(circlechef_core circlechef_log)
+target_link_libraries(circlechef_core mio_circle)
+target_link_libraries(circlechef_core souschef)
diff --git a/compiler/circlechef/core/include/circlechef/ModelChef.h b/compiler/circlechef/core/include/circlechef/ModelChef.h
new file mode 100644
index 000000000..64326179c
--- /dev/null
+++ b/compiler/circlechef/core/include/circlechef/ModelChef.h
@@ -0,0 +1,56 @@
+/*
+ * 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 __MODEL_CHEF_H__
+#define __MODEL_CHEF_H__
+
+#include <circlechef.pb.h>
+
+#include <memory>
+
+namespace circlechef
+{
+
+class GeneratedModel final
+{
+public:
+ struct Impl
+ {
+ virtual ~Impl() = default;
+
+ virtual const char *base(void) const = 0;
+ virtual size_t size(void) const = 0;
+ };
+
+public:
+ GeneratedModel(std::unique_ptr<Impl> &&impl) : _impl{std::move(impl)}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const char *base(void) const { return _impl->base(); }
+ size_t size(void) const { return _impl->size(); }
+
+private:
+ std::unique_ptr<Impl> _impl;
+};
+
+GeneratedModel cook(const ModelRecipe &model_recipe);
+
+} // namespace circlechef
+
+#endif // __MODEL_CHEF_H__
diff --git a/compiler/circlechef/core/src/Arguments.h b/compiler/circlechef/core/src/Arguments.h
new file mode 100644
index 000000000..9fe7bbb77
--- /dev/null
+++ b/compiler/circlechef/core/src/Arguments.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ARGUMENTS_H__
+#define __ARGUMENTS_H__
+
+#include <cstdint>
+#include <string>
+
+/**
+ * @brief Read-only string sequence view
+ */
+struct Arguments
+{
+ virtual ~Arguments() = default;
+
+ virtual uint32_t count(void) const = 0;
+ virtual const std::string &value(uint32_t n) const = 0;
+};
+
+#endif // __ARGUMENTS_H__
diff --git a/compiler/circlechef/core/src/Convert.cpp b/compiler/circlechef/core/src/Convert.cpp
new file mode 100644
index 000000000..2db0a6212
--- /dev/null
+++ b/compiler/circlechef/core/src/Convert.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 "Convert.h"
+
+#include <stdexcept>
+
+circle::Padding as_circle_padding(const circlechef::Padding &value)
+{
+ switch (value)
+ {
+ case circlechef::SAME:
+ return circle::Padding_SAME;
+ case circlechef::VALID:
+ return circle::Padding_VALID;
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"Unknown padding value"};
+}
+
+circle::ActivationFunctionType as_circle_activation(const circlechef::Activation &value)
+{
+ switch (value)
+ {
+ case circlechef::NONE:
+ return circle::ActivationFunctionType_NONE;
+ case circlechef::RELU:
+ return circle::ActivationFunctionType_RELU;
+ case circlechef::RELU6:
+ return circle::ActivationFunctionType_RELU6;
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"Unknown activation"};
+}
+
+circle::TensorType as_circle_tensortype(const circlechef::TensorType &value)
+{
+ switch (value)
+ {
+ case circlechef::FLOAT32:
+ return circle::TensorType_FLOAT32;
+ case circlechef::INT32:
+ return circle::TensorType_INT32;
+ case circlechef::UINT8:
+ return circle::TensorType_UINT8;
+ case circlechef::INT64:
+ return circle::TensorType_INT64;
+ case circlechef::BOOL:
+ return circle::TensorType_BOOL;
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"Unknown tensor type"};
+}
diff --git a/compiler/circlechef/core/src/Convert.h b/compiler/circlechef/core/src/Convert.h
new file mode 100644
index 000000000..766098da2
--- /dev/null
+++ b/compiler/circlechef/core/src/Convert.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file Convert.h
+ * @brief This header declares various as_circle_TYPE functions
+ */
+#ifndef __CONVERT_H__
+#define __CONVERT_H__
+
+#include <circlechef.pb.h>
+#include <mio/circle/schema_generated.h>
+
+circle::Padding as_circle_padding(const circlechef::Padding &value);
+circle::ActivationFunctionType as_circle_activation(const circlechef::Activation &value);
+circle::TensorType as_circle_tensortype(const circlechef::TensorType &value);
+
+#endif // __CONVERT_H__
diff --git a/compiler/circlechef/core/src/ModelChef.cpp b/compiler/circlechef/core/src/ModelChef.cpp
new file mode 100644
index 000000000..76aeacdd9
--- /dev/null
+++ b/compiler/circlechef/core/src/ModelChef.cpp
@@ -0,0 +1,631 @@
+/*
+ * 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 "circlechef/ModelChef.h"
+#include <souschef/RangedArguments.h>
+#include <souschef/Registry.h>
+
+#include "Convert.h"
+
+#include <souschef/DataChefs.h>
+
+#include "OpChef.h"
+#include "OpChefs.h"
+
+#include <souschef/Dataset.h>
+
+#include "Log.h"
+
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <numeric>
+#include <sstream>
+#include <stdexcept>
+
+namespace
+{
+
+using namespace souschef;
+
+template <typename T> std::vector<T> as_vector(const ::google::protobuf::RepeatedPtrField<T> &field)
+{
+ std::vector<T> res;
+ for (const auto &elem : field)
+ {
+ res.emplace_back(elem);
+ }
+ return res;
+}
+
+template <typename T> Dataset<T> as_dataset(const ::google::protobuf::RepeatedPtrField<T> &field)
+{
+ return Dataset<T>(as_vector<T>(field));
+}
+
+} // namespace
+
+namespace
+{
+
+template <typename T> using Dims = std::vector<T>;
+
+Dims<int32_t> as_dims(const circlechef::TensorShape &shape)
+{
+ std::vector<int32_t> res;
+
+ for (auto &dim : shape.dim())
+ {
+ res.emplace_back(static_cast<int32_t>(dim));
+ }
+
+ return res;
+}
+
+int32_t element_count(const Dims<int32_t> &dims)
+{
+ return std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<int32_t>());
+}
+
+} // namespace
+
+namespace
+{
+
+class GeneratedModelImpl final : public circlechef::GeneratedModel::Impl
+{
+public:
+ GeneratedModelImpl(std::unique_ptr<flatbuffers::FlatBufferBuilder> &&builder)
+ : _builder{std::move(builder)}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const char *base(void) const override
+ {
+ // Return the base address of generated flatbuffer model
+ return reinterpret_cast<const char *>(_builder->GetBufferPointer());
+ }
+
+public:
+ size_t size(void) const override
+ {
+ // Return the size of generated flatbuffer model
+ return _builder->GetSize();
+ }
+
+private:
+ std::unique_ptr<flatbuffers::FlatBufferBuilder> _builder;
+};
+
+} // namespace
+
+namespace
+{
+
+struct DataChefRegistry final : public Registry<DataChefFactory>
+{
+};
+
+DataChefRegistry &data_chef_registry(const circlechef::TensorType &type)
+{
+ static DataChefRegistry s32;
+ static DataChefRegistry s64;
+ static DataChefRegistry fp32;
+ static DataChefRegistry u8;
+ static DataChefRegistry boolean;
+
+ switch (type)
+ {
+ case circlechef::INT32:
+ return s32;
+ case circlechef::INT64:
+ return s64;
+ case circlechef::FLOAT32:
+ return fp32;
+ case circlechef::UINT8:
+ return u8;
+ case circlechef::BOOL:
+ return boolean;
+ default:
+ break;
+ }
+
+ throw std::runtime_error{"Unknown tensor type"};
+}
+
+struct OpChefRegistry final : public Registry<OpChefFactory>
+{
+};
+
+OpChefRegistry &op_chef_registry(void)
+{
+ static OpChefRegistry registry;
+ return registry;
+}
+
+/// @brief This will prepare a map of unique builtin codes in the model recipe
+std::map<circle::BuiltinOperator, int32_t>
+gather_builtincode_map(const ::circlechef::ModelRecipe &model_recipe)
+{
+ // Key and value of the map are BuiltinOperator and operator version
+ std::map<circle::BuiltinOperator, int32_t> builtin_map;
+
+ for (const auto &operation : model_recipe.operation())
+ {
+ auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
+ if (op_chef->code() == circle::BuiltinOperator_CUSTOM)
+ continue;
+
+ // Various operation version is unified as the highest version among them
+ if (builtin_map.find(op_chef->code()) == builtin_map.end() ||
+ builtin_map[op_chef->code()] < operation.version())
+ builtin_map[op_chef->code()] = operation.version();
+ }
+
+ // Add ops used in Graphs(subgraphs)
+ for (int g = 0; g < model_recipe.graph_size(); ++g)
+ {
+ const auto &graph = model_recipe.graph(g);
+ for (const auto &operation : graph.operation())
+ {
+ auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
+ if (op_chef->code() == circle::BuiltinOperator_CUSTOM)
+ continue;
+
+ // Various operation version is unified as the highest version among them
+ if (builtin_map.find(op_chef->code()) == builtin_map.end() ||
+ builtin_map[op_chef->code()] < operation.version())
+ builtin_map[op_chef->code()] = operation.version();
+ }
+ }
+
+ return builtin_map;
+}
+
+/// @brief This will prepare a set of unique custom codes in the mode recipe
+std::set<std::string> gather_customcode_set(const ::circlechef::ModelRecipe &model_recipe)
+{
+ std::set<std::string> customcode_set;
+ for (const auto &operation : model_recipe.operation())
+ {
+ auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
+ if (op_chef->code() == circle::BuiltinOperator_CUSTOM)
+ customcode_set.insert(operation.type());
+ }
+
+ // Add ops used in Graphs(subgraphs)
+ for (int g = 0; g < model_recipe.graph_size(); ++g)
+ {
+ const auto &graph = model_recipe.graph(g);
+ for (const auto &operation : graph.operation())
+ {
+ auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
+ if (op_chef->code() == circle::BuiltinOperator_CUSTOM)
+ customcode_set.insert(operation.type());
+ }
+ }
+
+ return customcode_set;
+}
+
+} // namespace
+
+namespace
+{
+
+struct CookParams
+{
+ std::vector<flatbuffers::Offset<::circle::Buffer>> &buffer_vec;
+ std::vector<flatbuffers::Offset<::circle::OperatorCode>> &code_vec;
+ std::vector<flatbuffers::Offset<::circle::SubGraph>> &subgraph_vec;
+ std::unique_ptr<flatbuffers::FlatBufferBuilder> &flatbuffer_builder;
+ std::map<circle::BuiltinOperator, int32_t> &builtin_code_map;
+ std::string noname;
+};
+
+template <typename T> void cook_graph(const T &graph, CookParams &cp)
+{
+ LOGGER(l);
+
+ std::vector<flatbuffers::Offset<::circle::Buffer>> &buffer_vec = cp.buffer_vec;
+ std::vector<flatbuffers::Offset<::circle::OperatorCode>> &code_vec = cp.code_vec;
+ std::vector<flatbuffers::Offset<::circle::SubGraph>> &subgraph_vec = cp.subgraph_vec;
+ std::unique_ptr<flatbuffers::FlatBufferBuilder> &flatbuffer_builder = cp.flatbuffer_builder;
+ std::map<circle::BuiltinOperator, int32_t> &builtin_code_map = cp.builtin_code_map;
+
+ // Operand-related
+ std::vector<flatbuffers::Offset<::circle::Tensor>> tensor_vec;
+
+ // Operation-related
+ std::vector<flatbuffers::Offset<::circle::Operator>> operator_vec;
+
+ // default name for graph
+ std::string graph_name = cp.noname;
+ if (graph.has_name())
+ graph_name = graph.name();
+
+ // Tensor Name -> Tensor ID mapping (per Graph)
+ std::map<std::string, int32_t> symbol_table;
+
+ auto lookup = [&symbol_table, &graph_name](const std::string &name) {
+ if (symbol_table.find(name) != symbol_table.end())
+ return symbol_table.at(name);
+ else if (name == "")
+ return -1; // -1 in circle means that optional input tensor is empty.
+ else
+ {
+ std::string msg = "circlechef : input not found in " + graph_name + " graph";
+ throw std::runtime_error(msg.c_str());
+ }
+ };
+
+ int32_t buffer_start = buffer_vec.size();
+ int32_t buffer_index = 0;
+
+ // Create buffer(s) 1~n(I) for input(s)
+ const auto size_input = graph.input_size();
+ for (int ci = 0; ci < size_input; ++ci)
+ {
+ circle::BufferBuilder buffer_builder{*flatbuffer_builder};
+ buffer_vec.emplace_back(buffer_builder.Finish());
+ }
+ // Create buffer(s) n(I)+1~n(I)+n(O) for output(s)
+ const auto size_output = graph.output_size();
+ for (int co = 0; co < size_output; ++co)
+ {
+ circle::BufferBuilder buffer_builder{*flatbuffer_builder};
+ buffer_vec.emplace_back(buffer_builder.Finish());
+ }
+
+ auto input_names = as_dataset(graph.input()).vectorize();
+ auto output_names = as_dataset(graph.output()).vectorize();
+
+ for (const auto &operand : graph.operand())
+ {
+ assert(operand.has_name());
+
+ assert(operand.has_type());
+
+ flatbuffers::Offset<flatbuffers::Vector<int32_t>> shape;
+ std::vector<int32_t> dims;
+ if (operand.has_shape())
+ {
+ dims = as_dims(operand.shape());
+ shape = flatbuffer_builder->CreateVector(dims);
+ }
+
+ auto name = flatbuffer_builder->CreateString(operand.name());
+
+ buffer_index = 0;
+
+ // Create Buffer if filler is specified
+ if (operand.has_filler())
+ {
+ const auto &filler = operand.filler();
+
+ assert(filler.has_tag());
+
+ auto args = ranged_arguments(filler.arg().begin(), filler.arg().end());
+ auto chef = data_chef_registry(operand.type()).lookup(filler.tag()).create(args);
+
+ assert(chef != nullptr);
+
+ // Create Data
+ int32_t count = (element_count(dims) > 0) ? element_count(dims) : filler.arg_size();
+ auto data_vec = chef->generate(count);
+ auto data = flatbuffer_builder->CreateVector(data_vec);
+
+ // Create Buffer
+ circle::BufferBuilder buffer_builder{*flatbuffer_builder};
+ buffer_builder.add_data(data);
+ auto buffer = buffer_builder.Finish();
+
+ // Update Buffer Index & Vector
+ buffer_index = buffer_vec.size();
+ buffer_vec.emplace_back(buffer);
+ }
+ else
+ {
+ // if this is input or output, assign to that buffer_index
+ int idx = 0;
+ for (auto it = input_names.begin(); it != input_names.end(); ++it, ++idx)
+ {
+ if (*it == operand.name())
+ {
+ buffer_index = buffer_start + idx;
+ break;
+ }
+ }
+ if (buffer_index == 0)
+ {
+ idx = 0;
+ for (auto it = output_names.begin(); it != output_names.end(); ++it, ++idx)
+ {
+ if (*it == operand.name())
+ {
+ buffer_index = buffer_start + size_input + idx;
+ break;
+ }
+ }
+ }
+ if (buffer_index == 0)
+ {
+ // we couldn't find the buffer; create an empty buffer for this tensor
+ buffer_index = buffer_vec.size();
+
+ circle::BufferBuilder buffer_builder{*flatbuffer_builder};
+ buffer_vec.emplace_back(buffer_builder.Finish());
+ }
+ }
+ assert(buffer_index != 0);
+
+ flatbuffers::Offset<circle::QuantizationParameters> quant_index;
+
+ // Create QuantizationParameters if quant is specified
+ if (operand.has_quant())
+ {
+ const auto &quant = operand.quant();
+
+ // Create each parameters
+ // NOTE if some parameters are not given, those will be set to default value
+ std::vector<float> quant_max_vec(quant.max_size());
+ std::vector<float> quant_min_vec(quant.min_size());
+ std::vector<float> quant_scale_vec(quant.scale_size());
+ std::vector<int64_t> quant_zero_point_vec(quant.zero_point_size());
+
+ for (uint32_t i = 0; i < quant.max_size(); ++i)
+ quant_max_vec.at(i) = quant.max(i);
+ for (uint32_t i = 0; i < quant.min_size(); ++i)
+ quant_min_vec.at(i) = quant.min(i);
+ for (uint32_t i = 0; i < quant.scale_size(); ++i)
+ quant_scale_vec.at(i) = quant.scale(i);
+ for (uint32_t i = 0; i < quant.zero_point_size(); ++i)
+ quant_zero_point_vec.at(i) = quant.zero_point(i);
+
+ auto quant_max = flatbuffer_builder->CreateVector(quant_max_vec);
+ auto quant_min = flatbuffer_builder->CreateVector(quant_min_vec);
+ auto quant_scale = flatbuffer_builder->CreateVector(quant_scale_vec);
+ auto quant_zero_point = flatbuffer_builder->CreateVector(quant_zero_point_vec);
+
+ // Create QuantizationParameters
+ circle::QuantizationParametersBuilder quant_builder{*flatbuffer_builder};
+ quant_builder.add_max(quant_max);
+ quant_builder.add_min(quant_min);
+ quant_builder.add_scale(quant_scale);
+ quant_builder.add_zero_point(quant_zero_point);
+
+ // Update QuantizationParameters Index
+ quant_index = quant_builder.Finish();
+ }
+
+ // Create Tensor
+ circle::TensorBuilder tensor_builder{*flatbuffer_builder};
+
+ tensor_builder.add_shape(shape);
+ tensor_builder.add_type(as_circle_tensortype(operand.type()));
+ tensor_builder.add_buffer(buffer_index);
+ tensor_builder.add_name(name);
+ if (operand.has_quant())
+ tensor_builder.add_quantization(quant_index);
+
+ // Append!
+ tensor_vec.emplace_back(tensor_builder.Finish());
+
+ // Update Tensor Name -> Tensor Index Map
+ int32_t tensor_index = symbol_table.size();
+ const auto &tensor_name = operand.name();
+
+ INFO(l) << "Symbol [" << tensor_name << "] = Tensor " << tensor_index << std::endl;
+
+ symbol_table[tensor_name] = tensor_index;
+ }
+
+ // Create Operator
+ for (const auto &operation : graph.operation())
+ {
+ assert(operation.has_type());
+
+ auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
+
+ // Create 'inputs'
+ std::vector<int32_t> input_vec = as_dataset(operation.input()).map(lookup).vectorize();
+ auto inputs = flatbuffer_builder->CreateVector(input_vec);
+
+ // Create 'outputs'
+ std::vector<int32_t> output_vec = as_dataset(operation.output()).map(lookup).vectorize();
+ auto outputs = flatbuffer_builder->CreateVector(output_vec);
+
+ // Create Option
+ auto options = op_chef->value(*flatbuffer_builder);
+
+ // Create Custom option
+ auto circle_custom_options = op_chef->custom_value(*flatbuffer_builder);
+
+ // Create Operator
+ circle::OperatorBuilder op_builder{*flatbuffer_builder};
+
+ // Get operator code index from builtin_code_map with assumption, order of
+ // builtin_code_map is same as that of code_vec
+ auto op_it = builtin_code_map.find(op_chef->code());
+ assert(op_it != builtin_code_map.end());
+ uint32_t opcode_index = std::distance(builtin_code_map.begin(), op_it);
+
+ op_builder.add_opcode_index(opcode_index);
+ op_builder.add_inputs(inputs);
+ op_builder.add_outputs(outputs);
+ op_builder.add_builtin_options_type(op_chef->type());
+ op_builder.add_builtin_options(options);
+ op_builder.add_custom_options(circle_custom_options);
+ op_builder.add_custom_options_format(circle::CustomOptionsFormat_FLEXBUFFERS);
+ // Append Operator
+ operator_vec.emplace_back(op_builder.Finish());
+ }
+
+ // Create network input/output vector
+ std::vector<int32_t> input_vec = as_dataset(graph.input()).map(lookup).vectorize();
+ std::vector<int32_t> output_vec = as_dataset(graph.output()).map(lookup).vectorize();
+
+ // Create "SubGraph" arguments
+ auto tensors = flatbuffer_builder->CreateVector(tensor_vec);
+ auto inputs = flatbuffer_builder->CreateVector(input_vec);
+ auto outputs = flatbuffer_builder->CreateVector(output_vec);
+ auto operators = flatbuffer_builder->CreateVector(operator_vec);
+ auto name = flatbuffer_builder->CreateString(graph_name);
+
+ circle::SubGraphBuilder subgraph_builder{*flatbuffer_builder};
+
+ subgraph_builder.add_tensors(tensors);
+ subgraph_builder.add_inputs(inputs);
+ subgraph_builder.add_outputs(outputs);
+ subgraph_builder.add_operators(operators);
+ subgraph_builder.add_name(name);
+
+ subgraph_vec.emplace_back(subgraph_builder.Finish());
+}
+
+} // namespace
+
+namespace circlechef
+{
+
+/**
+ * @brief Generate a (in-memory) TensorFlow Lite model from a given model recipe
+ */
+GeneratedModel cook(const ::circlechef::ModelRecipe &model_recipe)
+{
+// Initialize Op Chef Registry
+#define OP_CHEF(NAME, FACTORY_CLASS) \
+ op_chef_registry().add(#NAME, std::unique_ptr<FACTORY_CLASS>(new FACTORY_CLASS()));
+#include "OpChef.def"
+#undef OP_CHEF
+
+// Initialize Data Chef Registry
+#define DATA_CHEF(TYPE, NAME, FACTORY_CLASS) \
+ data_chef_registry(::circlechef::TYPE) \
+ .add(#NAME, std::unique_ptr<FACTORY_CLASS>(new FACTORY_CLASS()));
+#include <souschef/DataChef.def>
+#undef DATA_CHEF
+
+ //
+ // Create FlatBufferBuilder
+ //
+ auto flatbuffer_builder =
+ std::unique_ptr<flatbuffers::FlatBufferBuilder>(new flatbuffers::FlatBufferBuilder(1024));
+
+ // Operand-related
+ std::vector<flatbuffers::Offset<::circle::Buffer>> buffer_vec;
+
+ // Operation-related
+ std::vector<flatbuffers::Offset<::circle::OperatorCode>> code_vec;
+
+ // Graphs-related
+ std::vector<flatbuffers::Offset<::circle::SubGraph>> subgraph_vec;
+
+ // Create OperatorCode with Builtin Operator
+ std::map<circle::BuiltinOperator, int32_t> builtin_code_map =
+ gather_builtincode_map(model_recipe);
+ for (auto const &opcode : builtin_code_map)
+ {
+ circle::OperatorCodeBuilder code_builder{*flatbuffer_builder};
+ code_builder.add_builtin_code(opcode.first);
+ code_builder.add_version(opcode.second);
+ auto code = code_builder.Finish();
+ // Update OperatorCode vector
+ code_vec.emplace_back(code);
+ }
+
+ // Create OperatorCode with Custom Operator
+ std::set<std::string> custom_code_set = gather_customcode_set(model_recipe);
+ if (custom_code_set.size() &&
+ builtin_code_map.find(circle::BuiltinOperator_CUSTOM) == builtin_code_map.end())
+ builtin_code_map[circle::BuiltinOperator_CUSTOM] = 1;
+
+ for (auto opcode : custom_code_set)
+ {
+ auto custom_code = flatbuffer_builder->CreateString(opcode);
+ circle::OperatorCodeBuilder code_builder{*flatbuffer_builder};
+ code_builder.add_builtin_code(circle::BuiltinOperator_CUSTOM);
+ code_builder.add_custom_code(custom_code);
+ auto code = code_builder.Finish();
+ // Update OperatorCode vector
+ code_vec.emplace_back(code);
+ }
+
+ // Create an Empty Buffer
+ //
+ // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file
+ // (Please refer to the comment for Tensor.buffer field in schema)
+ {
+ circle::BufferBuilder buffer_builder{*flatbuffer_builder};
+ buffer_vec.emplace_back(buffer_builder.Finish());
+ }
+
+ //
+ // Create Main graph
+ //
+ CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, builtin_code_map, "main"};
+
+ cook_graph<::circlechef::ModelRecipe>(model_recipe, cp);
+
+ //
+ // Create subgraphs if exist
+ //
+ for (int g = 0; g < model_recipe.graph_size(); ++g)
+ {
+ const auto &graph = model_recipe.graph(g);
+
+ std::ostringstream stringStream;
+ stringStream << "sub_" << (g + 1);
+
+ CookParams cp{buffer_vec, code_vec, subgraph_vec,
+ flatbuffer_builder, builtin_code_map, stringStream.str()};
+
+ cook_graph<::circlechef::Graph>(graph, cp);
+ }
+
+ // Create "Model" arguments
+ auto buffers = flatbuffer_builder->CreateVector(buffer_vec);
+ auto operator_codes = flatbuffer_builder->CreateVector(code_vec);
+ auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec);
+ auto description = flatbuffer_builder->CreateString("Generated by circlechef");
+
+ // Create "Model"
+ circle::ModelBuilder model_builder{*flatbuffer_builder};
+
+ model_builder.add_version(3);
+ model_builder.add_operator_codes(operator_codes);
+ model_builder.add_subgraphs(subgraphs);
+ model_builder.add_description(description);
+ model_builder.add_buffers(buffers);
+
+ auto model = model_builder.Finish();
+
+ // Finalize
+ ::circle::FinishModelBuffer(*flatbuffer_builder, model);
+
+ // Return "GenerateModel"
+ return GeneratedModel{
+ std::unique_ptr<GeneratedModelImpl>(new GeneratedModelImpl(std::move(flatbuffer_builder)))};
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/core/src/Op/BCQFullyConnected.cpp b/compiler/circlechef/core/src/Op/BCQFullyConnected.cpp
new file mode 100644
index 000000000..4c82c52cc
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BCQFullyConnected.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "BCQFullyConnected.h"
+
+#include "Convert.h"
+
+flatbuffers::Offset<void> BCQFullyConnectedChef::value(flatbuffers::FlatBufferBuilder &fbb) const
+{
+ auto &operation = (*_operation);
+
+ assert(operation.has_bcq_fully_connected_options());
+
+ circle::BCQFullyConnectedOptionsBuilder bcq_fully_connected_options_builder{fbb};
+ bcq_fully_connected_options_builder.add_weights_hidden_size(
+ operation.bcq_fully_connected_options().weights_hidden_size());
+ bcq_fully_connected_options_builder.add_fused_activation_function(
+ as_circle_activation(operation.bcq_fully_connected_options().activation()));
+
+ return bcq_fully_connected_options_builder.Finish().Union();
+}
+
+std::unique_ptr<OpChef>
+BCQFullyConnectedChefFactory::create(const circlechef::Operation *operation) const
+{
+ return std::unique_ptr<OpChef>{new BCQFullyConnectedChef{operation}};
+}
diff --git a/compiler/circlechef/core/src/Op/BCQFullyConnected.h b/compiler/circlechef/core/src/Op/BCQFullyConnected.h
new file mode 100644
index 000000000..41e6b53d5
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BCQFullyConnected.h
@@ -0,0 +1,52 @@
+/*
+ * 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 __OP_BCQFULLYCONNECTED_H__
+#define __OP_BCQFULLYCONNECTED_H__
+
+#include "OpChef.h"
+
+class BCQFullyConnectedChef final : public OpChef
+{
+public:
+ explicit BCQFullyConnectedChef(const circlechef::Operation *operation) : _operation{operation}
+ {
+ // DO NOTHING
+ }
+
+public:
+ circle::BuiltinOperator code(void) const override
+ {
+ return circle::BuiltinOperator_BCQ_FULLY_CONNECTED;
+ }
+
+ circle::BuiltinOptions type(void) const override
+ {
+ return circle::BuiltinOptions_BCQFullyConnectedOptions;
+ }
+
+ flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override;
+
+private:
+ const circlechef::Operation *_operation;
+};
+
+struct BCQFullyConnectedChefFactory final : public OpChefFactory
+{
+ std::unique_ptr<OpChef> create(const circlechef::Operation *operation) const override;
+};
+
+#endif // __OP_BCQFULLYCONNECTED_H__
diff --git a/compiler/circlechef/core/src/Op/BCQGather.cpp b/compiler/circlechef/core/src/Op/BCQGather.cpp
new file mode 100644
index 000000000..08f6f611f
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BCQGather.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "BCQGather.h"
+
+flatbuffers::Offset<void> BCQGatherChef::value(flatbuffers::FlatBufferBuilder &fbb) const
+{
+ auto &operation = (*_operation);
+
+ assert(operation.has_bcq_gather_options());
+
+ circle::BCQGatherOptionsBuilder bcq_gather_options_builder{fbb};
+ bcq_gather_options_builder.add_input_hidden_size(
+ operation.bcq_gather_options().input_hidden_size());
+ bcq_gather_options_builder.add_axis(operation.bcq_gather_options().axis());
+
+ return bcq_gather_options_builder.Finish().Union();
+}
+
+std::unique_ptr<OpChef> BCQGatherChefFactory::create(const circlechef::Operation *operation) const
+{
+ return std::unique_ptr<OpChef>{new BCQGatherChef{operation}};
+}
diff --git a/compiler/circlechef/core/src/Op/BCQGather.h b/compiler/circlechef/core/src/Op/BCQGather.h
new file mode 100644
index 000000000..24a797a41
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BCQGather.h
@@ -0,0 +1,49 @@
+/*
+ * 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 __OP_BCQGATHER_H__
+#define __OP_BCQGATHER_H__
+
+#include "OpChef.h"
+
+class BCQGatherChef final : public OpChef
+{
+public:
+ explicit BCQGatherChef(const circlechef::Operation *operation) : _operation{operation}
+ {
+ // DO NOTHING
+ }
+
+public:
+ circle::BuiltinOperator code(void) const override { return circle::BuiltinOperator_BCQ_GATHER; }
+
+ circle::BuiltinOptions type(void) const override
+ {
+ return circle::BuiltinOptions_BCQGatherOptions;
+ }
+
+ flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override;
+
+private:
+ const circlechef::Operation *_operation;
+};
+
+struct BCQGatherChefFactory final : public OpChefFactory
+{
+ std::unique_ptr<OpChef> create(const circlechef::Operation *operation) const override;
+};
+
+#endif // __OP_BCQGATHER_H__
diff --git a/compiler/circlechef/core/src/Op/BatchMatMul.cpp b/compiler/circlechef/core/src/Op/BatchMatMul.cpp
new file mode 100644
index 000000000..d98c0801a
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BatchMatMul.cpp
@@ -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.
+ */
+
+#include "BatchMatMul.h"
+
+flatbuffers::Offset<void> BatchMatMulChef::value(flatbuffers::FlatBufferBuilder &fbb) const
+{
+ auto &operation = (*_operation);
+
+ assert(operation.has_batch_matmul_options());
+
+ circle::BatchMatMulOptionsBuilder batch_matmul_options_options_builder{fbb};
+ batch_matmul_options_options_builder.add_adjoint_lhs(
+ operation.batch_matmul_options().adjoint_lhs());
+ batch_matmul_options_options_builder.add_adjoint_rhs(
+ operation.batch_matmul_options().adjoint_rhs());
+
+ return batch_matmul_options_options_builder.Finish().Union();
+}
+
+std::unique_ptr<OpChef> BatchMatMulChefFactory::create(const circlechef::Operation *operation) const
+{
+ return std::unique_ptr<OpChef>{new BatchMatMulChef{operation}};
+}
diff --git a/compiler/circlechef/core/src/Op/BatchMatMul.h b/compiler/circlechef/core/src/Op/BatchMatMul.h
new file mode 100644
index 000000000..fbb411eff
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/BatchMatMul.h
@@ -0,0 +1,49 @@
+/*
+ * 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 __OP_BATCH_MATMUL_H__
+#define __OP_BATCH_MATMUL_H__
+
+#include "OpChef.h"
+
+class BatchMatMulChef final : public OpChef
+{
+public:
+ explicit BatchMatMulChef(const circlechef::Operation *operation) : _operation{operation}
+ {
+ // DO NOTHING
+ }
+
+public:
+ circle::BuiltinOperator code(void) const override { return circle::BuiltinOperator_BATCH_MATMUL; }
+
+ circle::BuiltinOptions type(void) const override
+ {
+ return circle::BuiltinOptions_BatchMatMulOptions;
+ }
+
+ flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override;
+
+private:
+ const circlechef::Operation *_operation;
+};
+
+struct BatchMatMulChefFactory final : public OpChefFactory
+{
+ std::unique_ptr<OpChef> create(const circlechef::Operation *operation) const override;
+};
+
+#endif // __OP_BATCH_MATMUL_H__
diff --git a/compiler/circlechef/core/src/Op/InstanceNorm.cpp b/compiler/circlechef/core/src/Op/InstanceNorm.cpp
new file mode 100644
index 000000000..115eceffc
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/InstanceNorm.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "InstanceNorm.h"
+
+#include "Convert.h"
+
+flatbuffers::Offset<void> InstanceNormChef::value(flatbuffers::FlatBufferBuilder &fbb) const
+{
+ auto &operation = (*_operation);
+
+ assert(operation.has_instance_norm_options());
+ auto circle_activation = as_circle_activation(operation.instance_norm_options().activation());
+
+ circle::InstanceNormOptionsBuilder options_builder{fbb};
+ options_builder.add_epsilon(operation.instance_norm_options().epsilon());
+ options_builder.add_fused_activation_function(circle_activation);
+
+ return options_builder.Finish().Union();
+}
+
+std::unique_ptr<OpChef>
+InstanceNormChefFactory::create(const circlechef::Operation *operation) const
+{
+ return std::unique_ptr<OpChef>{new InstanceNormChef{operation}};
+}
diff --git a/compiler/circlechef/core/src/Op/InstanceNorm.h b/compiler/circlechef/core/src/Op/InstanceNorm.h
new file mode 100644
index 000000000..f36b5d7b9
--- /dev/null
+++ b/compiler/circlechef/core/src/Op/InstanceNorm.h
@@ -0,0 +1,52 @@
+/*
+ * 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 __OP_INSTANCE_NORM_H__
+#define __OP_INSTANCE_NORM_H__
+
+#include "OpChef.h"
+
+class InstanceNormChef final : public OpChef
+{
+public:
+ explicit InstanceNormChef(const circlechef::Operation *operation) : _operation{operation}
+ {
+ // DO NOTHING
+ }
+
+public:
+ circle::BuiltinOperator code(void) const override
+ {
+ return circle::BuiltinOperator_INSTANCE_NORM;
+ }
+
+ circle::BuiltinOptions type(void) const override
+ {
+ return circle::BuiltinOptions_InstanceNormOptions;
+ }
+
+ flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override;
+
+private:
+ const circlechef::Operation *_operation;
+};
+
+struct InstanceNormChefFactory final : public OpChefFactory
+{
+ std::unique_ptr<OpChef> create(const circlechef::Operation *operation) const override;
+};
+
+#endif // __OP_INSTANCE_NORM_H__
diff --git a/compiler/circlechef/core/src/OpChef.def b/compiler/circlechef/core/src/OpChef.def
new file mode 100644
index 000000000..3128d3ba2
--- /dev/null
+++ b/compiler/circlechef/core/src/OpChef.def
@@ -0,0 +1,10 @@
+#ifndef OP_CHEF
+#error "Define OP first"
+#endif // OP_CHEF
+
+// Please keep the list in alphabetical order
+// OP_CHEF(NAME, FACTORY_CLASS)
+OP_CHEF(BatchMatMul, BatchMatMulChefFactory)
+OP_CHEF(BCQFullyConnected, BCQFullyConnectedChefFactory)
+OP_CHEF(BCQGather, BCQGatherChefFactory)
+OP_CHEF(InstanceNorm, InstanceNormChefFactory)
diff --git a/compiler/circlechef/core/src/OpChef.h b/compiler/circlechef/core/src/OpChef.h
new file mode 100644
index 000000000..3479e51ef
--- /dev/null
+++ b/compiler/circlechef/core/src/OpChef.h
@@ -0,0 +1,48 @@
+/*
+ * 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 __OP_CHEF_H__
+#define __OP_CHEF_H__
+
+#include <circlechef.pb.h>
+#include <mio/circle/schema_generated.h>
+
+#include <memory>
+
+struct OpChef
+{
+ virtual ~OpChef() = default;
+
+ virtual circle::BuiltinOperator code(void) const = 0;
+ virtual circle::BuiltinOptions type(void) const = 0;
+ virtual flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const = 0;
+
+ // TODO Find a way to place this method in a better place
+ virtual flatbuffers::Offset<flatbuffers::Vector<uint8_t>>
+ custom_value(flatbuffers::FlatBufferBuilder &fbb) const
+ {
+ return flatbuffers::Offset<flatbuffers::Vector<uint8_t>>();
+ }
+};
+
+struct OpChefFactory
+{
+ virtual ~OpChefFactory() = default;
+
+ virtual std::unique_ptr<OpChef> create(const circlechef::Operation *operation) const = 0;
+};
+
+#endif // __OP_CHEF_H__
diff --git a/compiler/circlechef/core/src/OpChefs.h b/compiler/circlechef/core/src/OpChefs.h
new file mode 100644
index 000000000..e13c5e0c6
--- /dev/null
+++ b/compiler/circlechef/core/src/OpChefs.h
@@ -0,0 +1,25 @@
+/*
+ * 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 __OP_CHEFS_H__
+#define __OP_CHEFS_H__
+
+#include "Op/BatchMatMul.h"
+#include "Op/BCQFullyConnected.h"
+#include "Op/BCQGather.h"
+#include "Op/InstanceNorm.h"
+
+#endif // __OP_CHEFS_H__
diff --git a/compiler/circlechef/log/CMakeLists.txt b/compiler/circlechef/log/CMakeLists.txt
new file mode 100644
index 000000000..6527ca7d8
--- /dev/null
+++ b/compiler/circlechef/log/CMakeLists.txt
@@ -0,0 +1,7 @@
+# TODO Find how to test logging framework
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+
+add_library(circlechef_log STATIC ${SOURCES})
+target_include_directories(circlechef_log PUBLIC include)
+target_link_libraries(circlechef_log PUBLIC hermes)
+target_link_libraries(circlechef_log PRIVATE hermes_std)
diff --git a/compiler/circlechef/log/include/Log.h b/compiler/circlechef/log/include/Log.h
new file mode 100644
index 000000000..ef00b26cc
--- /dev/null
+++ b/compiler/circlechef/log/include/Log.h
@@ -0,0 +1,75 @@
+/*
+ * 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 __CIRCLECHEF_LOG_H__
+#define __CIRCLECHEF_LOG_H__
+
+#include <hermes.h>
+
+namespace circlechef
+{
+
+/**
+ * @brief Logger Implementation
+ */
+class Logger final : public hermes::Source
+{
+public:
+ Logger(hermes::Context *ctx);
+ ~Logger();
+};
+
+/**
+ * @brief Logger Configuration
+ *
+ * Users are able to turn logging on/off via CIRCLECHEF_LOG environment variable.
+ */
+class LoggerConfig final : public hermes::Config
+{
+public:
+ LoggerConfig();
+
+public:
+ void configure(const hermes::Source *, hermes::Source::Setting &) const final;
+ void configure(const Logger *, hermes::Source::Setting &) const;
+
+private:
+ bool _enabled;
+};
+
+} // namespace circlechef
+
+#include "LoggingContext.h"
+
+/**
+ * HOW TO USE:
+ *
+ * LOGGER(l);
+ *
+ * INFO(l) << "Hello, World" << std::endl;
+ *
+ */
+#define LOGGER(name) ::circlechef::Logger name{::circlechef::LoggingContext::get()};
+
+// TODO Support FATAL, ERROR, WARN, and VERBOSE
+#define INFO(name) HERMES_INFO(name)
+
+// WARNING!
+//
+// THE CURRENT IMPLEMENTATION IS NOT THREAD SAFE.
+//
+
+#endif // __CIRCLECHEF_LOG_H__
diff --git a/compiler/circlechef/log/include/LoggingContext.h b/compiler/circlechef/log/include/LoggingContext.h
new file mode 100644
index 000000000..1282cfd45
--- /dev/null
+++ b/compiler/circlechef/log/include/LoggingContext.h
@@ -0,0 +1,35 @@
+/*
+ * 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 __CIRCLECHEF_LOGGING_CONTEXT_H__
+#define __CIRCLECHEF_LOGGING_CONTEXT_H__
+
+#include <hermes.h>
+
+namespace circlechef
+{
+
+/**
+ * @brief Global logging context
+ */
+struct LoggingContext
+{
+ static hermes::Context *get(void);
+};
+
+} // namespace circlechef
+
+#endif // __CIRCLECHEF_LOGGING_CONTEXT_H__
diff --git a/compiler/circlechef/log/src/Log.cpp b/compiler/circlechef/log/src/Log.cpp
new file mode 100644
index 000000000..11a60fb8d
--- /dev/null
+++ b/compiler/circlechef/log/src/Log.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 "Log.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+
+// TODO Extract these lexical conversion routines as a library
+namespace
+{
+
+/**
+ * @brief Convert C-string as a value of type T
+ *
+ * safecast(s, v) returns v if s is nullptr.
+ */
+template <typename T> T safecast(const char *, const T &);
+
+template <> bool safecast<bool>(const char *s, const bool &value)
+{
+ return (s == nullptr) ? value : (std::stoi(s) != 0);
+}
+
+} // namespace
+
+//
+// Logger
+//
+namespace circlechef
+{
+
+Logger::Logger(hermes::Context *ctx) { activate(ctx->sources(), ctx->bus()); }
+Logger::~Logger() { deactivate(); }
+
+} // namespace circlechef
+
+//
+// LoggerConfig
+//
+namespace circlechef
+{
+
+LoggerConfig::LoggerConfig()
+{
+ // Turn on logging if CIRCLECHEF_LOG is set as non-zero value
+ _enabled = safecast<bool>(std::getenv("CIRCLECHEF_LOG"), false);
+}
+
+void LoggerConfig::configure(const hermes::Source *source, hermes::Source::Setting &setting) const
+{
+ // Let's ignore hermes::Sources if that is not a moco logger
+ if (auto logger = dynamic_cast<const Logger *>(source))
+ {
+ configure(logger, setting);
+ }
+}
+
+void LoggerConfig::configure(const Logger *, hermes::Source::Setting &setting) const
+{
+ if (_enabled)
+ {
+ // Enable all catagories
+ setting.accept_all();
+ }
+ else
+ {
+ // Disable all catagories
+ setting.reject_all();
+ }
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/log/src/LoggingContext.cpp b/compiler/circlechef/log/src/LoggingContext.cpp
new file mode 100644
index 000000000..b64bd3f3d
--- /dev/null
+++ b/compiler/circlechef/log/src/LoggingContext.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "LoggingContext.h"
+#include "Log.h"
+
+#include <hermes/ConsoleReporter.h>
+
+#include <memory>
+
+namespace circlechef
+{
+
+hermes::Context *LoggingContext::get(void)
+{
+ static hermes::Context *ctx = nullptr;
+
+ if (ctx == nullptr)
+ {
+ ctx = new hermes::Context;
+ ctx->sinks()->append(std::make_unique<hermes::ConsoleReporter>());
+ ctx->config(std::make_unique<LoggerConfig>());
+ }
+
+ return ctx;
+}
+
+} // namespace circlechef
diff --git a/compiler/circlechef/proto/CMakeLists.txt b/compiler/circlechef/proto/CMakeLists.txt
new file mode 100644
index 000000000..3cc26de84
--- /dev/null
+++ b/compiler/circlechef/proto/CMakeLists.txt
@@ -0,0 +1,5 @@
+Protobuf_Generate(CIRCLECHEF_PROTO "${CMAKE_CURRENT_BINARY_DIR}/generated" "${CMAKE_CURRENT_SOURCE_DIR}" "circlechef.proto")
+
+add_library(circlechef_proto STATIC ${CIRCLECHEF_PROTO_SOURCES})
+target_include_directories(circlechef_proto PUBLIC ${CIRCLECHEF_PROTO_INCLUDE_DIRS})
+target_link_libraries(circlechef_proto libprotobuf)
diff --git a/compiler/circlechef/proto/circlechef.proto b/compiler/circlechef/proto/circlechef.proto
new file mode 100644
index 000000000..b8c009b38
--- /dev/null
+++ b/compiler/circlechef/proto/circlechef.proto
@@ -0,0 +1,110 @@
+syntax = "proto2";
+
+package circlechef;
+
+//
+// Initial version
+// - Our initial version
+//
+// Version 1
+// - Backward compatible with Initial version
+// - Added Graph to represent sub graphs
+// - Added name, version(default as 1), graph in ModelRecipe
+//
+
+// This enum value corresponds to TensorType in TensorFlow Lite schema
+enum TensorType {
+ FLOAT32 = 0;
+ INT32 = 2;
+ UINT8 = 3;
+ INT64 = 4;
+ BOOL = 6;
+}
+
+message TensorShape {
+ repeated uint32 dim = 3;
+}
+
+message TensorFiller {
+ optional string tag = 1;
+ repeated string arg = 2;
+}
+
+message TensorQuantization {
+ repeated float min = 1;
+ repeated float max = 2;
+ repeated float scale = 3;
+ repeated int64 zero_point = 4;
+}
+
+message Operand {
+ optional string name = 1;
+ optional TensorType type = 2;
+ optional TensorShape shape = 3;
+ optional TensorFiller filler = 4;
+ optional TensorQuantization quant = 5;
+}
+
+// This enum value corresponds to Padding in TensorFlow Lite schema
+enum Padding {
+ SAME = 0;
+ VALID = 1;
+}
+
+// This enum value corresponds to ActivationFunctionType in TensorFlow Lite schema
+enum Activation {
+ NONE = 0;
+ RELU = 1;
+ RELU6 = 3;
+}
+
+message BatchMatMulOptions {
+ optional bool adjoint_lhs = 1 [default = false];
+ optional bool adjoint_rhs = 2 [default = false];
+}
+
+message InstanceNormOptions {
+ optional float epsilon = 1 [default = 1e-05];
+ optional Activation activation = 2 [default = NONE];
+}
+
+message BCQFullyConnectedOptions {
+ optional int32 weights_hidden_size = 1 [default = 0];
+ optional Activation activation = 2 [default = NONE];
+}
+
+message BCQGatherOptions {
+ optional int32 input_hidden_size = 1 [default = 0];
+ optional int32 axis = 2 [default = 0];
+}
+
+message Operation {
+ optional string type = 1;
+ repeated string input = 2;
+ repeated string output = 3;
+ optional int32 version = 4 [default = 1];
+
+ optional BatchMatMulOptions batch_matmul_options = 100;
+ optional InstanceNormOptions instance_norm_options = 101;
+ optional BCQFullyConnectedOptions bcq_fully_connected_options = 102;
+ optional BCQGatherOptions bcq_gather_options = 103;
+}
+
+// For additional subgraphs
+message Graph {
+ repeated Operand operand = 1;
+ repeated Operation operation = 2;
+ repeated string input = 3;
+ repeated string output = 4;
+ optional string name = 5;
+}
+
+message ModelRecipe {
+ repeated Operand operand = 1;
+ repeated Operation operation = 2;
+ repeated string input = 3;
+ repeated string output = 4;
+ optional string name = 5;
+ optional uint32 version = 6 [default = 1];
+ repeated Graph graph = 7;
+}
diff --git a/compiler/circlechef/requires.cmake b/compiler/circlechef/requires.cmake
new file mode 100644
index 000000000..2106146d7
--- /dev/null
+++ b/compiler/circlechef/requires.cmake
@@ -0,0 +1,9 @@
+require("arser")
+require("nnkit")
+require("cwrap")
+require("mio-circle")
+require("safemain")
+require("hermes")
+require("hermes-std")
+require("foder")
+require("souschef")
diff --git a/compiler/circlechef/tests/CMakeLists.txt b/compiler/circlechef/tests/CMakeLists.txt
new file mode 100644
index 000000000..4dc58addf
--- /dev/null
+++ b/compiler/circlechef/tests/CMakeLists.txt
@@ -0,0 +1,70 @@
+nncc_find_resource(CircleRecipes)
+set(CIRCLERECIPES_DIR "${CircleRecipes_DIR}")
+
+file(GLOB RECIPES RELATIVE ${CIRCLERECIPES_DIR} "${CIRCLERECIPES_DIR}/*/test.recipe")
+
+foreach(RECIPE IN ITEMS ${RECIPES})
+ get_filename_component(RECIPE_PREFIX ${RECIPE} DIRECTORY)
+
+ set(RECIPE_SOURCE_FILE "${RECIPE_PREFIX}.recipe")
+ set(RECIPE_OUTPUT_FILE "${RECIPE_PREFIX}.circle")
+
+ # Copy .recipe
+ add_custom_command(OUTPUT ${RECIPE_SOURCE_FILE}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${CIRCLERECIPES_DIR}/${RECIPE}" ${RECIPE_SOURCE_FILE}
+ DEPENDS "${CIRCLERECIPES_DIR}/${RECIPE}"
+ COMMENT "Generating ${RECIPE_SOURCE_FILE}")
+
+ # Generate .circle
+ add_custom_command(OUTPUT ${RECIPE_OUTPUT_FILE}
+ COMMAND circlechef-file ${RECIPE_SOURCE_FILE} ${RECIPE_OUTPUT_FILE}
+ DEPENDS circlechef-file ${RECIPE_SOURCE_FILE}
+ COMMENT "Generating ${RECIPE_OUTPUT_FILE}")
+
+ list(APPEND TESTS ${RECIPE_PREFIX})
+ list(APPEND TESTFILES ${RECIPE_OUTPUT_FILE})
+endforeach(RECIPE)
+
+#Test circlechef-reverse
+file(GLOB GEN_CIRCLEFILES RELATIVE ${CIRCLERECIPES_DIR} "${CIRCLERECIPES_DIR}/*/test.reverse")
+# Note: While in development, circlechef-reverse may not handle the operator.
+# To separate this linkage scan empty test.reverse for test targets for circlechef-reverse.
+
+foreach(CIRCLEFILE IN ITEMS ${GEN_CIRCLEFILES})
+ get_filename_component(CIRCLE_PREFIX ${CIRCLEFILE} DIRECTORY)
+
+ # file from above circlechef-file block
+ # use circle file as input of circlechef-reverse generated from circlechef-file
+ set(RECIPE_OUTPUT_FILE "${CIRCLE_PREFIX}.circle")
+ set(RECIPE_GEN_OUTPUT_FILE "${CIRCLE_PREFIX}.gen.recipe")
+ set(RECIPE_GEN_OUTPUT_FILE2 "${CIRCLE_PREFIX}.gen.circle")
+
+ # Generate .gen.recipe from generated .circle
+ add_custom_command(OUTPUT ${RECIPE_GEN_OUTPUT_FILE}
+ COMMAND circlechef-reverse ${RECIPE_OUTPUT_FILE} ${RECIPE_GEN_OUTPUT_FILE}
+ DEPENDS circlechef-reverse ${RECIPE_OUTPUT_FILE}
+ COMMENT "Generating ${RECIPE_GEN_OUTPUT_FILE}")
+
+ # now we are going to generate .gen.circle from .gen.recipe
+ # to check generated .gen.recipe file is correct by using it.
+ # as weight values may be different, binary comparision is not acceptable.
+ add_custom_command(OUTPUT ${RECIPE_GEN_OUTPUT_FILE2}
+ COMMAND circlechef-file ${RECIPE_GEN_OUTPUT_FILE} ${RECIPE_GEN_OUTPUT_FILE2}
+ DEPENDS circlechef-file ${RECIPE_GEN_OUTPUT_FILE}
+ COMMENT "Generating ${RECIPE_GEN_OUTPUT_FILE2}")
+
+ list(APPEND TESTS ${CIRCLE_PREFIX}.gen)
+ list(APPEND TESTFILES ${RECIPE_GEN_OUTPUT_FILE2})
+endforeach(CIRCLEFILE)
+
+# Add a dummy target to create a target-level dependency.
+# TODO Find a way to create a dependency between circlechef_test and generated testfiles.
+add_custom_target(circlechef_testfiles ALL DEPENDS ${TESTFILES})
+
+# Using circle_verify for temporary as it only calls flatbuffer validate
+# TODO do testing with running the model with runtime/interpreter
+add_test(NAME circlechef_test
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/runvalidate.sh"
+ $<TARGET_FILE:circle-verify>
+ ${TESTS})
diff --git a/compiler/circlechef/tests/runvalidate.sh b/compiler/circlechef/tests/runvalidate.sh
new file mode 100755
index 000000000..46ad125ae
--- /dev/null
+++ b/compiler/circlechef/tests/runvalidate.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+if [[ $# -le 2 ]]; then
+ echo "USAGE: $0 [circle-verify path] [prefix 0] "
+ exit 255
+fi
+
+CIRCLE_VERIFY_PATH="$1"; shift
+
+echo "-- Found circle-verify: ${CIRCLE_VERIFY_PATH}"
+
+TESTED=()
+PASSED=()
+FAILED=()
+
+pushd "${WORKDIR}"
+while [[ $# -ne 0 ]]; do
+ PREFIX="$1"; shift
+
+ TESTED+=("${PREFIX}")
+
+ PASSED_TAG="${PREFIX}.passed"
+
+ rm -f "${PASSED_TAG}"
+
+ cat > "${PREFIX}.log" <(
+ exec 2>&1
+
+ echo "'${CIRCLE_VERIFY_PATH}' '${PREFIX}.circle'"
+ "${CIRCLE_VERIFY_PATH}" "${PREFIX}.circle"
+
+ if [[ $? -eq 0 ]]; then
+ touch "${PASSED_TAG}"
+ fi
+ )
+
+ if [[ -f "${PASSED_TAG}" ]]; then
+ PASSED+=("$PREFIX")
+ else
+ FAILED+=("$PREFIX")
+ fi
+done
+popd
+
+echo "SUMMARY: ${#PASSED[@]} PASS AND ${#FAILED[@]} FAIL AMONG ${#TESTED[@]} TESTS"
+
+if [[ ${#TESTED[@]} -ne ${#PASSED[@]} ]]; then
+ echo "FAILED"
+ for TEST in "${FAILED[@]}"
+ do
+ echo "- ${TEST}"
+ done
+ exit 255
+fi
+
+exit 0
diff --git a/compiler/circlechef/tools/CMakeLists.txt b/compiler/circlechef/tools/CMakeLists.txt
new file mode 100644
index 000000000..c958614b2
--- /dev/null
+++ b/compiler/circlechef/tools/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Console-based tool (circlechef)
+add_subdirectory(console)
+# File-based tool (circlechef-file)
+add_subdirectory(file)
+# Reverse tool to generate recipe from circle (circlechef-reverse)
+add_subdirectory(reverse)
diff --git a/compiler/circlechef/tools/console/CMakeLists.txt b/compiler/circlechef/tools/console/CMakeLists.txt
new file mode 100644
index 000000000..10168fca3
--- /dev/null
+++ b/compiler/circlechef/tools/console/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(circlechef Driver.cpp)
+target_link_libraries(circlechef circlechef_core)
+target_link_libraries(circlechef safemain)
diff --git a/compiler/circlechef/tools/console/Driver.cpp b/compiler/circlechef/tools/console/Driver.cpp
new file mode 100644
index 000000000..0909f5927
--- /dev/null
+++ b/compiler/circlechef/tools/console/Driver.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 "circlechef/ModelChef.h"
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <iostream>
+
+int entry(int argc, char **argv)
+{
+ int32_t model_version = 1;
+
+ ::circlechef::ModelRecipe model_recipe;
+
+ // Read a model recipe from standard input
+ {
+ google::protobuf::io::IstreamInputStream iis{&std::cin};
+ if (!google::protobuf::TextFormat::Parse(&iis, &model_recipe))
+ {
+ std::cerr << "ERROR: Failed to parse recipe" << std::endl;
+ return 255;
+ }
+
+ if (model_recipe.has_version())
+ {
+ model_version = model_recipe.version();
+ }
+ }
+
+ if (model_version > 1)
+ {
+ std::cerr << "ERROR: Unsupported recipe version: " << model_version << std::endl;
+ return 255;
+ }
+
+ auto generated_model = circlechef::cook(model_recipe);
+
+ // Write a generated model into standard output
+ std::cout.write(generated_model.base(), generated_model.size());
+
+ return 0;
+}
diff --git a/compiler/circlechef/tools/file/CMakeLists.txt b/compiler/circlechef/tools/file/CMakeLists.txt
new file mode 100644
index 000000000..2524a657c
--- /dev/null
+++ b/compiler/circlechef/tools/file/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(circlechef-file Driver.cpp)
+target_link_libraries(circlechef-file arser)
+target_link_libraries(circlechef-file circlechef_core)
+target_link_libraries(circlechef-file safemain)
diff --git a/compiler/circlechef/tools/file/Driver.cpp b/compiler/circlechef/tools/file/Driver.cpp
new file mode 100644
index 000000000..a15da4002
--- /dev/null
+++ b/compiler/circlechef/tools/file/Driver.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "circlechef/ModelChef.h"
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <arser/arser.h>
+
+#include <fstream>
+#include <iostream>
+
+int entry(int argc, char **argv)
+{
+ arser::Arser arser;
+ arser.add_argument("recipe")
+ .type(arser::DataType::STR)
+ .help("Source recipe file path to convert");
+ arser.add_argument("circle").type(arser::DataType::STR).help("Target circle file path");
+
+ try
+ {
+ arser.parse(argc, argv);
+ }
+ catch (const std::runtime_error &err)
+ {
+ std::cout << err.what() << std::endl;
+ std::cout << arser;
+ return 0;
+ }
+
+ int32_t model_version = 1;
+
+ ::circlechef::ModelRecipe model_recipe;
+
+ std::string recipe_path = arser.get<std::string>("recipe");
+ // Load model recipe from a file
+ {
+ std::ifstream is{recipe_path};
+ google::protobuf::io::IstreamInputStream iis{&is};
+ if (!google::protobuf::TextFormat::Parse(&iis, &model_recipe))
+ {
+ std::cerr << "ERROR: Failed to parse recipe '" << recipe_path << "'" << std::endl;
+ return 255;
+ }
+
+ if (model_recipe.has_version())
+ {
+ model_version = model_recipe.version();
+ }
+ }
+
+ if (model_version > 1)
+ {
+ std::cerr << "ERROR: Unsupported recipe version: " << model_version << ", '" << recipe_path
+ << "'" << std::endl;
+ return 255;
+ }
+
+ auto generated_model = circlechef::cook(model_recipe);
+
+ std::string circle_path = arser.get<std::string>("circle");
+ // Dump generated model into a file
+ {
+ std::ofstream os{circle_path, std::ios::binary};
+ os.write(generated_model.base(), generated_model.size());
+ }
+
+ return 0;
+}
diff --git a/compiler/circlechef/tools/reverse/CMakeLists.txt b/compiler/circlechef/tools/reverse/CMakeLists.txt
new file mode 100644
index 000000000..a1606c94e
--- /dev/null
+++ b/compiler/circlechef/tools/reverse/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(circlechef-reverse Driver.cpp)
+target_link_libraries(circlechef-reverse arser)
+target_link_libraries(circlechef-reverse circlechef_circle)
+target_link_libraries(circlechef-reverse safemain)
+target_link_libraries(circlechef-reverse foder)
diff --git a/compiler/circlechef/tools/reverse/Driver.cpp b/compiler/circlechef/tools/reverse/Driver.cpp
new file mode 100644
index 000000000..9c0b9ea24
--- /dev/null
+++ b/compiler/circlechef/tools/reverse/Driver.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 <circlechef/RecipeChef.h>
+
+#include <arser/arser.h>
+#include <foder/FileLoader.h>
+
+#include <memory>
+#include <iostream>
+
+int entry(int argc, char **argv)
+{
+ arser::Arser arser;
+ arser.add_argument("circle")
+ .type(arser::DataType::STR)
+ .help("Source circle file path to convert");
+ arser.add_argument("recipe").type(arser::DataType::STR).help("Target recipe file path");
+
+ try
+ {
+ arser.parse(argc, argv);
+ }
+ catch (const std::runtime_error &err)
+ {
+ std::cout << err.what() << std::endl;
+ std::cout << arser;
+ return 0;
+ }
+
+ std::string circle_path = arser.get<std::string>("circle");
+ // Load TF lite model from a circle file
+ const foder::FileLoader fileLoader{circle_path};
+ std::vector<char> modelData = fileLoader.load();
+ const circle::Model *circlemodel = circle::GetModel(modelData.data());
+ if (circlemodel == nullptr)
+ {
+ std::cerr << "ERROR: Failed to load circle '" << circle_path << "'" << std::endl;
+ return 255;
+ }
+
+ // Generate ModelRecipe recipe
+ std::unique_ptr<circlechef::ModelRecipe> recipe = circlechef::generate_recipe(circlemodel);
+ if (recipe.get() == nullptr)
+ {
+ std::cerr << "ERROR: Failed to generate recipe" << std::endl;
+ return 255;
+ }
+
+ std::string recipe_path = arser.get<std::string>("recipe");
+ // Save to a file
+ bool result = circlechef::write_recipe(recipe_path, recipe);
+ if (!result)
+ {
+ std::cerr << "ERROR: Failed to write to recipe '" << recipe_path << "'" << std::endl;
+ return 255;
+ }
+ return 0;
+}