onnx-ir 0.1.3__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of onnx-ir might be problematic. Click here for more details.
- {onnx_ir-0.1.3/src/onnx_ir.egg-info → onnx_ir-0.1.5}/PKG-INFO +2 -1
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/README.md +1 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/__init__.py +1 -1
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_core.py +15 -19
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_enums.py +49 -0
- onnx_ir-0.1.5/src/onnx_ir/_type_casting.py +50 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/__init__.py +4 -0
- onnx_ir-0.1.5/src/onnx_ir/passes/common/identity_elimination.py +97 -0
- onnx_ir-0.1.5/src/onnx_ir/py.typed +1 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/serde.py +74 -46
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/tensor_adapters.py +3 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5/src/onnx_ir.egg-info}/PKG-INFO +2 -1
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir.egg-info/SOURCES.txt +2 -0
- onnx_ir-0.1.3/src/onnx_ir/_type_casting.py +0 -107
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/LICENSE +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/MANIFEST.in +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/pyproject.toml +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/setup.cfg +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_convenience/__init__.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_convenience/_constructors.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_display.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_graph_comparison.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_graph_containers.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_io.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_linked_list.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_metadata.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_name_authority.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_polyfill.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_protocols.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_tape.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_thirdparty/asciichartpy.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/_version_utils.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/convenience.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/external_data.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/__init__.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/_pass_infra.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/_c_api_utils.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/clear_metadata_and_docstring.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/common_subexpression_elimination.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/constant_manipulation.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/initializer_deduplication.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/inliner.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/onnx_checker.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/shape_inference.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/topological_sort.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/unused_removal.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/tape.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/testing.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/traversal.py +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir.egg-info/dependency_links.txt +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir.egg-info/requires.txt +0 -0
- {onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onnx-ir
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Efficient in-memory representation for ONNX
|
|
5
5
|
Author-email: ONNX Contributors <onnx-technical-discuss@lists.lfaidata.foundation>
|
|
6
6
|
License: Apache License v2.0
|
|
@@ -30,6 +30,7 @@ Dynamic: license-file
|
|
|
30
30
|
[](https://github.com/astral-sh/ruff)
|
|
31
31
|
[](https://codecov.io/gh/onnx/ir-py)
|
|
32
32
|
[](https://deepwiki.com/onnx/ir-py)
|
|
33
|
+
[](https://pepy.tech/projects/onnx-ir)
|
|
33
34
|
|
|
34
35
|
An in-memory IR that supports the full ONNX spec, designed for graph construction, analysis and transformation.
|
|
35
36
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](https://github.com/astral-sh/ruff)
|
|
6
6
|
[](https://codecov.io/gh/onnx/ir-py)
|
|
7
7
|
[](https://deepwiki.com/onnx/ir-py)
|
|
8
|
+
[](https://pepy.tech/projects/onnx-ir)
|
|
8
9
|
|
|
9
10
|
An in-memory IR that supports the full ONNX spec, designed for graph construction, analysis and transformation.
|
|
10
11
|
|
|
@@ -78,6 +78,7 @@ _NON_NUMPY_NATIVE_TYPES = frozenset(
|
|
|
78
78
|
_enums.DataType.FLOAT8E4M3FNUZ,
|
|
79
79
|
_enums.DataType.FLOAT8E5M2,
|
|
80
80
|
_enums.DataType.FLOAT8E5M2FNUZ,
|
|
81
|
+
_enums.DataType.FLOAT8E8M0,
|
|
81
82
|
_enums.DataType.INT4,
|
|
82
83
|
_enums.DataType.UINT4,
|
|
83
84
|
_enums.DataType.FLOAT4E2M1,
|
|
@@ -261,6 +262,7 @@ def _check_numpy_representation_type(array: np.ndarray, dtype: _enums.DataType)
|
|
|
261
262
|
ml_dtypes.float8_e4m3fn,
|
|
262
263
|
ml_dtypes.float8_e5m2fnuz,
|
|
263
264
|
ml_dtypes.float8_e5m2,
|
|
265
|
+
ml_dtypes.float8_e8m0fnu,
|
|
264
266
|
):
|
|
265
267
|
raise TypeError(
|
|
266
268
|
f"The numpy array dtype must be uint8 or ml_dtypes.float8* (not {array.dtype}) for IR data type {dtype}."
|
|
@@ -319,6 +321,8 @@ def _maybe_view_np_array_with_ml_dtypes(
|
|
|
319
321
|
return array.view(ml_dtypes.float8_e5m2)
|
|
320
322
|
if dtype == _enums.DataType.FLOAT8E5M2FNUZ:
|
|
321
323
|
return array.view(ml_dtypes.float8_e5m2fnuz)
|
|
324
|
+
if dtype == _enums.DataType.FLOAT8E8M0:
|
|
325
|
+
return array.view(ml_dtypes.float8_e8m0fnu)
|
|
322
326
|
if dtype == _enums.DataType.INT4:
|
|
323
327
|
return array.view(ml_dtypes.int4)
|
|
324
328
|
if dtype == _enums.DataType.UINT4:
|
|
@@ -657,15 +661,13 @@ class ExternalTensor(TensorBase, _protocols.TensorProtocol): # pylint: disable=
|
|
|
657
661
|
self._array = np.empty(self.shape.numpy(), dtype=self.dtype.numpy())
|
|
658
662
|
return
|
|
659
663
|
# Map the whole file into the memory
|
|
660
|
-
# TODO(justinchuby): Verify if this would exhaust the memory address space
|
|
661
664
|
with open(self.path, "rb") as f:
|
|
662
665
|
self.raw = mmap.mmap(
|
|
663
666
|
f.fileno(),
|
|
664
667
|
0,
|
|
665
668
|
access=mmap.ACCESS_READ,
|
|
666
669
|
)
|
|
667
|
-
|
|
668
|
-
dt = np.dtype(self.dtype.numpy()).newbyteorder("<")
|
|
670
|
+
|
|
669
671
|
if self.dtype in {
|
|
670
672
|
_enums.DataType.INT4,
|
|
671
673
|
_enums.DataType.UINT4,
|
|
@@ -675,16 +677,18 @@ class ExternalTensor(TensorBase, _protocols.TensorProtocol): # pylint: disable=
|
|
|
675
677
|
dt = np.dtype(np.uint8).newbyteorder("<")
|
|
676
678
|
count = self.size // 2 + self.size % 2
|
|
677
679
|
else:
|
|
680
|
+
# Handle the byte order correctly by always using little endian
|
|
681
|
+
dt = np.dtype(self.dtype.numpy()).newbyteorder("<")
|
|
678
682
|
count = self.size
|
|
683
|
+
|
|
679
684
|
self._array = np.frombuffer(self.raw, dtype=dt, offset=self.offset or 0, count=count)
|
|
680
685
|
shape = self.shape.numpy()
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
self._array = _type_casting.unpack_float4e2m1(self._array, shape)
|
|
686
|
+
|
|
687
|
+
if self.dtype.bitwidth == 4:
|
|
688
|
+
# Unpack the 4bit arrays
|
|
689
|
+
self._array = _type_casting.unpack_4bitx2(self._array, shape).view(
|
|
690
|
+
self.dtype.numpy()
|
|
691
|
+
)
|
|
688
692
|
else:
|
|
689
693
|
self._array = self._array.reshape(shape)
|
|
690
694
|
|
|
@@ -1071,15 +1075,7 @@ class PackedTensor(TensorBase, _protocols.TensorProtocol, Generic[TArrayCompatib
|
|
|
1071
1075
|
"""
|
|
1072
1076
|
array = self.numpy_packed()
|
|
1073
1077
|
# ONNX IR returns the unpacked arrays
|
|
1074
|
-
|
|
1075
|
-
return _type_casting.unpack_int4(array, self.shape.numpy())
|
|
1076
|
-
if self.dtype == _enums.DataType.UINT4:
|
|
1077
|
-
return _type_casting.unpack_uint4(array, self.shape.numpy())
|
|
1078
|
-
if self.dtype == _enums.DataType.FLOAT4E2M1:
|
|
1079
|
-
return _type_casting.unpack_float4e2m1(array, self.shape.numpy())
|
|
1080
|
-
raise TypeError(
|
|
1081
|
-
f"PackedTensor only supports INT4, UINT4, FLOAT4E2M1, but got {self.dtype}"
|
|
1082
|
-
)
|
|
1078
|
+
return _type_casting.unpack_4bitx2(array, self.shape.numpy()).view(self.dtype.numpy())
|
|
1083
1079
|
|
|
1084
1080
|
def numpy_packed(self) -> npt.NDArray[np.uint8]:
|
|
1085
1081
|
"""Return the tensor as a packed array."""
|
|
@@ -65,6 +65,7 @@ class DataType(enum.IntEnum):
|
|
|
65
65
|
UINT4 = 21
|
|
66
66
|
INT4 = 22
|
|
67
67
|
FLOAT4E2M1 = 23
|
|
68
|
+
FLOAT8E8M0 = 24
|
|
68
69
|
|
|
69
70
|
@classmethod
|
|
70
71
|
def from_numpy(cls, dtype: np.dtype) -> DataType:
|
|
@@ -81,6 +82,7 @@ class DataType(enum.IntEnum):
|
|
|
81
82
|
|
|
82
83
|
# Special cases for handling custom dtypes defined in ONNX (as of onnx 1.18)
|
|
83
84
|
# Ref: https://github.com/onnx/onnx/blob/2d42b6a60a52e925e57c422593e88cc51890f58a/onnx/_custom_element_types.py
|
|
85
|
+
# TODO(#137): Remove this when ONNX 1.19 is the minimum requirement
|
|
84
86
|
if hasattr(dtype, "names"):
|
|
85
87
|
if dtype.names == ("bfloat16",):
|
|
86
88
|
return DataType.BFLOAT16
|
|
@@ -167,6 +169,50 @@ class DataType(enum.IntEnum):
|
|
|
167
169
|
DataType.FLOAT8E5M2,
|
|
168
170
|
DataType.FLOAT8E5M2FNUZ,
|
|
169
171
|
DataType.FLOAT4E2M1,
|
|
172
|
+
DataType.FLOAT8E8M0,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
def is_integer(self) -> bool:
|
|
176
|
+
"""Returns True if the data type is an integer.
|
|
177
|
+
|
|
178
|
+
.. versionadded:: 0.1.4
|
|
179
|
+
"""
|
|
180
|
+
return self in {
|
|
181
|
+
DataType.UINT8,
|
|
182
|
+
DataType.INT8,
|
|
183
|
+
DataType.UINT16,
|
|
184
|
+
DataType.INT16,
|
|
185
|
+
DataType.INT32,
|
|
186
|
+
DataType.INT64,
|
|
187
|
+
DataType.UINT32,
|
|
188
|
+
DataType.UINT64,
|
|
189
|
+
DataType.UINT4,
|
|
190
|
+
DataType.INT4,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
def is_signed(self) -> bool:
|
|
194
|
+
"""Returns True if the data type is a signed type.
|
|
195
|
+
|
|
196
|
+
.. versionadded:: 0.1.4
|
|
197
|
+
"""
|
|
198
|
+
return self in {
|
|
199
|
+
DataType.FLOAT,
|
|
200
|
+
DataType.INT8,
|
|
201
|
+
DataType.INT16,
|
|
202
|
+
DataType.INT32,
|
|
203
|
+
DataType.INT64,
|
|
204
|
+
DataType.FLOAT16,
|
|
205
|
+
DataType.DOUBLE,
|
|
206
|
+
DataType.COMPLEX64,
|
|
207
|
+
DataType.COMPLEX128,
|
|
208
|
+
DataType.BFLOAT16,
|
|
209
|
+
DataType.FLOAT8E4M3FN,
|
|
210
|
+
DataType.FLOAT8E4M3FNUZ,
|
|
211
|
+
DataType.FLOAT8E5M2,
|
|
212
|
+
DataType.FLOAT8E5M2FNUZ,
|
|
213
|
+
DataType.INT4,
|
|
214
|
+
DataType.FLOAT4E2M1,
|
|
215
|
+
DataType.FLOAT8E8M0,
|
|
170
216
|
}
|
|
171
217
|
|
|
172
218
|
def __repr__(self) -> str:
|
|
@@ -199,6 +245,7 @@ _BITWIDTH_MAP = {
|
|
|
199
245
|
DataType.UINT4: 4,
|
|
200
246
|
DataType.INT4: 4,
|
|
201
247
|
DataType.FLOAT4E2M1: 4,
|
|
248
|
+
DataType.FLOAT8E8M0: 8,
|
|
202
249
|
}
|
|
203
250
|
|
|
204
251
|
|
|
@@ -224,6 +271,7 @@ _NP_TYPE_TO_DATA_TYPE = {
|
|
|
224
271
|
np.dtype(ml_dtypes.float8_e4m3fnuz): DataType.FLOAT8E4M3FNUZ,
|
|
225
272
|
np.dtype(ml_dtypes.float8_e5m2): DataType.FLOAT8E5M2,
|
|
226
273
|
np.dtype(ml_dtypes.float8_e5m2fnuz): DataType.FLOAT8E5M2FNUZ,
|
|
274
|
+
np.dtype(ml_dtypes.float8_e8m0fnu): DataType.FLOAT8E8M0,
|
|
227
275
|
np.dtype(ml_dtypes.int4): DataType.INT4,
|
|
228
276
|
np.dtype(ml_dtypes.uint4): DataType.UINT4,
|
|
229
277
|
}
|
|
@@ -248,6 +296,7 @@ _DATA_TYPE_TO_SHORT_NAME = {
|
|
|
248
296
|
DataType.FLOAT8E5M2: "f8e5m2",
|
|
249
297
|
DataType.FLOAT8E4M3FNUZ: "f8e4m3fnuz",
|
|
250
298
|
DataType.FLOAT8E5M2FNUZ: "f8e5m2fnuz",
|
|
299
|
+
DataType.FLOAT8E8M0: "f8e8m0",
|
|
251
300
|
DataType.FLOAT4E2M1: "f4e2m1",
|
|
252
301
|
DataType.COMPLEX64: "c64",
|
|
253
302
|
DataType.COMPLEX128: "c128",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (c) ONNX Project Contributors
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Numpy utilities for non-native type operation."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
from collections.abc import Sequence
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
if typing.TYPE_CHECKING:
|
|
13
|
+
import numpy.typing as npt
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def pack_4bitx2(array: np.ndarray) -> npt.NDArray[np.uint8]:
|
|
17
|
+
"""Convert a numpy array to flatten, packed int4/uint4. Elements must be in the correct range."""
|
|
18
|
+
# Create a 1D copy
|
|
19
|
+
array_flat = array.ravel().view(np.uint8).copy()
|
|
20
|
+
size = array.size
|
|
21
|
+
odd_sized = size % 2 == 1
|
|
22
|
+
if odd_sized:
|
|
23
|
+
array_flat.resize([size + 1], refcheck=False)
|
|
24
|
+
array_flat &= 0x0F
|
|
25
|
+
array_flat[1::2] <<= 4
|
|
26
|
+
return array_flat[0::2] | array_flat[1::2] # type: ignore[return-type]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def unpack_4bitx2(data: npt.NDArray[np.uint8], dims: Sequence[int]) -> npt.NDArray[np.uint8]:
|
|
30
|
+
"""Convert a packed uint4 array to unpacked uint4 array represented as uint8.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
data: A numpy array.
|
|
34
|
+
dims: The dimensions are used to reshape the unpacked buffer.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
A numpy array of int8/uint8 reshaped to dims.
|
|
38
|
+
"""
|
|
39
|
+
assert data.dtype == np.uint8, "Input data must be of type uint8"
|
|
40
|
+
result = np.empty([data.size * 2], dtype=data.dtype)
|
|
41
|
+
array_low = data & np.uint8(0x0F)
|
|
42
|
+
array_high = data & np.uint8(0xF0)
|
|
43
|
+
array_high >>= np.uint8(4)
|
|
44
|
+
result[0::2] = array_low
|
|
45
|
+
result[1::2] = array_high
|
|
46
|
+
if result.size == np.prod(dims) + 1:
|
|
47
|
+
# handle single-element padding due to odd number of elements
|
|
48
|
+
result = result[:-1]
|
|
49
|
+
result.resize(dims, refcheck=False)
|
|
50
|
+
return result
|
|
@@ -7,6 +7,7 @@ __all__ = [
|
|
|
7
7
|
"ClearMetadataAndDocStringPass",
|
|
8
8
|
"CommonSubexpressionEliminationPass",
|
|
9
9
|
"DeduplicateInitializersPass",
|
|
10
|
+
"IdentityEliminationPass",
|
|
10
11
|
"InlinePass",
|
|
11
12
|
"LiftConstantsToInitializersPass",
|
|
12
13
|
"LiftSubgraphInitializersToMainGraphPass",
|
|
@@ -30,6 +31,9 @@ from onnx_ir.passes.common.constant_manipulation import (
|
|
|
30
31
|
LiftSubgraphInitializersToMainGraphPass,
|
|
31
32
|
RemoveInitializersFromInputsPass,
|
|
32
33
|
)
|
|
34
|
+
from onnx_ir.passes.common.identity_elimination import (
|
|
35
|
+
IdentityEliminationPass,
|
|
36
|
+
)
|
|
33
37
|
from onnx_ir.passes.common.initializer_deduplication import (
|
|
34
38
|
DeduplicateInitializersPass,
|
|
35
39
|
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright (c) ONNX Project Contributors
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Identity elimination pass for removing redundant Identity nodes."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"IdentityEliminationPass",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
import onnx_ir as ir
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IdentityEliminationPass(ir.passes.InPlacePass):
|
|
19
|
+
"""Pass for eliminating redundant Identity nodes.
|
|
20
|
+
|
|
21
|
+
This pass removes Identity nodes according to the following rules:
|
|
22
|
+
1. For any node of the form `y = Identity(x)`, where `y` is not an output
|
|
23
|
+
of any graph, replace all uses of `y` with a use of `x`, and remove the node.
|
|
24
|
+
2. If `y` is an output of a graph, and `x` is not an input of any graph,
|
|
25
|
+
we can still do the elimination, but the value `x` should be renamed to be `y`.
|
|
26
|
+
3. If `y` is a graph-output and `x` is a graph-input, we cannot eliminate
|
|
27
|
+
the node. It should be retained.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def call(self, model: ir.Model) -> ir.passes.PassResult:
|
|
31
|
+
"""Main entry point for the identity elimination pass."""
|
|
32
|
+
modified = False
|
|
33
|
+
|
|
34
|
+
# Use RecursiveGraphIterator to process all nodes in the model graph and subgraphs
|
|
35
|
+
for node in ir.traversal.RecursiveGraphIterator(model.graph):
|
|
36
|
+
if self._try_eliminate_identity_node(node):
|
|
37
|
+
modified = True
|
|
38
|
+
|
|
39
|
+
# Process nodes in functions
|
|
40
|
+
for function in model.functions.values():
|
|
41
|
+
for node in ir.traversal.RecursiveGraphIterator(function):
|
|
42
|
+
if self._try_eliminate_identity_node(node):
|
|
43
|
+
modified = True
|
|
44
|
+
|
|
45
|
+
if modified:
|
|
46
|
+
logger.info("Identity elimination pass modified the model")
|
|
47
|
+
|
|
48
|
+
return ir.passes.PassResult(model, modified=modified)
|
|
49
|
+
|
|
50
|
+
def _try_eliminate_identity_node(self, node: ir.Node) -> bool:
|
|
51
|
+
"""Try to eliminate a single identity node. Returns True if modified."""
|
|
52
|
+
if node.op_type != "Identity" or node.domain != "":
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
if len(node.inputs) != 1 or len(node.outputs) != 1:
|
|
56
|
+
# Invalid Identity node, skip
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
input_value = node.inputs[0]
|
|
60
|
+
output_value = node.outputs[0]
|
|
61
|
+
|
|
62
|
+
if input_value is None:
|
|
63
|
+
# Cannot eliminate if input is None
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
# Get the graph that contains this node
|
|
67
|
+
graph_like = node.graph
|
|
68
|
+
assert graph_like is not None, "Node must be in a graph"
|
|
69
|
+
|
|
70
|
+
output_is_graph_output = output_value.is_graph_output()
|
|
71
|
+
input_is_graph_input = input_value.is_graph_input()
|
|
72
|
+
|
|
73
|
+
# Case 3: Both output is graph output and input is graph input - keep the node
|
|
74
|
+
if output_is_graph_output and input_is_graph_input:
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
# Case 1 & 2 (merged): Eliminate the identity node
|
|
78
|
+
# Replace all uses of output with input
|
|
79
|
+
ir.convenience.replace_all_uses_with(output_value, input_value)
|
|
80
|
+
|
|
81
|
+
# If output is a graph output, we need to rename input and update graph outputs
|
|
82
|
+
if output_is_graph_output:
|
|
83
|
+
# Store the original output name
|
|
84
|
+
original_output_name = output_value.name
|
|
85
|
+
|
|
86
|
+
# Update the input value to have the output's name
|
|
87
|
+
input_value.name = original_output_name
|
|
88
|
+
|
|
89
|
+
# Update graph outputs to point to the input value
|
|
90
|
+
for idx, graph_output in enumerate(graph_like.outputs):
|
|
91
|
+
if graph_output is output_value:
|
|
92
|
+
graph_like.outputs[idx] = input_value
|
|
93
|
+
|
|
94
|
+
# Remove the identity node
|
|
95
|
+
graph_like.remove(node, safe=True)
|
|
96
|
+
logger.debug("Eliminated identity node: %s", node)
|
|
97
|
+
return True
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -74,7 +74,6 @@ from onnx_ir import _convenience, _core, _enums, _protocols, _type_casting
|
|
|
74
74
|
|
|
75
75
|
if typing.TYPE_CHECKING:
|
|
76
76
|
import google.protobuf.internal.containers as proto_containers
|
|
77
|
-
import numpy.typing as npt
|
|
78
77
|
|
|
79
78
|
logger = logging.getLogger(__name__)
|
|
80
79
|
|
|
@@ -117,13 +116,6 @@ def _little_endian_dtype(dtype) -> np.dtype:
|
|
|
117
116
|
return np.dtype(dtype).newbyteorder("<")
|
|
118
117
|
|
|
119
118
|
|
|
120
|
-
def _unflatten_complex(
|
|
121
|
-
array: npt.NDArray[np.float32 | np.float64],
|
|
122
|
-
) -> npt.NDArray[np.complex64 | np.complex128]:
|
|
123
|
-
"""Convert the real representation of a complex dtype to the complex dtype."""
|
|
124
|
-
return array[::2] + 1j * array[1::2]
|
|
125
|
-
|
|
126
|
-
|
|
127
119
|
@typing.overload
|
|
128
120
|
def from_proto(proto: onnx.ModelProto) -> _core.Model: ... # type: ignore[overload-overlap]
|
|
129
121
|
@typing.overload
|
|
@@ -391,54 +383,89 @@ class TensorProtoTensor(_core.TensorBase): # pylint: disable=too-many-ancestors
|
|
|
391
383
|
"Cannot convert external tensor to numpy array. Use ir.ExternalTensor instead."
|
|
392
384
|
)
|
|
393
385
|
|
|
386
|
+
shape = self._proto.dims
|
|
387
|
+
|
|
394
388
|
if self._proto.HasField("raw_data"):
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
389
|
+
if dtype.bitwidth == 4:
|
|
390
|
+
return _type_casting.unpack_4bitx2(
|
|
391
|
+
np.frombuffer(self._proto.raw_data, dtype=np.uint8), shape
|
|
392
|
+
).view(dtype.numpy())
|
|
393
|
+
return np.frombuffer(
|
|
394
|
+
self._proto.raw_data, dtype=dtype.numpy().newbyteorder("<")
|
|
395
|
+
).reshape(shape)
|
|
396
|
+
if dtype == _enums.DataType.STRING:
|
|
397
|
+
return np.array(self._proto.string_data).reshape(shape)
|
|
398
|
+
if self._proto.int32_data:
|
|
399
|
+
assert dtype in {
|
|
400
|
+
_enums.DataType.BFLOAT16,
|
|
401
|
+
_enums.DataType.BOOL,
|
|
402
|
+
_enums.DataType.FLOAT16,
|
|
403
|
+
_enums.DataType.FLOAT4E2M1,
|
|
405
404
|
_enums.DataType.FLOAT8E4M3FN,
|
|
406
405
|
_enums.DataType.FLOAT8E4M3FNUZ,
|
|
407
406
|
_enums.DataType.FLOAT8E5M2,
|
|
408
407
|
_enums.DataType.FLOAT8E5M2FNUZ,
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
408
|
+
_enums.DataType.FLOAT8E8M0,
|
|
409
|
+
_enums.DataType.INT16,
|
|
410
|
+
_enums.DataType.INT32,
|
|
411
|
+
_enums.DataType.INT4,
|
|
412
|
+
_enums.DataType.INT8,
|
|
413
|
+
_enums.DataType.UINT16,
|
|
414
|
+
_enums.DataType.UINT4,
|
|
415
|
+
_enums.DataType.UINT8,
|
|
416
|
+
}, f"Unsupported dtype {dtype} for int32_data"
|
|
417
|
+
array = np.array(self._proto.int32_data, dtype=_little_endian_dtype(np.int32))
|
|
418
|
+
if dtype.bitwidth == 32:
|
|
419
|
+
return array.reshape(shape)
|
|
420
|
+
if dtype.bitwidth == 16:
|
|
421
|
+
# Reinterpret the int32 as float16 or bfloat16
|
|
422
|
+
return array.astype(np.uint16).view(dtype.numpy()).reshape(shape)
|
|
423
|
+
if dtype.bitwidth == 8:
|
|
424
|
+
return array.astype(np.uint8).view(dtype.numpy()).reshape(shape)
|
|
425
|
+
if dtype.bitwidth == 4:
|
|
426
|
+
return _type_casting.unpack_4bitx2(array.astype(np.uint8), shape).view(
|
|
427
|
+
dtype.numpy()
|
|
428
|
+
)
|
|
429
|
+
raise ValueError(
|
|
430
|
+
f"Unsupported dtype {dtype} for int32_data with bitwidth {dtype.bitwidth}"
|
|
431
|
+
)
|
|
432
|
+
if self._proto.int64_data:
|
|
433
|
+
assert dtype in {
|
|
434
|
+
_enums.DataType.INT64,
|
|
435
|
+
}, f"Unsupported dtype {dtype} for int64_data"
|
|
436
|
+
return np.array(
|
|
437
|
+
self._proto.int64_data, dtype=_little_endian_dtype(np.int64)
|
|
438
|
+
).reshape(shape)
|
|
439
|
+
if self._proto.uint64_data:
|
|
440
|
+
assert dtype in {
|
|
441
|
+
_enums.DataType.UINT64,
|
|
442
|
+
_enums.DataType.UINT32,
|
|
443
|
+
}, f"Unsupported dtype {dtype} for uint64_data"
|
|
414
444
|
array = np.array(self._proto.uint64_data, dtype=_little_endian_dtype(np.uint64))
|
|
415
|
-
|
|
445
|
+
if dtype == _enums.DataType.UINT32:
|
|
446
|
+
return array.astype(np.uint32).reshape(shape)
|
|
447
|
+
return array.reshape(shape)
|
|
448
|
+
if self._proto.float_data:
|
|
449
|
+
assert dtype in {
|
|
450
|
+
_enums.DataType.FLOAT,
|
|
451
|
+
_enums.DataType.COMPLEX64,
|
|
452
|
+
}, f"Unsupported dtype {dtype} for float_data"
|
|
416
453
|
array = np.array(self._proto.float_data, dtype=_little_endian_dtype(np.float32))
|
|
417
454
|
if dtype == _enums.DataType.COMPLEX64:
|
|
418
|
-
array
|
|
419
|
-
|
|
455
|
+
return array.view(np.complex64).reshape(shape)
|
|
456
|
+
return array.reshape(shape)
|
|
457
|
+
if self._proto.double_data:
|
|
458
|
+
assert dtype in {
|
|
459
|
+
_enums.DataType.DOUBLE,
|
|
460
|
+
_enums.DataType.COMPLEX128,
|
|
461
|
+
}, f"Unsupported dtype {dtype} for double_data"
|
|
420
462
|
array = np.array(self._proto.double_data, dtype=_little_endian_dtype(np.float64))
|
|
421
463
|
if dtype == _enums.DataType.COMPLEX128:
|
|
422
|
-
array
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return np.array([], dtype=dtype.numpy())
|
|
428
|
-
else:
|
|
429
|
-
# Otherwise we return a size 0 array with the correct shape
|
|
430
|
-
return np.zeros(self._proto.dims, dtype=dtype.numpy())
|
|
431
|
-
|
|
432
|
-
if dtype == _enums.DataType.INT4:
|
|
433
|
-
return _type_casting.unpack_int4(array.astype(np.uint8), self._proto.dims)
|
|
434
|
-
elif dtype == _enums.DataType.UINT4:
|
|
435
|
-
return _type_casting.unpack_uint4(array.astype(np.uint8), self._proto.dims)
|
|
436
|
-
elif dtype == _enums.DataType.FLOAT4E2M1:
|
|
437
|
-
return _type_casting.unpack_float4e2m1(array.astype(np.uint8), self._proto.dims)
|
|
438
|
-
else:
|
|
439
|
-
# Otherwise convert to the correct dtype and reshape
|
|
440
|
-
# Note we cannot use view() here because the storage dtype may not be the same size as the target
|
|
441
|
-
return array.astype(dtype.numpy()).reshape(self._proto.dims)
|
|
464
|
+
return array.view(np.complex128).reshape(shape)
|
|
465
|
+
return array.reshape(shape)
|
|
466
|
+
|
|
467
|
+
# Empty tensor. We return a size 0 array with the correct shape
|
|
468
|
+
return np.zeros(shape, dtype=dtype.numpy())
|
|
442
469
|
|
|
443
470
|
def tobytes(self) -> bytes:
|
|
444
471
|
"""Return the tensor as a byte string conformed to the ONNX specification, in little endian.
|
|
@@ -479,6 +506,7 @@ class TensorProtoTensor(_core.TensorBase): # pylint: disable=too-many-ancestors
|
|
|
479
506
|
_enums.DataType.FLOAT8E4M3FNUZ,
|
|
480
507
|
_enums.DataType.FLOAT8E5M2,
|
|
481
508
|
_enums.DataType.FLOAT8E5M2FNUZ,
|
|
509
|
+
_enums.DataType.FLOAT8E8M0,
|
|
482
510
|
_enums.DataType.INT4,
|
|
483
511
|
_enums.DataType.UINT4,
|
|
484
512
|
_enums.DataType.FLOAT4E2M1,
|
|
@@ -68,6 +68,7 @@ def from_torch_dtype(dtype: torch.dtype) -> ir.DataType:
|
|
|
68
68
|
torch.float8_e4m3fnuz: ir.DataType.FLOAT8E4M3FNUZ,
|
|
69
69
|
torch.float8_e5m2: ir.DataType.FLOAT8E5M2,
|
|
70
70
|
torch.float8_e5m2fnuz: ir.DataType.FLOAT8E5M2FNUZ,
|
|
71
|
+
torch.float8_e8m0fnu: ir.DataType.FLOAT8E8M0,
|
|
71
72
|
torch.int16: ir.DataType.INT16,
|
|
72
73
|
torch.int32: ir.DataType.INT32,
|
|
73
74
|
torch.int64: ir.DataType.INT64,
|
|
@@ -104,6 +105,7 @@ def to_torch_dtype(dtype: ir.DataType) -> torch.dtype:
|
|
|
104
105
|
ir.DataType.FLOAT8E4M3FNUZ: torch.float8_e4m3fnuz,
|
|
105
106
|
ir.DataType.FLOAT8E5M2: torch.float8_e5m2,
|
|
106
107
|
ir.DataType.FLOAT8E5M2FNUZ: torch.float8_e5m2fnuz,
|
|
108
|
+
ir.DataType.FLOAT8E8M0: torch.float8_e8m0fnu,
|
|
107
109
|
ir.DataType.INT16: torch.int16,
|
|
108
110
|
ir.DataType.INT32: torch.int32,
|
|
109
111
|
ir.DataType.INT64: torch.int64,
|
|
@@ -142,6 +144,7 @@ class TorchTensor(_core.Tensor):
|
|
|
142
144
|
ir.DataType.FLOAT8E4M3FNUZ,
|
|
143
145
|
ir.DataType.FLOAT8E5M2,
|
|
144
146
|
ir.DataType.FLOAT8E5M2FNUZ,
|
|
147
|
+
ir.DataType.FLOAT8E8M0,
|
|
145
148
|
}:
|
|
146
149
|
return self.raw.view(torch.uint8).numpy(force=True).view(self.dtype.numpy())
|
|
147
150
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onnx-ir
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Efficient in-memory representation for ONNX
|
|
5
5
|
Author-email: ONNX Contributors <onnx-technical-discuss@lists.lfaidata.foundation>
|
|
6
6
|
License: Apache License v2.0
|
|
@@ -30,6 +30,7 @@ Dynamic: license-file
|
|
|
30
30
|
[](https://github.com/astral-sh/ruff)
|
|
31
31
|
[](https://codecov.io/gh/onnx/ir-py)
|
|
32
32
|
[](https://deepwiki.com/onnx/ir-py)
|
|
33
|
+
[](https://pepy.tech/projects/onnx-ir)
|
|
33
34
|
|
|
34
35
|
An in-memory IR that supports the full ONNX spec, designed for graph construction, analysis and transformation.
|
|
35
36
|
|
|
@@ -19,6 +19,7 @@ src/onnx_ir/_type_casting.py
|
|
|
19
19
|
src/onnx_ir/_version_utils.py
|
|
20
20
|
src/onnx_ir/convenience.py
|
|
21
21
|
src/onnx_ir/external_data.py
|
|
22
|
+
src/onnx_ir/py.typed
|
|
22
23
|
src/onnx_ir/serde.py
|
|
23
24
|
src/onnx_ir/tape.py
|
|
24
25
|
src/onnx_ir/tensor_adapters.py
|
|
@@ -39,6 +40,7 @@ src/onnx_ir/passes/common/_c_api_utils.py
|
|
|
39
40
|
src/onnx_ir/passes/common/clear_metadata_and_docstring.py
|
|
40
41
|
src/onnx_ir/passes/common/common_subexpression_elimination.py
|
|
41
42
|
src/onnx_ir/passes/common/constant_manipulation.py
|
|
43
|
+
src/onnx_ir/passes/common/identity_elimination.py
|
|
42
44
|
src/onnx_ir/passes/common/initializer_deduplication.py
|
|
43
45
|
src/onnx_ir/passes/common/inliner.py
|
|
44
46
|
src/onnx_ir/passes/common/onnx_checker.py
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Copyright (c) ONNX Project Contributors
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
"""Numpy utilities for non-native type operation."""
|
|
4
|
-
# TODO(justinchuby): Upstream the logic to onnx
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
import typing
|
|
9
|
-
from collections.abc import Sequence
|
|
10
|
-
|
|
11
|
-
import ml_dtypes
|
|
12
|
-
import numpy as np
|
|
13
|
-
|
|
14
|
-
if typing.TYPE_CHECKING:
|
|
15
|
-
import numpy.typing as npt
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def pack_4bitx2(array: np.ndarray) -> npt.NDArray[np.uint8]:
|
|
19
|
-
"""Convert a numpy array to flatten, packed int4/uint4. Elements must be in the correct range."""
|
|
20
|
-
# Create a 1D copy
|
|
21
|
-
array_flat = array.ravel().view(np.uint8).copy()
|
|
22
|
-
size = array.size
|
|
23
|
-
odd_sized = size % 2 == 1
|
|
24
|
-
if odd_sized:
|
|
25
|
-
array_flat.resize([size + 1], refcheck=False)
|
|
26
|
-
array_flat &= 0x0F
|
|
27
|
-
array_flat[1::2] <<= 4
|
|
28
|
-
return array_flat[0::2] | array_flat[1::2] # type: ignore[return-type]
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _unpack_uint4_as_uint8(
|
|
32
|
-
data: npt.NDArray[np.uint8], dims: Sequence[int]
|
|
33
|
-
) -> npt.NDArray[np.uint8]:
|
|
34
|
-
"""Convert a packed uint4 array to unpacked uint4 array represented as uint8.
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
data: A numpy array.
|
|
38
|
-
dims: The dimensions are used to reshape the unpacked buffer.
|
|
39
|
-
|
|
40
|
-
Returns:
|
|
41
|
-
A numpy array of int8/uint8 reshaped to dims.
|
|
42
|
-
"""
|
|
43
|
-
assert data.dtype == np.uint8, "Input data must be of type uint8"
|
|
44
|
-
result = np.empty([data.size * 2], dtype=data.dtype)
|
|
45
|
-
array_low = data & np.uint8(0x0F)
|
|
46
|
-
array_high = data & np.uint8(0xF0)
|
|
47
|
-
array_high >>= np.uint8(4)
|
|
48
|
-
result[0::2] = array_low
|
|
49
|
-
result[1::2] = array_high
|
|
50
|
-
if result.size == np.prod(dims) + 1:
|
|
51
|
-
# handle single-element padding due to odd number of elements
|
|
52
|
-
result = result[:-1]
|
|
53
|
-
result.resize(dims, refcheck=False)
|
|
54
|
-
return result
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def unpack_uint4(
|
|
58
|
-
data: npt.NDArray[np.uint8], dims: Sequence[int]
|
|
59
|
-
) -> npt.NDArray[ml_dtypes.uint4]:
|
|
60
|
-
"""Convert a packed uint4 array to unpacked uint4 array represented as uint8.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
data: A numpy array.
|
|
64
|
-
dims: The dimensions are used to reshape the unpacked buffer.
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
A numpy array of int8/uint8 reshaped to dims.
|
|
68
|
-
"""
|
|
69
|
-
return _unpack_uint4_as_uint8(data, dims).view(ml_dtypes.uint4)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _extend_int4_sign_bits(x: npt.NDArray[np.uint8]) -> npt.NDArray[np.int8]:
|
|
73
|
-
"""Extend 4-bit signed integer to 8-bit signed integer."""
|
|
74
|
-
return np.where((x >> 3) == 0, x, x | 0xF0).astype(np.int8)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def unpack_int4(
|
|
78
|
-
data: npt.NDArray[np.uint8], dims: Sequence[int]
|
|
79
|
-
) -> npt.NDArray[ml_dtypes.int4]:
|
|
80
|
-
"""Convert a packed (signed) int4 array to unpacked int4 array represented as int8.
|
|
81
|
-
|
|
82
|
-
The sign bit is extended to the most significant bit of the int8.
|
|
83
|
-
|
|
84
|
-
Args:
|
|
85
|
-
data: A numpy array.
|
|
86
|
-
dims: The dimensions are used to reshape the unpacked buffer.
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
A numpy array of int8 reshaped to dims.
|
|
90
|
-
"""
|
|
91
|
-
unpacked = _unpack_uint4_as_uint8(data, dims)
|
|
92
|
-
return _extend_int4_sign_bits(unpacked).view(ml_dtypes.int4)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def unpack_float4e2m1(
|
|
96
|
-
data: npt.NDArray[np.uint8], dims: Sequence[int]
|
|
97
|
-
) -> npt.NDArray[ml_dtypes.float4_e2m1fn]:
|
|
98
|
-
"""Convert a packed float4e2m1 array to unpacked float4e2m1 array.
|
|
99
|
-
|
|
100
|
-
Args:
|
|
101
|
-
data: A numpy array.
|
|
102
|
-
dims: The dimensions are used to reshape the unpacked buffer.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
A numpy array of float32 reshaped to dims.
|
|
106
|
-
"""
|
|
107
|
-
return _unpack_uint4_as_uint8(data, dims).view(ml_dtypes.float4_e2m1fn)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{onnx_ir-0.1.3 → onnx_ir-0.1.5}/src/onnx_ir/passes/common/common_subexpression_elimination.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|