Create tflkit directory (#3438)
author윤지영/동작제어Lab(SR)/Engineer/삼성전자 <jy910.yun@samsung.com>
Fri, 9 Nov 2018 05:20:39 +0000 (14:20 +0900)
committer박세희/동작제어Lab(SR)/Principal Engineer/삼성전자 <saehie.park@samsung.com>
Fri, 9 Nov 2018 05:20:39 +0000 (14:20 +0900)
* Create tflite_easytool directory

This directory is created to make it easier to run frequently used tools in scripts.
Now, it has two functions:
- Summraize PB model
- Summraize TfLite model

Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
* Change the directory name to tflkit

Also changes the relative path to absolute path

Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
* Add Prerequires and TF tool guideline

Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
* Add additional description for prerequires

Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
tools/tflkit/README.md [new file with mode: 0644]
tools/tflkit/summarize_pb.py [new file with mode: 0644]
tools/tflkit/summarize_pb.sh [new file with mode: 0755]
tools/tflkit/summarize_tflite.sh [new file with mode: 0755]

diff --git a/tools/tflkit/README.md b/tools/tflkit/README.md
new file mode 100644 (file)
index 0000000..2a2769e
--- /dev/null
@@ -0,0 +1,111 @@
+# 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)
+```
diff --git a/tools/tflkit/summarize_pb.py b/tools/tflkit/summarize_pb.py
new file mode 100644 (file)
index 0000000..6338041
--- /dev/null
@@ -0,0 +1,111 @@
+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)
diff --git a/tools/tflkit/summarize_pb.sh b/tools/tflkit/summarize_pb.sh
new file mode 100755 (executable)
index 0000000..141f27b
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+python summarize_pb.py --input_file=$1 $2
diff --git a/tools/tflkit/summarize_tflite.sh b/tools/tflkit/summarize_tflite.sh
new file mode 100755 (executable)
index 0000000..3560de2
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+python "${SCRIPT_PATH}/../tflitefile_tool/model_parser.py" $1