Metadata-Version: 2.4
Name: onnx2keras
Version: 0.0.25
Summary: The deep learning models converter
Home-page: https://github.com/gmalivenko/onnx2keras
Author: Grigory Malivenko
Author-email: 
License: MIT
Keywords: machine-learning deep-learning pytorch keras neuralnetwork vgg resnet densenet drn dpn darknet squeezenet mobilenet
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tensorflow>=2.16
Requires-Dist: numpy
Requires-Dist: onnx
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# onnx2keras

ONNX to Keras deep neural network converter. 

[![GitHub License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Python Version](https://img.shields.io/badge/python-3.10%2B-lightgrey.svg)](https://github.com/gmalivenko/onnx2keras)
[![Downloads](https://pepy.tech/badge/onnx2keras)](https://pepy.tech/project/onnx2keras)
![PyPI](https://img.shields.io/pypi/v/onnx2keras.svg)

## Requirements

Python 3.10+ and TensorFlow 2.16 or newer (the first release that ships Keras 3).

Verified against Python 3.13, TensorFlow 2.21 / Keras 3.15, ONNX 1.22 and PyTorch 2.14,
with ONNX opsets 9 to 23 and both PyTorch exporters (`torch.onnx.export` with and without `dynamo=True`).

Note that TensorFlow only runs `channels_first` (NCHW) convolutions and poolings on a GPU.
To convert and run a model on a CPU, either use `change_ordering=True` or enable oneDNN,
which does implement them, by setting `TF_ENABLE_ONEDNN_OPTS=1` in the environment.

## API

`onnx_to_keras(onnx_model, input_names, input_shapes=None, name_policy=None, verbose=True, change_ordering=False) -> {Keras model}`

`onnx_model`: ONNX model to convert

`input_names`: list with graph input names

`input_shapes`: override input shapes (experimental)

`name_policy`: ['renumerate', 'short', 'default'] override layer names (experimental)

`verbose`: detailed output

`change_ordering:` change ordering to HWC (experimental)


## Getting started

### ONNX model
```python
import onnx
from onnx2keras import onnx_to_keras

# Load ONNX model
onnx_model = onnx.load('resnet18.onnx')

# Call the converter (input - is the main model input name, can be different for your model)
k_model = onnx_to_keras(onnx_model, ['input'])
```

Keras model will be stored to the `k_model` variable. So simple, isn't it?


### PyTorch model

Using ONNX as intermediate format, you can convert PyTorch model as well.

```python
import numpy as np
import torch
from torch.autograd import Variable
from pytorch2keras.converter import pytorch_to_keras
import torchvision.models as models

if __name__ == '__main__':
    input_np = np.random.uniform(0, 1, (1, 3, 224, 224))
    input_var = Variable(torch.FloatTensor(input_np))
    model = models.resnet18()
    model.eval()
    k_model = \
        pytorch_to_keras(model, input_var, [(3, 224, 224,)], verbose=True, change_ordering=True)

    for i in range(3):
        input_np = np.random.uniform(0, 1, (1, 3, 224, 224))
        input_var = Variable(torch.FloatTensor(input_np))
        output = model(input_var)
        pytorch_output = output.data.numpy()
        keras_output = k_model.predict(np.transpose(input_np, [0, 2, 3, 1]))
        error = np.max(pytorch_output - keras_output)
        print('error -- ', error)  # Around zero :)
```

### Deploying model to LiteRT (TensorFlow Lite)

Export the converted model to a SavedModel first, then convert that:

```python
k_model = onnx_to_keras(onnx_model, ['input'], change_ordering=True)
k_model.export('saved_model')

converter = tf.lite.TFLiteConverter.from_saved_model('saved_model')
open('model.tflite', 'wb').write(converter.convert())
```

`change_ordering=True` is required: LiteRT kernels are NHWC, and a `channels_first` model
does not convert without the Flex delegate. The resulting model uses only builtin ops, so
no `SELECT_TF_OPS` is needed. Remember that its input is NHWC, so feed it
`np.transpose(input_np, [0, 2, 3, 1])`.

### Deplying model as frozen graph

You can try using the snippet below to convert your onnx / PyTorch model to frozen graph. It may be useful for deploy for Tensorflow.js / for Tensorflow for Android / for Tensorflow C-API.

```python
import numpy as np
import torch
from pytorch2keras.converter import pytorch_to_keras
from torch.autograd import Variable
import tensorflow as tf
from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2


# Create and load model
model = Model()
model.load_state_dict(torch.load('model-checkpoint.pth'))
model.eval()

# Make dummy variables (and checking if the model works)
input_np = np.random.uniform(0, 1, (1, 3, 224, 224))
input_var = Variable(torch.FloatTensor(input_np))
output = model(input_var)

# Convert the model!
k_model = \
    pytorch_to_keras(model, input_var, (3, 224, 224), 
                     verbose=True, name_policy='short',
                     change_ordering=True)

# Save model to SavedModel format
tf.saved_model.save(k_model, "./models")

# Convert Keras model to ConcreteFunction
full_model = tf.function(lambda x: k_model(x))
full_model = full_model.get_concrete_function(
    tf.TensorSpec(k_model.inputs[0].shape, k_model.inputs[0].dtype))

# Get frozen ConcreteFunction
frozen_func = convert_variables_to_constants_v2(full_model)
frozen_func.graph.as_graph_def()

print("-" * 50)
print("Frozen model layers: ")
for layer in [op.name for op in frozen_func.graph.get_operations()]:
    print(layer)

print("-" * 50)
print("Frozen model inputs: ")
print(frozen_func.inputs)
print("Frozen model outputs: ")
print(frozen_func.outputs)

# Save frozen graph from frozen ConcreteFunction to hard drive
tf.io.write_graph(graph_or_graph_def=frozen_func.graph,
                  logdir="./frozen_models",
                  name="frozen_graph.pb",
                  as_text=False)
```


## License
This software is covered by MIT License.
