{"id":15066221,"url":"https://github.com/enot-autodl/onnx2torch","last_synced_at":"2025-04-11T16:26:48.597Z","repository":{"id":37093668,"uuid":"438145512","full_name":"ENOT-AutoDL/onnx2torch","owner":"ENOT-AutoDL","description":"Convert ONNX models to PyTorch.","archived":false,"fork":false,"pushed_at":"2024-08-15T16:02:59.000Z","size":388,"stargazers_count":663,"open_issues_count":43,"forks_count":74,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-11T04:04:27.492Z","etag":null,"topics":["convert","export","onnx","pytorch"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ENOT-AutoDL.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-14T06:41:02.000Z","updated_at":"2025-04-11T02:41:37.000Z","dependencies_parsed_at":"2023-01-31T08:46:34.815Z","dependency_job_id":"185ee727-0579-41c3-91ad-5dadad5c9431","html_url":"https://github.com/ENOT-AutoDL/onnx2torch","commit_stats":{"total_commits":85,"total_committers":20,"mean_commits":4.25,"dds":0.8352941176470589,"last_synced_commit":"c8f8ac4e32c4d79402a82a0068a05c4fdc726330"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ENOT-AutoDL%2Fonnx2torch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ENOT-AutoDL%2Fonnx2torch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ENOT-AutoDL%2Fonnx2torch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ENOT-AutoDL%2Fonnx2torch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ENOT-AutoDL","download_url":"https://codeload.github.com/ENOT-AutoDL/onnx2torch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248439810,"owners_count":21103684,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["convert","export","onnx","pytorch"],"created_at":"2024-09-25T01:03:52.417Z","updated_at":"2025-04-11T16:26:48.567Z","avatar_url":"https://github.com/ENOT-AutoDL.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/logo/onnx2torch_light.png#gh-light-mode-only\"\u003e\n  \u003cimg src=\"assets/logo/onnx2torch_dark.png#gh-dark-mode-only\"\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://pypi.org/project/onnx2torch\"\u003e\n        \u003cimg src=\"https://badgen.net/pypi/v/onnx2torch\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://anaconda.org/conda-forge/onnx2torch\"\u003e\n        \u003cimg src=\"https://img.shields.io/conda/vn/conda-forge/onnx2torch\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/onnx2torch\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/license/ENOT-AutoDL/onnx2torch?color=blue\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/onnx2torch\"\u003e\n        \u003cimg src=\"https://img.shields.io/pypi/dm/onnx2torch?color=blue\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/ENOT-AutoDL/onnx2torch/stargazers\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/stars/ENOT-AutoDL/onnx2torch.svg?style=social\u0026label=Star\u0026maxAge=2592000\" /\u003e\n    \u003c/a\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://github.com/psf/black\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/code%20style-black-black?color=blue\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/pre-commit/pre-commit\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/pre--commit-enabled-blue?logo=pre-commit\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://conventionalcommits.org\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits\u0026logoColor=white\u0026color=blue\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nonnx2torch is an ONNX to PyTorch converter.\nOur converter:\n\n- Is easy to use – Convert the ONNX model with the function call `convert`;\n- Is easy to extend – Write your own custom layer in PyTorch and register it with `@add_converter`;\n- Convert back to ONNX – You can convert the model back to ONNX using the `torch.onnx.export` function.\n\nIf you find an issue, please [let us know](https://github.com/ENOT-AutoDL/onnx2torch/issues)!\nAnd feel free to create merge requests.\n\nPlease note that this converter covers only a limited number of PyTorch / ONNX models and operations.\nLet us know which models you use or want to convert from ONNX to PyTorch [here](https://github.com/ENOT-AutoDL/onnx2torch/discussions).\n\n## Installation\n\n```bash\npip install onnx2torch\n```\n\nor\n\n```bash\nconda install -c conda-forge onnx2torch\n```\n\n## Usage\n\nBelow you can find some examples of use.\n\n### Convert\n\n```python\nimport onnx\nimport torch\nfrom onnx2torch import convert\n\n# Path to ONNX model\nonnx_model_path = \"/some/path/mobile_net_v2.onnx\"\n# You can pass the path to the onnx model to convert it or...\ntorch_model_1 = convert(onnx_model_path)\n\n# Or you can load a regular onnx model and pass it to the converter\nonnx_model = onnx.load(onnx_model_path)\ntorch_model_2 = convert(onnx_model)\n```\n\n### Execute\n\nWe can execute the returned `PyTorch model` in the same way as the original torch model.\n\n```python\nimport onnxruntime as ort\n\n# Create example data\nx = torch.ones((1, 2, 224, 224)).cuda()\n\nout_torch = torch_model_1(x)\n\nort_sess = ort.InferenceSession(onnx_model_path)\noutputs_ort = ort_sess.run(None, {\"input\": x.numpy()})\n\n# Check the Onnx output against PyTorch\nprint(torch.max(torch.abs(outputs_ort - out_torch.detach().numpy())))\nprint(np.allclose(outputs_ort, out_torch.detach().numpy(), atol=1.0e-7))\n```\n\n## Models\n\nWe have tested the following models:\n\nSegmentation models:\n\n- [x] DeepLabV3+\n- [x] DeepLabV3 ResNet-50 (TorchVision)\n- [x] HRNet\n- [x] UNet (TorchVision)\n- [x] FCN ResNet-50 (TorchVision)\n- [x] LRASPP MobileNetV3 (TorchVision)\n\nDetection from MMdetection:\n\n- [x] [SSDLite with MobileNetV2 backbone](https://github.com/open-mmlab/mmdetection)\n- [x] [RetinaNet R50](https://github.com/open-mmlab/mmdetection)\n- [x] [SSD300 with VGG backbone](https://github.com/open-mmlab/mmdetection)\n- [x] [YOLOv3 d53](https://github.com/open-mmlab/mmdetection)\n- [x] [YOLOv5](https://github.com/ultralytics/yolov5)\n\nClassification from __TorchVision__:\n\n- [x] ResNet-18\n- [x] ResNet-50\n- [x] MobileNetV2\n- [x] MobileNetV3 Large\n- [x] EfficientNet-B{0, 1, 2, 3}\n- [x] WideResNet-50\n- [x] ResNext-50\n- [x] VGG-16\n- [x] GoogLeNet\n- [x] MnasNet\n- [x] RegNet\n\nTransformers:\n\n- [x] ViT\n- [x] Swin\n- [x] GPT-J\n\n#### :page_facing_up: List of currently supported operations can be founded [here](operators.md).\n\n## How to add new operations to converter\n\nHere we show how to extend onnx2torch with new ONNX operation, that supported by both PyTorch and ONNX\n\n\u003cdetails\u003e\n\u003csummary\u003eand has the same behaviour\u003c/summary\u003e\n\nAn example of such a module is [Relu](./onnx2torch/node_converters/activations.py)\n\n```python\n@add_converter(operation_type=\"Relu\", version=6)\n@add_converter(operation_type=\"Relu\", version=13)\n@add_converter(operation_type=\"Relu\", version=14)\ndef _(node: OnnxNode, graph: OnnxGraph) -\u003e OperationConverterResult:\n    return OperationConverterResult(\n        torch_module=nn.ReLU(),\n        onnx_mapping=onnx_mapping_from_node(node=node),\n    )\n```\n\nHere we have registered an operation named `Relu` for opset versions 6, 13, 14.\nNote that the `torch_module` argument in `OperationConverterResult` must be a torch.nn.Module, not just a callable object!\nIf Operation's behaviour differs from one opset version to another, you should implement it separately.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ebut has different behaviour\u003c/summary\u003e\n\nAn example of such a module is [ScatterND](./onnx2torch/node_converters/scatter_nd.py)\n\n```python\n# It is recommended to use Enum for string ONNX attributes.\nclass ReductionOnnxAttr(Enum):\n    NONE = \"none\"\n    ADD = \"add\"\n    MUL = \"mul\"\n\n\nclass OnnxScatterND(nn.Module, OnnxToTorchModuleWithCustomExport):\n    def __init__(self, reduction: ReductionOnnxAttr):\n        super().__init__()\n        self._reduction = reduction\n\n    # The following method should return ONNX attributes with their values as a dictionary.\n    # The number of attributes, their names and values depend on opset version;\n    # method should return correct set of attributes.\n    # Note: add type-postfix for each key: reduction -\u003e reduction_s, where s means \"string\".\n    def _onnx_attrs(self, opset_version: int) -\u003e Dict[str, Any]:\n        onnx_attrs: Dict[str, Any] = {}\n\n        # Here we handle opset versions \u003c 16 where there is no \"reduction\" attribute.\n        if opset_version \u003c 16:\n            if self._reduction != ReductionOnnxAttr.NONE:\n                raise ValueError(\n                    \"ScatterND from opset \u003c 16 does not support\"\n                    f\"reduction attribute != {ReductionOnnxAttr.NONE.value},\"\n                    f\"got {self._reduction.value}\"\n                )\n            return onnx_attrs\n\n        onnx_attrs[\"reduction_s\"] = self._reduction.value\n        return onnx_attrs\n\n    def forward(\n        self,\n        data: torch.Tensor,\n        indices: torch.Tensor,\n        updates: torch.Tensor,\n    ) -\u003e torch.Tensor:\n        def _forward():\n            # ScatterND forward implementation...\n            return output\n\n        if torch.onnx.is_in_onnx_export():\n            # Please follow our convention, args consists of:\n            # forward function, operation type, operation inputs, operation attributes.\n            onnx_attrs = self._onnx_attrs(opset_version=get_onnx_version())\n            return DefaultExportToOnnx.export(\n                _forward, \"ScatterND\", data, indices, updates, onnx_attrs\n            )\n\n        return _forward()\n\n\n@add_converter(operation_type=\"ScatterND\", version=11)\n@add_converter(operation_type=\"ScatterND\", version=13)\n@add_converter(operation_type=\"ScatterND\", version=16)\ndef _(node: OnnxNode, graph: OnnxGraph) -\u003e OperationConverterResult:\n    node_attributes = node.attributes\n    reduction = ReductionOnnxAttr(node_attributes.get(\"reduction\", \"none\"))\n    return OperationConverterResult(\n        torch_module=OnnxScatterND(reduction=reduction),\n        onnx_mapping=onnx_mapping_from_node(node=node),\n    )\n```\n\nHere we have used a trick to convert the model from torch back to ONNX by defining the custom `_ScatterNDExportToOnnx`.\n\n\u003c/details\u003e\n\n## Opset version workaround\n\nIncase you are using a model with older opset, try the following workaround:\n\n[ONNX Version Conversion - Official Docs](https://github.com/onnx/onnx/blob/main/docs/PythonAPIOverview.md#converting-version-of-an-onnx-model-within-default-domain-aionnx)\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```python\nimport onnx\nfrom onnx import version_converter\nimport torch\nfrom onnx2torch import convert\n\n# Load the ONNX model.\nmodel = onnx.load(\"model.onnx\")\n# Convert the model to the target version.\ntarget_version = 13\nconverted_model = version_converter.convert_version(model, target_version)\n# Convert to torch.\ntorch_model = convert(converted_model)\ntorch.save(torch_model, \"model.pt\")\n```\n\n\u003c/details\u003e\n\nNote: use this only when the model does not convert to PyTorch using the existing opset version. Result might vary.\n\n## Citation\n\nTo cite onnx2torch use `Cite this repository` button, or:\n\n```\n@misc{onnx2torch,\n  title={onnx2torch},\n  author={ENOT developers and Kalgin, Igor and Yanchenko, Arseny and Ivanov, Pyoter and Goncharenko, Alexander},\n  year={2021},\n  howpublished={\\url{https://enot.ai/}},\n  note={Version: x.y.z}\n}\n```\n\n## Acknowledgments\n\nThanks to Dmitry Chudakov [@cakeofwar42](https://github.com/cakeofwar42) for his contributions.\\\nSpecial thanks to Andrey Denisov [@denisovap2013](https://github.com/denisovap2013) for the logo design.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenot-autodl%2Fonnx2torch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenot-autodl%2Fonnx2torch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenot-autodl%2Fonnx2torch/lists"}