Skip to main content

Parity Augmentation — bit-exact CPU/GPU parity for image augmentation

Project description

paraug

paraug banner — CPU and GPU augmentation pipelines converging to a single bit-exact output

Bit-exact CPU/GPU parity for image augmentation.

License: Apache 2.0 Python 3.9-3.12

Languages: English | 繁體中文

paraug is a PyTorch-native augmentation library that guarantees the same seed produces the same output on CPU and CUDA. Per-primitive RNG is sampled on CPU regardless of tensor device, so a training run that randomly switches between CPU and GPU stages — or a unit test that swaps backends — stays deterministic.

Why parity matters

Most augmentation libraries (albumentations, kornia, torchvision) use device- local RNG. Same seed, different output across CPU/CUDA. This bites in three places:

  1. Reproducibility: paper-to-code lineage breaks when a reviewer can't match published numbers.
  2. Debugging: CPU-side unit tests don't catch GPU-only bugs and vice versa.
  3. Distributed training: workers on heterogeneous hardware drift apart.

paraug fixes this by isolating RNG to CPU (torch.Generator(device="cpu")) and routing only the deterministic torch ops through device. Tolerance:

  • Elementwise ops (gamma, noise, color jitter, …): atol 1e-6
  • grid_sample-class ops (affine, perspective, tps, …): atol 2e-4 (bilinear ulp drift across ATen vs cuDNN)

Installation

pip install git+https://github.com/alieuidsh/paraug.git

PyPI release (pip install paraug) coming once the v0.1.x publish workflow is wired up — see issue tracker for status.

Quickstart

import torch
from paraug import AugPipeline

aug = AugPipeline({
    "geometric": {
        "affine": {"p": 1.0, "rot_deg": 15.0, "scale_range": (0.9, 1.1)},
        "tps":    {"p": 0.5, "max_disp": 12.0, "n_ctrl": 5},
    },
    "photometric": {
        "gamma":         {"p": 0.5},
        "color_jitter":  {"p": 0.5},
        "gaussian_blur": {"p": 0.3},
    },
})

img  = torch.rand(2, 3, 256, 256)         # (B, C, H, W)
mask = torch.ones(2, 1, 256, 256)         # optional

img_out, mask_out = aug(img, mask=mask, seed_base=42, epoch=0, step=0)

The same call on GPU is bit-exact within tolerance:

img_gpu  = img.cuda()
mask_gpu = mask.cuda()
img_cuda, mask_cuda = aug(img_gpu, mask=mask_gpu, seed_base=42, epoch=0, step=0)
assert (img_out - img_cuda.cpu()).abs().max() < 2e-4

Primitives

Geometric (7)

Name Description
affine Rotation + scale + translation via F.affine_grid
perspective 4-point homography from corner jitter
random_crop_pad Scale-then-pad crop, area-preserving
elastic_transform Bilinear-upsampled random displacement field
optical_distortion Radial barrel / pincushion (k·r²)
random_shadow Soft-blurred triangle multiplicative shadow
tps Thin-plate-spline-like warp from low-res control grid

Photometric (24)

Intensity / color: gamma, color_jitter, hue_shift, random_grayscale, lighting, clahe, local_contrast, sharpness.

Noise: gaussian_noise, salt_pepper_noise, salt_patches.

Blur / artifacts: gaussian_blur, motion_blur, jpeg_approx.

Lighting: vignette, specular_highlight, specular_streaks.

Content overlays: cutout, paper_texture_overlay, watermark, random_text_overlay, background_compose, stains, creases.

Parity comparison

Library Bit-exact CPU↔GPU Per-item RNG GPU native Mask-aware Batch-native # Geometric¹ # Photometric¹ License
paraug (1e-6 / 2e-4)² ✓ (torch) 7 24 Apache 2.0
albumentations ✗ (numpy-only) partial ~20 ~50+ MIT
kornia ✗ (device-local RNG) ✓ (torch) ~10 ~45 Apache 2.0
torchvision.v2 ✗ (device-local RNG) ✓ (torch) partial ~18 ~12 BSD-3
imgaug ✗ (numpy-only) partial ~20 ~40 MIT
augly ✗ (PIL-only) ~5 ~20 MIT

¹ External counts are approximate as of 2026-05 (sampled from each project's __init__.py / docs index). Versions move fast — consult each project's authoritative API reference for current numbers. paraug counts are code-exact (len(GEOMETRIC_PRIMITIVES) / len(PHOTOMETRIC_PRIMITIVES)).

² Tolerance verified by tests/test_parity.py on NVIDIA 5060 Ti + 4080 at v0.1.0; exact bounds: 1e-6 for the 6 elementwise photometric ops listed in PHOTO_ELEMENTWISE (gamma / gaussian_noise / color_jitter / vignette / cutout / hue_shift), 2e-4 for grid_sample-class (geometric) and conv-class (blur) ops. GitHub free CI runners are CPU-only, so the 13 CUDA parity tests skip on CI — community verification on additional GPU SKUs is welcome (open a PR with the result, or run pytest tests/test_parity.py -k cpu_vs_cuda locally and post the output).

When to use paraug

  • Cross-device reproducibility (paper-grade ablation where CPU↔GPU drift breaks a baseline)
  • Distributed training on heterogeneous hardware
  • Unit-test-friendly augmentation pipelines (CPU-side RNG means a test on a free CI runner reproduces a developer's GPU result)

When NOT to use paraug

  • You need 50+ primitive options out of the box → try albumentations or imgaug
  • You need PIL-style per-image API → try augly
  • You need built-in compositional ops like OneOf / SomeOf → try albumentations

Examples

See examples/:

  • 01_quickstart.py — minimal load → augment → save
  • 02_mask_aware.py — image + segmentation mask warped together
  • 03_cpu_gpu_parity.py — same seed on CPU and CUDA, assert max_abs_diff < 2e-4

Citation

@software{paraug2026,
  author = {alieuidsh},
  title  = {paraug: Bit-exact CPU/GPU parity for image augmentation},
  year   = {2026},
  url    = {https://github.com/alieuidsh/paraug},
}

License

Apache 2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paraug-0.1.1.tar.gz (2.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paraug-0.1.1-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file paraug-0.1.1.tar.gz.

File metadata

  • Download URL: paraug-0.1.1.tar.gz
  • Upload date:
  • Size: 2.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for paraug-0.1.1.tar.gz
Algorithm Hash digest
SHA256 836b1a7865e8ac19d85121af120d46b9e5cfe3924da855c7ab45dfa9bd4a8520
MD5 641ca8a2703dacd9665ee5cc419425a1
BLAKE2b-256 10aec0befe99a8ef4a2a4abd1fff8681968fc18b7ea87e6335fa864831f729e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for paraug-0.1.1.tar.gz:

Publisher: publish.yml on alieuidsh/paraug

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file paraug-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: paraug-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 28.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for paraug-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2c05855051c6f1de5b9c63aa1549f222f401fde55b4b5be881f5edc5382ad267
MD5 3a75070bf88c853dbfa9cba5c741dad6
BLAKE2b-256 479cb36b777c894b7b012dd789db2c22ca82f8a383dc0f80fcf33d89f0da2b45

See more details on using hashes here.

Provenance

The following attestation bundles were made for paraug-0.1.1-py3-none-any.whl:

Publisher: publish.yml on alieuidsh/paraug

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page