{"id":13440054,"url":"https://github.com/onnx/tensorflow-onnx","last_synced_at":"2026-02-20T07:02:50.592Z","repository":{"id":37580008,"uuid":"125098252","full_name":"onnx/tensorflow-onnx","owner":"onnx","description":"Convert TensorFlow, Keras, Tensorflow.js and Tflite models to ONNX","archived":false,"fork":false,"pushed_at":"2025-02-04T14:30:44.000Z","size":27432,"stargazers_count":2413,"open_issues_count":215,"forks_count":440,"subscribers_count":53,"default_branch":"main","last_synced_at":"2025-05-07T08:02:43.831Z","etag":null,"topics":["convert","deep-learning","export","keras","onnx","tensorflow","tensorflowjs","tflite"],"latest_commit_sha":null,"homepage":"","language":"Jupyter Notebook","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/onnx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"support_status.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-03-13T18:39:56.000Z","updated_at":"2025-05-05T20:31:32.000Z","dependencies_parsed_at":"2024-01-17T11:33:43.691Z","dependency_job_id":"47d6b968-4456-4c36-ac9b-f83a4be55465","html_url":"https://github.com/onnx/tensorflow-onnx","commit_stats":{"total_commits":2187,"total_committers":96,"mean_commits":22.78125,"dds":0.8436213991769548,"last_synced_commit":"79cedf926380cdf494dbfc6dd01eaa66122616d2"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onnx%2Ftensorflow-onnx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onnx%2Ftensorflow-onnx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onnx%2Ftensorflow-onnx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onnx%2Ftensorflow-onnx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onnx","download_url":"https://codeload.github.com/onnx/tensorflow-onnx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254110363,"owners_count":22016391,"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","deep-learning","export","keras","onnx","tensorflow","tensorflowjs","tflite"],"created_at":"2024-07-31T03:01:19.395Z","updated_at":"2026-02-20T07:02:50.585Z","avatar_url":"https://github.com/onnx.png","language":"Jupyter Notebook","funding_links":[],"categories":["Jupyter Notebook"],"sub_categories":[],"readme":"\u003c!--\nCopyright (c) ONNX Project Contributors\n\nSPDX-License-Identifier: Apache-2.0\n--\u003e\n\n# tf2onnx - Convert TensorFlow, Keras, Tensorflow.js and Tflite models to ONNX.\n\ntf2onnx converts TensorFlow (tf-2.x), keras, tensorflow.js and tflite models to ONNX via command\nline or python api.\n\n## 🛠 Maintainer Wanted\n\nWe are currently **looking for a new maintainer** to help support and evolve the `tf2onnx` project.\n\nIf you're passionate about the ONNX standard or contributing to the open source machine learning ecosystem, we'd love to hear from you! This is a great opportunity to contribute to a widely used project and collaborate with the ONNX community.\n\n**To express interest:**  \nPlease open an issue or comment on [this thread](https://github.com/onnx/tensorflow-onnx/issues) and let us know about your interest and background.\n\n__Note: tensorflow.js support was just added. While we tested it with many tfjs models from tfhub, it should be considered experimental.__\n\nTensorFlow has many more ops than ONNX and occasionally mapping a model to ONNX creates issues.\n\nYou find a list of supported TensorFlow ops and their mapping to ONNX [here](support_status.md).\n\nThe common issues we run into we try to document here [Troubleshooting Guide](Troubleshooting.md).\n\n\u003cbr/\u003e\n\n| Build Type | OS | Python | TensorFlow | ONNX opset |\n| ---        | -  | ---    | ---        | ---        |\n| Unit Test - Basic | Linux, Windows | 3.10-3.12 | 2.13-2.15 | 14-18 |\n| Unit Test - Full | Linux, Windows | 3.10-3.12 | 2.13-2.15 | 14-18 | \n\u003cbr/\u003e\n\n## Supported Versions\n\n### ONNX\n\ntf2onnx will use the ONNX version installed on your system and installs the latest ONNX version if none is found.\n\nWe support and test ONNX opset-14 to opset-18. opset-6 to opset-13 should work but we don't test them.\nBy default we use ```opset-15``` for the resulting ONNX graph.\n\nIf you want the graph to be generated with a specific opset, use ```--opset``` in the command line, for example ```--opset 15```.\n\n### TensorFlow\n\nWe support ```tf-2.x```. To keep our test matrix manageable we test tf2onnx running on top of ```tf-2.13 or better```.\n\n### Python\n\nWe support Python ```3.10-3.12```.\n\n## Prerequisites\n\n### Install TensorFlow\n\nIf you don't have TensorFlow installed already, install the desired TensorFlow build, for example:\n\n```pip install tensorflow```\n\n### (Optional) Install runtime\n\nIf you want to run tests, install a runtime that can run ONNX models. For example:\n\nONNX Runtime (available for Linux, Windows, and Mac):\n\n```pip install onnxruntime```\n\n## Installation\n\n### Install from pypi\n\n```pip install -U tf2onnx```\n\n### Install latest from github\n\n```pip install git+https://github.com/onnx/tensorflow-onnx```\n\n### Build and install latest from source (for development)\n\n```git clone https://github.com/onnx/tensorflow-onnx```\n\nOnce dependencies are installed, from the tensorflow-onnx folder call:\n\n```python setup.py install```\n\nor\n\n```python setup.py develop```\n\ntensorflow-onnx requires onnx-1.9 or better and will install/upgrade onnx if needed.\n\nTo create a wheel for distribution:\n\n```python setup.py bdist_wheel```\n\n## Getting started\n\nTo get started with `tensorflow-onnx`, run the `tf2onnx.convert` command, providing:\n\n* the path to your TensorFlow model (where the model is in `saved model` format)\n* a name for the ONNX output file:\n\n```python -m tf2onnx.convert --saved-model tensorflow-model-path --output model.onnx```\n\nThe above command uses a default of `15` for the ONNX opset. If you need a newer opset, or want to limit your model to use an older opset then you can provide the `--opset` argument to the command. If you are unsure about which opset to use, refer to the [ONNX operator documentation](https://github.com/onnx/onnx/releases).\n\n```python -m tf2onnx.convert --saved-model tensorflow-model-path --opset 18 --output model.onnx```\n\nIf your TensorFlow model is in a format other than `saved model`, then you need to provide the inputs and outputs of the model graph.\n\nFor `checkpoint` format:\n\n```python -m tf2onnx.convert --checkpoint  tensorflow-model-meta-file-path --output model.onnx --inputs input0:0,input1:0 --outputs output0:0```\n\nFor `graphdef` format:\n\n```python -m tf2onnx.convert --graphdef  tensorflow-model-graphdef-file --output model.onnx --inputs input0:0,input1:0 --outputs output0:0```\n\nIf your model is in `checkpoint` or `graphdef` format and you do not know the input and output nodes of the model, you can use the [summarize_graph](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms) TensorFlow utility. The `summarize_graph` tool does need to be downloaded and built from source. If you have the option of going to your model provider and obtaining the model in `saved model` format, then we recommend doing so.\n\nYou find an end-to-end tutorial for ssd-mobilenet [here](tutorials/ConvertingSSDMobilenetToONNX.ipynb)\n\nWe recently added support for tflite. You convert ```tflite``` models via command line, for example:\n\n```python -m tf2onnx.convert --opset 16 --tflite tflite-file --output model.onnx```\n\n## CLI reference\n\n```\npython -m tf2onnx.convert\n    --saved-model SOURCE_SAVED_MODEL_PATH |\n    --checkpoint SOURCE_CHECKPOINT_METAFILE_PATH |\n    --tflite TFLITE_MODEL_PATH |\n    --tfjs TFJS_MODEL_PATH | \n    --input | --graphdef SOURCE_GRAPHDEF_PB\n    --output TARGET_ONNX_MODEL\n    [--inputs GRAPH_INPUTS]\n    [--outputs GRAPH_OUTPUS]\n    [--inputs-as-nchw inputs_provided_as_nchw]\n    [--outputs-as-nchw outputs_provided_as_nchw]\n    [--opset OPSET]\n    [--dequantize]\n    [--tag TAG]\n    [--signature_def SIGNATURE_DEF]\n    [--concrete_function CONCRETE_FUNCTION]\n    [--target TARGET]\n    [--extra_opset list-of-extra-opset]\n    [--custom-ops list-of-custom-ops]\n    [--load_op_libraries tensorflow_library_path]\n    [--large_model]\n    [--continue_on_error]\n    [--verbose]\n    [--output_frozen_graph]\n```\n\n### Parameters\n\n#### --saved-model\n\nTensorFlow model as saved_model. We expect the path to the saved_model directory.\n\n#### --checkpoint\n\nTensorFlow model as checkpoint. We expect the path to the .meta file.\n\n#### --input or --graphdef\n\nTensorFlow model as graphdef file.\n\n#### --tfjs\n\nConvert a tensorflow.js model by providing a path to the .tfjs file. Inputs/outputs do not need to be specified.\n\n#### --tflite\n\nConvert a tflite model by providing a path to the .tflite file. Inputs/outputs do not need to be specified.\n\n#### --output\n\nThe target onnx file path.\n\n#### --inputs, --outputs\n\nTensorFlow model's input/output names, which can be found with [summarize graph tool](#summarize_graph). Those names typically end with ```:0```, for example ```--inputs input0:0,input1:0```. Inputs and outputs are ***not*** needed for models in saved-model format. Some models specify placeholders with unknown ranks and dims which can not be mapped to onnx. In those cases one can add the shape after the input name inside `[]`, for example `--inputs X:0[1,28,28,3]`. Use -1 to indicate unknown dimensions.\n\n#### --inputs-as-nchw\n\nBy default we preserve the image format of inputs (`nchw` or `nhwc`) as given in the TensorFlow model. If your hosts (for example windows) native format nchw and the model is written for nhwc, ```--inputs-as-nchw``` tensorflow-onnx will transpose the input. Doing so is convenient for the application and the converter in many cases can optimize the transpose away. For example ```--inputs input0:0,input1:0 --inputs-as-nchw input0:0``` assumes that images are passed into ```input0:0``` as nchw while the TensorFlow model given uses nhwc.\n\n#### --outputs-as-nchw\n\nSimilar usage with `--inputs-as-nchw`. By default we preserve the format of outputs (`nchw` or `nhwc`) as shown in the TensorFlow model. If your hosts native format nchw and the model is written for nhwc, ```--outputs-as-nchw``` tensorflow-onnx will transpose the output and optimize the transpose away. For example ```--outputs output0:0,output1:0 --outputs-as-nchw output0:0``` will change the ```output0:0``` as nchw while the TensorFlow model given uses nhwc.\n\n#### --ignore_default, --use_default\n\nONNX requires default values for graph inputs to be constant, while Tensorflow's PlaceholderWithDefault op accepts computed defaults. To convert such models, pass a comma-separated list of node names to the ignore_default and/or use_default flags.  PlaceholderWithDefault nodes with matching names will be replaced with Placeholder or Identity ops, respectively.\n\n#### --opset\n\nBy default we use the opset 15 to generate the graph. By specifying ```--opset``` the user can override the default to generate a graph with the desired opset. For example ```--opset 17``` would create a onnx graph that uses only ops available in opset 17. Because older opsets have in most cases fewer ops, some models might not convert on an older opset.\n\n#### --dequantize\n\n(This is experimental, only supported for tflite)\n\nProduces a float32 model from a quantized tflite model. Detects ReLU and ReLU6 ops from quantization bounds.\n\n#### --tag\n\nOnly valid with parameter `--saved_model`. Specifies the tag in the saved_model to be used. Typical value is 'serve'.\n\n#### --signature_def\n\nOnly valid with parameter `--saved_model`. Specifies which signature to use within the specified --tag value. Typical value is 'serving_default'.\n\n#### --concrete_function\n\n(This is experimental, valid only for TF2.x models)\n\nOnly valid with parameter `--saved_model`. If a model contains a list of concrete functions, under the function name `__call__` (as can be viewed using the command `saved_model_cli show --all`), this parameter is a 0-based integer specifying which function in that list should be converted. This parameter takes priority over `--signature_def`, which will be ignored.\n\n#### --target\n\nSome models require special handling to run on some runtimes. In particular, the model may use unsupported data types. Workarounds are activated with ```--target TARGET```. Currently supported values are listed on this [wiki](https://github.com/onnx/tensorflow-onnx/wiki/target). If your model will be run on Windows ML, you should specify the appropriate target value.\n\n#### --extra_opset\n\nIf you want to convert a TF model using an existing custom op, this can specify the correspongding domain and version.\nThe format is a comma-separated map of domain and version, for example: `ai.onnx.contrib:1`.\n\n#### --custom-ops\n\nIf a model contains ops not recognized by onnx runtime, you can tag these ops with a custom op domain so that the\nruntime can still open the model. The format is a comma-separated map of tf op names to domains in the format\nOpName:domain. If only an op name is provided (no colon), the default domain of `ai.onnx.converters.tensorflow`\nwill be used.\n\n#### --load_op_libraries\n\nLoad the comma-separated list of tensorflow plugin/op libraries before conversion.\n\n#### --large_model\n\n(Can be used only for TF2.x models)\n\nOnly valid with parameter `--saved_model`. When set, creates a zip file containing the ONNX protobuf model and large tensor values stored externally. This allows for converting models whose size exceeds the 2 GB.\n\n#### --continue_on_error\nContinue to run conversion on error, ignore graph cycles so it can report all missing ops and errors.\n\n#### --verbose\nVerbose detailed output for diagnostic purposes.\n\n#### --output_frozen_graph\n\nSave the frozen and optimized tensorflow graph to a file for debug.\n\n\n### \u003ca name=\"summarize_graph\"\u003e\u003c/a\u003eTool to get Graph Inputs \u0026 Outputs\n\nTo find the inputs and outputs for the TensorFlow graph the model developer will know or you can consult TensorFlow's [summarize_graph](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms) tool, for example:\n```\nsummarize_graph --in_graph=tests/models/fc-layers/frozen.pb\n```\n\n## Testing\nThere are 2 types of tests.\n\n### Unit test\n```\npython setup.py test\n```\n\n### Validate pre-trained TensorFlow models\n```\npython tests/run_pretrained_models.py\nusage: run_pretrained_models.py [-h] [--cache CACHE] [--tests TESTS] [--backend BACKEND] [--verbose] [--debug] [--config yaml-config]\n\noptional arguments:\n  -h, --help         show this help message and exit\n  --cache CACHE      pre-trained models cache dir\n  --tests TESTS      tests to run\n  --backend BACKEND  backend to use\n  --config           yaml config file\n  --verbose          verbose output, option is additive\n  --opset OPSET      target opset to use\n  --perf csv-file    capture performance numbers for tensorflow and onnx runtime\n  --debug            dump generated graph with shape info\n```\n```run_pretrained_models.py``` will run the TensorFlow model, captures the TensorFlow output and runs the same test against the specified ONNX backend after converting the model.\n\nIf the option ```--perf csv-file``` is specified, we'll capture the timing for inference of tensorflow and onnx runtime and write the result into the given csv file.\n\nYou call it for example with:\n```\npython tests/run_pretrained_models.py --backend onnxruntime --config tests/run_pretrained_models.yaml --perf perf.csv\n```\n\n#### \u003ca name=\"save_pretrained_model\"\u003e\u003c/a\u003eTool to save pre-trained model\n\nWe provide an [utility](tools/save_pretrained_model.py) to save pre-trained model along with its config.\nPut `save_pretrained_model(sess, outputs, feed_inputs, save_dir, model_name)` in your last testing epoch and the pre-trained model and config will be saved under `save_dir/to_onnx`.\nPlease refer to the example in [tools/save_pretrained_model.py](tools/save_pretrained_model.py) for more information.\nNote the minimum required Tensorflow version is r1.6.\n\n## Python API Reference\nWith tf2onnx-1.8.4 we updated our API. Our old API still works - you find the documentation [here](https://github.com/onnx/tensorflow-onnx/blob/v1.8.3/README.md#python-api-reference).\n\n### from_keras (tf-2.0 and newer)\n```\nimport tf2onnx\n\nmodel_proto, external_tensor_storage = tf2onnx.convert.from_keras(model,\n                input_signature=None, opset=None, custom_ops=None,\n                custom_op_handlers=None, custom_rewriter=None,\n                inputs_as_nchw=None, outputs_as_nchw=None, extra_opset=None,\n                shape_override=None, target=None, large_model=False, output_path=None)\n\n    Args:\n        model: the tf.keras model we want to convert\n        input_signature: a tf.TensorSpec or a numpy array defining the shape/dtype of the input\n        opset: the opset to be used for the ONNX model, default is the latest\n        custom_ops: if a model contains ops not recognized by onnx runtime,\n            you can tag these ops with a custom op domain so that the\n            runtime can still open the model. Type is a dictionary `{op name: domain}`.\n        target: list of workarounds applied to help certain platforms\n        custom_op_handlers: dictionary of custom ops handlers\n        custom_rewriter: list of custom graph rewriters\n        extra_opset: list of extra opset's, for example the opset's used by custom ops\n        shape_override: dict with inputs that override the shapes given by tensorflow\n        inputs_as_nchw: transpose inputs in list from nhwc to nchw\n        outputs_as_nchw: transpose outputs in list from nhwc to nchw\n        large_model: use the ONNX external tensor storage format\n        output_path: save model to output_path\n\n    Returns:\n        An ONNX model_proto and an external_tensor_storage dict.\n```\n\nSee [tutorials/keras-resnet50.ipynb](tutorials/keras-resnet50.ipynb) for an end to end example.\n\n### from_function (tf-2.0 and newer)\n```\nimport tf2onnx\n\nmodel_proto, external_tensor_storage = tf2onnx.convert.from_function(function,\n                input_signature=None, opset=None, custom_ops=None,\n                custom_op_handlers=None, custom_rewriter=None, inputs_as_nchw=None,\n                outputs_as_nchw=None, extra_opset=None, shape_override=None,\n                target=None, large_model=False, output_path=None)\n\n    Args:\n        function: the tf.function we want to convert\n        input_signature: a tf.TensorSpec or a numpy array defining the shape/dtype of the input\n        opset: the opset to be used for the ONNX model, default is the latest\n        custom_ops: if a model contains ops not recognized by onnx runtime,\n            you can tag these ops with a custom op domain so that the\n            runtime can still open the model. Type is a dictionary `{op name: domain}`.\n        target: list of workarounds applied to help certain platforms\n        custom_op_handlers: dictionary of custom ops handlers\n        custom_rewriter: list of custom graph rewriters\n        extra_opset: list of extra opset's, for example the opset's used by custom ops\n        shape_override: dict with inputs that override the shapes given by tensorflow\n        inputs_as_nchw: transpose inputs in list from nhwc to nchw\n        outputs_as_nchw: transpose outputs in list from nhwc to nchw\n        large_model: use the ONNX external tensor storage format\n        output_path: save model to output_path\n\n    Returns:\n        An ONNX model_proto and an external_tensor_storage dict.\n```\n\n### from_graph_def\n```\nimport tf2onnx\n\nmodel_proto, external_tensor_storage = tf2onnx.convert.from_graph_def(graph_def,\n                name=None, input_names=None, output_names=None, opset=None,\n                custom_ops=None, custom_op_handlers=None, custom_rewriter=None, \n                inputs_as_nchw=None, outputs_as_nchw=None, extra_opset=None,\n                shape_override=None, target=None, large_model=False,\n                output_path=None)\n\n    Args:\n        graph_def: the graph_def we want to convert\n        input_names: list of input names\n        output_names: list of output names\n        name: A name for the graph\n        opset: the opset to be used for the ONNX model, default is the latest\n        target: list of workarounds applied to help certain platforms\n        custom_op_handlers: dictionary of custom ops handlers\n        custom_rewriter: list of custom graph rewriters\n        extra_opset: list of extra opset's, for example the opset's used by custom ops\n        shape_override: dict with inputs that override the shapes given by tensorflow\n        inputs_as_nchw: transpose inputs in list from nhwc to nchw\n        outputs_as_nchw: transpose outputs in list from nhwc to nchw\n        large_model: use the ONNX external tensor storage format\n        output_path: save model to output_path\n\n    Returns:\n        An ONNX model_proto and an external_tensor_storage dict.\n```\n\n### from_tflite\n```\nimport tf2onnx\n\nmodel_proto, external_tensor_storage = tf2onnx.convert.from_tflite(tflite_path,\n                input_names=None, output_names=None, opset=None, custom_ops=None, custom_op_handlers=None,\n                custom_rewriter=None, inputs_as_nchw=None, outputs_as_nchw=None, extra_opset=None,\n                shape_override=None, target=None, large_model=False, output_path=None):\n\n    Args:\n        tflite_path: the tflite model file full path\n        input_names: list of input names\n        output_names: list of output names\n        opset: the opset to be used for the ONNX model, default is the latest\n        custom_ops: if a model contains ops not recognized by onnx runtime,\n            you can tag these ops with a custom op domain so that the\n            runtime can still open the model. Type is a dictionary `{op name: domain}`.\n        custom_op_handlers: dictionary of custom ops handlers\n        custom_rewriter: list of custom graph rewriters\n        inputs_as_nchw: transpose inputs in list from nhwc to nchw\n        outputs_as_nchw: transpose outputs in list from nhwc to nchw\n        extra_opset: list of extra opset's, for example the opset's used by custom ops\n        shape_override: dict with inputs that override the shapes given by tensorflow\n        target: list of workarounds applied to help certain platforms\n        large_model: use the ONNX external tensor storage format\n        output_path: save model to output_path\n\n    Returns:\n        An ONNX model_proto and an external_tensor_storage dict.\n```\n\n### Creating custom op mappings from python\n\nFor complex custom ops that require graph rewrites or input / attribute rewrites using the python interface to insert a custom op will be the easiest way to accomplish the task.\nA dictionary of name-\u003ecustom_op_handler can be passed to tf2onnx.tfonnx.process_tf_graph. If the op name is found in the graph the handler will have access to all internal structures and can rewrite that is needed. For example [examples/custom_op_via_python.py]():\n\n```\nimport tensorflow as tf\nimport tf2onnx\nfrom onnx import helper\n\n_TENSORFLOW_DOMAIN = \"ai.onnx.converters.tensorflow\"\n\n\ndef print_handler(ctx, node, name, args):\n    # replace tf.Print() with Identity\n    #   T output = Print(T input, data, @list(type) U, @string message, @int first_n, @int summarize)\n    # becomes:\n    #   T output = Identity(T Input)\n    node.domain = _TENSORFLOW_DOMAIN\n    del node.input[1:]\n    return node\n\n\nwith tf.Session() as sess:\n    x = tf.placeholder(tf.float32, [2, 3], name=\"input\")\n    x_ = tf.add(x, x)\n    x_ = tf.Print(x, [x], \"hello\")\n    _ = tf.identity(x_, name=\"output\")\n    onnx_graph = tf2onnx.tfonnx.process_tf_graph(sess.graph,\n                                                 custom_op_handlers={\"Print\": (print_handler, [\"Identity\", \"mode\"])},\n                                                 extra_opset=[helper.make_opsetid(_TENSORFLOW_DOMAIN, 1)],\n                                                 input_names=[\"input:0\"],\n                                                 output_names=[\"output:0\"])\n    model_proto = onnx_graph.make_model(\"test\")\n    with open(\"/tmp/model.onnx\", \"wb\") as f:\n        f.write(model_proto.SerializeToString())\n```\n\n## How tf2onnx works\n\nThe converter needs to take care of a few things:\n\n1. Convert the protobuf format. Since the format is similar this step is straight forward.\n2. TensorFlow types need to be mapped to their ONNX equivalent.\n3. For many ops TensorFlow passes parameters like shapes as inputs where ONNX wants to see them as attributes. Since we use a frozen graph, the converter will fetch the input as constant, converts it to an attribute and remove the original input.\n4. TensorFlow in many cases composes ops out of multiple simpler ops. The converter will need to identify the subgraph for such ops, slice the subgraph out and replace it with the ONNX equivalent. This can become fairly complex so we use a graph matching library for it. A good example of this is the tensorflow transpose op.\n5. TensorFlow's default data format is NHWC where ONNX requires NCHW. The converter will insert transpose ops to deal with this.\n6. There are some ops like relu6 that are not supported in ONNX but the converter can be composed out of other ONNX ops.\n7. ONNX backends are new and their implementations are not complete yet. For some ops the converter generate ops with deal with issues in existing backends.\n\n### Step 1 - start with a frozen graph\n\ntf2onnx starts with a frozen graph. This is because of item 3 above.\n\n### Step 2 - 1:1 conversion of the protobuf from tensorflow to onnx\n\ntf2onnx first does a simple conversion from the TensorFlow protobuf format to the ONNX protobuf format without looking at individual ops.\nWe do this so we can use the ONNX graph as internal representation and write helper functions around it.\nThe code that does the conversion is in tensorflow_to_onnx(). tensorflow_to_onnx() will return the ONNX graph and a dictionary with shape information from TensorFlow. The shape information is helpful in some cases when processing individual ops.\nThe ONNX graph is wrapped in a Graph object and nodes in the graph are wrapped in a Node object to allow easier graph manipulations on the graph. All code that deals with nodes and graphs is in graph.py.\n\n### Step 3 - rewrite subgraphs\n\nIn the next step we apply graph matching code on the graph to re-write subgraphs for ops like transpose and lstm. For an example looks at rewrite_transpose().\n\n### Step 4 - process individual ops\n\nIn the fourth step we look at individual ops that need attention. The dictionary _OPS_MAPPING will map tensorflow op types to a method that is used to process the op. The simplest case is direct_op() where the op can be taken as is. Whenever possible we try to group ops into common processing, for example all ops that require dealing with broadcasting are mapped to broadcast_op(). For an op that composes the tensorflow op from multiple onnx ops, see relu6_op().\n\n### Step 5 - optimize the functional ONNX graph\n\nWe than try to optimize the functional ONNX graph. For example we remove ops that are not needed,\nremove transposes as much as possible, de-dupe constants, fuse ops whenever possible, ...\n\n### Step 6 - final processing\n\nOnce all ops are converted and optimize, we need to do a topological sort since ONNX requires it. process_tf_graph() is the method that takes care of all above steps.\n\n## Extending tf2onnx\n\nIf you like to contribute and add new conversions to tf2onnx, the process is something like:\n\n1. See if the op fits into one of the existing mappings. If so adding it to _OPS_MAPPING is all that is needed.\n2. If the new op needs extra processing, start a new mapping function.\n3. If the tensorflow op is composed of multiple ops, consider using a graph re-write. While this might be a little harder initially, it works better for complex patterns.\n4. Add a unit test in tests/test_backend.py. The unit tests mostly create the tensorflow graph, run it and capture the output, than convert to onnx, run against a onnx backend and compare tensorflow and onnx results.\n5. If there are pre-trained models that use the new op, consider adding those to test/run_pretrained_models.py.\n\n## License\n\n[Apache License v2.0](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonnx%2Ftensorflow-onnx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonnx%2Ftensorflow-onnx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonnx%2Ftensorflow-onnx/lists"}