Skip to content

Commit f1782f3

Browse files
yongwwwyzhliu
authored andcommitted
Add tf parser wrapper, infer shape automatically
1 parent 2da23bd commit f1782f3

3 files changed

Lines changed: 60 additions & 19 deletions

File tree

nnvm/python/nnvm/frontend/tensorflow.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ def __init__(self):
11291129
self._num_param = 0
11301130
self._num_rnn_layer = False
11311131
self._outputs_are_0d = {}
1132+
self._input_shapes = {}
11321133

11331134
def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
11341135
"""Construct nnvm nodes from tensorflow graph definition - GraphDef.
@@ -1176,6 +1177,13 @@ def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
11761177
if missing_operators:
11771178
raise NotImplementedError( \
11781179
"The following operators are not implemented: {}".format(missing_operators))
1180+
for node in graph.node:
1181+
if node.op == 'Placeholder':
1182+
self._input_shapes[node.name] = tensor_util.TensorShapeProtoToList(node.attr['shape'].shape)
1183+
self._input_shapes[node.name][0] = 1
1184+
elif node.op == 'Const':
1185+
tensor_value = node.attr['value'].tensor
1186+
self._input_shapes[node.name] = tensor_util.TensorShapeProtoToList(tensor_value.tensor_shape)
11791187

11801188
final_op = None
11811189
# Parse the nodes to re-create TF graph using Symbol API of NNVM
@@ -1189,13 +1197,12 @@ def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
11891197

11901198
#Variable converted to Const will not have only value attr
11911199
if 'value' in attr and node.op == 'Const':
1192-
tensor_value = attr['value']
1193-
self._output_shapes[node.name] = \
1194-
[tensor_util.TensorShapeProtoToList( \
1195-
tensor_value.tensor_shape)]
1200+
self._output_shapes[node.name] = [self._input_shapes[node.name]]
1201+
elif node.op == 'Placeholder':
1202+
self._output_shapes[node.name] = [self._input_shapes[node.name]]
11961203
elif shape and node.name in shape:
1197-
# Give priority to user argument.
1198-
self._output_shapes[node.name] = [shape[node.name]]
1204+
# Give priority to user argument.
1205+
self._output_shapes[node.name] = [shape[node.name]]
11991206
elif '_output_shapes' in attr:
12001207
self._output_shapes[node.name] = \
12011208
[tensor_util.TensorShapeProtoToList(tshape) \
@@ -1205,15 +1212,14 @@ def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
12051212
# Actual value will be filled after node creation.
12061213
self._output_shapes[node.name] = [None]
12071214
else:
1208-
raise NotImplementedError( \
1209-
"Please freeze the graph with add_shapes=True")
1215+
self._output_shapes[node.name] = None
12101216
self._outputs_are_0d[node.name] = [ \
12111217
not tshape if isinstance(tshape, list) else False \
12121218
for tshape in self._output_shapes[node.name]]
12131219

12141220
if node.op == "Placeholder":
12151221
self._nodes[node.name] = _sym.Variable(name=node.name,
1216-
shape=self._output_shapes[node.name][0])
1222+
shape=self._input_shapes[node.name])
12171223

12181224
elif node.op == "Const":
12191225
# All Const nodes are Param nodes, lets parse
@@ -1228,7 +1234,7 @@ def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
12281234

12291235
else:
12301236
# Pass the parsed shapes instead
1231-
attr["_output_shapes"] = self._output_shapes[node.name]
1237+
output_shapes = self._output_shapes[node.name]
12321238

12331239
# Pass the node name too in attr
12341240
attr["_node_name"] = node.name
@@ -1278,15 +1284,19 @@ def from_tensorflow(self, graph, layout="NHWC", shape=None, outputs=None):
12781284
# Assuming only one output.
12791285
self._nodes[node.name] = op
12801286
final_op = op
1281-
1282-
# Infer shapes if passed explicitely
1283-
node_output = self._nodes[node.name]
1284-
if shape:
1285-
g = _graph.create(node_output)
1286-
shape_dict = {k: v.shape for k, v in self._params.items()}
1287-
shape_dict.update(shape)
1288-
_, out_shapes = graph_util.infer_shape(g, **shape_dict)
1289-
self._output_shapes[node.name] = out_shapes
1287+
# Infer shapes if passed explicitely
1288+
node_output = self._nodes[node.name]
1289+
if shape:
1290+
g = _graph.create(node_output)
1291+
shape_dict = {k: v.shape for k, v in self._params.items()}
1292+
shape_dict.update(shape)
1293+
_, out_shapes = graph_util.infer_shape(g, **shape_dict)
1294+
self._output_shapes[node.name] = out_shapes
1295+
elif output_shapes == None:
1296+
g = _graph.create(node_output)
1297+
self._output_shapes[node.name] = list(graph_util.infer_shape(g, **self._input_shapes))[-1]
1298+
else:
1299+
self._output_shapes[node.name] = output_shapes
12901300

12911301
out = []
12921302
if outputs is None:

nnvm/python/nnvm/frontend/util/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""TF: Tensorflow parser"""
2+
from __future__ import absolute_import as _abs
3+
from __future__ import print_function
4+
from nnvm.frontend.protobuf import graph_pb2
5+
6+
class TFParser(object):
7+
"""A Wrapper to handle tensorflow frozen model parsing
8+
Works w/o installing tensorflow,
9+
Protocol Buffer is needed
10+
```
11+
parser = TfParser(pb_file)
12+
graph = parser.parse()
13+
```
14+
Parameters
15+
----------
16+
pb_file : tensorflow frozen pb file
17+
The pb file should include both operations and tensors
18+
"""
19+
20+
def __init__(self, pb_file):
21+
self._pb = pb_file
22+
self._graph = graph_pb2.GraphDef()
23+
24+
def _load_model(self):
25+
"""load frozen tensorflow model, return GraphDef """
26+
with open(self._pb, "rb") as f:
27+
self._graph.ParseFromString(f.read())
28+
29+
def parse(self):
30+
self._load_model()
31+
return self._graph

0 commit comments

Comments
 (0)