TensorProto#

class onnx_light.onnx.TensorProto(*args, **kwargs)#

Defines a tensor and its content.

ByteSize(self) → int#

Returns the serialized size in bytes, following the protobuf API.

Clear(self) → None#

Clears the object.

ClearField(self, field_name: str) → None#

Clears the field field_name, following the protobuf API.

CopyFrom(self, arg: onnx_light.onnx_py._onnxpyprotoop.TensorProto, /) → None#

Copies one instance into this one.

class DataLocation(*values)#
class DataType(*values)#
HasField(self, field_name: str) → bool#

Checks if a field is set, following the protobuf HasField API.

ParseFromFile(self, name: str, options: object | None = None, external_data_file: str = '') → None#

Parses a binary file to fill this instance.

ParseFromString(self, data: bytes, options: object | None = None) → None#
ParseFromString(self, data: str, options: object | None = None) → None

Overloaded function.

  1. ParseFromString(self, data: bytes, options: object | None = None) -> None

Parses a sequence of bytes to fill this instance.

  1. ParseFromString(self, data: str, options: object | None = None) -> None

Parses a string to fill this instance.

SerializeSize(self, options: object | None = None) → onnx_light.onnx_py._onnxpyprotoop.SerializeSizeResult#

Returns the size once serialized without serializing.

SerializeToFile(self, name: str, options: object | None = None, external_data_file: str = '') → None#

Serializes this instance into a file. If external_data_size is not empty, big weights are stored in this (depending on options.raw_data_threshold). When writing to two files, temporary external-data metadata is cleared so the in-memory model stays unchanged.

SerializeToFileDescriptor(self, fd: int, options: object | None = None) → None#

Serializes this instance into an open file descriptor without closing it.

SerializeToOStream(self, output: object) → None#

Alias for SerializeToOstream (capital S) for protobuf API compatibility. Serializes this instance to a Python file-like object that has a write() method.

SerializeToOstream(self, output: object) → None#

Serializes this instance to a Python file-like object that has a write() method.

SerializeToString(self, options: object | None = None) → bytes#

Serializes this instance into a sequence of bytes.

property data_location#
  • DEFAULT - data stored inside the protobuf message. Data is stored in raw_data (if set) otherwise in type-specified field. - EXTERNAL - data stored in an external location as described by external_data field. If value not set, data is stored in raw_data (if set) otherwise in type-specified field.

Type:

Location of the data for this tensor. MUST be one of

property data_type#

The data type of the tensor. This field MUST have a valid TensorProto.DataType value

property dims#

The shape of the tensor.

property doc_string#

A human-readable documentation for this tensor. Markdown is allowed.

property double_data#

For double Complex128 tensors are encoded as a single array of doubles, with the real components appearing in odd numbered positions, and the corresponding imaginary component appearing in the subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] is encoded as [1.0, 2.0 ,3.0 ,4.0] When this field is present, the data_type field MUST be DOUBLE or COMPLEX128.

property external_data#
  • location (required) - POSIX filesystem path relative to the directory where the ONNX protobuf model was stored - offset (optional) - position of byte at which stored data begins. Integer stored as string. Offset values SHOULD be multiples 4096 (page size) to enable mmap support. - length (optional) - number of bytes containing data. Integer stored as string. - checksum (optional) - SHA1 digest of file specified in under ‘location’ key.

Type:

Data can be stored inside the protobuf file using type-specific fields or raw_data. Alternatively, raw bytes data can be stored in an external file, using the external_data field. external_data stores key-value pairs describing data location. Recognized keys are

property float_data#

Tensor content must be organized in row-major order. Depending on the data_type field, exactly one of the fields below with name ending in _data is used to store the elements of the tensor. For float and complex64 values Complex64 tensors are encoded as a single array of floats, with the real components appearing in odd numbered positions, and the corresponding imaginary component appearing in the subsequent even numbered position. (e.g., [1.0 + 2.0i, 3.0 + 4.0i] is encoded as [1.0, 2.0 ,3.0 ,4.0] When this field is present, the data_type field MUST be FLOAT or COMPLEX64.

from_dlpack = <nanobind.nb_func object>#
has_dims(self) → bool#
has_dims(self) → bool

Tells if ‘dims’ has a value.

has_doc_string(self) → bool#

Tells if ‘doc_string’ has a value

has_double_data(self) → bool#

Tells if ‘double_data’ has a value.

has_external_data(self) → bool#

Tells if ‘external_data’ has a value.

has_float_data(self) → bool#

Tells if ‘float_data’ has a value.

has_int32_data(self) → bool#

Tells if ‘int32_data’ has a value.

has_int64_data(self) → bool#

Tells if ‘int64_data’ has a value.

has_metadata_props(self) → bool#

Tells if ‘metadata_props’ has a value.

has_name(self) → bool#

Tells if ‘name’ has a value

has_string_data(self) → bool#

Tells if ‘string_data’ has a value.

has_uint64_data(self) → bool#

Tells if ‘uint64_data’ has a value.

property int32_data#
  • For data types with a bit-width of 8 or greater, each int32_data stores one element. - For 4-bit data types, each int32_data stores two elements. For FLOAT6E2M3 and FLOAT6E3M2, each int32_data stores one element’s unsigned 6-bit encoding in bits 0-5; bits 6-31 MUST be zero. Producers SHOULD use packed raw_data when compact serialization is desired. When this field is present, the data_type field MUST be INT32, INT16, INT8, INT4, UINT16, UINT8, UINT4, BOOL, FLOAT16, BFLOAT16, FLOAT8E4M3FN, FLOAT8E4M3FNUZ, FLOAT8E5M2, FLOAT8E5M2FNUZ, FLOAT8E8M0, FLOAT4E2M1, UINT2, INT2, FLOAT6E2M3, FLOAT6E3M2

Type:

For int32, uint8, int8, uint16, int16, uint4, int4, bool, (b)float16, float8, float6, and float4

Type:
  • (b)float16 and float8 values MUST be converted bit-wise into an unsigned integer representation before being written to the buffer. - Each pair of uint4, int4, and float4 values MUST be packed as two 4-bit elements into a single byte. The first element is stored in the 4 least significant bits (LSB), and the second element is stored in the 4 most significant bits (MSB). Consequently

property int64_data#

For int64. When this field is present, the data_type field MUST be INT64

load_external_data(self, base_dir: str = '') → None#

Loads the raw bytes of this tensor from the external file described by its external_data field into raw_data. The external_data and data_location fields are preserved.

property metadata_props#

Named metadata values; keys should be distinct.

property name#

Optionally, a name for the tensor.

property raw_data#

the advantage of specific field rather than the raw_data field is that in some cases (e.g. int data), protobuf does a better packing via variable length storage, and may lead to smaller binary footprint. When this field is present, the data_type field MUST NOT be STRING or UNDEFINED.

Type:

Serializations can either use one of the fields above, or use this raw bytes field. The only exception is the string case, where one is required to store the content in the repeated bytes string_data field. When this raw_data field is used to store tensor value, elements MUST be stored in as fixed-width, little-endian order. Floating-point data types MUST be stored in IEEE 754 format. Complex64 elements must be written as two consecutive FLOAT values, real component first. Complex128 elements must be written as two consecutive DOUBLE values, real component first. Boolean type MUST be written one byte per tensor element (00000001 for true, 00000000 for false). uint4 and int4 values must be packed to 4bitx2, the first element is stored in the 4 LSB and the second element is stored in the 4 MSB. uint2 and int2 values are packed four per byte from LSB to MSB. float6e2m3 and float6e3m2 values are packed four at a time into three bytes as a contiguous LSB-first bitstream. A partial final group is zero-padded and the byte length is ceil(6 * num_elements / 8). Note

release_dlpack(self) → object#

Transfers raw_data without copying to a single-consumption CPU DLPack capsule.

Warning

DESTRUCTIVE: unlike __dlpack__, this immediately removes the source payload. The tensor and any initializer/model containing it cannot use that payload until raw_data is reassigned. All other proto fields remain unchanged.

The descriptor snapshots shape/type and owns storage independently of the source, so it survives source destruction or reuse. Its deleter never accesses the source. User-supplied storage callbacks must likewise not reference a destroyed source. Borrowed data requires a lifetime owner. Validation/allocation failure leaves the source unchanged. The same dtype, shape, alignment and endian restrictions as __dlpack__ apply. Consumers must not write to the buffer. Owned storage with active __dlpack__ consumers cannot be transferred: release those consumers first. Borrowed exports retain their shared owner. The result is a legacy dltensor capsule, not an array.

property size#

Returns the number of elements in the tensor.

property string_data#

For strings. Each element of string_data is a UTF-8 encoded Unicode string. No trailing null, no leading BOM. The ‘string’ scalar type is not used to match ML community conventions. When this field is present, the data_type field MUST be STRING

property uint64_data#

For uint64 and uint32 values. When this field is present, the data_type field MUST be UINT32 or UINT64.

DLPack import#

TensorProto.from_dlpack(array, name="") constructs a tensor without allocating or copying its payload. array must implement both __dlpack__ and __dlpack_device__. For example:

import numpy
from onnx_light.onnx import TensorProto

array = numpy.arange(12, dtype=numpy.float32).reshape(3, 4)
tensor = TensorProto.from_dlpack(array, name="weights")
del array
serialized = tensor.SerializeToString()

The explicit import API does not change numpy_helper.from_array: that compatibility path still copies. Reading the Python tensor.raw_data property also returns a bytes copy; use numpy.from_dlpack(tensor) to inspect shared storage without copying.

Import accepts only CPU device (1, 0), compact row-major storage, and the whole-byte dtypes listed under export below. Dimensions and byte counts are validated, including overflow. Singleton strides are ignored, as are strides of empty tensors. Nonzero byte offsets are supported when element-aligned, with pointer overflow checks. The producer must supply a valid allocation covering the described storage; DLPack does not convey its allocation size.

DLPack describes native-endian storage. Producers must reject non-native-endian arrays (as NumPy does); multi-byte imports on big-endian hosts are rejected because ONNX requires little-endian bytes. Unsupported layouts, devices, dtypes, misalignment, copied versioned exports, and unknown flags fail rather than being converted. Read-only versioned exports are accepted.

The consumer requests stream=None, max_version=(1, 0), and copy=False. For legacy producers that reject negotiation keywords, it retries with only stream=None. It never retries a synchronization failure. CPU data must be ready for synchronous access when export returns: no accelerator streams, events, or asynchronous synchronization are supported.

Both legacy dltensor and versioned dltensor_versioned capsules are consumed exactly once. Metadata is copied, while raw_data borrows the allocation. The managed DLPack deleter runs under the Python GIL after the last shared owner is released, including on validation failure after capsule consumption. This also applies to zero-sized tensors with null data pointers. The original Python array may be deleted immediately; the producer’s managed tensor retains storage.

copy.copy(tensor), TensorProto.CopyFrom, repeated tensor insertion, and GraphBuilder’s make_initializer / make_initializer_move preserve the borrowed owner, as do the builder’s returned graph and model. CopyFrom and copy.copy still copy owned payloads and ownerless borrowed buffers. Serialization creates independent bytes; reparsing those bytes does not retain the DLPack owner. Treat shared storage as read-only while the tensor, builder, or model is in use, including through the original array.

DLPack export#

numpy.from_dlpack(tensor) creates a read-only, zero-copy CPU view of a TensorProto with dense, row-major raw_data. __dlpack_device__() returns (1, 0) (CPU). Export allocates only bookkeeping and shape metadata, never a payload buffer, and does not call numpy_helper.to_array.

Supported types are signed and unsigned 8/16/32/64-bit integers, BOOL, FLOAT16/FLOAT/DOUBLE, COMPLEX64/COMPLEX128, BFLOAT16, and all five ONNX FLOAT8 formats. Each uses its exact DLPack dtype, including format-specific FLOAT8 codes; consumers such as NumPy may not support every exported dtype. STRING, UNDEFINED, packed sub-byte types, segmented tensors, typed-field-only payloads, and external data not yet loaded into raw_data are rejected. Dimensions must be non-negative, the rank at most 128, and shape/byte counts must fit the platform’s size and signed 64-bit limits. The payload must match the shape exactly. Empty tensors require an explicitly present empty raw_data field.

ONNX raw bytes are little-endian. On big-endian hosts, multi-byte types raise BufferError instead of being byte-swapped. Nonempty buffers must be aligned to the element width (the component width for complex types); unaligned buffers raise BufferError instead of being copied.

Each export returns a fresh, single-consumption legacy dltensor capsule. stream must be None; dl_device must be None or (1, 0). copy=None and copy=False are accepted; copy=True or another device raises BufferError. max_version is accepted, but export still uses the legacy capsule ABI. Consumers must not write into exported storage, which may be backed by a read-only memory mapping.

The capsule retains the source Python proto and a separate reference to its raw-data owner token until the consumer releases the tensor (or an unused capsule is destroyed). Deleting the source variable is safe; copied borrowed protos share the original owner. Do not clear, resize, replace, or reparse owned source storage while a view exists, including through a containing model. Borrowed storage with no owner token remains the caller’s lifetime responsibility. Shape metadata is snapshotted at export.

Explicit destructive transfer#

tensor.release_dlpack() transfers the existing allocation or shared borrowed-storage owner to an independent, single-consumption legacy dltensor capsule. Unlike __dlpack__, it does not retain the source. The native equivalent is ReleaseDLPack(TensorProto&) in onnx_dlpack.h.

Warning

DESTRUCTIVE: release_dlpack() immediately removes the source raw_data: its pointer becomes null, size becomes zero, and HasField("raw_data") becomes false. The tensor and any initializer/model containing it cannot use that payload until it is reassigned. All other proto fields (including name, dimensions, dtype, and external metadata) remain unchanged.

The descriptor snapshots dimensions and dtype, and its storage survives source destruction or reuse. The deleter never accesses the source. User-provided storage callbacks must likewise be independent of the source. Owned and aligned-owned allocations transfer without copying; borrowed data requires a lifetime owner and shares exactly-once cleanup with other owners. Validation and allocation failures leave the source unchanged, including failure to create the Python capsule.

This method applies the same dtype, shape, endian, alignment, and explicit empty-payload restrictions as __dlpack__. Consumers must not write to the buffer. The return value is a capsule, not an array or protocol object; consumers accepting capsules directly can consume it once.

Warning

Transferring owned storage while earlier __dlpack__ views or capsules are still alive raises an exception without modifying the source. Release those consumers first. Borrowed storage with a shared lifetime owner can be transferred while views remain alive; each view retains that owner.

Binary-size measurement#

The following historical measurement covers the original non-destructive Python-only export, before native destructive transfer was added. The current implementation shares validation and dtype mapping through lib_onnx_proto and vendors the header-only DLPack C ABI; it adds no DLPack runtime library. These size deltas do not measure the native transfer API. A Linux x86-64 Release build with GCC 13.3.0, Python 3.13.15 and nanobind 3.1.0, using python setup.py build_ext --inplace --no-kernels, measured as follows (bytes, after strip --strip-unneeded; .text from size -A):

Artifact / section

Before

After

Delta

_onnxpyprotoop.abi3.so stripped file

2,404,304

2,412,528

+8,224 (+0.34%)

_onnxpyprotoop.abi3.so .text

1,517,797

1,523,861

+6,064 (+0.40%)

liblib_onnx_proto.so stripped file

1,371,656

1,371,656

0

liblib_onnx_proto.so .text

948,058

948,058

0

In that historical measurement the stripped proto library was byte-identical before and after, and the extension’s DT_NEEDED entries were unchanged.

Native transfer build budget#

With native transfer and the out-of-line export guard, the same Linux x86-64 GCC 13.3.0 Release build initially exceeded the CI .text limit. Compiling onnx_dlpack.cc for size and sharing validation-error construction reduces the footprint without changing validation conditions or exception types:

liblib_onnx_proto.so metric

Before size fix

After size fix

CI maximum

Stripped file bytes

1,383,976

1,379,880

1,390,552 (unchanged)

.text bytes

956,186

952,826

953,706 (unchanged)

Defined dynamic symbols

793

793

793 (previously 792)

The one-symbol allowance accounts for ByteSpan::acquire_export_guard() moving out of line. No public API is hidden to satisfy the count. The shared diagnostic helper keeps the [onnx-light] prefix and descriptive message, but omits the redundant stringified C++ condition.

Measurements use strip --strip-unneeded and .github/scripts/report_proto_binary_size.py on the shared proto library, configured with CMAKE_BUILD_TYPE=Release, ONNX_LIGHT_BUILD_PYTHON=ON and ONNX_LIGHT_BUILD_KERNELS=OFF. The baseline reproduces the failing full-build CI measurements exactly. The dependency allowlist is unchanged: libcrypto.so.3, libstdc++.so.6, libgcc_s.so.1, libc.so.6, and ld-linux-x86-64.so.2.