Spaces:
Sleeping
Sleeping
| import torch | |
| import numpy as np | |
| from torch.nn import functional as F | |
| from lib.fpn.box_intersections_cpu.bbox import bbox_overlaps as bbox_overlaps_np | |
| from lib.fpn.box_intersections_cpu.bbox import bbox_intersections as bbox_intersections_np | |
| def bbox_loss(prior_boxes, deltas, gt_boxes, eps=1e-4, scale_before=1): | |
| """ | |
| Computes the loss for predicting the GT boxes from prior boxes | |
| :param prior_boxes: [num_boxes, 4] (x1, y1, x2, y2) | |
| :param deltas: [num_boxes, 4] (tx, ty, th, tw) | |
| :param gt_boxes: [num_boxes, 4] (x1, y1, x2, y2) | |
| :return: | |
| """ | |
| prior_centers = center_size(prior_boxes) #(cx, cy, w, h) | |
| gt_centers = center_size(gt_boxes) #(cx, cy, w, h) | |
| center_targets = (gt_centers[:, :2] - prior_centers[:, :2]) / prior_centers[:, 2:] | |
| size_targets = torch.log(gt_centers[:, 2:]) - torch.log(prior_centers[:, 2:]) | |
| all_targets = torch.cat((center_targets, size_targets), 1) | |
| loss = F.smooth_l1_loss(deltas, all_targets, size_average=False)/(eps + prior_centers.size(0)) | |
| return loss | |
| def bbox_preds(boxes, deltas): | |
| """ | |
| Converts "deltas" (predicted by the network) along with prior boxes | |
| into (x1, y1, x2, y2) representation. | |
| :param boxes: Prior boxes, represented as (x1, y1, x2, y2) | |
| :param deltas: Offsets (tx, ty, tw, th) | |
| :param box_strides [num_boxes,] distance apart between boxes. anchor box can't go more than | |
| \pm box_strides/2.0 from its current position. If None then we'll use the widths | |
| and heights | |
| :return: Transformed boxes | |
| """ | |
| if boxes.size(0) == 0: | |
| return boxes | |
| prior_centers = center_size(boxes) | |
| xys = prior_centers[:, :2] + prior_centers[:, 2:] * deltas[:, :2] | |
| whs = torch.exp(deltas[:, 2:]) * prior_centers[:, 2:] | |
| return point_form(torch.cat((xys, whs), 1)) | |
| def center_size(boxes): | |
| """ Convert prior_boxes to (cx, cy, w, h) | |
| representation for comparison to center-size form ground truth data. | |
| Args: | |
| boxes: (tensor) point_form boxes | |
| Return: | |
| boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. | |
| """ | |
| wh = boxes[:, 2:] - boxes[:, :2] + 1.0 | |
| if isinstance(boxes, np.ndarray): | |
| return np.column_stack((boxes[:, :2] + 0.5 * wh, wh)) | |
| return torch.cat((boxes[:, :2] + 0.5 * wh, wh), 1) | |
| def point_form(boxes): | |
| """ Convert prior_boxes to (xmin, ymin, xmax, ymax) | |
| representation for comparison to point form ground truth data. | |
| Args: | |
| boxes: (tensor) center-size default boxes from priorbox layers. | |
| Return: | |
| boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes. | |
| """ | |
| if isinstance(boxes, np.ndarray): | |
| return np.column_stack((boxes[:, :2] - 0.5 * boxes[:, 2:], | |
| boxes[:, :2] + 0.5 * (boxes[:, 2:] - 2.0))) | |
| return torch.cat((boxes[:, :2] - 0.5 * boxes[:, 2:], | |
| boxes[:, :2] + 0.5 * (boxes[:, 2:] - 2.0)), 1) # xmax, ymax | |
| ########################################################################### | |
| ### Torch Utils, creds to Max de Groot | |
| ########################################################################### | |
| def bbox_intersections(box_a, box_b): | |
| """ We resize both tensors to [A,B,2.0] without new malloc: | |
| [A,2.0] -> [A,ĺeftright,2.0] -> [A,B,2.0] | |
| [B,2.0] -> [ĺeftright,B,2.0] -> [A,B,2.0] | |
| Then we compute the area of intersect between box_a and box_b. | |
| Args: | |
| box_a: (tensor) bounding boxes, Shape: [A,4]. | |
| box_b: (tensor) bounding boxes, Shape: [B,4]. | |
| Return: | |
| (tensor) intersection area, Shape: [A,B]. | |
| """ | |
| if isinstance(box_a, np.ndarray): | |
| assert isinstance(box_b, np.ndarray) | |
| return bbox_intersections_np(box_a, box_b) | |
| A = box_a.size(0) | |
| B = box_b.size(0) | |
| max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2), | |
| box_b[:, 2:].unsqueeze(0).expand(A, B, 2)) | |
| min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2), | |
| box_b[:, :2].unsqueeze(0).expand(A, B, 2)) | |
| inter = torch.clamp((max_xy - min_xy + 1.0), min=0) | |
| return inter[:, :, 0] * inter[:, :, 1] | |
| def bbox_overlaps(box_a, box_b): | |
| """Compute the jaccard overlap of two sets of boxes. The jaccard overlap | |
| is simply the intersection over union of two boxes. Here we operate on | |
| ground truth boxes and default boxes. | |
| E.g.: | |
| A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B) | |
| Args: | |
| box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4] | |
| box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4] | |
| Return: | |
| jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)] | |
| """ | |
| if isinstance(box_a, np.ndarray): | |
| assert isinstance(box_b, np.ndarray) | |
| return bbox_overlaps_np(box_a, box_b) | |
| inter = bbox_intersections(box_a, box_b) | |
| area_a = ((box_a[:, 2] - box_a[:, 0] + 1.0) * | |
| (box_a[:, 3] - box_a[:, 1] + 1.0)).unsqueeze(1).expand_as(inter) # [A,B] | |
| area_b = ((box_b[:, 2] - box_b[:, 0] + 1.0) * | |
| (box_b[:, 3] - box_b[:, 1] + 1.0)).unsqueeze(0).expand_as(inter) # [A,B] | |
| union = area_a + area_b - inter | |
| return inter / union # [A,B] | |
| def nms_overlaps(boxes): | |
| """ get overlaps for each channel""" | |
| assert boxes.dim() == 3 | |
| N = boxes.size(0) | |
| nc = boxes.size(1) | |
| max_xy = torch.min(boxes[:, None, :, 2:].expand(N, N, nc, 2), | |
| boxes[None, :, :, 2:].expand(N, N, nc, 2)) | |
| min_xy = torch.max(boxes[:, None, :, :2].expand(N, N, nc, 2), | |
| boxes[None, :, :, :2].expand(N, N, nc, 2)) | |
| inter = torch.clamp((max_xy - min_xy + 1.0), min=0) | |
| # n, n, 151 | |
| inters = inter[:,:,:,0]*inter[:,:,:,1] | |
| boxes_flat = boxes.view(-1, 4) | |
| areas_flat = (boxes_flat[:,2]- boxes_flat[:,0]+1.0)*( | |
| boxes_flat[:,3]- boxes_flat[:,1]+1.0) | |
| areas = areas_flat.view(boxes.size(0), boxes.size(1)) | |
| union = -inters + areas[None] + areas[:, None] | |
| return inters / union | |