MRaCL / ASDA /utils /utils.py
dianecy's picture
Upload folder using huggingface_hub
3dcfb26 verified
import math
import numpy as np
import torch
import torch.nn.functional as F
from torch import optim
from torch.optim import Optimizer
class AverageMeter(object):
"""Computes and stores the average and current value"""
def __init__(self):
self.reset()
def reset(self):
self.val = 0
self.avg = 0
self.sum = 0
self.count = 0
def update(self, val, n=1):
self.val = val
self.sum += val * n
self.count += n
self.avg = self.sum / self.count
def xyxy2xywh(x): # Convert bounding box format from [x1, y1, x2, y2] to [x, y, w, h]
y = torch.zeros(x.shape) if x.dtype is torch.float32 else np.zeros(x.shape)
y[:, 0] = (x[:, 0] + x[:, 2]) / 2
y[:, 1] = (x[:, 1] + x[:, 3]) / 2
y[:, 2] = x[:, 2] - x[:, 0]
y[:, 3] = x[:, 3] - x[:, 1]
return y
def xywh2xyxy(x): # Convert bounding box format from [x, y, w, h] to [x1, y1, x2, y2]
y = torch.zeros(x.shape) if x.dtype is torch.float32 else np.zeros(x.shape)
y[:, 0] = (x[:, 0] - x[:, 2] / 2)
y[:, 1] = (x[:, 1] - x[:, 3] / 2)
y[:, 2] = (x[:, 0] + x[:, 2] / 2)
y[:, 3] = (x[:, 1] + x[:, 3] / 2)
return y
def bbox_iou_numpy(box1, box2):
"""Computes IoU between bounding boxes.
Parameters
----------
box1 : ndarray
(N, 4) shaped array with bboxes
box2 : ndarray
(M, 4) shaped array with bboxes
Returns
-------
: ndarray
(N, M) shaped array with IoUs
"""
area = (box2[:, 2] - box2[:, 0]) * (box2[:, 3] - box2[:, 1])
iw = np.minimum(np.expand_dims(box1[:, 2], axis=1), box2[:, 2]) - np.maximum(
np.expand_dims(box1[:, 0], 1), box2[:, 0]
)
ih = np.minimum(np.expand_dims(box1[:, 3], axis=1), box2[:, 3]) - np.maximum(
np.expand_dims(box1[:, 1], 1), box2[:, 1]
)
iw = np.maximum(iw, 0)
ih = np.maximum(ih, 0)
ua = np.expand_dims((box1[:, 2] - box1[:, 0]) * (box1[:, 3] - box1[:, 1]), axis=1) + area - iw * ih
ua = np.maximum(ua, np.finfo(float).eps)
intersection = iw * ih
return intersection / ua
def bbox_iou(box1, box2, x1y1x2y2=True):
"""
Returns the IoU of two bounding boxes
"""
if x1y1x2y2:
# Get the coordinates of bounding boxes
b1_x1, b1_y1, b1_x2, b1_y2 = box1[:, 0], box1[:, 1], box1[:, 2], box1[:, 3]
b2_x1, b2_y1, b2_x2, b2_y2 = box2[:, 0], box2[:, 1], box2[:, 2], box2[:, 3]
else:
# Transform from center and width to exact coordinates
b1_x1, b1_x2 = box1[:, 0] - box1[:, 2] / 2, box1[:, 0] + box1[:, 2] / 2
b1_y1, b1_y2 = box1[:, 1] - box1[:, 3] / 2, box1[:, 1] + box1[:, 3] / 2
b2_x1, b2_x2 = box2[:, 0] - box2[:, 2] / 2, box2[:, 0] + box2[:, 2] / 2
b2_y1, b2_y2 = box2[:, 1] - box2[:, 3] / 2, box2[:, 1] + box2[:, 3] / 2
# get the coordinates of the intersection rectangle
inter_rect_x1 = torch.max(b1_x1, b2_x1)
inter_rect_y1 = torch.max(b1_y1, b2_y1)
inter_rect_x2 = torch.min(b1_x2, b2_x2)
inter_rect_y2 = torch.min(b1_y2, b2_y2)
# Intersection area
inter_area = torch.clamp(inter_rect_x2 - inter_rect_x1, 0) * torch.clamp(inter_rect_y2 - inter_rect_y1, 0)
# Union Area
b1_area = (b1_x2 - b1_x1) * (b1_y2 - b1_y1)
b2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1)
# print(box1, box1.shape)
# print(box2, box2.shape)
return inter_area / (b1_area + b2_area - inter_area + 1e-16)
def multiclass_metrics(pred, gt):
"""
check precision and recall for predictions.
Output: overall = {precision, recall, f1}
"""
eps=1e-6
overall = {'precision': -1, 'recall': -1, 'f1': -1}
NP, NR, NC = 0, 0, 0 # num of pred, num of recall, num of correct
for ii in range(pred.shape[0]):
pred_ind = np.array(pred[ii]>0.5, dtype=int)
gt_ind = np.array(gt[ii]>0.5, dtype=int)
inter = pred_ind * gt_ind
# add to overall
NC += np.sum(inter)
NP += np.sum(pred_ind)
NR += np.sum(gt_ind)
if NP > 0:
overall['precision'] = float(NC)/NP
if NR > 0:
overall['recall'] = float(NC)/NR
if NP > 0 and NR > 0:
overall['f1'] = 2*overall['precision']*overall['recall']/(overall['precision']+overall['recall']+eps)
return overall
def compute_ap(recall, precision):
""" Compute the average precision, given the recall and precision curves.
Code originally from https://github.com/rbgirshick/py-faster-rcnn.
# Arguments
recall: The recall curve (list).
precision: The precision curve (list).
# Returns
The average precision as computed in py-faster-rcnn.
"""
# correct AP calculation
# first append sentinel values at the end
mrec = np.concatenate(([0.0], recall, [1.0]))
mpre = np.concatenate(([0.0], precision, [0.0]))
# compute the precision envelope
for i in range(mpre.size - 1, 0, -1):
mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
# to calculate area under PR curve, look for points
# where X axis (recall) changes value
i = np.where(mrec[1:] != mrec[:-1])[0]
# and sum (\Delta recall) * prec
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap
def concat_coord(x):
ins_feat = x # [bt, c, h, w] [512, 26, 26]
batch_size, c, h, w = x.size()
float_h = float(h)
float_w = float(w)
y_range = torch.arange(0., float_h, dtype=torch.float32) # [h, ]
y_range = 2.0 * y_range / (float_h - 1.0) - 1.0
x_range = torch.arange(0., float_w, dtype=torch.float32) # [w, ]
x_range = 2.0 * x_range / (float_w - 1.0) - 1.0
x_range = x_range[None, :] # [1, w]
y_range = y_range[:, None] # [h, 1]
x = x_range.repeat(h, 1) # [h, w]
y = y_range.repeat(1, w) # [h, w]
x = x[None, None, :, :] # [1, 1, h, w]
y = y[None, None, :, :] # [1, 1, h, w]
x = x.repeat(batch_size, 1, 1, 1) # [N, 1, h, w]
y = y.repeat(batch_size, 1, 1, 1) # [N, 1, h, w]
x = x.cuda()
y = y.cuda()
ins_feat_out = torch.cat((ins_feat, x, x, x, y, y, y), 1) # [N, c+6, h, w]
return ins_feat_out
def get_cosine_schedule_with_warmup(optimizer: Optimizer, num_warmup_steps: int, num_training_steps: int,
num_cycles: float = 0.5, last_epoch: int = -1):
"""
Implementation by Huggingface:
https://github.com/huggingface/transformers/blob/v4.16.2/src/transformers/optimization.py
Create a schedule with a learning rate that decreases following the values
of the cosine function between the initial lr set in the optimizer to 0,
after a warmup period during which it increases linearly between 0 and the
initial lr set in the optimizer.
Args:
optimizer ([`~torch.optim.Optimizer`]):
The optimizer for which to schedule the learning rate.
num_warmup_steps (`int`):
The number of steps for the warmup phase.
num_training_steps (`int`):
The total number of training steps.
num_cycles (`float`, *optional*, defaults to 0.5):
The number of waves in the cosine schedule (the defaults is to just
decrease from the max value to 0 following a half-cosine).
last_epoch (`int`, *optional*, defaults to -1):
The index of the last epoch when resuming training.
Return:
`torch.optim.lr_scheduler.LambdaLR` with the appropriate schedule.
"""
def lr_lambda(current_step):
if current_step < num_warmup_steps:
return max(1e-6, float(current_step) / float(max(1, num_warmup_steps)))
progress = float(current_step - num_warmup_steps) / float(max(1, num_training_steps - num_warmup_steps))
return max(0.0, 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)))
return optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch)
def dice_loss(inputs, targets):
"""
Compute the DICE loss, similar to generalized IOU for masks
Args:
inputs: A float tensor of arbitrary shape.
The predictions for each example.
targets: A float tensor with the same shape as inputs. Stores the binary
classification label for each element in inputs
(0 for the negative class and 1 for the positive class).
"""
inputs = inputs.sigmoid()
inputs = inputs.flatten(1)
targets = targets.flatten(1)
numerator = 2 * (inputs * targets).sum(1)
denominator = inputs.sum(-1) + targets.sum(-1)
loss = 1 - (numerator + 1) / (denominator + 1)
return loss.mean()
def sigmoid_focal_loss(inputs, targets, alpha: float = -1, gamma: float = 0):
"""
Loss used in RetinaNet for dense detection: https://arxiv.org/abs/1708.02002.
Args:
inputs: A float tensor of arbitrary shape.
The predictions for each example.
targets: A float tensor with the same shape as inputs. Stores the binary
classification label for each element in inputs
(0 for the negative class and 1 for the positive class).
alpha: (optional) Weighting factor in range (0,1) to balance
positive vs negative examples. Default = -1 (no weighting).
gamma: Exponent of the modulating factor (1 - p_t) to
balance easy vs hard examples.
Returns:
Loss tensor
"""
prob = inputs.sigmoid()
ce_loss = F.binary_cross_entropy_with_logits(inputs, targets, reduction="none")
p_t = prob * targets + (1 - prob) * (1 - targets)
loss = ce_loss * ((1 - p_t) ** gamma)
if alpha >= 0:
alpha_t = alpha * targets + (1 - alpha) * (1 - targets)
loss = alpha_t * loss
return loss.mean()