FFmpeg
convert_from_tensorflow.py
Go to the documentation of this file.
1 # Copyright (c) 2019 Guo Yejun
2 #
3 # This file is part of FFmpeg.
4 #
5 # FFmpeg is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
9 #
10 # FFmpeg is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with FFmpeg; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 # ==============================================================================
19 
20 import tensorflow as tf
21 import numpy as np
22 import sys, struct
23 import convert_header as header
24 
25 __all__ = ['convert_from_tensorflow']
26 
27 class Operand(object):
28  IOTYPE_INPUT = 1
29  IOTYPE_OUTPUT = 2
30  IOTYPE_INTERMEDIATE = IOTYPE_INPUT | IOTYPE_OUTPUT
31  DTYPE_FLOAT = 1
32  DTYPE_UINT8 = 4
33  index = 0
34  def __init__(self, name, dtype, dims):
35  self.name = name
36  self.dtype = dtype
37  self.dims = dims
38  self.iotype = 0
39  self.used_count = 0
40  self.index = Operand.index
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'}
44 
45  def add_iotype(self, iotype):
46  self.iotype = self.iotype | iotype
47  if iotype == Operand.IOTYPE_INPUT:
48  self.used_count = self.used_count + 1
49 
50  def __str__(self):
51  return "{}: (name: {}, iotype: {}, dtype: {}, dims: {}, used_count: {})".format(self.index,
52  self.name, self.iotype2str[self.iotype], self.dtype2str[self.dtype],
53  self.dims, self.used_count)
54 
55  def __lt__(self, other):
56  return self.index < other.index
57 
59  def __init__(self, graph_def, nodes, outfile, dump4tb):
60  self.graph_def = graph_def
61  self.nodes = nodes
62  self.outfile = outfile
63  self.dump4tb = dump4tb
64  self.layer_number = 0
65  self.output_names = []
66  self.name_node_dict = {}
67  self.edges = {}
68  self.conv_activations = {'Relu':0, 'Tanh':1, 'Sigmoid':2, 'None':3, 'LeakyRelu':4}
69  self.conv_paddings = {'VALID':0, 'SAME':1}
70  self.pool_paddings = {'VALID':0, 'SAME':1}
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,
82  'Exp':16}
83  self.mirrorpad_mode = {'CONSTANT':0, 'REFLECT':1, 'SYMMETRIC':2}
85 
86 
87  def add_operand(self, name, type):
88  node = self.name_node_dict[name]
89  if name not in self.name_operand_dict:
90  dtype = node.attr['dtype'].type
91  if dtype == 0:
92  dtype = node.attr['T'].type
93  dims = [-1,-1,-1,-1]
94  if 'shape' in node.attr:
95  dims[0] = node.attr['shape'].shape.dim[0].size
96  dims[1] = node.attr['shape'].shape.dim[1].size
97  dims[2] = node.attr['shape'].shape.dim[2].size
98  dims[3] = node.attr['shape'].shape.dim[3].size
99  operand = Operand(name, dtype, dims)
100  self.name_operand_dict[name] = operand;
101  self.name_operand_dict[name].add_iotype(type)
102  return self.name_operand_dict[name].index
103 
104 
106  graph = tf.get_default_graph()
107  tf.import_graph_def(self.graph_def, name="")
108  tf.summary.FileWriter('/tmp/graph', graph)
109  print('graph saved, run "tensorboard --logdir=/tmp/graph" to see it')
110 
111 
112  def get_conv2d_params(self, conv2d_scope_name):
113  knode = self.name_node_dict[conv2d_scope_name + '/kernel']
114  bnode = self.name_node_dict[conv2d_scope_name + '/bias']
115 
116  if conv2d_scope_name + '/dilation_rate' in self.name_node_dict:
117  dnode = self.name_node_dict[conv2d_scope_name + '/dilation_rate']
118  else:
119  dnode = None
120 
121  # the BiasAdd name is possible be changed into the output name,
122  # if activation is None, and BiasAdd.next is the last op which is Identity
123  if conv2d_scope_name + '/BiasAdd' in self.edges:
124  anode = self.edges[conv2d_scope_name + '/BiasAdd'][0]
125  if anode.op not in self.conv_activations:
126  anode = None
127  else:
128  anode = None
129  return knode, bnode, dnode, anode
130 
131 
132  def get_dense_params(self, dense_scope_name):
133  knode = self.name_node_dict[dense_scope_name + '/kernel']
134  bnode = self.name_node_dict.get(dense_scope_name + '/bias')
135  # the BiasAdd name is possible be changed into the output name,
136  # if activation is None, and BiasAdd.next is the last op which is Identity
137  anode = None
138  if bnode:
139  if dense_scope_name + '/BiasAdd' in self.edges:
140  anode = self.edges[dense_scope_name + '/BiasAdd'][0]
141  if anode.op not in self.conv_activations:
142  anode = None
143  else:
144  anode = None
145  return knode, bnode, anode
146 
147 
148  def dump_complex_conv2d_to_file(self, node, f):
149  assert(node.op == 'Conv2D')
150  self.layer_number = self.layer_number + 1
151  self.converted_nodes.add(node.name)
152 
153  scope_name = TFConverter.get_scope_name(node.name)
154  #knode for kernel, bnode for bias, dnode for dilation, anode for activation
155  knode, bnode, dnode, anode = self.get_conv2d_params(scope_name)
156 
157  if dnode is not None:
158  dilation = struct.unpack('i', dnode.attr['value'].tensor.tensor_content[0:4])[0]
159  else:
160  dilation = 1
161 
162  if anode is not None:
163  activation = anode.op
164  else:
165  activation = 'None'
166 
167  padding = node.attr['padding'].s.decode("utf-8")
168  # conv2d with dilation > 1 generates tens of nodes, not easy to parse them, so use this tricky method.
169  if dilation > 1 and scope_name + '/stack' in self.name_node_dict:
170  if self.name_node_dict[scope_name + '/stack'].op == "Const":
171  padding = 'SAME'
172  padding = self.conv_paddings[padding]
173 
174  ktensor = knode.attr['value'].tensor
175  filter_height = ktensor.tensor_shape.dim[0].size
176  filter_width = ktensor.tensor_shape.dim[1].size
177  in_channels = ktensor.tensor_shape.dim[2].size
178  out_channels = ktensor.tensor_shape.dim[3].size
179  kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
180  kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
181  kernel = np.transpose(kernel, [3, 0, 1, 2])
182 
183  has_bias = 1
184  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)
185  kernel.tofile(f)
186 
187  btensor = bnode.attr['value'].tensor
188  if btensor.tensor_shape.dim[0].size == 1:
189  bias = struct.pack("f", btensor.float_val[0])
190  else:
191  bias = btensor.tensor_content
192  f.write(bias)
193 
194  input_name = self.conv2d_scopename_inputname_dict[scope_name]
195  input_operand_index = self.add_operand(input_name, Operand.IOTYPE_INPUT)
196 
197  if anode is not None:
198  output_operand_index = self.add_operand(anode.name, Operand.IOTYPE_OUTPUT)
199  else:
200  output_operand_index = self.add_operand(self.edges[bnode.name][0].name, Operand.IOTYPE_OUTPUT)
201  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
202 
203  def dump_dense_to_file(self, node, f):
204  assert(node.op == 'MatMul')
205  self.layer_number = self.layer_number + 1
206  self.converted_nodes.add(node.name)
207 
208  scope_name = TFConverter.get_scope_name(node.name)
209  #knode for kernel, bnode for bias, anode for activation
210  knode, bnode, anode = self.get_dense_params(scope_name.split('/')[0])
211 
212  if bnode is not None:
213  has_bias = 1
214  btensor = bnode.attr['value'].tensor
215  if btensor.tensor_shape.dim[0].size == 1:
216  bias = struct.pack("f", btensor.float_val[0])
217  else:
218  bias = btensor.tensor_content
219  else:
220  has_bias = 0
221 
222  if anode is not None:
223  activation = anode.op
224  else:
225  activation = 'None'
226 
227  ktensor = knode.attr['value'].tensor
228  in_channels = ktensor.tensor_shape.dim[0].size
229  out_channels = ktensor.tensor_shape.dim[1].size
230  if in_channels * out_channels == 1:
231  kernel = np.float32(ktensor.float_val[0])
232  else:
233  kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
234  kernel = kernel.reshape(in_channels, out_channels)
235  kernel = np.transpose(kernel, [1, 0])
236 
237  np.array([self.op2code[node.op], self.conv_activations[activation], in_channels, out_channels, has_bias], dtype=np.uint32).tofile(f)
238  kernel.tofile(f)
239  if has_bias:
240  f.write(bias)
241 
242  input_name = self.dense_scopename_inputname_dict[scope_name.split('/')[0]]
243  input_operand_index = self.add_operand(input_name, Operand.IOTYPE_INPUT)
244 
245  if anode is not None:
246  output_operand_index = self.add_operand(anode.name, Operand.IOTYPE_OUTPUT)
247  else:
248  if bnode is not None:
249  output_operand_index = self.add_operand(self.edges[bnode.name][0].name, Operand.IOTYPE_OUTPUT)
250  else:
251  output_operand_index = self.add_operand(self.edges[scope_name+'/concat_1'][0].name, Operand.IOTYPE_OUTPUT)
252  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
253 
254 
255  def dump_simple_conv2d_to_file(self, node, f):
256  assert(node.op == 'Conv2D')
257  self.layer_number = self.layer_number + 1
258  self.converted_nodes.add(node.name)
259 
260  node0 = self.name_node_dict[node.input[0]]
261  node1 = self.name_node_dict[node.input[1]]
262  if node0.op == 'Const':
263  knode = node0
264  input_name = node.input[1]
265  else:
266  knode = node1
267  input_name = node.input[0]
268 
269  ktensor = knode.attr['value'].tensor
270  filter_height = ktensor.tensor_shape.dim[0].size
271  filter_width = ktensor.tensor_shape.dim[1].size
272  in_channels = ktensor.tensor_shape.dim[2].size
273  out_channels = ktensor.tensor_shape.dim[3].size
274  if filter_height * filter_width * in_channels * out_channels == 1:
275  kernel = np.float32(ktensor.float_val[0])
276  else:
277  kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
278  kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
279  kernel = np.transpose(kernel, [3, 0, 1, 2])
280 
281  has_bias = 0
282  dilation = 1
283  padding = node.attr['padding'].s.decode("utf-8")
284  np.array([self.op2code[node.op], dilation, self.conv_paddings[padding], self.conv_activations['None'],
285  in_channels, out_channels, filter_height, has_bias], dtype=np.uint32).tofile(f)
286  kernel.tofile(f)
287 
288  input_operand_index = self.add_operand(input_name, Operand.IOTYPE_INPUT)
289  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
290  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
291 
292 
293  def dump_depth2space_to_file(self, node, f):
294  assert(node.op == 'DepthToSpace')
295  self.layer_number = self.layer_number + 1
296  block_size = node.attr['block_size'].i
297  np.array([self.op2code[node.op], block_size], dtype=np.uint32).tofile(f)
298  self.converted_nodes.add(node.name)
299  input_operand_index = self.add_operand(node.input[0], Operand.IOTYPE_INPUT)
300  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
301  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
302 
303 
304  def dump_mirrorpad_to_file(self, node, f):
305  assert(node.op == 'MirrorPad')
306  self.layer_number = self.layer_number + 1
307  mode = node.attr['mode'].s
308  mode = self.mirrorpad_mode[mode.decode("utf-8")]
309  np.array([self.op2code[node.op], mode], dtype=np.uint32).tofile(f)
310  pnode = self.name_node_dict[node.input[1]]
311  self.converted_nodes.add(pnode.name)
312  paddings = pnode.attr['value'].tensor.tensor_content
313  f.write(paddings)
314  self.converted_nodes.add(node.name)
315  input_operand_index = self.add_operand(node.input[0], Operand.IOTYPE_INPUT)
316  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
317  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
318 
319 
320  def dump_maximum_to_file(self, node, f):
321  assert(node.op == 'Maximum')
322  self.layer_number = self.layer_number + 1
323  ynode = self.name_node_dict[node.input[1]]
324  y = ynode.attr['value'].tensor.float_val[0]
325  np.array([self.op2code[node.op]], dtype=np.uint32).tofile(f)
326  np.array([y], dtype=np.float32).tofile(f)
327  self.converted_nodes.add(node.name)
328  input_operand_index = self.add_operand(node.input[0], Operand.IOTYPE_INPUT)
329  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
330  np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
331 
332 
333  def dump_mathbinary_to_file(self, node, f):
334  self.layer_number = self.layer_number + 1
335  self.converted_nodes.add(node.name)
336  i0_node = self.name_node_dict[node.input[0]]
337  i1_node = self.name_node_dict[node.input[1]]
338  np.array([self.op2code['MathBinary'], self.mathbin2code[node.op]], dtype=np.uint32).tofile(f)
339  if i0_node.op == 'Const':
340  scalar = i0_node.attr['value'].tensor.float_val[0]
341  np.array([1], dtype=np.uint32).tofile(f) # broadcast: 1
342  np.array([scalar], dtype=np.float32).tofile(f)
343  np.array([0], dtype=np.uint32).tofile(f) # broadcast: 0
344  input_operand_index = self.add_operand(i1_node.name, Operand.IOTYPE_INPUT)
345  np.array([input_operand_index], dtype=np.uint32).tofile(f)
346  elif i1_node.op == 'Const':
347  scalar = i1_node.attr['value'].tensor.float_val[0]
348  np.array([0], dtype=np.uint32).tofile(f)
349  input_operand_index = self.add_operand(i0_node.name, Operand.IOTYPE_INPUT)
350  np.array([input_operand_index], dtype=np.uint32).tofile(f)
351  np.array([1], dtype=np.uint32).tofile(f)
352  np.array([scalar], dtype=np.float32).tofile(f)
353  else:
354  np.array([0], dtype=np.uint32).tofile(f)
355  input_operand_index = self.add_operand(i0_node.name, Operand.IOTYPE_INPUT)
356  np.array([input_operand_index], dtype=np.uint32).tofile(f)
357  np.array([0], dtype=np.uint32).tofile(f)
358  input_operand_index = self.add_operand(i1_node.name, Operand.IOTYPE_INPUT)
359  np.array([input_operand_index], dtype=np.uint32).tofile(f)
360  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
361  np.array([output_operand_index], dtype=np.uint32).tofile(f)
362 
363 
364  def dump_mathunary_to_file(self, node, f):
365  self.layer_number = self.layer_number + 1
366  self.converted_nodes.add(node.name)
367  i0_node = self.name_node_dict[node.input[0]]
368  np.array([self.op2code['MathUnary'], self.mathun2code[node.op]], dtype=np.uint32).tofile(f)
369  input_operand_index = self.add_operand(i0_node.name, Operand.IOTYPE_INPUT)
370  np.array([input_operand_index], dtype=np.uint32).tofile(f)
371  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
372  np.array([output_operand_index],dtype=np.uint32).tofile(f)
373 
374 
375  def dump_avg_pool_to_file(self, node, f):
376  assert(node.op == 'AvgPool')
377  self.layer_number = self.layer_number + 1
378  self.converted_nodes.add(node.name)
379  node0 = self.name_node_dict[node.input[0]]
380  strides = node.attr['strides']
381 
382  # Tensorflow do not support pooling strides in batch dimension and
383  # current native NN do not support pooling strides in channel dimension, added assert() here.
384  assert(strides.list.i[1]==strides.list.i[2])
385  assert(strides.list.i[0]==1)
386  assert(strides.list.i[3]==1)
387  strides = strides.list.i[1]
388  filter_node = node.attr['ksize']
389  input_name = node.input[0]
390 
391  # Tensorflow do not support pooling ksize in batch dimension and channel dimension.
392  assert(filter_node.list.i[0]==1)
393  assert(filter_node.list.i[3]==1)
394  filter_height = filter_node.list.i[1]
395  filter_width = filter_node.list.i[2]
396 
397  padding = node.attr['padding'].s.decode("utf-8")
398  np.array([self.op2code[node.op], strides, self.pool_paddings[padding], filter_height],
399  dtype=np.uint32).tofile(f)
400 
401  input_operand_index = self.add_operand(input_name, Operand.IOTYPE_INPUT)
402  output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
403  np.array([input_operand_index, output_operand_index],dtype=np.uint32).tofile(f)
404 
405 
406  def dump_layers_to_file(self, f):
407  for node in self.nodes:
408  if node.name in self.converted_nodes:
409  continue
410 
411  # conv2d with dilation generates very complex nodes, so handle it in special
412  if self.in_conv2d_scope(node.name):
413  if node.op == 'Conv2D':
414  self.dump_complex_conv2d_to_file(node, f)
415  continue
416  if self.in_dense_scope(node.name):
417  if node.op == 'MatMul':
418  self.dump_dense_to_file(node, f)
419  continue
420 
421 
422  if node.op == 'Conv2D':
423  self.dump_simple_conv2d_to_file(node, f)
424  continue
425  if node.name in self.output_names:
426  input_name = self.id_different_scope_dict[node.name]
427  if TFConverter.get_scope_name(input_name)!=TFConverter.get_scope_name(node.name):
428  continue
429  if node.op == 'AvgPool':
430  self.dump_avg_pool_to_file(node, f)
431  elif node.op == 'DepthToSpace':
432  self.dump_depth2space_to_file(node, f)
433  elif node.op == 'MirrorPad':
434  self.dump_mirrorpad_to_file(node, f)
435  elif node.op == 'Maximum':
436  self.dump_maximum_to_file(node, f)
437  elif node.op in self.mathbin2code:
438  self.dump_mathbinary_to_file(node, f)
439  elif node.op in self.mathun2code:
440  self.dump_mathunary_to_file(node, f)
441 
442 
443  def dump_operands_to_file(self, f):
444  operands = sorted(self.name_operand_dict.values())
445  for operand in operands:
446  #print('{}'.format(operand))
447  np.array([operand.index, len(operand.name)], dtype=np.uint32).tofile(f)
448  f.write(operand.name.encode('utf-8'))
449  np.array([operand.iotype, operand.dtype], dtype=np.uint32).tofile(f)
450  np.array(operand.dims, dtype=np.uint32).tofile(f)
451 
452 
453  def dump_to_file(self):
454  with open(self.outfile, 'wb') as f:
455  f.write(header.str.encode('utf-8'))
456  np.array([header.major, header.minor], dtype=np.uint32).tofile(f)
457  self.dump_layers_to_file(f)
458  self.dump_operands_to_file(f)
459  np.array([self.layer_number, len(self.name_operand_dict)], dtype=np.uint32).tofile(f)
460 
461 
463  for node in self.nodes:
464  self.name_node_dict[node.name] = node
465 
466 
468  used_names = []
469  for node in self.nodes:
470  for input in node.input:
471  used_names.append(input)
472 
473  for node in self.nodes:
474  if node.name not in used_names:
475  self.output_names.append(node.name)
476 
477 
478  def remove_identity(self):
480  id_nodes = []
481  id_dict = {}
482  for node in self.nodes:
483  if node.op == 'Identity':
484  name = node.name
485  input = node.input[0]
486  id_nodes.append(node)
487  # do not change the output name
488  if name in self.output_names:
489  self.name_node_dict[input].name = name
490  self.name_node_dict[name] = self.name_node_dict[input]
491  del self.name_node_dict[input]
492  self.id_different_scope_dict[name] = input
493  else:
494  id_dict[name] = input
495 
496  for idnode in id_nodes:
497  self.nodes.remove(idnode)
498 
499  for node in self.nodes:
500  for i in range(len(node.input)):
501  input = node.input[i]
502  if input in id_dict:
503  node.input[i] = id_dict[input]
504 
505 
506  def generate_edges(self):
507  for node in self.nodes:
508  for input in node.input:
509  if input in self.edges:
510  self.edges[input].append(node)
511  else:
512  self.edges[input] = [node]
513 
514 
515  @staticmethod
516  def get_scope_name(name):
517  index = name.rfind('/')
518  if index == -1:
519  return ""
520  return name[0:index]
521 
522 
523  def in_conv2d_scope(self, name):
524  inner_scope = TFConverter.get_scope_name(name)
525  if inner_scope == "":
526  return False;
527  for scope in self.conv2d_scope_names:
528  index = inner_scope.find(scope)
529  if index == 0:
530  return True
531  return False
532 
533 
534  def in_dense_scope(self, name):
535  inner_scope = TFConverter.get_scope_name(name)
536  if inner_scope == "":
537  return False;
538  for scope in self.dense_scope_names:
539  index = inner_scope.find(scope)
540  if index == 0:
541  return True
542  return False
543 
545  # mostly, conv2d/dense is a sub block in graph, get the scope name
546  for node in self.nodes:
547  if node.op == 'Conv2D':
548  scope = TFConverter.get_scope_name(node.name)
549  # for the case tf.nn.conv2d is called directly
550  if scope == '':
551  continue
552  # for the case tf.nn.conv2d is called within a scope
553  if scope + '/kernel' not in self.name_node_dict:
554  continue
555  self.conv2d_scope_names.add(scope)
556  elif node.op == 'MatMul':
557  scope = TFConverter.get_scope_name(node.name)
558  # for the case tf.nn.dense is called directly
559  if scope == '':
560  continue
561  # for the case tf.nn.dense is called within a scope
562  if scope + '/kernel' not in self.name_node_dict and scope.split('/Tensordot')[0] + '/kernel' not in self.name_node_dict:
563  continue
564  self.dense_scope_names.add(scope.split('/Tensordot')[0])
565 
566  # get the input name to the conv2d/dense sub block
567  for node in self.nodes:
568  scope = TFConverter.get_scope_name(node.name)
569  if scope in self.conv2d_scope_names:
570  if node.op == 'Conv2D' or node.op == 'Shape':
571  for inp in node.input:
572  if TFConverter.get_scope_name(inp) != scope:
573  self.conv2d_scopename_inputname_dict[scope] = inp
574  elif scope in self.dense_scope_names:
575  if node.op == 'MatMul' or node.op == 'Shape':
576  for inp in node.input:
577  if TFConverter.get_scope_name(inp) != scope:
578  self.dense_scopename_inputname_dict[scope] = inp
579  elif scope.split('/Tensordot')[0] in self.dense_scope_names:
580  if node.op == 'Transpose':
581  for inp in node.input:
582  if TFConverter.get_scope_name(inp).find(scope)<0 and TFConverter.get_scope_name(inp).find(scope.split('/')[0])<0:
583  self.dense_scopename_inputname_dict[scope.split('/Tensordot')[0]] = inp
584 
585 
586  def run(self):
588  self.generate_output_names()
589  self.remove_identity()
590  self.generate_edges()
592 
593  if self.dump4tb:
594  self.dump_for_tensorboard()
595 
596  self.dump_to_file()
597 
598 
599 def convert_from_tensorflow(infile, outfile, dump4tb):
600  with open(infile, 'rb') as f:
601  # read the file in .proto format
602  graph_def = tf.GraphDef()
603  graph_def.ParseFromString(f.read())
604  nodes = graph_def.node
605 
606  converter = TFConverter(graph_def, nodes, outfile, dump4tb)
607  converter.run()
convert_from_tensorflow.TFConverter.dump_avg_pool_to_file
def dump_avg_pool_to_file(self, node, f)
Definition: convert_from_tensorflow.py:375
append
static uint8_t * append(uint8_t *buf, const uint8_t *src, int size)
Definition: mjpeg2jpeg_bsf.c:59
convert_from_tensorflow.Operand.dtype
dtype
Definition: convert_from_tensorflow.py:36
convert_from_tensorflow.TFConverter.conv_activations
conv_activations
Definition: convert_from_tensorflow.py:68
convert_from_tensorflow.TFConverter.generate_name_node_dict
def generate_name_node_dict(self)
Definition: convert_from_tensorflow.py:462
convert_from_tensorflow.TFConverter.get_scope_name
def get_scope_name(name)
Definition: convert_from_tensorflow.py:516
convert_from_tensorflow.TFConverter.__init__
def __init__(self, graph_def, nodes, outfile, dump4tb)
Definition: convert_from_tensorflow.py:59
convert_from_tensorflow.TFConverter.name_operand_dict
name_operand_dict
Definition: convert_from_tensorflow.py:84
convert_from_tensorflow.Operand.__str__
def __str__(self)
Definition: convert_from_tensorflow.py:50
convert_from_tensorflow.TFConverter.dense_scopename_inputname_dict
dense_scopename_inputname_dict
Definition: convert_from_tensorflow.py:75
convert_from_tensorflow.TFConverter.mathun2code
mathun2code
Definition: convert_from_tensorflow.py:79
convert_from_tensorflow.TFConverter.layer_number
layer_number
Definition: convert_from_tensorflow.py:64
convert_from_tensorflow.TFConverter.add_operand
def add_operand(self, name, type)
Definition: convert_from_tensorflow.py:87
convert_from_tensorflow.TFConverter.nodes
nodes
Definition: convert_from_tensorflow.py:61
convert_from_tensorflow.TFConverter.dump_mathbinary_to_file
def dump_mathbinary_to_file(self, node, f)
Definition: convert_from_tensorflow.py:333
convert_from_tensorflow.Operand
Definition: convert_from_tensorflow.py:27
convert_from_tensorflow.TFConverter.edges
edges
Definition: convert_from_tensorflow.py:67
convert_from_tensorflow.TFConverter.graph_def
graph_def
Definition: convert_from_tensorflow.py:60
convert_from_tensorflow.Operand.dtype2str
dtype2str
Definition: convert_from_tensorflow.py:43
convert_from_tensorflow.TFConverter.id_different_scope_dict
id_different_scope_dict
Definition: convert_from_tensorflow.py:479
convert_from_tensorflow.TFConverter.conv2d_scope_names
conv2d_scope_names
Definition: convert_from_tensorflow.py:72
set
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
Definition: swresample.c:59
format
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
convert_from_tensorflow.TFConverter.dense_scope_names
dense_scope_names
Definition: convert_from_tensorflow.py:74
convert_from_tensorflow.TFConverter.dump_simple_conv2d_to_file
def dump_simple_conv2d_to_file(self, node, f)
Definition: convert_from_tensorflow.py:255
convert_from_tensorflow.TFConverter.converted_nodes
converted_nodes
Definition: convert_from_tensorflow.py:71
convert_from_tensorflow.TFConverter.output_names
output_names
Definition: convert_from_tensorflow.py:65
convert_from_tensorflow.TFConverter.outfile
outfile
Definition: convert_from_tensorflow.py:62
convert_from_tensorflow.TFConverter.dump_depth2space_to_file
def dump_depth2space_to_file(self, node, f)
Definition: convert_from_tensorflow.py:293
convert_from_tensorflow.TFConverter.mirrorpad_mode
mirrorpad_mode
Definition: convert_from_tensorflow.py:83
get
static void get(const uint8_t *pixels, int stride, int16_t *block)
Definition: proresenc_anatoliy.c:307
convert_from_tensorflow.TFConverter.in_conv2d_scope
def in_conv2d_scope(self, name)
Definition: convert_from_tensorflow.py:523
convert_from_tensorflow.Operand.__init__
def __init__(self, name, dtype, dims)
Definition: convert_from_tensorflow.py:34
convert_from_tensorflow.TFConverter.dump_mirrorpad_to_file
def dump_mirrorpad_to_file(self, node, f)
Definition: convert_from_tensorflow.py:304
convert_from_tensorflow.TFConverter.pool_paddings
pool_paddings
Definition: convert_from_tensorflow.py:70
convert_from_tensorflow.TFConverter.remove_identity
def remove_identity(self)
Definition: convert_from_tensorflow.py:478
convert_from_tensorflow.Operand.used_count
used_count
Definition: convert_from_tensorflow.py:39
convert_from_tensorflow.TFConverter.dump_layers_to_file
def dump_layers_to_file(self, f)
Definition: convert_from_tensorflow.py:406
convert_from_tensorflow.Operand.__lt__
def __lt__(self, other)
Definition: convert_from_tensorflow.py:55
print
static void print(AVTreeNode *t, int depth)
Definition: tree.c:44
convert_from_tensorflow.TFConverter.generate_sub_block_op_scope_info
def generate_sub_block_op_scope_info(self)
Definition: convert_from_tensorflow.py:544
convert_from_tensorflow.TFConverter.dump_dense_to_file
def dump_dense_to_file(self, node, f)
Definition: convert_from_tensorflow.py:203
convert_from_tensorflow.TFConverter.get_conv2d_params
def get_conv2d_params(self, conv2d_scope_name)
Definition: convert_from_tensorflow.py:112
convert_from_tensorflow.Operand.iotype2str
iotype2str
Definition: convert_from_tensorflow.py:42
convert_from_tensorflow.TFConverter.in_dense_scope
def in_dense_scope(self, name)
Definition: convert_from_tensorflow.py:534
convert_from_tensorflow.TFConverter.dump4tb
dump4tb
Definition: convert_from_tensorflow.py:63
convert_from_tensorflow.TFConverter.mathbin2code
mathbin2code
Definition: convert_from_tensorflow.py:78
convert_from_tensorflow.TFConverter.op2code
op2code
Definition: convert_from_tensorflow.py:76
convert_from_tensorflow.TFConverter.dump_for_tensorboard
def dump_for_tensorboard(self)
Definition: convert_from_tensorflow.py:105
len
int len
Definition: vorbis_enc_data.h:426
convert_from_tensorflow.TFConverter.conv2d_scopename_inputname_dict
conv2d_scopename_inputname_dict
Definition: convert_from_tensorflow.py:73
convert_from_tensorflow.Operand.add_iotype
def add_iotype(self, iotype)
Definition: convert_from_tensorflow.py:45
convert_from_tensorflow.Operand.iotype
iotype
Definition: convert_from_tensorflow.py:38
convert_from_tensorflow.TFConverter.dump_complex_conv2d_to_file
def dump_complex_conv2d_to_file(self, node, f)
Definition: convert_from_tensorflow.py:148
convert_from_tensorflow.TFConverter.run
def run(self)
Definition: convert_from_tensorflow.py:586
convert_from_tensorflow.TFConverter.name_node_dict
name_node_dict
Definition: convert_from_tensorflow.py:66
convert_from_tensorflow.Operand.index
int index
Definition: convert_from_tensorflow.py:33
convert_from_tensorflow.Operand.dims
dims
Definition: convert_from_tensorflow.py:37
convert_from_tensorflow.TFConverter.generate_output_names
def generate_output_names(self)
Definition: convert_from_tensorflow.py:467
values
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return values
Definition: filter_design.txt:263
convert_from_tensorflow.TFConverter.generate_edges
def generate_edges(self)
Definition: convert_from_tensorflow.py:506
convert_from_tensorflow.TFConverter
Definition: convert_from_tensorflow.py:58
add
static float add(float src0, float src1)
Definition: dnn_backend_native_layer_mathbinary.c:35
convert_from_tensorflow.Operand.name
name
Definition: convert_from_tensorflow.py:35
convert_from_tensorflow.TFConverter.conv_paddings
conv_paddings
Definition: convert_from_tensorflow.py:69
convert_from_tensorflow.convert_from_tensorflow
def convert_from_tensorflow(infile, outfile, dump4tb)
Definition: convert_from_tensorflow.py:599
convert_from_tensorflow.TFConverter.dump_maximum_to_file
def dump_maximum_to_file(self, node, f)
Definition: convert_from_tensorflow.py:320
convert_from_tensorflow.TFConverter.dump_mathunary_to_file
def dump_mathunary_to_file(self, node, f)
Definition: convert_from_tensorflow.py:364
convert_from_tensorflow.TFConverter.get_dense_params
def get_dense_params(self, dense_scope_name)
Definition: convert_from_tensorflow.py:132
convert_from_tensorflow.TFConverter.dump_to_file
def dump_to_file(self)
Definition: convert_from_tensorflow.py:453
convert_from_tensorflow.TFConverter.dump_operands_to_file
def dump_operands_to_file(self, f)
Definition: convert_from_tensorflow.py:443