History

dnn: add tf.nn.conv2d support for native model

Unlike other tf.*.conv2d layers, tf.nn.conv2d does not create many nodes (within a scope) in the graph, it just acts like other layers. tf.nn.conv2d only creates one node in the graph, and no internal nodes such as 'kernel' are created. The format of native model file is also changed, a flag named has_bias is added, so change the version number.

Guo, Yejun committed 7 years ago

Commit dff39ea1 parent a269fa06 files · +82 −18Browse files

Showing the changes to tools/python/convert_from_tensorflow.py (1 of 6 files). Show all

Unified · Split

tools/python/convert_from_tensorflow.py+49−5
@@ -118,7 +118,7 @@ class TFConverter: · 117 unmodified lines
118118 return knode, bnode, dnode, anode
119119
120120
121− def dump_conv2d_to_file(self, node, f):
121+ def dump_complex_conv2d_to_file(self, node, f):
122122 assert(node.op == 'Conv2D')
123123 self.layer_number = self.layer_number + 1
124124 self.converted_nodes.add(node.name)
@@ -153,7 +153,8 @@ class TFConverter: · 28 unmodified lines
153153 kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
154154 kernel = np.transpose(kernel, [3, 0, 1, 2])
155155
156− np.array([self.op2code[node.op], dilation, padding, self.conv_activations[activation], in_channels, out_channels, filter_height], dtype=np.uint32).tofile(f)
156+ has_bias = 1
157+ 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)
157158 kernel.tofile(f)
158159
159160 btensor = bnode.attr['value'].tensor
@@ -173,6 +174,41 @@ class TFConverter: · 13 unmodified lines
173174 np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
174175
175176
177+ def dump_simple_conv2d_to_file(self, node, f):
178+ assert(node.op == 'Conv2D')
179+ self.layer_number = self.layer_number + 1
180+ self.converted_nodes.add(node.name)
181+
182+ node0 = self.name_node_dict[node.input[0]]
183+ node1 = self.name_node_dict[node.input[1]]
184+ if node0.op == 'Const':
185+ knode = node0
186+ input_name = node.input[1]
187+ else:
188+ knode = node1
189+ input_name = node.input[0]
190+
191+ ktensor = knode.attr['value'].tensor
192+ filter_height = ktensor.tensor_shape.dim[0].size
193+ filter_width = ktensor.tensor_shape.dim[1].size
194+ in_channels = ktensor.tensor_shape.dim[2].size
195+ out_channels = ktensor.tensor_shape.dim[3].size
196+ kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32)
197+ kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels)
198+ kernel = np.transpose(kernel, [3, 0, 1, 2])
199+
200+ has_bias = 0
201+ dilation = 1
202+ padding = node.attr['padding'].s.decode("utf-8")
203+ np.array([self.op2code[node.op], dilation, self.conv_paddings[padding], self.conv_activations['None'],
204+ in_channels, out_channels, filter_height, has_bias], dtype=np.uint32).tofile(f)
205+ kernel.tofile(f)
206+
207+ input_operand_index = self.add_operand(input_name, Operand.IOTYPE_INPUT)
208+ output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT)
209+ np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f)
210+
211+
176212 def dump_depth2space_to_file(self, node, f):
177213 assert(node.op == 'DepthToSpace')
178214 self.layer_number = self.layer_number + 1
@@ -222,10 +258,12 @@ class TFConverter: · 43 unmodified lines
222258 scope_name = TFConverter.get_scope_name(node.name)
223259 if scope_name in self.conv2d_scope_names:
224260 if node.op == 'Conv2D':
225− self.dump_conv2d_to_file(node, f)
261+ self.dump_complex_conv2d_to_file(node, f)
226262 continue
227263
228− if node.op == 'DepthToSpace':
264+ if node.op == 'Conv2D':
265+ self.dump_simple_conv2d_to_file(node, f)
266+ elif node.op == 'DepthToSpace':
229267 self.dump_depth2space_to_file(node, f)
230268 elif node.op == 'MirrorPad':
231269 self.dump_mirrorpad_to_file(node, f)
@@ -312,10 +350,16 @@ class TFConverter: · 80 unmodified lines
312350
313351
314352 def generate_conv2d_scope_info(self):
315− # conv2d is a sub block in graph, get the scope name
353+ # mostly, conv2d is a sub block in graph, get the scope name
316354 for node in self.nodes:
317355 if node.op == 'Conv2D':
318356 scope = TFConverter.get_scope_name(node.name)
357+ # for the case tf.nn.conv2d is called directly
358+ if scope == '':
359+ continue
360+ # for the case tf.nn.conv2d is called within a scope
361+ if scope + '/kernel' not in self.name_node_dict:
362+ continue
319363 self.conv2d_scope_names.add(scope)
320364
321365 # get the input name to the conv2d sub block

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t