more math binary operations will be added here
Showing the changes to tools/python (2 of 7 files). Show all
Unified · Split
| @@ -70,7 +70,8 @@ class TFConverter: · 69 unmodified lines | ||
| 70 | 70 | self.converted_nodes = set() |
| 71 | 71 | self.conv2d_scope_names = set() |
| 72 | 72 | self.conv2d_scopename_inputname_dict = {} |
| 73 | − self.op2code = {'Conv2D':1, 'DepthToSpace':2, 'MirrorPad':3, 'Maximum':4} | |
| 73 | + self.op2code = {'Conv2D':1, 'DepthToSpace':2, 'MirrorPad':3, 'Maximum':4, 'MathBinary':5} | |
| 74 | + self.mathbin2code = {'Sub':0} | |
| 74 | 75 | self.mirrorpad_mode = {'CONSTANT':0, 'REFLECT':1, 'SYMMETRIC':2} |
| 75 | 76 | self.name_operand_dict = {} |
| 76 | 77 | |
| @@ -113,6 +114,8 @@ class TFConverter: · 36 unmodified lines | ||
| 113 | 114 | # if activation is None, and BiasAdd.next is the last op which is Identity |
| 114 | 115 | if conv2d_scope_name + '/BiasAdd' in self.edges: |
| 115 | 116 | anode = self.edges[conv2d_scope_name + '/BiasAdd'][0] |
| 117 | + if anode.op not in self.conv_activations: | |
| 118 | + anode = None | |
| 116 | 119 | else: |
| 117 | 120 | anode = None |
| 118 | 121 | return knode, bnode, dnode, anode |
| @@ -252,14 +255,47 @@ class TFConverter: · 133 unmodified lines | ||
| 252 | 255 | np.array([input_operand_index, output_operand_index], dtype=np.uint32).tofile(f) |
| 253 | 256 | |
| 254 | 257 | |
| 258 | + def dump_sub_to_file(self, node, f): | |
| 259 | + assert(node.op == 'Sub') | |
| 260 | + self.layer_number = self.layer_number + 1 | |
| 261 | + self.converted_nodes.add(node.name) | |
| 262 | + i0_node = self.name_node_dict[node.input[0]] | |
| 263 | + i1_node = self.name_node_dict[node.input[1]] | |
| 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 | + assert(i0_node.name.find('sub/x')) | |
| 268 | + np.array([1], dtype=np.uint32).tofile(f) | |
| 269 | + np.array([scalar], dtype=np.float32).tofile(f) | |
| 270 | + np.array([0], dtype=np.uint32).tofile(f) | |
| 271 | + input_operand_index = self.add_operand(i1_node.name, Operand.IOTYPE_INPUT) | |
| 272 | + np.array([input_operand_index], dtype=np.uint32).tofile(f) | |
| 273 | + elif i1_node.op == 'Const': | |
| 274 | + scalar = i1_node.attr['value'].tensor.float_val[0] | |
| 275 | + assert(i1_node.name.find('sub/y')) | |
| 276 | + np.array([0], dtype=np.uint32).tofile(f) | |
| 277 | + input_operand_index = self.add_operand(i0_node.name, Operand.IOTYPE_INPUT) | |
| 278 | + np.array([input_operand_index], dtype=np.uint32).tofile(f) | |
| 279 | + np.array([1], dtype=np.uint32).tofile(f) | |
| 280 | + np.array([scalar], dtype=np.float32).tofile(f) | |
| 281 | + else: | |
| 282 | + np.array([0], dtype=np.uint32).tofile(f) | |
| 283 | + input_operand_index = self.add_operand(i0_node.name, Operand.IOTYPE_INPUT) | |
| 284 | + np.array([input_operand_index], dtype=np.uint32).tofile(f) | |
| 285 | + np.array([0], dtype=np.uint32).tofile(f) | |
| 286 | + input_operand_index = self.add_operand(i1_node.name, Operand.IOTYPE_INPUT) | |
| 287 | + np.array([input_operand_index], dtype=np.uint32).tofile(f) | |
| 288 | + output_operand_index = self.add_operand(node.name, Operand.IOTYPE_OUTPUT) | |
| 289 | + np.array([output_operand_index], dtype=np.uint32).tofile(f) | |
| 290 | + | |
| 291 | + | |
| 255 | 292 | def dump_layers_to_file(self, f): |
| 256 | 293 | for node in self.nodes: |
| 257 | 294 | if node.name in self.converted_nodes: |
| 258 | 295 | continue |
| 259 | 296 | |
| 260 | 297 | # conv2d with dilation generates very complex nodes, so handle it in special |
| 261 | − scope_name = TFConverter.get_scope_name(node.name) | |
| 262 | − if scope_name in self.conv2d_scope_names: | |
| 298 | + if self.in_conv2d_scope(node.name): | |
| 263 | 299 | if node.op == 'Conv2D': |
| 264 | 300 | self.dump_complex_conv2d_to_file(node, f) |
| 265 | 301 | continue |
| @@ -272,6 +308,8 @@ class TFConverter: · 6 unmodified lines | ||
| 272 | 308 | self.dump_mirrorpad_to_file(node, f) |
| 273 | 309 | elif node.op == 'Maximum': |
| 274 | 310 | self.dump_maximum_to_file(node, f) |
| 311 | + elif node.op == 'Sub': | |
| 312 | + self.dump_sub_to_file(node, f) | |
| 275 | 313 | |
| 276 | 314 | |
| 277 | 315 | def dump_operands_to_file(self, f): |
| @@ -352,6 +390,17 @@ class TFConverter: · 74 unmodified lines | ||
| 352 | 390 | return name[0:index] |
| 353 | 391 | |
| 354 | 392 | |
| 393 | + def in_conv2d_scope(self, name): | |
| 394 | + inner_scope = TFConverter.get_scope_name(name) | |
| 395 | + if inner_scope == "": | |
| 396 | + return False; | |
| 397 | + for scope in self.conv2d_scope_names: | |
| 398 | + index = inner_scope.find(scope) | |
| 399 | + if index == 0: | |
| 400 | + return True | |
| 401 | + return False | |
| 402 | + | |
| 403 | + | |
| 355 | 404 | def generate_conv2d_scope_info(self): |
| 356 | 405 | # mostly, conv2d is a sub block in graph, get the scope name |
| 357 | 406 | for node in self.nodes: |
| @@ -23,4 +23,4 @@ str = 'FFMPEGDNNNATIVE' · 22 unmodified lines | ||
| 23 | 23 | major = 1 |
| 24 | 24 | |
| 25 | 25 | # increase minor when we don't have to re-convert the model file |
| 26 | −minor = 0 | |
| 26 | +minor = 1 | |