diff options
author | Chunseok Lee <chunseok.lee@samsung.com> | 2020-08-14 15:19:19 +0900 |
---|---|---|
committer | Chunseok Lee <chunseok.lee@samsung.com> | 2020-08-14 15:19:19 +0900 |
commit | 042b262b3633b6c0f577aed6cb4b980ad0c1dcf3 (patch) | |
tree | e79fb9ffe65b21bdc5863306db2757ab187a3306 /compiler | |
parent | 05e0ec30a632339a8533082476f27bda31ccde16 (diff) | |
download | nnfw-042b262b3633b6c0f577aed6cb4b980ad0c1dcf3.tar.gz nnfw-042b262b3633b6c0f577aed6cb4b980ad0c1dcf3.tar.bz2 nnfw-042b262b3633b6c0f577aed6cb4b980ad0c1dcf3.zip |
Imported Upstream version 1.8.0upstream/1.8.0submit/tizen/20200814.062151
Diffstat (limited to 'compiler')
319 files changed, 5770 insertions, 1066 deletions
diff --git a/compiler/.ahub/tcchecker-tca/config.yaml b/compiler/.ahub/tcchecker-tca/config.yaml new file mode 100644 index 000000000..ef681de1a --- /dev/null +++ b/compiler/.ahub/tcchecker-tca/config.yaml @@ -0,0 +1,54 @@ +version: 2 +test: + - name: NN Compiler + testCaseLanguage: CPP + testFW: GTEST + testCaseFolder: + - ./angkor + - ./arser + - ./circle2circle + - ./circle-quantizer + - ./cwrap + - ./foder + - ./hermes + - ./hermes-std + - ./loco + - ./locomotiv + - ./locop + - ./logo + - ./logo-core + - ./luci + - ./luci-interpreter + - ./luci-value-test + - ./mio-circle + - ./mio-tflite + - ./oops + - ./pepper-assert + - ./pepper-str + - ./pepper-strcast + - ./pp + - ./record-minmax + - ./safemain + - ./souschef + - ./stdex + - ./tflite2circle + + testFile: + - extension: .test.cpp + any: true + + testCase: + - condition: + - functionName: + starts: + - TEST + + negativeTestCase: + - condition: + - testName: + ends: + - _NEG + + positiveTestCase: + - condition: + - inverse: negativeTestCase diff --git a/compiler/bcq-tools/CMakeLists.txt b/compiler/bcq-tools/CMakeLists.txt new file mode 100644 index 000000000..fcf01de7d --- /dev/null +++ b/compiler/bcq-tools/CMakeLists.txt @@ -0,0 +1,27 @@ +set(BCQ_TOOLS_FILES + generate_bcq_output_arrays + preserve_bcq_info +) + +foreach(BCQ_TOOLS IN ITEMS ${BCQ_TOOLS_FILES}) + + set(BCQ_TOOLS_FILE ${BCQ_TOOLS}) + set(BCQ_TOOLS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${BCQ_TOOLS_FILE}") + set(BCQ_TOOLS_BIN "${CMAKE_CURRENT_BINARY_DIR}/${BCQ_TOOLS_FILE}") + set(BCQ_TOOLS_TARGET "${BCQ_TOOLS}_target") + + add_custom_command(OUTPUT ${BCQ_TOOLS_BIN} + COMMAND ${CMAKE_COMMAND} -E copy "${BCQ_TOOLS_SRC}" "${BCQ_TOOLS_BIN}" + DEPENDS ${BCQ_TOOLS_SRC} + COMMENT "Generate ${BCQ_TOOLS_BIN}" + ) + + add_custom_target(${BCQ_TOOLS_TARGET} ALL DEPENDS ${BCQ_TOOLS_BIN}) + + install(FILES ${BCQ_TOOLS_BIN} + PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE + DESTINATION bin) + +endforeach(BCQ_TOOLS) diff --git a/compiler/bcq-tools/README.md b/compiler/bcq-tools/README.md new file mode 100644 index 000000000..18b0f4826 --- /dev/null +++ b/compiler/bcq-tools/README.md @@ -0,0 +1,78 @@ +# BCQ Tools + +This directory includes some tools related with BCQ. + +## preserve_bcq_info + +### Purpose + +`preserve_bcq_info` is for preserving constant nodes which include BCQ information. +When `.pb` file is converted to `.tflite` file by TFlite converter, constant nodes whose values are exactly same are removed and then linked to only one representative node. +This makes us impossible to know what constant node should be linked to a node which we want to apply BCQ. +One of the solutions is making all the same constant nodes different by inserting unique values and ignore the newly generated unique values when BCQ fusing is applied. +`preserve_bcq_info` will generate and insert unique dummy values to the constant nodes whose values are same not to be removed by Tensorflow Lite converter. +As a result, BCQ information will be preserved. + +### How to use + +```bash +preserve_bcq_info \ +--input_path /path/to/original_model.pb \ +--output_path /path/to/preserved_model.pb +``` + +### How it works + +If we add unique dummy value at the end of each constant nodes, all the constant nodes would be different. Following is an example. + +``` +[Original Constant Nodes] +const(value=[1, 2, 3], name='const1') +const(value=[1, 2, 3], name='const2') +const(value=[1, 2, 3], name='const3') + +[After BCQ information preserved] +const(value=[1, 2, 3, -1], name='const1') +const(value=[1, 2, 3, -2], name='const2') +const(value=[1, 2, 3, -3], name='const3') +``` + +For dummy values, negative values are used instead of positive values. +This is because positive valus may be confused with original constant node values. +For your information, unique dummy value starts from -1 and moves to -2, -3, ..., -N, where N is the number of preserved constant nodes. + +### Caution + +- Newly generated dummy values should be ignored when the constant nodes are used. + +## generate_bcq_output_arrays + +### Purpose + +To apply BCQ, BCQ information nodes should be designated as model output so that they are alive even after TFLite conversion is finished. +However, there are so many nodes to designate and sometimes we cannot copy and paste all of them because the string size is too big. +`generate_bcq_output_arrays` is for generating output_arrays, which include BCQ information nodes. + +### How to use + +```bash +generate_bcq_output_arrays \ +--input_path /path/to/original_model.pb \ +--output_path /path/to/output_arrays.txt +``` + +### How it works + +``` +[Original BCQ information nodes] +const(value=[1, 2, 3, -1], name='const1') +const(value=[1, 2, 3, -2], name='const2') +const(value=[1, 2, 3, -3], name='const3') + +[Generated output_arrays] +,const1,const2,const3 +``` + +### Caution + +- Generated output_arrays will be start with comma. diff --git a/compiler/bcq-tools/generate_bcq_output_arrays b/compiler/bcq-tools/generate_bcq_output_arrays new file mode 100644 index 000000000..48e8a9373 --- /dev/null +++ b/compiler/bcq-tools/generate_bcq_output_arrays @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 + +import tensorflow as tf + +import argparse +import sys + + +def _get_parser(): + """ + Returns an ArgumentParser for generating output_arrays. + """ + parser = argparse.ArgumentParser( + description=("Command line tool to generated output_arrays of BCQ nodes")) + + # Input and output path. + parser.add_argument( + "-i", + "--input_path", + type=str, + help="Full filepath of the input file.", + required=True) + parser.add_argument( + "-o", + "--output_path", + type=str, + help="Full filepath of the output file.", + required=True) + + return parser + + +def load_graph(frozen_graph_filename): + """ + Load graph from frozen pb file + """ + with tf.compat.v1.gfile.GFile(frozen_graph_filename, "rb") as f: + graph_def = tf.compat.v1.GraphDef() + graph_def.ParseFromString(f.read()) + with tf.Graph().as_default() as graph: + tf.import_graph_def(graph_def, name='') + return graph + + +def dtype2str(dtype): + if dtype == "int32": + return "TF_INT32" + elif dtype == "int64": + return "TF_INT64" + elif dtype == "float32": + return "TF_FLOAT" + elif dtype == "bool": + return "TF_BOOL" + else: + raise Exception("Not supported dtype") + + +def print_output_arrays(flags): + graph_model = load_graph(flags.input_path) + graph_model_def = graph_model.as_graph_def() + ops = graph_model.get_operations() + + output_names = [op.outputs[0].name for op in ops + if op.type == "Const" and "bcqinfo_" in op.outputs[0].name] + + output_arrays = "" + for output_name in output_names: + output_arrays += "," + + colon_index = output_name.find(":") + if colon_index == -1: + output_arrays += output_name + else: + output_arrays += output_name[:colon_index] + + f = open(flags.output_path, 'w') + f.write(output_arrays) + f.close() + + +def main(): + # Parse argument. + parser = _get_parser() + flags = parser.parse_known_args(args=sys.argv[1:]) + + print_output_arrays(flags[0]) + + +if __name__ == "__main__": + main() diff --git a/compiler/bcq-tools/preserve_bcq_info b/compiler/bcq-tools/preserve_bcq_info new file mode 100644 index 000000000..2ede8d4d0 --- /dev/null +++ b/compiler/bcq-tools/preserve_bcq_info @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +import tensorflow as tf +import numpy as np + +import argparse +import sys + + +def _get_parser(): + """ + Returns an ArgumentParser for preserving BCQ information. + """ + parser = argparse.ArgumentParser( + description=("Command line tool to preserve BCQ information")) + + # Input and output path. + parser.add_argument( + "-i", + "--input_path", + type=str, + help="Full filepath of the input file.", + required=True) + parser.add_argument( + "-o", + "--output_path", + type=str, + help="Full filepath of the output file.", + required=True) + + return parser + + +def load_graph(frozen_graph_filename): + """ + Load graph from frozen pb file + """ + with tf.compat.v1.gfile.GFile(frozen_graph_filename, "rb") as f: + graph_def = tf.compat.v1.GraphDef() + graph_def.ParseFromString(f.read()) + with tf.Graph().as_default() as graph: + tf.import_graph_def(graph_def, name='') + return graph + + +def preserve_bcq_info(flags): + """ + Generate unique dummy value from -1 to -N. + + We use negative values to preserve BCQ information because + positive values may cause some confusion with real BCQ information values. + """ + + class UniqueValueGen: + def __init__(self): + self.unique_value = -1 + + def gen(self): + val = self.unique_value + self.unique_value = val - 1 + return val + + unique_value = UniqueValueGen() + + original_graph_model = load_graph(flags.input_path) + original_graph_model_def = original_graph_model.as_graph_def() + + new_graph = tf.compat.v1.GraphDef() + substitution_dict = {} + + DT_INT32 = None # Just for copying DT_INT32 attribute value + + for node in original_graph_model_def.node: + if node.op == "Const": + # Because bcqinfo_do_w_x is BOOL type, we cannot add dummy value at the end. + # Therefore we should convert the type to INT32 type. + if "/bcqinfo_do_w_x" in node.name: + original_tensor = tf.make_ndarray(node.attr["value"].tensor) + substitution_dict[node.name] = tf.make_tensor_proto( + [int(original_tensor[0]), unique_value.gen()], tf.int32) + + preserved_bcqinfo_list = ["/bcqinfo_number_of_clusters", "/bcqinfo_size_of_clusters", + "/bcqinfo_qbits_of_clusters"] + + if any(name in node.name for name in preserved_bcqinfo_list): + original_tensor = tf.make_ndarray( + node.attr["value"].tensor) # variable name change + substitution_dict[node.name] = tf.make_tensor_proto( + np.append(original_tensor, unique_value.gen()), tf.int32) + DT_INT32 = node.attr["dtype"] + + for node in original_graph_model_def.node: + if node.name in substitution_dict: + new_node = new_graph.node.add() + new_node.op = "Const" + new_node.name = node.name + new_node.attr["dtype"].CopyFrom(DT_INT32) + new_node.attr["value"].tensor.CopyFrom(substitution_dict[node.name]) + else: + new_node = new_graph.node.add() + new_node.CopyFrom(node) + + tf.io.write_graph(new_graph, '.', flags.output_path, False) + + +def main(): + # Parse argument. + parser = _get_parser() + flags = parser.parse_known_args(args=sys.argv[1:]) + + # Generate a new pb file, which BCQ information is preserved. + preserve_bcq_info(flags[0]) + + +if __name__ == "__main__": + main() diff --git a/compiler/circle-quantizer/CMakeLists.txt b/compiler/circle-quantizer/CMakeLists.txt index 1335057eb..009bfabea 100644 --- a/compiler/circle-quantizer/CMakeLists.txt +++ b/compiler/circle-quantizer/CMakeLists.txt @@ -13,5 +13,6 @@ target_link_libraries(circle-quantizer luci_service) target_link_libraries(circle-quantizer luci_pass) target_link_libraries(circle-quantizer luci_export) target_link_libraries(circle-quantizer arser) +target_link_libraries(circle-quantizer vconone) install(TARGETS circle-quantizer DESTINATION bin) diff --git a/compiler/circle-quantizer/requires.cmake b/compiler/circle-quantizer/requires.cmake index 2293e53f8..c21e28e8d 100644 --- a/compiler/circle-quantizer/requires.cmake +++ b/compiler/circle-quantizer/requires.cmake @@ -5,3 +5,4 @@ require("safemain") require("luci") require("oops") require("arser") +require("vconone") diff --git a/compiler/circle-quantizer/src/CircleQuantizer.cpp b/compiler/circle-quantizer/src/CircleQuantizer.cpp index b56b547a9..8d3a80c91 100644 --- a/compiler/circle-quantizer/src/CircleQuantizer.cpp +++ b/compiler/circle-quantizer/src/CircleQuantizer.cpp @@ -25,6 +25,7 @@ #include <oops/InternalExn.h> #include <arser/arser.h> +#include <vconone/vconone.h> #include <functional> #include <iostream> @@ -36,6 +37,12 @@ using OptionHook = std::function<int(const char **)>; using Algorithms = luci::CircleOptimizer::Options::Algorithm; using AlgorithmParameters = luci::CircleOptimizer::Options::AlgorithmParameters; +void print_version(void) +{ + std::cout << "circle-quantizer version " << vconone::get_string() << std::endl; + std::cout << vconone::get_copyright() << std::endl; +} + int entry(int argc, char **argv) { // Simple argument parser (based on map) @@ -49,13 +56,20 @@ int entry(int argc, char **argv) arser::Arser arser("circle-quantizer provides circle model quantization"); + arser.add_argument("--version") + .nargs(0) + .required(false) + .default_value(false) + .help("Show version information and exit") + .exit_with(print_version); + arser.add_argument(qdqw) .nargs(3) .type(arser::DataType::STR_VEC) .required(false) .help("Quantize-dequantize weight values required action before quantization. " "Three arguments required: input_dtype(float32) " - "output_dtype(uint8) granularity(layer)"); + "output_dtype(uint8) granularity(layer, channel)"); arser.add_argument(qwmm) .nargs(3) @@ -63,7 +77,7 @@ int entry(int argc, char **argv) .required(false) .help("Quantize with min/max values. " "Three arguments required: input_dtype(float32) " - "output_dtype(uint8) granularity(layer)"); + "output_dtype(uint8) granularity(layer, channel)"); arser.add_argument("input").nargs(1).type(arser::DataType::STR).help("Input circle model"); arser.add_argument("output").nargs(1).type(arser::DataType::STR).help("Output circle model"); diff --git a/compiler/circle-tensordump/driver/Driver.cpp b/compiler/circle-tensordump/driver/Driver.cpp index a55cd4574..5bab9f59e 100644 --- a/compiler/circle-tensordump/driver/Driver.cpp +++ b/compiler/circle-tensordump/driver/Driver.cpp @@ -46,7 +46,14 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; + } + + if (arser["--tensors_to_hdf5"] == arser["--tensors"]) + { + std::cout << "[Error] You must specify one option for how to print." << std::endl; + std::cout << arser; + return 255; } std::unique_ptr<circletensordump::DumpInterface> dump; diff --git a/compiler/circle-tensordump/src/Dump.cpp b/compiler/circle-tensordump/src/Dump.cpp index dfa78f031..a8d32564f 100644 --- a/compiler/circle-tensordump/src/Dump.cpp +++ b/compiler/circle-tensordump/src/Dump.cpp @@ -136,6 +136,7 @@ void DumpTensors::run(std::ostream &os, const circle::Model *model, const std::s auto max = quant_param->max(); auto scale = quant_param->scale(); auto zero_point = quant_param->zero_point(); + auto quantized_dimension = quant_param->quantized_dimension(); os << " " + print_format2 + "  ├── min : "; ::print_comma_sepearted(os, min); @@ -146,9 +147,11 @@ void DumpTensors::run(std::ostream &os, const circle::Model *model, const std::s os << " " + print_format2 + "  ├── scale : "; ::print_comma_sepearted(os, scale); os << std::endl; - os << " " + print_format2 + "  └── zero_point : "; + os << " " + print_format2 + "  ├── zero_point : "; ::print_comma_sepearted(os, zero_point); os << std::endl; + os << " " + print_format2 + "  └── quantized_dimension : " << quantized_dimension; + os << std::endl; } // buffer @@ -229,7 +232,7 @@ std::vector<hsize_t> hdf5_dims_cast(const flatbuffers::Vector<T> *data, } /** - * This function writes data to given hdf5 file like below. + * This function writes vector data to given hdf5 file like below. * * GROUP "group_name" * ã„´DATATYPE "type" @@ -238,9 +241,9 @@ std::vector<hsize_t> hdf5_dims_cast(const flatbuffers::Vector<T> *data, * ã„´DATA "data" */ template <typename T> -void write_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string dataset_name, - const H5::PredType &type, const flatbuffers::Vector<T> *data, - std::vector<hsize_t> dims) +void write_vector_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string dataset_name, + const H5::PredType &type, const flatbuffers::Vector<T> *data, + std::vector<hsize_t> dims) { if (data == nullptr) return; @@ -250,6 +253,17 @@ void write_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string d dataset->write(data->data(), type); } +/// @brief This function writes scalar data to given hdf5 file +template <typename T> +void write_scalar_data_to_hdf5(H5::H5File &file, std::string &group_name, std::string dataset_name, + const H5::PredType &type, T data) +{ + auto dataspace = std::make_unique<H5::DataSpace>(H5S_SCALAR); + auto dataset = std::make_unique<H5::DataSet>( + file.createDataSet(group_name + "/" + dataset_name, type, *dataspace)); + dataset->write(&data, type); +} + } // namespace namespace circletensordump @@ -297,8 +311,9 @@ void DumpTensorsToHdf5::run(std::ostream &os, const circle::Model *model, auto buff_data_ptr = reader.buffers()->Get(buff_idx)->data(); if (buff_data_ptr) { - ::write_data_to_hdf5(file, group_name, "weights", ::hdf5_dtype_cast(tensor->type()), - buff_data_ptr, ::hdf5_dims_cast(buff_data_ptr, tensor->shape())); + ::write_vector_data_to_hdf5(file, group_name, "weights", ::hdf5_dtype_cast(tensor->type()), + buff_data_ptr, + ::hdf5_dims_cast(buff_data_ptr, tensor->shape())); } // write quantization parameters @@ -306,17 +321,20 @@ void DumpTensorsToHdf5::run(std::ostream &os, const circle::Model *model, if (quant_param) { auto min = quant_param->min(); - ::write_data_to_hdf5(file, group_name, "min", H5::PredType::NATIVE_FLOAT, min, - ::hdf5_dims_cast(min)); + ::write_vector_data_to_hdf5(file, group_name, "min", H5::PredType::NATIVE_FLOAT, min, + ::hdf5_dims_cast(min)); auto max = quant_param->max(); - ::write_data_to_hdf5(file, group_name, "max", H5::PredType::NATIVE_FLOAT, max, - ::hdf5_dims_cast(max)); + ::write_vector_data_to_hdf5(file, group_name, "max", H5::PredType::NATIVE_FLOAT, max, + ::hdf5_dims_cast(max)); auto scale = quant_param->scale(); - ::write_data_to_hdf5(file, group_name, "scale", H5::PredType::NATIVE_FLOAT, scale, - ::hdf5_dims_cast(scale)); + ::write_vector_data_to_hdf5(file, group_name, "scale", H5::PredType::NATIVE_FLOAT, scale, + ::hdf5_dims_cast(scale)); auto zero_point = quant_param->zero_point(); - ::write_data_to_hdf5(file, group_name, "zero_point", H5::PredType::NATIVE_INT64, zero_point, - ::hdf5_dims_cast(zero_point)); + ::write_vector_data_to_hdf5(file, group_name, "zero_point", H5::PredType::NATIVE_INT64, + zero_point, ::hdf5_dims_cast(zero_point)); + auto quantized_dimension = quant_param->quantized_dimension(); + ::write_scalar_data_to_hdf5(file, group_name, "quantized_dimension", + H5::PredType::NATIVE_INT32, quantized_dimension); } } } diff --git a/compiler/circle-verify/src/Driver.cpp b/compiler/circle-verify/src/Driver.cpp index 1af31d986..7a44c65b9 100644 --- a/compiler/circle-verify/src/Driver.cpp +++ b/compiler/circle-verify/src/Driver.cpp @@ -35,7 +35,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } auto verifier = std::make_unique<VerifyFlatbuffers>(); diff --git a/compiler/circle2circle-dredd-recipe-test/CMakeLists.txt b/compiler/circle2circle-dredd-recipe-test/CMakeLists.txt index 6663cb938..4bcaae347 100644 --- a/compiler/circle2circle-dredd-recipe-test/CMakeLists.txt +++ b/compiler/circle2circle-dredd-recipe-test/CMakeLists.txt @@ -1,25 +1,12 @@ nnas_include(TargetRequire) unset(REQUIRED_TARGETS) -list(APPEND REQUIRED_TARGETS circlechef) list(APPEND REQUIRED_TARGETS circle-inspect) list(APPEND REQUIRED_TARGETS circle-verify) list(APPEND REQUIRED_TARGETS circle2circle) list(APPEND REQUIRED_TARGETS dredd_rule_lib) -list(APPEND REQUIRED_TARGETS tflchef) -list(APPEND REQUIRED_TARGETS tflite2circle) TargetRequire_Return(${REQUIRED_TARGETS}) -nncc_find_resource(TensorFlowLiteRecipes) -nncc_find_resource(CircleRecipes) - -set(TFLITE_RECIPE_REPO "${TensorFlowLiteRecipes_DIR}") -set(CIRCLE_RECIPE_REPO "${CircleRecipes_DIR}") -unset(RECIPE_REPO) - -set(TEST_RECIPE_FILENAME "test.recipe") -set(TEST_RULE_FILENAME "test.rule") - unset(TEST_DEPS) unset(TEST_NAMES) @@ -27,21 +14,9 @@ set(options "") set(oneValueArgs "") set(multiValueArgs PASS) -macro(Add RECIPE) - if(NOT EXISTS "${TFLITE_RECIPE_REPO}/${RECIPE}/test.recipe") - if(NOT EXISTS "${CIRCLE_RECIPE_REPO}/${RECIPE}/test.recipe") - message(FATAL_ERROR "Missing recipe of '${RECIPE}' test") - else() - set(RECIPE_REPO ${CIRCLE_RECIPE_REPO}) - endif() - else() - set(RECIPE_REPO ${TFLITE_RECIPE_REPO}) - endif() - - if(NOT EXISTS "${RECIPE_REPO}/${RECIPE}/test.rule") - message(FATAL_ERROR "Missing rule of '${RECIPE}' test") - endif() +get_target_property(ARTIFACTS_BIN_PATH testDataGenerator BINARY_DIR) +macro(Add RECIPE) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) unset(OPT_OPTIONS) foreach(src ${ARG_PASS}) @@ -49,71 +24,20 @@ macro(Add RECIPE) list(APPEND OPT_OPTIONS "--${src}") endforeach(src ${ARG_PASS}) - set(RECIPE_FILE "${RECIPE}.recipe") - set(RECIPE_SOURCE_PATH "${RECIPE_REPO}/${RECIPE}/${TEST_RECIPE_FILENAME}") - set(RECIPE_BINARY_PATH "${CMAKE_CURRENT_BINARY_DIR}/${RECIPE_FILE}") - - set(RULE_FILE "${RECIPE}.rule") - set(RULE_SOURCE_PATH "${RECIPE_REPO}/${RECIPE}/${TEST_RULE_FILENAME}") - set(RULE_BINARY_PATH "${CMAKE_CURRENT_BINARY_DIR}/${RULE_FILE}") - - set(TFLITE_FILE "${RECIPE}.tflite") - set(TFLITE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${TFLITE_FILE}") - set(CIRCLE_FILE "${RECIPE}.circle") - set(CIRCLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CIRCLE_FILE}") + set(CIRCLE_PATH "${ARTIFACTS_BIN_PATH}/${CIRCLE_FILE}") set(OPT_CIRCLE_FILE "${RECIPE}.opt.circle") set(OPT_CIRCLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${OPT_CIRCLE_FILE}") - # Copy .recipe - add_custom_command(OUTPUT ${RECIPE_BINARY_PATH} - COMMAND ${CMAKE_COMMAND} -E copy "${RECIPE_SOURCE_PATH}" "${RECIPE_BINARY_PATH}" - DEPENDS ${RECIPE_SOURCE_PATH} - COMMENT "Generate ${RECIPE_FILE}" - ) - - # Copy .rule - add_custom_command(OUTPUT ${RULE_BINARY_PATH} - COMMAND ${CMAKE_COMMAND} -E copy "${RULE_SOURCE_PATH}" "${RULE_BINARY_PATH}" - DEPENDS ${RULE_SOURCE_PATH} - COMMENT "Generate ${RULE_FILE}" - ) - - if(${RECIPE_REPO} STREQUAL ${TFLITE_RECIPE_REPO}) - # Generate .tflite - add_custom_command(OUTPUT ${TFLITE_OUTPUT_PATH} - COMMAND $<TARGET_FILE:tflchef-file> ${RECIPE_BINARY_PATH} ${TFLITE_OUTPUT_PATH} - DEPENDS $<TARGET_FILE:tflchef-file> ${RECIPE_BINARY_PATH} - COMMENT "Generate ${TFLITE_FILE}" - ) - - # Generate .circle - add_custom_command(OUTPUT ${CIRCLE_OUTPUT_PATH} - COMMAND $<TARGET_FILE:tflite2circle> ${TFLITE_OUTPUT_PATH} ${CIRCLE_OUTPUT_PATH} - DEPENDS $<TARGET_FILE:tflite2circle> ${TFLITE_OUTPUT_PATH} - COMMENT "Generate ${CIRCLE_FILE}" - ) - - list(APPEND TEST_DEPS ${TFLITE_OUTPUT_PATH}) - else() - # Generate .circle - add_custom_command(OUTPUT ${CIRCLE_OUTPUT_PATH} - COMMAND $<TARGET_FILE:circlechef-file> ${RECIPE_BINARY_PATH} ${CIRCLE_OUTPUT_PATH} - DEPENDS $<TARGET_FILE:circlechef-file> ${RECIPE_BINARY_PATH} - COMMENT "Generate ${CIRCLE_FILE}" - ) - endif() - # Generate optimized .circle add_custom_command(OUTPUT ${OPT_CIRCLE_OUTPUT_PATH} - COMMAND $<TARGET_FILE:circle2circle> ${OPT_OPTIONS} ${CIRCLE_OUTPUT_PATH} ${OPT_CIRCLE_OUTPUT_PATH} - DEPENDS $<TARGET_FILE:circle2circle> ${CIRCLE_OUTPUT_PATH} + COMMAND $<TARGET_FILE:circle2circle> ${OPT_OPTIONS} ${CIRCLE_PATH} ${OPT_CIRCLE_OUTPUT_PATH} + DEPENDS $<TARGET_FILE:circle2circle> ${CIRCLE_PATH} COMMENT "Generate ${OPT_CIRCLE_FILE}" ) - list(APPEND TEST_DEPS ${RECIPE_BINARY_PATH} ${RULE_BINARY_PATH} - ${CIRCLE_OUTPUT_PATH} ${OPT_CIRCLE_OUTPUT_PATH}) + list(APPEND TEST_DEPS ${OPT_CIRCLE_OUTPUT_PATH}) list(APPEND TEST_NAMES ${RECIPE}) endmacro(Add) @@ -174,12 +98,15 @@ list(APPEND TEST_DEPS "${RULE_LIB_BINARY_PATH}") # Generate dependencies add_custom_target(circle2circle_dredd_recipe_test ALL DEPENDS ${TEST_DEPS}) +add_dependencies(circle2circle_dredd_recipe_test common_artifacts_deps) + +get_target_property(ARTIFACTS_BIN_PATH testDataGenerator BINARY_DIR) # Run tests add_test( NAME circle2circle_dredd_recipe_test COMMAND "${TEST_RUNNER}" "${TEST_CONFIG}" - "${CMAKE_CURRENT_BINARY_DIR}" + "${ARTIFACTS_BIN_PATH}" ${TEST_NAMES} ) diff --git a/compiler/circle2circle-dredd-recipe-test/requires.cmake b/compiler/circle2circle-dredd-recipe-test/requires.cmake index e4a5b71a7..70e7c5295 100644 --- a/compiler/circle2circle-dredd-recipe-test/requires.cmake +++ b/compiler/circle2circle-dredd-recipe-test/requires.cmake @@ -1,7 +1,5 @@ -require("circlechef") require("circle2circle") require("circle-inspect") require("circle-verify") +require("common-artifacts") require("dredd-rule-lib") -require("tflchef") -require("tflite2circle") diff --git a/compiler/circle2circle-dredd-recipe-test/test.lst b/compiler/circle2circle-dredd-recipe-test/test.lst index 202f66938..6328a64db 100644 --- a/compiler/circle2circle-dredd-recipe-test/test.lst +++ b/compiler/circle2circle-dredd-recipe-test/test.lst @@ -11,9 +11,10 @@ ## TFLITE RECIPE Add(Net_InstanceNorm_001 PASS fuse_instnorm) -# Add(Net_InstanceNorm_002 PASS fuse_instnorm) +Add(Net_InstanceNorm_002 PASS fuse_instnorm) Add(BatchMatMulV2_000 PASS resolve_customop_batchmatmul) Add(MatMul_000 PASS resolve_customop_matmul) +Add(DepthwiseConv2D_003 PASS) ## CIRCLE RECIPE diff --git a/compiler/circle2circle-dredd-recipe-test/testall.sh b/compiler/circle2circle-dredd-recipe-test/testall.sh index 33a2036bb..2899587ba 100755 --- a/compiler/circle2circle-dredd-recipe-test/testall.sh +++ b/compiler/circle2circle-dredd-recipe-test/testall.sh @@ -13,21 +13,22 @@ if [[ $# -lt 2 ]]; then exit 255 fi +WORKDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CONFIG_PATH="$1"; shift -WORKDIR="$1"; shift +RESOURCE_DIR="$1"; shift source "${CONFIG_PATH}" echo "-- Found circle-inspect: ${CIRCLE_INSPECT_PATH}" echo "-- Found circle-verify: ${CIRCLE_VERIFY_PATH}" echo "-- Found circle2circle: ${CIRCLE2CIRCLE_PATH}" -echo "-- Found workdir: ${WORKDIR}" +echo "-- Found common-artifacts: ${RESOURCE_DIR}" TESTED=() PASSED=() FAILED=() -pushd "${WORKDIR}" +pushd ${WORKDIR} while [[ $# -ne 0 ]]; do PREFIX="$1"; shift @@ -40,7 +41,7 @@ while [[ $# -ne 0 ]]; do cat > "${PREFIX}.log" <( exec 2>&1 - echo "-- Found tflite: ${PREFIX}.tflite" + echo "-- Found circle: ${PREFIX}.opt.circle" # Exit immediately if any command fails set -e @@ -55,7 +56,7 @@ while [[ $# -ne 0 ]]; do set +x # (COMPILED_FILE, INSPECT_PROG_PATH, VERIFY_PROG_PATH, ERROR_LOG) must be set for rule-lib.sh - COMPILED_FILE="${WORKDIR}/${PREFIX}.opt.circle" + COMPILED_FILE="${PREFIX}.opt.circle" INSPECT_PROG_PATH=${CIRCLE_INSPECT_PATH} VERIFY_PROG_PATH=${CIRCLE_VERIFY_PATH} ERROR_LOG="${PREFIX}.error" @@ -66,7 +67,7 @@ while [[ $# -ne 0 ]]; do trap 'echo "** ERROR **" ; cat "${ERROR_LOG}"' ERR source rule-lib.sh - source "${PREFIX}.rule" + source "${RESOURCE_DIR}/${PREFIX}.rule" # unset trap - ERR diff --git a/compiler/circle2circle/CMakeLists.txt b/compiler/circle2circle/CMakeLists.txt index 7b2bf9b02..f60c896d8 100644 --- a/compiler/circle2circle/CMakeLists.txt +++ b/compiler/circle2circle/CMakeLists.txt @@ -19,6 +19,7 @@ target_link_libraries(circle2circle luci_service) target_link_libraries(circle2circle luci_pass) target_link_libraries(circle2circle luci_export) target_link_libraries(circle2circle arser) +target_link_libraries(circle2circle vconone) install(TARGETS circle2circle DESTINATION bin) @@ -44,3 +45,4 @@ target_link_libraries(circle2circle_test luci_service) target_link_libraries(circle2circle_test luci_pass) target_link_libraries(circle2circle_test luci_export) target_link_libraries(circle2circle_test arser) +target_link_libraries(circle2circle_test vconone) diff --git a/compiler/circle2circle/requires.cmake b/compiler/circle2circle/requires.cmake index 8cbb90dbf..36a9efd16 100644 --- a/compiler/circle2circle/requires.cmake +++ b/compiler/circle2circle/requires.cmake @@ -9,3 +9,4 @@ require("hermes") require("hermes-std") require("luci") require("arser") +require("vconone") diff --git a/compiler/circle2circle/src/Circle2Circle.cpp b/compiler/circle2circle/src/Circle2Circle.cpp index 6888d26e3..849597b46 100644 --- a/compiler/circle2circle/src/Circle2Circle.cpp +++ b/compiler/circle2circle/src/Circle2Circle.cpp @@ -26,6 +26,7 @@ #include <oops/InternalExn.h> #include <arser/arser.h> +#include <vconone/vconone.h> #include <functional> #include <iostream> @@ -34,6 +35,12 @@ using Algorithms = luci::CircleOptimizer::Options::Algorithm; using AlgorithmParameters = luci::CircleOptimizer::Options::AlgorithmParameters; +void print_version(void) +{ + std::cout << "circle2circle version " << vconone::get_string() << std::endl; + std::cout << vconone::get_copyright() << std::endl; +} + int entry(int argc, char **argv) { // Simple argument parser (based on map) @@ -44,6 +51,13 @@ int entry(int argc, char **argv) arser::Arser arser("circle2circle provides circle model optimization and transformations"); + arser.add_argument("--version") + .nargs(0) + .required(false) + .default_value(false) + .help("Show version information and exit") + .exit_with(print_version); + arser.add_argument("--all").nargs(0).required(false).default_value(false).help( "Enable all optimize options"); diff --git a/compiler/circlechef/CMakeLists.txt b/compiler/circlechef/CMakeLists.txt index cba7d0a4e..3e2ddcbb3 100644 --- a/compiler/circlechef/CMakeLists.txt +++ b/compiler/circlechef/CMakeLists.txt @@ -18,4 +18,6 @@ add_subdirectory(core) add_subdirectory(circle) # Tools add_subdirectory(tools) -add_subdirectory(tests) +if(ENABLE_TEST) + add_subdirectory(tests) +endif(ENABLE_TEST) diff --git a/compiler/circlechef/circle/src/RecipeChef.cpp b/compiler/circlechef/circle/src/RecipeChef.cpp index 17ef1be6e..51326c7f8 100644 --- a/compiler/circlechef/circle/src/RecipeChef.cpp +++ b/compiler/circlechef/circle/src/RecipeChef.cpp @@ -181,6 +181,8 @@ std::unique_ptr<ModelRecipe> generate_recipe(const circle::Model *model) for (uint32_t idx = 0; idx < quant->zero_point()->size(); ++idx) chef_quant->add_zero_point(quant->zero_point()->Get(idx)); } + circlechef::TensorQuantization *chef_quant = operand->mutable_quant(); + chef_quant->set_quantized_dimension(quant->quantized_dimension()); } } diff --git a/compiler/circlechef/core/src/ModelChef.cpp b/compiler/circlechef/core/src/ModelChef.cpp index 76aeacdd9..d81467d68 100644 --- a/compiler/circlechef/core/src/ModelChef.cpp +++ b/compiler/circlechef/core/src/ModelChef.cpp @@ -413,6 +413,7 @@ template <typename T> void cook_graph(const T &graph, CookParams &cp) quant_builder.add_min(quant_min); quant_builder.add_scale(quant_scale); quant_builder.add_zero_point(quant_zero_point); + quant_builder.add_quantized_dimension(quant.quantized_dimension()); // Update QuantizationParameters Index quant_index = quant_builder.Finish(); diff --git a/compiler/circlechef/proto/circlechef.proto b/compiler/circlechef/proto/circlechef.proto index b8c009b38..3e5e6b168 100644 --- a/compiler/circlechef/proto/circlechef.proto +++ b/compiler/circlechef/proto/circlechef.proto @@ -35,6 +35,7 @@ message TensorQuantization { repeated float max = 2; repeated float scale = 3; repeated int64 zero_point = 4; + optional int32 quantized_dimension = 5 [default = 0]; } message Operand { diff --git a/compiler/circlechef/tools/file/Driver.cpp b/compiler/circlechef/tools/file/Driver.cpp index a15da4002..bcc0c7ae9 100644 --- a/compiler/circlechef/tools/file/Driver.cpp +++ b/compiler/circlechef/tools/file/Driver.cpp @@ -41,7 +41,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } int32_t model_version = 1; diff --git a/compiler/circlechef/tools/reverse/Driver.cpp b/compiler/circlechef/tools/reverse/Driver.cpp index 9c0b9ea24..8a2b85fc7 100644 --- a/compiler/circlechef/tools/reverse/Driver.cpp +++ b/compiler/circlechef/tools/reverse/Driver.cpp @@ -38,7 +38,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } std::string circle_path = arser.get<std::string>("circle"); diff --git a/compiler/circledump/driver/Driver.cpp b/compiler/circledump/driver/Driver.cpp index b8f561fee..657f24fe0 100644 --- a/compiler/circledump/driver/Driver.cpp +++ b/compiler/circledump/driver/Driver.cpp @@ -33,7 +33,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << '\n'; std::cout << arser; - return 0; + return 255; } std::string circle_path = arser.get<std::string>("circle"); diff --git a/compiler/circledump/src/OpPrinter.cpp b/compiler/circledump/src/OpPrinter.cpp index 2c0320396..3294bb23d 100644 --- a/compiler/circledump/src/OpPrinter.cpp +++ b/compiler/circledump/src/OpPrinter.cpp @@ -593,6 +593,20 @@ public: } }; +class UniquePrinter : public OpPrinter +{ +public: + void options(const circle::Operator *op, std::ostream &os) const override + { + if (auto *params = op->builtin_options_as_UniqueOptions()) + { + os << " "; + os << "idx_out_type(" << EnumNameTensorType(params->idx_out_type()) << ") "; + os << std::endl; + } + } +}; + class WhilePrinter : public OpPrinter { public: @@ -710,9 +724,11 @@ OpPrinterRegistry::OpPrinterRegistry() _op_map[circle::BuiltinOperator_MAX_POOL_2D] = make_unique<Pool2DPrinter>(); _op_map[circle::BuiltinOperator_MIRROR_PAD] = make_unique<MirrorPadPrinter>(); _op_map[circle::BuiltinOperator_MUL] = make_unique<MulPrinter>(); + // There is no Option for NON_MAX_SUPPRESSION_V4 _op_map[circle::BuiltinOperator_ONE_HOT] = make_unique<OneHotPrinter>(); _op_map[circle::BuiltinOperator_PACK] = make_unique<PackPrinter>(); // There is no Option for PAD + // There is no Option for PADV2 // There is no Option for PRELU // There is no Option for RELU // There is no Option for RELU6 @@ -744,6 +760,7 @@ OpPrinterRegistry::OpPrinterRegistry() _op_map[circle::BuiltinOperator_SUM] = make_unique<ReducerPrinter>(); _op_map[circle::BuiltinOperator_TRANSPOSE_CONV] = make_unique<TransposeConvPrinter>(); // There is no Option for TOPK_V2 + _op_map[circle::BuiltinOperator_UNIQUE] = make_unique<UniquePrinter>(); _op_map[circle::BuiltinOperator_WHILE] = make_unique<WhilePrinter>(); _op_map[circle::BuiltinOperator_CUSTOM] = make_unique<CustomOpPrinter>(); diff --git a/compiler/common-artifacts/CMakeLists.txt b/compiler/common-artifacts/CMakeLists.txt index ee4191d73..ef50e8d43 100644 --- a/compiler/common-artifacts/CMakeLists.txt +++ b/compiler/common-artifacts/CMakeLists.txt @@ -13,30 +13,47 @@ if(${PYTHON_VERSION_MINOR} LESS 3) endif() # Create python virtual environment with tensorflow 1.13.2 -set(VIRTUALENV_OVERLAY "${NNCC_OVERLAY_DIR}/venv_1_13_2") +set(VIRTUALENV_OVERLAY_TF_1_13_2 "${NNCC_OVERLAY_DIR}/venv_1_13_2") + +# Create python virtual environment with tensorflow 2.3.0 +set(VIRTUALENV_OVERLAY_TF_2_3_0 "${NNCC_OVERLAY_DIR}/venv_2_3_0") + +add_custom_command( + OUTPUT ${VIRTUALENV_OVERLAY_TF_1_13_2} + COMMAND ${PYTHON_EXECUTABLE} -m venv ${VIRTUALENV_OVERLAY_TF_1_13_2} +) add_custom_command( - OUTPUT ${VIRTUALENV_OVERLAY} - COMMAND ${PYTHON_EXECUTABLE} -m venv ${VIRTUALENV_OVERLAY} + OUTPUT ${VIRTUALENV_OVERLAY_TF_2_3_0} + COMMAND ${PYTHON_EXECUTABLE} -m venv ${VIRTUALENV_OVERLAY_TF_2_3_0} ) # Create requirements.txt and install required pip packages set(REQUIREMENTS_FILE "requirements.txt") -set(REQUIREMENTS_OVERLAY_PATH "${NNCC_OVERLAY_DIR}/${REQUIREMENTS_FILE}") +set(REQUIREMENTS_OVERLAY_PATH_TF_1_13_2 "${VIRTUALENV_OVERLAY_TF_1_13_2}/${REQUIREMENTS_FILE}") +set(REQUIREMENTS_OVERLAY_PATH_TF_2_3_0 "${VIRTUALENV_OVERLAY_TF_2_3_0}/${REQUIREMENTS_FILE}") add_custom_command( - OUTPUT ${REQUIREMENTS_OVERLAY_PATH} - COMMAND ${CMAKE_COMMAND} -E echo "tensorflow==1.13.2" > ${REQUIREMENTS_OVERLAY_PATH} - COMMAND ${VIRTUALENV_OVERLAY}/bin/python -m pip --default-timeout=1000 install --upgrade pip setuptools - COMMAND ${VIRTUALENV_OVERLAY}/bin/python -m pip --default-timeout=1000 install -r ${REQUIREMENTS_OVERLAY_PATH} --upgrade - DEPENDS ${VIRTUALENV_OVERLAY} ${REQUIREMENTS_OVERLAY_PATH} + OUTPUT ${REQUIREMENTS_OVERLAY_PATH_TF_1_13_2} + COMMAND ${CMAKE_COMMAND} -E echo "tensorflow==1.13.2" > ${REQUIREMENTS_OVERLAY_PATH_TF_1_13_2} + COMMAND ${VIRTUALENV_OVERLAY_TF_1_13_2}/bin/python -m pip --default-timeout=1000 install --upgrade pip setuptools + COMMAND ${VIRTUALENV_OVERLAY_TF_1_13_2}/bin/python -m pip --default-timeout=1000 install -r ${REQUIREMENTS_OVERLAY_PATH_TF_1_13_2} --upgrade + DEPENDS ${VIRTUALENV_OVERLAY_TF_1_13_2} ) -add_custom_target(common_artifacts_python_deps ALL - DEPENDS ${VIRTUALENV_OVERLAY} ${REQUIREMENTS_OVERLAY_PATH} +add_custom_command( + OUTPUT ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} + COMMAND ${CMAKE_COMMAND} -E remove -f ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} + COMMAND ${CMAKE_COMMAND} -E echo "tensorflow-cpu==2.3.0" >> ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} + COMMAND ${CMAKE_COMMAND} -E echo "flatbuffers==1.12" >> ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} + COMMAND ${VIRTUALENV_OVERLAY_TF_2_3_0}/bin/python -m pip --default-timeout=1000 install --upgrade pip setuptools + COMMAND ${VIRTUALENV_OVERLAY_TF_2_3_0}/bin/python -m pip --default-timeout=1000 install -r ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} --upgrade + DEPENDS ${VIRTUALENV_OVERLAY_TF_2_3_0} ) -# TODO Create python virtual environment with tensorflow 2.3.0-rc0 +add_custom_target(common_artifacts_python_deps ALL + DEPENDS ${VIRTUALENV_OVERLAY_TF_1_13_2} ${VIRTUALENV_OVERLAY_TF_2_3_0} ${REQUIREMENTS_OVERLAY_PATH_TF_1_13_2} ${REQUIREMENTS_OVERLAY_PATH_TF_2_3_0} +) #[[ Generate common resources ]] # TODO add pbtxt @@ -52,6 +69,7 @@ set(SOURCES src/TestDataGenerator.cpp) add_executable(testDataGenerator ${SOURCES}) target_include_directories(testDataGenerator PRIVATE ${HDF5_INCLUDE_DIRS}) target_link_libraries(testDataGenerator PRIVATE ${HDF5_CXX_LIBRARIES}) +target_link_libraries(testDataGenerator PRIVATE arser) target_link_libraries(testDataGenerator PRIVATE foder) target_link_libraries(testDataGenerator PRIVATE luci_import) target_link_libraries(testDataGenerator PRIVATE luci_interpreter) diff --git a/compiler/common-artifacts/exclude.lst b/compiler/common-artifacts/exclude.lst index b614b7182..fe9933ae0 100644 --- a/compiler/common-artifacts/exclude.lst +++ b/compiler/common-artifacts/exclude.lst @@ -5,9 +5,12 @@ #[[ optimize : Exclude from circle optimization(circle2circle) ]] ## TensorFlowLiteRecipes -optimize(ReLU6_000) -optimize(Where_000) -optimize(Where_001) +optimize(Unique_000) +optimize(Unique_001) +optimize(Unique_002) +optimize(Unique_003) +optimize(Unique_U8_000) +optimize(Unique_U8_001) ## CircleRecipes @@ -46,6 +49,7 @@ tcgenerate(DepthToSpace_000) tcgenerate(DepthwiseConv2D_001) # runtime doesn't support dilation tcgenerate(DepthwiseConv2D_003) # runtime doesn't support dilation tcgenerate(DepthwiseConv2D_U8_000) +tcgenerate(DepthwiseConv2D_U8_001) # luci-interpreter doesn't support channel-wise quantization yet tcgenerate(Div_000) tcgenerate(ELU_000) tcgenerate(Equal_000) @@ -90,13 +94,15 @@ tcgenerate(Maximum_000) tcgenerate(MaxPool2D_U8_000) tcgenerate(Mean_U8_000) tcgenerate(Minimum_000) +tcgenerate(NonMaxSuppressionV4_000) +tcgenerate(NonMaxSuppressionV4_001) tcgenerate(MirrorPad_000) tcgenerate(Mul_U8_000) tcgenerate(Neg_000) tcgenerate(Net_Dangle_001) tcgenerate(Net_InstanceNorm_001) tcgenerate(Net_InstanceNorm_002) -tcgenerate(Net_ZeroDim_001) # fix luci +tcgenerate(Net_ZeroDim_001) # luci-interpreter doesn't support zero dim tcgenerate(NotEqual_000) tcgenerate(OneHot_000) tcgenerate(OneHot_001) @@ -105,6 +111,7 @@ tcgenerate(OneHot_003) tcgenerate(Pack_000) tcgenerate(Pack_U8_000) tcgenerate(Pad_U8_000) +tcgenerate(PadV2_000) tcgenerate(Pow_000) tcgenerate(PRelu_000) tcgenerate(Range_000) @@ -120,11 +127,12 @@ tcgenerate(ReduceProd_001) tcgenerate(ReduceProd_002) tcgenerate(ReduceProd_003) tcgenerate(ReLU_000) -tcgenerate(ReLU6_000) # luci NYI +tcgenerate(ReLU6_000) tcgenerate(ReLUN1To1_000) -tcgenerate(Reshape_003) # fix luci +tcgenerate(Reshape_003) # luci-interpreter doesn't support reshape without built-in option tcgenerate(Reshape_U8_000) tcgenerate(ResizeBilinear_000) +tcgenerate(ResizeBilinear_U8_000) # luci-interpreter tcgenerate(ResizeNearestNeighbor_000) tcgenerate(ReverseSequence_000) tcgenerate(ReverseV2_000) @@ -148,7 +156,7 @@ tcgenerate(SpaceToBatchND_002) tcgenerate(SpaceToBatchND_003) tcgenerate(SpaceToDepth_000) tcgenerate(SparseToDense_000) -tcgenerate(SplitV_000) # fix luci +tcgenerate(SplitV_000) tcgenerate(Sqrt_000) tcgenerate(Square_000) tcgenerate(SquaredDifference_000) @@ -164,22 +172,21 @@ tcgenerate(Sum_001) tcgenerate(Tanh_000) tcgenerate(Tile_000) tcgenerate(Tile_U8_000) -tcgenerate(TopKV2_000) # fix luci -tcgenerate(TopKV2_001) # fix luci -tcgenerate(TransposeConv_000) # fix interpreter +tcgenerate(TopKV2_000) +tcgenerate(TopKV2_001) tcgenerate(Unique_000) tcgenerate(Unique_001) tcgenerate(Unique_002) tcgenerate(Unique_003) tcgenerate(Unique_U8_000) tcgenerate(Unique_U8_001) -tcgenerate(Where_000) # luci NYI -tcgenerate(Where_001) # luci NYI -tcgenerate(While_000) # fix luci +tcgenerate(Where_000) +tcgenerate(Where_001) +tcgenerate(While_000) tcgenerate(While_001) tcgenerate(While_002) tcgenerate(While_003) -tcgenerate(YUV_TO_RGB_000) # fix luci +tcgenerate(YUV_TO_RGB_000) tcgenerate(YUV_TO_RGB_U8_000) tcgenerate(ZerosLike_000) diff --git a/compiler/common-artifacts/requires.cmake b/compiler/common-artifacts/requires.cmake index 8c27565cf..d7bed21fe 100644 --- a/compiler/common-artifacts/requires.cmake +++ b/compiler/common-artifacts/requires.cmake @@ -1,3 +1,4 @@ +require("arser") require("circle2circle") require("circlechef") require("foder") diff --git a/compiler/common-artifacts/src/TestDataGenerator.cpp b/compiler/common-artifacts/src/TestDataGenerator.cpp index 739300d18..7a07dd88e 100644 --- a/compiler/common-artifacts/src/TestDataGenerator.cpp +++ b/compiler/common-artifacts/src/TestDataGenerator.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <arser/arser.h> #include <foder/FileLoader.h> #include <luci/Importer.h> #include <luci_interpreter/Interpreter.h> @@ -62,10 +63,9 @@ template <typename T> void geneate_random_data(std::mt19937 &gen, void *data, ui } } -void fill_random_data(void *data, uint32_t size, loco::DataType dtype) +void fill_random_data(void *data, uint32_t size, loco::DataType dtype, uint32_t seed) { - std::random_device rd; // used to obtain a seed for the random number engine - std::mt19937 gen(rd()); // standard mersenne_twister_engine seeded with rd() + std::mt19937 gen(seed); // standard mersenne_twister_engine seeded with rd() switch (dtype) { @@ -90,7 +90,25 @@ void fill_random_data(void *data, uint32_t size, loco::DataType dtype) int entry(int argc, char **argv) { - std::string circle_file{argv[1]}; + arser::Arser arser; + arser.add_argument("circle").type(arser::DataType::STR).help("Circle file you want to test"); + arser.add_argument("--fixed_seed") + .required(false) + .nargs(0) + .help("Put a fixed seed into the random number generator"); + + try + { + arser.parse(argc, argv); + } + catch (const std::runtime_error &err) + { + std::cout << err.what() << std::endl; + std::cout << arser; + return 255; + } + + std::string circle_file = arser.get<std::string>("circle"); size_t last_dot_index = circle_file.find_last_of("."); std::string prefix = circle_file.substr(0, last_dot_index); @@ -136,6 +154,7 @@ int entry(int argc, char **argv) std::unique_ptr<H5::Group> output_value_group = std::make_unique<H5::Group>(output_file.createGroup("value")); + std::random_device rd; // used to obtain a seed for the random number engine uint32_t input_index = 0; for (uint32_t g = 0; g < circle_model->subgraphs()->size(); g++) { @@ -174,7 +193,10 @@ int entry(int argc, char **argv) std::vector<int8_t> data(byte_size); // generate random data - fill_random_data(data.data(), data_size, input_node->dtype()); + if (arser["--fixed_seed"]) + fill_random_data(data.data(), data_size, input_node->dtype(), 0); + else + fill_random_data(data.data(), data_size, input_node->dtype(), rd()); dataset->write(data.data(), dtype); diff --git a/compiler/hermes/src/hermes.test.cpp b/compiler/hermes/src/hermes.test.cpp index 2cbc0939d..ea7ef65d8 100644 --- a/compiler/hermes/src/hermes.test.cpp +++ b/compiler/hermes/src/hermes.test.cpp @@ -18,7 +18,28 @@ #include <gtest/gtest.h> -TEST(HermesTest, simple_usecase) +namespace { - // TO BE FILLED + +class Logger final : public hermes::Source +{ +public: + Logger(hermes::Context *ctx); + ~Logger(); +}; + +Logger::Logger(hermes::Context *ctx) { activate(ctx->sources(), ctx->bus()); } +Logger::~Logger() { deactivate(); } + +} // namespace + +TEST(HermesTest, logger_constructor_NEG) +{ + hermes::Context context; + // we expect segmentfault from nullptr->sources() + ASSERT_DEATH(Logger logger(&context), ""); + + SUCCEED(); } + +// TODO add HermesTest simple_usecase diff --git a/compiler/locomotiv/src/Node/BiasEncode.test.cpp b/compiler/locomotiv/src/Node/BiasEncode.test.cpp index cdb255ccb..4680f5c5a 100644 --- a/compiler/locomotiv/src/Node/BiasEncode.test.cpp +++ b/compiler/locomotiv/src/Node/BiasEncode.test.cpp @@ -90,6 +90,16 @@ template <typename T> void test() } } // namespace -TEST(NodeExecution_BiasEncode, s32) { test<int32_t>(); } +TEST(NodeExecution_BiasEncode, s32) +{ + test<int32_t>(); + + SUCCEED(); +} -TEST(NodeExecution_BiasEncode, f32) { test<float>(); } +TEST(NodeExecution_BiasEncode, f32) +{ + test<float>(); + + SUCCEED(); +} diff --git a/compiler/locomotiv/src/Node/MatMul.test.cpp b/compiler/locomotiv/src/Node/MatMul.test.cpp index f1f3a52d3..7d942e1d0 100644 --- a/compiler/locomotiv/src/Node/MatMul.test.cpp +++ b/compiler/locomotiv/src/Node/MatMul.test.cpp @@ -142,6 +142,8 @@ TEST(NodeExecution_MatMul, f32_2x3_3x3) }; run_test<float>(lhs, rhs, out, Shape{2, 3}, Shape{3, 3}, Shape{2, 3}, loco::DataType::FLOAT32); + + SUCCEED(); } /* from the code below: @@ -183,6 +185,8 @@ TEST(NodeExecution_MatMul, s32_4x2_2x6) }; run_test<int32_t>(lhs, rhs, out, Shape{4, 2}, Shape{2, 6}, Shape{4, 6}, loco::DataType::S32); + + SUCCEED(); } // clang-format on diff --git a/compiler/locop/src/FormattedGraph.test.cpp b/compiler/locop/src/FormattedGraph.test.cpp index c9808d3a2..aff9ebe5f 100644 --- a/compiler/locop/src/FormattedGraph.test.cpp +++ b/compiler/locop/src/FormattedGraph.test.cpp @@ -28,6 +28,8 @@ TEST(LinearV1FormatterTest, simple) // TODO Validate the output (when the implementation becomes stable) std::cout << locop::fmt<locop::LinearV1>(g) << std::endl; + + SUCCEED(); } TEST(LinearV1FormatterTest, user_defined_node_summary_builder) diff --git a/compiler/locop/src/FormattedTensorShape.test.cpp b/compiler/locop/src/FormattedTensorShape.test.cpp index 0f0017ab4..fc85df3a6 100644 --- a/compiler/locop/src/FormattedTensorShape.test.cpp +++ b/compiler/locop/src/FormattedTensorShape.test.cpp @@ -30,4 +30,6 @@ TEST(FormattedTensorShapeTest, BracketFormat) tensor_shape->dim(0) = 4; std::cout << fmt<TensorShapeFormat::Bracket>(tensor_shape.get()) << std::endl; + + SUCCEED(); } diff --git a/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h b/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h index 998789882..4ac3d8660 100644 --- a/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h +++ b/compiler/luci-interpreter/include/luci_interpreter/core/Tensor.h @@ -79,12 +79,11 @@ private: // // Note that due to historical and performance reasons, per-tensor quantization uses unsigned // integer types, while per-channel uses signed types assuming 'zero_point' == 0. -// -// TODO Add 'quantized_dimension' field for per-channel case when IR provides it. struct AffineQuantization { std::vector<float> scale; std::vector<int32_t> zero_point; + int32_t quantized_dimension; }; class Tensor @@ -108,6 +107,12 @@ public: return _quantization.zero_point[0]; } + const std::vector<float> &scales() const { return _quantization.scale; } + + const std::vector<int32_t> &zero_points() const { return _quantization.zero_point; } + + int32_t quantized_dimension() const { return _quantization.quantized_dimension; } + template <typename T> const T *data() const { return reinterpret_cast<const T *>(_data.get()); } template <typename T> T *data() { return reinterpret_cast<T *>(_data.get()); } diff --git a/compiler/luci-interpreter/src/core/KernelParams.h b/compiler/luci-interpreter/src/core/KernelParams.h index a32e0d4a5..65d119761 100644 --- a/compiler/luci-interpreter/src/core/KernelParams.h +++ b/compiler/luci-interpreter/src/core/KernelParams.h @@ -56,6 +56,11 @@ struct Conv2DParams Activation activation; }; +struct DepthToSpaceParams +{ + int block_size; +}; + struct DepthwiseConv2DParams { Padding padding; diff --git a/compiler/luci-interpreter/src/kernels/Add.cpp b/compiler/luci-interpreter/src/kernels/Add.cpp index 9b9334792..9ed155e94 100644 --- a/compiler/luci-interpreter/src/kernels/Add.cpp +++ b/compiler/luci-interpreter/src/kernels/Add.cpp @@ -36,7 +36,10 @@ Add::Add(const Tensor *input1, const Tensor *input2, Tensor *output, const AddPa void Add::configure() { - assert(input1()->element_type() == input2()->element_type()); + if (input1()->element_type() != input2()->element_type()) + { + throw std::runtime_error("Input Tensor Data Type Mismatch."); + } output()->resize(calculateShapeForBroadcast(input1()->shape(), input2()->shape())); } diff --git a/compiler/luci-interpreter/src/kernels/Add.test.cpp b/compiler/luci-interpreter/src/kernels/Add.test.cpp index 54e1cc672..705b648c8 100644 --- a/compiler/luci-interpreter/src/kernels/Add.test.cpp +++ b/compiler/luci-interpreter/src/kernels/Add.test.cpp @@ -169,6 +169,33 @@ TEST(AddTest, Float) } } +TEST(AddTest, Input_Output_Type_NEG) +{ + Tensor input1_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); + Tensor input2_tensor = makeInputTensor<DataType::S32>({1}, {2}); + Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); + + AddParams params{}; + params.activation = Activation::RELU; + + Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); + EXPECT_ANY_THROW(kernel.configure()); +} + +TEST(AddTest, Invalid_Input_Type_NEG) +{ + Tensor input1_tensor = makeInputTensor<DataType::S64>({1}, {1}); + Tensor input2_tensor = makeInputTensor<DataType::S64>({1}, {2}); + Tensor output_tensor = makeOutputTensor(DataType::S64); + + AddParams params{}; + params.activation = Activation::RELU; + + Add kernel(&input1_tensor, &input2_tensor, &output_tensor, params); + kernel.configure(); + EXPECT_ANY_THROW(kernel.execute()); +} + } // namespace } // namespace kernels } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/CMakeLists.txt b/compiler/luci-interpreter/src/kernels/CMakeLists.txt index fe3623135..a1fd1deaf 100644 --- a/compiler/luci-interpreter/src/kernels/CMakeLists.txt +++ b/compiler/luci-interpreter/src/kernels/CMakeLists.txt @@ -12,6 +12,8 @@ set(SOURCES Concatenation.cpp Conv2D.h Conv2D.cpp + DepthToSpace.h + DepthToSpace.cpp DepthwiseConv2D.h DepthwiseConv2D.cpp Elu.h @@ -40,6 +42,10 @@ set(SOURCES Pad.cpp Reshape.h Reshape.cpp + Reverse.h + Reverse.cpp + Slice.h + Slice.cpp Softmax.h Softmax.cpp SpaceToDepth.h @@ -77,6 +83,7 @@ set(TEST_SOURCES AveragePool2D.test.cpp Concatenation.test.cpp Conv2D.test.cpp + DepthToSpace.test.cpp DepthwiseConv2D.test.cpp Elu.test.cpp FullyConnected.test.cpp @@ -91,6 +98,8 @@ set(TEST_SOURCES Mul.test.cpp Pad.test.cpp Reshape.test.cpp + Reverse.test.cpp + Slice.test.cpp Softmax.test.cpp SpaceToDepth.test.cpp Split.test.cpp diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp b/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp new file mode 100644 index 000000000..cab63e26d --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/DepthToSpace.cpp @@ -0,0 +1,90 @@ +/* + * 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 "DepthToSpace.h" +#include "Utils.h" +#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> + +namespace luci_interpreter +{ +namespace kernels +{ + +DepthToSpace::DepthToSpace(const Tensor *input, Tensor *output, const DepthToSpaceParams ¶ms) + : KernelWithParams<DepthToSpaceParams>({input}, {output}, params) +{ +} + +void DepthToSpace::configure() +{ + if (input()->shape().num_dims() != 4) + { + throw std::runtime_error("Invalid input num_dims."); + } + if (output()->element_type() != DataType::FLOAT32 && output()->element_type() != DataType::U8 && + output()->element_type() != DataType::S8 && output()->element_type() != DataType::S32 && + output()->element_type() != DataType::S64) + { + throw std::runtime_error("Invalid output type"); + } + if (input()->element_type() != output()->element_type()) + { + throw std::runtime_error("Type mismatch on input and output."); + } + const int block_size = params().block_size; + const int32_t input_height = input()->shape().dim(1); + const int32_t input_width = input()->shape().dim(2); + const int32_t input_channels = input()->shape().dim(3); + int32_t output_height = input_height * block_size; + int32_t output_width = input_width * block_size; + int32_t output_channels = input_channels / block_size / block_size; + + assert(input_height == output_height / block_size); + assert(input_width == output_width / block_size); + assert(input_channels == output_channels * block_size * block_size); + + Shape output_shape(4); + output_shape.dim(0) = input()->shape().dim(0); + output_shape.dim(1) = output_height; + output_shape.dim(2) = output_width; + output_shape.dim(3) = output_channels; + + output()->resize(output_shape); +} + +void DepthToSpace::execute() const +{ + tflite::DepthToSpaceParams op_params; + op_params.block_size = params().block_size; + switch (input()->element_type()) + { + case DataType::FLOAT32: + tflite::optimized_ops::DepthToSpace(op_params, getTensorShape(input()), + getTensorData<float>(input()), getTensorShape(output()), + getTensorData<float>(output())); + break; + case DataType::U8: + tflite::optimized_ops::DepthToSpace(op_params, getTensorShape(input()), + getTensorData<uint8_t>(input()), getTensorShape(output()), + getTensorData<uint8_t>(output())); + break; + default: + throw std::runtime_error("Unsupported Type."); + } +} + +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.h b/compiler/luci-interpreter/src/kernels/DepthToSpace.h new file mode 100644 index 000000000..63ce37610 --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/DepthToSpace.h @@ -0,0 +1,45 @@ +/* + * 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 LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H +#define LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H + +#include "core/Kernel.h" +#include "core/KernelParams.h" + +#include <vector> + +namespace luci_interpreter +{ +namespace kernels +{ + +class DepthToSpace : public KernelWithParams<DepthToSpaceParams> +{ +public: + DepthToSpace(const Tensor *input, Tensor *output, const DepthToSpaceParams ¶ms); + + const Tensor *input() const { return _inputs[0]; } + Tensor *output() const { return _outputs[0]; } + + void configure() override; + void execute() const override; +}; + +} // namespace kernels +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_KERNELS_DEPTHTOSPACE_H diff --git a/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp b/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp new file mode 100644 index 000000000..1b805702d --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/DepthToSpace.test.cpp @@ -0,0 +1,60 @@ +/* + * 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 "kernels/DepthToSpace.h" +#include "kernels/TestUtils.h" + +namespace luci_interpreter +{ +namespace kernels +{ +namespace +{ + +using namespace testing; + +template <typename T> class DepthToSpaceTest : public ::testing::Test +{ +}; + +using DataTypes = ::testing::Types<float, uint8_t>; +TYPED_TEST_CASE(DepthToSpaceTest, DataTypes); + +TYPED_TEST(DepthToSpaceTest, SimpleCase) +{ + std::vector<TypeParam> input_data{1, 2, 3, 4, 5, 6, 7, 8}; + Shape input_shape{1, 1, 2, 4}; + std::vector<TypeParam> output_data{1, 2, 5, 6, 3, 4, 7, 8}; + std::vector<int32_t> output_shape{1, 2, 4, 1}; + + Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); + Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); + + DepthToSpaceParams params{}; + params.block_size = 2; + + DepthToSpace kernel = DepthToSpace(&input_tensor, &output_tensor, params); + kernel.configure(); + kernel.execute(); + + EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), + ::testing::ElementsAreArray(output_data)); + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); +} + +} // namespace +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp b/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp index fad450d66..f53eaca94 100644 --- a/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp +++ b/compiler/luci-interpreter/src/kernels/L2Normalize.test.cpp @@ -45,12 +45,9 @@ TEST(L2NormalizeTest, Float) ElementsAreArray(ArrayFloatNear(ref_output_data))); } -TEST(L2NormalizeTest, Uint8Quantized) -{ - // TODO - // Implement GetDequantizedOutput Function. - // Create Test for Uint8 Case -} +// TODO Uint8Quantized +// Implement GetDequantizedOutput Function. +// Create Test for Uint8 Case } // namespace } // namespace kernels diff --git a/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp b/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp index b0c06e7a3..c79d3d6bc 100644 --- a/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp +++ b/compiler/luci-interpreter/src/kernels/LeakyRelu.test.cpp @@ -61,15 +61,14 @@ TEST(LeakReluTest, FloatSimple) 1.0f, -0.5f, -1.0f, // Row 2 }, /*alpha=*/0.5f, getElementType<float>()); -} -TEST(LeakReluTest, Uint8Simple) -{ - // TODO - // Implement GetDequantizedOutput Function. - // Create Test for Uint8 Case + SUCCEED(); } +// TODO Uint8Simple +// Implement GetDequantizedOutput Function. +// Create Test for Uint8 Case + } // namespace } // namespace kernels } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Logistic.test.cpp b/compiler/luci-interpreter/src/kernels/Logistic.test.cpp index 17456a4a8..00feddf3d 100644 --- a/compiler/luci-interpreter/src/kernels/Logistic.test.cpp +++ b/compiler/luci-interpreter/src/kernels/Logistic.test.cpp @@ -49,10 +49,8 @@ TEST(LogisticTest, Float) // TODO make a Shape checking of output_tensor. } -TEST(LogisticTest, Uint8) -{ - // Need to Implement GetDequantizedOutput Function. -} +// TODO Uint8 +// Need to Implement GetDequantizedOutput Function. } // namespace } // namespace kernels diff --git a/compiler/luci-interpreter/src/kernels/Reverse.cpp b/compiler/luci-interpreter/src/kernels/Reverse.cpp new file mode 100644 index 000000000..a46308412 --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Reverse.cpp @@ -0,0 +1,81 @@ +/* + * 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 "kernels/Reverse.h" +#include "kernels/Utils.h" +#include <tensorflow/lite/kernels/internal/reference/reference_ops.h> + +namespace luci_interpreter +{ + +namespace kernels +{ + +Reverse::Reverse(const Tensor *input, const Tensor *axes, Tensor *output) + : Kernel({input, axes}, {output}) +{ +} + +void Reverse::configure() +{ + assert(axes()->shape().num_dims() == 1); + assert(input()->shape().num_dims() >= axes()->shape().num_elements()); + if (input()->element_type() != DataType::S32 && input()->element_type() != DataType::FLOAT32 && + input()->element_type() != DataType::U8 && input()->element_type() != DataType::S16 && + input()->element_type() != DataType::S64) + { + throw std::runtime_error("Unsupported input type."); + } + if (axes()->element_type() != DataType::S32) + { + throw std::runtime_error("Unsupported axes type."); + } + if (axes()->shape().num_elements() > 1) + { + throw std::runtime_error("Current implementation does not support more than 1 axis."); + } + int axis_value = getTensorData<int32_t>(axes())[0]; + if (axis_value < 0 || axis_value >= input()->shape().num_dims()) + { + throw std::runtime_error("Invalid axes value"); + } + assert(input()->element_type() == output()->element_type()); + + output()->resize(input()->shape()); +} + +void Reverse::execute() const +{ + int axis_value = getTensorData<int32_t>(axes())[0]; + switch (output()->element_type()) + { + case DataType::FLOAT32: + tflite::reference_ops::Reverse<float>(axis_value, getTensorShape(input()), + getTensorData<float>(input()), getTensorShape(output()), + getTensorData<float>(output())); + break; + case DataType::U8: + tflite::reference_ops::Reverse<uint8_t>( + axis_value, getTensorShape(input()), getTensorData<uint8_t>(input()), + getTensorShape(output()), getTensorData<uint8_t>(output())); + break; + default: + throw std::runtime_error("Unsupported output type"); + } +} + +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Reverse.h b/compiler/luci-interpreter/src/kernels/Reverse.h new file mode 100644 index 000000000..3489dae28 --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Reverse.h @@ -0,0 +1,43 @@ +/* + * 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 LUCI_INTERPRETER_KERNELS_REVERSE_H +#define LUCI_INTERPRETER_KERNELS_REVERSE_H + +#include "core/Kernel.h" + +namespace luci_interpreter +{ +namespace kernels +{ + +class Reverse : public Kernel +{ +public: + Reverse(const Tensor *input, const Tensor *axes, Tensor *output); + + const Tensor *input() const { return _inputs[0]; } + const Tensor *axes() const { return _inputs[1]; } + Tensor *output() const { return _outputs[0]; } + + void configure() override; + void execute() const override; +}; + +} // namespace kernels +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_KERNELS_REVERSE_H diff --git a/compiler/luci-interpreter/src/kernels/Reverse.test.cpp b/compiler/luci-interpreter/src/kernels/Reverse.test.cpp new file mode 100644 index 000000000..5475a8bd3 --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Reverse.test.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2017 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kernels/Reverse.h" +#include "kernels/TestUtils.h" + +namespace luci_interpreter +{ +namespace kernels +{ +namespace +{ + +using namespace testing; + +template <typename T> class ReverseTest : public ::testing::Test +{ +}; + +using DataTypes = ::testing::Types<float, uint8_t>; +TYPED_TEST_CASE(ReverseTest, DataTypes); + +TYPED_TEST(ReverseTest, MultiDimensions) +{ + // TypeParam + std::vector<TypeParam> input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + Shape input_shape{4, 3, 2}; + std::vector<int32_t> axis_data{1}; + Shape axis_shape{1}; + + std::vector<TypeParam> output_data{5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; + std::vector<int32_t> output_shape{4, 3, 2}; + + Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); + Tensor axis_tensor = makeInputTensor<DataType::S32>(axis_shape, axis_data); + + Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); + + Reverse kernel = Reverse(&input_tensor, &axis_tensor, &output_tensor); + kernel.configure(); + kernel.execute(); + + EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), + ::testing::ElementsAreArray(output_data)); + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); +} + +} // namespace +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Slice.cpp b/compiler/luci-interpreter/src/kernels/Slice.cpp new file mode 100644 index 000000000..c4bc3c57c --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Slice.cpp @@ -0,0 +1,149 @@ +/* + * 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 "kernels/Slice.h" +#include "Utils.h" +#include <tensorflow/lite/kernels/internal/optimized/optimized_ops.h> + +#include <cassert> +#include <cstring> + +namespace luci_interpreter +{ + +namespace kernels +{ +const int max_dim = 4; + +Slice::Slice(const Tensor *input, const Tensor *begin, const Tensor *size, Tensor *output) + : Kernel({input, begin, size}, {output}) +{ +} + +template <typename T> +Shape calculateOutputShape(const Tensor *input, const Tensor *begin, const Tensor *size) +{ + Shape output_shape = Shape(input->shape().num_dims()); + for (int idx = 0; idx < input->shape().num_dims(); idx++) + { + T size_value = getTensorData<T>(size)[idx]; + if (size_value < 0) + { + if (size_value != -1) + { + throw std::runtime_error("Invalid size."); + } + size_value = input->shape().dim(idx) - getTensorData<T>(begin)[idx]; + } + else + { + if (input->shape().dim(idx) < getTensorData<T>(begin)[idx] + size_value) + { + throw std::runtime_error("Invalid begin and size."); + } + } + output_shape.dim(idx) = static_cast<int>(size_value); + } + return output_shape; +} + +template <typename T> +void getBeginAndSizeVectors(int dimensions, const Tensor *begin, const Tensor *size, + std::vector<int> *begins, std::vector<int> *sizes) +{ + for (int idx = dimensions - 1; idx >= 0; --idx) + { + begins->push_back(getTensorData<T>(begin)[idx]); + sizes->push_back(getTensorData<T>(size)[idx]); + } +} + +void Slice::configure() +{ + assert(input()->element_type() == output()->element_type()); + assert(begin()->element_type() == DataType::S32 || begin()->element_type() == DataType::S64); + assert(size()->element_type() == DataType::S32 || size()->element_type() == DataType::S64); + assert(begin()->shape().num_dims() == 1); + assert(size()->shape().num_dims() == 1); + assert(input()->shape().num_dims() <= max_dim); + + if (begin()->element_type() == DataType::S32) + { + output()->resize(calculateOutputShape<int32_t>(input(), begin(), size())); + } + else if (begin()->element_type() == DataType::S64) + { + output()->resize(calculateOutputShape<int64_t>(input(), begin(), size())); + } + else + { + throw std::runtime_error("Unsupported type."); + } +} + +void Slice::execute() const +{ + std::vector<int> begins; + begins.reserve(max_dim); + std::vector<int> sizes; + sizes.reserve(max_dim); + if (begin()->element_type() == DataType::S32) + { + getBeginAndSizeVectors<int32_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes); + } + else if (begin()->element_type() == DataType::S64) + { + getBeginAndSizeVectors<int64_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes); + } + else + { + throw std::runtime_error("Unsupported begin type."); + } + for (int i = input()->shape().num_dims(); i < max_dim; ++i) + { + begins.push_back(0); + sizes.push_back(1); + } + + assert(begins.size() == 4); + assert(sizes.size() == 4); + tflite::SliceParams op_params{}; + op_params.begin_count = 4; + op_params.size_count = 4; + for (int i = 0; i < 4; i++) + { + op_params.begin[i] = begins[3 - i]; + op_params.size[i] = sizes[3 - i]; + } + switch (input()->element_type()) + { + case DataType::FLOAT32: + tflite::optimized_ops::Slice(op_params, getTensorShape(input()), + getTensorData<float>(input()), getTensorShape(output()), + getTensorData<float>(output())); + break; + case DataType::U8: + tflite::optimized_ops::Slice(op_params, getTensorShape(input()), + getTensorData<uint8_t>(input()), getTensorShape(output()), + getTensorData<uint8_t>(output())); + break; + default: + throw std::runtime_error("Unsupported input type."); + } +} + +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Slice.h b/compiler/luci-interpreter/src/kernels/Slice.h new file mode 100644 index 000000000..23c359608 --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Slice.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 LUCI_INTERPRETER_KERNELS_SLICE_H +#define LUCI_INTERPRETER_KERNELS_SLICE_H + +#include "core/Kernel.h" + +namespace luci_interpreter +{ +namespace kernels +{ + +class Slice : public Kernel +{ +public: + Slice(const Tensor *input, const Tensor *begin, const Tensor *size, Tensor *output); + + const Tensor *input() const { return _inputs[0]; } + const Tensor *begin() const { return _inputs[1]; } + const Tensor *size() const { return _inputs[2]; } + Tensor *output() const { return _outputs[0]; } + + void configure() override; + void execute() const override; +}; + +} // namespace kernels +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_KERNELS_SLICE_H diff --git a/compiler/luci-interpreter/src/kernels/Slice.test.cpp b/compiler/luci-interpreter/src/kernels/Slice.test.cpp new file mode 100644 index 000000000..a360a29cc --- /dev/null +++ b/compiler/luci-interpreter/src/kernels/Slice.test.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 "kernels/Slice.h" +#include "kernels/TestUtils.h" + +namespace luci_interpreter +{ +namespace kernels +{ +namespace +{ + +using namespace testing; + +template <typename T> class SliceTest : public ::testing::Test +{ +}; + +using DataTypes = ::testing::Types<float, uint8_t>; +TYPED_TEST_CASE(SliceTest, DataTypes); + +TYPED_TEST(SliceTest, SimpleTest) +{ + std::vector<TypeParam> input_data{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}; + Shape input_shape{3, 2, 3, 1}; + std::vector<int32_t> begin_data{1, 0, 0, 0}; + Shape begin_shape{4}; + std::vector<int32_t> size_data{2, 1, -1, 1}; + Shape size_shape{4}; + std::vector<TypeParam> output_data{3, 3, 3, 5, 5, 5}; + std::vector<int32_t> output_shape{2, 1, 3, 1}; + + Tensor input_tensor = makeInputTensor<getElementType<TypeParam>()>(input_shape, input_data); + Tensor begin_tensor = makeInputTensor<DataType::S32>(begin_shape, begin_data); + Tensor size_tensor = makeInputTensor<DataType::S32>(size_shape, size_data); + + Tensor output_tensor = makeOutputTensor(getElementType<TypeParam>()); + + Slice kernel(&input_tensor, &begin_tensor, &size_tensor, &output_tensor); + kernel.configure(); + kernel.execute(); + + EXPECT_THAT(extractTensorData<TypeParam>(output_tensor), + ::testing::ElementsAreArray(output_data)); + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); +} + +} // namespace +} // namespace kernels +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp b/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp index 3386d3683..b8c0ac497 100644 --- a/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp +++ b/compiler/luci-interpreter/src/kernels/TransposeConv.test.cpp @@ -68,6 +68,8 @@ TEST(TransposeConvTest, FloatSimple) /*output_data=*/{29, 62, 83, 75, 99, 192, 237, 198, 207, 372, 417, 330, 263, 446, 485, 365}, /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1, getElementType<float>()); + + SUCCEED(); } TEST(TransposeConvTest, FloatTwoFiltersTest) @@ -82,21 +84,18 @@ TEST(TransposeConvTest, FloatTwoFiltersTest) 3352, 3652, 2760}, /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1, getElementType<float>()); -} -TEST(TransposeConvTest, Uint8Simple) -{ - // TODO - // Implement GetDequantizedOutput Function. - // Create Test for Uint8 Case -} -TEST(TransposeConvTest, Uint8FiltersTest) -{ - // TODO - // Implement GetDequantizedOutput Function. - // Create Test for Uint8 Case + SUCCEED(); } +// TODO Uint8Simple +// Implement GetDequantizedOutput Function. +// Create Test for Uint8 Case + +// TODO Uint8FiltersTest +// Implement GetDequantizedOutput Function. +// Create Test for Uint8 Case + } // namespace } // namespace kernels } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/CMakeLists.txt b/compiler/luci-interpreter/src/loader/CMakeLists.txt index fb36c4ab0..d99485d06 100644 --- a/compiler/luci-interpreter/src/loader/CMakeLists.txt +++ b/compiler/luci-interpreter/src/loader/CMakeLists.txt @@ -1,3 +1,5 @@ +nnas_find_package(GTest REQUIRED) + set(SOURCES GraphLoader.h GraphLoader.cpp @@ -13,3 +15,8 @@ target_include_directories(luci_interpreter_loader PUBLIC "${LUCI_INTERPRETER_SO target_link_libraries(luci_interpreter_loader PUBLIC luci_lang luci_interpreter_core PRIVATE luci_interpreter_kernels nncc_common) + +set(TEST_SOURCES KernelBuilder.test.cpp) + +GTest_AddTest(luci_interpreter_loader_test ${TEST_SOURCES}) +target_link_libraries(luci_interpreter_loader_test luci_interpreter_loader) diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.cpp b/compiler/luci-interpreter/src/loader/GraphLoader.cpp index 779fa0647..95c654769 100644 --- a/compiler/luci-interpreter/src/loader/GraphLoader.cpp +++ b/compiler/luci-interpreter/src/loader/GraphLoader.cpp @@ -16,7 +16,6 @@ #include "loader/GraphLoader.h" -#include "loader/ModuleLoader.h" #include "loader/KernelBuilder.h" #include <loco/IR/Algorithm.h> @@ -70,9 +69,10 @@ bool isExecutableNode(const luci::CircleNode *node) switch (node->opcode()) { // These nodes denote inputs / outputs of a graph. - case luci::CircleOpcode::CONST: + case luci::CircleOpcode::CIRCLECONST: case luci::CircleOpcode::CIRCLEINPUT: case luci::CircleOpcode::CIRCLEOUTPUT: + case luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE: // The following nodes denote outputs of multiple-output nodes. case luci::CircleOpcode::CIRCLEIFOUT: case luci::CircleOpcode::CIRCLESPLITOUT: @@ -102,11 +102,12 @@ bool isTensorProducingNode(const luci::CircleNode *node) } // namespace -GraphLoader::GraphLoader(const ModuleLoader &module_loader, const loco::Graph *graph, - RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _module_loader(module_loader), _graph(graph), _runtime_graph(runtime_graph), - _runtime_to_ir(runtime_to_ir), _node_to_tensor(node_to_tensor) +GraphLoader::GraphLoader( + const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) + : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir), + _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) { } @@ -136,6 +137,7 @@ void GraphLoader::loadTensors() const luci::CircleQuantParam *params = node->quantparam(); quantization.scale.assign(params->scale.cbegin(), params->scale.cend()); quantization.zero_point.assign(params->zerop.cbegin(), params->zerop.cend()); + quantization.quantized_dimension = params->quantized_dimension; } auto tensor = std::make_unique<Tensor>(node->dtype(), std::move(shape), std::move(quantization), @@ -178,7 +180,7 @@ void GraphLoader::initInputOutputTensors() const void GraphLoader::loadOperators() { - KernelBuilder kernel_builder(_module_loader, *this); + KernelBuilder kernel_builder(_graph_to_runtime_graph, _node_to_tensor); // Create kernels for executable nodes. This has to be done in execution order. for (const loco::Node *loco_node : @@ -195,11 +197,4 @@ void GraphLoader::loadOperators() } } -void GraphLoader::load() -{ - loadTensors(); - initInputOutputTensors(); - loadOperators(); -} - } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.h b/compiler/luci-interpreter/src/loader/GraphLoader.h index e0adc0f6c..89c5bcad7 100644 --- a/compiler/luci-interpreter/src/loader/GraphLoader.h +++ b/compiler/luci-interpreter/src/loader/GraphLoader.h @@ -27,29 +27,23 @@ namespace luci_interpreter { -class ModuleLoader; - class GraphLoader { public: - GraphLoader(const ModuleLoader &module_loader, const loco::Graph *graph, - RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, + GraphLoader(const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); - void load(); - - Tensor *getTensorForNode(const loco::Node *node) const { return _node_to_tensor.at(node); } - -private: - void loadOperators(); - void initInputOutputTensors() const; void loadTensors(); + void initInputOutputTensors() const; + void loadOperators(); - const ModuleLoader &_module_loader; +private: const loco::Graph *_graph; RuntimeGraph *_runtime_graph; RuntimeToIR &_runtime_to_ir; + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; }; diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp index 56da961dd..12c7f4526 100644 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp @@ -21,6 +21,7 @@ #include "kernels/AveragePool2D.h" #include "kernels/Concatenation.h" #include "kernels/Conv2D.h" +#include "kernels/DepthToSpace.h" #include "kernels/DepthwiseConv2D.h" #include "kernels/Elu.h" #include "kernels/FullyConnected.h" @@ -35,6 +36,8 @@ #include "kernels/Mul.h" #include "kernels/Pad.h" #include "kernels/Reshape.h" +#include "kernels/Reverse.h" +#include "kernels/Slice.h" #include "kernels/Softmax.h" #include "kernels/SpaceToDepth.h" #include "kernels/Split.h" @@ -43,8 +46,6 @@ #include "kernels/Unpack.h" #include "kernels/Transpose.h" #include "kernels/TransposeConv.h" -#include "loader/GraphLoader.h" -#include "loader/ModuleLoader.h" #include <stdexcept> @@ -68,20 +69,23 @@ static std::vector<const loco::Node *> collectOutputNodes(const luci::CircleNode const Tensor *KernelBuilder::getInputTensor(const loco::Node *node) const { - const Tensor *tensor = _graph_loader.getTensorForNode(node); + const Tensor *tensor = _node_to_tensor.at(node); assert(tensor != nullptr); return tensor; } const Tensor *KernelBuilder::getOptionalInputTensor(const loco::Node *node) const { - // TODO Revise this when optional inputs are implemented in the IR. + if (dynamic_cast<const luci::CircleOutputExclude *>(node)) + { + return nullptr; + } return getInputTensor(node); } Tensor *KernelBuilder::getOutputTensor(const loco::Node *node) const { - Tensor *tensor = _graph_loader.getTensorForNode(node); + Tensor *tensor = _node_to_tensor.at(node); assert(tensor != nullptr); return tensor; } @@ -98,7 +102,7 @@ KernelBuilder::getOutputTensors(const std::vector<const loco::Node *> &nodes) co RuntimeGraph *KernelBuilder::getRuntimeGraph(const loco::Graph *graph) const { - RuntimeGraph *runtime_graph = _module_loader.getRuntimeGraph(graph); + RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); assert(runtime_graph != nullptr); return runtime_graph; } @@ -120,14 +124,14 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAdd *node) std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleArgMax *node) { assert(node->arity() == 2); - const Tensor *input1 = getInputTensor(node->input()); - const Tensor *input2 = getInputTensor(node->dimension()); + const Tensor *input = getInputTensor(node->input()); + const Tensor *axis = getInputTensor(node->dimension()); Tensor *output = getOutputTensor(node); ArgMaxParams params{}; params.output_type = node->output_type(); - return std::make_unique<kernels::ArgMax>(input1, input2, output, params); + return std::make_unique<kernels::ArgMax>(input, axis, output, params); } std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAveragePool2D *node) @@ -188,6 +192,19 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConv2D *node) return std::make_unique<kernels::Conv2D>(input, filter, bias, output, params); } +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthToSpace *node) +{ + assert(node->arity() == 1); + + const Tensor *input = getInputTensor(node->input()); + Tensor *output = getOutputTensor(node); + + DepthToSpaceParams params{}; + params.block_size = node->block_size(); + + return std::make_unique<kernels::DepthToSpace>(input, output, params); +} + std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthwiseConv2D *node) { assert(node->arity() == 3); @@ -224,14 +241,14 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFullyConnected *n assert(node->arity() == 3); const Tensor *input = getInputTensor(node->input()); - const Tensor *filter = getInputTensor(node->weights()); + const Tensor *weights = getInputTensor(node->weights()); const Tensor *bias = getOptionalInputTensor(node->bias()); Tensor *output = getOutputTensor(node); FullyConnectedParams params{}; params.activation = node->fusedActivationFunction(); - return std::make_unique<kernels::FullyConnected>(input, filter, bias, output, params); + return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params); } std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node) @@ -255,6 +272,11 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node) else_graph); } +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *) +{ + throw std::runtime_error("Input node cannot be executed."); +} + std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Normalize *node) { assert(node->arity() == 1); @@ -323,11 +345,6 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogistic *node) return std::make_unique<kernels::Logistic>(input, output); } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *) -{ - throw std::runtime_error("Input node cannot be executed."); -} - std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaxPool2D *node) { assert(node->arity() == 1); @@ -402,6 +419,30 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReshape *node) return std::make_unique<kernels::Reshape>(input, shape, output); } +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReverseV2 *node) +{ + assert(node->arity() == 2); + + const Tensor *input = getInputTensor(node->tensor()); + const Tensor *axes = getInputTensor(node->axis()); + Tensor *output = getOutputTensor(node); + + return std::make_unique<kernels::Reverse>(input, axes, output); +} + +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSlice *node) +{ + assert(node->arity() == 3); + + const Tensor *input = getInputTensor(node->input()); + const Tensor *begin = getInputTensor(node->begin()); + const Tensor *size = getInputTensor(node->size()); + + Tensor *output = getOutputTensor(node); + + return std::make_unique<kernels::Slice>(input, begin, size, output); +} + std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSoftmax *node) { assert(node->arity() == 1); @@ -442,6 +483,19 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSplit *node) return std::make_unique<kernels::Split>(axis, input, std::move(outputs)); } +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node) +{ + assert(node->arity() == 1); + + const Tensor *input = getInputTensor(node->input()); + Tensor *output = getOutputTensor(node); + + SqueezeParams params{}; + params.squeeze_dims = node->squeeze_dims(); + + return std::make_unique<kernels::Squeeze>(input, output, params); +} + std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *node) { assert(node->arity() == 4); @@ -463,21 +517,15 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *nod return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params); } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node) +std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node) { - assert(node->arity() == 1); + assert(node->arity() == 2); - const Tensor *input = getInputTensor(node->input()); + const Tensor *input = getInputTensor(node->a()); + const Tensor *perm = getInputTensor(node->perm()); Tensor *output = getOutputTensor(node); - SqueezeParams params{}; - assert(node->squeeze_dims().size() <= 4); - for (size_t i = 0; i < node->squeeze_dims().size(); i++) - { - params.squeeze_dims.push_back(node->squeeze_dims().at(i)); - } - - return std::make_unique<kernels::Squeeze>(input, output, params); + return std::make_unique<kernels::Transpose>(input, perm, output); } std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTransposeConv *node) @@ -515,15 +563,4 @@ std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleUnpack *node) return std::make_unique<kernels::Unpack>(input, std::move(outputs), params); } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->a()); - const Tensor *perm = getInputTensor(node->perm()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Transpose>(input, perm, output); -} - } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.h b/compiler/luci-interpreter/src/loader/KernelBuilder.h index 7e30d395b..d5c5a4b56 100644 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.h +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.h @@ -24,18 +24,18 @@ #include <memory> #include <vector> +#include <unordered_map> namespace luci_interpreter { -class GraphLoader; -class ModuleLoader; - class KernelBuilder : public luci::CircleNodeVisitor<std::unique_ptr<Kernel>> { public: - KernelBuilder(const ModuleLoader &module_loader, const GraphLoader &graph_loader) - : _module_loader(module_loader), _graph_loader(graph_loader) + KernelBuilder( + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) + : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) { } @@ -45,6 +45,7 @@ public: std::unique_ptr<Kernel> visit(const luci::CircleConcatenation *node) override; std::unique_ptr<Kernel> visit(const luci::CircleConv2D *node) override; std::unique_ptr<Kernel> visit(const luci::CircleConst *node) override; + std::unique_ptr<Kernel> visit(const luci::CircleDepthToSpace *node) override; std::unique_ptr<Kernel> visit(const luci::CircleDepthwiseConv2D *node) override; std::unique_ptr<Kernel> visit(const luci::CircleElu *node) override; std::unique_ptr<Kernel> visit(const luci::CircleFullyConnected *node) override; @@ -61,6 +62,8 @@ public: std::unique_ptr<Kernel> visit(const luci::CircleOutput *node) override; std::unique_ptr<Kernel> visit(const luci::CirclePad *node) override; std::unique_ptr<Kernel> visit(const luci::CircleReshape *node) override; + std::unique_ptr<Kernel> visit(const luci::CircleReverseV2 *node) override; + std::unique_ptr<Kernel> visit(const luci::CircleSlice *node) override; std::unique_ptr<Kernel> visit(const luci::CircleSoftmax *node) override; std::unique_ptr<Kernel> visit(const luci::CircleSpaceToDepth *node) override; std::unique_ptr<Kernel> visit(const luci::CircleSplit *node) override; @@ -82,8 +85,8 @@ private: RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const; private: - const ModuleLoader &_module_loader; - const GraphLoader &_graph_loader; + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; + const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; }; } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp new file mode 100644 index 000000000..33bc8ec9b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp @@ -0,0 +1,743 @@ +/* + * 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 "loader/GraphLoader.h" +#include "loader/KernelBuilder.h" + +#include <kernels/Add.h> +#include <kernels/ArgMax.h> +#include <kernels/AveragePool2D.h> +#include <kernels/Concatenation.h> +#include <kernels/Conv2D.h> +#include <kernels/DepthToSpace.h> +#include <kernels/DepthwiseConv2D.h> +#include <kernels/Elu.h> +#include <kernels/FullyConnected.h> +#include <kernels/L2Normalize.h> +#include <kernels/L2Pool2D.h> +#include <kernels/LeakyRelu.h> +#include <kernels/LocalResponseNormalization.h> +#include <kernels/Logistic.h> +#include <kernels/MaxPool2D.h> +#include <kernels/Mean.h> +#include <kernels/Mul.h> +#include <kernels/Pad.h> +#include <kernels/Reshape.h> +#include <kernels/Reverse.h> +#include <kernels/Slice.h> +#include <kernels/Softmax.h> +#include <kernels/SpaceToDepth.h> +#include <kernels/Split.h> +#include <kernels/Squeeze.h> +#include <kernels/StridedSlice.h> +#include <kernels/Transpose.h> +#include <kernels/TransposeConv.h> +#include <kernels/Unpack.h> + +#include <gmock/gmock.h> + +namespace luci_interpreter +{ +namespace +{ + +using namespace testing; + +class KernelBuilderTest : public Test +{ +protected: + luci::CircleInput *createInputNode() { return createNode<luci::CircleInput>(); } + + template <typename NodeT, typename... Args> NodeT *createNode(Args &&... args) + { + auto *node = _graph.nodes()->create<NodeT>(std::forward<Args>(args)...); + // The actual type does not matter for the purpose of the tests. + // NOTE The type is meaningless for nodes with multiple outputs (corresponding *Out nodes carry + // actual output types). + node->dtype(loco::DataType::FLOAT32); + return node; + } + + template <typename NodeOutT> NodeOutT *createNodeOut(loco::Node *node, int index) + { + auto *node_out = createNode<NodeOutT>(); + node_out->input(node); + node_out->index(index); + return node_out; + } + + template <typename KernelT> std::unique_ptr<KernelT> buildKernel(const luci::CircleNode *op) + { + std::unordered_map<const loco::Graph *, RuntimeGraph *> graph_to_runtime_graph; + + RuntimeGraph runtime_graph(nullptr); + RuntimeToIR runtime_to_ir; + GraphLoader graph_loader(&_graph, &runtime_graph, runtime_to_ir, graph_to_runtime_graph, + _node_to_tensor); + graph_loader.loadTensors(); + + KernelBuilder kernel_builder(graph_to_runtime_graph, _node_to_tensor); + + auto kernel = op->accept(&kernel_builder); + return std::unique_ptr<KernelT>(dynamic_cast<KernelT *>(kernel.release())); + } + + void checkTensor(const Tensor *tensor, const loco::Node *node) + { + EXPECT_THAT(tensor, Eq(_node_to_tensor.at(node))); + } + +private: + loco::Graph _graph; + std::unordered_map<const loco::Node *, Tensor *> _node_to_tensor; +}; + +TEST_F(KernelBuilderTest, Add) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleAdd>(); + op->x(input1); + op->y(input2); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::Add>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, ArgMax) +{ + auto *input = createInputNode(); + auto *axis = createInputNode(); + + auto *op = createNode<luci::CircleArgMax>(); + op->input(input); + op->dimension(axis); + + op->output_type(loco::DataType::FLOAT32); + + auto kernel = buildKernel<kernels::ArgMax>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->axis(), axis); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().output_type, Eq(op->output_type())); +} + +TEST_F(KernelBuilderTest, AveragePool2D) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleAveragePool2D>(); + op->value(input); + + op->padding(luci::Padding::SAME); + op->filter()->h(11); + op->filter()->w(13); + op->stride()->h(17); + op->stride()->w(19); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::AveragePool2D>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); + EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, Concatenation) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleConcatenation>(2); + op->values(0, input1); + op->values(1, input2); + op->axis(11); + + auto kernel = buildKernel<kernels::Concatenation>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(0), input1); + checkTensor(kernel->input(1), input2); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().axis, Eq(op->axis())); +} + +TEST_F(KernelBuilderTest, Conv2D) +{ + auto *input = createInputNode(); + auto *filter = createInputNode(); + auto *bias = createInputNode(); + + auto *op = createNode<luci::CircleConv2D>(); + op->input(input); + op->filter(filter); + op->bias(bias); + + op->padding(luci::Padding::SAME); + op->stride()->h(11); + op->stride()->w(13); + op->dilation()->h(17); + op->dilation()->w(19); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::Conv2D>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->filter(), filter); + checkTensor(kernel->bias(), bias); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h())); + EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, DepthToSpace) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleDepthToSpace>(); + op->input(input); + + op->block_size(11); + + auto kernel = buildKernel<kernels::DepthToSpace>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().block_size, Eq(op->block_size())); +} + +TEST_F(KernelBuilderTest, DepthwiseConv2D) +{ + auto *input = createInputNode(); + auto *filter = createInputNode(); + auto *bias = createInputNode(); + + auto *op = createNode<luci::CircleDepthwiseConv2D>(); + op->input(input); + op->filter(filter); + op->bias(bias); + + op->padding(luci::Padding::SAME); + op->depthMultiplier(11); + op->stride()->h(13); + op->stride()->w(17); + op->dilation()->h(19); + op->dilation()->w(23); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::DepthwiseConv2D>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->filter(), filter); + checkTensor(kernel->bias(), bias); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().depth_multiplier, Eq(op->depthMultiplier())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().dilation_height_factor, Eq(op->dilation()->h())); + EXPECT_THAT(kernel->params().dilation_width_factor, Eq(op->dilation()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, Elu) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleElu>(); + op->features(input); + + auto kernel = buildKernel<kernels::Elu>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, FullyConnected) +{ + auto *input = createInputNode(); + auto *weights = createInputNode(); + auto *bias = createInputNode(); + + auto *op = createNode<luci::CircleFullyConnected>(); + op->input(input); + op->weights(weights); + op->bias(bias); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::FullyConnected>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->weights(), weights); + checkTensor(kernel->bias(), bias); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, L2Normalize) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleL2Normalize>(); + op->x(input); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::L2Normalize>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, L2Pool2D) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleL2Pool2D>(); + op->value(input); + + op->padding(luci::Padding::SAME); + op->filter()->h(11); + op->filter()->w(13); + op->stride()->h(17); + op->stride()->w(19); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::L2Pool2D>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); + EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, LeakyRelu) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleLeakyRelu>(); + op->features(input); + + op->alpha(11.0f); + + auto kernel = buildKernel<kernels::LeakyRelu>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().alpha, Eq(op->alpha())); +} + +TEST_F(KernelBuilderTest, LocalResponseNormalization) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleLocalResponseNormalization>(); + op->input(input); + + op->radius(11); + op->bias(13.0f); + op->alpha(15.0f); + op->beta(17.0f); + + auto kernel = buildKernel<kernels::LocalResponseNormalization>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().radius, Eq(op->radius())); + EXPECT_THAT(kernel->params().bias, Eq(op->bias())); + EXPECT_THAT(kernel->params().alpha, Eq(op->alpha())); + EXPECT_THAT(kernel->params().beta, Eq(op->beta())); +} + +TEST_F(KernelBuilderTest, Logistic) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleLogistic>(); + op->x(input); + + auto kernel = buildKernel<kernels::Logistic>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, MaxPool2D) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleMaxPool2D>(); + op->value(input); + + op->padding(luci::Padding::SAME); + op->filter()->h(11); + op->filter()->w(13); + op->stride()->h(17); + op->stride()->w(19); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::MaxPool2D>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().filter_height, Eq(op->filter()->h())); + EXPECT_THAT(kernel->params().filter_width, Eq(op->filter()->w())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, Mean) +{ + auto *input = createInputNode(); + auto *axes = createInputNode(); + + auto *op = createNode<luci::CircleMean>(); + op->input(input); + op->reduction_indices(axes); + + op->keep_dims(true); + + auto kernel = buildKernel<kernels::Mean>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->axes(), axes); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().keep_dims, Eq(op->keep_dims())); +} + +TEST_F(KernelBuilderTest, Mul) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleMul>(); + op->x(input1); + op->y(input2); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::Mul>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + +TEST_F(KernelBuilderTest, Pad) +{ + auto *input = createInputNode(); + auto *paddings = createInputNode(); + + auto *op = createNode<luci::CirclePad>(); + op->input(input); + op->paddings(paddings); + + auto kernel = buildKernel<kernels::Pad>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->paddings(), paddings); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Reshape) +{ + auto *input = createInputNode(); + auto *shape = createInputNode(); + + auto *op = createNode<luci::CircleReshape>(); + op->tensor(input); + op->shape(shape); + + auto kernel = buildKernel<kernels::Reshape>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->shape(), shape); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, ReverseV2) +{ + auto *input = createInputNode(); + auto *axes = createInputNode(); + + auto *op = createNode<luci::CircleReverseV2>(); + op->tensor(input); + op->axis(axes); + + auto kernel = buildKernel<kernels::Reverse>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->axes(), axes); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Slice) +{ + auto *input = createInputNode(); + auto *begin = createInputNode(); + auto *size = createInputNode(); + + auto *op = createNode<luci::CircleSlice>(); + op->input(input); + op->begin(begin); + op->size(size); + + auto kernel = buildKernel<kernels::Slice>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->begin(), begin); + checkTensor(kernel->size(), size); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Softmax) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleSoftmax>(); + op->logits(input); + + op->beta(11.0f); + + auto kernel = buildKernel<kernels::Softmax>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().beta, Eq(op->beta())); +} + +TEST_F(KernelBuilderTest, SpaceToDepth) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleSpaceToDepth>(); + op->input(input); + + op->block_size(11); + + auto kernel = buildKernel<kernels::SpaceToDepth>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().block_size, op->block_size()); +} + +TEST_F(KernelBuilderTest, Split) +{ + auto *axis = createInputNode(); + auto *input = createInputNode(); + auto *op = createNode<luci::CircleSplit>(); + auto *output1 = createNodeOut<luci::CircleSplitOut>(op, 0); + auto *output2 = createNodeOut<luci::CircleSplitOut>(op, 1); + + op->split_dim(axis); + op->input(input); + + op->num_split(2); + + auto kernel = buildKernel<kernels::Split>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->axis(), axis); + checkTensor(kernel->input(), input); + checkTensor(kernel->output(0), output1); + checkTensor(kernel->output(1), output2); +} + +TEST_F(KernelBuilderTest, Squeeze) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleSqueeze>(); + op->input(input); + + op->squeeze_dims({11, 13}); + + auto kernel = buildKernel<kernels::Squeeze>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().squeeze_dims, ElementsAreArray(op->squeeze_dims())); +} + +TEST_F(KernelBuilderTest, StridedSlice) +{ + auto *input = createInputNode(); + auto *begin = createInputNode(); + auto *end = createInputNode(); + auto *strides = createInputNode(); + + auto *op = createNode<luci::CircleStridedSlice>(); + op->input(input); + op->begin(begin); + op->end(end); + op->strides(strides); + + op->begin_mask(11); + op->ellipsis_mask(13); + op->end_mask(17); + op->new_axis_mask(19); + op->shrink_axis_mask(23); + + auto kernel = buildKernel<kernels::StridedSlice>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->begin(), begin); + checkTensor(kernel->end(), end); + checkTensor(kernel->strides(), strides); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().begin_mask, Eq(op->begin_mask())); + EXPECT_THAT(kernel->params().ellipsis_mask, Eq(op->ellipsis_mask())); + EXPECT_THAT(kernel->params().end_mask, Eq(op->end_mask())); + EXPECT_THAT(kernel->params().new_axis_mask, Eq(op->new_axis_mask())); + EXPECT_THAT(kernel->params().shrink_axis_mask, Eq(op->shrink_axis_mask())); +} + +TEST_F(KernelBuilderTest, Transpose) +{ + auto *input = createInputNode(); + auto *perm = createInputNode(); + + auto *op = createNode<luci::CircleTranspose>(); + op->a(input); + op->perm(perm); + + auto kernel = buildKernel<kernels::Transpose>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->perm(), perm); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, TransposeConv) +{ + auto *output_shape = createInputNode(); + auto *filter = createInputNode(); + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleTransposeConv>(); + op->inputSizes(output_shape); + op->filter(filter); + op->outBackprop(input); + + op->padding(luci::Padding::SAME); + op->stride()->h(11); + op->stride()->w(13); + + auto kernel = buildKernel<kernels::TransposeConv>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->output_shape(), output_shape); + checkTensor(kernel->filter(), filter); + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().padding, Eq(op->padding())); + EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); + EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); +} + +TEST_F(KernelBuilderTest, Unpack) +{ + auto *input = createInputNode(); + auto *op = createNode<luci::CircleUnpack>(); + auto *output1 = createNodeOut<luci::CircleUnpackOut>(op, 0); + auto *output2 = createNodeOut<luci::CircleUnpackOut>(op, 1); + + op->value(input); + + op->num(2); + op->axis(11); + + auto kernel = buildKernel<kernels::Unpack>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(0), output1); + checkTensor(kernel->output(1), output2); + EXPECT_THAT(kernel->params().axis, Eq(op->axis())); +} + +TEST_F(KernelBuilderTest, NonExisting1_NEG) +{ + auto *op = createNode<luci::CircleConst>(); + ASSERT_ANY_THROW(buildKernel<Kernel>(op)); +} + +TEST_F(KernelBuilderTest, NonExisting2_NEG) +{ + auto *op = createNode<luci::CircleInput>(); + ASSERT_ANY_THROW(buildKernel<Kernel>(op)); +} + +TEST_F(KernelBuilderTest, NonExisting3_NEG) +{ + auto *op = createNode<luci::CircleOutput>(); + ASSERT_ANY_THROW(buildKernel<Kernel>(op)); +} + +} // namespace +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp index 7780a61b6..b9a2ae0a9 100644 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp +++ b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp @@ -41,8 +41,11 @@ void ModuleLoader::load() { const loco::Graph *graph = _module->graph(i); RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); - GraphLoader loader(*this, graph, runtime_graph, _runtime_to_ir, _node_to_tensor); - loader.load(); + GraphLoader loader(graph, runtime_graph, _runtime_to_ir, _graph_to_runtime_graph, + _node_to_tensor); + loader.loadTensors(); + loader.initInputOutputTensors(); + loader.loadOperators(); } } diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.h b/compiler/luci-interpreter/src/loader/ModuleLoader.h index 954dbfb61..1af0ed747 100644 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.h +++ b/compiler/luci-interpreter/src/loader/ModuleLoader.h @@ -36,11 +36,6 @@ public: void load(); - RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const - { - return _graph_to_runtime_graph.at(graph); - } - private: const luci::Module *_module; RuntimeModule *_runtime_module; diff --git a/compiler/luci-value-test/CMakeLists.txt b/compiler/luci-value-test/CMakeLists.txt index 3a5c42b11..ec7463409 100644 --- a/compiler/luci-value-test/CMakeLists.txt +++ b/compiler/luci-value-test/CMakeLists.txt @@ -20,6 +20,6 @@ add_test(NAME luci_value_test COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/evalverify.sh" "${CMAKE_CURRENT_BINARY_DIR}" "${ARTIFACTS_BIN_PATH}" - "${NNCC_OVERLAY_DIR}/venv_1_13_2" + "${NNCC_OVERLAY_DIR}/venv_2_3_0" ${LUCI_VALUE_TESTS} ) diff --git a/compiler/luci-value-test/evalverify.sh b/compiler/luci-value-test/evalverify.sh index dfd55a691..12c9a459a 100755 --- a/compiler/luci-value-test/evalverify.sh +++ b/compiler/luci-value-test/evalverify.sh @@ -4,8 +4,10 @@ # # HOW TO USE # -# ./evalverify.sh <path/to/work_dir> <TEST 1> <TEST 2> ... -# work_dir : build directory of luci-value-test (ex: build/compiler/luci-value-test) +# ./evalverify.sh <path/to/bin_dir> <path/to/work_dir> <path/to/venv_dir> <TEST 1> <TEST 2> ... +# bin_dir : build directory of luci-value-test (ex: build/compiler/luci-value-test) +# work_dir : artifacts directoy where test materials exist +# venv_dir : python virtual environment home directory VERIFY_SOURCE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VERIFY_SCRIPT_PATH="${VERIFY_SOURCE_PATH}/luci_eval_verifier.py" diff --git a/compiler/luci-value-test/luci_eval_verifier.py b/compiler/luci-value-test/luci_eval_verifier.py index 6999110b6..7a2cebb91 100755 --- a/compiler/luci-value-test/luci_eval_verifier.py +++ b/compiler/luci-value-test/luci_eval_verifier.py @@ -35,6 +35,10 @@ for i in range(num_inputs): input_data = np.array( np.random.randint(0, 256, size=input_details["shape"]), input_details["dtype"]) + elif input_details["dtype"] == np.bool_: + input_data = np.array( + np.random.choice(a=[True, False], size=input_details["shape"]), + input_details["dtype"]) else: raise SystemExit("Unsupported input dtype") @@ -44,11 +48,6 @@ for i in range(num_inputs): # Do inference interpreter.invoke() -# Get reference output data. -assert len(interpreter.get_output_details()) == 1 # TODO: Support multiple outputs -output_details = interpreter.get_output_details()[0] -ref_output_data = interpreter.get_tensor(output_details["index"]) - # Execute luci interpreter. subprocess.run( [ @@ -56,27 +55,56 @@ subprocess.run( str(num_inputs), circle_model + ".input", circle_model + ".output" ], check=True) -output_data = np.fromfile(circle_model + ".output", output_details["dtype"]) -shape_file = open(circle_model + ".output.shape", 'r') -output_shape = [int(i) for i in shape_file.read().split(',')] -shape_file.close() -luci_output_data = np.reshape(output_data, output_shape) # Compare the results. -try: - if output_details["dtype"] == np.uint8: - if np.allclose(luci_output_data, ref_output_data, rtol=0, atol=0) == False: - raise SystemExit("Execution result of " + tflite_model + - " does not match with " + circle_model) - elif output_details["dtype"] == np.float32: - if np.allclose( - luci_output_data, ref_output_data, rtol=1.e-5, atol=1.e-5) == False: - raise SystemExit("Execution result of " + tflite_model + - " does not match with " + circle_model) - else: - raise SystemExit("Unsupported data type: ", output_details["dtype"]) -except: - print(traceback.format_exc()) - quit(255) +for idx in range(len(interpreter.get_output_details())): + output_details = interpreter.get_output_details()[idx] + output_data = np.fromfile(circle_model + ".output" + str(idx), + output_details["dtype"]) + shape_file = open(circle_model + ".output" + str(idx) + ".shape", 'r') + output_shape = [int(i) for i in shape_file.read().split(',')] + luci_output_data = np.reshape(output_data, output_shape) + try: + if output_details["dtype"] == np.uint8: + if np.allclose( + luci_output_data, + interpreter.get_tensor( + interpreter.get_output_details()[idx]["index"]), + rtol=0, + atol=0) == False: + raise SystemExit("Execution result of " + tflite_model + + " does not match with " + circle_model) + elif output_details["dtype"] == np.float32: + if np.allclose( + luci_output_data, + interpreter.get_tensor( + interpreter.get_output_details()[idx]["index"]), + rtol=1.e-5, + atol=1.e-5) == False: + raise SystemExit("Execution result of " + tflite_model + + " does not match with " + circle_model) + elif output_details["dtype"] == np.int64: + if np.allclose( + luci_output_data, + interpreter.get_tensor( + interpreter.get_output_details()[idx]["index"]), + rtol=0, + atol=0) == False: + raise SystemExit("Execution result of " + tflite_model + + " does not match with " + circle_model) + elif output_details["dtype"] == np.int32: + if np.allclose( + luci_output_data, + interpreter.get_tensor( + interpreter.get_output_details()[idx]["index"]), + rtol=0, + atol=0) == False: + raise SystemExit("Execution result of " + tflite_model + + " does not match with " + circle_model) + else: + raise SystemExit("Unsupported data type: ", output_details["dtype"]) + except: + print(traceback.format_exc()) + quit(255) quit(0) diff --git a/compiler/luci-value-test/test.lst b/compiler/luci-value-test/test.lst index 6a332f92c..0e5231eca 100644 --- a/compiler/luci-value-test/test.lst +++ b/compiler/luci-value-test/test.lst @@ -1,81 +1,183 @@ #addeval(Abs_000) addeval(Add_000) +#addeval(Add_001) addeval(Add_U8_000) -#addeval(ArgMax_000) -#addeval(ArgMax_001) -#addeval(ArgMax_002) -#addeval(ArgMax_003) -#addeval(ArgMax_U8_000) -#addeval(ArgMax_U8_001) -#addeval(ArgMax_U8_002) -#addeval(ArgMax_U8_003) +#addeval(AddN_000) +addeval(ArgMax_000) +addeval(ArgMax_001) +addeval(ArgMax_002) +addeval(ArgMax_003) +addeval(ArgMax_U8_000) +addeval(ArgMax_U8_001) +addeval(ArgMax_U8_002) +addeval(ArgMax_U8_003) +#addeval(ArgMin_000) +#addeval(ArgMin_001) +#addeval(ArgMin_002) +#addeval(ArgMin_003) +#addeval(ArgMin_U8_000) +#addeval(ArgMin_U8_001) +#addeval(ArgMin_U8_002) +#addeval(ArgMin_U8_003) addeval(AveragePool2D_000) +#addeval(BatchMatMul_000) #addeval(BatchMatMulV2_000) #addeval(BatchMatMulV2_001) #addeval(BatchToSpaceND_000) #addeval(Cast_000) +#addeval(Cast_001) +#addeval(Ceil_000) addeval(Concatenation_000) addeval(Concatenation_U8_000) addeval(Conv2D_000) addeval(Conv2D_001) addeval(Conv2D_002) +#addeval(Conv2D_003) addeval(Conv2D_U8_000) addeval(Conv2D_U8_001) #addeval(Cos_000) +#addeval(DepthToSpace_000) addeval(DepthwiseConv2D_000) addeval(DepthwiseConv2D_U8_000) +#addeval(DepthwiseConv2D_U8_001) +addeval(DepthwiseConv2D_001) #addeval(Div_000) +addeval(ELU_000) #addeval(Equal_000) #addeval(Exp_000) +#addeval(ExpandDims_000) +#addeval(ExpandDims_001) +#addeval(ExpandDims_002) +#addeval(ExpandDims_003) +#addeval(Fill_000) +#addeval(Fill_001) +#addeval(Floor_000) +#addeval(FloorDiv_000) +#addeval(FloorDiv_001) +#addeval(FloorMod_000) +#addeval(FloorMod_001) addeval(FullyConnected_000) addeval(FullyConnected_001) -#addeval(FullyConnected_002) +addeval(FullyConnected_002) #addeval(FullyConnected_U8_000) #addeval(Gather_000) -#addeval(If_000) -#addeval(If_001) +#addeval(GatherNd_000) +#addeval(Greater_000) +#addeval(GreaterEqual_000) +addeval(If_000) +addeval(If_001) +addeval(L2Normalize_000) +addeval(L2Pool2D_000) +#addeval(L2Pool2D_U8_000) +addeval(LeakyRelu_000) +#addeval(Less_000) +#addeval(LessEqual_000) +addeval(LocalResponseNormalization_000) +#addeval(Log_000) +#addeval(LogicalAnd_000) #addeval(LogicalNot_000) #addeval(LogicalOr_000) -#addeval(Logistic_000) +addeval(Logistic_000) +#addeval(LogSoftmax_000) +#addeval(MatMul_000) +#addeval(MatrixDiag_000) +#addeval(MatrixSetDiag_000) +#addeval(Maximum_000) addeval(MaxPool2D_000) addeval(MaxPool2D_U8_000) addeval(Mean_000) addeval(Mean_001) -addeval(Mean_U8_000) +#addeval(Mean_U8_000) +#addeval(Minimum_000) +#addeval(MirrorPad_000) addeval(Mul_000) #addeval(Mul_U8_000) +#addeval(Neg_000) +#addeval(NotEqual_000) +#addeval(OneHot_000) +#addeval(OneHot_001) +#addeval(OneHot_002) +#addeval(OneHot_003) #addeval(Pack_000) #addeval(Pack_U8_000) addeval(Pad_000) addeval(Pad_U8_000) +#addeval(Pow_000) +#addeval(PRelu_000) +#addeval(Range_000) +#addeval(Rank_000) +#addeval(ReduceAny_000) +#addeval(ReduceAny_001) +#addeval(ReduceAny_002) +#addeval(ReduceAny_003) +#addeval(ReduceMax_000) +#addeval(ReduceMin_000) #addeval(ReduceProd_000) #addeval(ReduceProd_001) #addeval(ReduceProd_002) #addeval(ReduceProd_003) #addeval(ReLU_000) +#addeval(ReLU6_000) +#addeval(ReLUN1To1_000) addeval(Reshape_000) addeval(Reshape_001) addeval(Reshape_002) #addeval(Reshape_003) addeval(Reshape_U8_000) +#addeval(ResizeBilinear_000) +#addeval(ResizeNearestNeighbor_000) +#addeval(ReverseSequence_000) +#addeval(ReverseV2_000) +#addeval(Round_000) #addeval(Rsqrt_000) +#addeval(ScatterNd_000) +#addeval(SegmentSum_000) +#addeval(Select_000) +#addeval(Select_001) +#addeval(Select_002) +#addeval(SelectV2_000) +#addeval(SelectV2_001) +#addeval(SelectV2_002) +#addeval(Shape_000) #addeval(Sin_000) +addeval(Slice_000) addeval(Softmax_000) #addeval(Softmax_U8_000) #addeval(SpaceToBatchND_000) #addeval(SpaceToBatchND_001) #addeval(SpaceToBatchND_002) #addeval(SpaceToBatchND_003) -#addeval(StridedSlice_000) -#addeval(StridedSlice_001) +addeval(SpaceToDepth_000) +#addeval(SparseToDense_000) +addeval(Split_000) +#addeval(SplitV_000) +#addeval(Sqrt_000) +#addeval(Square_000) +#addeval(SquaredDifference_000) +addeval(Squeeze_000) +addeval(StridedSlice_000) +addeval(StridedSlice_001) +addeval(StridedSlice_002) #addeval(Sub_000) #addeval(Sub_U8_000) +#addeval(Sum_000) +#addeval(Sum_001) #addeval(Tanh_000) #addeval(Tile_000) #addeval(Tile_U8_000) -#addeval(Transpose_000) -#addeval(Unpack_000) -#addeval(Unpack_001) -#addeval(Unpack_002) +#addeval(TopKV2_000) +#addeval(TopKV2_001) +addeval(Transpose_000) +#addeval(TransposeConv_000) +addeval(Unpack_000) +addeval(Unpack_001) +addeval(Unpack_002) +addeval(Unpack_003) +#addeval(Where_000) +#addeval(Where_001) #addeval(While_000) #addeval(While_001) +#addeval(While_002) +#addeval(While_003) +#addeval(YUV_TO_RGB_U8_000) +#addeval(ZerosLike_000) diff --git a/compiler/luci-value-test/tester/src/EvalTester.cpp b/compiler/luci-value-test/tester/src/EvalTester.cpp index 58f62f54c..09eef223a 100644 --- a/compiler/luci-value-test/tester/src/EvalTester.cpp +++ b/compiler/luci-value-test/tester/src/EvalTester.cpp @@ -129,7 +129,7 @@ int entry(int argc, char **argv) assert(num_inputs == input_nodes.size()); for (int32_t i = 0; i < num_inputs; i++) { - const auto *input_node = dynamic_cast<const luci::CircleInput *>(input_nodes[i]); + const auto *input_node = loco::must_cast<const luci::CircleInput *>(input_nodes[i]); std::vector<char> input_data(getTensorSize(input_node)); readDataFromFile(std::string(input_prefix) + std::to_string(i), input_data.data(), input_data.size()); @@ -141,24 +141,35 @@ int entry(int argc, char **argv) // Get output. const auto output_nodes = loco::output_nodes(module->graph()); - // TODO: Support multiple outputs - assert(output_nodes.size() == 1); - const auto *output_node = dynamic_cast<const luci::CircleOutput *>(output_nodes[0]); - std::vector<char> output_data(getTensorSize(output_node)); - interpreter.readOutputTensor(output_node, output_data.data(), output_data.size()); - - // Output data is written in ${output_file} - // (ex: Add.circle.output) - // Output shape is written in ${output_file}.shape - // (ex: Add.circle.output.shape) - // TODO: Use HDF5 file format - writeDataToFile(output_file, output_data.data(), output_data.size()); - auto shape_str = std::to_string(output_node->dim(0).value()); - for (int i = 1; i < output_node->rank(); i++) + for (int i = 0; i < module->graph()->outputs()->size(); i++) { - shape_str += ","; - shape_str += std::to_string(output_node->dim(i).value()); + const auto *output_node = loco::must_cast<const luci::CircleOutput *>(output_nodes[i]); + std::vector<char> output_data(getTensorSize(output_node)); + interpreter.readOutputTensor(output_node, output_data.data(), output_data.size()); + + // Output data is written in ${output_file} + // (ex: Add.circle.output0) + // Output shape is written in ${output_file}.shape + // (ex: Add.circle.output0.shape) + writeDataToFile(std::string(output_file) + std::to_string(i), output_data.data(), + output_data.size()); + // In case of Tensor output is Scalar value. + // The output tensor with rank 0 is treated as a scalar with shape (1) + if (output_node->rank() == 0) + { + writeDataToFile(std::string(output_file) + std::to_string(i) + ".shape", "1", 1); + } + else + { + auto shape_str = std::to_string(output_node->dim(0).value()); + for (int j = 1; j < output_node->rank(); j++) + { + shape_str += ","; + shape_str += std::to_string(output_node->dim(j).value()); + } + writeDataToFile(std::string(output_file) + std::to_string(i) + ".shape", shape_str.c_str(), + shape_str.size()); + } } - writeDataToFile(std::string(output_file) + ".shape", shape_str.c_str(), shape_str.size()); return EXIT_SUCCESS; } diff --git a/compiler/luci/export/src/CircleOperationExporter.cpp b/compiler/luci/export/src/CircleOperationExporter.cpp index 3c01b676f..bca122050 100644 --- a/compiler/luci/export/src/CircleOperationExporter.cpp +++ b/compiler/luci/export/src/CircleOperationExporter.cpp @@ -102,6 +102,7 @@ public: void visit(luci::CircleMirrorPad *) final; void visit(luci::CircleMul *) final; void visit(luci::CircleNeg *) final; + void visit(luci::CircleNonMaxSuppressionV4 *) final; void visit(luci::CircleNotEqual *) final; void visit(luci::CircleOneHot *) final; void visit(luci::CirclePack *) final; @@ -149,6 +150,7 @@ public: void visit(luci::CircleTopKV2 *) final; void visit(luci::CircleTranspose *) final; void visit(luci::CircleTransposeConv *) final; + void visit(luci::CircleUnique *) final; void visit(luci::CircleUnpack *) final; void visit(luci::CircleWhere *) final; void visit(luci::CircleWhile *) final; @@ -165,9 +167,11 @@ public: // Virtual for multiple-outputs void visit(luci::CircleCustomOut *) final {} void visit(luci::CircleIfOut *) final {} + void visit(luci::CircleNonMaxSuppressionV4Out *) final {} void visit(luci::CircleSplitOut *) final {} void visit(luci::CircleSplitVOut *) final {} void visit(luci::CircleTopKV2Out *) final {} + void visit(luci::CircleUniqueOut *) final {} void visit(luci::CircleUnpackOut *) final {} void visit(luci::CircleWhileOut *) final {} @@ -599,7 +603,9 @@ void OperationExporter::visit(luci::CircleLocalResponseNormalization *node) { export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, circle::BuiltinOptions_LocalResponseNormalizationOptions, - CreateLocalResponseNormalizationOptions(builder).Union()); + CreateLocalResponseNormalizationOptions(builder, node->radius(), node->bias(), + node->alpha(), node->beta()) + .Union()); } void OperationExporter::visit(luci::CircleLog *node) @@ -691,6 +697,49 @@ void OperationExporter::visit(luci::CircleNeg *node) CreateNegOptions(builder).Union()); } +void OperationExporter::visit(luci::CircleNonMaxSuppressionV4 *node) +{ + auto nms_outs = loco::succs(node); + assert(nms_outs.size() == 2); + + uint32_t op_idx = + md.registerBuiltinOpcode(circle::BuiltinOperator_NON_MAX_SUPPRESSION_V4, node->op_version()); + std::vector<int32_t> inputs_vec{ + get_tensor_index(node->boxes()), get_tensor_index(node->scores()), + get_tensor_index(node->max_output_size()), get_tensor_index(node->iou_threshold()), + get_tensor_index(node->score_threshold()), + }; + std::vector<int32_t> outputs_vec; + + for (uint32_t idx = 0; idx < nms_outs.size(); ++idx) + { + // store in order of index + bool found = false; + for (auto out : nms_outs) + { + auto nms_out = loco::must_cast<luci::CircleNonMaxSuppressionV4Out *>(out); + if (nms_out->index() == static_cast<int32_t>(idx)) + { + outputs_vec.push_back(get_tensor_index(nms_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid NonMaxSuppressionV4 output"); + } + } + + auto inputs = builder.CreateVector(inputs_vec); + auto outputs = builder.CreateVector(outputs_vec); + auto options = CreateNonMaxSuppressionV4Options(builder); + auto op_offset = + CreateOperator(builder, op_idx, inputs, outputs, + circle::BuiltinOptions_NonMaxSuppressionV4Options, options.Union()); + gd._operators.push_back(op_offset); +} + void OperationExporter::visit(luci::CircleNotEqual *node) { export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions, @@ -890,7 +939,7 @@ void OperationExporter::visit(luci::CircleSpaceToDepth *node) { export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH, circle::BuiltinOptions_SpaceToDepthOptions, - CreateSpaceToDepthOptions(builder).Union()); + CreateSpaceToDepthOptions(builder, node->block_size()).Union()); } void OperationExporter::visit(luci::CircleSparseToDense *node) @@ -1090,6 +1139,43 @@ void OperationExporter::visit(luci::CircleTransposeConv *node) .Union()); } +void OperationExporter::visit(luci::CircleUnique *node) +{ + auto unique_outs = loco::succs(node); + assert(int32_t(unique_outs.size()) == 2); + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNIQUE, node->op_version()); + + std::vector<int32_t> inputs_vec{get_tensor_index(node->input())}; + std::vector<int32_t> outputs_vec; + + for (int32_t index = 0; index < 2; index++) + { + // store in order of index + bool found = false; + for (auto out : unique_outs) + { + auto unique_out = loco::must_cast<luci::CircleUniqueOut *>(out); + if (unique_out->index() == index) + { + outputs_vec.push_back(get_tensor_index(unique_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid Unique output"); + } + } + + auto inputs = builder.CreateVector(inputs_vec); + auto outputs = builder.CreateVector(outputs_vec); + auto options = CreateUniqueOptions(builder, to_circle_tensortype(node->idx_out_type())); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, + circle::BuiltinOptions_UniqueOptions, options.Union()); + gd._operators.push_back(op_offset); +} + void OperationExporter::visit(luci::CircleUnpack *node) { LOGGER(l); diff --git a/compiler/luci/export/src/CircleTensorExporter.cpp b/compiler/luci/export/src/CircleTensorExporter.cpp index 5cad3920b..dc8c2fbc9 100644 --- a/compiler/luci/export/src/CircleTensorExporter.cpp +++ b/compiler/luci/export/src/CircleTensorExporter.cpp @@ -302,7 +302,10 @@ encodeQuantizationParameters(FlatBufferBuilder &builder, luci::CircleQuantParam scale = builder.CreateVector(quantparam->scale); zero_point = builder.CreateVector(quantparam->zerop); } - return circle::CreateQuantizationParameters(builder, min, max, scale, zero_point); + // Note: QuantizationDetails is not supported + return circle::CreateQuantizationParameters(builder, min, max, scale, zero_point, + circle::QuantizationDetails::QuantizationDetails_NONE, + 0, quantparam->quantized_dimension); } void exportOpDefinedTensor(const CircleTensoInfo &info, FlatBufferBuilder &builder, diff --git a/compiler/luci/import/include/luci/Import/Nodes.h b/compiler/luci/import/include/luci/Import/Nodes.h index 2719a5aec..825c2147d 100644 --- a/compiler/luci/import/include/luci/Import/Nodes.h +++ b/compiler/luci/import/include/luci/Import/Nodes.h @@ -73,6 +73,7 @@ #include "Nodes/CircleMirrorPad.h" #include "Nodes/CircleMul.h" #include "Nodes/CircleNeg.h" +#include "Nodes/CircleNonMaxSuppressionV4.h" #include "Nodes/CircleNotEqual.h" #include "Nodes/CircleOneHot.h" #include "Nodes/CirclePack.h" @@ -120,6 +121,7 @@ #include "Nodes/CircleTopKV2.h" #include "Nodes/CircleTranspose.h" #include "Nodes/CircleTransposeConv.h" +#include "Nodes/CircleUnique.h" #include "Nodes/CircleUnpack.h" #include "Nodes/CircleWhere.h" #include "Nodes/CircleWhile.h" diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleNonMaxSuppressionV4.h b/compiler/luci/import/include/luci/Import/Nodes/CircleNonMaxSuppressionV4.h new file mode 100644 index 000000000..f193aae35 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleNonMaxSuppressionV4.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 __LUCI_IMPORT_OP_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ +#define __LUCI_IMPORT_OP_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleNonMaxSuppressionV4GraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleUnique.h b/compiler/luci/import/include/luci/Import/Nodes/CircleUnique.h new file mode 100644 index 000000000..ed5b5035d --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleUnique.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 __LUCI_IMPORT_OP_CIRCLE_UNIQUE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_UNIQUE_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleUniqueGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_UNIQUE_H__ diff --git a/compiler/luci/import/src/CircleReader.cpp b/compiler/luci/import/src/CircleReader.cpp index 81e945dd1..bc7f39762 100644 --- a/compiler/luci/import/src/CircleReader.cpp +++ b/compiler/luci/import/src/CircleReader.cpp @@ -156,6 +156,7 @@ luci_quantparam(const circle::QuantizationParametersT *quantization) const auto &max = quantization->max; const auto &scale = quantization->scale; const auto &zero_point = quantization->zero_point; + const auto &quantized_dimension = quantization->quantized_dimension; if ((!min.empty() && !max.empty()) || (!scale.empty() && !zero_point.empty())) { @@ -165,6 +166,7 @@ luci_quantparam(const circle::QuantizationParametersT *quantization) quantparam->max = max; quantparam->scale = scale; quantparam->zerop = zero_point; + quantparam->quantized_dimension = quantized_dimension; return quantparam; } diff --git a/compiler/luci/import/src/GraphBuilderRegistry.cpp b/compiler/luci/import/src/GraphBuilderRegistry.cpp index d29557f74..cc328cc16 100644 --- a/compiler/luci/import/src/GraphBuilderRegistry.cpp +++ b/compiler/luci/import/src/GraphBuilderRegistry.cpp @@ -82,6 +82,7 @@ GraphBuilderRegistry::GraphBuilderRegistry() CIRCLE_NODE(MIRROR_PAD, CircleMirrorPadGraphBuilder); // 100 CIRCLE_NODE(MUL, CircleMulGraphBuilder); // 18 CIRCLE_NODE(NEG, CircleNegGraphBuilder); // 59 + CIRCLE_NODE(NON_MAX_SUPPRESSION_V4, CircleNonMaxSuppressionV4GraphBuilder); // 120, CIRCLE_NODE(NOT_EQUAL, CircleNotEqualGraphBuilder); // 72 CIRCLE_NODE(ONE_HOT, CircleOneHotGraphBuilder); // 85 CIRCLE_NODE(PACK, CirclePackGraphBuilder); // 83 @@ -129,6 +130,7 @@ GraphBuilderRegistry::GraphBuilderRegistry() CIRCLE_NODE(TOPK_V2, CircleTopKV2GraphBuilder); // 48 CIRCLE_NODE(TRANSPOSE, CircleTransposeGraphBuilder); // 39 CIRCLE_NODE(TRANSPOSE_CONV, CircleTransposeConvGraphBuilder); // 67 + CIRCLE_NODE(UNIQUE, CircleUniqueGraphBuilder); // 103 CIRCLE_NODE(UNPACK, CircleUnpackGraphBuilder); // 88 CIRCLE_NODE(WHERE, CircleWhereGraphBuilder); // 109 CIRCLE_NODE(WHILE, CircleWhileGraphBuilder); // 119 @@ -155,10 +157,8 @@ GraphBuilderRegistry::GraphBuilderRegistry() // BuiltinOperator_ARG_MAX = 56, // BuiltinOperator_PADV2 = 60, // BuiltinOperator_FAKE_QUANT = 80, - // BuiltinOperator_UNIQUE = 103, // BuiltinOperator_QUANTIZE = 114, // BuiltinOperator_HARD_SWISH = 117, - // BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120, // BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121, // BuiltinOperator_DENSIFY = 124, } diff --git a/compiler/luci/import/src/Importer.test.cpp b/compiler/luci/import/src/Importer.test.cpp index 4426e15fd..8366546f0 100644 --- a/compiler/luci/import/src/Importer.test.cpp +++ b/compiler/luci/import/src/Importer.test.cpp @@ -20,4 +20,9 @@ #include <gtest/gtest.h> -TEST(TensorFlowLiteImport, Dummy) { luci::Importer import; } +TEST(TensorFlowLiteImport, Dummy) +{ + luci::Importer import; + + SUCCEED(); +} diff --git a/compiler/luci/import/src/Nodes/CircleAbs.cpp b/compiler/luci/import/src/Nodes/CircleAbs.cpp index 9054986bd..3556dc7fa 100644 --- a/compiler/luci/import/src/Nodes/CircleAbs.cpp +++ b/compiler/luci/import/src/Nodes/CircleAbs.cpp @@ -36,7 +36,7 @@ CircleNode *CircleAbsGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleAbs>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleAdd.cpp b/compiler/luci/import/src/Nodes/CircleAdd.cpp index 3b1bb734f..b767d4af2 100644 --- a/compiler/luci/import/src/Nodes/CircleAdd.cpp +++ b/compiler/luci/import/src/Nodes/CircleAdd.cpp @@ -36,8 +36,8 @@ CircleNode *CircleAddGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleAdd>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); const auto *options = op.builtin_options.AsAddOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleArgMax.cpp b/compiler/luci/import/src/Nodes/CircleArgMax.cpp index 2679827e2..10e8516f4 100644 --- a/compiler/luci/import/src/Nodes/CircleArgMax.cpp +++ b/compiler/luci/import/src/Nodes/CircleArgMax.cpp @@ -36,8 +36,8 @@ CircleNode *CircleArgMaxGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleArgMax>(); - node->input(inputs[0]); - node->dimension(inputs[1]); + node->input(inputs.at(0)); + node->dimension(inputs.at(1)); const auto *options = op.builtin_options.AsArgMaxOptions(); node->output_type(luci_datatype(options->output_type)); diff --git a/compiler/luci/import/src/Nodes/CircleArgMin.cpp b/compiler/luci/import/src/Nodes/CircleArgMin.cpp index 4d85bbff0..5ff534dbb 100644 --- a/compiler/luci/import/src/Nodes/CircleArgMin.cpp +++ b/compiler/luci/import/src/Nodes/CircleArgMin.cpp @@ -36,8 +36,8 @@ CircleNode *CircleArgMinGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleArgMin>(); - node->input(inputs[0]); - node->dimension(inputs[1]); + node->input(inputs.at(0)); + node->dimension(inputs.at(1)); const auto *options = op.builtin_options.AsArgMinOptions(); node->output_type(luci_datatype(options->output_type)); diff --git a/compiler/luci/import/src/Nodes/CircleAveragePool2D.cpp b/compiler/luci/import/src/Nodes/CircleAveragePool2D.cpp index cfc3cf126..ad011f71f 100644 --- a/compiler/luci/import/src/Nodes/CircleAveragePool2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleAveragePool2D.cpp @@ -34,7 +34,7 @@ CircleNode *CircleAveragePool2DGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleAveragePool2D>(); - node->value(inputs[0]); + node->value(inputs.at(0)); const auto *options = op.builtin_options.AsPool2DOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp index 7cc077ed6..16ecebd5c 100644 --- a/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp +++ b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp @@ -37,11 +37,11 @@ CircleNode *CircleBCQFullyConnectedGraphBuilder::build_node(const circle::Operat { auto *node = graph->nodes()->create<CircleBCQFullyConnected>(); - node->input(inputs[0]); - node->weights_scales(inputs[1]); - node->weights_binary(inputs[2]); - node->bias(inputs[3]); - node->weights_clusters(inputs[4]); + node->input(inputs.at(0)); + node->weights_scales(inputs.at(1)); + node->weights_binary(inputs.at(2)); + node->bias(inputs.at(3)); + node->weights_clusters(inputs.at(4)); // TODO Find and move to appropriate place for setting optional input if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias())) diff --git a/compiler/luci/import/src/Nodes/CircleBCQGather.cpp b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp index c6d2ab559..464f1ac18 100644 --- a/compiler/luci/import/src/Nodes/CircleBCQGather.cpp +++ b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp @@ -37,10 +37,10 @@ CircleNode *CircleBCQGatherGraphBuilder::build_node(const circle::OperatorT &op, { auto *node = graph->nodes()->create<CircleBCQGather>(); - node->input_scales(inputs[0]); - node->input_binary(inputs[1]); - node->indices(inputs[2]); - node->input_clusters(inputs[3]); + node->input_scales(inputs.at(0)); + node->input_binary(inputs.at(1)); + node->indices(inputs.at(2)); + node->input_clusters(inputs.at(3)); const auto *options = op.builtin_options.AsBCQGatherOptions(); node->input_hidden_size(options->input_hidden_size); diff --git a/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp index 6026b2a72..330775691 100644 --- a/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp +++ b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp @@ -34,8 +34,8 @@ CircleNode *CircleBatchMatMulGraphBuilder::build_node(const circle::OperatorT &o loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleBatchMatMul>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); const auto *options = op.builtin_options.AsBatchMatMulOptions(); node->adj_x(options->adjoint_lhs); diff --git a/compiler/luci/import/src/Nodes/CircleBatchToSpaceND.cpp b/compiler/luci/import/src/Nodes/CircleBatchToSpaceND.cpp index 4bbfadf64..8c2039fff 100644 --- a/compiler/luci/import/src/Nodes/CircleBatchToSpaceND.cpp +++ b/compiler/luci/import/src/Nodes/CircleBatchToSpaceND.cpp @@ -33,7 +33,7 @@ bool CircleBatchToSpaceNDGraphBuilder::validate(const ValidateArgs &args) const // input 1 and 2 should have INT32/INT64 type const auto &tensors = args.reader.tensors(); - const auto &tensor_1 = tensors.at(inputs[1]); + const auto &tensor_1 = tensors.at(inputs.at(1)); switch (tensor_1->type) { case circle::TensorType_INT32: @@ -42,7 +42,7 @@ bool CircleBatchToSpaceNDGraphBuilder::validate(const ValidateArgs &args) const default: return false; } - const auto &tensor_2 = tensors.at(inputs[2]); + const auto &tensor_2 = tensors.at(inputs.at(2)); switch (tensor_2->type) { case circle::TensorType_INT32: @@ -53,7 +53,7 @@ bool CircleBatchToSpaceNDGraphBuilder::validate(const ValidateArgs &args) const } // Only support input shape dimension 3 and 4 only - const auto &tensor_0 = tensors.at(inputs[0]); + const auto &tensor_0 = tensors.at(inputs.at(0)); const auto t_0_s = tensor_0->shape.size(); if (t_0_s != 3 && t_0_s != 4) return false; @@ -68,9 +68,9 @@ CircleNode *CircleBatchToSpaceNDGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleBatchToSpaceND>(); - node->input(inputs[0]); - node->block_shape(inputs[1]); - node->crops(inputs[2]); + node->input(inputs.at(0)); + node->block_shape(inputs.at(1)); + node->crops(inputs.at(2)); // No options for BatchToSpaceND diff --git a/compiler/luci/import/src/Nodes/CircleCast.cpp b/compiler/luci/import/src/Nodes/CircleCast.cpp index a4d09b505..7bdb63044 100644 --- a/compiler/luci/import/src/Nodes/CircleCast.cpp +++ b/compiler/luci/import/src/Nodes/CircleCast.cpp @@ -47,7 +47,7 @@ bool CircleCastGraphBuilder::validate(const ValidateArgs &args) const const circle::TensorT &output_tensor = *tensors[outputs[0]]; auto name = tensor_name(output_tensor); - const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_in = tensors.at(inputs.at(0)); if (tensor_in->type != options->in_data_type) { if (settings->get(luci::UserSettings::Key::DisableValidation)) @@ -77,7 +77,7 @@ CircleNode *CircleCastGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleCast>(); - node->x(inputs[0]); + node->x(inputs.at(0)); const auto *options = op.builtin_options.AsCastOptions(); if (options != nullptr) @@ -87,7 +87,7 @@ CircleNode *CircleCastGraphBuilder::build_node(const circle::OperatorT &op, } else { - node->in_data_type(inputs[0]->dtype()); + node->in_data_type(inputs.at(0)->dtype()); node->out_data_type(loco::DataType::Unknown); // type inference should use node->dtype() for Unknown // export should use BuiltinOptions_NONE for Unknown diff --git a/compiler/luci/import/src/Nodes/CircleCeil.cpp b/compiler/luci/import/src/Nodes/CircleCeil.cpp index d3d6cd945..2e1aaa295 100644 --- a/compiler/luci/import/src/Nodes/CircleCeil.cpp +++ b/compiler/luci/import/src/Nodes/CircleCeil.cpp @@ -42,7 +42,7 @@ CircleNode *CircleCeilGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleCeil>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleConv2D.cpp b/compiler/luci/import/src/Nodes/CircleConv2D.cpp index 42c5c265a..9516ef16a 100644 --- a/compiler/luci/import/src/Nodes/CircleConv2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleConv2D.cpp @@ -39,11 +39,11 @@ CircleNode *CircleConv2DGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleConv2D>(); - node->input(inputs[0]); - node->filter(inputs[1]); + node->input(inputs.at(0)); + node->filter(inputs.at(1)); // For now, bias is required (checked in `verify` method). assert(inputs.size() == 3); - node->bias(inputs[2]); + node->bias(inputs.at(2)); const auto *options = op.builtin_options.AsConv2DOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleCos.cpp b/compiler/luci/import/src/Nodes/CircleCos.cpp index 5f61cc7f6..27d60c62c 100644 --- a/compiler/luci/import/src/Nodes/CircleCos.cpp +++ b/compiler/luci/import/src/Nodes/CircleCos.cpp @@ -36,7 +36,7 @@ CircleNode *CircleCosGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleCos>(); - node->x(inputs[0]); + node->x(inputs.at(0)); // No options for Cos diff --git a/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp index 827b63468..49d31bb99 100644 --- a/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp +++ b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp @@ -40,7 +40,7 @@ bool CircleDepthToSpaceGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - if (tensors[outputs[0]]->type != tensors[inputs[0]]->type) + if (tensors[outputs[0]]->type != tensors[inputs.at(0)]->type) { return false; } @@ -56,7 +56,7 @@ CircleNode *CircleDepthToSpaceGraphBuilder::build_node(const circle::OperatorT & loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleDepthToSpace>(); - node->input(inputs[0]); + node->input(inputs.at(0)); const auto *options = op.builtin_options.AsDepthToSpaceOptions(); node->block_size(options->block_size); diff --git a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp index 2b13f9ebb..53f85f2f5 100644 --- a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp @@ -40,11 +40,11 @@ CircleNode *CircleDepthwiseConv2DGraphBuilder::build_node(const circle::Operator loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleDepthwiseConv2D>(); - node->input(inputs[0]); - node->filter(inputs[1]); + node->input(inputs.at(0)); + node->filter(inputs.at(1)); if (inputs.size() != 3) throw oops::UserExn("DepthwiseConv2d without bias is unsupported"); - node->bias(inputs[2]); + node->bias(inputs.at(2)); const auto *options = op.builtin_options.AsDepthwiseConv2DOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleDiv.cpp b/compiler/luci/import/src/Nodes/CircleDiv.cpp index d09cfb815..615c224d7 100644 --- a/compiler/luci/import/src/Nodes/CircleDiv.cpp +++ b/compiler/luci/import/src/Nodes/CircleDiv.cpp @@ -37,8 +37,8 @@ CircleNode *CircleDivGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto node = graph->nodes()->create<CircleDiv>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); const auto *options = op.builtin_options.AsDivOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleElu.cpp b/compiler/luci/import/src/Nodes/CircleElu.cpp index 37a290cb1..919e95ee4 100644 --- a/compiler/luci/import/src/Nodes/CircleElu.cpp +++ b/compiler/luci/import/src/Nodes/CircleElu.cpp @@ -35,7 +35,7 @@ bool CircleEluGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { @@ -56,7 +56,7 @@ CircleNode *CircleEluGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleElu>(); - node->features(inputs[0]); + node->features(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleEqual.cpp b/compiler/luci/import/src/Nodes/CircleEqual.cpp index a53f6e94b..1db33b8ac 100644 --- a/compiler/luci/import/src/Nodes/CircleEqual.cpp +++ b/compiler/luci/import/src/Nodes/CircleEqual.cpp @@ -34,7 +34,7 @@ bool CircleEqualGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - return tensors[inputs[0]]->type == tensors[inputs[1]]->type; + return tensors[inputs.at(0)]->type == tensors[inputs.at(1)]->type; } CircleNode *CircleEqualGraphBuilder::build_node(const circle::OperatorT &, @@ -42,8 +42,8 @@ CircleNode *CircleEqualGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleEqual>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleExp.cpp b/compiler/luci/import/src/Nodes/CircleExp.cpp index a32851458..2c031d6b3 100644 --- a/compiler/luci/import/src/Nodes/CircleExp.cpp +++ b/compiler/luci/import/src/Nodes/CircleExp.cpp @@ -31,7 +31,7 @@ bool CircleExpGraphBuilder::validate(const ValidateArgs &args) const // input type check const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_FLOAT16: @@ -51,7 +51,7 @@ CircleNode *CircleExpGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleExp>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleExpandDims.cpp b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp index 1cef67a83..ab537c710 100644 --- a/compiler/luci/import/src/Nodes/CircleExpandDims.cpp +++ b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp @@ -34,7 +34,7 @@ bool CircleExpandDimsGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - return tensors[inputs[1]]->type == circle::TensorType_INT32; + return tensors[inputs.at(1)]->type == circle::TensorType_INT32; } CircleNode *CircleExpandDimsGraphBuilder::build_node(const circle::OperatorT &, @@ -42,8 +42,8 @@ CircleNode *CircleExpandDimsGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleExpandDims>(); - node->input(inputs[0]); - node->axis(inputs[1]); + node->input(inputs.at(0)); + node->axis(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleFill.cpp b/compiler/luci/import/src/Nodes/CircleFill.cpp index 6c3d3a247..95d5b876b 100644 --- a/compiler/luci/import/src/Nodes/CircleFill.cpp +++ b/compiler/luci/import/src/Nodes/CircleFill.cpp @@ -37,8 +37,8 @@ CircleNode *CircleFillGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleFill>(); - node->dims(inputs[0]); - node->value(inputs[1]); + node->dims(inputs.at(0)); + node->value(inputs.at(1)); const auto *options = op.builtin_options.AsFillOptions(); (void)options; diff --git a/compiler/luci/import/src/Nodes/CircleFloor.cpp b/compiler/luci/import/src/Nodes/CircleFloor.cpp index 302a9eae3..ce756b3b1 100644 --- a/compiler/luci/import/src/Nodes/CircleFloor.cpp +++ b/compiler/luci/import/src/Nodes/CircleFloor.cpp @@ -42,7 +42,7 @@ CircleNode *CircleFloorGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleFloor>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp index 875197890..55f385d60 100644 --- a/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp +++ b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp @@ -39,8 +39,8 @@ bool CircleFloorDivGraphBuilder::validate(const ValidateArgs &args) const } const auto &tensors = args.reader.tensors(); - const auto &tensor_in_0 = tensors.at(inputs[0]); - const auto &tensor_in_1 = tensors.at(inputs[1]); + const auto &tensor_in_0 = tensors.at(inputs.at(0)); + const auto &tensor_in_1 = tensors.at(inputs.at(1)); const auto &tensor_out = tensors.at(outputs[0]); if (tensor_in_0->type != tensor_in_1->type) @@ -59,8 +59,8 @@ CircleNode *CircleFloorDivGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleFloorDiv>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleFloorMod.cpp b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp index 3ccdce0cd..2101e417e 100644 --- a/compiler/luci/import/src/Nodes/CircleFloorMod.cpp +++ b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp @@ -33,8 +33,8 @@ bool CircleFloorModGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_in_0 = tensors.at(inputs[0]); - const auto &tensor_in_1 = tensors.at(inputs[1]); + const auto &tensor_in_0 = tensors.at(inputs.at(0)); + const auto &tensor_in_1 = tensors.at(inputs.at(1)); if (tensor_in_0->type != tensor_in_1->type) return false; @@ -48,8 +48,8 @@ CircleNode *CircleFloorModGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleFloorMod>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp index 8937e78f1..65a863bde 100644 --- a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp +++ b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp @@ -38,9 +38,9 @@ CircleNode *CircleFullyConnectedGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleFullyConnected>(); - node->input(inputs[0]); - node->weights(inputs[1]); - node->bias(inputs[2]); // bias is optional + node->input(inputs.at(0)); + node->weights(inputs.at(1)); + node->bias(inputs.at(2)); // bias is optional // TODO Find and move to appropriate place for setting optional input if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias())) diff --git a/compiler/luci/import/src/Nodes/CircleGather.cpp b/compiler/luci/import/src/Nodes/CircleGather.cpp index 1caa05ec2..75447a38a 100644 --- a/compiler/luci/import/src/Nodes/CircleGather.cpp +++ b/compiler/luci/import/src/Nodes/CircleGather.cpp @@ -56,8 +56,8 @@ CircleNode *CircleGatherGraphBuilder::build_node(const circle::OperatorT &op, { auto *node = graph->nodes()->create<CircleGather>(); - node->params(inputs[0]); - node->indices(inputs[1]); + node->params(inputs.at(0)); + node->indices(inputs.at(1)); const auto *options = op.builtin_options.AsGatherOptions(); node->axis(options->axis); diff --git a/compiler/luci/import/src/Nodes/CircleGatherNd.cpp b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp index 621d4ae92..981adbf63 100644 --- a/compiler/luci/import/src/Nodes/CircleGatherNd.cpp +++ b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp @@ -36,7 +36,7 @@ bool CircleGatherNdGraphBuilder::validate(const ValidateArgs &args) const if (outputs.size() != 1) return false; - auto &indices_tensor = args.reader.tensors()[inputs[1]]; + auto &indices_tensor = args.reader.tensors()[inputs.at(1)]; if (!(indices_tensor->type == circle::TensorType::TensorType_INT32 || indices_tensor->type == circle::TensorType::TensorType_INT64)) @@ -53,8 +53,8 @@ CircleNode *CircleGatherNdGraphBuilder::build_node(const circle::OperatorT &, { auto *node = graph->nodes()->create<CircleGatherNd>(); - node->params(inputs[0]); - node->indices(inputs[1]); + node->params(inputs.at(0)); + node->indices(inputs.at(1)); // GatherNd options empty diff --git a/compiler/luci/import/src/Nodes/CircleGreater.cpp b/compiler/luci/import/src/Nodes/CircleGreater.cpp index 88107589c..1ad0467e4 100644 --- a/compiler/luci/import/src/Nodes/CircleGreater.cpp +++ b/compiler/luci/import/src/Nodes/CircleGreater.cpp @@ -43,7 +43,7 @@ bool CircleGreaterGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + if (tensors[inputs.at(0)]->type != tensors[inputs.at(1)]->type) return false; // NOTE: real models do have output dtype NOT BOOL @@ -67,8 +67,8 @@ CircleNode *CircleGreaterGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleGreater>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp index dff1510c5..0ac63b017 100644 --- a/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp +++ b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp @@ -40,7 +40,7 @@ bool CircleGreaterEqualGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + if (tensors[inputs.at(0)]->type != tensors[inputs.at(1)]->type) { return false; } @@ -53,8 +53,8 @@ CircleNode *CircleGreaterEqualGraphBuilder::build_node(const circle::OperatorT & loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleGreaterEqual>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleIf.cpp b/compiler/luci/import/src/Nodes/CircleIf.cpp index d6090640d..db9ffe1cd 100644 --- a/compiler/luci/import/src/Nodes/CircleIf.cpp +++ b/compiler/luci/import/src/Nodes/CircleIf.cpp @@ -43,7 +43,7 @@ bool CircleIfGraphBuilder::validate(const ValidateArgs &args) const // input 0 should be BOOL type const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); if (tensor->type != circle::TensorType_BOOL) return false; diff --git a/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp index b95c54c89..6349fd3b7 100644 --- a/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp +++ b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp @@ -38,9 +38,9 @@ CircleNode *CircleInstanceNormGraphBuilder::build_node(const circle::OperatorT & loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleInstanceNorm>(); - node->input(inputs[0]); - node->gamma(inputs[1]); - node->beta(inputs[2]); + node->input(inputs.at(0)); + node->gamma(inputs.at(1)); + node->beta(inputs.at(2)); const auto *options = op.builtin_options.AsInstanceNormOptions(); node->epsilon(options->epsilon); diff --git a/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp index fe10a8572..e4fdc200c 100644 --- a/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp +++ b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp @@ -46,7 +46,7 @@ CircleNode *CircleL2NormalizeGraphBuilder::build_node(const circle::OperatorT &o loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleL2Normalize>(); - node->x(inputs[0]); + node->x(inputs.at(0)); const auto *options = op.builtin_options.AsL2NormOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp index 023206695..202d9d6fb 100644 --- a/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp @@ -38,7 +38,7 @@ CircleNode *CircleL2Pool2DGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleL2Pool2D>(); - node->value(inputs[0]); + node->value(inputs.at(0)); const auto *options = op.builtin_options.AsPool2DOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp index 4957ceae0..ad4979f39 100644 --- a/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp +++ b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp @@ -39,7 +39,7 @@ CircleNode *CircleLeakyReluGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLeakyRelu>(); - node->features(inputs[0]); + node->features(inputs.at(0)); const auto *options = op.builtin_options.AsLeakyReluOptions(); node->alpha(options->alpha); diff --git a/compiler/luci/import/src/Nodes/CircleLess.cpp b/compiler/luci/import/src/Nodes/CircleLess.cpp index 40ad28c6e..506036908 100644 --- a/compiler/luci/import/src/Nodes/CircleLess.cpp +++ b/compiler/luci/import/src/Nodes/CircleLess.cpp @@ -39,7 +39,7 @@ bool CircleLessGraphBuilder::validate(const ValidateArgs &args) const } const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { @@ -56,7 +56,7 @@ bool CircleLessGraphBuilder::validate(const ValidateArgs &args) const return false; } - if (tensors[inputs[1]]->type != tensor->type) + if (tensors[inputs.at(1)]->type != tensor->type) { return false; } @@ -69,8 +69,8 @@ CircleNode *CircleLessGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLess>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLessEqual.cpp b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp index 13e995069..9b4f934a5 100644 --- a/compiler/luci/import/src/Nodes/CircleLessEqual.cpp +++ b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp @@ -40,7 +40,7 @@ bool CircleLessEqualGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + if (tensors[inputs.at(0)]->type != tensors[inputs.at(1)]->type) { return false; } @@ -53,8 +53,8 @@ CircleNode *CircleLessEqualGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLessEqual>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp index 7b1f0db56..0e32f62de 100644 --- a/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp +++ b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp @@ -37,7 +37,7 @@ CircleNode *CircleLocalResponseNormalizationGraphBuilder::build_node( const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLocalResponseNormalization>(); - node->input(inputs[0]); + node->input(inputs.at(0)); const auto *options = op.builtin_options.AsLocalResponseNormalizationOptions(); node->radius(options->radius); diff --git a/compiler/luci/import/src/Nodes/CircleLog.cpp b/compiler/luci/import/src/Nodes/CircleLog.cpp index 21408327d..346fc43bb 100644 --- a/compiler/luci/import/src/Nodes/CircleLog.cpp +++ b/compiler/luci/import/src/Nodes/CircleLog.cpp @@ -35,7 +35,7 @@ bool CircleLogGraphBuilder::validate(const ValidateArgs &args) const // Must be one of bfloat16, half, float32, float64, complex64, complex128. // Currently circle supports half(float16), float32, float64, complex64. const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_FLOAT16: @@ -55,7 +55,7 @@ CircleNode *CircleLogGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLog>(); - node->x(inputs[0]); + node->x(inputs.at(0)); // No options for Log diff --git a/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp index e738c4a0c..ef69e868a 100644 --- a/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp +++ b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp @@ -38,7 +38,7 @@ CircleNode *CircleLogSoftmaxGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLogSoftmax>(); - node->logits(inputs[0]); + node->logits(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp index 8509dbaf3..7844da0f6 100644 --- a/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp +++ b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp @@ -46,8 +46,8 @@ CircleNode *CircleLogicalAndGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLogicalAnd>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLogicalNot.cpp b/compiler/luci/import/src/Nodes/CircleLogicalNot.cpp index b1ed3ea37..3758642e4 100644 --- a/compiler/luci/import/src/Nodes/CircleLogicalNot.cpp +++ b/compiler/luci/import/src/Nodes/CircleLogicalNot.cpp @@ -31,7 +31,7 @@ bool CircleLogicalNotGraphBuilder::validate(const ValidateArgs &args) const // Only BOOL type is allowed for the input const auto &inputs = args.op.inputs; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); if (tensor->type != circle::TensorType::TensorType_BOOL) return false; @@ -43,7 +43,7 @@ CircleNode *CircleLogicalNotGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLogicalNot>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLogicalOr.cpp b/compiler/luci/import/src/Nodes/CircleLogicalOr.cpp index 00eb9c5df..1b87e6f9c 100644 --- a/compiler/luci/import/src/Nodes/CircleLogicalOr.cpp +++ b/compiler/luci/import/src/Nodes/CircleLogicalOr.cpp @@ -46,8 +46,8 @@ CircleNode *CircleLogicalOrGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLogicalOr>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleLogistic.cpp b/compiler/luci/import/src/Nodes/CircleLogistic.cpp index 85e7e55b2..9606e19cd 100644 --- a/compiler/luci/import/src/Nodes/CircleLogistic.cpp +++ b/compiler/luci/import/src/Nodes/CircleLogistic.cpp @@ -32,22 +32,8 @@ bool CircleLogisticGraphBuilder::validate(const ValidateArgs &args) const if (outputs.size() != 1) return false; - // Must be one of the following types - // float16, float32, float64, complex64, or complex128 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); - switch (tensor->type) - { - case circle::TensorType_FLOAT16: - case circle::TensorType_FLOAT32: - case circle::TensorType_FLOAT64: - case circle::TensorType_COMPLEX64: - break; - default: - return false; - } - - if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + if (tensors.at(inputs.at(0))->type != tensors.at(outputs[0])->type) return false; return true; @@ -58,7 +44,7 @@ CircleNode *CircleLogisticGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleLogistic>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp index f4ae03c58..a4a21a8b7 100644 --- a/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp +++ b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp @@ -35,7 +35,7 @@ bool CircleMatrixDiagGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); if (tensors[outputs[0]]->type != tensor->type) return false; @@ -48,7 +48,7 @@ CircleNode *CircleMatrixDiagGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMatrixDiag>(); - node->diagonal(inputs[0]); + node->diagonal(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp index d6f6aee33..cf0313149 100644 --- a/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp +++ b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp @@ -35,7 +35,7 @@ bool CircleMatrixSetDiagGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); if (tensors[outputs[0]]->type != tensor->type) return false; @@ -48,8 +48,8 @@ CircleNode *CircleMatrixSetDiagGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMatrixSetDiag>(); - node->input(inputs[0]); - node->diagonal(inputs[1]); + node->input(inputs.at(0)); + node->diagonal(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleMaxPool2D.cpp b/compiler/luci/import/src/Nodes/CircleMaxPool2D.cpp index 1798819cf..4bca0f40b 100644 --- a/compiler/luci/import/src/Nodes/CircleMaxPool2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleMaxPool2D.cpp @@ -36,7 +36,7 @@ CircleNode *CircleMaxPool2DGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMaxPool2D>(); - node->value(inputs[0]); + node->value(inputs.at(0)); const auto *options = op.builtin_options.AsPool2DOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleMaximum.cpp b/compiler/luci/import/src/Nodes/CircleMaximum.cpp index 6ca7e4079..4d1468f19 100644 --- a/compiler/luci/import/src/Nodes/CircleMaximum.cpp +++ b/compiler/luci/import/src/Nodes/CircleMaximum.cpp @@ -35,7 +35,7 @@ bool CircleMaximumGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { @@ -49,7 +49,7 @@ bool CircleMaximumGraphBuilder::validate(const ValidateArgs &args) const return false; } - if (tensors[inputs[1]]->type != tensor->type) + if (tensors[inputs.at(1)]->type != tensor->type) return false; if (tensors[outputs[0]]->type != tensor->type) @@ -63,8 +63,8 @@ CircleNode *CircleMaximumGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMaximum>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleMean.cpp b/compiler/luci/import/src/Nodes/CircleMean.cpp index 8261c7b38..d8fa9a53d 100644 --- a/compiler/luci/import/src/Nodes/CircleMean.cpp +++ b/compiler/luci/import/src/Nodes/CircleMean.cpp @@ -34,8 +34,8 @@ CircleNode *CircleMeanGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMean>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleMinimum.cpp b/compiler/luci/import/src/Nodes/CircleMinimum.cpp index b770f365f..8b4daf197 100644 --- a/compiler/luci/import/src/Nodes/CircleMinimum.cpp +++ b/compiler/luci/import/src/Nodes/CircleMinimum.cpp @@ -35,7 +35,7 @@ bool CircleMinimumGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { @@ -49,7 +49,7 @@ bool CircleMinimumGraphBuilder::validate(const ValidateArgs &args) const return false; } - if (tensors[inputs[1]]->type != tensor->type) + if (tensors[inputs.at(1)]->type != tensor->type) return false; if (tensors[outputs[0]]->type != tensor->type) @@ -63,8 +63,8 @@ CircleNode *CircleMinimumGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMinimum>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp index 41b5e5d80..e0ddd4c11 100644 --- a/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp +++ b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp @@ -38,8 +38,8 @@ CircleNode *CircleMirrorPadGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMirrorPad>(); - node->input(inputs[0]); - node->paddings(inputs[1]); + node->input(inputs.at(0)); + node->paddings(inputs.at(1)); const auto *options = op.builtin_options.AsMirrorPadOptions(); node->mode(luci_mirrorpad_mode(options->mode)); diff --git a/compiler/luci/import/src/Nodes/CircleMul.cpp b/compiler/luci/import/src/Nodes/CircleMul.cpp index d4412b96b..e3c4a7ee5 100644 --- a/compiler/luci/import/src/Nodes/CircleMul.cpp +++ b/compiler/luci/import/src/Nodes/CircleMul.cpp @@ -37,8 +37,8 @@ CircleNode *CircleMulGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleMul>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); const auto *options = op.builtin_options.AsMulOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleNeg.cpp b/compiler/luci/import/src/Nodes/CircleNeg.cpp index 3d3079ca2..a64a69560 100644 --- a/compiler/luci/import/src/Nodes/CircleNeg.cpp +++ b/compiler/luci/import/src/Nodes/CircleNeg.cpp @@ -36,7 +36,7 @@ CircleNode *CircleNegGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleNeg>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleNonMaxSuppressionV4.cpp b/compiler/luci/import/src/Nodes/CircleNonMaxSuppressionV4.cpp new file mode 100644 index 000000000..a4ad4a53d --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleNonMaxSuppressionV4.cpp @@ -0,0 +1,123 @@ +/* + * 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 "luci/Import/Nodes/CircleNonMaxSuppressionV4.h" + +#include <luci/IR/Nodes/CircleNonMaxSuppressionV4.h> +#include <luci/IR/Nodes/CircleNonMaxSuppressionV4Out.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleNonMaxSuppressionV4GraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 5) + return false; + if (outputs.size() != 2) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &boxes_tensor = tensors.at(inputs[0]); + if (boxes_tensor->shape.size() != 2) + return false; + if (boxes_tensor->shape.at(1) != 4) + return false; + if (boxes_tensor->shape.at(0) != tensors.at(inputs[1])->shape.at(0)) + return false; + + if (tensors.at(inputs[2])->type != circle::TensorType_INT32) + return false; + if (tensors.at(inputs[3])->type != circle::TensorType_FLOAT32) + return false; + if (tensors.at(inputs[4])->type != circle::TensorType_FLOAT32) + return false; + + return true; +} + +/** + * @brief NonMaxSuppressionV4 Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple NonMasSuppressionV4Oout nodes to emulate this + */ + +void CircleNonMaxSuppressionV4GraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleNonMaxSuppressionV4 + auto node = graph->nodes()->create<CircleNonMaxSuppressionV4>(); + node->boxes(input_nodes[0]); + node->scores(input_nodes[1]); + node->max_output_size(input_nodes[2]); + node->iou_threshold(input_nodes[3]); + node->score_threshold(input_nodes[4]); + + assert(outputs.size() == 2); + { + // Let's use name of output 0 as NonMaxSuppressionV4 name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for NonMaxSuppressionV4 itself but to virtual outputs + } + + // Create virtual outputs of NonMaxSuppressionV4 + for (size_t n = 0; n < outputs.size(); ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleNonMaxSuppressionV4Out>(); + copy_tensor_attributes(output_tensor, nodeout); + + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleNotEqual.cpp b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp index 5b04856db..77e986de1 100644 --- a/compiler/luci/import/src/Nodes/CircleNotEqual.cpp +++ b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp @@ -40,7 +40,7 @@ bool CircleNotEqualGraphBuilder::validate(const ValidateArgs &args) const const auto &tensors = args.reader.tensors(); - if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + if (tensors[inputs.at(0)]->type != tensors[inputs.at(1)]->type) { return false; } @@ -53,8 +53,8 @@ CircleNode *CircleNotEqualGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleNotEqual>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleOneHot.cpp b/compiler/luci/import/src/Nodes/CircleOneHot.cpp index 9fdbfa84d..69294e1ed 100644 --- a/compiler/luci/import/src/Nodes/CircleOneHot.cpp +++ b/compiler/luci/import/src/Nodes/CircleOneHot.cpp @@ -38,10 +38,10 @@ bool CircleOneHotGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &indices = tensors.at(inputs[0]); - const auto &depth = tensors.at(inputs[1]); - const auto &on_value = tensors.at(inputs[2]); - const auto &off_value = tensors.at(inputs[3]); + const auto &indices = tensors.at(inputs.at(0)); + const auto &depth = tensors.at(inputs.at(1)); + const auto &on_value = tensors.at(inputs.at(2)); + const auto &off_value = tensors.at(inputs.at(3)); if (options->axis < -1 || options->axis > static_cast<int32_t>(indices->shape.size())) return false; @@ -63,10 +63,10 @@ CircleNode *CircleOneHotGraphBuilder::build_node(const circle::OperatorT &op, { auto *node = graph->nodes()->create<CircleOneHot>(); - node->indices(inputs[0]); - node->depth(inputs[1]); - node->on_value(inputs[2]); - node->off_value(inputs[3]); + node->indices(inputs.at(0)); + node->depth(inputs.at(1)); + node->on_value(inputs.at(2)); + node->off_value(inputs.at(3)); const auto *options = op.builtin_options.AsOneHotOptions(); node->axis(options->axis); diff --git a/compiler/luci/import/src/Nodes/CirclePRelu.cpp b/compiler/luci/import/src/Nodes/CirclePRelu.cpp index 0d87cd423..c07920f7c 100644 --- a/compiler/luci/import/src/Nodes/CirclePRelu.cpp +++ b/compiler/luci/import/src/Nodes/CirclePRelu.cpp @@ -39,8 +39,8 @@ CircleNode *CirclePReluGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CirclePRelu>(); - node->input(inputs[0]); - node->alpha(inputs[1]); + node->input(inputs.at(0)); + node->alpha(inputs.at(1)); // PRelu options are empty diff --git a/compiler/luci/import/src/Nodes/CirclePad.cpp b/compiler/luci/import/src/Nodes/CirclePad.cpp index 6abcf2d6c..999173b90 100644 --- a/compiler/luci/import/src/Nodes/CirclePad.cpp +++ b/compiler/luci/import/src/Nodes/CirclePad.cpp @@ -38,8 +38,8 @@ CircleNode *CirclePadGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CirclePad>(); - node->input(inputs[0]); - node->paddings(inputs[1]); + node->input(inputs.at(0)); + node->paddings(inputs.at(1)); const auto *options = op.builtin_options.AsPadOptions(); (void)options; // There are no options. diff --git a/compiler/luci/import/src/Nodes/CirclePow.cpp b/compiler/luci/import/src/Nodes/CirclePow.cpp index ff9833165..def012614 100644 --- a/compiler/luci/import/src/Nodes/CirclePow.cpp +++ b/compiler/luci/import/src/Nodes/CirclePow.cpp @@ -39,8 +39,8 @@ CircleNode *CirclePowGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CirclePow>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); // Pow options are empty diff --git a/compiler/luci/import/src/Nodes/CircleRange.cpp b/compiler/luci/import/src/Nodes/CircleRange.cpp index c21191605..38dc44ed6 100644 --- a/compiler/luci/import/src/Nodes/CircleRange.cpp +++ b/compiler/luci/import/src/Nodes/CircleRange.cpp @@ -36,9 +36,9 @@ CircleNode *CircleRangeGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRange>(); - node->start(inputs[0]); - node->limit(inputs[1]); - node->delta(inputs[2]); + node->start(inputs.at(0)); + node->limit(inputs.at(1)); + node->delta(inputs.at(2)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleRank.cpp b/compiler/luci/import/src/Nodes/CircleRank.cpp index 705ae0120..12658b192 100644 --- a/compiler/luci/import/src/Nodes/CircleRank.cpp +++ b/compiler/luci/import/src/Nodes/CircleRank.cpp @@ -38,7 +38,7 @@ CircleNode *CircleRankGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRank>(); - node->input(inputs[0]); + node->input(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleReduceAny.cpp b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp index 030c5304c..21a821951 100644 --- a/compiler/luci/import/src/Nodes/CircleReduceAny.cpp +++ b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp @@ -31,8 +31,8 @@ bool CircleReduceAnyGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_0 = tensors.at(inputs[0]); - const auto &tensor_1 = tensors.at(inputs[1]); + const auto &tensor_0 = tensors.at(inputs.at(0)); + const auto &tensor_1 = tensors.at(inputs.at(1)); const auto &tensor_o = tensors.at(outputs[0]); if (tensor_0->type != circle::TensorType_BOOL) @@ -57,8 +57,8 @@ CircleNode *CircleReduceAnyGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReduceAny>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleReduceMax.cpp b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp index 8ca8e2e34..05492dbc6 100644 --- a/compiler/luci/import/src/Nodes/CircleReduceMax.cpp +++ b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp @@ -33,7 +33,7 @@ bool CircleReduceMaxGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_axis = tensors.at(inputs[1]); + const auto &tensor_axis = tensors.at(inputs.at(1)); switch (tensor_axis->type) { @@ -52,8 +52,8 @@ CircleNode *CircleReduceMaxGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReduceMax>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleReduceMin.cpp b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp index 3020c3778..117d5295a 100644 --- a/compiler/luci/import/src/Nodes/CircleReduceMin.cpp +++ b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp @@ -33,7 +33,7 @@ bool CircleReduceMinGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_axis = tensors.at(inputs[1]); + const auto &tensor_axis = tensors.at(inputs.at(1)); switch (tensor_axis->type) { @@ -52,8 +52,8 @@ CircleNode *CircleReduceMinGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReduceMin>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleReduceProd.cpp b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp index 2bb43f6ce..5f054586e 100644 --- a/compiler/luci/import/src/Nodes/CircleReduceProd.cpp +++ b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp @@ -30,7 +30,7 @@ bool CircleReduceProdGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_1 = tensors.at(inputs[1]); + const auto &tensor_1 = tensors.at(inputs.at(1)); // TODO check input types @@ -52,8 +52,8 @@ CircleNode *CircleReduceProdGraphBuilder::build_node(const circle::OperatorT &op loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReduceProd>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleRelu.cpp b/compiler/luci/import/src/Nodes/CircleRelu.cpp index 056268a5b..8e1c32a3a 100644 --- a/compiler/luci/import/src/Nodes/CircleRelu.cpp +++ b/compiler/luci/import/src/Nodes/CircleRelu.cpp @@ -39,7 +39,7 @@ CircleNode *CircleReluGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRelu>(); - node->features(inputs[0]); + node->features(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleRelu6.cpp b/compiler/luci/import/src/Nodes/CircleRelu6.cpp index 5b443993b..0283d7350 100644 --- a/compiler/luci/import/src/Nodes/CircleRelu6.cpp +++ b/compiler/luci/import/src/Nodes/CircleRelu6.cpp @@ -39,7 +39,7 @@ CircleNode *CircleRelu6GraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRelu6>(); - node->features(inputs[0]); + node->features(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp index edf662fb9..7f517bc0d 100644 --- a/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp +++ b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp @@ -41,7 +41,7 @@ CircleNode *CircleReluN1To1GraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReluN1To1>(); - node->features(inputs[0]); + node->features(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleReshape.cpp b/compiler/luci/import/src/Nodes/CircleReshape.cpp index f72c152b1..996ae9d20 100644 --- a/compiler/luci/import/src/Nodes/CircleReshape.cpp +++ b/compiler/luci/import/src/Nodes/CircleReshape.cpp @@ -62,7 +62,7 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op, { // If the second input is not provided, generate it based on the value of the attribute. // TODO Presence of the second input is the current requirement of the IR. - auto *shape_node = (inputs.size() == 2) ? inputs[1] : nullptr; + auto *shape_node = (inputs.size() == 2) ? inputs.at(1) : nullptr; if (shape_node == nullptr) { const auto *options = op.builtin_options.AsReshapeOptions(); @@ -77,7 +77,7 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op, } auto *node = graph->nodes()->create<CircleReshape>(); - node->tensor(inputs[0]); + node->tensor(inputs.at(0)); node->shape(shape_node); const auto *options = op.builtin_options.AsReshapeOptions(); diff --git a/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp index 6128f1b86..0fccb7b44 100644 --- a/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp +++ b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp @@ -38,8 +38,8 @@ CircleNode *CircleResizeBilinearGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleResizeBilinear>(); - node->input(inputs[0]); - node->size(inputs[1]); + node->input(inputs.at(0)); + node->size(inputs.at(1)); const auto *options = op.builtin_options.AsResizeBilinearOptions(); node->align_corners(options->align_corners); diff --git a/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp index a1f1ef0ff..324323f59 100644 --- a/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp +++ b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp @@ -37,8 +37,8 @@ CircleNode *CircleResizeNearestNeighborGraphBuilder::build_node( const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleResizeNearestNeighbor>(); - node->input(inputs[0]); - node->size(inputs[1]); + node->input(inputs.at(0)); + node->size(inputs.at(1)); const auto *options = op.builtin_options.AsResizeNearestNeighborOptions(); node->align_corners(options->align_corners); diff --git a/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp index 72d3b153d..ad11d4c63 100644 --- a/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp +++ b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp @@ -34,8 +34,8 @@ bool CircleReverseSequenceGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_in = tensors.at(inputs[0]); - const auto &tensor_lengths = tensors.at(inputs[1]); + const auto &tensor_in = tensors.at(inputs.at(0)); + const auto &tensor_lengths = tensors.at(inputs.at(1)); const auto &tensor_out = tensors.at(outputs[0]); switch (tensor_lengths->type) @@ -58,8 +58,8 @@ CircleNode *CircleReverseSequenceGraphBuilder::build_node(const circle::Operator loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReverseSequence>(); - node->input(inputs[0]); - node->seq_lengths(inputs[1]); + node->input(inputs.at(0)); + node->seq_lengths(inputs.at(1)); const auto *options = op.builtin_options.AsReverseSequenceOptions(); node->seq_axis(options->seq_dim); diff --git a/compiler/luci/import/src/Nodes/CircleReverseV2.cpp b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp index cd18128a7..e2e53bb4b 100644 --- a/compiler/luci/import/src/Nodes/CircleReverseV2.cpp +++ b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp @@ -34,8 +34,8 @@ bool CircleReverseV2GraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_in = tensors.at(inputs[0]); - const auto &tensor_axis = tensors.at(inputs[1]); + const auto &tensor_in = tensors.at(inputs.at(0)); + const auto &tensor_axis = tensors.at(inputs.at(1)); const auto &tensor_out = tensors.at(outputs[0]); switch (tensor_axis->type) @@ -58,8 +58,8 @@ CircleNode *CircleReverseV2GraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleReverseV2>(); - node->tensor(inputs[0]); - node->axis(inputs[1]); + node->tensor(inputs.at(0)); + node->axis(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleRound.cpp b/compiler/luci/import/src/Nodes/CircleRound.cpp index 896489521..ad77f9f03 100644 --- a/compiler/luci/import/src/Nodes/CircleRound.cpp +++ b/compiler/luci/import/src/Nodes/CircleRound.cpp @@ -37,7 +37,7 @@ bool CircleRoundGraphBuilder::validate(const ValidateArgs &args) const // bfloat16, half (float16), float32, float64, complex64, complex128 // Currently, circle supports float16, float32, complex64 const auto &tensors = args.reader.tensors(); - const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_in = tensors.at(inputs.at(0)); const auto &tensor_out = tensors.at(outputs[0]); switch (tensor_in->type) @@ -63,7 +63,7 @@ CircleNode *CircleRoundGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRound>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleRsqrt.cpp b/compiler/luci/import/src/Nodes/CircleRsqrt.cpp index b5de0b575..ae05fbbf9 100644 --- a/compiler/luci/import/src/Nodes/CircleRsqrt.cpp +++ b/compiler/luci/import/src/Nodes/CircleRsqrt.cpp @@ -33,7 +33,7 @@ bool CircleRsqrtGraphBuilder::validate(const ValidateArgs &args) const // bfloat16, half (float16), float32, float64, complex64, complex128 // Currently, circle supports float16, float32, complex64 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_FLOAT16: @@ -52,7 +52,7 @@ CircleNode *CircleRsqrtGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleRsqrt>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleScatterNd.cpp b/compiler/luci/import/src/Nodes/CircleScatterNd.cpp index adcaa0030..7f86aeb74 100644 --- a/compiler/luci/import/src/Nodes/CircleScatterNd.cpp +++ b/compiler/luci/import/src/Nodes/CircleScatterNd.cpp @@ -32,12 +32,12 @@ bool CircleScatterNdGraphBuilder::validate(const ValidateArgs &args) const // indices must have the same type as shape const auto &tensors = args.reader.tensors(); - if (tensors[inputs[0]]->type != tensors[inputs[2]]->type) + if (tensors[inputs.at(0)]->type != tensors[inputs.at(2)]->type) return false; // indices must be either int32 or int64 - if (tensors[inputs[0]]->type != circle::TensorType_INT32 && - tensors[inputs[0]]->type != circle::TensorType_INT64) + if (tensors[inputs.at(0)]->type != circle::TensorType_INT32 && + tensors[inputs.at(0)]->type != circle::TensorType_INT64) return false; return true; @@ -48,9 +48,9 @@ CircleNode *CircleScatterNdGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleScatterNd>(); - node->indices(inputs[0]); - node->updates(inputs[1]); - node->shape(inputs[2]); + node->indices(inputs.at(0)); + node->updates(inputs.at(1)); + node->shape(inputs.at(2)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp index 1122bdca3..fb84e5d52 100644 --- a/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp +++ b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp @@ -33,9 +33,9 @@ bool CircleSegmentSumGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_in = tensors.at(inputs.at(0)); const auto &tensor_out = tensors.at(outputs[0]); - const auto &tensor_ids = tensors.at(inputs[1]); + const auto &tensor_ids = tensors.at(inputs.at(1)); switch (tensor_ids->type) { @@ -59,8 +59,8 @@ CircleNode *CircleSegmentSumGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSegmentSum>(); - node->input(inputs[0]); - node->segment_ids(inputs[1]); + node->input(inputs.at(0)); + node->segment_ids(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSelect.cpp b/compiler/luci/import/src/Nodes/CircleSelect.cpp index ff94212c3..1e649f1e0 100644 --- a/compiler/luci/import/src/Nodes/CircleSelect.cpp +++ b/compiler/luci/import/src/Nodes/CircleSelect.cpp @@ -33,7 +33,7 @@ bool CircleSelectGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); if (tensor->type != circle::TensorType_BOOL) return false; // TODO check dtypes for input 1, 2 @@ -46,9 +46,9 @@ CircleNode *CircleSelectGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSelect>(); - node->condition(inputs[0]); - node->t(inputs[1]); - node->e(inputs[2]); + node->condition(inputs.at(0)); + node->t(inputs.at(1)); + node->e(inputs.at(2)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSelectV2.cpp b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp index 78b2e6459..e6dd04de0 100644 --- a/compiler/luci/import/src/Nodes/CircleSelectV2.cpp +++ b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp @@ -33,12 +33,12 @@ bool CircleSelectV2GraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &condition = tensors.at(inputs[0]); + const auto &condition = tensors.at(inputs.at(0)); if (condition->type != circle::TensorType_BOOL) return false; - const auto &t = tensors.at(inputs[1]); - const auto &e = tensors.at(inputs[2]); + const auto &t = tensors.at(inputs.at(1)); + const auto &e = tensors.at(inputs.at(2)); if (t->type != e->type) return false; @@ -50,9 +50,9 @@ CircleNode *CircleSelectV2GraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSelectV2>(); - node->condition(inputs[0]); - node->t(inputs[1]); - node->e(inputs[2]); + node->condition(inputs.at(0)); + node->t(inputs.at(1)); + node->e(inputs.at(2)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleShape.cpp b/compiler/luci/import/src/Nodes/CircleShape.cpp index 864b5eb51..bd7dfc9d9 100644 --- a/compiler/luci/import/src/Nodes/CircleShape.cpp +++ b/compiler/luci/import/src/Nodes/CircleShape.cpp @@ -42,7 +42,7 @@ CircleNode *CircleShapeGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleShape>(); - node->input(inputs[0]); + node->input(inputs.at(0)); const auto *options = op.builtin_options.AsShapeOptions(); node->out_type(luci_datatype(options->out_type)); diff --git a/compiler/luci/import/src/Nodes/CircleSin.cpp b/compiler/luci/import/src/Nodes/CircleSin.cpp index 61d60c78f..4b245ef6b 100644 --- a/compiler/luci/import/src/Nodes/CircleSin.cpp +++ b/compiler/luci/import/src/Nodes/CircleSin.cpp @@ -33,7 +33,7 @@ bool CircleSinGraphBuilder::validate(const ValidateArgs &args) const // input type check const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_FLOAT16: @@ -53,7 +53,7 @@ CircleNode *CircleSinGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSin>(); - node->x(inputs[0]); + node->x(inputs.at(0)); // No options for Sin diff --git a/compiler/luci/import/src/Nodes/CircleSlice.cpp b/compiler/luci/import/src/Nodes/CircleSlice.cpp index 313c35599..8601fbf21 100644 --- a/compiler/luci/import/src/Nodes/CircleSlice.cpp +++ b/compiler/luci/import/src/Nodes/CircleSlice.cpp @@ -42,9 +42,9 @@ CircleNode *CircleSliceGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSlice>(); - node->input(inputs[0]); - node->begin(inputs[1]); - node->size(inputs[2]); + node->input(inputs.at(0)); + node->begin(inputs.at(1)); + node->size(inputs.at(2)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSoftmax.cpp b/compiler/luci/import/src/Nodes/CircleSoftmax.cpp index 0d316e18c..0ef0b5418 100644 --- a/compiler/luci/import/src/Nodes/CircleSoftmax.cpp +++ b/compiler/luci/import/src/Nodes/CircleSoftmax.cpp @@ -38,7 +38,7 @@ CircleNode *CircleSoftmaxGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSoftmax>(); - node->logits(inputs[0]); + node->logits(inputs.at(0)); const auto *options = op.builtin_options.AsSoftmaxOptions(); node->beta(options->beta); diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp index f1361fb11..c1d508e3e 100644 --- a/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp +++ b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp @@ -33,7 +33,7 @@ bool CircleSpaceToBatchNDGraphBuilder::validate(const ValidateArgs &args) const // input 1 and 2 should have INT32/INT64 type const auto &tensors = args.reader.tensors(); - const auto &tensor_1 = tensors.at(inputs[1]); + const auto &tensor_1 = tensors.at(inputs.at(1)); switch (tensor_1->type) { case circle::TensorType_INT32: @@ -42,7 +42,7 @@ bool CircleSpaceToBatchNDGraphBuilder::validate(const ValidateArgs &args) const default: return false; } - const auto &tensor_2 = tensors.at(inputs[2]); + const auto &tensor_2 = tensors.at(inputs.at(2)); switch (tensor_2->type) { case circle::TensorType_INT32: @@ -53,7 +53,7 @@ bool CircleSpaceToBatchNDGraphBuilder::validate(const ValidateArgs &args) const } // Only support input shape dimension 3 and 4 only - const auto &tensor_0 = tensors.at(inputs[0]); + const auto &tensor_0 = tensors.at(inputs.at(0)); const auto t_0_s = tensor_0->shape.size(); if (t_0_s != 3 && t_0_s != 4) return false; @@ -68,9 +68,9 @@ CircleNode *CircleSpaceToBatchNDGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSpaceToBatchND>(); - node->input(inputs[0]); - node->block_shape(inputs[1]); - node->paddings(inputs[2]); + node->input(inputs.at(0)); + node->block_shape(inputs.at(1)); + node->paddings(inputs.at(2)); // No options for SpaceToBatchND diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp index b612c9a9a..8ccd55dc6 100644 --- a/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp +++ b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp @@ -41,7 +41,7 @@ CircleNode *CircleSpaceToDepthGraphBuilder::build_node(const circle::OperatorT & loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSpaceToDepth>(); - node->input(inputs[0]); + node->input(inputs.at(0)); const auto *options = op.builtin_options.AsSpaceToDepthOptions(); node->block_size(options->block_size); diff --git a/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp index bfe790fc1..26d575e90 100644 --- a/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp +++ b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp @@ -36,10 +36,10 @@ CircleNode *CircleSparseToDenseGraphBuilder::build_node(const circle::OperatorT loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSparseToDense>(); - node->indices(inputs[0]); - node->output_shape(inputs[1]); - node->values(inputs[2]); - node->default_value(inputs[3]); + node->indices(inputs.at(0)); + node->output_shape(inputs.at(1)); + node->values(inputs.at(2)); + node->default_value(inputs.at(3)); const auto *options = op.builtin_options.AsSparseToDenseOptions(); node->validate_indices(options->validate_indices); diff --git a/compiler/luci/import/src/Nodes/CircleSqrt.cpp b/compiler/luci/import/src/Nodes/CircleSqrt.cpp index 8a90f6691..c8beaee0d 100644 --- a/compiler/luci/import/src/Nodes/CircleSqrt.cpp +++ b/compiler/luci/import/src/Nodes/CircleSqrt.cpp @@ -36,7 +36,7 @@ CircleNode *CircleSqrtGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSqrt>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSquare.cpp b/compiler/luci/import/src/Nodes/CircleSquare.cpp index 8398548b6..b5ba048d7 100644 --- a/compiler/luci/import/src/Nodes/CircleSquare.cpp +++ b/compiler/luci/import/src/Nodes/CircleSquare.cpp @@ -33,7 +33,7 @@ bool CircleSquareGraphBuilder::validate(const ValidateArgs &args) const // bfloat16, half (float16), float32, float64, complex64, complex128 // Currently, circle supports float16, float32, complex64 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_INT32: @@ -55,7 +55,7 @@ CircleNode *CircleSquareGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSquare>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp index 93ce959e2..6deae94c5 100644 --- a/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp +++ b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp @@ -37,7 +37,7 @@ bool CircleSquaredDifferenceGraphBuilder::validate(const ValidateArgs &args) con // Inputs must be one of the following types // bfloat16, half(float16), float32, float64, int32, int64, complex64, complex128 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); switch (tensor->type) { case circle::TensorType_FLOAT16: @@ -53,11 +53,11 @@ bool CircleSquaredDifferenceGraphBuilder::validate(const ValidateArgs &args) con } // Input types must match - if (tensors.at(inputs[0])->type != tensors.at(inputs[1])->type) + if (tensors.at(inputs.at(0))->type != tensors.at(inputs.at(1))->type) return false; // Input and output types must match - if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + if (tensors.at(inputs.at(0))->type != tensors.at(outputs[0])->type) return false; return true; @@ -68,8 +68,8 @@ CircleNode *CircleSquaredDifferenceGraphBuilder::build_node(const circle::Operat loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSquaredDifference>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleSqueeze.cpp b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp index a5252d0bb..32792c266 100644 --- a/compiler/luci/import/src/Nodes/CircleSqueeze.cpp +++ b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp @@ -38,7 +38,7 @@ CircleNode *CircleSqueezeGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSqueeze>(); - node->input(inputs[0]); + node->input(inputs.at(0)); const auto *options = op.builtin_options.AsSqueezeOptions(); assert(options); diff --git a/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp index 95e446704..8f943a682 100644 --- a/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp +++ b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp @@ -42,10 +42,10 @@ CircleNode *CircleStridedSliceGraphBuilder::build_node(const circle::OperatorT & loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleStridedSlice>(); - node->input(inputs[0]); - node->begin(inputs[1]); - node->end(inputs[2]); - node->strides(inputs[3]); + node->input(inputs.at(0)); + node->begin(inputs.at(1)); + node->end(inputs.at(2)); + node->strides(inputs.at(3)); const auto *options = op.builtin_options.AsStridedSliceOptions(); node->begin_mask(options->begin_mask); diff --git a/compiler/luci/import/src/Nodes/CircleSub.cpp b/compiler/luci/import/src/Nodes/CircleSub.cpp index 968e9f51f..9acf83d40 100644 --- a/compiler/luci/import/src/Nodes/CircleSub.cpp +++ b/compiler/luci/import/src/Nodes/CircleSub.cpp @@ -39,8 +39,8 @@ CircleNode *CircleSubGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSub>(); - node->x(inputs[0]); - node->y(inputs[1]); + node->x(inputs.at(0)); + node->y(inputs.at(1)); const auto *options = op.builtin_options.AsSubOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleSum.cpp b/compiler/luci/import/src/Nodes/CircleSum.cpp index b4865de59..bd3cb6239 100644 --- a/compiler/luci/import/src/Nodes/CircleSum.cpp +++ b/compiler/luci/import/src/Nodes/CircleSum.cpp @@ -34,8 +34,8 @@ CircleNode *CircleSumGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleSum>(); - node->input(inputs[0]); - node->reduction_indices(inputs[1]); + node->input(inputs.at(0)); + node->reduction_indices(inputs.at(1)); const auto *options = op.builtin_options.AsReducerOptions(); node->keep_dims(options->keep_dims); diff --git a/compiler/luci/import/src/Nodes/CircleTanh.cpp b/compiler/luci/import/src/Nodes/CircleTanh.cpp index 8986378c4..018f5701b 100644 --- a/compiler/luci/import/src/Nodes/CircleTanh.cpp +++ b/compiler/luci/import/src/Nodes/CircleTanh.cpp @@ -28,21 +28,13 @@ bool CircleTanhGraphBuilder::validate(const ValidateArgs &args) const const auto &inputs = args.op.inputs; if (inputs.size() != 1) return false; + const auto &outputs = args.op.outputs; + if (outputs.size() != 1) + return false; - // Must be one of the following types - // bfloat16, half (float16), float32, float64, complex64, complex128 - // Currently, circle supports float16, float32, complex64 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); - switch (tensor->type) - { - case circle::TensorType_FLOAT16: - case circle::TensorType_FLOAT32: - case circle::TensorType_COMPLEX64: - break; - default: - return false; - } + if (tensors.at(inputs.at(0))->type != tensors.at(outputs[0])->type) + return false; return true; } @@ -52,7 +44,7 @@ CircleNode *CircleTanhGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleTanh>(); - node->x(inputs[0]); + node->x(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleTile.cpp b/compiler/luci/import/src/Nodes/CircleTile.cpp index 91054ce7f..bc6f320ba 100644 --- a/compiler/luci/import/src/Nodes/CircleTile.cpp +++ b/compiler/luci/import/src/Nodes/CircleTile.cpp @@ -34,10 +34,10 @@ bool CircleTileGraphBuilder::validate(const ValidateArgs &args) const if (outputs.size() != 1) return false; - // Multiples (inputs[1]) must be one of the following types + // Multiples (inputs.at(1)) must be one of the following types // int32, int64 const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[1]); + const auto &tensor = tensors.at(inputs.at(1)); switch (tensor->type) { case circle::TensorType_INT32: @@ -48,7 +48,7 @@ bool CircleTileGraphBuilder::validate(const ValidateArgs &args) const } // Type of input and output must be the same - if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + if (tensors.at(inputs.at(0))->type != tensors.at(outputs[0])->type) return false; return true; @@ -59,8 +59,8 @@ CircleNode *CircleTileGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleTile>(); - node->input(inputs[0]); - node->multiples(inputs[1]); + node->input(inputs.at(0)); + node->multiples(inputs.at(1)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleTopKV2.cpp b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp index 5c1051c43..f0677de86 100644 --- a/compiler/luci/import/src/Nodes/CircleTopKV2.cpp +++ b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp @@ -36,7 +36,7 @@ bool CircleTopKV2GraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[1]); + const auto &tensor = tensors.at(inputs.at(1)); if (tensor->type != circle::TensorType_INT32) return false; diff --git a/compiler/luci/import/src/Nodes/CircleTranspose.cpp b/compiler/luci/import/src/Nodes/CircleTranspose.cpp index 8622c8b80..cc3153085 100644 --- a/compiler/luci/import/src/Nodes/CircleTranspose.cpp +++ b/compiler/luci/import/src/Nodes/CircleTranspose.cpp @@ -39,8 +39,8 @@ CircleNode *CircleTransposeGraphBuilder::build_node(const circle::OperatorT &op, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleTranspose>(); - node->a(inputs[0]); - node->perm(inputs[1]); + node->a(inputs.at(0)); + node->perm(inputs.at(1)); const auto *options = op.builtin_options.AsTransposeOptions(); (void)options; diff --git a/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp index 7bdf46daa..ddb196657 100644 --- a/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp +++ b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp @@ -30,6 +30,24 @@ bool CircleTransposeConvGraphBuilder::validate(const ValidateArgs &args) const if (args.op.inputs.size() != 3) return false; + const auto &inputs = args.op.inputs; + const auto &tensors = args.reader.tensors(); + const auto &filter_tensor = tensors.at(inputs.at(1)); + const auto &filter_shape = filter_tensor.get()->shape; + const auto &ifm_tensor = tensors.at(inputs.at(2)); + const auto &ifm_shape = ifm_tensor.get()->shape; + + // ifm and filters must be 4-D tensor + if (ifm_shape.size() != 4) + return false; + if (filter_shape.size() != 4) + return false; + + // input shape : [batch, height, width, in_channels] + // filters shape : [output_channels, height, weight, in_channels] + if (ifm_tensor.get()->shape.at(3) != filter_tensor.get()->shape.at(3)) + return false; + return true; } @@ -39,9 +57,9 @@ CircleNode *CircleTransposeConvGraphBuilder::build_node(const circle::OperatorT { auto *node = graph->nodes()->create<CircleTransposeConv>(); - node->inputSizes(inputs[0]); - node->filter(inputs[1]); - node->outBackprop(inputs[2]); + node->inputSizes(inputs.at(0)); + node->filter(inputs.at(1)); + node->outBackprop(inputs.at(2)); const auto *options = op.builtin_options.AsTransposeConvOptions(); node->padding(luci_padding(options->padding)); diff --git a/compiler/luci/import/src/Nodes/CircleUnique.cpp b/compiler/luci/import/src/Nodes/CircleUnique.cpp new file mode 100644 index 000000000..5e79a2920 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleUnique.cpp @@ -0,0 +1,89 @@ +/* + * 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 "luci/Import/Nodes/CircleUnique.h" + +#include <luci/IR/Nodes/CircleUnique.h> +#include <luci/IR/Nodes/CircleUniqueOut.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleUniqueGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 2) + return false; + + return true; +} + +void CircleUniqueGraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleUnique + auto node = graph->nodes()->create<CircleUnique>(); + node->input(input_nodes[0]); + + const auto *options = op.builtin_options.AsUniqueOptions(); + node->output_type(luci_datatype(options->idx_out_type)); + + assert(int32_t(outputs.size()) == 2); + // Let's use name of output 0 as Unique name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + + // Create virtual outputs of Unique + for (int32_t n = 0; n < 2; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleUniqueOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleUnpack.cpp b/compiler/luci/import/src/Nodes/CircleUnpack.cpp index c4282e24f..9e7f3d3e1 100644 --- a/compiler/luci/import/src/Nodes/CircleUnpack.cpp +++ b/compiler/luci/import/src/Nodes/CircleUnpack.cpp @@ -59,7 +59,7 @@ bool CircleUnpackGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor = tensors.at(inputs[0]); + const auto &tensor = tensors.at(inputs.at(0)); const auto &shape = tensor->shape; auto shape_size = static_cast<int32_t>(shape.size()); if (shape_size > 0) diff --git a/compiler/luci/import/src/Nodes/CircleWhere.cpp b/compiler/luci/import/src/Nodes/CircleWhere.cpp index a13c4d6c9..f4c5f0c66 100644 --- a/compiler/luci/import/src/Nodes/CircleWhere.cpp +++ b/compiler/luci/import/src/Nodes/CircleWhere.cpp @@ -35,7 +35,7 @@ bool CircleWhereGraphBuilder::validate(const ValidateArgs &args) const return false; const auto &tensors = args.reader.tensors(); - const auto &tensor_condition = tensors.at(inputs[0]); + const auto &tensor_condition = tensors.at(inputs.at(0)); const auto &tensor_out = tensors.at(outputs[0]); if (tensor_condition->type != circle::TensorType_BOOL) @@ -52,7 +52,7 @@ CircleNode *CircleWhereGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleWhere>(); - node->condition(inputs[0]); + node->condition(inputs.at(0)); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleZerosLike.cpp b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp index 4362925cd..e60424def 100644 --- a/compiler/luci/import/src/Nodes/CircleZerosLike.cpp +++ b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp @@ -39,7 +39,7 @@ CircleNode *CircleZerosLikeGraphBuilder::build_node(const circle::OperatorT &, loco::Graph *graph) const { auto *node = graph->nodes()->create<CircleZerosLike>(); - node->input(inputs[0]); + node->input(inputs.at(0)); // ZerosLikeOptinos are empty diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.h b/compiler/luci/lang/include/luci/IR/CircleNodes.h index 3b31149b2..e57f5bb3e 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodes.h +++ b/compiler/luci/lang/include/luci/IR/CircleNodes.h @@ -70,10 +70,12 @@ #include "Nodes/CircleMirrorPad.h" #include "Nodes/CircleMul.h" #include "Nodes/CircleNeg.h" +#include "Nodes/CircleNonMaxSuppressionV4.h" #include "Nodes/CircleNotEqual.h" #include "Nodes/CircleOneHot.h" #include "Nodes/CirclePack.h" #include "Nodes/CirclePad.h" +#include "Nodes/CirclePadV2.h" #include "Nodes/CirclePow.h" #include "Nodes/CirclePRelu.h" #include "Nodes/CircleRange.h" @@ -117,6 +119,7 @@ #include "Nodes/CircleTopKV2.h" #include "Nodes/CircleTranspose.h" #include "Nodes/CircleTransposeConv.h" +#include "Nodes/CircleUnique.h" #include "Nodes/CircleUnpack.h" #include "Nodes/CircleWhere.h" #include "Nodes/CircleWhile.h" @@ -130,7 +133,9 @@ #include "Nodes/CircleOutput.h" #include "Nodes/CircleCustomOut.h" #include "Nodes/CircleIfOut.h" +#include "Nodes/CircleNonMaxSuppressionV4Out.h" #include "Nodes/CircleUnpackOut.h" +#include "Nodes/CircleUniqueOut.h" #include "Nodes/CircleSplitOut.h" #include "Nodes/CircleSplitVOut.h" #include "Nodes/CircleTopKV2Out.h" diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.lst b/compiler/luci/lang/include/luci/IR/CircleNodes.lst index 488dcfb89..801051848 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodes.lst +++ b/compiler/luci/lang/include/luci/IR/CircleNodes.lst @@ -22,7 +22,6 @@ CIRCLE_NODE(BATCHMATMUL, luci::CircleBatchMatMul) CIRCLE_NODE(CAST, luci::CircleCast) CIRCLE_NODE(CEIL, luci::CircleCeil) CIRCLE_NODE(CONCATENATION, luci::CircleConcatenation) -CIRCLE_NODE(CONST, luci::CircleConst) CIRCLE_NODE(CONV_2D, luci::CircleConv2D) CIRCLE_NODE(COS, luci::CircleCos) CIRCLE_NODE(CUSTOM, luci::CircleCustom) @@ -64,10 +63,12 @@ CIRCLE_NODE(MINIMUM, luci::CircleMinimum) CIRCLE_NODE(MIRROR_PAD, luci::CircleMirrorPad) CIRCLE_NODE(MUL, luci::CircleMul) CIRCLE_NODE(NEG, luci::CircleNeg) +CIRCLE_NODE(NON_MAX_SUPPRESSION_V4, luci::CircleNonMaxSuppressionV4) CIRCLE_NODE(NOT_EQUAL, luci::CircleNotEqual) CIRCLE_NODE(ONE_HOT, luci::CircleOneHot) CIRCLE_NODE(PACK, luci::CirclePack) CIRCLE_NODE(PAD, luci::CirclePad) +CIRCLE_NODE(PADV2, luci::CirclePadV2) CIRCLE_NODE(POW, luci::CirclePow) CIRCLE_NODE(PRELU, luci::CirclePRelu) CIRCLE_NODE(RANGE, luci::CircleRange) @@ -111,6 +112,7 @@ CIRCLE_NODE(TILE, luci::CircleTile) CIRCLE_NODE(TOPK_V2, luci::CircleTopKV2) CIRCLE_NODE(TRANSPOSE, luci::CircleTranspose) CIRCLE_NODE(TRANSPOSE_CONV, luci::CircleTransposeConv) +CIRCLE_NODE(UNIQUE, luci::CircleUnique) CIRCLE_NODE(UNPACK, luci::CircleUnpack) CIRCLE_NODE(WHERE, luci::CircleWhere) CIRCLE_NODE(WHILE, luci::CircleWhile) @@ -120,14 +122,17 @@ CIRCLE_NODE(BCQ_FULLY_CONNECTED, luci::CircleBCQFullyConnected) CIRCLE_NODE(BCQ_GATHER, luci::CircleBCQGather) CIRCLE_NODE(INSTANCE_NORM, luci::CircleInstanceNorm) // Virtual node(s) +CIRCLE_NODE(CIRCLECONST, luci::CircleConst) CIRCLE_NODE(CIRCLEINPUT, luci::CircleInput) CIRCLE_NODE(CIRCLEOUTPUT, luci::CircleOutput) CIRCLE_NODE(CIRCLEOUTPUTDUMMY, luci::CircleOutputDummy) CIRCLE_NODE(CIRCLEOUTPUTEXCLUDE, luci::CircleOutputExclude) CIRCLE_NODE(CIRCLECUSTOMOUT, luci::CircleCustomOut) CIRCLE_NODE(CIRCLEIFOUT, luci::CircleIfOut) +CIRCLE_NODE(CIRCLENONMAXSUPPRESSIONV4OUT, luci::CircleNonMaxSuppressionV4Out) CIRCLE_NODE(CIRCLESPLITOUT, luci::CircleSplitOut) CIRCLE_NODE(CIRCLESPLITVOUT, luci::CircleSplitVOut) CIRCLE_NODE(CIRCLETOPKV2OUT, luci::CircleTopKV2Out) +CIRCLE_NODE(CIRCLEUNIQUEOUT, luci::CircleUniqueOut) CIRCLE_NODE(CIRCLEUNPACKOUT, luci::CircleUnpackOut) CIRCLE_NODE(CIRCLEWHILEOUT, luci::CircleWhileOut) diff --git a/compiler/luci/lang/include/luci/IR/CircleQuantParam.h b/compiler/luci/lang/include/luci/IR/CircleQuantParam.h index 7253e657b..694437303 100644 --- a/compiler/luci/lang/include/luci/IR/CircleQuantParam.h +++ b/compiler/luci/lang/include/luci/IR/CircleQuantParam.h @@ -29,6 +29,7 @@ struct CircleQuantParam std::vector<float> max; std::vector<float> scale; std::vector<int64_t> zerop; + int32_t quantized_dimension{0}; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h index fc671746f..250282049 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h @@ -31,7 +31,7 @@ namespace luci * @brief Class to build tensor data * @note This will not be exported as a specific op */ -class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CONST>> +class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLECONST>> { public: CircleConst() = default; diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4.h new file mode 100644 index 000000000..69f3368c0 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4.h @@ -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. + */ + +#ifndef __LUCI_IR_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ +#define __LUCI_IR_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief NON_MAX_SUPPRESSION_V4 in Circle + */ +class CircleNonMaxSuppressionV4 final + : public FixedArityNode<5, CircleNodeImpl<CircleOpcode::NON_MAX_SUPPRESSION_V4>> +{ +public: + loco::Node *boxes(void) const { return at(0)->node(); } + void boxes(loco::Node *node) { at(0)->node(node); } + + loco::Node *scores(void) const { return at(1)->node(); } + void scores(loco::Node *node) { at(1)->node(node); } + + loco::Node *max_output_size(void) const { return at(2)->node(); } + void max_output_size(loco::Node *node) { at(2)->node(node); } + + loco::Node *iou_threshold(void) const { return at(3)->node(); } + void iou_threshold(loco::Node *node) { at(3)->node(node); } + + loco::Node *score_threshold(void) const { return at(4)->node(); } + void score_threshold(loco::Node *node) { at(4)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_NON_MAX_SUPPRESSION_V4_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4Out.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4Out.h new file mode 100644 index 000000000..a24dc3e9c --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNonMaxSuppressionV4Out.h @@ -0,0 +1,51 @@ +/* + * 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 __LUCI_IR_CIRCLE_NONMAXSUPPRESSIONV4OUT_H__ +#define __LUCI_IR_CIRCLE_NONMAXSUPPRESSIONV4OUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual NONMAXSUPPRESSIONV4OUT in Circle + */ +class CircleNonMaxSuppressionV4Out final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLENONMAXSUPPRESSIONV4OUT>> +{ +public: + CircleNonMaxSuppressionV4Out() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_NONMAXSUPPRESSIONV4OUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CirclePadV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CirclePadV2.h new file mode 100644 index 000000000..563cfd9a4 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CirclePadV2.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 __LUCI_IR_CIRCLEPADV2_H__ +#define __LUCI_IR_CIRCLEPADV2_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief PADV2 in Circle + */ +class CirclePadV2 final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::PADV2>> +{ +public: + CirclePadV2() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *paddings(void) const { return at(1)->node(); } + void paddings(loco::Node *node) { at(1)->node(node); } + + loco::Node *constant_values(void) const { return at(2)->node(); } + void constant_values(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEPADV2_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUnique.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnique.h new file mode 100644 index 000000000..719a72362 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnique.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCELUNIQUE_H__ +#define __LUCI_IR_CIRCELUNIQUE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Unique in Circle + */ +class CircleUnique final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::UNIQUE>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + loco::DataType idx_out_type(void) const { return _idx_out_type; } + void output_type(loco::DataType ot) { _idx_out_type = ot; } + +private: + loco::DataType _idx_out_type{loco::DataType::S32}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCELUNIQUE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUniqueOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUniqueOut.h new file mode 100644 index 000000000..f846403e0 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUniqueOut.h @@ -0,0 +1,51 @@ +/* + * 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 __LUCI_IR_CIRCLE_UNIQUEOUT_H__ +#define __LUCI_IR_CIRCLE_UNIQUEOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLEUNIQUEOUT in Circle + */ +class CircleUniqueOut final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEUNIQUEOUT>> +{ +public: + CircleUniqueOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_UNIQUEOUT_H__ diff --git a/compiler/luci/lang/src/Module.test.cpp b/compiler/luci/lang/src/Module.test.cpp index 26bf073be..a5973e52d 100644 --- a/compiler/luci/lang/src/Module.test.cpp +++ b/compiler/luci/lang/src/Module.test.cpp @@ -22,7 +22,7 @@ TEST(ModuleTest, consturctor) { auto gs = luci::make_module(); - GTEST_SUCCEED(); + SUCCEED(); } TEST(ModuleTest, add) diff --git a/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp index 74ea82c6c..c07268cbf 100644 --- a/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp @@ -35,7 +35,12 @@ TEST(CircleCustomTest, constructor) ASSERT_EQ(0, custom_node.custom_code().size()); } -TEST(CircleCustomTest, constructor_NEG) { ASSERT_DEBUG_DEATH(luci::CircleCustom{0}, ""); } +TEST(CircleCustomTest, constructor_NEG) +{ + ASSERT_DEBUG_DEATH(luci::CircleCustom{0}, ""); + + SUCCEED(); +} TEST(CircleCustomTest, invalidIndex_NEG) { diff --git a/compiler/luci/lang/src/Nodes/CircleIf.test.cpp b/compiler/luci/lang/src/Nodes/CircleIf.test.cpp index e3c8c9f60..35f28e9ac 100644 --- a/compiler/luci/lang/src/Nodes/CircleIf.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleIf.test.cpp @@ -41,11 +41,15 @@ TEST(CircleIfTest, constructor) TEST(CircleIfTestDeath, invalid_arity_NEG) { ASSERT_DEBUG_DEATH(luci::CircleIf very_long_name_if_node(0, 1), ""); + + SUCCEED(); } TEST(CircleIfTestDeath, invalid_output_count_NEG) { ASSERT_DEBUG_DEATH(luci::CircleIf if_node(2, 0), ""); + + SUCCEED(); } TEST(CircleIfTestDeath, invalid_input_get_index_NEG) diff --git a/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4.test.cpp b/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4.test.cpp new file mode 100644 index 000000000..b25ce4d6d --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4.test.cpp @@ -0,0 +1,96 @@ +/* + * 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 "luci/IR/Nodes/CircleNonMaxSuppressionV4.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleNonMaxSuppressionV4Test, constructor) +{ + luci::CircleNonMaxSuppressionV4 nmsv4_node; + + ASSERT_EQ(luci::CircleDialect::get(), nmsv4_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::NON_MAX_SUPPRESSION_V4, nmsv4_node.opcode()); + + ASSERT_EQ(nullptr, nmsv4_node.boxes()); + ASSERT_EQ(nullptr, nmsv4_node.scores()); + ASSERT_EQ(nullptr, nmsv4_node.max_output_size()); + ASSERT_EQ(nullptr, nmsv4_node.iou_threshold()); + ASSERT_EQ(nullptr, nmsv4_node.score_threshold()); +} + +TEST(CircleNonMaxSuppressionV4Test, input_NEG) +{ + luci::CircleNonMaxSuppressionV4 nmsv4_node; + luci::CircleNonMaxSuppressionV4 node; + + nmsv4_node.boxes(&node); + nmsv4_node.scores(&node); + nmsv4_node.max_output_size(&node); + nmsv4_node.iou_threshold(&node); + nmsv4_node.score_threshold(&node); + ASSERT_NE(nullptr, nmsv4_node.boxes()); + ASSERT_NE(nullptr, nmsv4_node.scores()); + ASSERT_NE(nullptr, nmsv4_node.max_output_size()); + ASSERT_NE(nullptr, nmsv4_node.iou_threshold()); + ASSERT_NE(nullptr, nmsv4_node.score_threshold()); + + nmsv4_node.boxes(nullptr); + nmsv4_node.scores(nullptr); + nmsv4_node.max_output_size(nullptr); + nmsv4_node.iou_threshold(nullptr); + nmsv4_node.score_threshold(nullptr); + ASSERT_EQ(nullptr, nmsv4_node.boxes()); + ASSERT_EQ(nullptr, nmsv4_node.scores()); + ASSERT_EQ(nullptr, nmsv4_node.max_output_size()); + ASSERT_EQ(nullptr, nmsv4_node.iou_threshold()); + ASSERT_EQ(nullptr, nmsv4_node.score_threshold()); +} + +TEST(CircleNonMaxSuppressionV4Test, arity_NEG) +{ + luci::CircleNonMaxSuppressionV4 nmsv4_node; + + ASSERT_NO_THROW(nmsv4_node.arg(4)); + ASSERT_THROW(nmsv4_node.arg(5), std::out_of_range); +} + +TEST(CircleNonMaxSuppressionV4Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleNonMaxSuppressionV4 nmsv4_node; + + TestVisitor tv; + ASSERT_THROW(nmsv4_node.accept(&tv), std::exception); +} + +TEST(CircleNonMaxSuppressionV4Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleNonMaxSuppressionV4 nmsv4_node; + + TestVisitor tv; + ASSERT_THROW(nmsv4_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4Out.test.cpp b/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4Out.test.cpp new file mode 100644 index 000000000..c6cef4e91 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleNonMaxSuppressionV4Out.test.cpp @@ -0,0 +1,32 @@ +/* + * 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 "luci/IR/Nodes/CircleNonMaxSuppressionV4Out.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleNonMaxSuppressionV4OutTest, constructor) +{ + luci::CircleNonMaxSuppressionV4Out vout_node; + + ASSERT_EQ(luci::CircleDialect::get(), vout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLENONMAXSUPPRESSIONV4OUT, vout_node.opcode()); + + ASSERT_EQ(nullptr, vout_node.input()); + ASSERT_EQ(-1, vout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CirclePadV2.test.cpp b/compiler/luci/lang/src/Nodes/CirclePadV2.test.cpp new file mode 100644 index 000000000..e09d517b2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CirclePadV2.test.cpp @@ -0,0 +1,86 @@ +/* + * 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 "luci/IR/Nodes/CirclePadV2.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CirclePadV2Test, constructor_P) +{ + luci::CirclePadV2 node; + + ASSERT_EQ(luci::CircleDialect::get(), node.dialect()); + ASSERT_EQ(luci::CircleOpcode::PADV2, node.opcode()); + + ASSERT_EQ(nullptr, node.input()); + ASSERT_EQ(nullptr, node.paddings()); + ASSERT_EQ(nullptr, node.constant_values()); +} + +TEST(CirclePadV2Test, input_NEG) +{ + luci::CirclePadV2 pad_node; + luci::CirclePadV2 node; + + pad_node.input(&node); + pad_node.paddings(&node); + pad_node.constant_values(&node); + ASSERT_NE(nullptr, pad_node.input()); + ASSERT_NE(nullptr, pad_node.paddings()); + ASSERT_NE(nullptr, pad_node.constant_values()); + + pad_node.input(nullptr); + pad_node.paddings(nullptr); + pad_node.constant_values(nullptr); + ASSERT_EQ(nullptr, pad_node.input()); + ASSERT_EQ(nullptr, pad_node.paddings()); + ASSERT_EQ(nullptr, pad_node.constant_values()); +} + +TEST(CirclePadV2Test, arity_NEG) +{ + luci::CirclePadV2 pad_node; + + ASSERT_NO_THROW(pad_node.arg(2)); + ASSERT_THROW(pad_node.arg(3), std::out_of_range); +} + +TEST(CirclePadV2Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CirclePadV2 pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); +} + +TEST(CirclePadV2Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CirclePadV2 pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleUnique.test.cpp b/compiler/luci/lang/src/Nodes/CircleUnique.test.cpp new file mode 100644 index 000000000..517ee97d5 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleUnique.test.cpp @@ -0,0 +1,76 @@ +/* + * 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 "luci/IR/Nodes/CircleUnique.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleUniqueTest, constructor) +{ + luci::CircleUnique unique_node; + + ASSERT_EQ(luci::CircleDialect::get(), unique_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::UNIQUE, unique_node.opcode()); + + ASSERT_EQ(nullptr, unique_node.input()); +} + +TEST(CircleUniqueTest, input_NEG) +{ + luci::CircleUnique unique_node; + luci::CircleUnique node; + + unique_node.input(&node); + ASSERT_NE(nullptr, unique_node.input()); + + unique_node.input(nullptr); + ASSERT_EQ(nullptr, unique_node.input()); +} + +TEST(CircleUniqueTest, arity_NEG) +{ + luci::CircleUnique unique_node; + + ASSERT_NO_THROW(unique_node.arg(0)); + ASSERT_THROW(unique_node.arg(1), std::out_of_range); +} + +TEST(CircleUniqueTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleUnique unique_node; + + TestVisitor tv; + ASSERT_THROW(unique_node.accept(&tv), std::exception); +} + +TEST(CircleUniqueTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleUnique unique_node; + + TestVisitor tv; + ASSERT_THROW(unique_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp index 19290c0a2..913686fbd 100644 --- a/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp @@ -41,11 +41,15 @@ TEST(CircleWhileTest, constructor) TEST(CircleWhileTestDeath, invalid_arity_NEG) { ASSERT_DEBUG_DEATH(luci::CircleWhile very_long_name_while_node(0, 1), ""); + + SUCCEED(); } TEST(CircleWhileTestDeath, invalid_output_count_NEG) { ASSERT_DEBUG_DEATH(luci::CircleWhile while_node(2, 0), ""); + + SUCCEED(); } TEST(CircleWhileTestDeath, invalid_input_get_index_NEG) diff --git a/compiler/luci/logex/src/FormattedGraph.cpp b/compiler/luci/logex/src/FormattedGraph.cpp index 4725ee3df..f04a418ef 100644 --- a/compiler/luci/logex/src/FormattedGraph.cpp +++ b/compiler/luci/logex/src/FormattedGraph.cpp @@ -244,6 +244,7 @@ private: IMPLEMENT(luci::CircleMirrorPad) IMPLEMENT(luci::CircleMul) IMPLEMENT(luci::CircleNeg) + IMPLEMENT(luci::CircleNonMaxSuppressionV4) IMPLEMENT(luci::CircleNotEqual) IMPLEMENT(luci::CircleOneHot) IMPLEMENT(luci::CirclePack) @@ -291,6 +292,7 @@ private: IMPLEMENT(luci::CircleTopKV2) IMPLEMENT(luci::CircleTranspose) IMPLEMENT(luci::CircleTransposeConv) + IMPLEMENT(luci::CircleUnique) IMPLEMENT(luci::CircleUnpack) IMPLEMENT(luci::CircleWhere) IMPLEMENT(luci::CircleWhile) @@ -303,9 +305,11 @@ private: IMPLEMENT(luci::CircleInput) IMPLEMENT(luci::CircleOutput) IMPLEMENT(luci::CircleIfOut) + IMPLEMENT(luci::CircleNonMaxSuppressionV4Out) IMPLEMENT(luci::CircleSplitOut) IMPLEMENT(luci::CircleSplitVOut) IMPLEMENT(luci::CircleTopKV2Out) + IMPLEMENT(luci::CircleUniqueOut) IMPLEMENT(luci::CircleUnpackOut) IMPLEMENT(luci::CircleWhileOut) #undef IMPLEMENT @@ -823,6 +827,19 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleNeg *node, locop::NodeS return use_x(tbl(), node, s); } +bool CircleNodeSummaryBuilder::summary(const luci::CircleNonMaxSuppressionV4 *node, + locop::NodeSummary &s) const +{ + s.args().append("boxes", pepper::str(node->boxes())); + s.args().append("scores", pepper::str(node->scores())); + s.args().append("max_output_size", pepper::str(node->max_output_size())); + s.args().append("iou_threshold", pepper::str(node->iou_threshold())); + s.args().append("score_threshold", pepper::str(node->score_threshold())); + + s.state(locop::NodeSummary::State::Complete); + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleNotEqual *node, locop::NodeSummary &s) const { @@ -1227,6 +1244,14 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleTransposeConv *node, return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleUnique *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("idx_out_type", to_str(node->idx_out_type())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpack *node, locop::NodeSummary &s) const { s.args().append("value", tbl()->lookup(node->value())); @@ -1293,6 +1318,16 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleTopKV2Out *node, return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleUniqueOut *node, + locop::NodeSummary &s) const +{ + s.args().append("unique", tbl()->lookup(node->input())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpackOut *node, locop::NodeSummary &s) const { @@ -1308,6 +1343,12 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleIfOut *node, locop::Nod return use_input(tbl(), node, s); } +bool CircleNodeSummaryBuilder::summary(const luci::CircleNonMaxSuppressionV4Out *node, + locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleWhileOut *node, locop::NodeSummary &s) const { diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp index 90fbe9009..2edf7a9c6 100644 --- a/compiler/luci/pass/src/CircleOptimizer.cpp +++ b/compiler/luci/pass/src/CircleOptimizer.cpp @@ -145,7 +145,7 @@ void CircleOptimizer::quantize(loco::Graph *g) const { static const std::vector<std::string> fakeq_supported_input_dtype{"float32"}; static const std::vector<std::string> fakeq_supported_output_dtype{"uint8"}; - static const std::vector<std::string> fakeq_supported_granularity{"layer"}; + static const std::vector<std::string> fakeq_supported_granularity{"layer", "channel"}; auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype); auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype); @@ -173,7 +173,7 @@ void CircleOptimizer::quantize(loco::Graph *g) const { static const std::vector<std::string> qwmm_supported_input_dtype{"float32"}; static const std::vector<std::string> qwmm_supported_output_dtype{"uint8"}; - static const std::vector<std::string> qwmm_supported_granularity{"layer"}; + static const std::vector<std::string> qwmm_supported_granularity{"layer", "channel"}; auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype); auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype); diff --git a/compiler/luci/pass/src/FuseBCQPass.cpp b/compiler/luci/pass/src/FuseBCQPass.cpp index b81db8827..260de5b30 100644 --- a/compiler/luci/pass/src/FuseBCQPass.cpp +++ b/compiler/luci/pass/src/FuseBCQPass.cpp @@ -53,6 +53,11 @@ const std::string node_name_prefix(luci::NodeName node_name) const auto index = prefix.find("Tensordot/"); prefix = prefix.substr(0, index - 1); } + else if (prefix.find("/MatMul") != std::string::npos) + { + const auto index = prefix.find("/MatMul"); + prefix = prefix.substr(0, index); + } else if (prefix.find("kernel/") != std::string::npos) { const auto index = prefix.find("kernel/"); @@ -67,14 +72,190 @@ const std::string node_name_prefix(luci::NodeName node_name) return prefix; } +/** + * @brief Create CircleOutputExclude operation, which has same shape and dtype with + * original circle_node. + */ +luci::CircleOutputExclude *createNoOp(luci::CircleNode *circle_node) +{ + auto graph = circle_node->graph(); + auto noOp = graph->nodes()->create<luci::CircleOutputExclude>(); + + if (circle_node->shape_status() == luci::ShapeStatus::VALID) + { + noOp->dtype(circle_node->dtype()); + noOp->rank(circle_node->rank()); + for (uint32_t i = 0; i < circle_node->rank(); ++i) + noOp->dim(i) = circle_node->dim(i); + } + else + { + // For type inference + noOp->dtype(loco::DataType::FLOAT32); + } + + return noOp; +}; + } // namespace namespace { -class BCQConverter final +// V means the version of BCQ. +template <int32_t V> class BCQFuser; + +template <> class BCQFuser<1> { public: + bool fuseBCQ(loco::Graph *g) + { + bool changed = false; + + for (auto node : loco::all_nodes(g)) + { + if (auto circle_const = dynamic_cast<luci::CircleConst *>(node)) + { + add_BCQ_info_node(circle_const); + } + } + + if (!is_bcqinfo_valid()) + return false; + + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + if (auto gather = dynamic_cast<luci::CircleGather *>(node)) + { + auto params = dynamic_cast<luci::CircleConst *>(gather->params()); + if (params != nullptr && has_BCQ_info(params)) + { + auto bcq_gather = g->nodes()->create<luci::CircleBCQGather>(); + + bcq_gather->op_version(1); + bcq_gather->input_scales(get_alpha(params)); + bcq_gather->input_binary(get_packed_binary_code(params)); + bcq_gather->indices(gather->indices()); + bcq_gather->input_clusters(packed_clusters(params)); + + // input_binary shape : [output_size, hidden_size] + const auto binary_hidden_size = + loco::must_cast<luci::CircleConst *>(bcq_gather->input_binary())->dim(1).value() * 32; + bcq_gather->input_hidden_size(binary_hidden_size); + + if (do_w_x(params)) + { + bcq_gather->axis(gather->axis()); + } + else + { + const auto axis_transpose = (gather->axis() == 0) ? 1 : 0; + bcq_gather->axis(axis_transpose); + } + + loco::replace(gather).with(bcq_gather); + + changed = true; + } + } + else if (auto fully_connected = dynamic_cast<luci::CircleFullyConnected *>(node)) + { + auto weights = dynamic_cast<luci::CircleConst *>(fully_connected->weights()); + if (weights != nullptr && has_BCQ_info(weights)) + { + auto bcq_fc = g->nodes()->create<luci::CircleBCQFullyConnected>(); + + bcq_fc->op_version(1); + bcq_fc->weights_scales(get_alpha(weights)); + bcq_fc->weights_binary(get_packed_binary_code(weights)); + bcq_fc->bias(fully_connected->bias()); + bcq_fc->weights_clusters(packed_clusters(weights)); + bcq_fc->fusedActivationFunction(fully_connected->fusedActivationFunction()); + + loco::Node *bcq_input = fully_connected->input(); + int32_t batch_rank = 0; + + // If input of BCQFullyConnected has more than rank 2, we should reshape it as rank 2 + const auto original_input = loco::must_cast<luci::CircleNode *>(fully_connected->input()); + if (original_input->shape_status() == luci::ShapeStatus::VALID && + original_input->rank() > 2) + { + auto new_shape = g->nodes()->create<luci::CircleConst>(); + new_shape->dtype(loco::DataType::S32); + new_shape->size<loco::DataType::S32>(2); + new_shape->rank(1); + new_shape->dim(0) = 2; + + auto batch_size = 1; + for (uint32_t i = 0; i < original_input->rank() - 1; ++i) + batch_size *= original_input->dim(i).value(); + + new_shape->at<loco::DataType::S32>(0) = batch_size; + new_shape->at<loco::DataType::S32>(1) = + original_input->dim(original_input->rank() - 1).value(); + new_shape->shape_status(luci::ShapeStatus::VALID); + + auto reshape = g->nodes()->create<luci::CircleReshape>(); + reshape->tensor(original_input); + reshape->shape(new_shape); + + bcq_input = reshape; + batch_rank = original_input->rank() - 2; + } + + // If x_w formation, we should insert Transpose in front and back of BCQFullyConnected + if (do_w_x(weights)) + { + const auto binary_hidden_size = + loco::must_cast<luci::CircleNode *>(fully_connected->input()) + ->dim(batch_rank) + .value(); + bcq_fc->weights_hidden_size(binary_hidden_size); + bcq_fc->input(bcq_input); + loco::replace(fully_connected).with(bcq_fc); + } + else + { + const auto binary_hidden_size = + loco::must_cast<luci::CircleNode *>(fully_connected->input()) + ->dim(1 + batch_rank) + .value(); + bcq_fc->weights_hidden_size(binary_hidden_size); + + auto perm = g->nodes()->create<luci::CircleConst>(); + perm->dtype(loco::DataType::S32); + perm->size<loco::DataType::S32>(2); + perm->rank(1); + perm->dim(0) = 2; + perm->at<loco::DataType::S32>(0) = 1; + perm->at<loco::DataType::S32>(1) = 0; + perm->shape_status(luci::ShapeStatus::VALID); + + auto input_transpose = g->nodes()->create<luci::CircleTranspose>(); + input_transpose->a(bcq_input); + input_transpose->perm(perm); + + bcq_fc->input(input_transpose); + + auto output_transpose = g->nodes()->create<luci::CircleTranspose>(); + output_transpose->a(bcq_fc); + output_transpose->perm(perm); + + loco::replace(fully_connected).with(output_transpose); + } + + changed = true; + } + } + } + + if (changed) + clear_BCQ_nodes(); + + return changed; + } + +private: void add_BCQ_info_node(luci::CircleConst *node) { const auto node_name = node->name(); @@ -119,16 +300,65 @@ public: return has_info; } + /** + * @brief Exclude BCQ information nodes which are used for fusing BCQ operations + * from graph output by using CircleOutputExclude + */ + void clear_BCQ_nodes() + { + auto clear_nodes = [](std::map<std::string, luci::CircleConst *> &nodes) { + for (auto &n : nodes) + { + auto node = n.second; + + for (auto s : loco::succs(node)) + { + if (auto outnode = dynamic_cast<luci::CircleOutput *>(s)) + { + outnode->from(createNoOp(node)); + } + else if (auto reshape_node = dynamic_cast<luci::CircleReshape *>(s)) + { + for (auto o : loco::succs(reshape_node)) + { + auto circle_output = loco::must_cast<luci::CircleOutput *>(o); + circle_output->from(createNoOp(reshape_node)); + } + } + } + } + }; + + clear_nodes(_do_w_x); + clear_nodes(_alpha); + clear_nodes(_packed_binary_code); + clear_nodes(_number_of_clusters); + clear_nodes(_size_of_clusters); + clear_nodes(_qbits_of_clusters); + clear_nodes(_dequant_weight); + } + + bool is_bcqinfo_valid() + { + // do_w_x should be int32 or bool type + for (auto n : _do_w_x) + { + if (n.second->dtype() != loco::DataType::BOOL && n.second->dtype() != loco::DataType::S32) + return false; + } + + return true; + } + +private: bool do_w_x(luci::CircleConst *node) { const auto prefix = node_name_prefix(node->name()); if (_do_w_x[prefix]->dtype() == loco::DataType::S32) return _do_w_x[prefix]->at<loco::DataType::S32>(0) == 1; - else if (_do_w_x[prefix]->dtype() == loco::DataType::BOOL) - return _do_w_x[prefix]->at<loco::DataType::BOOL>(0); else - throw std::runtime_error("do_w_x should be int or bool"); + return _do_w_x[prefix]->at<loco::DataType::BOOL>(0); } luci::CircleConst *get_alpha(luci::CircleConst *node) @@ -187,64 +417,6 @@ public: return packed_clusters; } - /** - * @brief Exclude BCQ information nodes which are used for fusing BCQ operations - * from graph output by using CircleOutputExclude - */ - void clear_BCQ_nodes() - { - auto createNoOp = [](luci::CircleNode *circle_node) { - auto graph = circle_node->graph(); - auto noOp = graph->nodes()->create<luci::CircleOutputExclude>(); - - if (circle_node->shape_status() == luci::ShapeStatus::VALID) - { - noOp->dtype(circle_node->dtype()); - noOp->rank(circle_node->rank()); - for (uint32_t i = 0; i < circle_node->rank(); ++i) - noOp->dim(i) = circle_node->dim(i); - } - else - { - // For type inference - noOp->dtype(loco::DataType::FLOAT32); - } - - return noOp; - }; - - auto clear_nodes = [createNoOp](std::map<std::string, luci::CircleConst *> &nodes) { - for (auto &n : nodes) - { - auto node = n.second; - - for (auto s : loco::succs(node)) - { - if (auto outnode = dynamic_cast<luci::CircleOutput *>(s)) - { - outnode->from(createNoOp(node)); - } - else if (auto reshape_node = dynamic_cast<luci::CircleReshape *>(s)) - { - for (auto o : loco::succs(reshape_node)) - { - auto circle_output = loco::must_cast<luci::CircleOutput *>(o); - circle_output->from(createNoOp(reshape_node)); - } - } - } - } - }; - - clear_nodes(_do_w_x); - clear_nodes(_alpha); - clear_nodes(_packed_binary_code); - clear_nodes(_number_of_clusters); - clear_nodes(_size_of_clusters); - clear_nodes(_qbits_of_clusters); - clear_nodes(_dequant_weight); - } - private: std::map<std::string, luci::CircleConst *> _do_w_x; std::map<std::string, luci::CircleConst *> _alpha; @@ -262,143 +434,42 @@ namespace luci bool FuseBCQPass::run(loco::Graph *g) { - BCQConverter converter; - bool changed = false; + // Find BCQ version information and check validity. + luci::CircleConst *version_node = nullptr; for (auto node : loco::all_nodes(g)) { if (auto circle_const = dynamic_cast<luci::CircleConst *>(node)) { - converter.add_BCQ_info_node(circle_const); - } - } - - for (auto node : loco::active_nodes(loco::output_nodes(g))) - { - if (auto gather = dynamic_cast<luci::CircleGather *>(node)) - { - auto params = dynamic_cast<luci::CircleConst *>(gather->params()); - if (params != nullptr && converter.has_BCQ_info(params)) + if (circle_const->name().find("/bcqinfo_version") != std::string::npos) { - auto bcq_gather = g->nodes()->create<luci::CircleBCQGather>(); - - bcq_gather->input_scales(converter.get_alpha(params)); - bcq_gather->input_binary(converter.get_packed_binary_code(params)); - bcq_gather->indices(gather->indices()); - bcq_gather->input_clusters(converter.packed_clusters(params)); - - const auto binary_hidden_size = - loco::must_cast<luci::CircleConst *>(bcq_gather->input_binary())->dim(1).value() * 32; - bcq_gather->input_hidden_size(binary_hidden_size); - - if (converter.do_w_x(params)) - { - bcq_gather->axis(gather->axis()); - } - else + // There should be only one bcqinfo_version in the model + if (version_node != nullptr) { - const auto axis_transpose = (gather->axis() == 0) ? 1 : 0; - bcq_gather->axis(axis_transpose); + assert(false && "Multiple version information found"); + return false; } - loco::replace(gather).with(bcq_gather); - - changed = true; + version_node = circle_const; } } - else if (auto fully_connected = dynamic_cast<luci::CircleFullyConnected *>(node)) - { - auto weights = dynamic_cast<luci::CircleConst *>(fully_connected->weights()); - if (weights != nullptr && converter.has_BCQ_info(weights)) - { - auto bcq_fc = g->nodes()->create<luci::CircleBCQFullyConnected>(); - - bcq_fc->weights_scales(converter.get_alpha(weights)); - bcq_fc->weights_binary(converter.get_packed_binary_code(weights)); - bcq_fc->bias(fully_connected->bias()); - bcq_fc->weights_clusters(converter.packed_clusters(weights)); - bcq_fc->fusedActivationFunction(fully_connected->fusedActivationFunction()); - - loco::Node *bcq_input = fully_connected->input(); - int32_t batch_rank = 0; + } - // If input of BCQFullyConnected has more than rank 2, we should reshape it as rank 2 - const auto original_input = loco::must_cast<luci::CircleNode *>(fully_connected->input()); - if (original_input->shape_status() == ShapeStatus::VALID && original_input->rank() > 2) - { - auto new_shape = g->nodes()->create<luci::CircleConst>(); - new_shape->dtype(loco::DataType::S32); - new_shape->size<loco::DataType::S32>(2); - new_shape->rank(1); - new_shape->dim(0) = 2; - - auto batch_size = 1; - for (uint32_t i = 0; i < original_input->rank() - 1; ++i) - batch_size *= original_input->dim(i).value(); - - new_shape->at<loco::DataType::S32>(0) = batch_size; - new_shape->at<loco::DataType::S32>(1) = - original_input->dim(original_input->rank() - 1).value(); - new_shape->shape_status(ShapeStatus::VALID); - - auto reshape = g->nodes()->create<luci::CircleReshape>(); - reshape->tensor(original_input); - reshape->shape(new_shape); - - bcq_input = reshape; - batch_rank = original_input->rank() - 2; - } + // If version node is not found, regard it as version 1. + int32_t bcq_version = (version_node != nullptr) ? version_node->at<loco::DataType::S32>(0) : 1; - // If x_w formation, we should insert Transpose in front and back of BCQFullyConnected - if (converter.do_w_x(weights)) - { - const auto binary_hidden_size = - loco::must_cast<luci::CircleNode *>(fully_connected->input()) - ->dim(batch_rank) - .value(); - bcq_fc->weights_hidden_size(binary_hidden_size); - bcq_fc->input(bcq_input); - loco::replace(fully_connected).with(bcq_fc); - } - else - { - const auto binary_hidden_size = - loco::must_cast<luci::CircleNode *>(fully_connected->input()) - ->dim(1 + batch_rank) - .value(); - bcq_fc->weights_hidden_size(binary_hidden_size); - - auto perm = g->nodes()->create<luci::CircleConst>(); - perm->dtype(loco::DataType::S32); - perm->size<loco::DataType::S32>(2); - perm->rank(1); - perm->dim(0) = 2; - perm->at<loco::DataType::S32>(0) = 1; - perm->at<loco::DataType::S32>(1) = 0; - perm->shape_status(ShapeStatus::VALID); - - auto input_transpose = g->nodes()->create<luci::CircleTranspose>(); - input_transpose->a(bcq_input); - input_transpose->perm(perm); - - bcq_fc->input(input_transpose); - - auto output_transpose = g->nodes()->create<luci::CircleTranspose>(); - output_transpose->a(bcq_fc); - output_transpose->perm(perm); - - loco::replace(fully_connected).with(output_transpose); - } + if (bcq_version == 1) + changed = BCQFuser<1>().fuseBCQ(g); + else + assert(false && "Not supported BCQ version"); - changed = true; - } - } + if (changed && version_node != nullptr) + { + // If BCQ is applied and version node was found, remove the node. + loco::replace(version_node).with(createNoOp(version_node)); } - if (changed) - converter.clear_BCQ_nodes(); - return changed; } diff --git a/compiler/luci/pass/src/QuantizationUtils.cpp b/compiler/luci/pass/src/QuantizationUtils.cpp index 6726ce746..e18690605 100644 --- a/compiler/luci/pass/src/QuantizationUtils.cpp +++ b/compiler/luci/pass/src/QuantizationUtils.cpp @@ -24,6 +24,13 @@ namespace luci { +uint8_t fp32_to_uint8_cast(float f) +{ + assert(std::numeric_limits<uint8_t>::min() <= f); + assert(f <= std::numeric_limits<uint8_t>::max()); + return static_cast<uint8_t>(f); +} + void compute_sym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp, float &nudged_min, float &nudged_max) { @@ -78,7 +85,7 @@ void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t } else zero_point_double = qmin_double - rmin / scale; - if (zero_point_double <= qmin_double) + if (min >= 0) { assert(min >= 0 && max >= 0); nudged_zero_point = kMinScale; @@ -86,7 +93,7 @@ void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t if (min > 0 && max > 0) WARN(l) << "The minimum and maximum values are all positive." << std::endl; } - else if (zero_point_double >= qmax_double) + else if (max < 0) { assert(min < 0 && max < 0); nudged_zero_point = kMaxScale; @@ -96,7 +103,14 @@ void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t else { assert(min < 0 && max >= 0); - nudged_zero_point = static_cast<uint8_t>(std::round(zero_point_double)); + nudged_zero_point = fp32_to_uint8_cast(std::round(zero_point_double)); + } + + // protect scale from being very low due to overflow + if (scale < 1e-5) + { + scale = 1e-5; + nudged_zero_point = fp32_to_uint8_cast(std::round(qmin_double - rmin / scale)); } nudged_min = static_cast<float>((qmin_double - nudged_zero_point) * scale); diff --git a/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp index f8abee751..b335a53b4 100644 --- a/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp +++ b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp @@ -138,7 +138,8 @@ bool is_quantized(const CircleNode *node) node->dtype() == loco::DataType::S32; // bias } -void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_factor) +void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_factor, + int32_t &channel_dim_index) { assert(node->dtype() == loco::DataType::FLOAT32); @@ -153,7 +154,6 @@ void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_facto uint32_t indices[4] = { 0, }; - int channel_dim_index{0}; if (!get_channel_dim_index(node, dimension, channel_dim_index)) { @@ -189,7 +189,7 @@ void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_facto } void asym_wquant_per_channel(CircleConst *node, std::vector<float> &min, - std::vector<float> &scaling_factor) + std::vector<float> &scaling_factor, int32_t &channel_dim_index) { assert(node->dtype() == loco::DataType::FLOAT32); @@ -204,7 +204,6 @@ void asym_wquant_per_channel(CircleConst *node, std::vector<float> &min, uint32_t indices[4] = { 0, }; - int channel_dim_index{0}; if (!get_channel_dim_index(node, dimension, channel_dim_index)) { @@ -282,6 +281,10 @@ bool is_weights(CircleNode *node) if (dw_conv != nullptr && dw_conv->filter() == circle_const) return true; + auto t_conv = dynamic_cast<CircleTransposeConv *>(out); + if (t_conv != nullptr && t_conv->filter() == circle_const && circle_const->rank() == 4) + return true; + auto fc = dynamic_cast<CircleFullyConnected *>(out); if (fc != nullptr && fc->weights() == circle_const) return true; @@ -350,8 +353,8 @@ struct QuantizeActivation final : public luci::CircleNodeMutableVisitor<bool> circle_node->dtype(loco::DataType::S16); } - circle_node->quantparam()->max[0] = nudged_max; - circle_node->quantparam()->min[0] = nudged_min; + circle_node->quantparam()->min.clear(); + circle_node->quantparam()->max.clear(); circle_node->quantparam()->scale.push_back(scaling_factor); circle_node->quantparam()->zerop.push_back(zp); } @@ -472,15 +475,19 @@ struct QuantizeWeights final : public luci::CircleNodeMutableVisitor<bool> assert(quantparam != nullptr); auto min = quantparam->min; auto scaling_factor = quantparam->scale; + int32_t channel_dim_index = 0; if (output_type == loco::DataType::U8) { - asym_wquant_per_channel(circle_const, min, scaling_factor); + asym_wquant_per_channel(circle_const, min, scaling_factor, channel_dim_index); } else { - sym_wquant_per_channel(circle_const, scaling_factor); + sym_wquant_per_channel(circle_const, scaling_factor, channel_dim_index); } + quantparam->min.clear(); + quantparam->max.clear(); + quantparam->quantized_dimension = channel_dim_index; } // Find min/max per layer-wise else @@ -493,6 +500,8 @@ struct QuantizeWeights final : public luci::CircleNodeMutableVisitor<bool> auto min = quantparam->min[0]; auto scaling_factor = quantparam->scale[0]; asym_wquant_per_layer(circle_const, min, scaling_factor); + quantparam->min.clear(); + quantparam->max.clear(); } } } diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp index a291cfe70..6355ec546 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp @@ -1010,6 +1010,12 @@ public: loco::NodeShape visit(const luci::CircleNeg *node) final { return use_x(node); } + loco::NodeShape visit(const luci::CircleNonMaxSuppressionV4 *node) final + { + const auto boxes_shape = loco::shape_get(node->boxes()).as<loco::TensorShape>(); + return loco::NodeShape{boxes_shape}; + } + loco::NodeShape visit(const luci::CircleNotEqual *node) final { return broadcast_xy(node); } loco::NodeShape visit(const luci::CircleOneHot *node) final @@ -1818,6 +1824,18 @@ public: return output_shape; } + loco::NodeShape visit(const luci::CircleUnique *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + assert(input_shape.rank() == 1); + + loco::TensorShape shape_output; + shape_output = own_shape(node); + + return loco::NodeShape{shape_output}; + } + loco::NodeShape visit(const luci::CircleTransposeConv *node) final { // TransposeConv's output shape is written in its 'inputSizes' argument @@ -2019,6 +2037,34 @@ public: return loco::NodeShape{*then_graph_output->shape()}; } + loco::NodeShape visit(const luci::CircleNonMaxSuppressionV4Out *node) final + { + const loco::DataType S32 = loco::DataType::S32; + + auto nmsv4 = dynamic_cast<const luci::CircleNonMaxSuppressionV4 *>(node->input()); + if (nmsv4 == nullptr) + INTERNAL_EXN("CircleNonMaxSuppressionV4 IR is not configured correctly"); + + auto index = node->index(); + if (index == 1) + return loco::TensorShape({0}); + + assert(index == 0); + + auto unknown = loco::TensorShape{loco::Dimension()}; + auto max_output_size = dynamic_cast<const luci::CircleConst *>(nmsv4->max_output_size()); + if (max_output_size == nullptr) + return unknown; // we need CircleConst for max output size + + LUCI_ASSERT(max_output_size->dtype() == S32, "Only support int32 for max_output_size"); + + if (max_output_size->size<S32>() < 1) + return unknown; + + auto max_output_size_value = uint32_t(max_output_size->at<S32>(0)); + return loco::TensorShape{max_output_size_value}; + } + loco::NodeShape visit(const luci::CircleSplitOut *node) final { const loco::DataType S32 = loco::DataType::S32; @@ -2142,6 +2188,19 @@ public: return loco::NodeShape{output_shape}; } + loco::NodeShape visit(const luci::CircleUniqueOut *node) final + { + auto unique = dynamic_cast<const luci::CircleUnique *>(node->input()); + if (unique == nullptr) + { + INTERNAL_EXN("CircleUnique IR is not configured correctly"); + } + + auto unique_shape = loco::shape_get(unique).as<loco::TensorShape>(); + + return loco::NodeShape{unique_shape}; + } + loco::NodeShape visit(const luci::CircleUnpackOut *node) final { auto unpack = dynamic_cast<const luci::CircleUnpack *>(node->input()); diff --git a/compiler/luci/service/src/CircleTypeInferenceRule.cpp b/compiler/luci/service/src/CircleTypeInferenceRule.cpp index de2ba3ea4..e7910bfc0 100644 --- a/compiler/luci/service/src/CircleTypeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleTypeInferenceRule.cpp @@ -252,6 +252,11 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CircleNeg *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleNonMaxSuppressionV4 *node) final + { + return loco::dtype_get(node->boxes()); + } + loco::DataType visit(const luci::CircleNotEqual *) final { return loco::DataType::BOOL; } loco::DataType visit(const luci::CirclePack *node) final @@ -345,7 +350,10 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->tensor()); } - loco::DataType visit(const luci::CircleResizeBilinear *) final { return loco::DataType::FLOAT32; } + loco::DataType visit(const luci::CircleResizeBilinear *node) final + { + return loco::dtype_get(node->input()); + } loco::DataType visit(const luci::CircleResizeNearestNeighbor *node) final { @@ -472,6 +480,11 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->outBackprop()); } + loco::DataType visit(const luci::CircleUnique *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleUnpack *node) final { return loco::dtype_get(node->value()); @@ -569,6 +582,13 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return then_graph_output->dtype(); } + loco::DataType visit(const luci::CircleNonMaxSuppressionV4Out *node) final + { + (void)node; + assert(node->index() == 0 || node->index() == 1); + return loco::DataType::S32; + } + loco::DataType visit(const luci::CircleSplitOut *node) final { return loco::dtype_get(node->input()); @@ -589,6 +609,17 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::DataType::S32; } + loco::DataType visit(const luci::CircleUniqueOut *node) final + { + if (node->index() == 0) + { + return loco::dtype_get(node->input()); + } + assert(node->index() == 1); + auto unique = loco::must_cast<luci::CircleUnique *>(node->input()); + return unique->idx_out_type(); + } + loco::DataType visit(const luci::CircleUnpackOut *node) final { return loco::dtype_get(node->input()); diff --git a/compiler/luci/tests/test.lst b/compiler/luci/tests/test.lst index 188e29828..9fd42ed4e 100644 --- a/compiler/luci/tests/test.lst +++ b/compiler/luci/tests/test.lst @@ -20,6 +20,7 @@ addread(ArgMin_U8_001) addread(ArgMin_U8_002) addread(ArgMin_U8_003) addread(AveragePool2D_000) +addread(AveragePool2D_U8_000) addread(BatchMatMul_000) addread(BatchMatMulV2_000) addread(BatchMatMulV2_001) @@ -30,13 +31,16 @@ addread(Ceil_000) addread(Concatenation_000) addread(Concatenation_U8_000) addread(Conv2D_000) +addread(Conv2D_001) addread(Conv2D_002) addread(Conv2D_003) addread(Conv2D_U8_000) +addread(Conv2D_U8_001) addread(Cos_000) addread(DepthToSpace_000) addread(DepthwiseConv2D_000) addread(DepthwiseConv2D_U8_000) +addread(DepthwiseConv2D_U8_001) addread(DepthwiseConv2D_001) addread(Div_000) addread(ELU_000) @@ -64,6 +68,7 @@ addread(GreaterEqual_000) addread(If_000) addread(If_001) addread(L2Normalize_000) +addread(L2Normalize_U8_000) addread(L2Pool2D_000) addread(L2Pool2D_U8_000) addread(LeakyRelu_000) @@ -75,6 +80,7 @@ addread(LogicalAnd_000) addread(LogicalNot_000) addread(LogicalOr_000) addread(Logistic_000) +addread(Logistic_U8_000) addread(LogSoftmax_000) addread(MatMul_000) addread(MatrixDiag_000) @@ -84,6 +90,7 @@ addread(MaxPool2D_000) addread(MaxPool2D_U8_000) addread(Mean_000) addread(Mean_001) +addread(Mean_U8_000) addread(Minimum_000) addread(MirrorPad_000) addread(Mul_000) @@ -97,6 +104,7 @@ addread(OneHot_003) addread(Pack_000) addread(Pack_U8_000) addread(Pad_000) +addread(Pad_U8_000) addread(Pow_000) addread(PRelu_000) addread(Range_000) @@ -212,6 +220,7 @@ addwrite(ArgMin_U8_001) addwrite(ArgMin_U8_002) addwrite(ArgMin_U8_003) addwrite(AveragePool2D_000) +addwrite(AveragePool2D_U8_000) addwrite(BatchMatMul_000) addwrite(BatchMatMulV2_000) addwrite(BatchMatMulV2_001) @@ -222,13 +231,16 @@ addwrite(Ceil_000) addwrite(Concatenation_000) addwrite(Concatenation_U8_000) addwrite(Conv2D_000) +addwrite(Conv2D_001) addwrite(Conv2D_002) addwrite(Conv2D_003) addwrite(Conv2D_U8_000) +addwrite(Conv2D_U8_001) addwrite(Cos_000) addwrite(DepthToSpace_000) addwrite(DepthwiseConv2D_000) addwrite(DepthwiseConv2D_U8_000) +addwrite(DepthwiseConv2D_U8_001) addwrite(DepthwiseConv2D_001) addwrite(Div_000) addwrite(ELU_000) @@ -256,6 +268,7 @@ addwrite(GreaterEqual_000) addwrite(If_000) addwrite(If_001) addwrite(L2Normalize_000) +addwrite(L2Normalize_U8_000) addwrite(L2Pool2D_000) addwrite(L2Pool2D_U8_000) addwrite(LeakyRelu_000) @@ -267,6 +280,7 @@ addwrite(LogicalAnd_000) addwrite(LogicalNot_000) addwrite(LogicalOr_000) addwrite(Logistic_000) +addwrite(Logistic_U8_000) addwrite(LogSoftmax_000) addwrite(MatMul_000) addwrite(MatrixDiag_000) @@ -276,6 +290,7 @@ addwrite(MaxPool2D_000) addwrite(MaxPool2D_U8_000) addwrite(Mean_000) addwrite(Mean_001) +addwrite(Mean_U8_000) addwrite(Minimum_000) addwrite(MirrorPad_000) addwrite(Mul_000) diff --git a/compiler/mio-tflite/CMakeLists.txt b/compiler/mio-tflite/CMakeLists.txt index 2cfed1449..9ef2859b9 100644 --- a/compiler/mio-tflite/CMakeLists.txt +++ b/compiler/mio-tflite/CMakeLists.txt @@ -5,11 +5,7 @@ if(NOT FlatBuffers_FOUND) return() endif(NOT FlatBuffers_FOUND) -# TODO recover official release version -# NOTE we cannot use version number like "2.3.0-rc0" for find_package() -# use TensorFlowSource-2.3.0-rc0 as config itself -# nnas_find_package(TensorFlowSource EXACT 2.3.0 QUIET) -nnas_find_package(TensorFlowSource-2.3.0-rc0 QUIET) +nnas_find_package(TensorFlowSource EXACT 2.3.0 QUIET) if(NOT TensorFlowSource_FOUND) return() diff --git a/compiler/one-cmds/CMakeLists.txt b/compiler/one-cmds/CMakeLists.txt index 7d73d9b23..173b8b476 100644 --- a/compiler/one-cmds/CMakeLists.txt +++ b/compiler/one-cmds/CMakeLists.txt @@ -1,5 +1,6 @@ set(ONE_COMMAND_FILES one-import + one-import-bcq one-import-tf one-import-tflite one-optimize @@ -26,7 +27,7 @@ foreach(ONE_COMMAND IN ITEMS ${ONE_COMMAND_FILES}) install(FILES ${ONE_COMMAND} PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE - GROUP_READ GROUP_WRITE GROUP_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION bin) diff --git a/compiler/one-cmds/how-to-prepare-virtualenv.txt b/compiler/one-cmds/how-to-prepare-virtualenv.txt index 41fff3aaf..62a94968b 100644 --- a/compiler/one-cmds/how-to-prepare-virtualenv.txt +++ b/compiler/one-cmds/how-to-prepare-virtualenv.txt @@ -1,12 +1,12 @@ About ----- -Last update: 2020-07-14 +Last update: 2020-08-03 This document explains about 'one-prepare-venv' command. 'one-prepare-venv' will prepare python3 virtual environment with tensorflow-cpu -version 2.3.0rc0, recommanded 2.x version as of now, so that 'one-import-tf' +version 2.3.0, recommanded 2.x version as of now, so that 'one-import-tf' command can execute properly. diff --git a/compiler/one-cmds/how-to-use-one-commands.txt b/compiler/one-cmds/how-to-use-one-commands.txt index 6c2176afa..0ee69e077 100644 --- a/compiler/one-cmds/how-to-use-one-commands.txt +++ b/compiler/one-cmds/how-to-use-one-commands.txt @@ -1,7 +1,7 @@ About ----- -Last update: 2020-07-14 +Last update: 2020-07-31 This document briefly explains how to use one-* commands. Detailed options are not explained here. Run the command to see options. @@ -30,6 +30,27 @@ Syntax: one-import [framework] [options] Currently supported frameworks are 'tf', 'tflite' for TensorFlow and TensorFlow lite. +one-import-bcq +------------- + +This will convert Tensorflow model file (.pb) to our circle model file with applying BCQ. +To execute this command, original Tensorflow model file must include BCQ information. + +This command invokes following scripts internally. +- preserve_bcq_info : Prevent BCQ information vanishing problem +- generate_bcq_info : Designate BCQ information nodes as model output automatically +- tf2tfliteV2 : Convert Tensorflow model to tflite model +- tflite2circle : Convert Tensorflow Lite model to circle model +When this command is finished, BCQ information nodes will be removed if BCQ information +was valid and applying BCQ is done correctly without any errors. + +As tf2tfliteV2.py runs TensorFlow lite converter, you need to have TensorFlow +installed in your system. We recommand to use 2.3.0 for now. + +We provide python virtual environment and one-import-bcq will enter and leave +this environment so that you don't need to explictly 'activate' virtual +environment. + one-import-tf ------------- @@ -40,7 +61,7 @@ will internally use TensorFlow lite converter and then invoke tflite2circle converter to convert tflite model to circle model. As tf2tfliteV2.py runs TensorFlow lite converter, you need to have TensorFlow -installed in your system. We recommand to use 2.3.0rc0 for now. +installed in your system. We recommand to use 2.3.0 for now. We provide python virtual environment and one-import-tf will enter and leave this environment so that you don't need to explictly 'activate' virtual diff --git a/compiler/one-cmds/one-codegen b/compiler/one-cmds/one-codegen index 2c80664e2..820b6d8a3 100644 --- a/compiler/one-cmds/one-codegen +++ b/compiler/one-cmds/one-codegen @@ -18,7 +18,7 @@ DRIVER_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" function Usage() { - echo "Usage: $0 [BACKEND] ..." + echo "Usage: one-codegen [BACKEND] ..." echo "Available BACKEND drivers:" backend_exist=0 for file in `find $DRIVER_PATH -name *-compile -type f`; @@ -33,23 +33,34 @@ function Usage() if [ $backend_exist == 0 ]; then echo " (There is no available backend drivers)" fi + + exit 255 } -# Get command from command-line -BACKEND=$1; shift -BACKEND_DRIVER="$BACKEND-compile" +function version() +{ + $DRIVER_PATH/one-version one-codegen + exit 255 +} -if [[ -z "${BACKEND_DRIVER}" ]]; then +# Get command from command-line +BACKEND=$1 +if [[ -z ${BACKEND} ]]; then Usage - exit 255 fi +shift + +if [[ "${BACKEND}" == "--version" ]]; then + version +fi + +BACKEND_DRIVER="${BACKEND}-compile" BACKEND_DRIVER_CMD="${DRIVER_PATH}/${BACKEND_DRIVER}" if [[ ! -f "${BACKEND_DRIVER_CMD}" ]]; then echo "ERROR: '${BACKEND_DRIVER}' is not supported" Usage - exit 255 fi "${BACKEND_DRIVER_CMD}" "$@" diff --git a/compiler/one-cmds/one-import b/compiler/one-cmds/one-import index dbf4af534..b1dd8f4c3 100644 --- a/compiler/one-cmds/one-import +++ b/compiler/one-cmds/one-import @@ -18,7 +18,7 @@ DRIVER_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" function Usage() { - echo "Usage: $0 [FRAMEWORK] ..." + echo "Usage: one-import [FRAMEWORK] ..." echo "Available FRAMEWORK drivers:" framework_exist=0 for file in "$DRIVER_PATH"/one-import-*; @@ -31,23 +31,34 @@ function Usage() if [ $framework_exist == 0 ]; then echo " (There is no available import drivers)" fi + + exit 255 } -# Get command from command-line -FRAMEWORK=$1; shift -FRAMEWORK_DRIVER="one-import-$FRAMEWORK" +function version() +{ + $DRIVER_PATH/one-version one-import-tf + exit 255 +} -if [[ -z "${FRAMEWORK_DRIVER}" ]]; then +# Get command from command-line +FRAMEWORK=$1 +if [[ -z ${FRAMEWORK} ]]; then Usage - exit 255 +fi +shift + +if [ ${FRAMEWORK} = "--version" ]; then + version fi +FRAMEWORK_DRIVER="one-import-$FRAMEWORK" + FRAMEWORK_DRIVER_CMD="${DRIVER_PATH}/${FRAMEWORK_DRIVER}" if [[ ! -f "${FRAMEWORK_DRIVER_CMD}" ]]; then echo "ERROR: '${FRAMEWORK_DRIVER}' is not supported" Usage - exit 255 fi "${FRAMEWORK_DRIVER_CMD}" "$@" diff --git a/compiler/one-cmds/one-import-bcq b/compiler/one-cmds/one-import-bcq new file mode 100644 index 000000000..98dd1efed --- /dev/null +++ b/compiler/one-cmds/one-import-bcq @@ -0,0 +1,150 @@ +#!/bin/bash + +# 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. + +set -e + +DRIVER_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +usage() +{ + echo "Convert TensorFlow model with BCQ to circle." + echo "Usage: one-import-bcq" + echo " --version Show version information and exit" + echo " --input_path <path/to/tfmodel/with/BCQ>" + echo " --output_path <path/to/circle>" + echo " --input_arrays <names of the input arrays, comma-separated>" + echo " --input_shapes <input shapes, colon-separated>" + echo " --output_arrays <names of the output arrays, comma-separated>" + echo " --v2 Use TensorFlow 2.x interface (default is 1.x interface)" + exit 255 +} + +version() +{ + $DRIVER_PATH/one-version one-import-bcq + exit 255 +} + +TF_INTERFACE="--v1" + +# Parse command-line arguments +# +while [ "$#" -ne 0 ]; do + CUR="$1" + + case $CUR in + '--help') + usage + ;; + '--version') + version + ;; + '--input_path') + export INPUT_PATH="$2" + shift 2 + ;; + '--output_path') + export OUTPUT_PATH="$2" + shift 2 + ;; + '--input_arrays') + export INPUT_ARRAYS="$2" + shift 2 + ;; + '--input_shapes') + export INPUT_SHAPES="$2" + shift 2 + ;; + '--output_arrays') + export OUTPUT_ARRAYS="$2" + shift 2 + ;; + '--v2') + TF_INTERFACE="--v2" + shift + ;; + *) + echo "Unknown parameter: ${CUR}" + shift + ;; + esac +done + +if [ -z ${INPUT_PATH} ] || [ ! -e ${INPUT_PATH} ]; then + echo "Error: input model not found" + echo "" + usage + exit 2 +fi + +FILE_BASE=$(basename ${OUTPUT_PATH}) +MODEL_NAME="${FILE_BASE%.*}" + +TMPDIR=$(mktemp -d) +trap "{ rm -rf $TMPDIR; }" EXIT + +# activate python virtual environment +VIRTUALENV_LINUX="${DRIVER_PATH}/venv/bin/activate" +VIRTUALENV_WINDOWS="${DRIVER_PATH}/venv/Scripts/activate" + +if [ -e ${VIRTUALENV_LINUX} ]; then + source ${VIRTUALENV_LINUX} +elif [ -e ${VIRTUALENV_WINDOWS} ]; then + source ${VIRTUALENV_WINDOWS} +fi + +# remove previous log +rm -rf "${OUTPUT_PATH}.log" + +# generate temporary preserved pb file +echo "${DRIVER_PATH}/preserve_bcq_info" --input_path ${INPUT_PATH} \ +--output_path "${TMPDIR}/${MODEL_NAME}_preserved.pb" > "${OUTPUT_PATH}.log" +echo " " >> "${OUTPUT_PATH}.log" + +"${DRIVER_PATH}/preserve_bcq_info" --input_path ${INPUT_PATH} \ +--output_path "${TMPDIR}/${MODEL_NAME}_preserved.pb" >> "${OUTPUT_PATH}.log" 2>&1 + +# generate output_arrays automatically +echo "${DRIVER_PATH}/generate_bcq_output_arrays" \ +--input_path "${TMPDIR}/${MODEL_NAME}_preserved.pb" \ +--output_path "${TMPDIR}/${MODEL_NAME}_output_arrays.txt" > "${OUTPUT_PATH}.log" +echo " " >> "${OUTPUT_PATH}.log" + +"${DRIVER_PATH}/generate_bcq_output_arrays" \ +--input_path "${TMPDIR}/${MODEL_NAME}_preserved.pb" \ +--output_path "${TMPDIR}/${MODEL_NAME}_output_arrays.txt" >> "${OUTPUT_PATH}.log" 2>&1 + +# generate temporary tflite file +CONVERT_SCRIPT="python ${DRIVER_PATH}/tf2tfliteV2.py ${TF_INTERFACE} " +CONVERT_SCRIPT+="--input_path ${TMPDIR}/${MODEL_NAME}_preserved.pb " +CONVERT_SCRIPT+="--input_arrays ${INPUT_ARRAYS} " +CONVERT_SCRIPT+="--output_path ${TMPDIR}/${MODEL_NAME}.tflite " +CONVERT_SCRIPT+="--output_arrays ${OUTPUT_ARRAYS}$(cat ${TMPDIR}/${MODEL_NAME}_output_arrays.txt) " +if [ ! -z ${INPUT_SHAPES} ]; then + CONVERT_SCRIPT+="--input_shapes ${INPUT_SHAPES} " +fi + +echo ${CONVERT_SCRIPT} > "${OUTPUT_PATH}.log" +$CONVERT_SCRIPT >> "${OUTPUT_PATH}.log" 2>&1 + +# convert .tflite to .circle +echo " " >> "${OUTPUT_PATH}.log" +echo "${DRIVER_PATH}/tflite2circle" "${TMPDIR}/${MODEL_NAME}.tflite" \ +"${OUTPUT_PATH}" >> "${OUTPUT_PATH}.log" +echo " " >> "${OUTPUT_PATH}.log" + +"${DRIVER_PATH}/tflite2circle" "${TMPDIR}/${MODEL_NAME}.tflite" \ +"${OUTPUT_PATH}" >> "${OUTPUT_PATH}.log" 2>&1 diff --git a/compiler/one-cmds/one-import-tf b/compiler/one-cmds/one-import-tf index c048a4e0c..d59e1c529 100644 --- a/compiler/one-cmds/one-import-tf +++ b/compiler/one-cmds/one-import-tf @@ -22,14 +22,24 @@ usage() { echo "Convert TensorFlow model to circle." echo "Usage: one-import-tf" + echo " --version Show version information and exit" echo " --input_path <path/to/tfmodel>" echo " --output_path <path/to/circle>" echo " --input_arrays <names of the input arrays, comma-separated>" echo " --input_shapes <input shapes, colon-separated>" echo " --output_arrays <names of the output arrays, comma-separated>" - exit 0 + echo " --v2 Use TensorFlow 2.x interface (default is 1.x interface)" + exit 255 } +version() +{ + $DRIVER_PATH/one-version one-import-tf + exit 255 +} + +TF_INTERFACE="--v1" + # Parse command-line arguments # while [ "$#" -ne 0 ]; do @@ -39,6 +49,9 @@ while [ "$#" -ne 0 ]; do '--help') usage ;; + '--version') + version + ;; '--input_path') export INPUT_PATH="$2" shift 2 @@ -59,6 +72,10 @@ while [ "$#" -ne 0 ]; do export OUTPUT_ARRAYS="$2" shift 2 ;; + '--v2') + TF_INTERFACE="--v2" + shift + ;; *) echo "Unknown parameter: ${CUR}" shift @@ -92,14 +109,21 @@ fi # remove previous log rm -rf "${OUTPUT_PATH}.log" +show_err_onexit() +{ + cat "${OUTPUT_PATH}.log" +} + +trap show_err_onexit ERR + # generate temporary tflite file -echo "python" "${DRIVER_PATH}/tf2tfliteV2.py" --v2 --input_path ${INPUT_PATH} \ +echo "python" "${DRIVER_PATH}/tf2tfliteV2.py" ${TF_INTERFACE} --input_path ${INPUT_PATH} \ --input_arrays ${INPUT_ARRAYS} --input_shapes ${INPUT_SHAPES} \ --output_path "${TMPDIR}/${MODEL_NAME}.tflite" \ --output_arrays ${OUTPUT_ARRAYS} > "${OUTPUT_PATH}.log" echo " " >> "${OUTPUT_PATH}.log" -python "${DRIVER_PATH}/tf2tfliteV2.py" --v2 --input_path ${INPUT_PATH} \ +python "${DRIVER_PATH}/tf2tfliteV2.py" ${TF_INTERFACE} --input_path ${INPUT_PATH} \ --input_arrays ${INPUT_ARRAYS} --input_shapes ${INPUT_SHAPES} \ --output_path "${TMPDIR}/${MODEL_NAME}.tflite" \ --output_arrays ${OUTPUT_ARRAYS} >> "${OUTPUT_PATH}.log" 2>&1 diff --git a/compiler/one-cmds/one-import-tflite b/compiler/one-cmds/one-import-tflite index 31ed5af85..053489c92 100644 --- a/compiler/one-cmds/one-import-tflite +++ b/compiler/one-cmds/one-import-tflite @@ -22,9 +22,16 @@ usage() { echo "Convert TensorFlow lite model to circle." echo "Usage: one-import-tflite" + echo " --version Show version information and exit" echo " --input_path <path/to/tflitemodel>" echo " --output_path <path/to/circle>" - exit 0 + exit 255 +} + +version() +{ + $DRIVER_PATH/one-version one-import-tflite + exit 255 } # Parse command-line arguments @@ -36,6 +43,9 @@ while [ "$#" -ne 0 ]; do '--help') usage ;; + '--version') + version + ;; '--input_path') export INPUT_PATH="$2" shift 2 @@ -55,12 +65,18 @@ if [ -z ${INPUT_PATH} ] || [ ! -e ${INPUT_PATH} ]; then echo "Error: input model not found" echo "" usage - exit 2 fi # remove previous log rm -rf "${OUTPUT_PATH}.log" +show_err_onexit() +{ + cat "${OUTPUT_PATH}.log" +} + +trap show_err_onexit ERR + # convert .tflite to .circle echo "${DRIVER_PATH}/tflite2circle" "${INPUT_PATH}" "${OUTPUT_PATH}" > "${OUTPUT_PATH}.log" diff --git a/compiler/one-cmds/one-optimize b/compiler/one-cmds/one-optimize index 95384c10d..17b6b980e 100644 --- a/compiler/one-cmds/one-optimize +++ b/compiler/one-cmds/one-optimize @@ -22,6 +22,7 @@ usage() { echo "Optimize circle model." echo "Usage: one-optimize" + echo " --version Show version information and exit" echo " --all Enable all optimization algorithms" echo " --fuse_bcq Enable FuseBCQ Pass" echo " --fuse_instnorm Enable FuseInstanceNormalization Pass" @@ -33,7 +34,13 @@ usage() echo " Enable ResolveCustomOpMatMulPass Pass" echo " --input_path <path/to/input/circle>" echo " --output_path <path/to/output/circle>" - exit 0 + exit 255 +} + +version() +{ + $DRIVER_PATH/one-version one-optimize + exit 255 } OPTIMIZE_all=0 @@ -52,6 +59,9 @@ while [ "$#" -ne 0 ]; do '--help') usage ;; + '--version') + version + ;; '--all') OPTIMIZE_all=1 shift @@ -96,7 +106,6 @@ if [ -z ${INPUT_PATH} ] || [ ! -e ${INPUT_PATH} ]; then echo "Error: input model not found" echo "" usage - exit 2 fi OPTIMIZE_OPTIONS="" @@ -123,6 +132,13 @@ fi # remove previous log rm -rf "${OUTPUT_PATH}.log" +show_err_onexit() +{ + cat "${OUTPUT_PATH}.log" +} + +trap show_err_onexit ERR + # NOTE do not wrap ${OPTIMIZE_OPTIONS} with "" # optimize circle echo "${DRIVER_PATH}/circle2circle" ${OPTIMIZE_OPTIONS} \ diff --git a/compiler/one-cmds/one-pack b/compiler/one-cmds/one-pack index 2bc4c601d..023b0a85f 100644 --- a/compiler/one-cmds/one-pack +++ b/compiler/one-cmds/one-pack @@ -22,9 +22,16 @@ usage() { echo "Package circle to nnpkg" echo "Usage: one-pack" + echo " -v, --version Show version information and exit" echo " -i <path/to/circle>" echo " -o <path/to/nnpackage/folder>" - exit 0 + exit 255 +} + +version() +{ + $DRIVER_PATH/one-version one-pack + exit 255 } # Parse command-line arguments @@ -36,6 +43,12 @@ while [ "$#" -ne 0 ]; do '--help') usage ;; + '-v') + version + ;; + '--version') + version + ;; '-i') export INPUT_PATH="$2" shift 2 @@ -55,13 +68,22 @@ if [ -z ${INPUT_PATH} ] || [ ! -e ${INPUT_PATH} ]; then echo "Error: input model not found" echo "" usage - exit 2 fi +INPUT_FILE=$(basename "${INPUT_PATH}") +LOG_FILE="${INPUT_FILE%.*}.pack.log" + # remove previous log -rm -rf "${OUTPUT_PATH}.log" +rm -rf "${LOG_FILE}" + +show_err_onexit() +{ + cat "${LOG_FILE}" +} + +trap show_err_onexit ERR # Package circle model file to nnpkg -echo "${DRIVER_PATH}/model2nnpkg.sh" -o "${OUTPUT_PATH}" "${INPUT_PATH}" > "${OUTPUT_PATH}.log" +echo "${DRIVER_PATH}/model2nnpkg.sh" -o "${OUTPUT_PATH}" "${INPUT_PATH}" > "${LOG_FILE}" -"${DRIVER_PATH}/model2nnpkg.sh" -o "${OUTPUT_PATH}" "${INPUT_PATH}" >> "${OUTPUT_PATH}.log" 2>&1 +"${DRIVER_PATH}/model2nnpkg.sh" -o "${OUTPUT_PATH}" "${INPUT_PATH}" >> "${LOG_FILE}" 2>&1 diff --git a/compiler/one-cmds/one-prepare-venv b/compiler/one-cmds/one-prepare-venv index fce838d81..0a53bd3dd 100644 --- a/compiler/one-cmds/one-prepare-venv +++ b/compiler/one-cmds/one-prepare-venv @@ -26,7 +26,19 @@ if [ -f ${VENV_ACTIVATE} ]; then fi # Install prerequisites -python3 -m pip install -U virtualenv +python3 -m pip install --user -U virtualenv + +function error_no_ensurepip () +{ + echo "ERROR: python3 'ensurepip' module is not found." + echo " On ubuntu, try following command:" + echo + echo " apt install python$(python3 --version | awk '{print $2}' | awk -F. '{print $1"."$2}')-venv" + echo + echo " You may need root privilege for this." + exit 1 +} +python3 -m ensurepip --version > /dev/null 2>&1 || error_no_ensurepip # Create python virtual enviornment python3 -m venv "${DRIVER_PATH}/venv" @@ -37,4 +49,4 @@ source "${VENV_ACTIVATE}" python -m pip --default-timeout=1000 --trusted-host pypi.org --trusted-host files.pythonhost.org \ install -U pip setuptools python -m pip --default-timeout=1000 --trusted-host pypi.org --trusted-host files.pythonhost.org \ - install tensorflow-cpu==2.3.0rc0 + install tensorflow-cpu==2.3.0 diff --git a/compiler/one-cmds/one-quantize b/compiler/one-cmds/one-quantize index ff9e26672..c74b2c2d2 100644 --- a/compiler/one-cmds/one-quantize +++ b/compiler/one-cmds/one-quantize @@ -22,16 +22,23 @@ usage() { echo "Quantize circle model." echo "Usage: one-quantize" + echo " --version Show version information and exit" echo " --input_dtype Input data type (supported: float32, default=float32)" echo " --quantized_dtype Output quantized data type (supported: uint8, default=uint8)" - echo " --granularity Quantize granularity (supported: layer, default=layer)" + echo " --granularity Quantize granularity (supported: layer, channel, default=layer)" echo " --min_percentile Minimum percentile (0.0~100.0, default=1.0)" echo " --max_percentile Maximum percentile (0.0~100.0, default=99.0)" echo " --mode Record mode (supported: percentile/moving_average, default=percentile)" echo " --input_path <path/to/input/circle>" echo " --input_data <path/to/input/data>" echo " --output_path <path/to/output/circle>" - exit 0 + exit 255 +} + +version() +{ + $DRIVER_PATH/one-version one-quantize + exit 255 } INPUT_DTYPE=float32 @@ -50,6 +57,9 @@ while [ "$#" -ne 0 ]; do '--help') usage ;; + '--version') + version + ;; '--input_dtype') INPUT_DTYPE="$2" @@ -100,13 +110,11 @@ if [ -z ${INPUT_PATH} ] || [ ! -e ${INPUT_PATH} ]; then echo "Error: input model not found" echo "" usage - exit 2 fi if [ -z ${INPUT_DATA} ] || [ ! -e ${INPUT_DATA} ]; then echo "Error: input data not found" echo "" usage - exit 2 fi FILE_BASE=$(basename ${OUTPUT_PATH}) @@ -118,6 +126,13 @@ trap "{ rm -rf $TMPDIR; }" EXIT # remove previous log rm -rf "${OUTPUT_PATH}.log" +show_err_onexit() +{ + cat "${OUTPUT_PATH}.log" +} + +trap show_err_onexit ERR + # quantize circle echo "${DRIVER_PATH}/circle-quantizer" \ --quantize_dequantize_weights ${INPUT_DTYPE} ${QUANTIZED_DTYPE} ${GRANULARITY} \ diff --git a/compiler/one-cmds/requires.cmake b/compiler/one-cmds/requires.cmake index 9b858ad90..50c24579f 100644 --- a/compiler/one-cmds/requires.cmake +++ b/compiler/one-cmds/requires.cmake @@ -3,3 +3,5 @@ require("tflite2circle") require("circle2circle") require("circle-quantizer") require("record-minmax") +require("vconone") +require("bcq-tools") diff --git a/compiler/pota-quantization-value-test/CMakeLists.txt b/compiler/pota-quantization-value-test/CMakeLists.txt index d97ffc123..73b9ead73 100644 --- a/compiler/pota-quantization-value-test/CMakeLists.txt +++ b/compiler/pota-quantization-value-test/CMakeLists.txt @@ -49,21 +49,21 @@ add_test( ${QUANTIZATION_VALUE_TEST_WITH_PARAM} ) -#add_test( -# NAME pota_record_minmax_test -# COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_record_minmax.sh" -# "${TEST_CONFIG}" -# "${ARTIFACTS_BIN_PATH}" -# ${QUANTIZATION_VALUE_TEST_WITH_PARAM} -#) +add_test( + NAME pota_record_minmax_test + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_record_minmax.sh" + "${TEST_CONFIG}" + "${ARTIFACTS_BIN_PATH}" + ${QUANTIZATION_VALUE_TEST_WITH_PARAM} +) -#add_test( -# NAME pota_quantization_test -# COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_quantization.sh" -# "${TEST_CONFIG}" -# "${ARTIFACTS_BIN_PATH}" -# ${QUANTIZATION_VALUE_TEST_WITH_PARAM} -#) +add_test( + NAME pota_quantization_test + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_quantization.sh" + "${TEST_CONFIG}" + "${ARTIFACTS_BIN_PATH}" + ${QUANTIZATION_VALUE_TEST_WITH_PARAM} +) -#set_tests_properties(pota_record_minmax_test PROPERTIES DEPENDS pota_fake_wquant_test) -#set_tests_properties(pota_quantization_test PROPERTIES DEPENDS pota_record_minmax_test) +set_tests_properties(pota_record_minmax_test PROPERTIES DEPENDS pota_fake_wquant_test) +set_tests_properties(pota_quantization_test PROPERTIES DEPENDS pota_record_minmax_test) diff --git a/compiler/pota-quantization-value-test/compare_tensors.py b/compiler/pota-quantization-value-test/compare_tensors.py index 258d46dc9..7d95d182d 100755 --- a/compiler/pota-quantization-value-test/compare_tensors.py +++ b/compiler/pota-quantization-value-test/compare_tensors.py @@ -69,7 +69,7 @@ def compare_quantization(tensor, tensor_name, expect_dir): if key == "weights": expected_weights = np.array(json_load["weights"]) input_weights = tensor["weights"][:] - if np.allclose(input_weights, expected_weights, rtol=0, atol=0) == False: + if np.allclose(input_weights, expected_weights, rtol=0, atol=1) == False: print("Quantized weights of " + tensor_name + " (" + str(input_weights) + ") do not match with expected value (" + str(expected_weights) + ").") @@ -87,7 +87,7 @@ def compare_quantization(tensor, tensor_name, expect_dir): expected_zero_point = np.array(json_load["zero_point"]) input_zero_point = tensor["zero_point"][:] if np.allclose( - input_zero_point, expected_zero_point, rtol=0, atol=0) == False: + input_zero_point, expected_zero_point, rtol=0, atol=1) == False: print("Quantized zero_point of " + tensor_name + " (" + str(input_zero_point) + ") do not match with expected value (" + str(expected_zero_point) + ").") diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/fake_quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/fake_quantization/ker.json index 21b8ecad7..2558bb2be 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/fake_quantization/ker.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/fake_quantization/ker.json @@ -3,44 +3,44 @@ [ [ [ - 1.003921627998352, - 2.007843255996704 - ], + 1.0039215087890625, + 2.007843017578125 + ], [ - -3.0117647647857666, + -3.0117650032043457, -4.015686511993408 ] - ], + ], [ [ - -5.019608020782471, - 6.023529529571533 - ], + -5.019608497619629, + 6.023530006408691 + ], [ - -7.027451038360596, - 7.968627452850342 + -7.027451515197754, + 7.9686279296875 ] ] - ], + ], [ [ [ - 4.015686511993408, - -2.007843255996704 - ], + 4.01568603515625, + -2.007843494415283 + ], [ - 3.0117647647857666, - -1.003921627998352 + 3.0117645263671875, + -1.0039215087890625 ] - ], + ], [ [ - -7.968627452850342, - -6.023529529571533 - ], + -7.9686279296875, + -6.023530006408691 + ], [ - 7.027451038360596, - 5.019608020782471 + 7.027451515197754, + 5.019608497619629 ] ] ] diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/bias.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/bias.json index 462d0d3e3..50d44ece7 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/bias.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/bias.json @@ -1,7 +1,7 @@ - { - "scale": 0.0059054209919261825, - "weights": [ - 169.0, - 339.0 - ] - } +{ + "weights": [ + 4069, + 8138 + ], + "scale": 0.0002457468386200985 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ifm.json index 107117b80..24508860d 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ifm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ifm.json @@ -1,4 +1,4 @@ { - "scale": 0.09411764705882353, + "scale": 0.003916590008884668, "zero_point": 0.0 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ker.json index 3a6e171a1..b249a0ce5 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ker.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ker.json @@ -1,52 +1,52 @@ { - "max": 7.968627450980392, - "scale": 0.06274509803921569, "weights": [ [ [ [ - 144, - 160 - ], + 143, + 159 + ], [ - 80, - 64 + 79, + 63 ] - ], + ], [ [ - 48, - 224 - ], + 47, + 223 + ], [ - 16, - 255 + 15, + 254 ] ] - ], + ], [ [ [ - 192, - 96 - ], + 191, + 95 + ], [ - 176, - 112 + 175, + 111 ] - ], + ], [ [ - 1, - 32 - ], + 0, + 31 + ], [ - 240, - 208 + 239, + 207 ] ] ] - ], - "min": -8.031372549019608, - "zero_point": 128.0 + ], + "scale": 0.062745101749897, + "zero_point": 127.0, + "min": -7.9686279296875, + "max": 8.031373023986816 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ofm.json index 2374639b1..a2dd6681f 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ofm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/quantization/ofm.json @@ -1,4 +1,4 @@ { - "scale": 0.17836222929113052, + "scale": 0.037479765713214874, "zero_point": 0.0 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ifm.json index 563c0424f..42f8b5617 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ifm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ifm.json @@ -1,4 +1,4 @@ { - "max": 24.0, - "min": 1.0 + "min": 0.005472412034869194, + "max": 0.9987304735183716 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ofm.json index fd0c6dc86..1862e8cb2 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ofm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/Conv2D_004/layer/uint8/record_minmax/ofm.json @@ -1,4 +1,4 @@ { - "max": 45.48236846923828, - "min": 0.0 + "min": 0.0, + "max": 9.557340850830078 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/fake_quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/fake_quantization/ker.json index 11e91ca42..cd3479781 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/fake_quantization/ker.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/fake_quantization/ker.json @@ -3,29 +3,29 @@ [ [ [ - 0.9725490212440491, - 1.9450980424880981, - 3.0392158031463623, + 0.9725494384765625, + 1.945098876953125, + 3.039216995239258, 4.0117645263671875 - ], + ], [ - -8.996078491210938, - 9.968626976013184, - -10.941176414489746, - 12.035294532775879 + -8.996077537536621, + 9.9686279296875, + -10.94117546081543, + 12.035295486450195 ] - ], + ], [ [ - 4.984313488006592, - 5.956862926483154, - 7.050980567932129, - 8.023529052734375 - ], + 4.98431396484375, + 5.9568634033203125, + 7.050981521606445, + 8.023530960083008 + ], [ - 13.007843017578125, - -13.980392456054688, - 14.952940940856934, + 13.007843017578125, + -13.980391502380371, + 14.95294189453125, -16.04705810546875 ] ] diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/bias.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/bias.json index df7cb14c4..e60ff312e 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/bias.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/bias.json @@ -1,9 +1,9 @@ { - "scale": 0.007627835447904652, "weights": [ - 131.0, - 262.0, - 393.0, - 524.0 - ] + 2156, + 4312, + 6468, + 8624 + ], + "scale": 0.0004638272181067826 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ifm.json index 254ce899a..4ec4ef2d7 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ifm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ifm.json @@ -1,4 +1,4 @@ { - "scale": 0.06274509803921569, + "scale": 0.0038153529167175293, "zero_point": 0.0 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ker.json index 3d14da173..01835fbde 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ker.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ker.json @@ -1,38 +1,38 @@ { - "max": 14.952941176470588, - "scale": 0.12156862745098039, "weights": [ [ [ [ - 140, - 148, - 157, + 140, + 148, + 157, 165 - ], + ], [ - 58, - 214, - 42, + 58, + 214, + 42, 231 ] - ], + ], [ [ - 173, - 181, - 190, + 173, + 181, + 190, 198 - ], + ], [ - 239, - 17, - 255, + 239, + 17, + 255, 0 ] ] ] - ], - "min": -16.04705882352941, - "zero_point": 132.0 + ], + "scale": 0.12156862765550613, + "zero_point": 132.0, + "min": -16.04705810546875, + "max": 14.952940940856934 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ofm.json index 85dd4d9ae..39c64f3ef 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ofm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/quantization/ofm.json @@ -1,4 +1,4 @@ { - "scale": 0.893733185412837, + "scale": 0.07362665981054306, "zero_point": 0.0 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ifm.json index 9aee7bcb0..bb4292efe 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ifm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ifm.json @@ -1,4 +1,4 @@ { - "max": 16.0, - "min": 1.0 + "min": 0.02638142943382263, + "max": 0.9729149651527405 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ofm.json index aa42a6614..1c118e1db 100644 --- a/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ofm.json +++ b/compiler/pota-quantization-value-test/expected_outputs/DepthwiseConv2D_002/layer/uint8/record_minmax/ofm.json @@ -1,4 +1,4 @@ { - "max": 227.90196228027344, - "min": 0.0 + "min": 0.0, + "max": 18.77479721069336 } diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/fake_quantization/weight.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/fake_quantization/weight.json new file mode 100644 index 000000000..e1da53ab0 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/fake_quantization/weight.json @@ -0,0 +1,76 @@ +{ + "weights": [ + [ + 1.0039215087890625, + 2.007843017578125, + -3.0117650032043457, + -4.015686511993408, + -5.019608497619629, + 6.023530006408691, + -7.027451515197754, + 7.9686279296875, + 4.01568603515625, + -2.007843494415283, + 3.0117645263671875, + -1.0039215087890625, + -7.9686279296875, + -6.023530006408691, + 7.027451515197754, + 5.019608497619629 + ], + [ + 1.0039215087890625, + 2.007843017578125, + -3.0117650032043457, + -4.015686511993408, + -5.019608497619629, + 6.023530006408691, + -7.027451515197754, + 7.9686279296875, + 4.01568603515625, + -2.007843494415283, + 3.0117645263671875, + -1.0039215087890625, + -7.9686279296875, + -6.023530006408691, + 7.027451515197754, + 5.019608497619629 + ], + [ + 1.0039215087890625, + 2.007843017578125, + -3.0117650032043457, + -4.015686511993408, + -5.019608497619629, + 6.023530006408691, + -7.027451515197754, + 7.9686279296875, + 4.01568603515625, + -2.007843494415283, + 3.0117645263671875, + -1.0039215087890625, + -7.9686279296875, + -6.023530006408691, + 7.027451515197754, + 5.019608497619629 + ], + [ + 1.0039215087890625, + 2.007843017578125, + -3.0117650032043457, + -4.015686511993408, + -5.019608497619629, + 6.023530006408691, + -7.027451515197754, + 7.9686279296875, + 4.01568603515625, + -2.007843494415283, + 3.0117645263671875, + -1.0039215087890625, + -7.9686279296875, + -6.023530006408691, + 7.027451515197754, + 5.019608497619629 + ] + ] +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/bias.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/bias.json new file mode 100644 index 000000000..ecb49bb64 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/bias.json @@ -0,0 +1,9 @@ +{ + "weights": [ + 415, + -829, + -1244, + 1658 + ], + "scale": 0.00241205753304663 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/in.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/in.json new file mode 100644 index 000000000..654824b5d --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/in.json @@ -0,0 +1,4 @@ +{ + "scale": 0.03844216465950012, + "zero_point": 126.0 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/out.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/out.json new file mode 100644 index 000000000..3baa42155 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/out.json @@ -0,0 +1,4 @@ +{ + "scale": 0.741962730884552, + "zero_point": 156.0 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/weight.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/weight.json new file mode 100644 index 000000000..940224049 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/quantization/weight.json @@ -0,0 +1,80 @@ +{ + "weights": [ + [ + 143, + 159, + 79, + 63, + 47, + 223, + 15, + 254, + 191, + 95, + 175, + 111, + 0, + 31, + 239, + 207 + ], + [ + 143, + 159, + 79, + 63, + 47, + 223, + 15, + 254, + 191, + 95, + 175, + 111, + 0, + 31, + 239, + 207 + ], + [ + 143, + 159, + 79, + 63, + 47, + 223, + 15, + 254, + 191, + 95, + 175, + 111, + 0, + 31, + 239, + 207 + ], + [ + 143, + 159, + 79, + 63, + 47, + 223, + 15, + 254, + 191, + 95, + 175, + 111, + 0, + 31, + 239, + 207 + ] + ], + "scale": 0.062745101749897, + "zero_point": 127.0, + "min": -7.9686279296875, + "max": 8.031373023986816 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/in.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/in.json new file mode 100644 index 000000000..a8ec5b2b6 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/in.json @@ -0,0 +1,4 @@ +{ + "min": -4.832756385803223, + "max": 4.969995346069336 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/out.json b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/out.json new file mode 100644 index 000000000..de3b41564 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/FullyConnected_003/layer/uint8/record_minmax/out.json @@ -0,0 +1,4 @@ +{ + "min": -115.99438369750976, + "max": 73.20612327575684 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/fake_quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/fake_quantization/ker.json new file mode 100644 index 000000000..76a0440a0 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/fake_quantization/ker.json @@ -0,0 +1,48 @@ +{ + "weights": [ + [ + [ + [ + 0.960784912109375, + 2.0588245391845703 + ], + [ + -3.0196075439453125, + -3.980391502380371 + ], + [ + 4.9411773681640625, + -6.039215087890625 + ] + ], + [ + [ + 7.0, + 7.960784912109375 + ], + [ + -9.058823585510254, + -10.019607543945312 + ], + [ + 10.980392456054688, + -11.941176414489746 + ] + ], + [ + [ + 13.039216995239258, + 14.000001907348633 + ], + [ + -14.960784912109375, + -16.05882453918457 + ], + [ + 17.019607543945312, + -17.980392456054688 + ] + ] + ] + ] +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ifm.json new file mode 100644 index 000000000..dc5ca8dd5 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ifm.json @@ -0,0 +1,4 @@ +{ + "scale": 0.03869570419192314, + "zero_point": 126.0 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ker.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ker.json new file mode 100644 index 000000000..bc150bbb0 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ker.json @@ -0,0 +1,52 @@ +{ + "weights": [ + [ + [ + [ + 138, + 146 + ], + [ + 109, + 102 + ], + [ + 167, + 87 + ] + ], + [ + [ + 182, + 189 + ], + [ + 65, + 58 + ], + [ + 211, + 44 + ] + ], + [ + [ + 226, + 233 + ], + [ + 22, + 14 + ], + [ + 255, + 0 + ] + ] + ] + ], + "scale": 0.13725490868091583, + "zero_point": 131.0, + "min": -17.980392456054688, + "max": 17.019609451293945 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ofm.json new file mode 100644 index 000000000..bfd862189 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/quantization/ofm.json @@ -0,0 +1,4 @@ +{ + "scale": 1.6333034038543701, + "zero_point": 127.0 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ifm.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ifm.json new file mode 100644 index 000000000..2d2af08a6 --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ifm.json @@ -0,0 +1,4 @@ +{ + "min": -4.890846576690674, + "max": 4.976558513641357 +} diff --git a/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ofm.json b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ofm.json new file mode 100644 index 000000000..24598f06e --- /dev/null +++ b/compiler/pota-quantization-value-test/expected_outputs/TransposeConv_001/layer/uint8/record_minmax/ofm.json @@ -0,0 +1,4 @@ +{ + "min": -207.54233032226563, + "max": 208.95002136230468 +} diff --git a/compiler/pota-quantization-value-test/test.lst b/compiler/pota-quantization-value-test/test.lst index 65613ff8f..9eb348922 100644 --- a/compiler/pota-quantization-value-test/test.lst +++ b/compiler/pota-quantization-value-test/test.lst @@ -1,2 +1,4 @@ addTest(Conv2D_004 layer uint8) addTest(DepthwiseConv2D_002 layer uint8) +addTest(FullyConnected_003 layer uint8) +addTest(TransposeConv_001 layer uint8) diff --git a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/0.txt b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/0.txt index 8803cb178..0614b5e83 100644 --- a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/0.txt +++ b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/0.txt @@ -1 +1 @@ -1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 +0.01090685,0.0581577 ,0.637094 ,0.64067715,0.26264507,0.13692169,0.9649414 ,0.5117181 ,0.18012471,0.07855253,0.6358017 ,0.62257963,0.41469443,0.93169045,0.20763828,0.7634293 ,0.75929826,0.72708374,0.23463063,0.58222896,0.6351517 ,0.68781173,0.5558012 ,0.7652179 diff --git a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/1.txt b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/1.txt new file mode 100644 index 000000000..b1c39382f --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/1.txt @@ -0,0 +1 @@ +0.57017624,0.08235867,0.03672464,0.40372616,0.7353964 ,0.59611887,0.7675548 ,0.21004233,0.09803218,0.20009473,0.8821493 ,0.17015271,0.14840214,0.99910176,0.37003204,0.22893582,0.43173164,0.3105084 ,0.41997132,0.43714985,0.08115962,0.71896386,0.7810953 ,0.00524598 diff --git a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/2.txt b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/2.txt new file mode 100644 index 000000000..7e562de75 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/2.txt @@ -0,0 +1 @@ +0.65292275,0.79842275,0.97853714,0.6711518 ,0.607567 ,0.40971732,0.74838483,0.95853555,0.32158023,0.911524 ,0.66938365,0.8573132 ,0.3047727 ,0.5561248 ,0.914098 ,0.07650814,0.37868017,0.29269257,0.19652605,0.63025194,0.61496884,0.32011527,0.8204132 ,0.21866946 diff --git a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/3.txt b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/3.txt new file mode 100644 index 000000000..2958a7f54 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/3.txt @@ -0,0 +1 @@ +0.4548901 ,0.56957537,0.0252368 ,0.4884317 ,0.7516498 ,0.02631272,0.22107519,0.95249426,0.34902394,0.11520014,0.808911 ,0.4148615 ,0.63615656,0.84020686,0.3633697 ,0.23993976,0.54176176,0.86938345,0.81628686,0.6380988 ,0.91891205,0.0406627 ,0.90289026,0.9429013 diff --git a/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/4.txt b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/4.txt new file mode 100644 index 000000000..fc969308e --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/Conv2D_004/layer/uint8/4.txt @@ -0,0 +1 @@ +0.9309136 ,0.02123719,0.64467335,0.6910113 ,0.47402772,0.54622203,0.31527275,0.81530565,0.98981965,0.36102158,0.03114039,0.1902339 ,0.45183742,0.60178596,0.4683102 ,0.59810966,0.40558222,0.5420302 ,0.72699505,0.9575108 ,0.46746576,0.08518691,0.40302262,0.69213694 diff --git a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/0.txt b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/0.txt index c210774d2..44f0ff107 100644 --- a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/0.txt +++ b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/0.txt @@ -1 +1 @@ -1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12, 13, 14, 15, 16 +0.31365377,0.6127105 ,0.7047126 ,0.2511918 ,0.16652136,0.36075932,0.44332707,0.77615815,0.60456425,0.26207635,0.28714025,0.11579613,0.89698446,0.67223394,0.3757766 ,0.11787009 diff --git a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/1.txt b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/1.txt new file mode 100644 index 000000000..98e81041f --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/1.txt @@ -0,0 +1 @@ +0.9409595 ,0.3991174 ,0.43546647,0.221152 ,0.7794665 ,0.8619514 ,0.5903087 ,0.24476172,0.5932698 ,0.2727837 ,0.3980262 ,0.13329633,0.4319272 ,0.37872055,0.1721639 ,0.92437047 diff --git a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/2.txt b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/2.txt new file mode 100644 index 000000000..e9867529b --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/2.txt @@ -0,0 +1 @@ +0.6484028 ,0.09222967,0.76285905,0.02265582,0.2564394 ,0.11219095,0.22529566,0.09101159,0.15937322,0.3540595 ,0.25971088,0.4681136 ,0.4279646 ,0.5386553 ,0.11397707,0.7413688 diff --git a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/3.txt b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/3.txt new file mode 100644 index 000000000..9b36fb520 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/3.txt @@ -0,0 +1 @@ +0.9182678 ,0.8253187 ,0.6572848 ,0.46436486,0.45208713,0.42112917,0.24383743,0.16039051,0.24649048,0.63431305,0.31141657,0.25664324,0.721266 ,0.18996912,0.35422477,0.8826148 diff --git a/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/4.txt b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/4.txt new file mode 100644 index 000000000..6b8957dcc --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/DepthwiseConv2D_002/layer/uint8/4.txt @@ -0,0 +1 @@ +0.97424644,0.9360494 ,0.6849295 ,0.21313633,0.23943195,0.32497332,0.5091704 ,0.67543274,0.49667478,0.73460567,0.5866559 ,0.5312464 ,0.8252662 ,0.36093768,0.7143621 ,0.7234413 diff --git a/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/0.txt b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/0.txt new file mode 100644 index 000000000..233e5eae3 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/0.txt @@ -0,0 +1 @@ + 2.7731526 , 2.451602 , 3.7535272 ,-1.2774152 , 1.5482912 , 1.3402948 , 4.4792123 ,-4.4954367 , 3.354679 ,-3.3615496 ,-4.619757 ,-3.3659618 , 4.7626247 ,-1.3596478 ,-4.835548 , 0.78964525 diff --git a/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/1.txt b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/1.txt new file mode 100644 index 000000000..6a126081d --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/1.txt @@ -0,0 +1 @@ + 0.5400839 ,-3.2621996 ,-3.4817135 , 3.8183312 , 0.48498327, 2.9812584 , 4.111276 , 0.11223658, 4.7201405 , 2.4256718 , 1.4895477 , 4.7596602 ,-0.32709372, 1.3507305 ,-0.30043927,-1.8077502 diff --git a/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/2.txt b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/2.txt new file mode 100644 index 000000000..eccd2c625 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/2.txt @@ -0,0 +1 @@ + 3.8758078 , 4.978636 ,-0.22925885,-2.6760504 ,-1.9160627 ,-4.609644 ,-0.9515802 , 3.558274 , 2.9096057 , 0.3340422 , 0.38608226,-0.32168412, 4.688853 ,-4.583811 ,-2.5113506 ,-4.6688786 diff --git a/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/3.txt b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/3.txt new file mode 100644 index 000000000..0da05277c --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/3.txt @@ -0,0 +1 @@ +-2.9868221 , 2.4237797 , 1.0833962 ,-0.9231426 ,-2.1091506 ,-2.6163697 ,-0.23101932,-1.9252896 , 4.7034135 , 3.1088963 ,-2.345823 ,-2.7866168 ,-3.186763 ,-4.431844 , 3.3113294 , 0.9501982 diff --git a/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/4.txt b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/4.txt new file mode 100644 index 000000000..ace24f7c1 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/FullyConnected_003/layer/uint8/4.txt @@ -0,0 +1 @@ + 3.9716747 ,-2.254871 , 1.1943274 ,-2.212602 , 3.4311683 , 1.114989 , 4.0739036 , 0.47244295,-3.5793104 ,-3.359908 ,-4.7657595 , 2.0369127 ,-2.5619278 ,-3.4452975 ,-4.5852203 ,-1.137643 diff --git a/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/0.txt b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/0.txt new file mode 100644 index 000000000..e9db48f9e --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/0.txt @@ -0,0 +1 @@ +-1.4124781 , 0.42694193, 1.1734594 ,-3.5111153 ,-2.9756174 , 1.3682148 ,-2.318465 , 2.198896 ,-4.5043235 , 3.1775594 ,-0.42802384,-1.4872279 , 1.3821319 ,-4.771963 ,-0.12837897, 4.132799 , 3.697655 , 2.0807178 ,-3.621293 , 2.121878 ,-0.25654107, 0.42100102,-1.4009671 ,-2.9733627 ,-0.7058871 ,-2.831215 , 3.5669627 , 2.1420689 ,-1.8789555 , 0.8104939 ,-2.0503597 , 1.7788508 diff --git a/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/1.txt b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/1.txt new file mode 100644 index 000000000..479d062f1 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/1.txt @@ -0,0 +1 @@ + 3.4726453 , 3.0497985 ,-4.234619 ,-1.0526706 , 1.7278554 ,-3.341614 , 4.54768 , 3.0954597 ,-3.735109 , 2.8810751 ,-2.5381427 ,-3.2360535 ,-1.5378917 , 2.3052745 ,-3.170938 ,-3.327242 , 2.0654576 ,-2.2294598 ,-1.881382 , 0.13216451,-4.2825613 , 0.26616526, 4.6196365 ,-0.88623226, 1.7103885 ,-1.5865034 ,-3.9114466 ,-3.2227128 , 4.909618 , 2.3318915 , 0.84300846, 0.760918 diff --git a/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/2.txt b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/2.txt new file mode 100644 index 000000000..ae28234bd --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/2.txt @@ -0,0 +1 @@ +-4.6097918,-4.21991 ,-3.9955974, 3.6492047, 2.9191775, 2.8082933, 1.6189331, 0.2730309,-1.5029653,-1.9471445, 4.8758197, 3.3177438, 3.1338058,-2.1281245,-1.7526287,-2.5518703,-1.7746793, 4.0455256,-0.5839861,-4.408046 ,-4.0034447, 1.5858272,-4.5896654, 4.7211285,-4.677515 ,-2.6027086,-4.7896166,-3.5512326,-1.9068764,-2.9705904,-4.854087 ,-4.892111 diff --git a/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/3.txt b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/3.txt new file mode 100644 index 000000000..fd40f84f4 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/3.txt @@ -0,0 +1 @@ + 2.1514777e-02, 2.6526773e+00,-3.0477784e+00, 1.3287724e+00,-4.1414630e-01,-1.7295350e-01, 7.6649576e-01,-1.8028022e+00,-7.0781744e-01,-2.5262204e-01,-3.0970418e+00,-1.3165286e+00,-4.6649928e+00, 2.0809033e+00,-1.5739973e+00,-4.0531826e-01,-2.1718202e+00, 2.0146034e+00, 2.5044403e+00,-1.1256610e+00, 1.3536702e+00, 1.0283234e-03,-1.8823910e+00, 4.7122188e+00, 9.4781297e-01, 3.2012525e+00,-5.5164534e-01,-2.6158772e+00,-1.8771547e+00,-3.1689723e+00, 4.9054880e+00,-3.4560370e+00 diff --git a/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/4.txt b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/4.txt new file mode 100644 index 000000000..e81c3b8e5 --- /dev/null +++ b/compiler/pota-quantization-value-test/test_inputs/TransposeConv_001/layer/uint8/4.txt @@ -0,0 +1 @@ +-2.0927553 ,-2.107511 ,-1.6963564 , 1.7006218 , 1.4575784 , 0.06095728, 1.2659966 , 4.1905265 , 1.3035946 , 4.9793477 ,-4.3388166 ,-0.23496658, 1.9831208 , 2.6154642 ,-0.2790228 ,-3.1774354 ,-3.178935 ,-1.1564373 ,-0.8199472 ,-2.245698 ,-4.8605046 ,-3.569018 ,-1.4226891 ,-4.1067843 , 2.6078918 ,-3.5830674 , 1.9065963 , 2.435578 ,-3.3216476 , 4.5930347 , 2.9191844 , 1.7885648 diff --git a/compiler/pota-quantization-value-test/test_record_minmax.sh b/compiler/pota-quantization-value-test/test_record_minmax.sh index eaa462d0c..acb7574c0 100755 --- a/compiler/pota-quantization-value-test/test_record_minmax.sh +++ b/compiler/pota-quantization-value-test/test_record_minmax.sh @@ -59,9 +59,9 @@ while [ "$1" != "" ]; do # Run record-minmax "${RECORD_MINMAX_PATH}" \ - "${TEST_RESULT_FILE}.fake_quantized.circle" \ - "${TEST_RESULT_FILE}.input.h5" \ - "${TEST_RESULT_FILE}.minmax_recorded.circle" + --input_model "${TEST_RESULT_FILE}.fake_quantized.circle" \ + --input_data "${TESTCASE_FILE}.input.h5" \ + --output_model "${TEST_RESULT_FILE}.minmax_recorded.circle" # Dump min/max values (circle-tensordump) "${CIRCLE_TENSORDUMP_PATH}" \ diff --git a/compiler/record-minmax/CMakeLists.txt b/compiler/record-minmax/CMakeLists.txt index 862660e06..f8a165bd3 100644 --- a/compiler/record-minmax/CMakeLists.txt +++ b/compiler/record-minmax/CMakeLists.txt @@ -19,9 +19,14 @@ target_link_libraries(record-minmax safemain) target_link_libraries(record-minmax luci_import) target_link_libraries(record-minmax luci_export) target_link_libraries(record-minmax luci_interpreter) +target_link_libraries(record-minmax vconone) install(TARGETS record-minmax DESTINATION bin) +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + nnas_find_package(GTest REQUIRED) GTest_AddTest(record_minmax_function_test "${CMAKE_CURRENT_SOURCE_DIR}/tests/RecordFunction.test.cpp") target_include_directories(record_minmax_function_test PRIVATE include) diff --git a/compiler/record-minmax/driver/Driver.cpp b/compiler/record-minmax/driver/Driver.cpp index ae4fcb7c7..8b09498c3 100644 --- a/compiler/record-minmax/driver/Driver.cpp +++ b/compiler/record-minmax/driver/Driver.cpp @@ -17,6 +17,13 @@ #include "RecordMinMax.h" #include <arser/arser.h> +#include <vconone/vconone.h> + +void print_version(void) +{ + std::cout << "record-minmax version " << vconone::get_string() << std::endl; + std::cout << vconone::get_copyright() << std::endl; +} int entry(const int argc, char **argv) { @@ -25,6 +32,13 @@ int entry(const int argc, char **argv) arser::Arser arser( "Embedding min/max values of activations to the circle model for post-training quantization"); + arser.add_argument("--version") + .nargs(0) + .required(false) + .default_value(false) + .help("Show version information and exit") + .exit_with(print_version); + arser.add_argument("--input_model") .nargs(1) .type(arser::DataType::STR) @@ -66,7 +80,7 @@ int entry(const int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } auto input_model_path = arser.get<std::string>("--input_model"); diff --git a/compiler/record-minmax/requires.cmake b/compiler/record-minmax/requires.cmake index 054503539..f6804cef1 100644 --- a/compiler/record-minmax/requires.cmake +++ b/compiler/record-minmax/requires.cmake @@ -1,3 +1,4 @@ require("luci") require("safemain") require("arser") +require("vconone") diff --git a/compiler/record-minmax/src/HDF5Importer.cpp b/compiler/record-minmax/src/HDF5Importer.cpp index cf30cd863..a0e65eeb7 100644 --- a/compiler/record-minmax/src/HDF5Importer.cpp +++ b/compiler/record-minmax/src/HDF5Importer.cpp @@ -20,6 +20,7 @@ #include <string> #include <cassert> +#include <stdexcept> using Shape = luci_interpreter::Shape; using DataType = luci_interpreter::DataType; diff --git a/compiler/record-minmax/src/MinMaxObserver.cpp b/compiler/record-minmax/src/MinMaxObserver.cpp index 45f0197c8..c22cb4132 100644 --- a/compiler/record-minmax/src/MinMaxObserver.cpp +++ b/compiler/record-minmax/src/MinMaxObserver.cpp @@ -38,7 +38,7 @@ void MinMaxObserver::postTensorWrite(const luci::CircleNode *node, assert(node->opcode() != luci::CircleOpcode::UNPACK); assert(node->opcode() != luci::CircleOpcode::WHILE); - if (node->opcode() == luci::CircleOpcode::CONST) + if (node->opcode() == luci::CircleOpcode::CIRCLECONST) { // node is not activation. Do nothing. return; diff --git a/compiler/record-minmax/src/RecordMinMax.cpp b/compiler/record-minmax/src/RecordMinMax.cpp index d12a0d3ae..17c6aa6ff 100644 --- a/compiler/record-minmax/src/RecordMinMax.cpp +++ b/compiler/record-minmax/src/RecordMinMax.cpp @@ -158,7 +158,7 @@ void RecordMinMax::profileData(const std::string &mode, const std::string &input auto node = iter->first; auto minmax = iter->second; - float min, max; + float min{0.0f}, max{0.0f}; if (mode == "percentile") { min = getNthPercentile(minmax.min_vector, min_percentile); diff --git a/compiler/record-minmax/tests/RecordFunction.test.cpp b/compiler/record-minmax/tests/RecordFunction.test.cpp index 13b464db9..e2f135a4e 100644 --- a/compiler/record-minmax/tests/RecordFunction.test.cpp +++ b/compiler/record-minmax/tests/RecordFunction.test.cpp @@ -32,6 +32,8 @@ TEST(GetNthPercentileTest, Edge) EXPECT_FLOAT_NEAR(0, getNthPercentile(input, 0)); EXPECT_FLOAT_NEAR(9, getNthPercentile(input, 100)); + + SUCCEED(); } TEST(GetNthPercentileTest, Simple) @@ -47,6 +49,8 @@ TEST(GetNthPercentileTest, Simple) { EXPECT_FLOAT_NEAR(0.09 * std::floor(i) + 0.045, getNthPercentile(input, i)); } + + SUCCEED(); } TEST(GetNthPercentileTest, Float) @@ -61,6 +65,8 @@ TEST(GetNthPercentileTest, Float) EXPECT_FLOAT_NEAR(2.799942346802177, getNthPercentile(input, 1)); EXPECT_FLOAT_NEAR(7.768503955476342, getNthPercentile(input, 3.14)); EXPECT_FLOAT_NEAR(99.40456084968194, getNthPercentile(input, 99)); + + SUCCEED(); } TEST(GetNthPercentileTest, FloatWithNegative) @@ -75,6 +81,8 @@ TEST(GetNthPercentileTest, FloatWithNegative) EXPECT_FLOAT_NEAR(-47.20005765319782, getNthPercentile(input, 1)); EXPECT_FLOAT_NEAR(-42.23149604452366, getNthPercentile(input, 3.14)); EXPECT_FLOAT_NEAR(49.40456084968194, getNthPercentile(input, 99)); + + SUCCEED(); } TEST(GetNthPercentileTest, SigleElement) @@ -84,6 +92,8 @@ TEST(GetNthPercentileTest, SigleElement) EXPECT_FLOAT_NEAR(33, getNthPercentile(input, 0)); EXPECT_FLOAT_NEAR(33, getNthPercentile(input, 50)); EXPECT_FLOAT_NEAR(33, getNthPercentile(input, 100)); + + SUCCEED(); } TEST(GetNthPercentileTest, OutOfBoundary_NEG) @@ -92,6 +102,8 @@ TEST(GetNthPercentileTest, OutOfBoundary_NEG) EXPECT_THROW(getNthPercentile(input, -1), std::runtime_error); EXPECT_THROW(getNthPercentile(input, 101), std::runtime_error); + + SUCCEED(); } TEST(GetNthPercentileTest, EmptyVector_NEG) @@ -99,6 +111,8 @@ TEST(GetNthPercentileTest, EmptyVector_NEG) std::vector<float> input; EXPECT_THROW(getNthPercentile(input, 10), std::runtime_error); + + SUCCEED(); } } // namespace record_minmax diff --git a/compiler/tf2circle-value-pbtxt-remote-test/CMakeLists.txt b/compiler/tf2circle-value-pbtxt-remote-test/CMakeLists.txt index 64dcc28fd..852018e64 100644 --- a/compiler/tf2circle-value-pbtxt-remote-test/CMakeLists.txt +++ b/compiler/tf2circle-value-pbtxt-remote-test/CMakeLists.txt @@ -141,7 +141,6 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E echo 'HDF5_EXPORT_ACTION_PATH=\"$<TARGET_FILE:nnkit_HDF5_export_action>\"' >> ${TEST_CONFIG} COMMAND ${CMAKE_COMMAND} -E echo 'HDF5_IMPORT_ACTION_PATH=\"$<TARGET_FILE:nnkit_HDF5_import_action>\"' >> ${TEST_CONFIG} COMMAND ${CMAKE_COMMAND} -E echo 'MODEL2NNPKG_PATH=\"${NNAS_PROJECT_SOURCE_DIR}/tools/nnpackage_tool/model2nnpkg/model2nnpkg.sh\"' >> ${TEST_CONFIG} - COMMAND ${CMAKE_COMMAND} -E echo 'NNPKG_TEST_PATH=\"${NNAS_PROJECT_SOURCE_DIR}/tests/scripts/nnpkg_test.sh\"' >> ${TEST_CONFIG} COMMAND ${CMAKE_COMMAND} -E echo 'RUNTIME_LIBRARY_PATH=\"${NNAS_PROJECT_SOURCE_DIR}/Product/out/\"' >> ${TEST_CONFIG} DEPENDS nnkit-run diff --git a/compiler/tf2circle-value-pbtxt-remote-test/README.md b/compiler/tf2circle-value-pbtxt-remote-test/README.md index 5546cc879..0d41b0a48 100644 --- a/compiler/tf2circle-value-pbtxt-remote-test/README.md +++ b/compiler/tf2circle-value-pbtxt-remote-test/README.md @@ -36,13 +36,13 @@ #--------------- Remote Machine Setting ---------------# set(REMOTE_IP "xxx.xxx.xxx.xxx") set(REMOTE_USER "remote_username") - + #--------------------- Tests list ---------------------# add(UNIT_Add_000) add(UNIT_Add_001) ... ``` - - If any Tensorflow model is added, or if `REMOTE_IP` and `REMOTE_USER` is not given, `tf2circle-value-pbtxt-remote-test` will not be created. + - If any Tensorflow model is added, or if `REMOTE_IP` and `REMOTE_USER` is not given, `tf2circle-value-pbtxt-remote-test` will not be created. 1. (Optional) ssh authentication - This test uses `ssh` and `scp` commands, and those commands require a password of remote machine whenever they are called. This means that you should enter the password everytime when `ssh` and `scp` require. - This test resolves the problem by using `ssh-copy-id`, which copies the public key of host machine to `authorized_keys` of remote machine. Because of that, this test will ask the password of remote machine only once, at the first time. This is the only user interaction while running this test. @@ -71,7 +71,7 @@ ├ Result_latest -> Result_YYMMDD_hhmmss.csv ├ Result_YYMMDD_hhmmss.csv ├ ... - | + | ├ UNIT_Add_000 | ├ metadata | | ├ MANIFEST @@ -91,16 +91,16 @@ | ├ ... ``` -- `nnpkg_test.sh`, runtime products and each nnpackage are sent to `REMOTE_WORKDIR` in remote machine. +- Runtime products and each nnpackage are sent to `REMOTE_WORKDIR` in remote machine. - (TBD) Modify script not to remove obtained h5 file. ``` REMOTE_WORKDIR - ├ nnpkg_test.sh | ├ Product | â”” out | ├ bin | ├ lib + | ├ test | ├ ... | ├ UNIT_Add_000 diff --git a/compiler/tf2circle-value-pbtxt-remote-test/testall.sh b/compiler/tf2circle-value-pbtxt-remote-test/testall.sh index ca6fb49c8..c80b00a14 100755 --- a/compiler/tf2circle-value-pbtxt-remote-test/testall.sh +++ b/compiler/tf2circle-value-pbtxt-remote-test/testall.sh @@ -30,7 +30,6 @@ echo "-- Found nnkit-run: ${NNKIT_RUN_PATH}" echo "-- Found TF backend: ${TF_BACKEND_PATH}" echo "-- Found TF2CIRCLE: ${TF2CIRCLE_PATH}" echo "-- Found MODEL2NNPKG: ${MODEL2NNPKG_PATH}" -echo "-- Found nnpkg_test: ${NNPKG_TEST_PATH}" echo "-- Found Runtime library: ${RUNTIME_LIBRARY_PATH}" echo "-- Found randomize action: ${RANDOMIZE_ACTION_PATH}" echo "-- Found HDF5 export action: ${HDF5_EXPORT_ACTION_PATH}" @@ -42,11 +41,6 @@ if [ -z ${MODEL2NNPKG_PATH} ] || [ ! -f ${MODEL2NNPKG_PATH} ]; then exit 3 fi -if [ -z ${NNPKG_TEST_PATH} ] || [ ! -f ${NNPKG_TEST_PATH} ]; then - echo "nnpkg_test is not found" - exit 4 -fi - # Register remote machine ssh information cat /dev/zero | ssh-keygen -q -N "" ssh-copy-id -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_IP}" @@ -61,9 +55,6 @@ fi ssh "${REMOTE_USER}@${REMOTE_IP}" "mkdir -p ${REMOTE_WORKDIR}/Product/" scp -r "${RUNTIME_LIBRARY_PATH}" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/Product/" -# Send nnpkg_test.sh -scp "${NNPKG_TEST_PATH}" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/" - TESTED=() PASSED=() FAILED=() @@ -120,8 +111,8 @@ while [[ $# -ne 0 ]]; do # Run test_arm_nnpkg in remote machine scp -r "${WORKDIR}/${PREFIX}/" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/${PREFIX}/" - ssh "${REMOTE_USER}@${REMOTE_IP}" "cd ${REMOTE_WORKDIR}; ./nnpkg_test.sh -i . -o ${PREFIX}/metadata/tc ${PREFIX}" - + ssh "${REMOTE_USER}@${REMOTE_IP}" "cd ${REMOTE_WORKDIR}; ./Product/out/test/onert-test nnpkg-test -i . -o ${PREFIX}/metadata/tc ${PREFIX}" + if [[ $? -eq 0 ]]; then touch "${PASSED_TAG}" fi diff --git a/compiler/tf2nnpackage-value-remote-test/CMakeLists.txt b/compiler/tf2nnpackage-value-remote-test/CMakeLists.txt index 4a59e8849..255806ce8 100644 --- a/compiler/tf2nnpackage-value-remote-test/CMakeLists.txt +++ b/compiler/tf2nnpackage-value-remote-test/CMakeLists.txt @@ -33,12 +33,12 @@ endforeach() get_target_property(ARTIFACTS_SRC_PATH testDataGenerator SOURCE_DIR) -# In this test, only the runtime test is performed because the test from tf to -# nnpackage is done in common-artifacts, and for this runtime test, generation of +# In this test, only the runtime test is performed because the test from tf to +# nnpackage is done in common-artifacts, and for this runtime test, generation of # test data is required. And, tcgenerate in ${ARTIFACTS_SRC_PATH}/exclude.lst # means it won't generate test data, which is why below "tcgenerate" macro excludes -# specific opearators from runtime test. -# Also, since circlize and optimize macro included in `exclude.lst` file is only +# specific opearators from runtime test. +# Also, since circlize and optimize macro included in `exclude.lst` file is only # needed in common-artifacts, it has no function here. macro(circlize) endmacro() @@ -72,7 +72,6 @@ set(TEST_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/test.config") add_custom_command( OUTPUT ${TEST_CONFIG} COMMAND ${CMAKE_COMMAND} -E remove -f ${TEST_CONFIG} - COMMAND ${CMAKE_COMMAND} -E echo 'NNPKG_TEST_PATH=\"${NNAS_PROJECT_SOURCE_DIR}/tests/scripts/nnpkg_test.sh\"' >> ${TEST_CONFIG} COMMAND ${CMAKE_COMMAND} -E echo 'RUNTIME_LIBRARY_PATH=\"${NNAS_PROJECT_SOURCE_DIR}/Product/out/\"' >> ${TEST_CONFIG} COMMENT "Generate test configuration" ) diff --git a/compiler/tf2nnpackage-value-remote-test/README.md b/compiler/tf2nnpackage-value-remote-test/README.md index 36436fc6b..65f307b13 100644 --- a/compiler/tf2nnpackage-value-remote-test/README.md +++ b/compiler/tf2nnpackage-value-remote-test/README.md @@ -15,7 +15,7 @@ set(REMOTE_IP "xxx.xxx.xxx.xxx") set(REMOTE_USER "remote_username") ``` - - If any recipe is added, or if `REMOTE_IP` and `REMOTE_USER` is not given, `tf2nnpackage-value-remote-test` will not be created. + - If any recipe is added, or if `REMOTE_IP` and `REMOTE_USER` is not given, `tf2nnpackage-value-remote-test` will not be created. 1. (Optional) ssh authentication - This test uses `ssh` and `scp` commands, and those commands require a password of remote machine whenever they are called. This means that you should enter the password everytime when `ssh` and `scp` require. - This test resolves the problem by using `ssh-copy-id`, which copies the public key of host machine to `authorized_keys` of remote machine. Because of that, this test will ask the password of remote machine only once, at the first time. This is the only user interaction while running this test. @@ -39,7 +39,7 @@ ### Generated Files While Running - All related files(`pb`, `circle`, `h5` ... etc.) are taken from `build/compiler/common-artifacts` folder. -- `nnpkg_test.sh`, runtime products and each nnpackage are sent to `REMOTE_WORKDIR` in remote machine. +- Runtime products and each nnpackage are sent to `REMOTE_WORKDIR` in remote machine. - Each test result is generated in `build/compiler/common-artifacts` with the name `${RECIPE}.log` ### Check Test Result diff --git a/compiler/tf2nnpackage-value-remote-test/testall.sh b/compiler/tf2nnpackage-value-remote-test/testall.sh index f1c9789b3..ca672a3eb 100755 --- a/compiler/tf2nnpackage-value-remote-test/testall.sh +++ b/compiler/tf2nnpackage-value-remote-test/testall.sh @@ -27,15 +27,9 @@ RESULT_CSV="${BINDIR}/Result_${CURRENT_DATETIME}.csv" source "${CONFIG_PATH}" -echo "-- Found nnpkg_test: ${NNPKG_TEST_PATH}" echo "-- Found Runtime library: ${RUNTIME_LIBRARY_PATH}" echo "-- Found workdir: ${WORKDIR}" -if [ -z ${NNPKG_TEST_PATH} ] || [ ! -f ${NNPKG_TEST_PATH} ]; then - echo "nnpkg_test is not found" - exit 4 -fi - # Register remote machine ssh information cat /dev/zero | ssh-keygen -q -N "" ssh-copy-id -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_IP}" @@ -50,9 +44,6 @@ fi ssh "${REMOTE_USER}@${REMOTE_IP}" "mkdir -p ${REMOTE_WORKDIR}/Product/" scp -r "${RUNTIME_LIBRARY_PATH}" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/Product/" -# Send nnpkg_test.sh -scp "${NNPKG_TEST_PATH}" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/" - TESTED=() PASSED=() FAILED=() @@ -84,8 +75,8 @@ while [[ $# -ne 0 ]]; do PREFIX=${PREFIX}.opt ; fi scp -r "${PREFIX}/" "${REMOTE_USER}@${REMOTE_IP}:${REMOTE_WORKDIR}/${PREFIX}/" - ssh "${REMOTE_USER}@${REMOTE_IP}" "cd ${REMOTE_WORKDIR}; ./nnpkg_test.sh ${PREFIX}" - + ssh "${REMOTE_USER}@${REMOTE_IP}" "cd ${REMOTE_WORKDIR}; ./Product/out/test/onert-test nnpkg-test ${PREFIX}" + if [[ $? -eq 0 ]]; then touch "${BINDIR}/${PASSED_TAG}" fi diff --git a/compiler/tf2tfliteV2/README.md b/compiler/tf2tfliteV2/README.md index 13359aab1..0a90735cb 100644 --- a/compiler/tf2tfliteV2/README.md +++ b/compiler/tf2tfliteV2/README.md @@ -47,6 +47,9 @@ python tf2tfliteV2.py \ -h, --help show this help message and exit --v1 Use TensorFlow Lite Converter 1.x --v2 Use TensorFlow Lite Converter 2.x + --graph_def Use graph def file(default) + --saved_model Use saved model + --keras_model Use keras model -i INPUT_PATH, --input_path INPUT_PATH Full filepath of the input file. -o OUTPUT_PATH, --output_path OUTPUT_PATH @@ -55,7 +58,8 @@ python tf2tfliteV2.py \ Names of the input arrays, comma-separated. -s INPUT_SHAPES, --input_shapes INPUT_SHAPES Shapes corresponding to --input_arrays, colon- - separated. + separated.(ex:"1,4,4,3:1,20,20,3") -O OUTPUT_ARRAYS, --output_arrays OUTPUT_ARRAYS Names of the output arrays, comma-separated. + ``` diff --git a/compiler/tf2tfliteV2/tf2tfliteV2.py b/compiler/tf2tfliteV2/tf2tfliteV2.py index 82d6ee232..c51dabde0 100755 --- a/compiler/tf2tfliteV2/tf2tfliteV2.py +++ b/compiler/tf2tfliteV2/tf2tfliteV2.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved # Copyright (C) 2018 The TensorFlow Authors @@ -48,6 +48,27 @@ def _get_parser(): converter_version.add_argument( "--v2", action="store_true", help="Use TensorFlow Lite Converter 2.x") + # Input model format + model_format_arg = parser.add_mutually_exclusive_group() + model_format_arg.add_argument( + "--graph_def", + action="store_const", + dest="model_format", + const="graph_def", + help="Use graph def file(default)") + model_format_arg.add_argument( + "--saved_model", + action="store_const", + dest="model_format", + const="saved_model", + help="Use saved model") + model_format_arg.add_argument( + "--keras_model", + action="store_const", + dest="model_format", + const="keras_model", + help="Use keras model") + # Input and output path. parser.add_argument( "-i", @@ -83,6 +104,8 @@ def _get_parser(): help="Names of the output arrays, comma-separated.", required=True) + # Set default value + parser.set_defaults(model_format="graph_def") return parser @@ -122,17 +145,26 @@ def _parse_array(arrays, type_fn=str): def _v1_convert(flags): - input_shapes = None - if flags.input_shapes: - input_arrays = _parse_array(flags.input_arrays) - input_shapes_list = [ - _parse_array(shape, type_fn=int) for shape in flags.input_shapes.split(":") - ] - input_shapes = dict(list(zip(input_arrays, input_shapes_list))) - - converter = tf.compat.v1.lite.TFLiteConverter.from_frozen_graph( - flags.input_path, _parse_array(flags.input_arrays), - _parse_array(flags.output_arrays), input_shapes) + if flags.model_format == "graph_def": + input_shapes = None + if flags.input_shapes: + input_arrays = _parse_array(flags.input_arrays) + input_shapes_list = [ + _parse_array(shape, type_fn=int) + for shape in flags.input_shapes.split(":") + ] + input_shapes = dict(list(zip(input_arrays, input_shapes_list))) + + converter = tf.compat.v1.lite.TFLiteConverter.from_frozen_graph( + flags.input_path, _parse_array(flags.input_arrays), + _parse_array(flags.output_arrays), input_shapes) + + if flags.model_format == "saved_model": + converter = tf.compat.v1.lite.TFLiteConverter.from_saved_model(flags.input_path) + + if flags.model_format == "keras_model": + converter = tf.compat.v1.lite.TFLiteConverter.from_keras_model_file( + flags.input_path) converter.allow_custom_ops = True @@ -141,27 +173,35 @@ def _v1_convert(flags): def _v2_convert(flags): - file_content = open(flags.input_path, 'rb').read() - try: - graph_def = tf.compat.v1.GraphDef() - graph_def.ParseFromString(file_content) - except (_text_format.ParseError, DecodeError): + if flags.model_format == "graph_def": + file_content = open(flags.input_path, 'rb').read() try: - _text_format.Merge(file_content, graph_def) + graph_def = tf.compat.v1.GraphDef() + graph_def.ParseFromString(file_content) except (_text_format.ParseError, DecodeError): - raise IOError("Unable to parse input file '{}'.".format(flags.input_path)) - - wrap_func = wrap_frozen_graph( - graph_def, - inputs=[ - _str + ":0" if len(_str.split(":")) == 1 else _str - for _str in _parse_array(flags.input_arrays) - ], - outputs=[ - _str + ":0" if len(_str.split(":")) == 1 else _str - for _str in _parse_array(flags.output_arrays) - ]) - converter = tf.lite.TFLiteConverter.from_concrete_functions([wrap_func]) + try: + _text_format.Merge(file_content, graph_def) + except (_text_format.ParseError, DecodeError): + raise IOError("Unable to parse input file '{}'.".format(flags.input_path)) + + wrap_func = wrap_frozen_graph( + graph_def, + inputs=[ + _str + ":0" if len(_str.split(":")) == 1 else _str + for _str in _parse_array(flags.input_arrays) + ], + outputs=[ + _str + ":0" if len(_str.split(":")) == 1 else _str + for _str in _parse_array(flags.output_arrays) + ]) + converter = tf.lite.TFLiteConverter.from_concrete_functions([wrap_func]) + + if flags.model_format == "saved_model": + converter = tf.lite.TFLiteConverter.from_saved_model(flags.input_path) + + if flags.model_format == "keras_model": + keras_model = tf.keras.models.load_model(flags.input_path) + converter = tf.lite.TFLiteConverter.from_keras_model(keras_model) converter.allow_custom_ops = True converter.experimental_new_converter = True diff --git a/compiler/tfl-verify/CMakeLists.txt b/compiler/tfl-verify/CMakeLists.txt index d33059fde..4421a4660 100644 --- a/compiler/tfl-verify/CMakeLists.txt +++ b/compiler/tfl-verify/CMakeLists.txt @@ -6,6 +6,7 @@ file(GLOB_RECURSE SOURCES "src/*.cpp") add_executable(tfl-verify ${SOURCES}) target_include_directories(tfl-verify PRIVATE src) +target_link_libraries(tfl-verify arser) target_link_libraries(tfl-verify foder) target_link_libraries(tfl-verify mio_tflite) target_link_libraries(tfl-verify safemain) diff --git a/compiler/tfl-verify/requires.cmake b/compiler/tfl-verify/requires.cmake index ed6b84db5..79503f325 100644 --- a/compiler/tfl-verify/requires.cmake +++ b/compiler/tfl-verify/requires.cmake @@ -1,3 +1,4 @@ +require("arser") require("foder") require("mio-tflite") require("safemain") diff --git a/compiler/tfl-verify/src/Driver.cpp b/compiler/tfl-verify/src/Driver.cpp index 81f6d5489..6d1897607 100644 --- a/compiler/tfl-verify/src/Driver.cpp +++ b/compiler/tfl-verify/src/Driver.cpp @@ -16,22 +16,31 @@ #include "VerifyFlatBuffers.h" +#include <arser/arser.h> + #include <iostream> #include <memory> #include <string> int entry(int argc, char **argv) { - if (argc != 2) + arser::Arser arser; + arser.add_argument("tflite").type(arser::DataType::STR).help("TFLite file path to verify"); + + try { - std::cerr << "ERROR: Failed to parse arguments" << std::endl; - std::cerr << std::endl; - std::cerr << "USAGE: " << argv[0] << " [tflite]" << std::endl; + arser.parse(argc, argv); + } + catch (const std::runtime_error &err) + { + std::cout << err.what() << std::endl; + std::cout << arser; return 255; } + auto verifier = std::make_unique<VerifyFlatbuffers>(); - std::string model_file = argv[argc - 1]; + std::string model_file = arser.get<std::string>("tflite"); std::cout << "[ RUN ] Check " << model_file << std::endl; diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 932a649c5..692ce48c1 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -413,6 +413,7 @@ template <typename T> void cook_graph(const T &graph, CookParams &cp) quant_builder.add_min(quant_min); quant_builder.add_scale(quant_scale); quant_builder.add_zero_point(quant_zero_point); + quant_builder.add_quantized_dimension(quant.quantized_dimension()); // Update QuantizationParameters Index quant_index = quant_builder.Finish(); diff --git a/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.cpp b/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.cpp new file mode 100644 index 000000000..eadd62cc6 --- /dev/null +++ b/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.cpp @@ -0,0 +1,30 @@ +/* + * 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 "NonMaxSuppressionV4.h" + +flatbuffers::Offset<void> NonMaxSuppressionV4Chef::value(flatbuffers::FlatBufferBuilder &fbb) const +{ + tflite::NonMaxSuppressionV4OptionsBuilder options_builder{fbb}; + + return options_builder.Finish().Union(); +} + +std::unique_ptr<OpChef> +NonMaxSuppressionV4ChefFactory::create(const tflchef::Operation *operation) const +{ + return std::unique_ptr<OpChef>{new NonMaxSuppressionV4Chef{operation}}; +} diff --git a/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.h b/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.h new file mode 100644 index 000000000..a8e783d53 --- /dev/null +++ b/compiler/tflchef/core/src/Op/NonMaxSuppressionV4.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_NON_MAX_SUPPRESSION_V4_H__ +#define __OP_NON_MAX_SUPPRESSION_V4_H__ + +#include "OpChef.h" + +class NonMaxSuppressionV4Chef final : public OpChef +{ +public: + explicit NonMaxSuppressionV4Chef(const tflchef::Operation *operation) : _operation{operation} + { + // DO NOTHING + } + +public: + tflite::BuiltinOperator code(void) const override + { + return tflite::BuiltinOperator_NON_MAX_SUPPRESSION_V4; + } + + tflite::BuiltinOptions type(void) const override + { + return tflite::BuiltinOptions_NonMaxSuppressionV4Options; + } + + flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override; + +private: + const tflchef::Operation *_operation; +}; + +struct NonMaxSuppressionV4ChefFactory final : public OpChefFactory +{ + std::unique_ptr<OpChef> create(const tflchef::Operation *operation) const override; +}; + +#endif // __OP_NON_MAX_SUPPRESSION_V4_H__ diff --git a/compiler/tflchef/core/src/Op/PadV2.cpp b/compiler/tflchef/core/src/Op/PadV2.cpp new file mode 100644 index 000000000..bfa2289e5 --- /dev/null +++ b/compiler/tflchef/core/src/Op/PadV2.cpp @@ -0,0 +1,28 @@ +/* + * 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 "PadV2.h" + +flatbuffers::Offset<void> PadV2Chef::value(flatbuffers::FlatBufferBuilder &fbb) const +{ + tflite::PadV2OptionsBuilder padv2_options_builder{fbb}; + return padv2_options_builder.Finish().Union(); +} + +std::unique_ptr<OpChef> PadV2ChefFactory::create(const tflchef::Operation *operation) const +{ + return std::unique_ptr<OpChef>{new PadV2Chef{operation}}; +} diff --git a/compiler/tflchef/core/src/Op/PadV2.h b/compiler/tflchef/core/src/Op/PadV2.h new file mode 100644 index 000000000..d15532390 --- /dev/null +++ b/compiler/tflchef/core/src/Op/PadV2.h @@ -0,0 +1,46 @@ +/* + * 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_PADV2_H__ +#define __OP_PADV2_H__ + +#include "OpChef.h" + +class PadV2Chef final : public OpChef +{ +public: + explicit PadV2Chef(const tflchef::Operation *operation) : _operation{operation} + { + // DO NOTHING + } + +public: + tflite::BuiltinOperator code(void) const override { return tflite::BuiltinOperator_PADV2; } + + tflite::BuiltinOptions type(void) const override { return tflite::BuiltinOptions_PadV2Options; } + + flatbuffers::Offset<void> value(flatbuffers::FlatBufferBuilder &fbb) const override; + +private: + const tflchef::Operation *_operation; +}; + +struct PadV2ChefFactory final : public OpChefFactory +{ + std::unique_ptr<OpChef> create(const tflchef::Operation *operation) const override; +}; + +#endif // __OP_PADV2_H__ diff --git a/compiler/tflchef/core/src/OpChef.def b/compiler/tflchef/core/src/OpChef.def index 263725a24..244186265 100644 --- a/compiler/tflchef/core/src/OpChef.def +++ b/compiler/tflchef/core/src/OpChef.def @@ -55,10 +55,12 @@ OP_CHEF(Minimum, MinimumChefFactory) OP_CHEF(MirrorPad, MirrorPadChefFactory) OP_CHEF(Mul, MulChefFactory) OP_CHEF(Neg, NegChefFactory) +OP_CHEF(NonMaxSuppressionV4, NonMaxSuppressionV4ChefFactory) OP_CHEF(NotEqual, NotEqualChefFactory) OP_CHEF(OneHot, OneHotChefFactory) OP_CHEF(Pack, PackChefFactory) OP_CHEF(Pad, PadChefFactory) +OP_CHEF(PadV2, PadV2ChefFactory) OP_CHEF(Pow, PowChefFactory) OP_CHEF(PRelu, PReluChefFactory) OP_CHEF(Range, RangeChefFactory) diff --git a/compiler/tflchef/core/src/OpChefs.h b/compiler/tflchef/core/src/OpChefs.h index 55c37ebfb..5b2e89bd9 100644 --- a/compiler/tflchef/core/src/OpChefs.h +++ b/compiler/tflchef/core/src/OpChefs.h @@ -68,10 +68,12 @@ #include "Op/MirrorPad.h" #include "Op/Mul.h" #include "Op/Neg.h" +#include "Op/NonMaxSuppressionV4.h" #include "Op/NotEqual.h" #include "Op/OneHot.h" #include "Op/Pack.h" #include "Op/Pad.h" +#include "Op/PadV2.h" #include "Op/Pow.h" #include "Op/PRelu.h" #include "Op/Range.h" diff --git a/compiler/tflchef/proto/tflchef.proto b/compiler/tflchef/proto/tflchef.proto index 792503bc9..70b966ec3 100644 --- a/compiler/tflchef/proto/tflchef.proto +++ b/compiler/tflchef/proto/tflchef.proto @@ -35,6 +35,7 @@ message TensorQuantization { repeated float max = 2; repeated float scale = 3; repeated int64 zero_point = 4; + optional int32 quantized_dimension = 5 [default = 0]; } message Operand { @@ -153,6 +154,10 @@ message PadOptions { // None } +message PadV2Options { + // None +} + message MirrorPadOptions { optional MirrorPadMode mode = 1 [default = REFLECT]; } @@ -362,6 +367,10 @@ message GatherNdOptions { // None } +message NonMaxSuppressionV4Options { + // None +} + message NotEqualOptions { // None } @@ -507,7 +516,7 @@ message Operation { optional LogSoftmaxOptions log_softmax_options = 168; // DequantizeOptions 169 optional NegOptions neg_options = 170; - // PadV2Options 171 + optional PadV2Options padv2_options = 171; optional LessEqualOptions lessequal_options = 172; optional SliceOptions slice_options = 173; optional TransposeConvOptions transpose_conv_options = 174; @@ -534,7 +543,7 @@ message Operation { optional MatrixSetDiagOptions matrix_set_diag_options = 195; // HardSwishOptions 196 optional DepthToSpaceOptions depth_to_space_options = 197; - // NonMaxSuppressionV4Options 198 + optional NonMaxSuppressionV4Options non_max_suppression_v4_options = 198; // NonMaxSuppressionV5Options 199 optional ScatterNdOptions scatter_nd_options = 200; optional NotEqualOptions notequal_options = 201; diff --git a/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.cpp b/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.cpp new file mode 100644 index 000000000..ad9921970 --- /dev/null +++ b/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.cpp @@ -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. + */ + +#include "NonMaxSuppressionV4.h" + +#include "Convert.h" +#include "FillerHelper.h" + +namespace tflchef +{ + +void TFliteOpNonMaxSuppressionV4::filler(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const +{ + const auto &inputs = *op->inputs(); + + const tflite::Tensor *max_output_size_tensor = import->tensors()->Get(inputs[2]); + assert(max_output_size_tensor->type() == tflite::TensorType::TensorType_INT32); + + const tflite::Tensor *iou_threshold_tensor = import->tensors()->Get(inputs[3]); + assert(iou_threshold_tensor->type() == tflite::TensorType::TensorType_FLOAT32); + + const tflite::Tensor *score_threshold_tensor = import->tensors()->Get(inputs[4]); + assert(score_threshold_tensor->type() == tflite::TensorType::TensorType_FLOAT32); + + for (int32_t index = 2; index < 5; ++index) + { + fill_tensor_to_import(index, import); + } +} + +tflchef::Operation *TFliteOpNonMaxSuppressionV4::build(const tflite::Operator *op, + TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const +{ + auto operation = model_recipe->add_operation(); + + operation->set_type("NonMaxSuppressionV4"); + + return operation; +} + +} // namespace tflchef diff --git a/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.h b/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.h new file mode 100644 index 000000000..114a2ad2f --- /dev/null +++ b/compiler/tflchef/tflite/src/Op/NonMaxSuppressionV4.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 __TFLITE_OP_NON_MAX_SUPPRESSION_V4_H__ +#define __TFLITE_OP_NON_MAX_SUPPRESSION_V4_H__ + +#include "TFliteOpChef.h" + +namespace tflchef +{ + +/** + * @brief tflchef operator builder for NON_MAX_SUPPRESSION_V4 + */ +class TFliteOpNonMaxSuppressionV4 : public TFliteOpChef +{ +public: + void filler(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const override; + tflchef::Operation *build(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const override; +}; + +} // namespace tflchef + +#endif // __TFLITE_OP_NON_MAX_SUPPRESSION_V4_H__ diff --git a/compiler/tflchef/tflite/src/Op/PadV2.cpp b/compiler/tflchef/tflite/src/Op/PadV2.cpp new file mode 100644 index 000000000..0b1c9f3b2 --- /dev/null +++ b/compiler/tflchef/tflite/src/Op/PadV2.cpp @@ -0,0 +1,42 @@ +/* + * 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 "PadV2.h" + +#include "FillerHelper.h" + +namespace tflchef +{ + +void TFliteOpPadV2::filler(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const +{ + // Filler for paddings and constant_values + fill_tensor_to_import(1, import); + fill_tensor_to_import(2, import); +} + +tflchef::Operation *TFliteOpPadV2::build(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const +{ + auto operation = model_recipe->add_operation(); + + operation->set_type("PadV2"); + + return operation; +} + +} // namespace tflchef diff --git a/compiler/tflchef/tflite/src/Op/PadV2.h b/compiler/tflchef/tflite/src/Op/PadV2.h new file mode 100644 index 000000000..3aa474b92 --- /dev/null +++ b/compiler/tflchef/tflite/src/Op/PadV2.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 __TFLITE_OP_PADV2_H__ +#define __TFLITE_OP_PADV2_H__ + +#include "TFliteOpChef.h" + +namespace tflchef +{ + +/** + * @brief tflchef operator builder for PADV2 + */ +class TFliteOpPadV2 : public TFliteOpChef +{ +public: + void filler(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const override; + tflchef::Operation *build(const tflite::Operator *op, TFliteImport *import, + tflchef::ModelRecipe *model_recipe) const override; +}; + +} // namespace tflchef + +#endif // __TFLITE_OP_PADV2_H__ diff --git a/compiler/tflchef/tflite/src/Op/TransposeConv.cpp b/compiler/tflchef/tflite/src/Op/TransposeConv.cpp index 7e772b954..4e7adf6c6 100644 --- a/compiler/tflchef/tflite/src/Op/TransposeConv.cpp +++ b/compiler/tflchef/tflite/src/Op/TransposeConv.cpp @@ -35,6 +35,10 @@ void TFliteOpTransposeConv::filler(const tflite::Operator *op, TFliteImport *imp auto vec = extract_buffer<int32_t>(buffer); import->set_tensor_filler(inputs[0], vec); } + + // filter + const tflite::Tensor *filter_tensor = import->tensors()->Get(inputs[1]); + import->set_tensor_filler(inputs[1]); } tflchef::Operation *TFliteOpTransposeConv::build(const tflite::Operator *op, TFliteImport *import, diff --git a/compiler/tflchef/tflite/src/RecipeChef.cpp b/compiler/tflchef/tflite/src/RecipeChef.cpp index db62d0e40..088961c1c 100644 --- a/compiler/tflchef/tflite/src/RecipeChef.cpp +++ b/compiler/tflchef/tflite/src/RecipeChef.cpp @@ -184,6 +184,8 @@ std::unique_ptr<ModelRecipe> generate_recipe(const tflite::Model *model) for (uint32_t idx = 0; idx < quant->zero_point()->size(); ++idx) chef_quant->add_zero_point(quant->zero_point()->Get(idx)); } + tflchef::TensorQuantization *chef_quant = operand->mutable_quant(); + chef_quant->set_quantized_dimension(quant->quantized_dimension()); } } diff --git a/compiler/tflchef/tflite/src/TFliteOpChefs.h b/compiler/tflchef/tflite/src/TFliteOpChefs.h index ad52af1c2..de14e37d1 100644 --- a/compiler/tflchef/tflite/src/TFliteOpChefs.h +++ b/compiler/tflchef/tflite/src/TFliteOpChefs.h @@ -68,10 +68,12 @@ #include "Op/MirrorPad.h" #include "Op/Mul.h" #include "Op/Neg.h" +#include "Op/NonMaxSuppressionV4.h" #include "Op/NotEqual.h" #include "Op/OneHot.h" #include "Op/Pack.h" #include "Op/Pad.h" +#include "Op/PadV2.h" #include "Op/Pow.h" #include "Op/PRelu.h" #include "Op/Range.h" diff --git a/compiler/tflchef/tflite/src/TFliteOpRegistry.h b/compiler/tflchef/tflite/src/TFliteOpRegistry.h index 0a44b3f06..8d33007be 100644 --- a/compiler/tflchef/tflite/src/TFliteOpRegistry.h +++ b/compiler/tflchef/tflite/src/TFliteOpRegistry.h @@ -105,10 +105,12 @@ private: REG_TFL_OP(MIRROR_PAD, TFliteOpMirrorPad); REG_TFL_OP(MUL, TFliteOpMul); REG_TFL_OP(NEG, TFliteOpNeg); + REG_TFL_OP(NON_MAX_SUPPRESSION_V4, TFliteOpNonMaxSuppressionV4); REG_TFL_OP(NOT_EQUAL, TFliteOpNotEqual); REG_TFL_OP(ONE_HOT, TFliteOpOneHot); REG_TFL_OP(PACK, TFliteOpPack); REG_TFL_OP(PAD, TFliteOpPad); + REG_TFL_OP(PADV2, TFliteOpPadV2); REG_TFL_OP(POW, TFliteOpPow); REG_TFL_OP(PRELU, TFliteOpPRelu); REG_TFL_OP(RANGE, TFliteOpRange); diff --git a/compiler/tflchef/tools/file/Driver.cpp b/compiler/tflchef/tools/file/Driver.cpp index cecfeeb3e..46e5b5583 100644 --- a/compiler/tflchef/tools/file/Driver.cpp +++ b/compiler/tflchef/tools/file/Driver.cpp @@ -41,7 +41,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } int32_t model_version = 1; diff --git a/compiler/tflchef/tools/reverse/Driver.cpp b/compiler/tflchef/tools/reverse/Driver.cpp index 1116dec34..4d795a3d0 100644 --- a/compiler/tflchef/tools/reverse/Driver.cpp +++ b/compiler/tflchef/tools/reverse/Driver.cpp @@ -38,7 +38,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } std::string tflite_path = arser.get<std::string>("tflite"); diff --git a/compiler/tfldump/driver/Driver.cpp b/compiler/tfldump/driver/Driver.cpp index 3961d2f17..38c9c062f 100644 --- a/compiler/tfldump/driver/Driver.cpp +++ b/compiler/tfldump/driver/Driver.cpp @@ -33,7 +33,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << '\n'; std::cout << arser; - return 0; + return 255; } std::string tflite_path = arser.get<std::string>("tflite"); diff --git a/compiler/tfldump/src/OpPrinter.cpp b/compiler/tfldump/src/OpPrinter.cpp index 9fc1a6456..df027c3e3 100644 --- a/compiler/tfldump/src/OpPrinter.cpp +++ b/compiler/tfldump/src/OpPrinter.cpp @@ -676,6 +676,7 @@ OpPrinterRegistry::OpPrinterRegistry() _op_map[tflite::BuiltinOperator_MAX_POOL_2D] = make_unique<Pool2DPrinter>(); _op_map[tflite::BuiltinOperator_MIRROR_PAD] = make_unique<MirrorPadPrinter>(); _op_map[tflite::BuiltinOperator_MUL] = make_unique<MulPrinter>(); + // There is no Option for NON_MAX_SUPPRESSION_V4 _op_map[tflite::BuiltinOperator_ONE_HOT] = make_unique<OneHotPrinter>(); _op_map[tflite::BuiltinOperator_PACK] = make_unique<PackPrinter>(); // There is no Option for PAD diff --git a/compiler/tflite2circle/CMakeLists.txt b/compiler/tflite2circle/CMakeLists.txt index a0a2e026b..b1d1f6149 100644 --- a/compiler/tflite2circle/CMakeLists.txt +++ b/compiler/tflite2circle/CMakeLists.txt @@ -14,5 +14,6 @@ target_link_libraries(tflite2circle arser) target_link_libraries(tflite2circle safemain) target_link_libraries(tflite2circle mio_tflite) target_link_libraries(tflite2circle mio_circle) +target_link_libraries(tflite2circle vconone) install(TARGETS tflite2circle DESTINATION bin) diff --git a/compiler/tflite2circle/driver/Driver.cpp b/compiler/tflite2circle/driver/Driver.cpp index 67b8e33bc..2f11e0a13 100644 --- a/compiler/tflite2circle/driver/Driver.cpp +++ b/compiler/tflite2circle/driver/Driver.cpp @@ -24,10 +24,25 @@ #include "CircleModel.h" #include "TFLModel.h" +#include <vconone/vconone.h> + +void print_version(void) +{ + std::cout << "tflite2circle version " << vconone::get_string() << std::endl; + std::cout << vconone::get_copyright() << std::endl; +} + int entry(int argc, char **argv) { arser::Arser arser{"tflite2circle is a Tensorflow lite to circle model converter"}; + arser.add_argument("--version") + .nargs(0) + .required(false) + .default_value(false) + .help("Show version information and exit") + .exit_with(print_version); + arser.add_argument("tflite") .nargs(1) .type(arser::DataType::STR) @@ -42,7 +57,7 @@ int entry(int argc, char **argv) { std::cout << err.what() << std::endl; std::cout << arser; - return 0; + return 255; } std::string tfl_path = arser.get<std::string>("tflite"); diff --git a/compiler/tflite2circle/requires.cmake b/compiler/tflite2circle/requires.cmake index ff19b7491..837c287b6 100644 --- a/compiler/tflite2circle/requires.cmake +++ b/compiler/tflite2circle/requires.cmake @@ -2,3 +2,4 @@ require("arser") require("mio-tflite") require("mio-circle") require("safemain") +require("vconone") diff --git a/compiler/tflite2circle/src/BuildBuiltinOptions.h b/compiler/tflite2circle/src/BuildBuiltinOptions.h index 159a8af97..00b3de943 100644 --- a/compiler/tflite2circle/src/BuildBuiltinOptions.h +++ b/compiler/tflite2circle/src/BuildBuiltinOptions.h @@ -62,10 +62,12 @@ #include "BuildBuiltinOptions/MirrorPadOptions.h" #include "BuildBuiltinOptions/MulOptions.h" #include "BuildBuiltinOptions/NegOptions.h" +#include "BuildBuiltinOptions/NonMaxSuppressionV4Options.h" #include "BuildBuiltinOptions/NotEqualOptions.h" #include "BuildBuiltinOptions/OneHotOptions.h" #include "BuildBuiltinOptions/PackOptions.h" #include "BuildBuiltinOptions/PadOptions.h" +#include "BuildBuiltinOptions/PadV2Options.h" #include "BuildBuiltinOptions/RangeOptions.h" #include "BuildBuiltinOptions/Pool2DOptions.h" #include "BuildBuiltinOptions/PowOptions.h" diff --git a/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.cpp b/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.cpp new file mode 100644 index 000000000..1a39f503b --- /dev/null +++ b/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.cpp @@ -0,0 +1,30 @@ +/* + * 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 "NonMaxSuppressionV4Options.h" + +namespace tflite2circle +{ + +flatbuffers::Offset<circle::NonMaxSuppressionV4Options> +build_circle_NonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &fb, + const tflite::Operator *) +{ + circle::NonMaxSuppressionV4OptionsBuilder builtin_options_builder{fb}; + return builtin_options_builder.Finish(); +} + +} // namespace tflite2circle diff --git a/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.h b/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.h new file mode 100644 index 000000000..6073142a8 --- /dev/null +++ b/compiler/tflite2circle/src/BuildBuiltinOptions/NonMaxSuppressionV4Options.h @@ -0,0 +1,32 @@ +/* + * 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 __BBO_NON_MAX_SUPPRESSION_V4_OPTIONS_H__ +#define __BBO_NON_MAX_SUPPRESSION_V4_OPTIONS_H__ + +#include <mio/tflite/schema_generated.h> +#include <mio/circle/schema_generated.h> + +namespace tflite2circle +{ + +flatbuffers::Offset<circle::NonMaxSuppressionV4Options> +build_circle_NonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &fb, + const tflite::Operator *op); + +} // namespace tflite2circle + +#endif // __BBO_NON_MAX_SUPPRESSION_V4_OPTIONS_H__ diff --git a/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.cpp b/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.cpp new file mode 100644 index 000000000..6636634a3 --- /dev/null +++ b/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.cpp @@ -0,0 +1,29 @@ +/* + * 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 "PadV2Options.h" + +namespace tflite2circle +{ + +flatbuffers::Offset<circle::PadV2Options> +build_circle_PadV2Options(flatbuffers::FlatBufferBuilder &fb, const tflite::Operator *op) +{ + circle::PadV2OptionsBuilder builtin_options_builder{fb}; + return builtin_options_builder.Finish(); +} + +} // namespace tflite2circle diff --git a/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.h b/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.h new file mode 100644 index 000000000..36a2c82e8 --- /dev/null +++ b/compiler/tflite2circle/src/BuildBuiltinOptions/PadV2Options.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. + */ + +#ifndef __BBO_PADV2_OPTIONS_H__ +#define __BBO_PADV2_OPTIONS_H__ + +#include <mio/tflite/schema_generated.h> +#include <mio/circle/schema_generated.h> + +namespace tflite2circle +{ + +flatbuffers::Offset<circle::PadV2Options> +build_circle_PadV2Options(flatbuffers::FlatBufferBuilder &fb, const tflite::Operator *op); + +} // namespace tflite2circle + +#endif // __BBO_PADV2_OPTIONS_H__ diff --git a/compiler/tflite2circle/src/TFLBuiltinOptions.lst b/compiler/tflite2circle/src/TFLBuiltinOptions.lst index 3ef9f1575..a2a14538e 100644 --- a/compiler/tflite2circle/src/TFLBuiltinOptions.lst +++ b/compiler/tflite2circle/src/TFLBuiltinOptions.lst @@ -26,6 +26,7 @@ TFL_BUILTIN_OPTIONS(SpaceToDepthOptions) //TFL_BUILTIN_OPTIONS(EmbeddingLookupSparseOptions) TFL_BUILTIN_OPTIONS(MulOptions) TFL_BUILTIN_OPTIONS(PadOptions) +TFL_BUILTIN_OPTIONS(PadV2Options) TFL_BUILTIN_OPTIONS(GatherOptions) TFL_BUILTIN_OPTIONS(BatchToSpaceNDOptions) TFL_BUILTIN_OPTIONS(SpaceToBatchNDOptions) @@ -99,7 +100,7 @@ TFL_BUILTIN_OPTIONS(MatrixSetDiagOptions) TFL_BUILTIN_OPTIONS(IfOptions) TFL_BUILTIN_OPTIONS(WhileOptions) TFL_BUILTIN_OPTIONS(DepthToSpaceOptions) -//TFL_BUILTIN_OPTIONS(NonMaxSuppressionV4Options) +TFL_BUILTIN_OPTIONS(NonMaxSuppressionV4Options) //TFL_BUILTIN_OPTIONS(NonMaxSuppressionV5Options) TFL_BUILTIN_OPTIONS(RankOptions) TFL_BUILTIN_OPTIONS(ScatterNdOptions) diff --git a/compiler/vconone/CMakeLists.txt b/compiler/vconone/CMakeLists.txt new file mode 100644 index 000000000..b8cb79331 --- /dev/null +++ b/compiler/vconone/CMakeLists.txt @@ -0,0 +1,31 @@ +if (NOT VCONONE_VERSION) + set(VCONONE_VERSION 0x0000000000080001) + # NOTE order is [build patch minor major] + # if VCONONE_VERSION is set with -D option, it will be cached + # you may have to remove cache file if you remove -D option +endif() + +configure_file(version_cfg.h.in version_cfg.h @ONLY) + +set(DRIVER "driver/driver.cpp") + +file(GLOB_RECURSE SOURCES "src/*.cpp") +file(GLOB_RECURSE TESTS "src/*.test.cpp") +list(REMOVE_ITEM SOURCES ${TESTS}) + +add_library(vconone STATIC ${SOURCES}) +target_include_directories(vconone PUBLIC include) +target_include_directories(vconone PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + +add_executable(one-version ${DRIVER}) +target_link_libraries(one-version vconone) +install(TARGETS one-version DESTINATION bin) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +nnas_find_package(GTest REQUIRED) + +GTest_AddTest(vconone_test ${TESTS}) +target_link_libraries(vconone_test vconone) diff --git a/compiler/vconone/README.md b/compiler/vconone/README.md new file mode 100644 index 000000000..c08dd63d3 --- /dev/null +++ b/compiler/vconone/README.md @@ -0,0 +1,14 @@ +# vconone + +_vconone_ provides version number and strings for one-* commands and command +line tools + +# Revise version number + +To revise version number, update `VCONONE_VERSION` in `CmakeLists.txt` +or give `-DVCONONE_VERSION=0x0000000100080001` at cmake configure step. + +Number given is four numbers `build`, `patch`, `minor` and `major` in order for +each 16bit integers. `build` is not used for now. + +`0x0000000100080001` version is interpretered as `1.8.1` diff --git a/compiler/vconone/driver/driver.cpp b/compiler/vconone/driver/driver.cpp new file mode 100644 index 000000000..12bd0eef2 --- /dev/null +++ b/compiler/vconone/driver/driver.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 <vconone/vconone.h> + +#include <string> +#include <iostream> + +int main(int argc, char *argv[]) +{ + auto str = vconone::get_string(); + if (argc >= 2) + { + for (int c = 1; c < argc; ++c) + std::cout << argv[c] << " "; + std::cout << "version " << str << std::endl; + std::cout << vconone::get_copyright() << std::endl; + } + else + std::cout << str; + + return 0; +} diff --git a/compiler/vconone/include/vconone/vconone.h b/compiler/vconone/include/vconone/vconone.h new file mode 100644 index 000000000..a6a1998a5 --- /dev/null +++ b/compiler/vconone/include/vconone/vconone.h @@ -0,0 +1,61 @@ +/* + * 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 __VCON_ONE_H__ +#define __VCON_ONE_H__ + +#include <cstdint> +#include <string> + +namespace vconone +{ + +struct four +{ + uint16_t major; + uint16_t minor; + uint16_t patch; + uint16_t build; // build is not used for now +}; + +union version { + uint64_t v; + four f; +}; + +/** + * @brief get_number will return version union structure + */ +version get_number(void); + +/** + * @brief get_string will return string of major.minor.patch (without build) + */ +std::string get_string(void); + +/** + * @brief get_string4 will return string of major.minor.patch.build + */ +std::string get_string4(void); + +/** + * @brief get_copyright will return copyright string + */ +std::string get_copyright(void); + +} // namespace vconone + +#endif // __VCON_ONE_H__ diff --git a/compiler/vconone/src/version.cpp b/compiler/vconone/src/version.cpp new file mode 100644 index 000000000..9b693c621 --- /dev/null +++ b/compiler/vconone/src/version.cpp @@ -0,0 +1,63 @@ +/* + * 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 "vconone/vconone.h" + +#include "version_cfg.h" + +#include <sstream> + +namespace vconone +{ + +version get_number(void) +{ + version v; + v.v = VCONONE_VERSION; + return v; +} + +std::string get_string4(void) +{ + std::ostringstream ss; + + auto v = get_number(); + ss << unsigned(v.f.major) << "." << unsigned(v.f.minor) << "." << unsigned(v.f.patch) << "." + << unsigned(v.f.build); + + return ss.str(); +} + +std::string get_string(void) +{ + std::ostringstream ss; + + auto v = get_number(); + ss << unsigned(v.f.major) << "." << unsigned(v.f.minor) << "." << unsigned(v.f.patch); + + return ss.str(); +} + +std::string get_copyright(void) +{ + std::string str; + str = "Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved\r\n"; + str += "Licensed under the Apache License, Version 2.0\r\n"; + str += "https://github.com/Samsung/ONE"; + return str; +} + +} // namespace vconone diff --git a/compiler/vconone/src/version.test.cpp b/compiler/vconone/src/version.test.cpp new file mode 100644 index 000000000..35a0647c1 --- /dev/null +++ b/compiler/vconone/src/version.test.cpp @@ -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. + */ + +#include <vconone/vconone.h> + +#include <gtest/gtest.h> + +TEST(vconone, version_number) +{ + auto v = vconone::get_number(); + + ASSERT_NE(0x0000000000000000ULL, v.v); +} + +TEST(vconone, version_string) +{ + auto str = vconone::get_string(); + + ASSERT_NE("..", str); + ASSERT_NE("", str); +} + +TEST(vconone, version_string4) +{ + auto str = vconone::get_string4(); + + ASSERT_NE("...", str); + ASSERT_NE("", str); +} + +TEST(vconone, copyright) +{ + auto str = vconone::get_copyright(); + + ASSERT_NE("", str); +} diff --git a/compiler/vconone/version_cfg.h.in b/compiler/vconone/version_cfg.h.in new file mode 100644 index 000000000..aa3ad9e70 --- /dev/null +++ b/compiler/vconone/version_cfg.h.in @@ -0,0 +1,22 @@ +/* + * 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 __VCON_ONE_VERSION_CFG_H__ +#define __VCON_ONE_VERSION_CFG_H__ + +#define VCONONE_VERSION @VCONONE_VERSION@ULL + +#endif // __VCON_ONE_VERSION_CFG_H__ |