fix(image): guard spectral_angle_mapper against NaN on zero-norm pixels#3372
Open
xodn348 wants to merge 1 commit intoLightning-AI:masterfrom
Open
fix(image): guard spectral_angle_mapper against NaN on zero-norm pixels#3372xodn348 wants to merge 1 commit intoLightning-AI:masterfrom
xodn348 wants to merge 1 commit intoLightning-AI:masterfrom
Conversation
…xels When any spatial pixel in `preds` or `target` has an all-zero channel vector its L2-norm is zero, making the cosine quotient 0/0 = NaN. Clamping preds_norm * target_norm to machine epsilon (dtype-aware, matching the convention of F.cosine_similarity) returns acos(0) = π/2 for those degenerate pixels instead of propagating NaN through the reduction. Fixes Lightning-AI#3322
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
spectral_angle_mapper(and theSpectralAngleMapperclass) silently returnsNaNwhen anyspatial pixel has an all-zero channel vector — for example a constant-black pixel in an image.
The SAM score is computed as
acos(dot / (|preds| * |target|)), and when either norm is zero thequotient is
0/0 = NaN, which then propagates throughtorch.clampandacosinto the finalreduction. The fix clamps
preds_norm * target_normtotorch.finfo(dtype).epsbefore dividing,matching the convention used by
torch.nn.functional.cosine_similarity. A zero-norm pixel nowcontributes
acos(0) = π/2(90°) to the mean score instead of poisoning it with NaN.Issue
Fixes #3322
Local verification
Risk
The only changed line is in
_sam_compute; existing random-valued inputs never produce azero-norm pixel so all current tests pass unchanged. The behaviour for non-degenerate inputs
is numerically identical because
preds_norm * target_norm ≥ epsalready holds. Any callerthat was deliberately testing for
NaNon zero-input would observeπ/2instead, which is abreaking change only in that narrow and arguably-incorrect use case.
📚 Documentation preview 📚: https://torchmetrics--3372.org.readthedocs.build/en/3372/