Unpack¶
Unpack - 29¶
Version¶
name: Unpack (GitHub)
domain:
mainsince_version:
29function:
Truesupport_level:
SupportType.COMMONshape inference:
True
This version of the operator has been available since version 29.
Summary¶
Unpacks UINT8 or UINT32 storage words into UINT8 unsigned integer codes
independently along axis (default -1). Input and output have the same
rank, at least 1. Negative axes are supported; axis must be in [-rank, rank-1].
The input type determines word_bits: 8 for UINT8, 32 for UINT32.
Specify either bits in [1, 8], or both radix and group_size;
the two spellings are mutually exclusive.
The input count must be a nonnegative scalar INT64 tensor specifying the
number of output codes along axis, excluding padding. With bits, each
element of Y is in [0, 2^bits - 1].
When using bits, the input axis dimension B must equal ceil(count * bits / word_bits).
The output axis dimension is count; all other dimensions are preserved.
Each fixed combination of indices in the other dimensions defines an
independent sequence, called a row below; a rank-1 tensor has one row.
Within each row, input words are read in increasing axis index order,
starting with the least significant bit of each word. Consecutive groups of
bits bits form output codes in order, with the first bit of each group as
the code’s least significant bit. Number the bits of each word and code
starting at 0 for the least significant bit. For code index
0 <= i < count and bit index 0 <= k < bits, bit k of output code i is
read from bit (i * bits + k) % word_bits of input word floor((i * bits + k) / word_bits).
When a code spans a word boundary, its higher-order bits are read from
the low bits of the next word. Each row begins at bit 0 of a new word.
Unused high bits in the final input word of each row are padding and are ignored.
Bit positions are defined numerically, independently of host endianness;
tensor raw data uses ONNX’s little-endian serialization.
All non-axis dimensions are preserved, including zero dimensions, and the
same shape requirements apply when any non-axis dimension is zero.
With count = 0, both input and output must have an empty selected axis.
With UINT8 storage, bits = 3 and count = 8 unpack [136, 198, 250] into
[0, 1, 2, 3, 4, 5, 6, 7]. With bits = 3 and count = 2, [255]
is unpacked into [7, 7].
Grouped unpacking uses radix R in [2, 256] and positive group size G, with R^G <= 2^63 - 1. Read consecutive W = ceil(log2(R^G)) bit group indices, least-significant bit first, without word alignment between groups. R^G determines the precision of the integer arithmetic required for both packing and unpacking: valid group indices require W value bits, and any explicitly computed R^G or other intermediate must also fit. Prefer (R, G) pairs supported by standard 32-bit or 64-bit integer arithmetic. The R^G bound above permits exact signed 64-bit base-radix calculations. A commonly used choice is (R, G) = (3, 5): five ternary codes per byte. Every group index must be less than R^G; encodings outside this range are invalid. Expand each index into G base-R digits, least significant digit first, then trim to count values per row. The input axis dimension must equal ceil(ceil(count/G) * W / word_bits). Unused digits of the last group and unused high bits of the last word are ignored. Each output code is in [0, R - 1]. The original bits spelling is (R, G) = (2^bits, 1). With UINT8 storage and R=3, G=5, [102] with count=5 becomes [0, 1, 2, 0, 1]; [7] with count=2 becomes [1, 2]. Results for invalid inputs are unspecified; function decompositions need not diagnose invalid indices or incorrect input sizes.
Attributes¶
axis - INT (default is
-1):Axis along which independent sequences are unpacked. Negative axes are supported.
bits - INT :
Number of bits per unsigned code. Mutually exclusive with radix/group_size.
group_size - INT :
Codes per group. Positive; radix^group_size must fit in positive INT64.
radix - INT :
Base of grouped codes, in [2, 256]. Requires group_size; excludes bits.
Inputs¶
X (heterogeneous) - TStorage:
UINT8 or UINT32 tensor of rank at least 1, with the exact packed word count along axis.
count (heterogeneous) - tensor(int64):
Scalar INT64 tensor giving the logical output length along axis. Must be nonnegative.
Outputs¶
Y (heterogeneous) - T:
UINT8 tensor preserving every dimension except axis, which becomes count. Each element is below the selected radix.
Type Constraints¶
T in (
tensor(uint8)):Unsigned byte tensors.
TStorage in (
tensor(uint32),tensor(uint8)):Unsigned storage word tensors.
Examples¶
_unpack_uint32_axis¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], bits=5, axis=0)
x = np.full((2, 2), 0xFFFFFFFF, dtype=np.uint32)
count = np.array(7, dtype=np.int64)
y = np.full((7, 2), 31, dtype=np.uint8)
expect(node, inputs=[x, count], outputs=[y], name="test_unpack_uint32_axis")
_unpack_ternary¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], radix=3, group_size=5)
x = np.array([[102], [242]], dtype=np.uint8)
count = np.array(5, dtype=np.int64)
y = np.array([[0, 1, 2, 0, 1], [2, 2, 2, 2, 2]], dtype=np.uint8)
expect(node, inputs=[x, count], outputs=[y], name="test_unpack_ternary")
_unpack_3bit¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], bits=3)
x = np.array([0x88, 0xC6, 0xFA], dtype=np.uint8)
count = np.array(8, dtype=np.int64)
y = np.arange(8, dtype=np.uint8)
expect(node, inputs=[x, count], outputs=[y], name="test_unpack_3bit")
_unpack_rows_5bit¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], bits=5)
x = np.array([[0x41, 0x0C], [0x1F, 0x40]], dtype=np.uint8)
count = np.array(3, dtype=np.int64)
y = np.array([[1, 2, 3], [31, 0, 16]], dtype=np.uint8)
expect(node, inputs=[x, count], outputs=[y], name="test_unpack_rows_5bit")
_unpack_empty¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], bits=3)
x = np.empty((2, 0), dtype=np.uint8)
count = np.array(0, dtype=np.int64)
expect(node, inputs=[x, count], outputs=[x], name="test_unpack_empty")
_unpack_empty_rows¶
import numpy as np
import onnx
node = helper.make_node("Unpack", ["X", "count"], ["Y"], bits=5)
x = np.empty((2, 0, 6), dtype=np.uint8)
count = np.array(9, dtype=np.int64)
y = np.empty((2, 0, 9), dtype=np.uint8)
expect(node, inputs=[x, count], outputs=[y], name="test_unpack_empty_rows")