@@ -317,15 +317,22 @@ def parzen_windowing_gaussian(self, img: torch.Tensor) -> tuple[torch.Tensor, to
317317 Args:
318318 img: the shape should be B[NDHW].
319319 """
320- img = torch .clamp (img , 0 , 1 )
320+ output_dtype = img .dtype
321+ if output_dtype == torch .float16 :
322+ img = img .float ()
323+ compute_dtype = torch .float32 if img .dtype in (torch .float16 , torch .bfloat16 ) else img .dtype
324+ img = torch .clamp (img , 0 , 1 ).to (dtype = compute_dtype )
321325 img = img .reshape (img .shape [0 ], - 1 , 1 ) # (batch, num_sample, 1)
322326 if self .bin_centers is None or self .preterm is None :
323327 raise ValueError ("bin_centers and preterm must be defined for gaussian parzen windowing." )
324- weight = torch . exp (
325- - self .preterm . to ( img ) * ( img - self . bin_centers .to (img )) ** 2
326- ) # (batch, num_sample, num_bin)
328+ preterm = self . preterm . to ( device = img . device , dtype = compute_dtype )
329+ bin_centers = self .bin_centers .to (device = img . device , dtype = compute_dtype )
330+ weight = torch . exp ( - preterm * ( img - bin_centers ) ** 2 ) # (batch, num_sample, num_bin)
327331 weight = weight / torch .sum (weight , dim = - 1 , keepdim = True ) # (batch, num_sample, num_bin)
328332 probability = torch .mean (weight , dim = - 2 , keepdim = True ) # (batch, 1, num_bin)
333+ if output_dtype in (torch .float16 , torch .bfloat16 ):
334+ weight = weight .to (dtype = output_dtype )
335+ probability = probability .to (dtype = output_dtype )
329336 return weight , probability
330337
331338 def forward (self , pred : torch .Tensor , target : torch .Tensor ) -> torch .Tensor :
@@ -340,16 +347,28 @@ def forward(self, pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
340347 raise ValueError (f"ground truth has differing shape ({ target .shape } ) from pred ({ pred .shape } )" )
341348 wa , pa , wb , pb = self .parzen_windowing (pred , target ) # (batch, num_sample, num_bin), (batch, 1, num_bin)
342349
343- pab = torch .bmm (wa .permute (0 , 2 , 1 ), wb .to (wa )).div (wa .shape [1 ]) # (batch, num_bins, num_bins)
344- papb = torch .bmm (pa .permute (0 , 2 , 1 ), pb .to (pa )) # (batch, num_bins, num_bins)
345- mi = torch .sum (
346- pab * torch .log ((pab + self .smooth_nr ) / (papb + self .smooth_dr ) + self .smooth_dr ), dim = (1 , 2 )
347- ) # (batch)
350+ # Half-precision matrix multiplication can overflow before the joint
351+ # histogram is divided by the number of samples. Accumulate histogram
352+ # products in float32 while preserving float64 inputs.
353+ output_dtype = wa .dtype
354+ compute_dtype = torch .float32 if wa .dtype in (torch .float16 , torch .bfloat16 ) else wa .dtype
355+ wa = wa .to (dtype = compute_dtype )
356+ wb = wb .to (wa )
357+ pa = pa .to (dtype = compute_dtype )
358+ pb = pb .to (pa )
359+ with torch .autocast (device_type = wa .device .type , enabled = False ):
360+ pab = torch .bmm (wa .permute (0 , 2 , 1 ), wb ).div (wa .shape [1 ]) # (batch, num_bins, num_bins)
361+ papb = torch .bmm (pa .permute (0 , 2 , 1 ), pb ) # (batch, num_bins, num_bins)
362+ mi = torch .sum (
363+ pab * torch .log ((pab + self .smooth_nr ) / (papb + self .smooth_dr ) + self .smooth_dr ), dim = (1 , 2 )
364+ ) # (batch)
348365
349366 if self .reduction == LossReduction .SUM .value :
350- return torch .sum (mi ).neg () # sum over the batch and channel ndims
351- if self .reduction == LossReduction .NONE .value :
352- return mi .neg ()
353- if self .reduction == LossReduction .MEAN .value :
354- return torch .mean (mi ).neg () # average over the batch and channel ndims
355- raise ValueError (f'Unsupported reduction: { self .reduction } , available options are ["mean", "sum", "none"].' )
367+ loss = torch .sum (mi ).neg () # sum over the batch and channel ndims
368+ elif self .reduction == LossReduction .NONE .value :
369+ loss = mi .neg ()
370+ elif self .reduction == LossReduction .MEAN .value :
371+ loss = torch .mean (mi ).neg () # average over the batch and channel ndims
372+ else :
373+ raise ValueError (f'Unsupported reduction: { self .reduction } , available options are ["mean", "sum", "none"].' )
374+ return loss .to (dtype = output_dtype )
0 commit comments