Skip to content

📦 WP-197 — perf(data): defer training HSV and quantization to CUDA

Engineering log · Phase 17 — R1 pose-objective parity

🔗 Depends on WP-196 · Needed by none

⬅️ WP-195 · Roadmap

WP-197 — the input workers sample colour and CUDA applies it in a batch

An isolated CPU profile attributed 5.476 of 12.668 seconds to the colour transform over 128 public COCO augmentation draws. That selects an enclosing input stage rather than a small helper.

device_hsv is opt-in for CUDA with float32 or mixed precision. Workers keep the existing HSV draw before the flip draw and carry the stated gains with the flipped image. A pointwise colour transform commutes with that pixel permutation. The consumer batches the existing RGB/HSV expressions with vmap, applies the same gains, then quantizes and restores the consumer dtype at the existing boundary. Float32 images cost four times the default uint8 image IPC and transfer bytes; the worker cap already budgets float32. Masks, validation and the default route keep their existing behavior. Precision plugins that cast floating inputs before the data hook retain worker-side HSV.

CUDA's host-scalar division lowered the hue divisor to a reciprocal multiply and changed 72 of 314,572,800 real augmentation pixel codes by one. R40 explains that boundary. A device-tensor six keeps the CPU division convention; the captured pixel is a regression test, and changing the divisor back to a host scalar makes it fail. No gain, recipe, target geometry or model arithmetic changes.

Five paired complete six-epoch detection-n fits on 256 public COCO images (640 px, batch 8, BF16, four workers, cached decoding) reduced the median from 102.053 s (99.831–103.663) to 79.468 s (78.859–81.501). The median paired reduction was 22.22%, range 18.72–22.79%, on an isolated four-vCPU NVIDIA L4 host, driver 580.178.04 and torch 2.9.1+cu129. Loss, model, optimizer, EMA, scheduler and metric byte hashes matched in each pair and across repeated baselines. Peak allocated CUDA memory was 1,595,021,312 versus 1,596,232,192 bytes.

With the batched MuSGD change, merged as 01b4d4c, applied to both arms (the measured row ran on that change's pre-merge revision, not on the squashed commit), five batch-4 fits (384 updates each) reduced the median from 115.651 s (115.136–116.204) to 95.898 s (95.501–96.696). The additional median paired reduction was 16.93%, range 16.38–17.82%, with the same six state/loss hashes equal. This is a separate workload row, not a percentage to add to the batch-8 result.

The final real-input replay compared 1,258,291,200 consumer image bytes over all 256 COCO images: zero differences, with equal packed geometry and a stable repeated baseline. The L4 passed 172 focused regressions, 28 changed-code doctests and one targeted augmentation-producer doctest; ten pre-existing doctest examples were explicitly skipped. A scalar-divisor mutation fails the captured CUDA pixel and the CPU-only divisor contract; restored code passes. Float32 and FP16 mixed precision each completed a finite one-batch real-data compatibility smoke with deferred mode active. Full pre-commit passed on CPU torch 2.14 with 149 focused tests and three CUDA skips.

Focused tests cover RNG order, ordinary and deferred transport, masks, consumer precision, the CPU fallback, validation and CUDA rounding. _host_sample lets the grid and golden helpers accept a deferred sample without quantizing it (unit-tested); both scripts build the default pipeline, so their outputs are unchanged. The complete-fit evidence uses public COCO, includes loading, augmentation, forward/backward, optimization, EMA, validation and checkpoints, and compares loss and final-state bytes. Full make gate was not run; this work package remains open.