--- /dev/null
+# tflkit
+
+## Purpose
+
+There are a lot of tools related to TfLite. However, it is inconvenient to use the tools directly because there are many locations and parameters. The tflkit has been created to make it easier to run frequently used tools in scripts. The function provided in this directory uses existing tools rather than implementing them directly. So, additional modifications may occur depending on the TensorFlow version or other external factors. The function provided in this directory will be gradually expanded.
+
+## Prerequisites
+
+The scripts here use TensorFlow's tools, so you need an environment to build TensorFlow.
+Running the scripts within this tutorial requires:
+* [Install Bazel](https://docs.bazel.build/versions/master/install.html), the build tool used to compile TensorFlow.
+
+Initially, no external packages are installed on this project. Therefore, before running these scripts, you should install the associcated packages by running the following command once.
+```
+make configure
+```
+
+## Summarize TF model
+
+### TensorFlow
+
+TensorFlow uses `summarize_graph` tool to inspect the model and provide guesses about likely input and output nodes, as well as other information that's useful for debugging. For more information, see [Inspecting Graphs](https://github.com/tensorflow/tensorflow/tree/9590c4c32dd4346ea5c35673336f5912c6072bf2/tensorflow/tools/graph_transforms#inspecting-graphs) page.
+
+Usage:
+```
+$ bazel build tensorflow/tools/graph_transforms:summarize_graph
+$ bazel-bin/tensorflow/tools/graph_transforms/summarize_graph --in_graph=<pb file>
+```
+
+### tflkit
+
+Usage:
+```
+$ ./summarize_pb.sh <pb file>
+```
+
+The results shown below:
+```
+$ ./summarize_pb.sh inception_v3.pb
+
+ inception_v3.pb
+
+Inputs
+ name=input
+ type=float(1)
+ shape=[?,299,299,3]
+Outputs
+ name=InceptionV3/Predictions/Reshape_1, op=Reshape
+Op Types
+ 488 Const
+ 379 Identity
+ 95 Conv2D
+ 94 FusedBatchNorm
+ 94 Relu
+ 15 ConcatV2
+ 10 AvgPool
+ 4 MaxPool
+ 2 Reshape
+ 1 BiasAdd
+ 1 Placeholder
+ 1 Shape
+ 1 Softmax
+ 1 Squeeze
+
+ 14 Total
+```
+
+## Summarize TfLite model
+
+### tflkit
+
+Usage:
+```
+$ ./summarize_tflite.sh <tflite file>
+```
+
+The results shown below:
+```
+$ ./summarize_tflite.sh inception_v3.tflite
+[Main model]
+
+Main model input tensors: [317]
+Main model output tensors: [316]
+
+Operator 0: CONV_2D (instrs: 39,073,760, cycls: 39,073,760)
+ Fused Activation: RELU
+ Input Tensors[317, 0, 5]
+ Tensor 317 : buffer 183 | Empty | FLOAT32 | Shape [1, 299, 299, 3] (b'input')
+ Tensor 0 : buffer 205 | Filled | FLOAT32 | Shape [32, 3, 3, 3] (b'InceptionV3/Conv2d_1a_3x3/weights')
+ Tensor 5 : buffer 52 | Filled | FLOAT32 | Shape [32] (b'InceptionV3/InceptionV3/Conv2d_1a_3x3/Conv2D_bias')
+ Output Tensors[6]
+ Tensor 6 : buffer 285 | Empty | FLOAT32 | Shape [1, 149, 149, 32] (b'InceptionV3/InceptionV3/Conv2d_1a_3x3/Relu')
+
+[...]
+
+Operator 125: SOFTMAX (instrs: 4,003, cycls: 4,003)
+ Input Tensors[225]
+ Tensor 225 : buffer 142 | Empty | FLOAT32 | Shape [1, 1001] (b'InceptionV3/Logits/SpatialSqueeze')
+ Output Tensors[316]
+ Tensor 316 : buffer 53 | Empty | FLOAT32 | Shape [1, 1001] (b'InceptionV3/Predictions/Reshape_1')
+
+
+Number of all operator types: 6
+ CONV_2D : 95 (instrs: 11,435,404,777)
+ MAX_POOL_2D : 4 (instrs: 12,755,516)
+ AVERAGE_POOL_2D : 10 (instrs: 36,305,334)
+ CONCATENATION : 15 (instrs: 0)
+ RESHAPE : 1 (instrs: ???)
+ SOFTMAX : 1 (instrs: 4,003)
+Number of all operators : 126 (total instrs: 11,484,469,630)
+```
--- /dev/null
+import argparse
+import os
+import subprocess
+import re
+
+
+class cd:
+ """Context manager for changing the current working directory"""
+
+ def __init__(self, newPath):
+ self.newPath = os.path.expanduser(newPath)
+
+ def __enter__(self):
+ self.savedPath = os.getcwd()
+ os.chdir(self.newPath)
+
+ def __exit__(self, etype, value, traceback):
+ os.chdir(self.savedPath)
+
+
+def CheckExt(choices, name):
+ ext = os.path.splitext(name)[1][1:]
+ if ext not in choices:
+ parser.error("file does not end with one of {}".format(choices))
+ return name
+
+
+def PrintName(path):
+ print("")
+ print('\t' + os.path.basename(path))
+ print("")
+
+
+def PrintInput(data):
+ print("Inputs")
+ sub = data.split('(', 1)[1].rsplit(')', 1)[0]
+ for i in re.split(', ', sub):
+ print('\t' + i)
+
+
+def PrintOutput(data):
+ print("Outputs")
+ sub = re.findall('\((.*?)\)', data)
+ for i in sub:
+ print('\t' + i)
+
+
+def PrintOpType(data):
+ print("Op Types")
+ cnt = 0
+ sub = data.rsplit(':', 1)[1].split(',')
+ for i in sub:
+ cnt = cnt + 1
+ print('\t' + i.lstrip())
+ print('\t{0} Total'.format(cnt))
+
+
+def BuildTensorFlowSummarizeGraph(tensorflow_path):
+ with cd(tensorflow_path):
+ subprocess.call(
+ ['bazel', 'build', 'tensorflow/tools/graph_transforms:summarize_graph'])
+
+
+def SummarizeGraph(args):
+ if args.verbose is True:
+ vstr = ""
+ PrintName(args.input_file)
+ with cd(args.tensorflow_path):
+ proc = subprocess.Popen(
+ [
+ 'bazel-bin/tensorflow/tools/graph_transforms/summarize_graph',
+ '--in_graph=' + args.input_file
+ ],
+ stdout=subprocess.PIPE)
+ while True:
+ line = proc.stdout.readline().decode()
+ if args.verbose:
+ vstr += line
+ if line != '':
+ if 'inputs:' in line:
+ PrintInput(line)
+ elif 'outputs:' in line:
+ PrintOutput(line)
+ elif 'Op types used:' in line:
+ PrintOpType(line)
+ else:
+ break
+
+ if args.verbose:
+ print(vstr)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--input_file',
+ required=True,
+ type=lambda s: CheckExt((['pb']), s),
+ help='pb file to read')
+ parser.add_argument(
+ '--tensorflow_path',
+ default='../../externals/tensorflow',
+ help='TensorFlow git repository path')
+ parser.add_argument('--verbose', action='store_true')
+ args = parser.parse_args()
+
+ # Build summarize_graph in external/tensorflow
+ BuildTensorFlowSummarizeGraph(args.tensorflow_path)
+
+ # Summarize graph
+ SummarizeGraph(args)