Skip to content

Commit 56f7fe1

Browse files
YUNQIUGUOwenbingl
andauthored
Cherry pick for 0.10.1 patch (#656)
* support python 3.12 for packaging pipeline (#650) * support python 3.12 for packaging pipeline * turn unit test build off for python package * update ctest flag for selected_ops build * make onnx package to be optional. (#653) * putting onnx package to be optional * update the ci.yml * add more message of missing ONNX package --------- Co-authored-by: Wenbing Li <10278425+wenbingl@users.noreply.github.com>
1 parent b9b3ebe commit 56f7fe1

12 files changed

Lines changed: 230 additions & 217 deletions

File tree

.pipelines/ci.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ stages:
8989
python -m pip install --upgrade pip
9090
python -m pip install --upgrade setuptools
9191
python -m pip install onnxruntime==$(ort.version)
92-
python -m pip install -r requirements.txt
93-
displayName: Install requirements.txt
92+
displayName: Install requirements
9493
9594
- script: |
9695
CPU_NUMBER=8 python -m pip install .
@@ -283,8 +282,7 @@ stages:
283282
python -m pip install --upgrade setuptools
284283
python -m pip install --upgrade wheel
285284
python -m pip install onnxruntime==$(ort.version)
286-
python -m pip install -r requirements.txt
287-
displayName: Install requirements.txt
285+
displayName: Install requirements
288286
289287
- script: |
290288
python -c "import onnxruntime;print(onnxruntime.__version__)"
@@ -419,7 +417,6 @@ stages:
419417
call activate pyenv
420418
python -m pip install --upgrade pip
421419
python -m pip install onnxruntime==$(ort.version)
422-
python -m pip install -r requirements.txt
423420
python -m pip install -r requirements-dev.txt
424421
displayName: Install requirements{-dev}.txt and cmake python modules
425422
@@ -653,7 +650,6 @@ stages:
653650
python3 -m pip install --upgrade pip; \
654651
python3 -m pip install --upgrade setuptools; \
655652
python3 -m pip install onnxruntime-gpu==$(ORT_VERSION); \
656-
python3 -m pip install -r requirements.txt; \
657653
python3 -m pip install -v --config-settings "ortx-user-option=use-cuda" . ; \
658654
python3 -m pip install $(TORCH_VERSION) ; \
659655
python3 -m pip install -r requirements-dev.txt; \

.pipelines/templates/onebranch-windows-build-stage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ stages:
1313
type: windows
1414

1515
variables:
16-
CIBW_BUILD: cp3{8,9,10,11}-*amd64
16+
CIBW_BUILD: cp3{8,9,10,11,12}-*amd64
1717
CIBW_ARCHS: AMD64
1818
CIBW_ENVIRONMENT: "${{ parameters.CibwEnv }}"
1919
CIBW_BUILD_VERBOSITY: 1

.pipelines/wheels_linux.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
timeoutInMinutes: 180
1010
pool: {name: 'Azure-Pipelines-EO-Ubuntu-2004-aiinfra'}
1111
variables:
12-
CIBW_BUILD: "cp3{8,9,10,11}-*"
12+
CIBW_BUILD: "cp3{8,9,10,11,12}-*"
1313
CIBW_ENVIRONMENT: "${{ parameters.ExtraEnv }}"
1414

1515
steps:
@@ -29,7 +29,7 @@ jobs:
2929
timeoutInMinutes: 180
3030
pool: {name: 'Azure-Pipelines-EO-Ubuntu-2004-aiinfra'}
3131
variables:
32-
CIBW_BUILD: "cp3{8,9,10,11}-*"
32+
CIBW_BUILD: "cp3{8,9,10,11,12}-*"
3333
CIBW_SKIP: "*musllinux_aarch64*"
3434
# AzureOp doesn't support aaarch64 yet.
3535
# CIBW_ENVIRONMENT: "${{ parameters.ExtraEnv }}"

.pipelines/wheels_macos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jobs:
44
pool:
55
vmImage: 'macOS-13'
66
variables:
7-
CIBW_BUILD: "cp3{8,9,10,11}-*"
7+
CIBW_BUILD: "cp3{8,9,10,11,12}-*"
88
CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
99
# Skip trying to test arm64 builds on Intel Macs
1010
# CIBW_TEST_SKIP: "*-macosx_arm64 *-macosx_universal2:arm64"

.pipelines/wheels_win32.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
timeoutInMinutes: 120
1010
pool: {name: 'onnxruntime-Win-CPU-2022'}
1111
variables:
12-
CIBW_BUILD: "cp3{8,9,10,11}-*amd64"
12+
CIBW_BUILD: "cp3{8,9,10,11,12}-*amd64"
1313
CIBW_ENVIRONMENT: "${{ parameters.ExtraEnv }}"
1414

1515
steps:

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ python -m pip install git+https://github.com/microsoft/onnxruntime-extensions.gi
3131

3232
## Usage
3333

34-
## 1. Generate the pre-/post- processing ONNX model
35-
With onnxruntime-extensions Python package, you can easily get the ONNX processing graph by converting them from Huggingface transformer data processing classes, check the following API for details.
34+
## 1. Generation of Pre-/Post-Processing ONNX Model
35+
The `onnxruntime-extensions` Python package provides a convenient way to generate the ONNX processing graph. This can be achieved by converting the Huggingface transformer data processing classes into the desired format. For more detailed information, please refer to the API below:
36+
3637
```python
3738
help(onnxruntime_extensions.gen_processing_models)
3839
```
39-
### NOTE: These data processing model can be merged into other model [onnx.compose](https://onnx.ai/onnx/api/compose.html) if needed.
40+
### NOTE:
41+
The generation of model processing requires the **ONNX** package to be installed. The data processing models generated in this manner can be merged with other models using the [onnx.compose](https://onnx.ai/onnx/api/compose.html) if needed.
42+
4043
## 2. Using Extensions for ONNX Runtime inference
4144

4245
### Python

onnxruntime_extensions/__init__.py

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,70 @@
1010

1111
__author__ = "Microsoft"
1212

13-
__all__ = [
14-
'gen_processing_models',
15-
'ort_inference',
16-
'get_library_path',
17-
'Opdef', 'onnx_op', 'PyCustomOpDef', 'PyOp',
18-
'enable_py_op',
19-
'expand_onnx_inputs',
20-
'hook_model_op',
21-
'default_opset_domain',
22-
'OrtPyFunction', 'PyOrtFunction',
23-
'optimize_model',
24-
'make_onnx_model',
25-
'ONNXRuntimeError',
26-
'hash_64',
27-
'__version__',
28-
]
2913

3014
from ._version import __version__
3115
from ._ocos import get_library_path
3216
from ._ocos import Opdef, PyCustomOpDef
3317
from ._ocos import hash_64
3418
from ._ocos import enable_py_op
35-
from ._ocos import expand_onnx_inputs
36-
from ._ocos import hook_model_op
3719
from ._ocos import default_opset_domain
38-
from ._cuops import * # noqa
39-
from ._ortapi2 import OrtPyFunction as PyOrtFunction # backward compatibility
40-
from ._ortapi2 import OrtPyFunction, ort_inference, optimize_model, make_onnx_model
41-
from ._ortapi2 import ONNXRuntimeError, ONNXRuntimeException
42-
from .cvt import gen_processing_models
20+
21+
22+
_lib_only = False
23+
24+
try:
25+
import onnx # noqa
26+
import onnxruntime # noqa
27+
except ImportError:
28+
_lib_only = True
29+
pass
30+
31+
32+
_offline_api = [
33+
"gen_processing_models",
34+
"ort_inference",
35+
"OrtPyFunction",
36+
"PyOrtFunction",
37+
"optimize_model",
38+
"make_onnx_model",
39+
"ONNXRuntimeError",
40+
]
41+
42+
__all__ = [
43+
"get_library_path",
44+
"Opdef",
45+
"onnx_op",
46+
"PyCustomOpDef",
47+
"PyOp",
48+
"enable_py_op",
49+
"expand_onnx_inputs",
50+
"hook_model_op",
51+
"default_opset_domain",
52+
"hash_64",
53+
"__version__",
54+
]
4355

4456
# rename the implementation with a more formal name
4557
onnx_op = Opdef.declare
4658
PyOp = PyCustomOpDef
59+
60+
61+
if _lib_only:
62+
63+
def _unimplemented(*args, **kwargs):
64+
raise NotImplementedError("ONNX or ONNX Runtime is not installed")
65+
66+
gen_processing_models = _unimplemented
67+
OrtPyFunction = _unimplemented
68+
ort_inference = _unimplemented
69+
70+
else:
71+
__all__ += _offline_api
72+
73+
from ._cuops import * # noqa
74+
from ._ortapi2 import hook_model_op
75+
from ._ortapi2 import expand_onnx_inputs
76+
from ._ortapi2 import OrtPyFunction, ort_inference, optimize_model, make_onnx_model
77+
from ._ortapi2 import OrtPyFunction as PyOrtFunction # backward compatibility
78+
from ._ortapi2 import ONNXRuntimeError, ONNXRuntimeException # noqa
79+
from .cvt import gen_processing_models

onnxruntime_extensions/_ocos.py

Lines changed: 22 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,48 @@
77
"""
88
import os
99
import sys
10-
import copy
1110
import glob
12-
import onnx
13-
from onnx import helper
1411

1512

1613
def _search_cuda_dir():
17-
paths = os.getenv('PATH', '').split(os.pathsep)
14+
paths = os.getenv("PATH", "").split(os.pathsep)
1815
for path in paths:
19-
for filename in glob.glob(os.path.join(path, 'cudart64*.dll')):
16+
for filename in glob.glob(os.path.join(path, "cudart64*.dll")):
2017
return os.path.dirname(filename)
2118

2219
return None
2320

2421

25-
if sys.platform == 'win32':
22+
if sys.platform == "win32":
2623
from . import _version # noqa: E402
27-
if hasattr(_version, 'cuda'):
24+
25+
if hasattr(_version, "cuda"):
2826
cuda_path = _search_cuda_dir()
2927
if cuda_path is None:
30-
raise RuntimeError(
31-
"Cannot locate CUDA directory in the environment variable for GPU package")
28+
raise RuntimeError("Cannot locate CUDA directory in the environment variable for GPU package")
3229

3330
os.add_dll_directory(cuda_path)
3431

3532

3633
from ._extensions_pydll import ( # noqa
37-
PyCustomOpDef, enable_py_op, add_custom_op, hash_64, default_opset_domain)
34+
PyCustomOpDef,
35+
enable_py_op,
36+
add_custom_op,
37+
hash_64,
38+
default_opset_domain,
39+
)
3840

3941

4042
def get_library_path():
4143
"""
4244
The custom operator library binary path
4345
:return: A string of this library path.
4446
"""
45-
mod = sys.modules['onnxruntime_extensions._extensions_pydll']
47+
mod = sys.modules["onnxruntime_extensions._extensions_pydll"]
4648
return mod.__file__
4749

4850

4951
class Opdef:
50-
5152
_odlist = {}
5253

5354
def __init__(self, op_type, func):
@@ -57,14 +58,14 @@ def __init__(self, op_type, func):
5758

5859
@staticmethod
5960
def declare(*args, **kwargs):
60-
if len(args) > 0 and hasattr(args[0], '__call__'):
61+
if len(args) > 0 and hasattr(args[0], "__call__"):
6162
raise RuntimeError("Unexpected arguments {}.".format(args))
6263
# return Opdef._create(args[0])
6364
return lambda f: Opdef.create(f, *args, **kwargs)
6465

6566
@staticmethod
6667
def create(func, *args, **kwargs):
67-
name = kwargs.get('op_type', None)
68+
name = kwargs.get("op_type", None)
6869
op_type = name or func.__name__
6970
opdef = Opdef(op_type, func)
7071
od_id = id(opdef)
@@ -76,15 +77,15 @@ def create(func, *args, **kwargs):
7677
opdef._nativedef.op_type = op_type
7778
opdef._nativedef.obj_id = od_id
7879

79-
inputs = kwargs.get('inputs', None)
80+
inputs = kwargs.get("inputs", None)
8081
if inputs is None:
8182
inputs = [PyCustomOpDef.dt_float]
8283
opdef._nativedef.input_types = inputs
83-
outputs = kwargs.get('outputs', None)
84+
outputs = kwargs.get("outputs", None)
8485
if outputs is None:
8586
outputs = [PyCustomOpDef.dt_float]
8687
opdef._nativedef.output_types = outputs
87-
attrs = kwargs.get('attrs', None)
88+
attrs = kwargs.get("attrs", None)
8889
if attrs is None:
8990
attrs = {}
9091
elif isinstance(attrs, (list, tuple)):
@@ -106,16 +107,15 @@ def cast_attributes(self, attributes):
106107
elif self._nativedef.attrs[k] == PyCustomOpDef.dt_string:
107108
res[k] = v
108109
else:
109-
raise RuntimeError("Unsupported attribute type {}.".format(
110-
self._nativedef.attrs[k]))
110+
raise RuntimeError("Unsupported attribute type {}.".format(self._nativedef.attrs[k]))
111111
return res
112112

113113

114114
def _on_pyop_invocation(k_id, feed, attributes):
115115
if k_id not in Opdef._odlist:
116116
raise RuntimeError(
117-
"Unable to find function id={}. "
118-
"Did you decorate the operator with @onnx_op?.".format(k_id))
117+
"Unable to find function id={}. " "Did you decorate the operator with @onnx_op?.".format(k_id)
118+
)
119119
op_ = Opdef._odlist[k_id]
120120
rv = op_.body(*feed, **op_.cast_attributes(attributes))
121121
if isinstance(rv, tuple):
@@ -127,86 +127,7 @@ def _on_pyop_invocation(k_id, feed, attributes):
127127
res = tuple(res)
128128
else:
129129
res = (rv.shape, rv.flatten().tolist())
130-
return (k_id, ) + res
131-
132-
133-
def _ensure_opset_domain(model):
134-
op_domain_name = default_opset_domain()
135-
domain_missing = True
136-
for oi_ in model.opset_import:
137-
if oi_.domain == op_domain_name:
138-
domain_missing = False
139-
140-
if domain_missing:
141-
model.opset_import.extend(
142-
[helper.make_operatorsetid(op_domain_name, 1)])
143-
144-
return model
145-
146-
147-
def expand_onnx_inputs(model, target_input, extra_nodes, new_inputs):
148-
"""
149-
Replace the existing inputs of a model with the new inputs, plus some extra nodes
150-
:param model: The ONNX model loaded as ModelProto
151-
:param target_input: The input name to be replaced
152-
:param extra_nodes: The extra nodes to be added
153-
:param new_inputs: The new input (type: ValueInfoProto) sequence
154-
:return: The ONNX model after modification
155-
"""
156-
graph = model.graph
157-
new_inputs = [n for n in graph.input if n.name !=
158-
target_input] + new_inputs
159-
new_nodes = list(model.graph.node) + extra_nodes
160-
new_graph = helper.make_graph(
161-
new_nodes, graph.name, new_inputs, list(graph.output), list(graph.initializer))
162-
163-
new_model = copy.deepcopy(model)
164-
new_model.graph.CopyFrom(new_graph)
165-
166-
return _ensure_opset_domain(new_model)
167-
168-
169-
def hook_model_op(model, node_name, hook_func, input_types):
170-
"""
171-
Add a hook function node in the ONNX Model, which could be used for the model diagnosis.
172-
:param model: The ONNX model loaded as ModelProto
173-
:param node_name: The node name where the hook will be installed
174-
:param hook_func: The hook function, callback on the model inference
175-
:param input_types: The input types as a list
176-
:return: The ONNX model with the hook installed
177-
"""
178-
179-
# onnx.shape_inference is very unstable, useless.
180-
# hkd_model = shape_inference.infer_shapes(model)
181-
hkd_model = model
182-
183-
n_idx = 0
184-
hnode, nnode = (None, None)
185-
nodes = list(hkd_model.graph.node)
186-
brkpt_name = node_name + '_hkd'
187-
optype_name = "op_{}_{}".format(hook_func.__name__, node_name)
188-
for n_ in nodes:
189-
if n_.name == node_name:
190-
input_names = list(n_.input)
191-
brk_output_name = [i_ + '_hkd' for i_ in input_names]
192-
hnode = onnx.helper.make_node(
193-
optype_name, n_.input, brk_output_name, name=brkpt_name, domain=default_opset_domain())
194-
nnode = n_
195-
del nnode.input[:]
196-
nnode.input.extend(brk_output_name)
197-
break
198-
n_idx += 1
199-
200-
if hnode is None:
201-
raise ValueError("{} is not an operator node name".format(node_name))
202-
203-
repacked = nodes[:n_idx] + [hnode, nnode] + nodes[n_idx+1:]
204-
del hkd_model.graph.node[:]
205-
hkd_model.graph.node.extend(repacked)
206-
207-
Opdef.create(hook_func, op_type=optype_name,
208-
inputs=input_types, outputs=input_types)
209-
return _ensure_opset_domain(hkd_model)
130+
return (k_id,) + res
210131

211132

212133
PyCustomOpDef.install_hooker(_on_pyop_invocation)

0 commit comments

Comments
 (0)