Fix NaN gradient in PerceptualLoss normalize_tensor#8982
Conversation
Fixes Project-MONAI#8412 Signed-off-by: Shizoqua <hr.lanreshittu@yahoo.com>
📝 WalkthroughWalkthroughThe change modifies Estimated code review effort: 2 (Simple) | ~10 minutes Changes
Related issues: Fixes PerceptualLoss NaN gradient bug ( Suggested reviewers: ericspod, KumoLiu PoemA rabbit hopped through gradient trees, 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
monai/losses/perceptual.py (1)
313-317: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCorrect fix for NaN gradient; add missing docstring.
Moving
epsinside the sqrt is the right fix—derivative ofsqrtat 0 is undefined/infinite, so keeping the argument bounded away from 0 avoids the NaN. Comments explain rationale well.However,
normalize_tensorstill lacks a docstring describingx,eps, and the return value.📝 Suggested docstring
def normalize_tensor(x: torch.Tensor, eps: float = 1e-10) -> torch.Tensor: + """Normalize a tensor across the channel dimension (dim=1). + + Args: + x: input tensor to normalize. + eps: small value added inside the sqrt to avoid NaN gradients when the + per-sample norm is zero (see issue `#8412`). + + Returns: + The channel-normalized tensor with the same shape as ``x``. + """ # Add eps inside the sqrt so the gradient stays finite when the norm is zero # (e.g. identical input/target features), avoiding NaNs from SqrtBackward. See issue `#8412`. norm_factor = torch.sqrt(torch.sum(x**2, dim=1, keepdim=True) + eps) return x / norm_factorAs per path instructions, "Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@monai/losses/perceptual.py` around lines 313 - 317, The normalize_tensor function in perceptual.py needs a Google-style docstring. Add a concise docstring to normalize_tensor that describes the x tensor argument, the eps parameter, and the normalized tensor return value, matching the project’s documentation standard while keeping the existing NaN-safe implementation intact.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@monai/losses/perceptual.py`:
- Around line 313-317: The normalize_tensor function in perceptual.py needs a
Google-style docstring. Add a concise docstring to normalize_tensor that
describes the x tensor argument, the eps parameter, and the normalized tensor
return value, matching the project’s documentation standard while keeping the
existing NaN-safe implementation intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 28a5a6b9-7313-4f8f-ac96-8d3344078194
📒 Files selected for processing (2)
monai/losses/perceptual.pytests/losses/test_perceptual_loss.py
Fixes #8412
Description
PerceptualLosscould crash withRuntimeError: Function 'SqrtBackward0' returned nan values in its 0th outputwhen the loss became very low (near-identical input/target features). The cause was innormalize_tensor, whereepswas added after the square root — this guarded the forward division but not thesqrtgradient, so a zero feature norm produced1/(2·√0) = inf → NaNduring backprop. This PR movesepsinside the sqrt (sqrt(sum(x**2) + eps)), keeping the forward output unchanged for normal inputs while ensuring the gradient stays finite. This matches the standard LPIPS normalization pattern.Types of changes
./runtests.sh -f -u --net --coverage../runtests.sh --quick --unittests --disttests.make htmlcommand in thedocs/folder.