20 import tensorflow
as tf
23 import convert_header
as header
25 __all__ = [
'convert_from_tensorflow']
30 IOTYPE_INTERMEDIATE = IOTYPE_INPUT | IOTYPE_OUTPUT
41 Operand.index = Operand.index + 1
42 self.
iotype2str = {Operand.IOTYPE_INPUT:
'in', Operand.IOTYPE_OUTPUT:
'out', Operand.IOTYPE_INTERMEDIATE:
'inout'}
43 self.
dtype2str = {Operand.DTYPE_FLOAT:
'DT_FLOAT', Operand.DTYPE_UINT8:
'DT_UINT8'}
47 if iotype == Operand.IOTYPE_INPUT:
51 return "{}: (name: {}, iotype: {}, dtype: {}, dims: ({},{},{},{}) used_count: {})".
format(self.
index,
56 return self.
index < other.index
59 def __init__(self, graph_def, nodes, outfile, dump4tb):
73 self.
op2code = {
'Conv2D':1,
'DepthToSpace':2,
'MirrorPad':3,
'Maximum':4,
'MathBinary':5,
'MathUnary':6}
74 self.
mathbin2code = {
'Sub':0,
'Add':1,
'Mul':2,
'RealDiv':3,
'Minimum':4}
83 dtype = node.attr[
'dtype'].type
85 dtype = node.attr[
'T'].type
87 if 'shape' in node.attr:
88 dims[0] = node.attr[
'shape'].shape.dim[0].size
89 dims[1] = node.attr[
'shape'].shape.dim[1].size
90 dims[2] = node.attr[
'shape'].shape.dim[2].size
91 dims[3] = node.attr[
'shape'].shape.dim[3].size
92 operand =
Operand(name, dtype, dims)
99 graph = tf.get_default_graph()
100 tf.import_graph_def(self.
graph_def, name=
"")
101 tf.summary.FileWriter(
'/tmp/graph', graph)
102 print(
'graph saved, run "tensorboard --logdir=/tmp/graph" to see it')
116 if conv2d_scope_name +
'/BiasAdd' in self.
edges:
117 anode = self.
edges[conv2d_scope_name +
'/BiasAdd'][0]
122 return knode, bnode, dnode, anode
126 assert(node.op ==
'Conv2D')
130 scope_name = TFConverter.get_scope_name(node.name)
134 if dnode
is not None:
135 dilation = struct.unpack(
'i', dnode.attr[
'value'].tensor.tensor_content[0:4])[0]
139 if anode
is not None:
140 activation = anode.op
144 padding = node.attr[
'padding'].s.decode(
"utf-8")
151 ktensor = knode.attr[
'value'].tensor
152 filter_height = ktensor.tensor_shape.dim[0].size
153 filter_width = ktensor.tensor_shape.dim[1].size
154 in_channels = ktensor.tensor_shape.dim[2].size
155 out_channels = ktensor.tensor_shape.dim[3].size
156 kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
157 kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
158 kernel = np.transpose(kernel, [3, 0, 1, 2])
161 np.array([self.
op2code[node.op], dilation, padding, self.
conv_activations[activation], in_channels, out_channels, filter_height, has_bias], dtype=np.uint32).tofile(f)
164 btensor = bnode.attr[
'value'].tensor
165 if btensor.tensor_shape.dim[0].size == 1:
166 bias = struct.pack(
"f", btensor.float_val[0])
168 bias = btensor.tensor_content
172 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
174 if anode
is not None:
175 output_operand_index = self.
add_operand(anode.name, Operand.IOTYPE_OUTPUT)
177 output_operand_index = self.
add_operand(self.
edges[bnode.name][0].name, Operand.IOTYPE_OUTPUT)
178 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
182 assert(node.op ==
'Conv2D')
188 if node0.op ==
'Const':
190 input_name = node.input[1]
193 input_name = node.input[0]
195 ktensor = knode.attr[
'value'].tensor
196 filter_height = ktensor.tensor_shape.dim[0].size
197 filter_width = ktensor.tensor_shape.dim[1].size
198 in_channels = ktensor.tensor_shape.dim[2].size
199 out_channels = ktensor.tensor_shape.dim[3].size
200 if filter_height * filter_width * in_channels * out_channels == 1:
201 kernel = np.float32(ktensor.float_val[0])
203 kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
204 kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
205 kernel = np.transpose(kernel, [3, 0, 1, 2])
209 padding = node.attr[
'padding'].s.decode(
"utf-8")
211 in_channels, out_channels, filter_height, has_bias], dtype=np.uint32).tofile(f)
214 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
215 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
216 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
220 assert(node.op ==
'DepthToSpace')
222 block_size = node.attr[
'block_size'].i
223 np.array([self.
op2code[node.op], block_size], dtype=np.uint32).tofile(f)
225 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
226 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
227 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
231 assert(node.op ==
'MirrorPad')
233 mode = node.attr[
'mode'].s
235 np.array([self.
op2code[node.op], mode], dtype=np.uint32).tofile(f)
238 paddings = pnode.attr[
'value'].tensor.tensor_content
241 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
242 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
243 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
247 assert(node.op ==
'Maximum')
250 y = ynode.attr[
'value'].tensor.float_val[0]
251 np.array([self.
op2code[node.op]], dtype=np.uint32).tofile(f)
252 np.array([y], dtype=np.float32).tofile(f)
254 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
255 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
256 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
264 np.array([self.
op2code[
'MathBinary'], self.
mathbin2code[node.op]], dtype=np.uint32).tofile(f)
265 if i0_node.op ==
'Const':
266 scalar = i0_node.attr[
'value'].tensor.float_val[0]
267 np.array([1], dtype=np.uint32).tofile(f)
268 np.array([scalar], dtype=np.float32).tofile(f)
269 np.array([0], dtype=np.uint32).tofile(f)
270 input_operand_index = self.
add_operand(i1_node.name, Operand.IOTYPE_INPUT)
271 np.array([input_operand_index], dtype=np.uint32).tofile(f)
272 elif i1_node.op ==
'Const':
273 scalar = i1_node.attr[
'value'].tensor.float_val[0]
274 np.array([0], dtype=np.uint32).tofile(f)
275 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
276 np.array([input_operand_index], dtype=np.uint32).tofile(f)
277 np.array([1], dtype=np.uint32).tofile(f)
278 np.array([scalar], dtype=np.float32).tofile(f)
280 np.array([0], dtype=np.uint32).tofile(f)
281 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
282 np.array([input_operand_index], dtype=np.uint32).tofile(f)
283 np.array([0], dtype=np.uint32).tofile(f)
284 input_operand_index = self.
add_operand(i1_node.name, Operand.IOTYPE_INPUT)
285 np.array([input_operand_index], dtype=np.uint32).tofile(f)
286 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
287 np.array([output_operand_index], dtype=np.uint32).tofile(f)
294 np.array([self.
op2code[
'MathUnary'], self.
mathun2code[node.op]], dtype=np.uint32).tofile(f)
295 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
296 np.array([input_operand_index], dtype=np.uint32).tofile(f)
297 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
298 np.array([output_operand_index],dtype=np.uint32).tofile(f)
302 for node
in self.
nodes:
308 if node.op ==
'Conv2D':
312 if node.op ==
'Conv2D':
314 elif node.op ==
'DepthToSpace':
316 elif node.op ==
'MirrorPad':
318 elif node.op ==
'Maximum':
328 for operand
in operands:
330 np.array([operand.index,
len(operand.name)], dtype=np.uint32).tofile(f)
331 f.write(operand.name.encode(
'utf-8'))
332 np.array([operand.iotype, operand.dtype], dtype=np.uint32).tofile(f)
333 np.array([operand.dims[0], operand.dims[1], operand.dims[2], operand.dims[3]], dtype=np.uint32).tofile(f)
337 with open(self.
outfile,
'wb')
as f:
338 f.write(header.str.encode(
'utf-8'))
339 np.array([header.major, header.minor], dtype=np.uint32).tofile(f)
346 for node
in self.
nodes:
352 for node
in self.
nodes:
353 for input
in node.input:
354 used_names.append(input)
356 for node
in self.
nodes:
357 if node.name
not in used_names:
364 for node
in self.
nodes:
365 if node.op ==
'Identity':
367 input = node.input[0]
368 id_nodes.append(node)
375 id_dict[name] = input
377 for idnode
in id_nodes:
378 self.
nodes.remove(idnode)
380 for node
in self.
nodes:
381 for i
in range(
len(node.input)):
382 input = node.input[i]
384 node.input[i] = id_dict[input]
388 for node
in self.
nodes:
389 for input
in node.input:
390 if input
in self.
edges:
393 self.
edges[input] = [node]
398 index = name.rfind(
'/')
405 inner_scope = TFConverter.get_scope_name(name)
406 if inner_scope ==
"":
409 index = inner_scope.find(scope)
417 for node
in self.
nodes:
418 if node.op ==
'Conv2D':
419 scope = TFConverter.get_scope_name(node.name)
429 for node
in self.
nodes:
430 scope = TFConverter.get_scope_name(node.name)
432 if node.op ==
'Conv2D' or node.op ==
'Shape':
433 for inp
in node.input:
434 if TFConverter.get_scope_name(inp) != scope:
452 with open(infile,
'rb')
as f:
454 graph_def = tf.GraphDef()
455 graph_def.ParseFromString(f.read())
456 nodes = graph_def.node
458 converter =
TFConverter(graph_def, nodes, outfile, dump4tb)