A model’s weights are tensors: the initializer list of its
graph holds one TensorProto for
each, and attributes such as a Constant node’s value hold more. Sparse
weights are SparseTensorProto messages. Both are defined in ONNX’s schema
onnx.proto (onnx 1.23, syntax = "proto2", package
onnx). This page lists every field of both. For the bytes of tags, varints
and lengths, see the Protocol Buffers
reference.
TensorProto
A tensor: its shape, its data type and its values, stored in
raw_data or in the typed field for its type. The table is in the order
of the schema, which is not the order of the numbers.
| Field | Name | Type | Wire type | Meaning |
|---|---|---|---|---|
| 1 | dims | repeated int64 | VARINT, one field per dimension | The size of each dimension, outermost first. None at all is a scalar, with one element. A dimension of 0 makes an empty tensor. |
| 2 | data_type | int32 | VARINT | The element type, a DataType. Every tensor must have one. |
| 3 | segment | Segment | LEN | For a large tensor stored in chunks: which elements this one holds. |
| 4 | float_data | repeated float, packed | LEN | Values of FLOAT tensors; COMPLEX64 as real, imaginary pairs. |
| 5 | int32_data | repeated int32, packed | LEN | Values of INT32, INT16, INT8, UINT16, UINT8, BOOL, FLOAT16, BFLOAT16, the float8, 4-bit, 2-bit and 6-bit types (see below). |
| 6 | string_data | repeated bytes | LEN, one field per string | Values of STRING tensors, each UTF-8, with no terminator and no byte-order mark. |
| 7 | int64_data | repeated int64, packed | LEN | Values of INT64 tensors. |
| 8 | name | string | LEN | The tensor’s name. An initialiser must have one: nodes use it as an input name. |
| 12 | doc_string | string | LEN | Documentation, Markdown allowed. |
| 9 | raw_data | bytes | LEN | The values as fixed-width little-endian bytes, row-major, used instead of the typed fields (see below). Not allowed for STRING. |
| 13 | external_data | repeated StringStringEntryProto | LEN, one field per entry | Where the values are when stored in another file: keys location (required), offset, length and checksum (SHA-1). See External data. |
| 14 | data_location | DataLocation | VARINT | DEFAULT (0): the values are in this message; EXTERNAL (1): in external_data. |
| 10 | double_data | repeated double, packed | LEN | Values of DOUBLE tensors; COMPLEX128 as pairs. |
| 11 | uint64_data | repeated uint64, packed | LEN | Values of UINT32 and UINT64 tensors. |
| 16 | metadata_props | repeated StringStringEntryProto | LEN, one field per entry | Named metadata, added in IR version 10. |
Field 15 is not used. Fields in proto2 are written even when they hold their default,
and dims is not marked packed, so ONNX’s writers give each dimension its
own field. A reader must also accept dims as one packed LEN field, and
the typed fields one value at a time; the explorer reads both forms.
Where the values are
Exactly one place holds the values: raw_data, the typed field for the
data type, or external data. A tensor with no elements has none.
| Data type | Typed field | Values in the typed field |
|---|---|---|
| FLOAT | float_data | one float per element |
| COMPLEX64 | float_data | two floats per element: real, imaginary |
| DOUBLE | double_data | one double per element |
| COMPLEX128 | double_data | two doubles per element |
| INT64 | int64_data | one per element |
| UINT32, UINT64 | uint64_data | one per element |
| INT32, INT16, INT8, UINT16, UINT8, BOOL | int32_data | one per element |
| FLOAT16, BFLOAT16, the float8 types, the 6-bit floats | int32_data | one per element: the bit pattern as an integer |
| INT4, UINT4, FLOAT4E2M1 | int32_data | one per two elements |
| INT2, UINT2 | int32_data | one per four elements |
| STRING | string_data | one string per element |
Small types in int32_data
FLOAT16, BFLOAT16 and the float8 types are stored as their bit patterns, so
FLOAT16 0.5 (0x3800) is the integer 14336. Two 4-bit values share one
int32, the first in the low four bits. Four 2-bit values share one int32, the first
in the lowest two bits. A 6-bit float takes one int32 of its own, in bits 0 to 5.
raw_data
The elements one after another in row-major order (the last dimension varies fastest), each little-endian and fixed-width. BOOL takes one byte per element. Smaller types are packed into bytes:
- 4-bit types: two to a byte, the first element in the low nibble;
- 2-bit types: four to a byte, as
x0 | x1<<2 | x2<<4 | x3<<6; - 6-bit floats: four in three bytes, as a stream of bits starting at the lowest bit, padded at the end; n elements take ⌈6 × n ÷ 8⌉ bytes.
So raw_data is always ⌈elements × bits ÷ 8⌉ bytes long. The explorer
checks this length, and turns the file down if it does not match.
Examples
An initialiser inside a model is written exactly like a tensor file of ONNX’s test data, nested in field 5 of the graph. These tensors are from the test data.
FLOAT in raw_data
08 03 08 04 08 05 10 01 42 01 78 4A F0 01 78 CC E1 3F …
x; raw_data of 240 bytes, the first float 1.764052FLOAT16 in raw_data
08 03 08 04 10 0A 42 06 6F 75 74 70 75 74 4A 18 64 38 …
output; raw_data of 24 bytesThe first value, 64 38, is 0x3864: sign 0, exponent 14,
mantissa 100, so (1 + 100 ÷ 1024) × 214 − 15 = 0.548828. The float the
test started from was 0.5488135.
STRING in string_data
08 02 10 08 32 03 61 62 63 32 03 64 65 66 42 01 78
abc and def; name xINT4 in int32_data
08 05 08 05 10 16 2A 11 88 01 A9 01 CB 01 …
25 elements need 13 int32 values. The first, 88 01, is 136
(0x88): the low nibble 8 and the high nibble 8, both −8 as signed
4-bit numbers. The input was −9, saturated to the smallest INT4.
TensorProto.Segment
The range of elements that one chunk of a large tensor holds, for tensors split
across several messages. It is the type of TensorProto’s field 3,
segment, and this section is where both the field and the message are
described.
| Field | Name | Type | Wire type | Meaning |
|---|---|---|---|---|
| 1 | begin | int64 | VARINT | The first element this chunk holds. |
| 2 | end | int64 | VARINT | The element after the last. |
The explorer does not check the size of a tensor that has a segment.
SparseTensorProto
A sparse tensor: only the values that are not zero, their positions, and the shape
of the whole tensor. A graph’s sparse_initializer list (IR 6) holds
weights in this form, and attributes of type SPARSE_TENSOR hold one.
| Field | Name | Type | Wire type | Meaning |
|---|---|---|---|---|
| 1 | values | TensorProto | LEN | The values that are not the default, as a 1-D tensor of NNZ elements. It must have a name when the sparse tensor is a model’s initialiser. |
| 2 | indices | TensorProto | LEN | Their positions: a tensor of shape [NNZ, rank], or linear indices of shape [NNZ], in ascending order. |
| 3 | dims | repeated int64 | VARINT, or one packed LEN | The shape of the dense tensor. |