Unverified Commit ba26d8ce authored by Kai Chen's avatar Kai Chen Committed by GitHub
Browse files

Refactoring for losses (#761)

* refactoring for losses

* update configs for guided anchoring

* add all imported losses to __all__

* allow weight=None for binary_cross_entropy

* use losses in mmdetection for FCOSHead

* bug fix for weight_reduce_loss

* add eps to iou_loss and handle weight=None

* unify loss api in FCOSHead

* fix avg_factor
parent afb7ec86
...@@ -25,7 +25,16 @@ model = dict( ...@@ -25,7 +25,16 @@ model = dict(
in_channels=256, in_channels=256,
stacked_convs=4, stacked_convs=4,
feat_channels=256, feat_channels=256,
strides=[8, 16, 32, 64, 128])) strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)))
# training and testing settings # training and testing settings
train_cfg = dict( train_cfg = dict(
assigner=dict( assigner=dict(
...@@ -34,9 +43,6 @@ train_cfg = dict( ...@@ -34,9 +43,6 @@ train_cfg = dict(
neg_iou_thr=0.4, neg_iou_thr=0.4,
min_pos_iou=0, min_pos_iou=0,
ignore_iof_thr=-1), ignore_iof_thr=-1),
smoothl1_beta=0.11,
gamma=2.0,
alpha=0.25,
allowed_border=-1, allowed_border=-1,
pos_weight=-1, pos_weight=-1,
debug=False) debug=False)
......
...@@ -26,7 +26,16 @@ model = dict( ...@@ -26,7 +26,16 @@ model = dict(
in_channels=256, in_channels=256,
stacked_convs=4, stacked_convs=4,
feat_channels=256, feat_channels=256,
strides=[8, 16, 32, 64, 128])) strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)))
# training and testing settings # training and testing settings
train_cfg = dict( train_cfg = dict(
assigner=dict( assigner=dict(
...@@ -35,9 +44,6 @@ train_cfg = dict( ...@@ -35,9 +44,6 @@ train_cfg = dict(
neg_iou_thr=0.4, neg_iou_thr=0.4,
min_pos_iou=0, min_pos_iou=0,
ignore_iof_thr=-1), ignore_iof_thr=-1),
smoothl1_beta=0.11,
gamma=2.0,
alpha=0.25,
allowed_border=-1, allowed_border=-1,
pos_weight=-1, pos_weight=-1,
debug=False) debug=False)
......
...@@ -25,7 +25,16 @@ model = dict( ...@@ -25,7 +25,16 @@ model = dict(
in_channels=256, in_channels=256,
stacked_convs=4, stacked_convs=4,
feat_channels=256, feat_channels=256,
strides=[8, 16, 32, 64, 128])) strides=[8, 16, 32, 64, 128],
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0)))
# training and testing settings # training and testing settings
train_cfg = dict( train_cfg = dict(
assigner=dict( assigner=dict(
...@@ -34,9 +43,6 @@ train_cfg = dict( ...@@ -34,9 +43,6 @@ train_cfg = dict(
neg_iou_thr=0.4, neg_iou_thr=0.4,
min_pos_iou=0, min_pos_iou=0,
ignore_iof_thr=-1), ignore_iof_thr=-1),
smoothl1_beta=0.11,
gamma=2.0,
alpha=0.25,
allowed_border=-1, allowed_border=-1,
pos_weight=-1, pos_weight=-1,
debug=False) debug=False)
......
...@@ -36,8 +36,7 @@ model = dict( ...@@ -36,8 +36,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)),
......
...@@ -36,8 +36,7 @@ model = dict( ...@@ -36,8 +36,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)), loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)),
......
...@@ -40,8 +40,7 @@ model = dict( ...@@ -40,8 +40,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='FocalLoss', type='FocalLoss',
use_sigmoid=True, use_sigmoid=True,
......
...@@ -40,8 +40,7 @@ model = dict( ...@@ -40,8 +40,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='FocalLoss', type='FocalLoss',
use_sigmoid=True, use_sigmoid=True,
......
...@@ -36,8 +36,7 @@ model = dict( ...@@ -36,8 +36,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))) loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)))
......
...@@ -36,8 +36,7 @@ model = dict( ...@@ -36,8 +36,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))) loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)))
......
...@@ -36,8 +36,7 @@ model = dict( ...@@ -36,8 +36,7 @@ model = dict(
gamma=2.0, gamma=2.0,
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(type='BoundedIoULoss', beta=0.2, loss_weight=1.0),
type='IoULoss', style='bounded', beta=0.2, loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))) loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)))
......
from .anchor import * # noqa: F401, F403 from .anchor import * # noqa: F401, F403
from .bbox import * # noqa: F401, F403 from .bbox import * # noqa: F401, F403
from .mask import * # noqa: F401, F403 from .mask import * # noqa: F401, F403
from .loss import * # noqa: F401, F403
from .evaluation import * # noqa: F401, F403 from .evaluation import * # noqa: F401, F403
from .post_processing import * # noqa: F401, F403 from .post_processing import * # noqa: F401, F403
from .utils import * # noqa: F401, F403 from .utils import * # noqa: F401, F403
from .losses import (weighted_nll_loss, weighted_cross_entropy,
weighted_binary_cross_entropy, sigmoid_focal_loss,
py_sigmoid_focal_loss, weighted_sigmoid_focal_loss,
mask_cross_entropy, smooth_l1_loss, weighted_smoothl1,
balanced_l1_loss, weighted_balanced_l1_loss, iou_loss,
bounded_iou_loss, weighted_iou_loss, accuracy)
__all__ = [
'weighted_nll_loss', 'weighted_cross_entropy',
'weighted_binary_cross_entropy', 'sigmoid_focal_loss',
'py_sigmoid_focal_loss', 'weighted_sigmoid_focal_loss',
'mask_cross_entropy', 'smooth_l1_loss', 'weighted_smoothl1',
'balanced_l1_loss', 'weighted_balanced_l1_loss', 'bounded_iou_loss',
'weighted_iou_loss', 'iou_loss', 'accuracy'
]
# TODO merge naive and weighted loss.
import numpy as np
import torch
import torch.nn.functional as F
from ..bbox import bbox_overlaps
from ...ops import sigmoid_focal_loss
def weighted_nll_loss(pred, label, weight, avg_factor=None):
if avg_factor is None:
avg_factor = max(torch.sum(weight > 0).float().item(), 1.)
raw = F.nll_loss(pred, label, reduction='none')
return torch.sum(raw * weight)[None] / avg_factor
def weighted_cross_entropy(pred, label, weight, avg_factor=None, reduce=True):
if avg_factor is None:
avg_factor = max(torch.sum(weight > 0).float().item(), 1.)
raw = F.cross_entropy(pred, label, reduction='none')
if reduce:
return torch.sum(raw * weight)[None] / avg_factor
else:
return raw * weight / avg_factor
def weighted_binary_cross_entropy(pred, label, weight, avg_factor=None):
if pred.dim() != label.dim():
label, weight = _expand_binary_labels(label, weight, pred.size(-1))
if avg_factor is None:
avg_factor = max(torch.sum(weight > 0).float().item(), 1.)
return F.binary_cross_entropy_with_logits(
pred, label.float(), weight.float(),
reduction='sum')[None] / avg_factor
def py_sigmoid_focal_loss(pred,
target,
weight,
gamma=2.0,
alpha=0.25,
reduction='mean'):
pred_sigmoid = pred.sigmoid()
target = target.type_as(pred)
pt = (1 - pred_sigmoid) * target + pred_sigmoid * (1 - target)
weight = (alpha * target + (1 - alpha) * (1 - target)) * weight
weight = weight * pt.pow(gamma)
loss = F.binary_cross_entropy_with_logits(
pred, target, reduction='none') * weight
reduction_enum = F._Reduction.get_enum(reduction)
# none: 0, mean:1, sum: 2
if reduction_enum == 0:
return loss
elif reduction_enum == 1:
return loss.mean()
elif reduction_enum == 2:
return loss.sum()
def weighted_sigmoid_focal_loss(pred,
target,
weight,
gamma=2.0,
alpha=0.25,
avg_factor=None,
num_classes=80):
if avg_factor is None:
avg_factor = torch.sum(weight > 0).float().item() / num_classes + 1e-6
return torch.sum(
sigmoid_focal_loss(pred, target, gamma, alpha, 'none') *
weight.view(-1, 1))[None] / avg_factor
def mask_cross_entropy(pred, target, label):
num_rois = pred.size()[0]
inds = torch.arange(0, num_rois, dtype=torch.long, device=pred.device)
pred_slice = pred[inds, label].squeeze(1)
return F.binary_cross_entropy_with_logits(
pred_slice, target, reduction='mean')[None]
def smooth_l1_loss(pred, target, beta=1.0, reduction='mean'):
assert beta > 0
assert pred.size() == target.size() and target.numel() > 0
diff = torch.abs(pred - target)
loss = torch.where(diff < beta, 0.5 * diff * diff / beta,
diff - 0.5 * beta)
reduction_enum = F._Reduction.get_enum(reduction)
# none: 0, mean:1, sum: 2
if reduction_enum == 0:
return loss
elif reduction_enum == 1:
return loss.sum() / pred.numel()
elif reduction_enum == 2:
return loss.sum()
def weighted_smoothl1(pred, target, weight, beta=1.0, avg_factor=None):
if avg_factor is None:
avg_factor = torch.sum(weight > 0).float().item() / 4 + 1e-6
loss = smooth_l1_loss(pred, target, beta, reduction='none')
return torch.sum(loss * weight)[None] / avg_factor
def balanced_l1_loss(pred,
target,
beta=1.0,
alpha=0.5,
gamma=1.5,
reduction='none'):
assert beta > 0
assert pred.size() == target.size() and target.numel() > 0
diff = torch.abs(pred - target)
b = np.e**(gamma / alpha) - 1
loss = torch.where(
diff < beta, alpha / b *
(b * diff + 1) * torch.log(b * diff / beta + 1) - alpha * diff,
gamma * diff + gamma / b - alpha * beta)
reduction_enum = F._Reduction.get_enum(reduction)
# none: 0, elementwise_mean:1, sum: 2
if reduction_enum == 0:
return loss
elif reduction_enum == 1:
return loss.sum() / pred.numel()
elif reduction_enum == 2:
return loss.sum()
return loss
def weighted_balanced_l1_loss(pred,
target,
weight,
beta=1.0,
alpha=0.5,
gamma=1.5,
avg_factor=None):
if avg_factor is None:
avg_factor = torch.sum(weight > 0).float().item() / 4 + 1e-6
loss = balanced_l1_loss(pred, target, beta, alpha, gamma, reduction='none')
return torch.sum(loss * weight)[None] / avg_factor
def bounded_iou_loss(pred, target, beta=0.2, eps=1e-3, reduction='mean'):
"""Improving Object Localization with Fitness NMS and Bounded IoU Loss,
https://arxiv.org/abs/1711.00164.
Args:
pred (tensor): Predicted bboxes.
target (tensor): Target bboxes.
beta (float): beta parameter in smoothl1.
eps (float): eps to avoid NaN.
reduction (str): Reduction type.
"""
pred_ctrx = (pred[:, 0] + pred[:, 2]) * 0.5
pred_ctry = (pred[:, 1] + pred[:, 3]) * 0.5
pred_w = pred[:, 2] - pred[:, 0] + 1
pred_h = pred[:, 3] - pred[:, 1] + 1
with torch.no_grad():
target_ctrx = (target[:, 0] + target[:, 2]) * 0.5
target_ctry = (target[:, 1] + target[:, 3]) * 0.5
target_w = target[:, 2] - target[:, 0] + 1
target_h = target[:, 3] - target[:, 1] + 1
dx = target_ctrx - pred_ctrx
dy = target_ctry - pred_ctry
loss_dx = 1 - torch.max(
(target_w - 2 * dx.abs()) /
(target_w + 2 * dx.abs() + eps), torch.zeros_like(dx))
loss_dy = 1 - torch.max(
(target_h - 2 * dy.abs()) /
(target_h + 2 * dy.abs() + eps), torch.zeros_like(dy))
loss_dw = 1 - torch.min(target_w / (pred_w + eps), pred_w /
(target_w + eps))
loss_dh = 1 - torch.min(target_h / (pred_h + eps), pred_h /
(target_h + eps))
loss_comb = torch.stack([loss_dx, loss_dy, loss_dw, loss_dh],
dim=-1).view(loss_dx.size(0), -1)
loss = torch.where(loss_comb < beta, 0.5 * loss_comb * loss_comb / beta,
loss_comb - 0.5 * beta)
reduction_enum = F._Reduction.get_enum(reduction)
# none: 0, mean:1, sum: 2
if reduction_enum == 0:
return loss
elif reduction_enum == 1:
return loss.sum() / pred.numel()
elif reduction_enum == 2:
return loss.sum()
def weighted_iou_loss(pred,
target,
weight,
style='naive',
beta=0.2,
eps=1e-3,
avg_factor=None):
if style not in ['bounded', 'naive']:
raise ValueError('Only support bounded iou loss and naive iou loss.')
inds = torch.nonzero(weight[:, 0] > 0)
if avg_factor is None:
avg_factor = inds.numel() + 1e-6
if inds.numel() > 0:
inds = inds.squeeze(1)
else:
return (pred * weight).sum()[None] / avg_factor
if style == 'bounded':
loss = bounded_iou_loss(
pred[inds], target[inds], beta=beta, eps=eps, reduction='sum')
else:
loss = iou_loss(pred[inds], target[inds], eps=eps, reduction='sum')
loss = loss[None] / avg_factor
return loss
def accuracy(pred, target, topk=1):
if isinstance(topk, int):
topk = (topk, )
return_single = True
else:
return_single = False
maxk = max(topk)
_, pred_label = pred.topk(maxk, 1, True, True)
pred_label = pred_label.t()
correct = pred_label.eq(target.view(1, -1).expand_as(pred_label))
res = []
for k in topk:
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / pred.size(0)))
return res[0] if return_single else res
def _expand_binary_labels(labels, label_weights, label_channels):
bin_labels = labels.new_full((labels.size(0), label_channels), 0)
inds = torch.nonzero(labels >= 1).squeeze()
if inds.numel() > 0:
bin_labels[inds, labels[inds] - 1] = 1
bin_label_weights = label_weights.view(-1, 1).expand(
label_weights.size(0), label_channels)
return bin_labels, bin_label_weights
def iou_loss(pred_bboxes, target_bboxes, eps=1e-6, reduction='mean'):
ious = bbox_overlaps(pred_bboxes, target_bboxes, is_aligned=True) + eps
loss = -ious.log()
reduction_enum = F._Reduction.get_enum(reduction)
if reduction_enum == 0:
return loss
elif reduction_enum == 1:
return loss.mean()
elif reduction_enum == 2:
return loss.sum()
import torch import torch
import torch.nn as nn import torch.nn as nn
import torch.nn.functional as F
from mmcv.cnn import normal_init from mmcv.cnn import normal_init
from mmdet.core import (sigmoid_focal_loss, iou_loss, multi_apply, from mmdet.core import multi_apply, multiclass_nms, distance2bbox
multiclass_nms, distance2bbox) from ..builder import build_loss
from ..registry import HEADS from ..registry import HEADS
from ..utils import bias_init_with_prob, Scale, ConvModule from ..utils import bias_init_with_prob, Scale, ConvModule
...@@ -22,6 +21,17 @@ class FCOSHead(nn.Module): ...@@ -22,6 +21,17 @@ class FCOSHead(nn.Module):
strides=(4, 8, 16, 32, 64), strides=(4, 8, 16, 32, 64),
regress_ranges=((-1, 64), (64, 128), (128, 256), (256, 512), regress_ranges=((-1, 64), (64, 128), (128, 256), (256, 512),
(512, INF)), (512, INF)),
loss_cls=dict(
type='FocalLoss',
use_sigmoid=True,
gamma=2.0,
alpha=0.25,
loss_weight=1.0),
loss_bbox=dict(type='IoULoss', loss_weight=1.0),
loss_centerness=dict(
type='CrossEntropyLoss',
use_sigmoid=True,
loss_weight=1.0),
conv_cfg=None, conv_cfg=None,
norm_cfg=dict(type='GN', num_groups=32, requires_grad=True)): norm_cfg=dict(type='GN', num_groups=32, requires_grad=True)):
super(FCOSHead, self).__init__() super(FCOSHead, self).__init__()
...@@ -33,6 +43,9 @@ class FCOSHead(nn.Module): ...@@ -33,6 +43,9 @@ class FCOSHead(nn.Module):
self.stacked_convs = stacked_convs self.stacked_convs = stacked_convs
self.strides = strides self.strides = strides
self.regress_ranges = regress_ranges self.regress_ranges = regress_ranges
self.loss_cls = build_loss(loss_cls)
self.loss_bbox = build_loss(loss_bbox)
self.loss_centerness = build_loss(loss_centerness)
self.conv_cfg = conv_cfg self.conv_cfg = conv_cfg
self.norm_cfg = norm_cfg self.norm_cfg = norm_cfg
...@@ -139,9 +152,9 @@ class FCOSHead(nn.Module): ...@@ -139,9 +152,9 @@ class FCOSHead(nn.Module):
pos_inds = flatten_labels.nonzero().reshape(-1) pos_inds = flatten_labels.nonzero().reshape(-1)
num_pos = len(pos_inds) num_pos = len(pos_inds)
loss_cls = sigmoid_focal_loss( loss_cls = self.loss_cls(
flatten_cls_scores, flatten_labels, cfg.gamma, cfg.alpha, flatten_cls_scores, flatten_labels,
'none').sum()[None] / (num_pos + num_imgs) # avoid num_pos is 0 avg_factor=num_pos + num_imgs) # avoid num_pos is 0
pos_bbox_preds = flatten_bbox_preds[pos_inds] pos_bbox_preds = flatten_bbox_preds[pos_inds]
pos_bbox_targets = flatten_bbox_targets[pos_inds] pos_bbox_targets = flatten_bbox_targets[pos_inds]
...@@ -154,20 +167,20 @@ class FCOSHead(nn.Module): ...@@ -154,20 +167,20 @@ class FCOSHead(nn.Module):
pos_decoded_target_preds = distance2bbox(pos_points, pos_decoded_target_preds = distance2bbox(pos_points,
pos_bbox_targets) pos_bbox_targets)
# centerness weighted iou loss # centerness weighted iou loss
loss_reg = ((iou_loss( loss_bbox = self.loss_bbox(
pos_decoded_bbox_preds, pos_decoded_bbox_preds,
pos_decoded_target_preds, pos_decoded_target_preds,
reduction='none') * pos_centerness_targets).sum() / weight=pos_centerness_targets,
pos_centerness_targets.sum())[None] avg_factor=pos_centerness_targets.sum())
loss_centerness = F.binary_cross_entropy_with_logits( loss_centerness = self.loss_centerness(pos_centerness,
pos_centerness, pos_centerness_targets, reduction='mean')[None] pos_centerness_targets)
else: else:
loss_reg = pos_bbox_preds.sum()[None] loss_bbox = pos_bbox_preds.sum()
loss_centerness = pos_centerness.sum()[None] loss_centerness = pos_centerness.sum()
return dict( return dict(
loss_cls=loss_cls, loss_cls=loss_cls,
loss_reg=loss_reg, loss_bbox=loss_bbox,
loss_centerness=loss_centerness) loss_centerness=loss_centerness)
def get_bboxes(self, def get_bboxes(self,
...@@ -196,9 +209,10 @@ class FCOSHead(nn.Module): ...@@ -196,9 +209,10 @@ class FCOSHead(nn.Module):
] ]
img_shape = img_metas[img_id]['img_shape'] img_shape = img_metas[img_id]['img_shape']
scale_factor = img_metas[img_id]['scale_factor'] scale_factor = img_metas[img_id]['scale_factor']
det_bboxes = self.get_bboxes_single( det_bboxes = self.get_bboxes_single(cls_score_list, bbox_pred_list,
cls_score_list, bbox_pred_list, centerness_pred_list, centerness_pred_list,
mlvl_points, img_shape, scale_factor, cfg, rescale) mlvl_points, img_shape,
scale_factor, cfg, rescale)
result_list.append(det_bboxes) result_list.append(det_bboxes)
return result_list return result_list
......
...@@ -115,8 +115,7 @@ class GuidedAnchorHead(AnchorHead): ...@@ -115,8 +115,7 @@ class GuidedAnchorHead(AnchorHead):
alpha=0.25, alpha=0.25,
loss_weight=1.0), loss_weight=1.0),
loss_shape=dict( loss_shape=dict(
type='IoULoss', type='BoundedIoULoss',
style='bounded',
beta=0.2, beta=0.2,
loss_weight=1.0), loss_weight=1.0),
loss_cls=dict( loss_cls=dict(
......
...@@ -4,9 +4,9 @@ import torch.nn as nn ...@@ -4,9 +4,9 @@ import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from mmcv.cnn import xavier_init from mmcv.cnn import xavier_init
from mmdet.core import (AnchorGenerator, anchor_target, weighted_smoothl1, from mmdet.core import AnchorGenerator, anchor_target, multi_apply
multi_apply)
from .anchor_head import AnchorHead from .anchor_head import AnchorHead
from ..losses import smooth_l1_loss
from ..registry import HEADS from ..registry import HEADS
...@@ -123,7 +123,7 @@ class SSDHead(AnchorHead): ...@@ -123,7 +123,7 @@ class SSDHead(AnchorHead):
loss_cls_neg = topk_loss_cls_neg.sum() loss_cls_neg = topk_loss_cls_neg.sum()
loss_cls = (loss_cls_pos + loss_cls_neg) / num_total_samples loss_cls = (loss_cls_pos + loss_cls_neg) / num_total_samples
loss_bbox = weighted_smoothl1( loss_bbox = smooth_l1_loss(
bbox_pred, bbox_pred,
bbox_targets, bbox_targets,
bbox_weights, bbox_weights,
......
...@@ -2,8 +2,9 @@ import torch ...@@ -2,8 +2,9 @@ import torch
import torch.nn as nn import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from mmdet.core import delta2bbox, multiclass_nms, bbox_target, accuracy from mmdet.core import delta2bbox, multiclass_nms, bbox_target
from ..builder import build_loss from ..builder import build_loss
from ..losses import accuracy
from ..registry import HEADS from ..registry import HEADS
...@@ -99,8 +100,9 @@ class BBoxHead(nn.Module): ...@@ -99,8 +100,9 @@ class BBoxHead(nn.Module):
reduce=True): reduce=True):
losses = dict() losses = dict()
if cls_score is not None: if cls_score is not None:
avg_factor = max(torch.sum(label_weights > 0).float().item(), 1.)
losses['loss_cls'] = self.loss_cls( losses['loss_cls'] = self.loss_cls(
cls_score, labels, label_weights, reduce=reduce) cls_score, labels, label_weights, avg_factor=avg_factor)
losses['acc'] = accuracy(cls_score, labels) losses['acc'] = accuracy(cls_score, labels)
if bbox_pred is not None: if bbox_pred is not None:
pos_inds = labels > 0 pos_inds = labels > 0
......
from .cross_entropy_loss import CrossEntropyLoss from .accuracy import accuracy, Accuracy
from .focal_loss import FocalLoss from .cross_entropy_loss import (cross_entropy, binary_cross_entropy,
from .smooth_l1_loss import SmoothL1Loss mask_cross_entropy, CrossEntropyLoss)
from .focal_loss import sigmoid_focal_loss, FocalLoss
from .smooth_l1_loss import smooth_l1_loss, SmoothL1Loss
from .ghm_loss import GHMC, GHMR from .ghm_loss import GHMC, GHMR
from .balanced_l1_loss import BalancedL1Loss from .balanced_l1_loss import balanced_l1_loss, BalancedL1Loss
from .iou_loss import IoULoss from .iou_loss import iou_loss, bounded_iou_loss, IoULoss, BoundedIoULoss
from .utils import reduce_loss, weight_reduce_loss, weighted_loss
__all__ = [ __all__ = [
'CrossEntropyLoss', 'FocalLoss', 'SmoothL1Loss', 'BalancedL1Loss', 'accuracy', 'Accuracy', 'cross_entropy', 'binary_cross_entropy',
'IoULoss', 'GHMC', 'GHMR' 'mask_cross_entropy', 'CrossEntropyLoss', 'sigmoid_focal_loss',
'FocalLoss', 'smooth_l1_loss', 'SmoothL1Loss', 'balanced_l1_loss',
'BalancedL1Loss', 'iou_loss', 'bounded_iou_loss', 'IoULoss',
'BoundedIoULoss', 'GHMC', 'GHMR', 'reduce_loss', 'weight_reduce_loss',
'weighted_loss'
] ]
import torch.nn as nn
def accuracy(pred, target, topk=1):
assert isinstance(topk, (int, tuple))
if isinstance(topk, int):
topk = (topk, )
return_single = True
else:
return_single = False
maxk = max(topk)
_, pred_label = pred.topk(maxk, dim=1)
pred_label = pred_label.t()
correct = pred_label.eq(target.view(1, -1).expand_as(pred_label))
res = []
for k in topk:
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / pred.size(0)))
return res[0] if return_single else res
class Accuracy(nn.Module):
def __init__(self, topk=(1, )):
super().__init__()
self.topk = topk
def forward(self, pred, target):
return accuracy(pred, target, self.topk)
import numpy as np
import torch
import torch.nn as nn import torch.nn as nn
from mmdet.core import weighted_balanced_l1_loss
from .utils import reduce_loss, weighted_loss
from ..registry import LOSSES from ..registry import LOSSES
@weighted_loss
def balanced_l1_loss(pred,
target,
beta=1.0,
alpha=0.5,
gamma=1.5,
reduction='mean'):
assert beta > 0
assert pred.size() == target.size() and target.numel() > 0
diff = torch.abs(pred - target)
b = np.e**(gamma / alpha) - 1
loss = torch.where(
diff < beta, alpha / b *
(b * diff + 1) * torch.log(b * diff / beta + 1) - alpha * diff,
gamma * diff + gamma / b - alpha * beta)
loss = reduce_loss(loss, reduction)
return loss
@LOSSES.register_module @LOSSES.register_module
class BalancedL1Loss(nn.Module): class BalancedL1Loss(nn.Module):
"""Balanced L1 Loss """Balanced L1 Loss
...@@ -11,21 +35,28 @@ class BalancedL1Loss(nn.Module): ...@@ -11,21 +35,28 @@ class BalancedL1Loss(nn.Module):
arXiv: https://arxiv.org/pdf/1904.02701.pdf (CVPR 2019) arXiv: https://arxiv.org/pdf/1904.02701.pdf (CVPR 2019)
""" """
def __init__(self, alpha=0.5, gamma=1.5, beta=1.0, loss_weight=1.0): def __init__(self,
alpha=0.5,
gamma=1.5,
beta=1.0,
reduction='mean',
loss_weight=1.0):
super(BalancedL1Loss, self).__init__() super(BalancedL1Loss, self).__init__()
self.alpha = alpha self.alpha = alpha
self.gamma = gamma self.gamma = gamma
self.beta = beta self.beta = beta
self.reduction = reduction
self.loss_weight = loss_weight self.loss_weight = loss_weight
def forward(self, pred, target, weight, *args, **kwargs): def forward(self, pred, target, weight=None, avg_factor=None, **kwargs):
loss_bbox = self.loss_weight * weighted_balanced_l1_loss( loss_bbox = self.loss_weight * balanced_l1_loss(
pred, pred,
target, target,
weight, weight,
alpha=self.alpha, alpha=self.alpha,
gamma=self.gamma, gamma=self.gamma,
beta=self.beta, beta=self.beta,
*args, reduction=self.reduction,
avg_factor=avg_factor,
**kwargs) **kwargs)
return loss_bbox return loss_bbox
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment