Search before asking
Bug
On the Kornia GPU backend, CLAHE applies a fixed clip_limit where the CPU (Albumentations) backend samples one from a range. This affects the default configuration, so it is not limited to unusual configs.
Albumentations expands a scalar clip_limit to (1, v):
>>> import albumentations as A
>>> A.CLAHE(clip_limit=4.0).clip_limit
(1.0, 4.0)
_make_clahe in src/rfdetr/datasets/kornia_transforms.py routes it through _as_range, which expands a scalar to (v, v):
return random_clahe(
clip_limit=_as_range(params.get("clip_limit", 4.0)),
...
)
4.0 is the default on both sides, so with no user configuration at all the two backends disagree:
| aug_config |
Kornia clip_limit |
Albumentations clip_limit |
{} (default) |
(4.0, 4.0) |
(1.0, 4.0) |
{"clip_limit": 4.0} |
(4.0, 4.0) |
(1.0, 4.0) |
{"clip_limit": 2.0} |
(2.0, 2.0) |
(1.0, 2.0) |
{"clip_limit": (1.0, 4.0)} |
(1.0, 4.0) |
(1.0, 4.0) |
Only the explicit-pair form agrees. Every scalar form, including the default, pins the GPU path to maximum contrast enhancement on every sample while the CPU path varies it, and nothing is logged.
The docstring states the opposite:
Both parameters map directly: Albumentations' clip_limit (a scalar or a pair) becomes Kornia's clip_limit range
_as_range's own docstring is accurate about what it does — it expands a scalar to the degenerate (v, v) — so this is a wrong choice of helper at the call site rather than a bug inside the helper.
Expected behavior
A scalar clip_limit should reach Kornia as (1, v), matching how Albumentations reads the same config, so the two backends draw from the same distribution.
Minimal Reproducible Example
import albumentations as A
from rfdetr.datasets.kornia_transforms import _make_clahe
print(_make_clahe({}).clip_limit) # (4.0, 4.0)
print(A.CLAHE().clip_limit) # (1.0, 4.0)
Environment
- RF-DETR:
develop at b18c9ca
- kornia 0.8.3, albumentations 2.0.8, torch 2.6.0
- CPU only; no GPU or model weights needed to reproduce
Additional
Introduced in #1277, which added the CLAHE mapping — mine, so I would like to fix it.
I checked the other factories that call _as_range for the same class of mismatch:
Sharpen (alpha) and GaussNoise (std_range) — Albumentations rejects a scalar for both with ValueError, so there is no scalar form to disagree about.
GaussianBlur (sigma) — Albumentations expands a scalar sigma_limit to (0, v) rather than (v, v), so the same gap exists, but only when a user passes a scalar; the configured default is already a pair. Happy to include it here or leave it separate, whichever you prefer.
Are you willing to submit a PR?
Search before asking
Bug
On the Kornia GPU backend,
CLAHEapplies a fixedclip_limitwhere the CPU (Albumentations) backend samples one from a range. This affects the default configuration, so it is not limited to unusual configs.Albumentations expands a scalar
clip_limitto(1, v):_make_claheinsrc/rfdetr/datasets/kornia_transforms.pyroutes it through_as_range, which expands a scalar to(v, v):4.0is the default on both sides, so with no user configuration at all the two backends disagree:clip_limitclip_limit{}(default)(4.0, 4.0)(1.0, 4.0){"clip_limit": 4.0}(4.0, 4.0)(1.0, 4.0){"clip_limit": 2.0}(2.0, 2.0)(1.0, 2.0){"clip_limit": (1.0, 4.0)}(1.0, 4.0)(1.0, 4.0)Only the explicit-pair form agrees. Every scalar form, including the default, pins the GPU path to maximum contrast enhancement on every sample while the CPU path varies it, and nothing is logged.
The docstring states the opposite:
_as_range's own docstring is accurate about what it does — it expands a scalar to the degenerate(v, v)— so this is a wrong choice of helper at the call site rather than a bug inside the helper.Expected behavior
A scalar
clip_limitshould reach Kornia as(1, v), matching how Albumentations reads the same config, so the two backends draw from the same distribution.Minimal Reproducible Example
Environment
developatb18c9caAdditional
Introduced in #1277, which added the CLAHE mapping — mine, so I would like to fix it.
I checked the other factories that call
_as_rangefor the same class of mismatch:Sharpen(alpha) andGaussNoise(std_range) — Albumentations rejects a scalar for both withValueError, so there is no scalar form to disagree about.GaussianBlur(sigma) — Albumentations expands a scalarsigma_limitto(0, v)rather than(v, v), so the same gap exists, but only when a user passes a scalar; the configured default is already a pair. Happy to include it here or leave it separate, whichever you prefer.Are you willing to submit a PR?