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):
76 self.
op2code = {
'Conv2D':1,
'DepthToSpace':2,
'MirrorPad':3,
'Maximum':4,
77 'MathBinary':5,
'MathUnary':6,
'AvgPool':7,
'MatMul':8}
78 self.
mathbin2code = {
'Sub':0,
'Add':1,
'Mul':2,
'RealDiv':3,
'Minimum':4,
'FloorMod':5}
79 self.
mathun2code = {
'Abs':0,
'Sin':1,
'Cos':2,
'Tan':3,
'Asin':4,
80 'Acos':5,
'Atan':6,
'Sinh':7,
'Cosh':8,
'Tanh':9,
'Asinh':10,
81 'Acosh':11,
'Atanh':12,
'Ceil':13,
'Floor':14,
'Round':15}
89 dtype = node.attr[
'dtype'].type
91 dtype = node.attr[
'T'].type
93 if 'shape' in node.attr:
94 dims[0] = node.attr[
'shape'].shape.dim[0].size
95 dims[1] = node.attr[
'shape'].shape.dim[1].size
96 dims[2] = node.attr[
'shape'].shape.dim[2].size
97 dims[3] = node.attr[
'shape'].shape.dim[3].size
98 operand =
Operand(name, dtype, dims)
105 graph = tf.get_default_graph()
106 tf.import_graph_def(self.
graph_def, name=
"")
107 tf.summary.FileWriter(
'/tmp/graph', graph)
108 print(
'graph saved, run "tensorboard --logdir=/tmp/graph" to see it')
122 if conv2d_scope_name +
'/BiasAdd' in self.
edges:
123 anode = self.
edges[conv2d_scope_name +
'/BiasAdd'][0]
128 return knode, bnode, dnode, anode
133 bnode = self.name_node_dict.get(dense_scope_name +
'/bias')
138 if dense_scope_name +
'/BiasAdd' in self.
edges:
139 anode = self.
edges[dense_scope_name +
'/BiasAdd'][0]
144 return knode, bnode, anode
148 assert(node.op ==
'Conv2D')
150 self.converted_nodes.add(node.name)
152 scope_name = TFConverter.get_scope_name(node.name)
156 if dnode
is not None:
157 dilation = struct.unpack(
'i', dnode.attr[
'value'].tensor.tensor_content[0:4])[0]
161 if anode
is not None:
162 activation = anode.op
166 padding = node.attr[
'padding'].s.decode(
"utf-8")
173 ktensor = knode.attr[
'value'].tensor
174 filter_height = ktensor.tensor_shape.dim[0].size
175 filter_width = ktensor.tensor_shape.dim[1].size
176 in_channels = ktensor.tensor_shape.dim[2].size
177 out_channels = ktensor.tensor_shape.dim[3].size
178 kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
179 kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
180 kernel = np.transpose(kernel, [3, 0, 1, 2])
183 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)
186 btensor = bnode.attr[
'value'].tensor
187 if btensor.tensor_shape.dim[0].size == 1:
188 bias = struct.pack(
"f", btensor.float_val[0])
190 bias = btensor.tensor_content
194 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
196 if anode
is not None:
197 output_operand_index = self.
add_operand(anode.name, Operand.IOTYPE_OUTPUT)
199 output_operand_index = self.
add_operand(self.
edges[bnode.name][0].name, Operand.IOTYPE_OUTPUT)
200 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
203 assert(node.op ==
'MatMul')
205 self.converted_nodes.add(node.name)
207 scope_name = TFConverter.get_scope_name(node.name)
211 if bnode
is not None:
213 btensor = bnode.attr[
'value'].tensor
214 if btensor.tensor_shape.dim[0].size == 1:
215 bias = struct.pack(
"f", btensor.float_val[0])
217 bias = btensor.tensor_content
221 if anode
is not None:
222 activation = anode.op
226 ktensor = knode.attr[
'value'].tensor
227 in_channels = ktensor.tensor_shape.dim[0].size
228 out_channels = ktensor.tensor_shape.dim[1].size
229 if in_channels * out_channels == 1:
230 kernel = np.float32(ktensor.float_val[0])
232 kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
233 kernel = kernel.reshape(in_channels, out_channels)
234 kernel = np.transpose(kernel, [1, 0])
236 np.array([self.
op2code[node.op], self.
conv_activations[activation], in_channels, out_channels, has_bias], dtype=np.uint32).tofile(f)
242 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
244 if anode
is not None:
245 output_operand_index = self.
add_operand(anode.name, Operand.IOTYPE_OUTPUT)
247 if bnode
is not None:
248 output_operand_index = self.
add_operand(self.
edges[bnode.name][0].name, Operand.IOTYPE_OUTPUT)
250 output_operand_index = self.
add_operand(self.
edges[scope_name+
'/concat_1'][0].name, Operand.IOTYPE_OUTPUT)
251 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
255 assert(node.op ==
'Conv2D')
257 self.converted_nodes.add(node.name)
261 if node0.op ==
'Const':
263 input_name = node.input[1]
266 input_name = node.input[0]
268 ktensor = knode.attr[
'value'].tensor
269 filter_height = ktensor.tensor_shape.dim[0].size
270 filter_width = ktensor.tensor_shape.dim[1].size
271 in_channels = ktensor.tensor_shape.dim[2].size
272 out_channels = ktensor.tensor_shape.dim[3].size
273 if filter_height * filter_width * in_channels * out_channels == 1:
274 kernel = np.float32(ktensor.float_val[0])
276 kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
277 kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
278 kernel = np.transpose(kernel, [3, 0, 1, 2])
282 padding = node.attr[
'padding'].s.decode(
"utf-8")
284 in_channels, out_channels, filter_height, has_bias], dtype=np.uint32).tofile(f)
287 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
288 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
289 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
293 assert(node.op ==
'DepthToSpace')
295 block_size = node.attr[
'block_size'].i
296 np.array([self.
op2code[node.op], block_size], dtype=np.uint32).tofile(f)
297 self.converted_nodes.add(node.name)
298 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
299 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
300 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
304 assert(node.op ==
'MirrorPad')
306 mode = node.attr[
'mode'].s
308 np.array([self.
op2code[node.op], mode], dtype=np.uint32).tofile(f)
310 self.converted_nodes.add(pnode.name)
311 paddings = pnode.attr[
'value'].tensor.tensor_content
313 self.converted_nodes.add(node.name)
314 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
315 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
316 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
320 assert(node.op ==
'Maximum')
323 y = ynode.attr[
'value'].tensor.float_val[0]
324 np.array([self.
op2code[node.op]], dtype=np.uint32).tofile(f)
325 np.array([y], dtype=np.float32).tofile(f)
326 self.converted_nodes.add(node.name)
327 input_operand_index = self.
add_operand(node.input[0], Operand.IOTYPE_INPUT)
328 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
329 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
334 self.converted_nodes.add(node.name)
337 np.array([self.
op2code[
'MathBinary'], self.
mathbin2code[node.op]], dtype=np.uint32).tofile(f)
338 if i0_node.op ==
'Const':
339 scalar = i0_node.attr[
'value'].tensor.float_val[0]
340 np.array([1], dtype=np.uint32).tofile(f)
341 np.array([scalar], dtype=np.float32).tofile(f)
342 np.array([0], dtype=np.uint32).tofile(f)
343 input_operand_index = self.
add_operand(i1_node.name, Operand.IOTYPE_INPUT)
344 np.array([input_operand_index], dtype=np.uint32).tofile(f)
345 elif i1_node.op ==
'Const':
346 scalar = i1_node.attr[
'value'].tensor.float_val[0]
347 np.array([0], dtype=np.uint32).tofile(f)
348 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
349 np.array([input_operand_index], dtype=np.uint32).tofile(f)
350 np.array([1], dtype=np.uint32).tofile(f)
351 np.array([scalar], dtype=np.float32).tofile(f)
353 np.array([0], dtype=np.uint32).tofile(f)
354 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
355 np.array([input_operand_index], dtype=np.uint32).tofile(f)
356 np.array([0], dtype=np.uint32).tofile(f)
357 input_operand_index = self.
add_operand(i1_node.name, Operand.IOTYPE_INPUT)
358 np.array([input_operand_index], dtype=np.uint32).tofile(f)
359 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
360 np.array([output_operand_index], dtype=np.uint32).tofile(f)
365 self.converted_nodes.add(node.name)
367 np.array([self.
op2code[
'MathUnary'], self.
mathun2code[node.op]], dtype=np.uint32).tofile(f)
368 input_operand_index = self.
add_operand(i0_node.name, Operand.IOTYPE_INPUT)
369 np.array([input_operand_index], dtype=np.uint32).tofile(f)
370 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
371 np.array([output_operand_index],dtype=np.uint32).tofile(f)
375 assert(node.op ==
'AvgPool')
377 self.converted_nodes.add(node.name)
379 strides = node.attr[
'strides']
383 assert(strides.list.i[1]==strides.list.i[2])
384 assert(strides.list.i[0]==1)
385 assert(strides.list.i[3]==1)
386 strides = strides.list.i[1]
387 filter_node = node.attr[
'ksize']
388 input_name = node.input[0]
391 assert(filter_node.list.i[0]==1)
392 assert(filter_node.list.i[3]==1)
393 filter_height = filter_node.list.i[1]
394 filter_width = filter_node.list.i[2]
396 padding = node.attr[
'padding'].s.decode(
"utf-8")
398 dtype=np.uint32).tofile(f)
400 input_operand_index = self.
add_operand(input_name, Operand.IOTYPE_INPUT)
401 output_operand_index = self.
add_operand(node.name, Operand.IOTYPE_OUTPUT)
402 np.array([input_operand_index, output_operand_index],dtype=np.uint32).tofile(f)
406 for node
in self.
nodes:
412 if node.op ==
'Conv2D':
416 if node.op ==
'MatMul':
421 if node.op ==
'Conv2D':
426 if TFConverter.get_scope_name(input_name)!=TFConverter.get_scope_name(node.name):
428 if node.op ==
'AvgPool':
430 elif node.op ==
'DepthToSpace':
432 elif node.op ==
'MirrorPad':
434 elif node.op ==
'Maximum':
443 operands = sorted(self.name_operand_dict.values())
444 for operand
in operands:
446 np.array([operand.index,
len(operand.name)], dtype=np.uint32).tofile(f)
447 f.write(operand.name.encode(
'utf-8'))
448 np.array([operand.iotype, operand.dtype], dtype=np.uint32).tofile(f)
449 np.array(operand.dims, dtype=np.uint32).tofile(f)
453 with open(self.
outfile,
'wb')
as f:
454 f.write(header.str.encode(
'utf-8'))
455 np.array([header.major, header.minor], dtype=np.uint32).tofile(f)
462 for node
in self.
nodes:
468 for node
in self.
nodes:
469 for input
in node.input:
470 used_names.append(input)
472 for node
in self.
nodes:
473 if node.name
not in used_names:
474 self.output_names.append(node.name)
481 for node
in self.
nodes:
482 if node.op ==
'Identity':
484 input = node.input[0]
485 id_nodes.append(node)
493 id_dict[name] = input
495 for idnode
in id_nodes:
496 self.nodes.remove(idnode)
498 for node
in self.
nodes:
499 for i
in range(
len(node.input)):
500 input = node.input[i]
502 node.input[i] = id_dict[input]
506 for node
in self.
nodes:
507 for input
in node.input:
508 if input
in self.
edges:
511 self.
edges[input] = [node]
516 index = name.rfind(
'/')
523 inner_scope = TFConverter.get_scope_name(name)
524 if inner_scope ==
"":
527 index = inner_scope.find(scope)
534 inner_scope = TFConverter.get_scope_name(name)
535 if inner_scope ==
"":
538 index = inner_scope.find(scope)
545 for node
in self.
nodes:
546 if node.op ==
'Conv2D':
547 scope = TFConverter.get_scope_name(node.name)
554 self.conv2d_scope_names.add(scope)
555 elif node.op ==
'MatMul':
556 scope = TFConverter.get_scope_name(node.name)
563 self.dense_scope_names.add(scope.split(
'/Tensordot')[0])
566 for node
in self.
nodes:
567 scope = TFConverter.get_scope_name(node.name)
569 if node.op ==
'Conv2D' or node.op ==
'Shape':
570 for inp
in node.input:
571 if TFConverter.get_scope_name(inp) != scope:
574 if node.op ==
'MatMul' or node.op ==
'Shape':
575 for inp
in node.input:
576 if TFConverter.get_scope_name(inp) != scope:
579 if node.op ==
'Transpose':
580 for inp
in node.input:
581 if TFConverter.get_scope_name(inp).find(scope)<0
and TFConverter.get_scope_name(inp).find(scope.split(
'/')[0])<0:
599 with open(infile,
'rb')
as f:
601 graph_def = tf.GraphDef()
602 graph_def.ParseFromString(f.read())
603 nodes = graph_def.node
605 converter =
TFConverter(graph_def, nodes, outfile, dump4tb)
def dump_operands_to_file(self, f)
def dump_mathbinary_to_file(self, node, f)
def dump_mathunary_to_file(self, node, f)
def in_dense_scope(self, name)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate.The lists are not just lists
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
dense_scopename_inputname_dict
def generate_output_names(self)
def add_operand(self, name, type)
def dump_avg_pool_to_file(self, node, f)
static uint8_t * append(uint8_t *buf, const uint8_t *src, int size)
def dump_mirrorpad_to_file(self, node, f)
def __init__(self, name, dtype, dims)
def __init__(self, graph_def, nodes, outfile, dump4tb)
def generate_sub_block_op_scope_info(self)
def get_dense_params(self, dense_scope_name)
def get_conv2d_params(self, conv2d_scope_name)
def generate_name_node_dict(self)
def dump_layers_to_file(self, f)
conv2d_scopename_inputname_dict
def add_iotype(self, iotype)
def dump_complex_conv2d_to_file(self, node, f)
def dump_dense_to_file(self, node, f)
def dump_maximum_to_file(self, node, f)
def dump_for_tensorboard(self)
def in_conv2d_scope(self, name)
def convert_from_tensorflow(infile, outfile, dump4tb)
def dump_depth2space_to_file(self, node, f)
static void print(AVTreeNode *t, int depth)
def dump_simple_conv2d_to_file(self, node, f)
def remove_identity(self)