Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build light weight PyRuntime without llvm or onnx-mlir #3044

Merged
merged 15 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
document
Signed-off-by: Chen Tong <chentong@us.ibm.com>
  • Loading branch information
chentong319 committed Jan 15, 2025
commit beff2e3b3c7fdbff32cf14cbcc18a4742cc044e9
35 changes: 35 additions & 0 deletions docs/BuildPyRuntimeLit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# How to build and use PyRuntime lit

## Purpsoe

PyRuntime lit is a different way to build the original PyRuntime (src/Runtime/python).
All necessary dependence, such as llvm_project and onnx-mlir compiler is removed. The purpose is to easily build the python driver for the model execution on
different systems. Currently, only the OMTenserUtils (src/Runtime), Python driver (src/Runtime/python), third_party/onnx and third_party/pybind11 are built.

The build of PyRuntime lit is controlled by a CMake option: ONNX_MLIR_ENABLE_PYRUNTIME_LIT. Without this option to cmake, the whole system remains the same.

## Functionalities
1. Build the python driver without llvm_project and onnx-mlir compiler built.
2. The python driver can be used with utils/RunONNXModel.py, or onnxmlir python package.
3. With PyRuntime lit, the compiler has not been built locally and docker image of onnx-mlir has to be usd to compile the model. The onnxmlir package contains
the python code to use python docker package to perform the compilation. Alternatively, the old script, onnx-mlir/docker/onnx-mlir.py, can do the fulfill the same task with subprocess and docker CLI.

## How to use
You can find the script for build and run at "onnx-mlir/utils/build-pyruntime-lit.sh.
```
#!/bin/bash

# Assume you are in an empty directory for build in cloned onnx-mlir.
# Usually it is "your_path/onnx-mlir/build"
# then you can run this script as "../util/build-pyruntime-lit.sh"

cmake .. -DONNX_MLIR_ENABLE_PYRUNTIME_LIT=ON
make
make OMCreatePyRuntimePackage

# Install the package
pip3 install src/Runtime/python/onnxmlir

# Run test case
python3 src/Runtime/python/onnxmlir/test/test_1.py
```
9 changes: 4 additions & 5 deletions src/Runtime/ExecutionSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <errno.h>
#include <string.h>


#include <iostream>
#include <memory>
#include <sstream>
Expand Down Expand Up @@ -83,7 +82,7 @@ void ExecutionSession::Init(
throw std::runtime_error(reportLibraryOpeningError(sharedLibPath));
#else
// Copy code from llvm/lib/Support/DynamicLibrary.cpp, especially the flags
// ToFix: copy the lock related code too.
// ToFix: copy the lock related code too.
_sharedLibraryHandle = dlopen(sharedLibPath.c_str(), RTLD_LAZY | RTLD_GLOBAL);
if (!_sharedLibraryHandle)
throw std::runtime_error(reportLibraryOpeningError(sharedLibPath));
Expand All @@ -96,7 +95,7 @@ void ExecutionSession::Init(
queryEntryPointsNameWithTag.c_str()));
#else
_queryEntryPointsFunc = reinterpret_cast<queryEntryPointsFuncType>(
dlsym(_sharedLibraryHandle, queryEntryPointsNameWithTag.c_str()));
dlsym(_sharedLibraryHandle, queryEntryPointsNameWithTag.c_str()));
#endif

if (!_queryEntryPointsFunc)
Expand Down Expand Up @@ -151,7 +150,7 @@ void ExecutionSession::Init(
}

ExecutionSession::~ExecutionSession() {
#ifndef ENABLE_PYRUNTIME_LIT
#ifndef ENABLE_PYRUNTIME_LIT
if (_sharedLibraryHandle.isValid())
llvm::sys::DynamicLibrary::closeLibrary(_sharedLibraryHandle);
#else
Expand All @@ -174,7 +173,7 @@ const std::string *ExecutionSession::queryEntryPoints(
void ExecutionSession::setEntryPoint(const std::string &entryPointName) {
if (!isInitialized)
throw std::runtime_error(reportInitError());
#ifndef ENABLE_PYRUNTIME_LIT
#ifndef ENABLE_PYRUNTIME_LIT
_entryPointFunc = reinterpret_cast<entryPointFuncType>(
_sharedLibraryHandle.getAddressOfSymbol(entryPointName.c_str()));
#else
Expand Down
2 changes: 1 addition & 1 deletion src/Runtime/ExecutionSession.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "llvm/Support/DynamicLibrary.h"
typedef llvm::sys::DynamicLibrary DynamicLibraryHandleType;
#else
typedef void* DynamicLibraryHandleType;
typedef void *DynamicLibraryHandleType;
#endif

namespace onnx_mlir {
Expand Down
4 changes: 1 addition & 3 deletions src/Runtime/python/PyRuntime.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
try:
from .PyRuntimeC import OMExecutionSession as OMExecutionSession_
except ImportError:
raise ImportError(
"Failure to load the prebuild PyRuntimeC.*.so."
)
raise ImportError("Failure to load the prebuild PyRuntimeC.*.so.")
else:
try:
from PyRuntimeC import OMExecutionSession as OMExecutionSession_
Expand Down
6 changes: 3 additions & 3 deletions src/Runtime/python/onnxmlir/tests/test_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
import numpy as np
import onnxmlirdocker

#sess = onnxmlirdocker.InferenceSession("test_add.so")
# sess = onnxmlirdocker.InferenceSession("test_add.so")
sess = onnxmlirdocker.InferenceSession("test_add.onnx")

a = np.zeros((3, 4, 5), dtype=np.float32)
b = a + 4

# Run with list of array
#r = sess.run(None, [a, b])
# r = sess.run(None, [a, b])

# Run with dictionary
r = sess.run(None, {'x': a, 'y': b})
r = sess.run(None, {"x": a, "y": b})
print(r)
68 changes: 40 additions & 28 deletions src/Runtime/python/onnxmlirdocker.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,42 @@
import tempfile
import json


def get_names_in_signature(signature):
names = []
names = []
# Load the input signature.
signature_dict = json.loads(signature)
for sig in signature_dict:
names.append(sig["name"])
return names


class InferenceSession:
def __init__(self, model_path, **kwargs):
if model_path.endswith(".mlir") :
if model_path.endswith(".mlir"):
model_suffix = ".mlir"
elif model_path.endswith(".onnx") :
elif model_path.endswith(".onnx"):
model_suffix = ".onnx"
elif model_path.endswith(".so") :
elif model_path.endswith(".so"):
self.compiled_lib = os.path.abspath(model_path)
self.session = self.getSession()
return;
else :
print(
"Invalid input model path. Must end with .onnx or .mlir or .onnxtext"
)
return
else:
print("Invalid input model path. Must end with .onnx or .mlir or .onnxtext")
exit(1)

if "compile-options" in kwargs.keys():
self.compile_options = kwargs["compile-options"]
else:
self.compile_options = ""


if "onnx-mlir-container" in kwargs.keys():
self.compiler_container = kwargs["onnx-mlir-container"]
else:
# Default image
# The compiler command may have different path in different image
#self.onnx_mlir_image = "ghcr.io/onnxmlir/onnx-mlir-dev"
# self.onnx_mlir_image = "ghcr.io/onnxmlir/onnx-mlir-dev"
self.onnx_mlir_image = "onnxmlir/onnx-mlir-dev"


# Path to mount the model to the image
self.container_model_dirname = "/myinput"
Expand All @@ -57,25 +55,41 @@ def __init__(self, model_path, **kwargs):
absolute_path = os.path.abspath(self.model_path)
self.model_basename = os.path.basename(absolute_path)
self.model_dirname = os.path.dirname(absolute_path)

# Compiled library
command_str += " " + self.compile_options
command_str += " " + os.path.join(self.container_model_dirname, self.model_basename)
command_str += " " + os.path.join(
self.container_model_dirname, self.model_basename
)

# ToFix: should use temporary directory for compilation, and
# use "-o" to put the compiled library in the temporary directory.
self.output_tempdir = tempfile.TemporaryDirectory()
self.output_dirname = self.output_tempdir.name
self.compiled_model = os.path.join(self.output_dirname, self.model_basename.removesuffix(model_suffix)+".so")
command_str += " -o " + os.path.join(self.container_output_dirname, self.model_basename.removesuffix(model_suffix))
self.compiled_model = os.path.join(
self.output_dirname, self.model_basename.removesuffix(model_suffix) + ".so"
)
command_str += " -o " + os.path.join(
self.container_output_dirname,
self.model_basename.removesuffix(model_suffix),
)

self.container_client = docker.from_env()
# Logically, the model directory could be mounted as read only.
# But wrong time error occurred with "r" mode
msg=self.container_client.containers.run(self.onnx_mlir_image,
msg = self.container_client.containers.run(
self.onnx_mlir_image,
command_str,
volumes={self.model_dirname: {'bind': self.container_model_dirname, 'mode': 'rw'}, self.output_dirname: {'bind': self.container_output_dirname, 'mode': 'rw'}
}
volumes={
self.model_dirname: {
"bind": self.container_model_dirname,
"mode": "rw",
},
self.output_dirname: {
"bind": self.container_output_dirname,
"mode": "rw",
},
},
)
print("afterwards tempdir: ", [f for f in os.listdir(self.output_dirname)])
self.session = self.getSession()
Expand All @@ -85,24 +99,22 @@ def getSession(self):
# are within the package. Path in the pakcage should be used.
# Otherwise, env variable ONNX_MLIR_HOME is used to for import path
if __package__ == "onnxmlir":
try:
try:
from .PyRuntime import OMExecutionSession
except ImportError:
raise ImportError(
" Error in importing PyRuntime for onnxmlir package"
)
raise ImportError(" Error in importing PyRuntime for onnxmlir package")

else:
if not os.environ.get("ONNX_MLIR_HOME", None):
raise RuntimeError(
"Environment variable ONNX_MLIR_HOME is not set, please set it to the path to "
"Environment variable ONNX_MLIR_HOME is not set, please set it to the path to "
"the HOME directory for onnx-mlir. The HOME directory for onnx-mlir refers to "
"the parent folder containing the bin, lib, etc sub-folders in which ONNX-MLIR "
"execu tables and libraries can be found, typically `onnx-mlir/build/Debug`"
)
"execu tables and libraries can be found, typically `onnx-mlir/build/Debug`"
)
RUNTIME_DIR = os.path.join(os.environ["ONNX_MLIR_HOME"], "lib")
sys.path.append(RUNTIME_DIR)
try:
try:
from PyRuntime import OMExecutionSession
except ImportError:
raise ImportError(
Expand Down Expand Up @@ -135,5 +147,5 @@ def run(self, outputname, input_feed, **kwargs):
# Provide random value inputs
print("error: input is not provided. ToFix: random input")
exit(1)

return self.session.run(inputs)
15 changes: 15 additions & 0 deletions utils/build-pyruntime-lit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# Assume you are in an empty directory for build in cloned onnx-mlir.
# Usually it is "your_path/onnx-mlir/build"
# then you can run this script as "../util/build-pyruntime-lit.sh"

cmake .. -DONNX_MLIR_ENABLE_PYRUNTIME_LIT=ON
make
make OMCreatePyRuntimePackage

# Install the package
pip3 install src/Runtime/python/onnxmlir

# Run test case
python3 src/Runtime/python/onnxmlir/test/test_1.py
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy