Skip to content

TBL-RAW pre-processed pipeline: decode once, mmap-serve every epoch — new efficiency frontier - #18

Merged
ALJainProjects merged 4 commits into
mainfrom
perf/tbl-raw
Aug 4, 2026
Merged

TBL-RAW pre-processed pipeline: decode once, mmap-serve every epoch — new efficiency frontier#18
ALJainProjects merged 4 commits into
mainfrom
perf/tbl-raw

Conversation

@ALJainProjects

Copy link
Copy Markdown
Owner

What

The efficiency-frontier sprint: memory, compression, and a real use for the TBL v2 format, which was previously disconnected from the training path entirely.

The pipeline

  • SampleFormat.RAW_U8 + preprocess_to_tbl(tar, tbl, image_size=N) — one-time parallel decode+resize (9,469 images in 6s on M4), exact uint8 recovery.
  • TblRawImageLoader / DataLoader('data.tbl') — batches served from a zero-copy mmap view through ONE fused parallel SIMD pass (normalize_u8_gather), bit-identical to the TAR pipeline (tested array_equal). Full contract: (seed, epoch) determinism, resume, drop_last, pinned ring, serve-time hflip, background prefetch.
  • MetalResidentLoader('data.tbl') and CudaResidentLoader.from_tbl(...) ingest the same file — their decode-all pass disappears.

Measured (per-stage subprocesses, dual consumption levels)

  • M4 Max: raw serve 531k img/s / 89k np.sum-consumed; prefetch mode 98.6k consumed; vs on-the-fly 32k and float32 cache 62k at 8.8 GB peak RSS vs ~1 GB of evictable file pages.
  • 3090 e2e ResNet-18: TBL-RAW 3.64s epochs — the fastest input pipeline this benchmark has measured (TAR 3.76, PyTorch 3.92, floor 3.39; hflip-only recipe caveat documented).
  • Honest results published alongside: first e2e run was SLOWER (4.51s) until background prefetch moved serving off the training thread; LZ4 on decoded photos = 1.06x (RAW defaults compression=False); on the bandwidth-poor WSL2 box a GIL-holding np.sum consumer favors the RAM cache while real training favors TBL-RAW.

Tests

26 new tests (bit-parity, prefetch==sync equivalence incl. hflip, ring lifetime, resume, early-exit wind-down, format/compression/dims rejection, resident ingestion) — 25 pass on M4, 21 pass on the 3090 incl. the CUDA resident test.

Arnav Jain added 4 commits August 3, 2026 22:52
…epoch

New efficiency frontier for many-epoch training, portably (FFCV's idea
without the .beton lock-in): preprocess_to_tbl runs the C++ fast path over a
TAR and stores RGB uint8 samples (SampleFormat.RAW_U8) in TBL v2;
TblRawImageLoader (and DataLoader('.tbl')) then serves batches from a
zero-copy mmap view through ONE fused parallel SIMD pass
(normalize_u8_gather: index gather + u8 HWC -> normalized f32 CHW, GIL
released) — bit-identical output to the TAR pipeline (tested array_equal).

M4 Max, Imagenette 160px: 525k img/s produce / 88k np.sum-consumed vs
on-the-fly 33k/31k and float32 cache_decoded 65k/59k — faster than the RAM
cache at BOTH consumption levels while owning file-backed pages instead of
its ~2.9 GB anonymous RAM (peak-RSS growth +448 MB vs +7.8 GB). LZ4 on
decoded photos measured 1.06x -> RAW defaults compression=False (documented).

MetalResidentLoader ingests .tbl directly (upload = one memcpy) and
CudaResidentLoader.from_tbl uploads through the mmap in chunks — the
decode-all pass disappears. Serve-time hflip_prob is the one aug this path
supports (crop/color must be baked; TAR pipeline keeps train_aug). e2e
benchmark gains --tbl; new benchmark_tbl_raw.py reports both consumption
levels + RSS + honest LZ4 ratio.
First 3090 e2e run exposed the design gap honestly: synchronous serve put
~10ms/step of gather+flip+normalize ON the training thread, making TBL-RAW
SLOWER e2e (4.51s) than the TAR pipeline's threaded prefetch (3.73s) despite
being 2x faster loader-only. A stop-aware producer thread now builds batches
ahead (the SIMD ops release the GIL, so production overlaps the training
step); pinned-ring depth is clamped to ring-2 so no buffer is overwritten
while held. Prefetch output is asserted identical to sync (incl. hflip path),
early-exit winds the thread down, resume works through the queue. Docs +
CHANGELOG carry the full honest numbers.
…docs numbers

In-process stage order contaminated the sync serve path by up to 6x (thread
pool/allocator state) — every configuration now runs in its own subprocess,
which also makes per-stage peak RSS exact. Docs carry the isolated numbers:
M4 raw serve 531k produce / 89k sum, prefetch 98.6k sum, cache 62k at 8.8 GB
RSS; 3090 e2e TBL-RAW 3.64s vs TAR 3.76 / PT 3.92 / floor 3.39 — fastest
input pipeline measured on this benchmark, incl. the honest 4.51s-before-
prefetch story.
@ALJainProjects
ALJainProjects merged commit c88660a into main Aug 4, 2026
8 checks passed
@ALJainProjects
ALJainProjects deleted the perf/tbl-raw branch August 4, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant