### Install onnx2torch Source: https://github.com/lzu-zhanghr/onnx2torch/blob/master/README.md Installation instructions for the onnx2torch library using pip or conda. ```bash pip install onnx2torch ``` ```bash conda install -c conda-forge onnx2torch ``` -------------------------------- ### Convert ONNX to PyTorch Source: https://github.com/lzu-zhanghr/onnx2torch/blob/master/README.md Demonstrates how to convert an ONNX model to a PyTorch model by passing either a file path or a loaded ONNX model object. ```python import torch from onnx2torch import convert onnx_model_path = '/some/path/mobile_net_v2.onnx' torch_model_1 = convert(onnx_model_path) onnx_model = onnx.load(onnx_model_path) torch_model_2 = convert(onnx_model) ``` -------------------------------- ### Implementing Custom Operation Logic with Export Support Source: https://github.com/lzu-zhanghr/onnx2torch/blob/master/README.md Shows how to implement an operation that requires custom PyTorch logic and specific ONNX export behavior using a custom nn.Module and the CustomExportToOnnx class. ```python class OnnxExpand(nn.Module, OnnxToTorchModuleWithCustomExport): def forward(self, input_tensor: torch.Tensor, shape: torch.Tensor) -> torch.Tensor: def _forward(): return input_tensor * torch.ones(torch.Size(shape), dtype=input_tensor.dtype, device=input_tensor.device) if torch.onnx.is_in_onnx_export(): return _ExpandExportToOnnx.set_forward_and_apply(_forward, input_tensor, shape) return _forward() class _ExpandExportToOnnx(CustomExportToOnnx): @staticmethod def symbolic(graph: torch_C.Graph, input_tensor: torch_C.Value, shape: torch_C.Value, *args) -> torch_C.Value: return graph.op('Expand', input_tensor, shape, outputs=1) @add_converter(operation_type='Expand', version=8) @add_converter(operation_type='Expand', version=13) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: return OperationConverterResult( torch_module=OnnxExpand(), onnx_mapping=onnx_mapping_from_node(node=node), ) ``` -------------------------------- ### Define a custom operation with manual mapping Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt Shows how to handle complex custom operations by manually defining the OnnxMapping, allowing specific selection of inputs and outputs. ```python @add_converter(operation_type='CustomOp', version=1) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: custom_mapping = OnnxMapping( inputs=(node.input_values[0],), outputs=node.output_values, ) return OperationConverterResult( torch_module=nn.Identity(), onnx_mapping=custom_mapping, ) ``` -------------------------------- ### Execute and Validate PyTorch Model Source: https://github.com/lzu-zhanghr/onnx2torch/blob/master/README.md Shows how to run the converted PyTorch model and validate its output against the original ONNX model using onnxruntime. ```python import onnxruntime as ort x = torch.ones((1, 2, 224, 224)).cuda() out_torch = torch_model_1(x) ort_sess = ort.InferenceSession(onnx_model_path) outputs_ort = ort_sess.run(None, {'input': x.numpy()}) print(torch.max(torch.abs(outputs_ort - out_torch.detach().numpy()))) print(np.allclose(outputs_ort, out_torch.detach().numpy(), atol=1.e-7)) ``` -------------------------------- ### Convert ONNX Model to PyTorch using convert() Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `convert` function is the primary method for transforming ONNX models into PyTorch `fx.GraphModule` objects. It accepts either a file path or a loaded ONNX ModelProto. Optional parameters can be used to preserve input names or attach mapping information. The converted model can be used for inference, training, or export, and its accuracy can be verified against ONNX Runtime. ```python import torch import onnx import onnxruntime as ort import numpy as np from onnx2torch import convert # Method 1: Convert directly from file path onnx_model_path = 'path/to/mobilenet_v2.onnx' torch_model = convert(onnx_model_path) # Method 2: Convert from loaded ONNX model onnx_model = onnx.load(onnx_model_path) torch_model = convert(onnx_model) # Method 3: With optional parameters torch_model = convert( onnx_model_path, save_input_names=True, # Preserve original ONNX input names attach_onnx_mapping=True # Attach mapping info for debugging ) # Run inference with the converted model torch_model.eval() x = torch.randn(1, 3, 224, 224) output = torch_model(x) # Verify conversion accuracy against ONNX Runtime ort_session = ort.InferenceSession(onnx_model_path) onnx_output = ort_session.run(None, {'input': x.numpy()})[0] max_diff = torch.max(torch.abs(torch.tensor(onnx_output) - output.detach())) print(f"Max difference: {max_diff}") # Should be very small (< 1e-6) is_close = np.allclose(onnx_output, output.detach().numpy(), atol=1e-7) print(f"Outputs match: {is_close}") # Expected: True ``` -------------------------------- ### Define a custom Clip operation converter Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt Demonstrates how to implement a converter for the 'Clip' operation. It extracts min/max bounds from the ONNX graph and wraps torch.clamp in a nn.Module. ```python @add_converter(operation_type='Clip', version=11) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: try: min_val = float(get_const_value(node.input_values[1], graph)) except (KeyError, IndexError): min_val = float('-inf') try: max_val = float(get_const_value(node.input_values[2], graph)) except (KeyError, IndexError): max_val = float('inf') class ClipModule(nn.Module): def __init__(self, min_val, max_val): super().__init__() self.min_val = min_val self.max_val = max_val def forward(self, x): return torch.clamp(x, min=self.min_val, max=self.max_val) return OperationConverterResult( torch_module=ClipModule(min_val, max_val), onnx_mapping=onnx_mapping_from_node(node=node), ) ``` -------------------------------- ### Registering Direct ONNX to PyTorch Operation Mapping Source: https://github.com/lzu-zhanghr/onnx2torch/blob/master/README.md Demonstrates how to use the @add_converter decorator to map an ONNX operation to a standard PyTorch nn.Module. This approach is suitable when the operation behavior is identical in both frameworks. ```python @add_converter(operation_type='Relu', version=6) @add_converter(operation_type='Relu', version=13) @add_converter(operation_type='Relu', version=14) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: return OperationConverterResult( torch_module=nn.ReLU(), onnx_mapping=onnx_mapping_from_node(node=node), ) ``` -------------------------------- ### Convert ONNX Model to PyTorch Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `convert` function is the primary method for transforming an ONNX model into a PyTorch `torch.fx.GraphModule`. It can accept either a file path or an ONNX ModelProto object. Optional parameters allow for preserving input names and attaching mapping information for debugging. ```APIDOC ## convert - Convert ONNX Model to PyTorch ### Description The `convert` function is the main entry point for converting ONNX models to PyTorch. It accepts either a file path to an ONNX model or an already-loaded ONNX ModelProto object. The function returns a `torch.fx.GraphModule` that can be used exactly like any PyTorch model for inference, training, or further export. ### Method `convert(onnx_model, save_input_names=False, attach_onnx_mapping=False)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **onnx_model** (str or onnx.ModelProto) - Required - Path to the ONNX model file or an ONNX ModelProto object. - **save_input_names** (bool) - Optional - If True, preserves the original ONNX input names. - **attach_onnx_mapping** (bool) - Optional - If True, attaches mapping information for debugging. ### Request Example ```python import torch import onnx from onnx2torch import convert # Method 1: Convert directly from file path onnx_model_path = 'path/to/mobilenet_v2.onnx' torch_model = convert(onnx_model_path) # Method 2: Convert from loaded ONNX model onnx_model = onnx.load(onnx_model_path) torch_model = convert(onnx_model) # Method 3: With optional parameters torch_model = convert( onnx_model_path, save_input_names=True, attach_onnx_mapping=True ) ``` ### Response #### Success Response (200) - **torch_model** (torch.fx.GraphModule) - The converted PyTorch model. #### Response Example ```python # Example usage after conversion torch_model.eval() x = torch.randn(1, 3, 224, 224) output = torch_model(x) print(output) ``` ``` -------------------------------- ### Accessing ONNX Graph Structure with OnnxGraph - Python Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `OnnxGraph` class provides a structured interface for traversing and inspecting ONNX computational graphs. It exposes nodes, initializers (weights), and value information, which are used by converters to build equivalent PyTorch modules. This allows for detailed analysis and manipulation of ONNX models. ```python import onnx from onnx2torch.onnx_graph import OnnxGraph, ValueType from onnx2torch.utils.safe_shape_inference import safe_shape_inference # Load and parse ONNX model onnx_model = onnx.load('model.onnx') onnx_model = safe_shape_inference(onnx_model) graph = OnnxGraph(onnx_model.graph) # Access graph inputs and outputs print(f"Graph name: {graph.name}") print(f"Input values: {graph.input_values}") # Tuple of input tensor names print(f"Output values: {graph.output_values}") # Tuple of output tensor names # Iterate over nodes (topologically sorted) for name, node in graph.nodes.items(): print(f"Node: {name}") print(f" Op type: {node.operation_type}") print(f" Inputs: {node.input_values}") print(f" Outputs: {node.output_values}") print(f" Attributes: {node.attributes}") # Access model weights (initializers) for name, tensor in graph.initializers.items(): torch_tensor = tensor.to_torch() print(f"Initializer '{name}': shape={torch_tensor.shape}, dtype={torch_tensor.dtype}") # Determine value types for input_name in graph.input_values: value_type = graph.value_type(input_name) print(f"{input_name}: {value_type}") # ValueType.GRAPH_INPUT # Get node that produces a specific value output_name = graph.output_values[0] producer_node, output_index = graph.value_as_node_output(output_name) print(f"Output '{output_name}' produced by node '{producer_node.unique_name}'") ``` -------------------------------- ### Register Custom Operation Converters using @add_converter Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `@add_converter` decorator facilitates the registration of custom PyTorch modules for specific ONNX operations and versions. Converter functions receive an `OnnxNode` and `OnnxGraph`, returning an `OperationConverterResult` that includes the PyTorch module and input/output mappings. This allows for extending ONNX2Torch to support custom or unsupported ONNX operations, including those with attributes or complex logic. ```python from torch import nn from onnx2torch.node_converters.registry import add_converter from onnx2torch.onnx_graph import OnnxGraph from onnx2torch.onnx_node import OnnxNode from onnx2torch.utils.common import OperationConverterResult, onnx_mapping_from_node # Example 1: Simple operation with direct PyTorch equivalent @add_converter(operation_type='Relu', version=6) @add_converter(operation_type='Relu', version=13) @add_converter(operation_type='Relu', version=14) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: return OperationConverterResult( torch_module=nn.ReLU(), onnx_mapping=onnx_mapping_from_node(node=node), ) # Example 2: Operation with attributes @add_converter(operation_type='LeakyRelu', version=6) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: alpha = node.attributes.get('alpha', 0.01) return OperationConverterResult( torch_module=nn.LeakyReLU(negative_slope=alpha), onnx_mapping=onnx_mapping_from_node(node=node), ) # Example 3: Custom module for complex operations class OnnxHardSigmoid(nn.Module): def __init__(self, alpha: float = 0.2, beta: float = 0.5): super().__init__() self.alpha = alpha self.beta = beta def forward(self, input_tensor): return torch.clip(input_tensor * self.alpha + self.beta, min=0.0, max=1.0) @add_converter(operation_type='HardSigmoid', version=6) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: alpha = node.attributes.get('alpha', 0.2) beta = node.attributes.get('beta', 0.5) return OperationConverterResult( torch_module=OnnxHardSigmoid(alpha=alpha, beta=beta), onnx_mapping=onnx_mapping_from_node(node=node), ) ``` -------------------------------- ### Custom ONNX Export for PyTorch Operations - Python Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt Enables round-trip ONNX conversion for operations where PyTorch and ONNX behaviors differ. It uses `CustomExportToOnnx` and `OnnxToTorchModuleWithCustomExport` to define custom symbolic functions, ensuring correct re-export to ONNX format. This is crucial for maintaining model integrity across conversion cycles. ```python import torch import torch._C as torch_C from torch import nn from onnx2torch.node_converters.registry import add_converter from onnx2torch.onnx_graph import OnnxGraph from onnx2torch.onnx_node import OnnxNode from onnx2torch.utils.common import OperationConverterResult, onnx_mapping_from_node from onnx2torch.utils.custom_export_to_onnx import ( CustomExportToOnnx, OnnxToTorchModuleWithCustomExport ) class OnnxExpand(nn.Module, OnnxToTorchModuleWithCustomExport): def forward(self, input_tensor: torch.Tensor, shape: torch.Tensor) -> torch.Tensor: # Define the actual forward computation def _forward(): return input_tensor * torch.ones( torch.Size(shape), dtype=input_tensor.dtype, device=input_tensor.device ) # During ONNX export, use custom symbolic if torch.onnx.is_in_onnx_export(): return _ExpandExportToOnnx.set_forward_and_apply( _forward, input_tensor, shape ) return _forward() class _ExpandExportToOnnx(CustomExportToOnnx): @staticmethod def symbolic(graph: torch_C.Graph, input_tensor, shape) -> torch_C.Value: # Define how this operation should appear in exported ONNX return graph.op('Expand', input_tensor, shape, outputs=1) @add_converter(operation_type='Expand', version=8) @add_converter(operation_type='Expand', version=13) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: return OperationConverterResult( torch_module=OnnxExpand(), onnx_mapping=onnx_mapping_from_node(node=node), ) # Usage: Convert and export back to ONNX from onnx2torch import convert torch_model = convert('model.onnx') dummy_input = torch.randn(1, 3, 224, 224) # Export back to ONNX with custom operations preserved torch.onnx.export( torch_model, dummy_input, 'model_exported.onnx', opset_version=13, input_names=['input'], output_names=['output'], dynamic_axes={'input': {0: 'batch'}, 'output': {0: 'batch'}} ) ``` -------------------------------- ### OperationConverterResult for ONNX to PyTorch Converters - Python Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `OperationConverterResult` is a named tuple that all custom ONNX to PyTorch converter functions must return. It encapsulates the PyTorch module implementing the operation and an `OnnxMapping` object, which details the correspondence between ONNX tensor names and the module's inputs and outputs. This structure is essential for correctly integrating custom operations into the conversion process. ```python from typing import NamedTuple, Tuple from torch import nn from onnx2torch.node_converters.registry import add_converter from onnx2torch.onnx_graph import OnnxGraph from onnx2torch.onnx_node import OnnxNode from onnx2torch.utils.common import ( OperationConverterResult, OnnxMapping, onnx_mapping_from_node, get_const_value ) # OnnxMapping structure # class OnnxMapping(NamedTuple): # inputs: Tuple[str, ...] # Names of input tensors from ONNX # outputs: Tuple[str, ...] # Names of output tensors from ONNX ``` -------------------------------- ### Register Custom Operation Converters Source: https://context7.com/lzu-zhanghr/onnx2torch/llms.txt The `@add_converter` decorator is used to register custom conversion functions for specific ONNX operations. This allows extending ONNX2Torch to support operations not natively handled by the library. Each converter must return an `OperationConverterResult`. ```APIDOC ## add_converter - Register Custom Operation Converters ### Description The `@add_converter` decorator allows registration of custom converters for ONNX operations. Each converter function receives an `OnnxNode` and `OnnxGraph` and must return an `OperationConverterResult` containing a PyTorch module and input/output mapping. This enables extending onnx2torch to support additional ONNX operations. ### Method `@add_converter(operation_type='', version=) def custom_converter(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult:` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **operation_type** (str) - Required - The type of the ONNX operation (e.g., 'Relu', 'LeakyRelu'). - **version** (int) - Required - The version of the ONNX operation. - **node** (OnnxNode) - Input parameter to the converter function, representing the ONNX node. - **graph** (OnnxGraph) - Input parameter to the converter function, representing the ONNX graph. ### Request Example ```python from torch import nn from onnx2torch.node_converters.registry import add_converter from onnx2torch.onnx_graph import OnnxGraph from onnx2torch.onnx_node import OnnxNode from onnx2torch.utils.common import OperationConverterResult, onnx_mapping_from_node # Example 1: Simple operation with direct PyTorch equivalent @add_converter(operation_type='Relu', version=6) @add_converter(operation_type='Relu', version=13) @add_converter(operation_type='Relu', version=14) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: return OperationConverterResult( torch_module=nn.ReLU(), onnx_mapping=onnx_mapping_from_node(node=node), ) # Example 2: Operation with attributes @add_converter(operation_type='LeakyRelu', version=6) def _(node: OnnxNode, graph: OnnxGraph) -> OperationConverterResult: alpha = node.attributes.get('alpha', 0.01) return OperationConverterResult( torch_module=nn.LeakyReLU(negative_slope=alpha), onnx_mapping=onnx_mapping_from_node(node=node), ) ``` ### Response #### Success Response (200) - **OperationConverterResult** - An object containing the PyTorch module and ONNX mapping information. #### Response Example ```python # The converter function itself doesn't return a direct response, # but it registers a handler for the specified ONNX operation. # The result is used internally by the convert function. ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.