import torch def smooth_l1_loss(input, target, beta=1. / 9, size_average=True): """ very similar to the smooth_l1_loss from pytorch, but with the extra beta parameter Modified according to detectron2's fvcore, refer to https://github.com/facebookresearch/fvcore/blob/master/fvcore/nn/smooth_l1_loss.py """ if beta < 1e-5: # if beta == 0, then torch.where will result in nan gradients when # the chain rule is applied due to pytorch implementation details # (the False branch "0.5 * n ** 2 / 0" has an incoming gradient of # zeros, rather than "no gradient"). To avoid this issue, we define # small values of beta to be exactly l1 loss. loss = torch.abs(input - target) else: n = torch.abs(input - target) cond = n < beta loss = torch.where(cond, 0.5 * n ** 2 / beta, n - 0.5 * beta) if size_average: return loss.mean() return loss.sum() def smooth_l1_loss_LW(bbox_pred, bbox_targets, bbox_inside_weights, bbox_outside_weights, beta=1.0): """ SmoothL1(x) = 0.5 * x^2 / beta if |x| < beta |x| - 0.5 * beta otherwise. 1 / N * sum_i alpha_out[i] * SmoothL1(alpha_in[i] * (y_hat[i] - y[i])). N is the number of batch elements in the input predictions """ box_diff = bbox_pred - bbox_targets in_box_diff = bbox_inside_weights * box_diff abs_in_box_diff = torch.abs(in_box_diff) smoothL1_sign = (abs_in_box_diff < beta).detach().float() in_loss_box = smoothL1_sign * 0.5 * torch.pow(in_box_diff, 2) / beta + \ (1 - smoothL1_sign) * (abs_in_box_diff - (0.5 * beta)) out_loss_box = bbox_outside_weights * in_loss_box loss_box = out_loss_box N = loss_box.size(0) # batch size loss_box = loss_box.view(-1).sum(0) / N return loss_box