Introduce new UnsupportedOperationCount class (#1876)
author김용섭/동작제어Lab(SR)/Engineer/삼성전자 <yons.kim@samsung.com>
Tue, 10 Jul 2018 05:30:56 +0000 (14:30 +0900)
committer박세희/동작제어Lab(SR)/Principal Engineer/삼성전자 <saehie.park@samsung.com>
Tue, 10 Jul 2018 05:30:56 +0000 (14:30 +0900)
- This UnsupportedOperationCount class will be used for distinguishing
whether an operator can be counted on operation counts.

Signed-off-by: Yongseop Kim <yons.kim@samsung.com>
tools/tflitefile_tool/operator_counter.py
tools/tflitefile_tool/operator_parser.py
tools/tflitefile_tool/operator_wrapping.py

index 77a4c80..cff0537 100755 (executable)
@@ -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,
 }
index c6600b0..ac880c6 100755 (executable)
@@ -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))
index 16559f2..6ffcb2f 100755 (executable)
@@ -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()