🐛 Bug
spectral_angle_mapper (and probably the class interface too) gives a NaN even with one zero pixel in the image.
The SAM score is the acos of the channel dot product, and requires normalising the dot by the input norms.
However in torchmetrics, the convention is to compute the metric over the whole image, and only reduce over spatial dims after. Therefore, even if there's a single pixel in the inputs that's zero, a pixel in the unreduced norm will be zero -> NaNs when one reduces.
This isn't good behaviour, because one only expects SAM to be NaN when an input is all-zeros, not just one zero pixel.
Solution could either be a) reduce ignoring NaNs; b) add an eps; c) return reduce(unnormalised_score) / reduce(preds_norm * target_norm)
To Reproduce
from torchmetrics.functional.image import spectral_angle_mapper
a, b = torch.ones(2, 1, 3, 8, 8)
a[:, :, 5, 3] = 0
spectral_angle_mapper(a, b)
out: tensor(nan)
🐛 Bug
spectral_angle_mapper(and probably the class interface too) gives a NaN even with one zero pixel in the image.The SAM score is the acos of the channel dot product, and requires normalising the dot by the input norms.
However in torchmetrics, the convention is to compute the metric over the whole image, and only reduce over spatial dims after. Therefore, even if there's a single pixel in the inputs that's zero, a pixel in the unreduced norm will be zero -> NaNs when one reduces.
This isn't good behaviour, because one only expects SAM to be NaN when an input is all-zeros, not just one zero pixel.
Solution could either be a) reduce ignoring NaNs; b) add an eps; c)
return reduce(unnormalised_score) / reduce(preds_norm * target_norm)To Reproduce