sigmoid_focal_loss gives NaN gradients for confident predictions when gamma < 1
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 78/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Ambito
- machine-learning
Direzione di ricerca
Inizia da torchvision/ops/focal_loss.py alle righe collegate nel report e riproduci i gradienti NaN con lo snippet fornito. Aggiungi un test di regressione per le predizioni corrette con elevata sicurezza quando gamma < 1, includendo la precisione ridotta se opportuno. Il lavoro è completato quando i gradienti rimangono finiti e il comportamento della loss è preservato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
🐛 Describe the bug
With 0 < gamma < 1, torchvision.ops.sigmoid_focal_loss returns a finite loss but NaN gradients for any element whose prediction is confidently correct. One such element makes the gradients of the whole model NaN. The default gamma=2 is not affected, and neither is gamma=1.
import torch
from torchvision.ops import sigmoid_focal_loss
# Confidently correct predictions: a positive with logit 20 and a negative with logit -20
logits = torch.tensor([20.0, -20.0], requires_grad=True)
targets = torch.tensor([1.0, 0.0])
sigmoid_focal_loss(logits, targets, gamma=0.5, reduction="sum").backward()
print(logits.grad) # tensor([nan, nan])
# In bfloat16 it already happens at logit 6.5
logits = torch.tensor([6.5, -6.5], dtype=torch.bfloat16, requires_grad=True)
sigmoid_focal_loss(logits, targets.bfloat16(), gamma=0.5, reduction="sum").backward()
print(logits.grad) # tensor([nan, nan], dtype=torch.bfloat16)
# One such logit makes every gradient of the classifier NaN
torch.manual_seed(0)
head = torch.nn.Linear(16, 1)
features = torch.randn(8, 16)
with torch.no_grad():
features[0] = -15 * head.weight[0].sign() # one easy, very confident negative
logits = head(features).squeeze(1)
loss = sigmoid_focal_loss(logits, torch.zeros(8), gamma=0.5, reduction="sum")
loss.backward()
print(logits[0].item(), loss.item(), head.weight.grad.isnan().all().item()) # about -24, finite loss, True
The gradients become NaN once |logit| of a correctly classified element reaches 16.75 in float32, 8.5 in float16 and 6.25 in bfloat16 (the same for gamma 0.25, 0.5 and 0.75).
The cause is in focal_loss.py#L41-L43. p = torch.sigmoid(inputs) rounds to exactly 1 (or 1 - p to exactly 1), so 1 - p_t is exactly 0. The derivative of (1 - p_t) ** gamma at 0 is infinite for gamma < 1, and the chain rule multiplies it by p * (1 - p), which is also 0, giving NaN.
Two changes I tried, both of which give the same loss as the current code in float64 (relative difference 0 on 10,000 random elements, gamma 0.5 and 2):
- Compute
1 - p_twithout the1 - pcancellation:p * (1 - targets) + torch.sigmoid(-inputs) * targets. This moves the threshold out to|logit| = 88.75, wheresigmoid(-x)underflows. - Clamp it:
(1 - p_t).clamp(min=torch.finfo(inputs.dtype).tiny) ** gamma. No NaN at any logit I tried.
I'm happy to open a PR with either one plus a test, if that sounds useful.
AI disclosure: I used Claude Code to write a script that runs torchvision.ops functions at edge-case inputs and checks values and gradients. It flagged this, then helped measure the thresholds and try the two fixes. I checked the cause in the code and ran the snippet above myself.
Versions
- PyTorch version: 2.16.0.dev20261107+cpu
- torchvision version: 0.30.0.dev20261107+cpu (the same code is on
mainat 426030113) - OS: Ubuntu 24.04.5 LTS (x86_64), WSL2
- Python version: 3.12.3
- Lingua principale
- Python
- Stelle
- 18k
- Fork
- 7.3k
- Merge medio
- 4h 56m
- PR unite (30g)
- 9
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di pytorch/vision
-
vision_stable.cpp gets hipified into a duplicate copy under ROCm, causing "multiple definition of vision::cuda_version()"Forse già presa Una pull request collegata a questa issue è aperta o già unita. Apertamodule: rocm
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
Clip samplers crash on iteration when no video clips are availableForse già presa @raunakpandey1 l’ha presa 5 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 1 giorno
-
complete_box_iou_loss / complete_box_iou: NaN gradients for zero-height boxes, NaN for point boxesAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno
-
sanitize_bounding_boxes computes the wrong height for rotated boxesForse già presa @u7k4rs6 l’ha presa 39 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 1 giorno
-
Support PIL images in v2.GaussianNoiseForse già presa @YeonwooSung l’ha presa 64 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
pytorch/vision#9652 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di pytorch/vision
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
adafruit/Fruit-Jam-OS#98 ·
-
python triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
microsoft/semantic-kernel#14753 ·
I maintainer di solito rispondono entro 5 giorni
-
area:cli area:configuration documentation priority:low size:small
Difficoltà 1/5 1-3 ore Idoneità per principianti 80/100
RonaldHensbergen/composable-data-stack#1222 ·
I maintainer di solito rispondono entro 1 giorno
-
bug python
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
pvlib/pvlib-python#2939 ·
I maintainer di solito rispondono entro 1 giorno