Skip to content

Streams

StreamStorage concatenates records into one logical stream. A read window can cross both document and shard boundaries. The storage format defines each element. Pass sequence_length to StatefulDataLoader.from_storage to choose how many elements each training sample contains.

The example below opens a StreamDataset reader to show those windows directly. That reader is part of the dataset API. A training loop does not construct it.

Tokens with a document ID and loss mask

This example stores three fixed-size fields per token. The repeated document ID preserves provenance after concatenation; the mask can select which tokens contribute to the training loss. All input arrays have the same length.

from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

from guideloom import StreamDataset, StreamNumpyFormat, StreamStorage


dtype = np.dtype([("tokens", "<i4"), ("document_ids", "<u4"), ("loss_mask", "u1")])
with TemporaryDirectory() as directory:
    storage = StreamStorage(Path(directory), StreamNumpyFormat(dtype))
    with storage.sync_writer() as writer:
        writer.append(
            0,
            {
                "tokens": np.array([10, 11, 12], dtype="<i4"),
                "document_ids": np.full(3, 7, dtype="<u4"),
                "loss_mask": np.array([0, 1, 1], dtype="u1"),
            },
        )
        writer.append(
            1,
            {
                "tokens": np.array([13, 14, 15, 16, 17], dtype="<i4"),
                "document_ids": np.full(5, 8, dtype="<u4"),
                "loss_mask": np.array([0, 1, 1, 1, 1], dtype="u1"),
            },
        )

    with StreamDataset(storage, sequence_length=4).sync_reader() as reader:
        assert len(reader) == 2
        sample = reader[0]
        assert sample["tokens"].tolist() == [10, 11, 12, 13]
        assert sample["document_ids"].tolist() == [7, 7, 7, 8]
        assert sample["loss_mask"].tolist() == [0, 1, 1, 0]

    # Change the window length without rewriting the files.
    with StreamDataset(storage, sequence_length=3).sync_reader() as reader:
        assert len(reader) == 2  # The final two tokens do not fill a sample.
        assert reader[1]["tokens"].tolist() == [13, 14, 15]

These are NumPy structured fields on disk. Small fixed-size annotations fit directly beside tokens; they do not need a separate metadata lookup. Document IDs must be globally unique if you use them alone for provenance. A custom format can also return the shard segments passed to unpack(stream, shard_lengths, shards).

The loader shuffles windows, preserving token order within each window. If you need to prevent cross-document windows, use documents or define a custom dataset view. For variable-length concept lists attached to token spans, use streams with metadata.

Custom stream format

Implement StreamStorageFormat when you need more control over packing or want a different decoded output shape. pack(data) returns a one-dimensional NumPy array with the declared stream_dtype. It may return a structured array directly, such as tokens with a repeated document ID field.

unpack(stream, shard_lengths, shards) returns the sample. The shard_lengths and shards arrays describe the consecutive shard segments making up the read. Windows can cross both document and shard boundaries. Use these segments when your output needs per-token shard IDs or other provenance.

Use explicit byte order and the same dtype when writing and reading. Preserve the encoding and decoding code with the dataset. See the format API reference for method signatures.