From c2b1885fa9659d6215a4a9df5eae66fbfe53ef83 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EA=B9=80=EC=9A=A9=EC=84=AD/=EB=8F=99=EC=9E=91=EC=A0=9C?= =?utf8?q?=EC=96=B4Lab=28SR=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84?= =?utf8?q?=EC=9E=90?= Date: Tue, 10 Jul 2018 14:30:56 +0900 Subject: [PATCH] Introduce new UnsupportedOperationCount class (#1876) - This UnsupportedOperationCount class will be used for distinguishing whether an operator can be counted on operation counts. Signed-off-by: Yongseop Kim --- tools/tflitefile_tool/operator_counter.py | 39 +++++++++++++++++++----------- tools/tflitefile_tool/operator_parser.py | 31 +++++++++++++++--------- tools/tflitefile_tool/operator_wrapping.py | 31 ++++++++++++++++-------- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/tools/tflitefile_tool/operator_counter.py b/tools/tflitefile_tool/operator_counter.py index 77a4c80..cff0537 100755 --- a/tools/tflitefile_tool/operator_counter.py +++ b/tools/tflitefile_tool/operator_counter.py @@ -40,6 +40,17 @@ class OperationCount(object): def TotalCount(self): return self.add_count + self.mul_count + self.nonlinear_count + def IsSupportedOperationCount(self): + return True + + +class UnsupportedOperationCount(OperationCount): + def __init__(self): + OperationCount.__init__(self) + + def IsSupportedOperationCount(self): + return False + # NOTE: How to count operations of convolution(and also pooling)? # @@ -152,8 +163,8 @@ def CountOpsNothing(tf_operator, inputs, outputs): return OperationCount() -def CountOpsDummy(tf_operator, inputs, outputs): - return OperationCount() +def CountOpsUnsupported(tf_operator, inputs, outputs): + return UnsupportedOperationCount() # TODO: can make this as a class which has above method @@ -167,16 +178,16 @@ ops_counters = { "CONCATENATION": CountOpsNothing, # ADAS - "TOPK_V2": CountOpsDummy, - "SUB": CountOpsDummy, - "STRIDED_SLICE": CountOpsDummy, - "RESHAPE": CountOpsDummy, - "GATHER": CountOpsDummy, - "RESIZE_BILINEAR": CountOpsDummy, - "CAST": CountOpsDummy, - "ADD": CountOpsDummy, - "MUL": CountOpsDummy, - "DIV": CountOpsDummy, - "CUSTOM(TensorFlowMax)": CountOpsDummy, - "CUSTOM": CountOpsDummy, + "TOPK_V2": CountOpsUnsupported, + "SUB": CountOpsUnsupported, + "STRIDED_SLICE": CountOpsUnsupported, + "RESHAPE": CountOpsUnsupported, + "GATHER": CountOpsUnsupported, + "RESIZE_BILINEAR": CountOpsUnsupported, + "CAST": CountOpsUnsupported, + "ADD": CountOpsUnsupported, + "MUL": CountOpsUnsupported, + "DIV": CountOpsUnsupported, + "CUSTOM(TensorFlowMax)": CountOpsUnsupported, + "CUSTOM": CountOpsUnsupported, } diff --git a/tools/tflitefile_tool/operator_parser.py b/tools/tflitefile_tool/operator_parser.py index c6600b0..ac880c6 100755 --- a/tools/tflitefile_tool/operator_parser.py +++ b/tools/tflitefile_tool/operator_parser.py @@ -7,17 +7,21 @@ import tflite.OperatorCode import tflite.BuiltinOperator from operator_wrapping import Operator, SetBuiltinOpcodeStr, BuiltinOpcodeStrList from tensor_wrapping import Tensor, SetTensorTypeStr -from operator_counter import OperationCount +from operator_counter import OperationCount, UnsupportedOperationCount class TypesCounter(object): - def __init__(self): + def __init__(self, op): self.type_count = 0 - self.op_count = OperationCount() + if op.IsSupportedOperationCount(): + self.op_count = OperationCount() + else: + self.op_count = UnsupportedOperationCount() def Update(self, op): self.type_count = self.type_count + 1 - self.op_count.Increase(op.GetOpCount()) + if self.op_count.IsSupportedOperationCount(): + self.op_count.Increase(op.GetOpCount()) def GetTypeCount(self): return self.type_count @@ -25,6 +29,9 @@ class TypesCounter(object): def GetOpCount(self): return self.op_count + def IsSupportedOperationCount(self): + return self.op_count.IsSupportedOperationCount() + class OperatorParser(object): def __init__(self, tf_model, tf_subgraph, perf_predictor=None): @@ -66,7 +73,7 @@ class OperatorParser(object): def CountOperator(self, op): opcode_str = op.GetOpcodeStr() if opcode_str not in self.op_types: - self.op_types[opcode_str] = TypesCounter() + self.op_types[opcode_str] = TypesCounter(op) self.op_types[opcode_str].Update(op) def GetInputTensors(self, tf_operator): @@ -104,15 +111,17 @@ class OperatorParser(object): total_opstr_count = 0 total_op_count = 0 for opstr, type_counter in self.op_types.items(): + supported = type_counter.IsSupportedOperationCount() + opstr_count = type_counter.GetTypeCount() op_count = type_counter.GetOpCount().TotalCount() - print("\t{0:38}: {1:4} \t (total_ops: {2})".format(opstr, opstr_count, - "{:,}".format(op_count))) + print("\t{0:38}: {1:4} \t (total_ops: {2})".format( + opstr, opstr_count, "{:,}".format(op_count) if supported else "???")) total_opstr_count = total_opstr_count + opstr_count - total_op_count = total_op_count + op_count + total_op_count = (total_op_count + op_count) if supported else total_op_count - print("{0:46}: {1:4} \t (total_ops: {2})".format("Total Number of operators", - total_opstr_count, - "{:,}".format(total_op_count))) + total_op_count = "{:,}".format(total_op_count) + print("{0:46}: {1:4} \t (total_ops: {2})".format( + "Total Number of operators", total_opstr_count, total_op_count)) diff --git a/tools/tflitefile_tool/operator_wrapping.py b/tools/tflitefile_tool/operator_wrapping.py index 16559f2..6ffcb2f 100755 --- a/tools/tflitefile_tool/operator_wrapping.py +++ b/tools/tflitefile_tool/operator_wrapping.py @@ -4,7 +4,7 @@ import tflite.Operator import tflite.OperatorCode import tflite.BuiltinOperator from tensor_wrapping import Tensor -from operator_counter import OperationCount, ops_counters +from operator_counter import OperationCount, UnsupportedOperationCount, ops_counters from perf_predictor import PerfPredictor BuiltinOpcodeStrList = {} @@ -45,11 +45,18 @@ class Operator(object): self.op_count = None # OperationCount def PrintInfo(self, perf_predictor=None): - cycles = (perf_predictor.PredictCycles( - self.op_count)) if perf_predictor != None else "???" + supported = self.IsSupportedOperationCount() + + # total op counts + counts = "{:,}".format(self.op_count.TotalCount()) if supported else "???" + + # total op cycles + cycles = "{:,}".format((perf_predictor.PredictCycles( + self.op_count))) if supported and perf_predictor != None else "???" + print("Operator {0}: {1} (ops: {2}, cycls: {3})".format( - self.operator_idx, self.opcode_str, "{:,}".format(self.op_count.TotalCount()), - "{:,}".format(cycles))) + self.operator_idx, self.opcode_str, counts, cycles)) + print("\tInput Tensors" + GetStrTensorIndex(self.inputs)) for tensor in self.inputs: tensor.PrintInfo("\t\t") @@ -59,14 +66,18 @@ class Operator(object): def CountOperations(self): opcode_str = self.opcode_str - if opcode_str not in ops_counters: - print("\n\t Operator {0} is not supported yet\n".format(opcode_str)) - return OperationCount() - self.op_count = ops_counters[opcode_str](self.tf_operator, self.inputs, - self.outputs) + # FIXME: if there would be a class for ops_counters, we can delete this + if not opcode_str in ops_counters: + self.op_count = UnsupportedOperationCount() + else: + self.op_count = ops_counters[opcode_str](self.tf_operator, self.inputs, + self.outputs) def GetOpcodeStr(self): return self.opcode_str def GetOpCount(self): return self.op_count + + def IsSupportedOperationCount(self): + return self.op_count.IsSupportedOperationCount() -- 2.7.4