Skip to content

feat: noise relative to the sample's own spread with RandomGaussianNoiseGPU(relative=True) - #147

Open
Hendrik-code wants to merge 1 commit into
mainfrom
hm/gaussian-noise-relative
Open

Hendrik-code wants to merge 1 commit into
mainfrom
hm/gaussian-noise-relative

Conversation

@Hendrik-code

Copy link
Copy Markdown
Collaborator

What

RandomGaussianNoiseGPU takes relative (default False). When set, std is read as a fraction of each sample's own std in that channel, not in absolute intensity units:

"RandomGaussianNoiseGPU": { "p": 0.1, "std": 0.2, "relative": true }

Why

The std is drawn from U(0, std) in absolute units, so one config is a different augmentation on every intensity scale. Measured on 128³ training patches, image std is about 0.9 on z-scored Dixon MR, 0.17 on CT under nnU-Net's CT normalisation, and 0.16-0.20 on a [0, 1] SynthSeg synthesis. The paper config's std: 1.0 therefore means:

  • noise up to about the image's own spread on MR;
  • up to about six times it on CT and on synthetic samples.

For scale, nnU-Net's default noise std is at most 0.1 on z-scored data (from memory of batchgenerators' noise_variance=(0, 0.1), which it uses as the std).

Behaviour

  • The relative scale is applied after both random draws, so the noise field is the absolute one rescaled per sample (tested). mean stays absolute.
  • The absolute path is arithmetically unchanged: the batch-shared std now broadcasts through the same reshape as the per-sample one, which multiplies by the same value (tested bit-exact against the old formula).
  • Also fixes the docstring, which gave the default std as 0.1. It is 1.0.

Tests

unit_tests/test_gaussian_noise_relative.py:

  • the absolute form is bit-identical to the old arithmetic;
  • the relative form is scale-equivariant;
  • it equals the absolute draw × the sample std;
  • the registry accepts the key.

Full suite: 477 passed, 13 skipped. mypy smauglab/ clean, pre-commit passes.

🤖 Generated with Claude Code

…iseGPU(relative=True)

The noise std is drawn from U(0, std) in absolute intensity units, so one
config is a different augmentation on every intensity scale. With the paper
config's std 1.0 a z-scored MR patch (std ~0.9) gets noise up to about its
own spread, a CT patch under nnU-Net's CT normalisation (std ~0.17) up to six
times its spread, and a [0, 1] SynthSeg synthesis (std ~0.18) likewise.

`relative=True` reads `std` as a fraction of each sample's std in that
channel, which makes the transform scale-equivariant. The scale is applied
after both random draws, so the noise field is the absolute one rescaled per
sample. `mean` stays absolute. Default False; the absolute path is
arithmetically unchanged (the per-sample and batch stds now broadcast through
the same reshape, which multiplies by the same value).

Also corrects the docstring, which gave the default std as 0.1; it is 1.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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