plitzer
A deterministic, resumable dataloader for ML training that reads Parquet directly from local disk or S3. The core is written in Rust and exposed to Python.
The order is a pure function of (seed, epoch) and the dataset. Documents are packed into fixed-length sequences by lanes, which depend on the batch size and never on the GPU count: every sequence is full, with no token dropped and no padding. Resuming mid-epoch is exact, and the sequences stay identical when the GPU count changes.
Status: alpha, 0.1.0. The API and the checkpoint format can still change between minor versions; a checkpoint from another version is refused with a clear error, never misread.
Install
pip install plitzer # wheels for Linux (x86_64, aarch64), macOS and Windows, CPython 3.11+
pip install "plitzer[torch]" # with the PyTorch IterableDataset
Quick start
The input is a Parquet dataset with a pre-tokenized list<int32> (or uint32) column.
import numpy as np
import plitzer
loader = plitzer.Loader(
"s3://bucket/fineweb-edu", # or a local folder
seed=0, lanes=512, window=64, # B lanes, W row groups per window
seq_len=2048, # every row is 2048 real tokens: none dropped, no padding
budget=8 << 30, # bytes of decoded row groups kept in memory
# (4 per token + 8 per document)
rank=0, world=8, # this GPU, of 8
)
while loader.epoch < 3: # also right after loader.resume(state)
for batch in loader: # the rest of this epoch; then epoch + 1
tokens = np.from_dlpack(batch.tokens) # or torch.from_dlpack, or pyarrow.array
...
state = loader.checkpoint() # this GPU's part; plitzer.merge(parts) joins all GPUs
With PyTorch (pip install plitzer[torch]), plitzer.torch.Dataset takes the same settings. It reads the rank and world from torch.distributed, and its state_dict() is one global checkpoint that resumes on any number of GPUs:
from torch.utils.data import DataLoader
import plitzer.torch
dataset = plitzer.torch.Dataset("s3://bucket/fineweb-edu", seed=0, lanes=512, window=64,
seq_len=2048, budget=8 << 30)
loader = DataLoader(dataset, batch_size=None, num_workers=0) # each item is one step
while dataset.epoch < 3: # also right after dataset.load_state_dict(state)
for batch in loader: # batch.tokens: (lanes per GPU, seq_len) int32
...
state = dataset.state_dict() # call it on every rank: it gathers all GPUs
# later, on any number of GPUs: dataset.load_state_dict(state)
The state is the position of the next batch the dataset gives, so a loop that prefetches batches before training them skips those on a resume (#22).
S3 credentials come from the usual AWS_* variables, or from storage_options={"endpoint": ..., "region": ...}.
The design, its rationale and the decision log are in docs/design.md.
Benchmarks
plitzer against MosaicML Streaming and Hugging Face datasets, all reading the same FineWeb-Edu-shaped Parquet files (512 row groups, 526 M tokens) through one harness, plitzer.bench.baseline, on 4 CPU cores with the files in the page cache (converted sizes in MiB, tokens lost on a resume at mid-epoch):
| loader | convert (s) | converted (MiB) | docs/s | Mtokens/s | cores | CPU ns/token | resume (s) | exact resume | tokens lost |
|---|---|---|---|---|---|---|---|---|---|
| plitzer | 0.0 | 0.0 | — | 298.5 | 3.95 | 13.2 | 0.34 | yes | 0 |
| mosaic | 27.5 | 1221.8 | 23,475 | 24.1 | 2.66 | 110.5 | 2.79 | yes | 0 |
| hf | 4.8 | 2008.7 | 82,952 | 85.2 | 0.99 | 11.6 | 0.16 | yes | 0 |
| hf-stream | 0.0 | 0.0 | 2,329 | 2.4 | 1.12 | 467.0 | 3.54 | no | 10,373,481 |
plitzer reads the Parquet as it is, with no conversion or copy, delivers 3.5× the tokens of hf and 12× those of Mosaic, packs every sequence full with no padding, and resumes exactly. hf still spends less CPU per token (11.6 vs 13.2 ns) and resumes faster (0.16 vs 0.34 s), from the Arrow copy it makes first; both are the next work on speed. --batch is in documents, and plitzer gets the same tokens in each batch (32 sequences of 2048). Method and caveats: design §5.14.
python -m plitzer.bench.baseline DATA --loaders plitzer,mosaic,hf,hf-stream --batch 64 --workers 4
TODO
- Benchmark baseline: measure MosaicML Streaming and HF
datasetson a FineWeb-Edu Parquet sample (conversion time, samples/s, CPU cores used, resume time) (plitzer.bench.baseline, design §5.14) - Ordering core: shuffle row groups per epoch, split each window into lane slices, and shuffle each slice (
rand_chacha). Property tests:- each epoch yields every sample exactly once
- each lane's slice is one contiguous stretch of storage
- a saved reference output matches on every OS
- Lanes: pack each lane's documents into fixed-length sequences, and checkpoint each lane's position. Property tests:
- resuming at step k matches the tail of an uninterrupted run
- global batches are identical across GPU counts
- Lossless packing: cut lane slices by tokens and fill each sequence to exactly L, with lanes running on across epochs, so no token is dropped or padded (was 19.3% lost on FineWeb-Edu lengths)
- Index: build a row-group index from Parquet footers, with caching
- I/O: async reads with
object_store(local disk and S3, tested against versitygw), plus a prefetch queue capped by bytes- read one row group's token column without its footer (local disk and S3)
- prefetch each GPU's row groups for a window, capped by bytes
- Python: PyO3 and maturin bindings, a PyTorch
IterableDatasetwithstate_dict(), and Arrow PyCapsule export- typed checkpoint bytes that merge across GPUs, and a per-GPU session that runs epochs and refuses a mismatched resume
- bindings: a
plitzerwheel exporting batches through DLPack and Arrow -
plitzer.torchIterableDatasetwithstate_dict()andload_state_dict()
- End-to-end test: kill training at a random step, resume on a different GPU count, and check the sample-stream hash matches
- Read amplification check: measure bytes read per GPU on real data. Lane slices simulate at 1.01–1.25×. Add a per-node cache only if it's needed. Measured on FineWeb-Edu lengths: at the bound 1 + (world − 1)/W (1.013× at W = 512 on 8 GPUs), so no cache (design §6)
- Benchmarks: publish a comparison table against Mosaic and HF (Benchmarks)
- Release: build wheels in CI and publish to PyPI
- wheels for Linux, macOS and Windows and an sdist, each tested on its own OS, published by a
v*tag (.github/workflows/release.yml) - publish 0.1.0 to PyPI
- wheels for Linux, macOS and Windows and an sdist, each tested on its own OS, published by a
- Stretch: in-loader tokenization
Known limits
- One
Loaderper GPU process, withnum_workers=0in PyTorch: the parallelism is in Rust, and forking a process with a running runtime is unsafe. - Read amplification is about 1 + (GPUs − 1)/W: set the window W to many times your GPU count (for example W = 512 costs 1.4 % on 8 GPUs).
- CPU per token and the time to the first batch after a resume are still behind Hugging Face
datasets' memory-mapped Arrow copy; both are the next work on speed. - Input is pre-tokenized text only; tokenization, images and dataset mixing are out of scope for 0.1.
Development
pip install maturin
maturin develop --release # build the extension into the active virtualenv
cargo test && python -m pytest plitzer-py/tests
CLAUDE.md lists every check that CI runs. A release is a v* tag: CI builds the wheels and the sdist, tests each wheel on its own OS, and publishes them to PyPI (CHANGELOG.md).
License
Licensed under either MIT or Apache-2.0, at your option.
Metadata
Release files for plitzer 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| plitzer-0.1.0.tar.gz | 181.6 kB | With provenance | Details for plitzer-0.1.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| plitzer-0.1.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details for plitzer-0.1.0-cp311-abi3-win_amd64.whl |
| plitzer-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ x86-64 | Details for plitzer-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl |
| plitzer-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64 | Details for plitzer-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl |
| plitzer-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64 | Details for plitzer-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl |
Total release size: 34.7 MB
Release files / plitzer-0.1.0.tar.gz
| Download URL | plitzer-0.1.0.tar.gz |
|---|---|
| Size | 181.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0bb535836704ffb98b475f28dc8e6a860f96c73d02d37b1c4f25d7585f0080b9
|
|
BLAKE2b-256 checksum How to use checksums |
f94bd4f65ed68ccb4a2e4fb17ce2cef48d84e116531755acab1bd9cf87cc78c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / plitzer-0.1.0-cp311-abi3-win_amd64.whl
| Download URL | plitzer-0.1.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 6.3 MB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
be75a489d04afe7b31add9ca3d4ddf89771f6bec163c05d8eb97540ba4d17a4d
|
|
BLAKE2b-256 checksum How to use checksums |
78e8907ad0afe6b3c8addb775bd1b63ce07123eaa9c4b29850d537f25bfbd98b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / plitzer-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl
| Download URL | plitzer-0.1.0-cp311-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 7.5 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
29dbedc5500e23a463967a4f7d596e0251864395fe02d96a4140eceeb13b9367
|
|
BLAKE2b-256 checksum How to use checksums |
77f03843efa4aa5d52a76176dc7b22cd2f69b7a359f77894904fadb4e054a6f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / plitzer-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl
| Download URL | plitzer-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 7.5 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
aa4007401baa0e6bc07e32adf98d2c08eb6735aa0c65cc396642cb686903f2db
|
|
BLAKE2b-256 checksum How to use checksums |
2933666d2a6de319aa1bcdc3b09d8c3ad047ee85cf8907e1c25abbf4aa2dc24c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / plitzer-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl
| Download URL | plitzer-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl |
|---|---|
| Size | 13.1 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c5dc494a851cdd4e73a1d46b212296c03fc8882ef2fde36b4ac1c177a11a7ba2
|
|
BLAKE2b-256 checksum How to use checksums |
8a99714614a6f74863156df1f09aae076181a61c845eea5ea6ce99101ab8b58a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logSecurity for plitzer 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 5 files in this release have been uploaded with provenance metadata.
Attestation for plitzer-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.