chunking
Utilities for sequential chunked forward passes of causal noise layers.
A chunked forward pass transforms a sequence one fixed-size chunk at a time, so that a seeded noise layer can be prefix-invariant: Appending tokens never changes the transformed outputs of the tokens already there. This module holds the prefix-stable noise sampling such a pass relies on, whose values at each position depend only on the seed and the position's chunk, and the splitting of a sequence into padded chunks.
Classes:
| Name | Description |
|---|---|
PaddedChunk |
One chunk of a sequence, padded at the end to the chunk size. |
Functions:
| Name | Description |
|---|---|
derive_chunk_seed |
Derive the seed of the generator that samples the noise of one chunk of a chunked forward pass. |
padded_chunks |
Split tensors along their sequence dimension into consecutive chunks, each padded at the end to |
sample_chunked_noise |
Sample standard normal noise whose values at each position depend only on |
PaddedChunk
dataclass
¶
One chunk of a sequence, padded at the end to the chunk size.
Added in version v4.3.0.
Methods:
| Name | Description |
|---|---|
unpad |
Drop the padded positions from a tensor computed for this chunk. |
Attributes:
| Name | Type | Description |
|---|---|---|
index |
tuple[slice, ...]
|
The index of the chunk's real positions in a tensor of the whole sequence, e.g. |
positions |
slice
|
The slice of the sequence's real positions that the chunk covers. It is shorter than the chunk size only for a padded last chunk. |
tensors |
tuple[Tensor, ...]
|
The padded chunk of each tensor that was split, in the order they were given. |
index
property
¶
The index of the chunk's real positions in a tensor of the whole sequence, e.g. output[chunk.index] = ....
positions
instance-attribute
¶
positions: slice
The slice of the sequence's real positions that the chunk covers. It is shorter than the chunk size only for a padded last chunk.
tensors
instance-attribute
¶
The padded chunk of each tensor that was split, in the order they were given.
unpad
¶
Drop the padded positions from a tensor computed for this chunk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
Tensor
|
A tensor of shape |
required |
Returns:
| Type | Description |
|---|---|
torch.Tensor
|
A view of |
derive_chunk_seed
¶
derive_chunk_seed(seed: int, chunk_index: int) -> int
Derive the seed of the generator that samples the noise of one chunk of a chunked forward pass.
The derived seed depends on chunk_index as well as seed. Seeding every chunk with seed alone would draw the same values for
every chunk, making the noise periodic with period chunk_size: anyone who learned the noise of one chunk would know it for all of
them.
The derived seed is a hash of seed and chunk_index, so each chunk of each seed gets an unrelated generator. Combining them
arithmetically instead, e.g. seed + chunk_index, would give different seeds overlapping chunks, such as chunk 1 of seed 0 and chunk
0 of seed 1, so consecutive per-request seeds would share noise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
int
|
The noise layer's seed. Values outside the range of a |
required |
|
int
|
The index of the chunk along the sequence dimension, in |
required |
Returns:
| Type | Description |
|---|---|
int
|
A seed in |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Added in version v4.1.0.
padded_chunks
¶
padded_chunks(
chunk_size: int, *tensors: Tensor
) -> Iterator[PaddedChunk]
Split tensors along their sequence dimension into consecutive chunks, each padded at the end to chunk_size positions.
Every chunk has the same shape, so a computation run chunk by chunk sees the same shapes whatever the sequence length. Only the last
chunk can be padded, with zeros, or False for boolean tensors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
int
|
The number of positions per chunk. |
required |
|
Tensor
|
The tensors to split, each of shape |
required |
Yields:
| Type | Description |
|---|---|
Iterator[PaddedChunk]
|
Each chunk, with the slice of the sequence's real positions it covers and the padded chunk of each tensor, in order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
ValueError
|
If the tensors do not all have the same sequence length. |
Added in version v4.3.0.
sample_chunked_noise
¶
sample_chunked_noise(
shape: Sequence[int],
*,
seed: int,
chunk_size: int,
device: device,
dtype: dtype
) -> torch.Tensor
Sample standard normal noise whose values at each position depend only on seed and the position's chunk.
The sequence dimension is split into chunks of chunk_size positions. Each chunk is drawn in full, with shape (1, chunk_size, ...),
from a generator freshly seeded by derive_chunk_seed(seed, chunk_index), broadcast to every batch row, and the last chunk is
trimmed to the sequence length. Every draw therefore has the same shape regardless of the sequence length and the batch size, so the
noise of the first n positions is identical whether n or more positions are sampled, and whichever row a sequence is in. Drawing a
chunk for the whole batch at once would instead give each row a different slice of the draw, so a sequence's noise would change with
its row.
Neither the global random number generator nor any persisted generator is advanced, so the noise is also identical across calls.
The noise is drawn per chunk rather than per position because only fixed-shape draws are reproducible, and each draw has a fixed cost. A single draw over the whole sequence is not prefix-stable: which random values land at a position depends on the total shape. A draw per position would be, but each draw costs a generator re-seed and a kernel launch, which made one draw per position about 60 times slower than a single draw for an 8192-token sequence.
Note
With a fixed seed, the noise does not depend on the input: every input sampled with the same seed, chunk_size, feature
shape, device type, and dtype receives the same noise at each position, across the whole sequence. That includes every row of a
batch, so sequences batched together share their noise, exactly as if each were sampled alone with that seed. The generators are
per device type, so the same seed yields different noise on different device types.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
|
Sequence[int]
|
The shape of the noise, |
required |
|
int
|
The seed to derive the per-chunk generator seeds from. |
required |
|
int
|
The number of positions per chunk. |
required |
|
device
|
The device to sample the noise on. |
required |
|
dtype
|
The dtype of the noise. |
required |
Returns:
| Type | Description |
|---|---|
torch.Tensor
|
Standard normal noise of the given |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Added in version v4.1.0.