From b6975f9d2afe154834dda913a82c513edcfe0583 Mon Sep 17 00:00:00 2001 From: Michael Bartling Date: Tue, 12 May 2020 18:30:03 -0500 Subject: [PATCH 1/7] Add BatchNorm, Mul, Add, Sub, Mean, and more ops --- .../backend/utensor/_graph_lower/_op_lower.py | 2 + .../rearch/_operators/_impls.py | 153 ++++++++++++ .../utensor/snippets/rearch/_snippets.py | 26 +++ utensor_cgen/frontend/tflite.py | 218 +++++++++++++++++- utensor_cgen/legalizer/tflite.py | 6 + 5 files changed, 395 insertions(+), 10 deletions(-) diff --git a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py index 7d0ed1e2..3facc56f 100644 --- a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py +++ b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py @@ -41,6 +41,8 @@ def __init__(self, config): class OptypeRenameManager(object): NAME_MAP = { 'Add': 'AddOperator', + 'Mul': 'MulOperator', + 'Sub': 'SubOperator', 'Conv2D': 'ConvOperator', 'MatMul': 'MatrixMultOperator' } diff --git a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py index 69ef421b..49fa25a0 100644 --- a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py +++ b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py @@ -405,6 +405,39 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): tensor_var_map=tensor_var_map, ) +@OperatorFactory.register +class _ConvOperator(_CommonParams): + op_type = "ConvOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return ConvOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + @OperatorFactory.register class _QuantizedFullyConnectedOperator(_CommonParams): @@ -433,3 +466,123 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): op_name=op_var_name, tensor_var_map=tensor_var_map, ) + +@OperatorFactory.register +class _BatchNormOperator(_CommonParams): + op_type = "BatchNormOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MeanOperator(_CommonParams): + op_type = "MeanOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + keep_dims = str(op_info.op_attr["keep_dims"]) + return (" {} ".format(keep_dims), ) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SoftmaxOperator(_CommonParams): + op_type = "SoftmaxOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + Beta = op_info.op_attr["Beta"] + return (" %f " % Beta,) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MulOperator(_Operator): + op_type = 'MulOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return MulOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SubOperator(_Operator): + op_type = 'SubOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return SubOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) diff --git a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py index e7de6eac..50fbc8eb 100644 --- a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py +++ b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py @@ -26,6 +26,12 @@ "MinPoolEvalSnippet", "MaxPoolEvalSnippet", "QuantizedFullyConnectedSnippet", + "BatchNormSnippet", + "MulOpEvalSnippet", + "SubOpEvalSnippet", + "ConvOpEvalSnippet", + "MeanOpEvalSnippet", + "SoftmaxOpEvalSnippet", "SimpleContainer", ] @@ -135,6 +141,9 @@ class DepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "depthwise_filter", "pointwise_filter"] __outputs__ = ["out"] +class ConvOpEvalSnippet(OpEvalSnippet): + __inputs__ = ["in", "filter"] + __outputs__ = ["out"] class QuantDepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "filter", "bias"] @@ -210,6 +219,23 @@ class QuantizedFullyConnectedSnippet(OpEvalSnippet): __inputs__ = ["input", "filter", "bias"] __outputs__ = ["output"] +class BatchNormSnippet(OpEvalSnippet): + __inputs__ = ["x", "mean", "variance", "offset", "scale"] + __outputs__ = ["output"] + +class MulOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class SubOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class MeanOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input', 'axis'] + __outputs__ = ['output'] +class SoftmaxOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input'] + __outputs__ = ['output'] + class SimpleContainer(SnippetBase): __headers__ = set(['"uTensor.h"', ""]) diff --git a/utensor_cgen/frontend/tflite.py b/utensor_cgen/frontend/tflite.py index c3149989..d1ad3d8d 100644 --- a/utensor_cgen/frontend/tflite.py +++ b/utensor_cgen/frontend/tflite.py @@ -70,6 +70,30 @@ def depthwise_conv2d_op_data(op): return option_dict +def conv2d_op_data(op): + option_dict = {} + if op.CustomOptionsLength() < 1: + from .tflite_flatbuffer.Conv2DOptions import Conv2DOptions + + option = Conv2DOptions() + builtin_data = op.BuiltinOptions() + option.Init(builtin_data.Bytes, builtin_data.Pos) + option_dict["Padding"] = option.Padding() + option_dict["StrideW"] = option.StrideW() + option_dict["StrideH"] = option.StrideH() + option_dict["FusedActivationFunction"] = class_option2str( + ActivationFunctionType, option.FusedActivationFunction() + ) + option_dict["DilationWFactor"] = option.DilationWFactor() + option_dict["DilationHFactor"] = option.DilationHFactor() + + else: + option_dict[ + _CUSTOM_OPTION_FORMAT_MAP[op.CustomOptionsFormat()] + ] = op.CustomOptionsAsNumpy() + + return option_dict + def reshape_op_data(op): option_dict = {} if op.CustomOptionsLength() < 1: @@ -86,6 +110,22 @@ def reshape_op_data(op): return option_dict +def reducer_op_data(op): + option_dict = {} + if op.CustomOptionsLength() < 1: + from .tflite_flatbuffer.ReducerOptions import ReducerOptions + + option = ReducerOptions() + builtin_data = op.BuiltinOptions() + option.Init(builtin_data.Bytes, builtin_data.Pos) + option_dict["keep_dims"] = option.KeepDims() + else: + option_dict[ + _CUSTOM_OPTION_FORMAT_MAP[op.CustomOptionsFormat()] + ] = op.CustomOptionsAsNumpy() + + return option_dict + def dequantize_op_data(op): option_dict = {} if op.CustomOptionsLength() < 1: @@ -161,15 +201,172 @@ def argmax_op_data(op): return option_dict +def mul_op_data(op): + option_dict = {} + if op.CustomOptionsLength() < 1: + from .tflite_flatbuffer.MulOptions import MulOptions + + option = MulOptions() + builtin_data = op.BuiltinOptions() + option.Init(builtin_data.Bytes, builtin_data.Pos) + #option_dict["OutputType"] = option.OutputType() + else: + option_dict[ + _CUSTOM_OPTION_FORMAT_MAP[op.CustomOptionsFormat()] + ] = op.CustomOptionsAsNumpy() + + return option_dict + +def sub_op_data(op): + option_dict = {} + if op.CustomOptionsLength() < 1: + from .tflite_flatbuffer.SubOptions import SubOptions -_OP_DATA_FUNC_MAP = dict() -_OP_DATA_FUNC_MAP["QUANTIZE"] = quantize_op_data -_OP_DATA_FUNC_MAP["DEPTHWISE_CONV_2D"] = depthwise_conv2d_op_data -_OP_DATA_FUNC_MAP["MAX_POOL_2D"] = pool2d_op_data -_OP_DATA_FUNC_MAP["RESHAPE"] = reshape_op_data -_OP_DATA_FUNC_MAP["FULLY_CONNECTED"] = fully_connected_op_data -_OP_DATA_FUNC_MAP["DEQUANTIZE"] = dequantize_op_data -_OP_DATA_FUNC_MAP["ARG_MAX"] = argmax_op_data + option = SubOptions() + builtin_data = op.BuiltinOptions() + option.Init(builtin_data.Bytes, builtin_data.Pos) + #option_dict["OutputType"] = option.OutputType() + else: + option_dict[ + _CUSTOM_OPTION_FORMAT_MAP[op.CustomOptionsFormat()] + ] = op.CustomOptionsAsNumpy() + + return option_dict + +def softmax_op_data(op): + option_dict = {} + if op.CustomOptionsLength() < 1: + from .tflite_flatbuffer.SoftmaxOptions import SoftmaxOptions + + option = SoftmaxOptions() + builtin_data = op.BuiltinOptions() + option.Init(builtin_data.Bytes, builtin_data.Pos) + option_dict["Beta"] = option.Beta() + #option_dict["OutputType"] = option.OutputType() + else: + option_dict[ + _CUSTOM_OPTION_FORMAT_MAP[op.CustomOptionsFormat()] + ] = op.CustomOptionsAsNumpy() + + return option_dict + + +_OP_DATA_FUNC_MAP = dict() +_OP_DATA_FUNC_MAP["ADD"] = None +_OP_DATA_FUNC_MAP["AVERAGE_POOL_2D"] = None +_OP_DATA_FUNC_MAP["CONCATENATION"] = None +_OP_DATA_FUNC_MAP["CONV_2D"] = conv2d_op_data +_OP_DATA_FUNC_MAP["DEPTHWISE_CONV_2D"] = depthwise_conv2d_op_data +_OP_DATA_FUNC_MAP["DEQUANTIZE"] = dequantize_op_data +_OP_DATA_FUNC_MAP["EMBEDDING_LOOKUP"] = None +_OP_DATA_FUNC_MAP["FLOOR"] = None +_OP_DATA_FUNC_MAP["FULLY_CONNECTED"] = fully_connected_op_data +_OP_DATA_FUNC_MAP["HASHTABLE_LOOKUP"] = None +_OP_DATA_FUNC_MAP["L2_NORMALIZATION"] = None +_OP_DATA_FUNC_MAP["L2_POOL_2D"] = None +_OP_DATA_FUNC_MAP["LOCAL_RESPONSE_NORMALIZATION"] = None +_OP_DATA_FUNC_MAP["LOGISTIC"] = None +_OP_DATA_FUNC_MAP["LSH_PROJECTION"] = None +_OP_DATA_FUNC_MAP["LSTM"] = None +_OP_DATA_FUNC_MAP["MAX_POOL_2D"] = pool2d_op_data +_OP_DATA_FUNC_MAP["MUL"] = mul_op_data +_OP_DATA_FUNC_MAP["RELU"] = None +_OP_DATA_FUNC_MAP["RELU_N1_TO_1"] = None +_OP_DATA_FUNC_MAP["RELU6"] = None +_OP_DATA_FUNC_MAP["RESHAPE"] = reshape_op_data +_OP_DATA_FUNC_MAP["RESIZE_BILINEAR"] = None +_OP_DATA_FUNC_MAP["RNN"] = None +_OP_DATA_FUNC_MAP["SOFTMAX"] = softmax_op_data +_OP_DATA_FUNC_MAP["SPACE_TO_DEPTH"] = None +_OP_DATA_FUNC_MAP["SVDF"] = None +_OP_DATA_FUNC_MAP["TANH"] = None +_OP_DATA_FUNC_MAP["CONCAT_EMBEDDINGS"] = None +_OP_DATA_FUNC_MAP["SKIP_GRAM"] = None +_OP_DATA_FUNC_MAP["CALL"] = None +_OP_DATA_FUNC_MAP["CUSTOM"] = None +_OP_DATA_FUNC_MAP["EMBEDDING_LOOKUP_SPARSE"] = None +_OP_DATA_FUNC_MAP["PAD"] = None +_OP_DATA_FUNC_MAP["UNIDIRECTIONAL_SEQUENCE_RNN"] = None +_OP_DATA_FUNC_MAP["GATHER"] = None +_OP_DATA_FUNC_MAP["BATCH_TO_SPACE_ND"] = None +_OP_DATA_FUNC_MAP["SPACE_TO_BATCH_ND"] = None +_OP_DATA_FUNC_MAP["TRANSPOSE"] = None +_OP_DATA_FUNC_MAP["MEAN"] = reducer_op_data +_OP_DATA_FUNC_MAP["SUB"] = sub_op_data +_OP_DATA_FUNC_MAP["DIV"] = None +_OP_DATA_FUNC_MAP["SQUEEZE"] = None +_OP_DATA_FUNC_MAP["UNIDIRECTIONAL_SEQUENCE_LSTM"] = None +_OP_DATA_FUNC_MAP["STRIDED_SLICE"] = None +_OP_DATA_FUNC_MAP["BIDIRECTIONAL_SEQUENCE_RNN"] = None +_OP_DATA_FUNC_MAP["EXP"] = None +_OP_DATA_FUNC_MAP["TOPK_V2"] = None +_OP_DATA_FUNC_MAP["SPLIT"] = None +_OP_DATA_FUNC_MAP["LOG_SOFTMAX"] = None +_OP_DATA_FUNC_MAP["DELEGATE"] = None +_OP_DATA_FUNC_MAP["BIDIRECTIONAL_SEQUENCE_LSTM"] = None +_OP_DATA_FUNC_MAP["CAST"] = None +_OP_DATA_FUNC_MAP["PRELU"] = None +_OP_DATA_FUNC_MAP["MAXIMUM"] = None +_OP_DATA_FUNC_MAP["ARG_MAX"] = argmax_op_data +_OP_DATA_FUNC_MAP["MINIMUM"] = None +_OP_DATA_FUNC_MAP["LESS"] = None +_OP_DATA_FUNC_MAP["NEG"] = None +_OP_DATA_FUNC_MAP["PADV2"] = None +_OP_DATA_FUNC_MAP["GREATER"] = None +_OP_DATA_FUNC_MAP["GREATER_EQUAL"] = None +_OP_DATA_FUNC_MAP["LESS_EQUAL"] = None +_OP_DATA_FUNC_MAP["SELECT"] = None +_OP_DATA_FUNC_MAP["SLICE"] = None +_OP_DATA_FUNC_MAP["SIN"] = None +_OP_DATA_FUNC_MAP["TRANSPOSE_CONV"] = None +_OP_DATA_FUNC_MAP["SPARSE_TO_DENSE"] = None +_OP_DATA_FUNC_MAP["TILE"] = None +_OP_DATA_FUNC_MAP["EXPAND_DIMS"] = None +_OP_DATA_FUNC_MAP["EQUAL"] = None +_OP_DATA_FUNC_MAP["NOT_EQUAL"] = None +_OP_DATA_FUNC_MAP["LOG"] = None +_OP_DATA_FUNC_MAP["SUM"] = None +_OP_DATA_FUNC_MAP["SQRT"] = None +_OP_DATA_FUNC_MAP["RSQRT"] = None +_OP_DATA_FUNC_MAP["SHAPE"] = None +_OP_DATA_FUNC_MAP["POW"] = None +_OP_DATA_FUNC_MAP["ARG_MIN"] = None +_OP_DATA_FUNC_MAP["FAKE_QUANT"] = None +_OP_DATA_FUNC_MAP["REDUCE_PROD"] = None +_OP_DATA_FUNC_MAP["REDUCE_MAX"] = None +_OP_DATA_FUNC_MAP["PACK"] = None +_OP_DATA_FUNC_MAP["LOGICAL_OR"] = None +_OP_DATA_FUNC_MAP["ONE_HOT"] = None +_OP_DATA_FUNC_MAP["LOGICAL_AND"] = None +_OP_DATA_FUNC_MAP["LOGICAL_NOT"] = None +_OP_DATA_FUNC_MAP["UNPACK"] = None +_OP_DATA_FUNC_MAP["REDUCE_MIN"] = None +_OP_DATA_FUNC_MAP["FLOOR_DIV"] = None +_OP_DATA_FUNC_MAP["REDUCE_ANY"] = None +_OP_DATA_FUNC_MAP["SQUARE"] = None +_OP_DATA_FUNC_MAP["ZEROS_LIKE"] = None +_OP_DATA_FUNC_MAP["FILL"] = None +_OP_DATA_FUNC_MAP["FLOOR_MOD"] = None +_OP_DATA_FUNC_MAP["RANGE"] = None +_OP_DATA_FUNC_MAP["RESIZE_NEAREST_NEIGHBOR"] = None +_OP_DATA_FUNC_MAP["LEAKY_RELU"] = None +_OP_DATA_FUNC_MAP["SQUARED_DIFFERENCE"] = None +_OP_DATA_FUNC_MAP["MIRROR_PAD"] = None +_OP_DATA_FUNC_MAP["ABS"] = None +_OP_DATA_FUNC_MAP["SPLIT_V"] = None +_OP_DATA_FUNC_MAP["UNIQUE"] = None +_OP_DATA_FUNC_MAP["CEIL"] = None +_OP_DATA_FUNC_MAP["REVERSE_V2"] = None +_OP_DATA_FUNC_MAP["ADD_N"] = None +_OP_DATA_FUNC_MAP["GATHER_ND"] = None +_OP_DATA_FUNC_MAP["COS"] = None +_OP_DATA_FUNC_MAP["WHERE"] = None +_OP_DATA_FUNC_MAP["RANK"] = None +_OP_DATA_FUNC_MAP["ELU"] = None +_OP_DATA_FUNC_MAP["REVERSE_SEQUENCE"] = None +_OP_DATA_FUNC_MAP["MATRIX_DIAG"] = None +_OP_DATA_FUNC_MAP["QUANTIZE"] = quantize_op_data +_OP_DATA_FUNC_MAP["MATRIX_SET_DIAG"] = None @FrontendSelector.register(target_exts=[".tflite"]) @@ -244,11 +441,11 @@ def _build_tensor_map(self, fb_model, ugraph): tensor_name = tensor.Name().decode('utf8') if tensor_name is "" or None: tensor_name = "tensor_" + str(idx) - + dtype = self._TENSOR_NP_TYPE[tensor.Type()] attributes = dict() quant_params = tensor.Quantization() - if quant_params is not None: + if quant_params is not None and quant_params.ZeroPointAsNumpy() and quant_params.ScaleAsNumpy(): zp = quant_params.ZeroPointAsNumpy() if zp.dtype == np.dtype(' Date: Tue, 12 May 2020 18:30:03 -0500 Subject: [PATCH 2/7] Add BatchNorm, Mul, Add, Sub, Mean, and more ops --- .../backend/utensor/_graph_lower/_op_lower.py | 2 + .../rearch/_operators/_impls.py | 153 ++++++++++++++++ .../utensor/snippets/rearch/_snippets.py | 26 +++ utensor_cgen/frontend/tflite.py | 170 ++++++++++++++++-- utensor_cgen/legalizer/tflite.py | 7 + 5 files changed, 345 insertions(+), 13 deletions(-) diff --git a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py index 7d0ed1e2..3facc56f 100644 --- a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py +++ b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py @@ -41,6 +41,8 @@ def __init__(self, config): class OptypeRenameManager(object): NAME_MAP = { 'Add': 'AddOperator', + 'Mul': 'MulOperator', + 'Sub': 'SubOperator', 'Conv2D': 'ConvOperator', 'MatMul': 'MatrixMultOperator' } diff --git a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py index 3b8b1c12..6a1e1f26 100644 --- a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py +++ b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py @@ -436,6 +436,39 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): tensor_var_map=tensor_var_map, ) +@OperatorFactory.register +class _ConvOperator(_CommonParams): + op_type = "ConvOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return ConvOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + @OperatorFactory.register class _QuantizedFullyConnectedOperator(_CommonParams): @@ -464,3 +497,123 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): op_name=op_var_name, tensor_var_map=tensor_var_map, ) + +@OperatorFactory.register +class _BatchNormOperator(_CommonParams): + op_type = "BatchNormOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MeanOperator(_CommonParams): + op_type = "MeanOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + keep_dims = str(op_info.op_attr["keep_dims"]) + return (" {} ".format(keep_dims), ) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SoftmaxOperator(_CommonParams): + op_type = "SoftmaxOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + Beta = op_info.op_attr["Beta"] + return (" %f " % Beta,) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MulOperator(_Operator): + op_type = 'MulOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return MulOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SubOperator(_Operator): + op_type = 'SubOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return SubOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) diff --git a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py index 5db80be8..7a4f57b1 100644 --- a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py +++ b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py @@ -27,6 +27,12 @@ "MinPoolEvalSnippet", "MaxPoolEvalSnippet", "QuantizedFullyConnectedSnippet", + "BatchNormSnippet", + "MulOpEvalSnippet", + "SubOpEvalSnippet", + "ConvOpEvalSnippet", + "MeanOpEvalSnippet", + "SoftmaxOpEvalSnippet", "SimpleContainer", ] @@ -143,6 +149,9 @@ class DepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "depthwise_filter", "pointwise_filter"] __outputs__ = ["out"] +class ConvOpEvalSnippet(OpEvalSnippet): + __inputs__ = ["in", "filter"] + __outputs__ = ["out"] class QuantDepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "filter", "bias"] @@ -218,6 +227,23 @@ class QuantizedFullyConnectedSnippet(OpEvalSnippet): __inputs__ = ["input", "filter", "bias"] __outputs__ = ["output"] +class BatchNormSnippet(OpEvalSnippet): + __inputs__ = ["x", "mean", "variance", "offset", "scale"] + __outputs__ = ["output"] + +class MulOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class SubOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class MeanOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input', 'axis'] + __outputs__ = ['output'] +class SoftmaxOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input'] + __outputs__ = ['output'] + class SimpleContainer(SnippetBase): __headers__ = set(['"uTensor.h"', ""]) diff --git a/utensor_cgen/frontend/tflite.py b/utensor_cgen/frontend/tflite.py index d7229a35..13d5978e 100644 --- a/utensor_cgen/frontend/tflite.py +++ b/utensor_cgen/frontend/tflite.py @@ -82,14 +82,17 @@ def _build_tensor_map(self, fb_model, ugraph): tensor_name = tensor.Name().decode('utf8') if tensor_name is "" or None: tensor_name = "tensor_" + str(idx) - + dtype = self._TENSOR_NP_TYPE[tensor.Type()] attributes = dict() quant_params = tensor.Quantization() - if quant_params is not None and \ - quant_params.ZeroPointLength() and \ - quant_params.ScaleLength(): - attributes["quantization_zeros"] = quant_params.ZeroPointAsNumpy() + if quant_params is not None and quant_params.ZeroPointAsNumpy() and quant_params.ScaleAsNumpy(): + zp = quant_params.ZeroPointAsNumpy() + if zp.dtype == np.dtype(' Date: Wed, 27 May 2020 09:40:33 -0500 Subject: [PATCH 3/7] Finish merge --- utensor_cgen/frontend/tflite.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/utensor_cgen/frontend/tflite.py b/utensor_cgen/frontend/tflite.py index 13d5978e..9897af2f 100644 --- a/utensor_cgen/frontend/tflite.py +++ b/utensor_cgen/frontend/tflite.py @@ -86,13 +86,18 @@ def _build_tensor_map(self, fb_model, ugraph): dtype = self._TENSOR_NP_TYPE[tensor.Type()] attributes = dict() quant_params = tensor.Quantization() - if quant_params is not None and quant_params.ZeroPointAsNumpy() and quant_params.ScaleAsNumpy(): - zp = quant_params.ZeroPointAsNumpy() - if zp.dtype == np.dtype(' Date: Tue, 12 May 2020 18:30:03 -0500 Subject: [PATCH 4/7] Add BatchNorm, Mul, Add, Sub, Mean, and more ops --- .../backend/utensor/_graph_lower/_op_lower.py | 2 + .../rearch/_operators/_impls.py | 168 +++++++++++++++++ .../utensor/snippets/rearch/_snippets.py | 26 +++ utensor_cgen/frontend/tflite.py | 170 ++++++++++++++++-- utensor_cgen/legalizer/tflite.py | 7 + 5 files changed, 360 insertions(+), 13 deletions(-) diff --git a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py index 4d1cd6a6..f7ec7672 100644 --- a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py +++ b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py @@ -40,6 +40,8 @@ class uTensorRearchGraphLower(uTensorGraphLowerBase): class OptypeRenameManager(object): NAME_MAP = { 'Add': 'AddOperator', + 'Mul': 'MulOperator', + 'Sub': 'SubOperator', 'Conv2D': 'ConvOperator', 'MatMul': 'MatrixMultOperator' } diff --git a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py index b07552f7..0cdeeda8 100644 --- a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py +++ b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py @@ -478,6 +478,39 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): nested_namespaces=type(self).namespaces, ) +@OperatorFactory.register +class _ConvOperator(_CommonParams): + op_type = "ConvOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return ConvOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + @OperatorFactory.register class _QuantizedFullyConnectedOperator(_CommonParams): @@ -521,3 +554,138 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): return MissingOpEvalSnippet(op_info, tensor_var_map) OperatorFactory._operators[_MissingOperator.op_type] = _MissingOperator + +@OperatorFactory.register +class _BatchNormOperator(_Operator): + namespaces = ('ReferenceOperators',) + op_type = "BatchNormOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, + ) + +@OperatorFactory.register +class _MeanOperator(_Operator): + namespaces = ('ReferenceOperators',) + op_type = "MeanOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + keep_dims = str(op_info.op_attr["keep_dims"]) + return (" {} ".format(keep_dims), ) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, + ) + +@OperatorFactory.register +class _SoftmaxOperator(_CommonParams): + namespaces = ('ReferenceOperators',) + op_type = "SoftmaxOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + Beta = op_info.op_attr["Beta"] + return (" %f " % Beta,) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, + ) + +@OperatorFactory.register +class _MulOperator(_Operator): + namespaces = ('ReferenceOperators',) + op_type = 'MulOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return MulOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, + ) + +@OperatorFactory.register +class _SubOperator(_Operator): + namespaces = ('ReferenceOperators',) + op_type = 'SubOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return SubOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, + ) diff --git a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py index a184420d..67f99023 100644 --- a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py +++ b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py @@ -30,6 +30,12 @@ "QuantizedFullyConnectedSnippet", "MissingOpEvalSnippet", "TimeSlotContainer", + "BatchNormSnippet", + "MulOpEvalSnippet", + "SubOpEvalSnippet", + "ConvOpEvalSnippet", + "MeanOpEvalSnippet", + "SoftmaxOpEvalSnippet", "SimpleContainer", ] @@ -156,6 +162,9 @@ class DepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "depthwise_filter", "pointwise_filter"] __outputs__ = ["out"] +class ConvOpEvalSnippet(OpEvalSnippet): + __inputs__ = ["in", "filter"] + __outputs__ = ["out"] class QuantDepthwiseSeperateConvOpEvalSnippet(OpEvalSnippet): __inputs__ = ["in", "filter", "bias"] @@ -231,6 +240,23 @@ class QuantizedFullyConnectedSnippet(OpEvalSnippet): __inputs__ = ["input", "filter", "bias"] __outputs__ = ["output"] +class BatchNormSnippet(OpEvalSnippet): + __inputs__ = ["x", "mean", "variance", "offset", "scale"] + __outputs__ = ["output"] + +class MulOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class SubOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['a', 'b'] + __outputs__ = ['c'] +class MeanOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input', 'axis'] + __outputs__ = ['output'] +class SoftmaxOpEvalSnippet(OpEvalSnippet): + __inputs__ = ['input'] + __outputs__ = ['output'] + class MissingOpEvalSnippet(OpEvalSnippet): __template_name__ = "snippets/rearch/op_missing.cpp" diff --git a/utensor_cgen/frontend/tflite.py b/utensor_cgen/frontend/tflite.py index d7229a35..13d5978e 100644 --- a/utensor_cgen/frontend/tflite.py +++ b/utensor_cgen/frontend/tflite.py @@ -82,14 +82,17 @@ def _build_tensor_map(self, fb_model, ugraph): tensor_name = tensor.Name().decode('utf8') if tensor_name is "" or None: tensor_name = "tensor_" + str(idx) - + dtype = self._TENSOR_NP_TYPE[tensor.Type()] attributes = dict() quant_params = tensor.Quantization() - if quant_params is not None and \ - quant_params.ZeroPointLength() and \ - quant_params.ScaleLength(): - attributes["quantization_zeros"] = quant_params.ZeroPointAsNumpy() + if quant_params is not None and quant_params.ZeroPointAsNumpy() and quant_params.ScaleAsNumpy(): + zp = quant_params.ZeroPointAsNumpy() + if zp.dtype == np.dtype(' Date: Wed, 27 May 2020 09:40:33 -0500 Subject: [PATCH 5/7] Finish merge --- utensor_cgen/frontend/tflite.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/utensor_cgen/frontend/tflite.py b/utensor_cgen/frontend/tflite.py index 13d5978e..9897af2f 100644 --- a/utensor_cgen/frontend/tflite.py +++ b/utensor_cgen/frontend/tflite.py @@ -86,13 +86,18 @@ def _build_tensor_map(self, fb_model, ugraph): dtype = self._TENSOR_NP_TYPE[tensor.Type()] attributes = dict() quant_params = tensor.Quantization() - if quant_params is not None and quant_params.ZeroPointAsNumpy() and quant_params.ScaleAsNumpy(): - zp = quant_params.ZeroPointAsNumpy() - if zp.dtype == np.dtype(' Date: Tue, 12 May 2020 18:30:03 -0500 Subject: [PATCH 6/7] Add BatchNorm, Mul, Add, Sub, Mean, and more ops --- .../rearch/_operators/_impls.py | 153 ++++++++++++++++++ .../utensor/snippets/rearch/_snippets.py | 1 - 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py index 0cdeeda8..c6dbed26 100644 --- a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py +++ b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py @@ -511,6 +511,39 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): tensor_var_map=tensor_var_map, ) +@OperatorFactory.register +class _ConvOperator(_CommonParams): + op_type = "ConvOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return ConvOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + @OperatorFactory.register class _QuantizedFullyConnectedOperator(_CommonParams): @@ -689,3 +722,123 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): tensor_var_map=tensor_var_map, nested_namespaces=type(self).namespaces, ) + +@OperatorFactory.register +class _BatchNormOperator(_CommonParams): + op_type = "BatchNormOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + strides = [ + 1, + op_info.op_attr['StrideW'], + op_info.op_attr['StrideH'], + 1, + ] + padding = cls._PADDING_MAP[op_info.op_attr['Padding']] + strides_str = ','.join(map(str, strides)) + return ("{{ {} }}".format(strides_str), padding) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MeanOperator(_CommonParams): + op_type = "MeanOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + keep_dims = str(op_info.op_attr["keep_dims"]) + return (" {} ".format(keep_dims), ) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SoftmaxOperator(_CommonParams): + op_type = "SoftmaxOperator" + + @classmethod + @must_return_type(Hashable) + def get_constructor_parameters(cls, op_info): + Beta = op_info.op_attr["Beta"] + return (" %f " % Beta,) + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.out_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return BatchNormSnippet( + op_info=op_info, + templ_dtypes=[self.out_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _MulOperator(_Operator): + op_type = 'MulOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return MulOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) + +@OperatorFactory.register +class _SubOperator(_Operator): + op_type = 'SubOperator' + + def get_declare_snippet(self, op_var_name, tensor_var_map): + return DeclareOpSnippet( + op=self, + templ_dtypes=[self.in_dtypes[0]], + op_var_name=op_var_name, + ) + + def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): + return SubOpEvalSnippet( + op_info=op_info, + templ_dtypes=[self.in_dtypes[0]], + op_name=op_var_name, + tensor_var_map=tensor_var_map, + ) diff --git a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py index 67f99023..c40b4613 100644 --- a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py +++ b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py @@ -30,7 +30,6 @@ "QuantizedFullyConnectedSnippet", "MissingOpEvalSnippet", "TimeSlotContainer", - "BatchNormSnippet", "MulOpEvalSnippet", "SubOpEvalSnippet", "ConvOpEvalSnippet", From 47863920a7bec51c5c79c7e7f1c8a5aeb5da7e27 Mon Sep 17 00:00:00 2001 From: Michael Bartling Date: Mon, 15 Jun 2020 17:40:57 -0500 Subject: [PATCH 7/7] Fix duplicates --- .../backend/utensor/_graph_lower/_op_lower.py | 2 + .../rearch/_operators/_impls.py | 299 +----------------- .../utensor/snippets/rearch/_snippets.py | 4 + 3 files changed, 18 insertions(+), 287 deletions(-) diff --git a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py index f7ec7672..e5255d4e 100644 --- a/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py +++ b/utensor_cgen/backend/utensor/_graph_lower/_op_lower.py @@ -91,6 +91,8 @@ def apply(cls, ugraph): for op_info in ugraph.get_ops_by_type('FullyConnectedOperator'): if cls._check_quantized(op_info): op_info.code_gen_attributes['namespaces'] = ('TflmSymQuantOps',) + else: + op_info.code_gen_attributes['namespaces'] = ('ReferenceOperators',) @classmethod def _check_quantized(cls, op_info): diff --git a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py index d0488a5a..ace26096 100644 --- a/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py +++ b/utensor_cgen/backend/utensor/code_generator/rearch/_operators/_impls.py @@ -512,72 +512,36 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): ) @OperatorFactory.register -class _ConvOperator(_CommonParams): - op_type = "ConvOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - - strides = [ - 1, - op_info.op_attr['StrideW'], - op_info.op_attr['StrideH'], - 1, - ] - padding = cls._PADDING_MAP[op_info.op_attr['Padding']] - strides_str = ','.join(map(str, strides)) - return ("{{ {} }}".format(strides_str), padding) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return ConvOpEvalSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _ConvOperator(_CommonParams): - op_type = "ConvOperator" +class _FullyConnectedOperator(_CommonParams): + namespaces = ('ReferenceOperators',) + op_type = "FullyConnectedOperator" @classmethod @must_return_type(Hashable) def get_constructor_parameters(cls, op_info): - - strides = [ - 1, - op_info.op_attr['StrideW'], - op_info.op_attr['StrideH'], - 1, - ] - padding = cls._PADDING_MAP[op_info.op_attr['Padding']] - strides_str = ','.join(map(str, strides)) - return ("{{ {} }}".format(strides_str), padding) + activation_idx = cls._ACTIVATION_STR_PATTERN.match( + op_info.op_attr['FusedActivationFunction'] + ).group(1) + activation = cls._ACTIVATION_MAP[activation_idx] + return (activation,) def get_declare_snippet(self, op_var_name, tensor_var_map): return DeclareOpSnippet( op=self, templ_dtypes=[self.out_dtypes[0]], op_var_name=op_var_name, + nested_namespaces=type(self).namespaces, ) def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return ConvOpEvalSnippet( + return FullyConnectedSnippet( op_info=op_info, templ_dtypes=[self.out_dtypes[0]], op_name=op_var_name, tensor_var_map=tensor_var_map, + nested_namespaces=type(self).namespaces, ) - @OperatorFactory.register class _QuantizedFullyConnectedOperator(_CommonParams): namespaces = ('TflmSymQuantOps',) @@ -756,248 +720,9 @@ def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): nested_namespaces=type(self).namespaces, ) -@OperatorFactory.register -class _BatchNormOperator(_CommonParams): - op_type = "BatchNormOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - strides = [ - 1, - op_info.op_attr['StrideW'], - op_info.op_attr['StrideH'], - 1, - ] - padding = cls._PADDING_MAP[op_info.op_attr['Padding']] - strides_str = ','.join(map(str, strides)) - return ("{{ {} }}".format(strides_str), padding) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _MeanOperator(_CommonParams): - op_type = "MeanOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - keep_dims = str(op_info.op_attr["keep_dims"]) - return (" {} ".format(keep_dims), ) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _SoftmaxOperator(_CommonParams): - op_type = "SoftmaxOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - Beta = op_info.op_attr["Beta"] - return (" %f " % Beta,) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _MulOperator(_Operator): - op_type = 'MulOperator' - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.in_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return MulOpEvalSnippet( - op_info=op_info, - templ_dtypes=[self.in_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _SubOperator(_Operator): - op_type = 'SubOperator' - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.in_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return SubOpEvalSnippet( - op_info=op_info, - templ_dtypes=[self.in_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _BatchNormOperator(_CommonParams): - op_type = "BatchNormOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - strides = [ - 1, - op_info.op_attr['StrideW'], - op_info.op_attr['StrideH'], - 1, - ] - padding = cls._PADDING_MAP[op_info.op_attr['Padding']] - strides_str = ','.join(map(str, strides)) - return ("{{ {} }}".format(strides_str), padding) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _MeanOperator(_CommonParams): - op_type = "MeanOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - keep_dims = str(op_info.op_attr["keep_dims"]) - return (" {} ".format(keep_dims), ) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _SoftmaxOperator(_CommonParams): - op_type = "SoftmaxOperator" - - @classmethod - @must_return_type(Hashable) - def get_constructor_parameters(cls, op_info): - Beta = op_info.op_attr["Beta"] - return (" %f " % Beta,) - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.out_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return BatchNormSnippet( - op_info=op_info, - templ_dtypes=[self.out_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _MulOperator(_Operator): - op_type = 'MulOperator' - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.in_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return MulOpEvalSnippet( - op_info=op_info, - templ_dtypes=[self.in_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - -@OperatorFactory.register -class _SubOperator(_Operator): - op_type = 'SubOperator' - - def get_declare_snippet(self, op_var_name, tensor_var_map): - return DeclareOpSnippet( - op=self, - templ_dtypes=[self.in_dtypes[0]], - op_var_name=op_var_name, - ) - - def get_eval_snippet(self, op_var_name, op_info, tensor_var_map): - return SubOpEvalSnippet( - op_info=op_info, - templ_dtypes=[self.in_dtypes[0]], - op_name=op_var_name, - tensor_var_map=tensor_var_map, - ) - @OperatorFactory.register class _SigmoidOperator(_Operator): + namespaces = ('ReferenceOperators',) op_type = 'SigmoidOperator' def get_declare_snippet(self, op_var_name, tensor_var_map): diff --git a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py index 264b5877..4ded93d4 100644 --- a/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py +++ b/utensor_cgen/backend/utensor/snippets/rearch/_snippets.py @@ -28,6 +28,7 @@ "MinPoolEvalSnippet", "MaxPoolEvalSnippet", "QuantizedFullyConnectedSnippet", + "FullyConnectedSnippet", "MissingOpEvalSnippet", "BatchNormSnippet", "TimeSlotContainer", @@ -236,6 +237,9 @@ class MaxPoolEvalSnippet(OpEvalSnippet): __inputs__ = ["in"] __outputs__ = ["out"] +class FullyConnectedSnippet(OpEvalSnippet): + __inputs__ = ["input", "filter", "bias"] + __outputs__ = ["output"] class QuantizedFullyConnectedSnippet(OpEvalSnippet): __inputs__ = ["input", "filter", "bias"]