|
30 | 30 | ATTR_INT = 2 |
31 | 31 | ATTR_TENSOR = 4 |
32 | 32 | ATTR_INTS = 7 |
| 33 | +ATTR_STRING = 3 |
33 | 34 |
|
34 | 35 |
|
35 | 36 | class NetworkParser: |
@@ -262,7 +263,7 @@ def _consume_dense_nodes( # noqa: C901, PLR0912 |
262 | 263 |
|
263 | 264 | input_output_size = _get_input_output_size(input_layer, transformer) |
264 | 265 |
|
265 | | - output_size = input_output_size[:-1] + [node_weights.shape[1]] |
| 266 | + output_size = [*input_output_size[:-1], node_weights.shape[1]] |
266 | 267 |
|
267 | 268 | activation = "linear" |
268 | 269 | if len(next_nodes) == 1: |
@@ -316,12 +317,12 @@ def _consume_gemm_dense_nodes(self, node, next_nodes): |
316 | 317 | input_output_size = _get_input_output_size(input_layer, transformer) |
317 | 318 |
|
318 | 319 | # output is the same size as input except for the last dimension |
319 | | - output_size = input_output_size[:-1] + [weights.shape[1]] |
| 320 | + output_size = [*input_output_size[:-1], weights.shape[1]] |
320 | 321 |
|
321 | 322 | activation = "linear" |
322 | 323 | if len(next_nodes) == 1: |
323 | 324 | # check if Relu |
324 | | - type_, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
| 325 | + _, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
325 | 326 | if maybe_node.op_type in _ACTIVATION_OP_TYPES: |
326 | 327 | node = maybe_node |
327 | 328 | activation = node.op_type.lower() |
@@ -376,15 +377,25 @@ def _consume_conv_nodes(self, node, next_nodes): # noqa: PLR0912, C901, PLR0915 |
376 | 377 | biases = np.zeros(out_channels) if in_2 is None else self._initializers[in_2] |
377 | 378 |
|
378 | 379 | attr = _collect_attributes(node) |
379 | | - |
| 380 | + if "strides" not in attr: |
| 381 | + node_name = node.name |
| 382 | + msg = f"{node_name} is missing required 'strides' attribute." |
| 383 | + raise ValueError(msg) |
380 | 384 | strides = attr["strides"] |
| 385 | + |
381 | 386 | # check only kernel shape and stride are set |
382 | | - if attr["kernel_shape"] != kernel_shape: |
383 | | - msg = ( |
384 | | - f"Kernel shape attribute {attr['kernel_shape']} does not match" |
385 | | - f" initialized kernel shape {kernel_shape}." |
386 | | - ) |
387 | | - raise ValueError(msg) |
| 387 | + if "kernel_shape" in attr: |
| 388 | + if attr["kernel_shape"] != kernel_shape: |
| 389 | + msg = ( |
| 390 | + f"Kernel shape attribute {attr['kernel_shape']} does not match" |
| 391 | + f" initialized kernel shape {kernel_shape}." |
| 392 | + ) |
| 393 | + raise ValueError(msg) |
| 394 | + else: |
| 395 | + # infer kernel shape from weights (ONNX default behavior) |
| 396 | + attr["kernel_shape"] = list(kernel_shape) |
| 397 | + # Assign to _kernel_shape attribute for testing purposes |
| 398 | + self._kernel_shape = list(kernel_shape) |
388 | 399 | if len(kernel_shape) != len(strides): |
389 | 400 | msg = ( |
390 | 401 | f"Initialized kernel shape {kernel_shape} has {len(kernel_shape)} " |
@@ -437,7 +448,7 @@ def _consume_conv_nodes(self, node, next_nodes): # noqa: PLR0912, C901, PLR0915 |
437 | 448 | activation = "linear" |
438 | 449 | if len(next_nodes) == 1: |
439 | 450 | # check if Relu |
440 | | - type_, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
| 451 | + _, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
441 | 452 | if maybe_node.op_type in _ACTIVATION_OP_TYPES: |
442 | 453 | node = maybe_node |
443 | 454 | activation = maybe_node.op_type.lower() |
@@ -479,7 +490,16 @@ def _consume_reshape_nodes(self, node, next_nodes): |
479 | 490 | raise ValueError(msg) |
480 | 491 | [in_0, in_1] = list(node.input) |
481 | 492 | input_layer = self._node_map[in_0] |
482 | | - new_shape = self._constants[in_1] |
| 493 | + if in_1 in self._constants: |
| 494 | + new_shape = self._constants[in_1] |
| 495 | + elif in_1 in self._initializers: |
| 496 | + new_shape = self._initializers[in_1] |
| 497 | + else: |
| 498 | + msg = ( |
| 499 | + f"Reshape node {node.name} has shape input {in_1} " |
| 500 | + "that is neither a Constant nor an initializer." |
| 501 | + ) |
| 502 | + raise KeyError(msg) |
483 | 503 | output_size = np.empty(input_layer.output_size).reshape(new_shape).shape |
484 | 504 | transformer = IndexMapper(input_layer.output_size, list(output_size)) |
485 | 505 | self._node_map[node.output[0]] = (transformer, input_layer) |
@@ -584,7 +604,7 @@ def _consume_pool_nodes(self, node, next_nodes): # noqa: PLR0912, C901, PLR0915 |
584 | 604 | activation = "linear" |
585 | 605 | if len(next_nodes) == 1: |
586 | 606 | # check if Relu |
587 | | - type_, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
| 607 | + _, maybe_node, maybe_next_nodes = self._nodes[next_nodes[0]] |
588 | 608 | if maybe_node.op_type in _ACTIVATION_OP_TYPES: |
589 | 609 | node = maybe_node |
590 | 610 | activation = maybe_node.op_type.lower() |
@@ -624,6 +644,8 @@ def _collect_attributes(node): |
624 | 644 | r[attr.name] = numpy_helper.to_array(attr.t) |
625 | 645 | elif attr.type == ATTR_INTS: # INTS |
626 | 646 | r[attr.name] = list(attr.ints) |
| 647 | + elif attr.type == ATTR_STRING: # STRING |
| 648 | + r[attr.name] = attr.s.decode("utf-8") |
627 | 649 | else: |
628 | 650 | msg = f"unhandled attribute type {attr.type}" |
629 | 651 | raise RuntimeError(msg) |
|
0 commit comments