Skip to content

Commit

Permalink
Add Python interface for compilation and one single interface for com…
Browse files Browse the repository at this point in the history
…pilation and running process (#1690)

* Add compiler interface to python

Signed-off-by: Jiaqing Chen <jchen501@asu.edu>
Co-authored-by: Alexandre Eichenberger <alexe@us.ibm.com>
  • Loading branch information
Jiaqing-ASU and AlexandreEichenberger authored Oct 24, 2022
1 parent 5062461 commit fdbd1f0
Show file tree
Hide file tree
Showing 19 changed files with 1,137 additions and 76 deletions.
222 changes: 208 additions & 14 deletions docs/UsingPyRuntime.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
<!--- SPDX-License-Identifier: Apache-2.0 -->

# Using PyRuntime
# Using Python interfaces

onnx-mlir has a runtime utility to run ONNX models compiled as a shared library
by `onnx-mlir --EmitLib`. The runtime is implemented in C++ by the `ExecutionSession` class
(src/Runtime/ExecutionSession.hpp) and has an associated Python binding generated by
[pybind library](https://github.com/pybind/pybind11).
Onnx-mlir has runtime utilities to compile and run ONNX models in Python.
These utilities are implemented by the `OnnxMlirCompiler` compiler interface
(include/OnnxMlirCompiler.h) and the `ExecutionSession` class
(src/Runtime/ExecutionSession.hpp).
Both utilities have an associated Python binding generated by [pybind library](https://github.com/pybind/pybind11).

## PyRuntime Module
## Configuring the Python interfaces

Using pybind, a C/C++ binary can be directly imported by the Python interpreter. For onnx-mlir,
such binary is generated by `PyExecutionSession` (src/Runtime/PyExecutionSession.hpp) and built
as a shared library to `build/Debug/lib/PyRuntime.cpython-<target>.so`.
Using pybind, a C/C++ binary can be directly imported by the Python interpreter.
For onnx-mlir, there are three such libraries, one to compile onnx-mlir models,
one to run the models and the other one is to compile and run the models.

## Configuring and using PyRuntime
1. The library to compile onnx-mlir models is generated
by `PyOMCompileSession` (src/Compiler/PyOMCompileSession.hpp) and build as a shared
library to `build/Debug/lib/PyCompile.cpython-<target>.so`.
2. The library to run onnx-mlir models is generated
by by `PyExecutionSession` (src/Runtime/PyExecutionSession.hpp) and built
as a shared library to `build/Debug/lib/PyRuntime.cpython-<target>.so`.
3. The library to compile and run onnx-mlir models is generated
by by `PyOMCompileExecutionSession` (src/Runtime/PyOMCompileExecutionSession.hpp) and built
as a shared library to `build/Debug/lib/PyCompileAndRuntime.cpython-<target>.so`.
This lobrary takes an .onnx file and the options as inputs, it will load it and then compile and run it.

### Configuration
The module can be imported normally by the Python interpreter as long as it is in your
PYTHONPATH. Another alternative is to create a symbolic link to it in your working directory.

```shell
cd <working directory>
ln -s <path to PyRuntime>
ln -s <path to PyCompile>
ln -s <path to PyCompileAndRuntime>
python3
```

### Running the PyRuntime interface
# Python interface to run models: PyRuntime

## Running the PyRuntime interface

An ONNX model is a computation graph and it is often the case that the graph
has a single entry point to trigger the computation. Below is an example of doing
Expand Down Expand Up @@ -80,8 +93,8 @@ for entry_point in entry_points:
```

## PyRuntime model API
The complete interface to ExecutionSession can be seen in the sources mentioned previously. However,
using the constructor and run method is enough to perform inferences.
The complete interface to ExecutionSession can be seen in the sources mentioned previously.
However, using the constructor and run method is enough to perform inferences.

```python
def __init__(self, shared_lib_path: str, use_default_entry_point: bool):
Expand Down Expand Up @@ -124,3 +137,184 @@ def set_entry_point(self, name: str):
name: an entry point name.
"""
```

# Python interface to compile models: PyCompile

## Running the PyCompile interface

An ONNX model can be compiled directly from the command line. The resulting library can then be executed using Python as shown in the previous sections. At times, it might be convenient to also compile a model directly in Python. This section explores the Python methods to do so.

The PyOMCompileSession object will take a file name while constructing. For the compilation, `compile()` will take a `flags` string as an input which will override any default options set from the env var.

```python
import numpy as np
from PyCompile import PyOMCompileSession

# Load onnx model and create PyOMCompileSession object.
file = './mnist.onnx'
compiler = PyOMCompileSession(file)
# Generate the library file. Success when rc == 0 while set the opt as "-O3"
rc = compiler.compile("-O3")
# Get the output file name
model = compiler.get_compiled_file_name()
if rc:
print("Failed to compile with error code", rc)
exit(1)
print("Compiled onnx file", file, "to", model, "with rc", rc)
```

The `PyCompile` module exports the `PyOMCompileSession` class to drive the
compilation of a ONNX model into an executable model.
Typically, a compiler object is created for a given model by giving it the file name of the ONNX model.
Then, all the compiler options can be set as a whole `std::string` to generate the desired executable.
Finally, the compilation itself is performed by calling the `compile()` command where the user passes the options string as the input of this function.

The `compile()` commands returns a return code reflecting the status of the compilation.
A zero value indicates success, and nonzero values reflect the error code.
Because different Operating Systems may have different suffixes for libraries,
the output file name can be retrieved using the `get_compiled_file_name()` method.

## PyCompile model API

The complete interface to OnnxMlirCompiler can be seen in the sources mentioned previously.
However, using the constructor and the methods below are enough to compile models.

```python
def __init__(self, file_name: str):
"""
Constructor for an ONNX model contained in a file.
Args:
file_name: relative or absolute path to your ONNX model.
"""
def __init__(self, input_buffer: void *, buffer_size: int):
"""
Constructor for an ONNX model contained in an input buffer.
Args:
input_buffer: buffer containing the protobuf representation of the model.
buffer_size: byte size of the input buffer.
"""
def compile(self, flags: str):
"""
Method to compile a model from a file.
Args:
flags: all the options users would like to set.
Returns:
Zero on success, error code on failure.
"""
def compile_from_array(self, output_base_name: str, target: OnnxMlirTarget):
"""
Method to compile a model from an array.
Args:
output_base_name: base name (relative or absolute, without suffix)
where the compiled model should be written into.
target: target for the compiler's output. Typical values are
OnnxMlirTarget.emit_lib or emit_jni.
Returns:
Zero on success, error code on failure.
"""
def get_compiled_file_name(self):
"""
Method to provide the full (absolute or relative) output compiled file name, including
its suffix.
Returns:
String containing the fle name after successful compilation; empty string on failure.
"""
def get_error_message(self):
"""
Method to provide the compilation error message.
Returns:
String containing the error message; empty string on success.
"""
```

# Python interface to compile and run models: PyCompileAndRuntime

## Running the PyCompileAndRuntime interface

```python
import numpy as np
from PyCompileAndRuntime import PyOMCompileExecutionSession

# Load onnx model and create CompileExecutionSession object.
inputFileName = './mnist.onnx'
# Set the full name of compiled model
sharedLibPath = './mnist.so'
# Set the compile option as "-O3"
session = PyOMCompileExecutionSession(inputFileName,sharedLibPath,"-O3")

# Print the models input/output signature, for display.
# Signature functions for info only, commented out if they cause problems.
session.print_input_signature()
session.print_output_signature()

# Do inference using the default entry point.
a = np.full((1, 1, 28, 28), 1, np.dtype(np.float32))
outputs = session.run(input=[a])

for output in outputs:
print(output.shape)
```

## PyCompileAndRuntime model API

The PyCompileAndRuntime is a new class, which combines compile and execution. Its constructor takes the `.onnx` input file and compile the model with the options given by the user and then run the model with an input.

```python
def __init__(self, input_model_path: str, compiled_file_path: str, flags: str, use_default_entry_point: bool):
"""
Constructor for an ONNX model contained in a file.
Args:
input_model_path: relative or absolute path to your ONNX model.
compiled_file_path: relative or absolute path to your compiled file.
flags: all the options users would like to set.
use_default_entry_point: use the default entry point that is `run_main_graph` or not. Set to True by default.
"""
def get_compiled_result(self):
"""
Method to provide the results of the compilation.
Returns:
Int containing the results. 0 represents successful compilation; others on failure.
"""
def get_compiled_file_name(self):
"""
Method to provide the full (absolute or relative) output file name, including
its suffix.
Returns:
String containing the fle name after successful compilation; empty string on failure.
"""
def get_error_message(self):
"""
Method to provide the compilation error message.
Returns:
String containing the error message; empty string on success.
"""
def entry_points(self) -> List[str]:
"""
Returns:
A list of entry point names.
"""
def set_entry_point(self, name: str):
"""
Args:
name: an entry point name.
"""
def run(self, input: List[ndarray]) -> List[ndarray]:
"""
Args:
input: A list of NumPy arrays, the inputs of your model.
Returns:
A list of NumPy arrays, the outputs of your model.
"""
def input_signature(self) -> str:
"""
Returns:
A string containing a JSON representation of the model's input signature.
"""

def output_signature(self) -> str:
"""
Returns:
A string containing a JSON representation of the model's output signature.
"""
```
Loading

0 comments on commit fdbd1f0

Please sign in to comment.