first commit
This commit is contained in:
commit
54ccfb11fe
218 files changed
+19525
No files matched your search
Executable
+138
@@ -0,0 +1,138 @@
|
||||
import torch
|
||||
import math
|
||||
|
||||
|
||||
def convert_locations_to_boxes(locations, priors, center_variance,
|
||||
size_variance):
|
||||
"""Convert regressional location results of SSD into boxes in the form of (center_x, center_y, h, w).
|
||||
|
||||
The conversion:
|
||||
$$predicted\_center * center_variance = \frac {real\_center - prior\_center} {prior\_hw}$$
|
||||
$$exp(predicted\_hw * size_variance) = \frac {real\_hw} {prior\_hw}$$
|
||||
We do it in the inverse direction here.
|
||||
Args:
|
||||
locations (batch_size, num_priors, 4): the regression output of SSD. It will contain the outputs as well.
|
||||
priors (num_priors, 4) or (batch_size/1, num_priors, 4): prior boxes.
|
||||
center_variance: a float used to change the scale of center.
|
||||
size_variance: a float used to change of scale of size.
|
||||
Returns:
|
||||
boxes: priors: [[center_x, center_y, w, h]]. All the values
|
||||
are relative to the image size.
|
||||
"""
|
||||
# priors can have one dimension less.
|
||||
if priors.dim() + 1 == locations.dim():
|
||||
priors = priors.unsqueeze(0)
|
||||
return torch.cat([
|
||||
locations[..., :2] * center_variance * priors[..., 2:] + priors[..., :2],
|
||||
torch.exp(locations[..., 2:] * size_variance) * priors[..., 2:]
|
||||
], dim=locations.dim() - 1)
|
||||
|
||||
|
||||
def convert_boxes_to_locations(center_form_boxes, center_form_priors, center_variance, size_variance):
|
||||
# priors can have one dimension less
|
||||
if center_form_priors.dim() + 1 == center_form_boxes.dim():
|
||||
center_form_priors = center_form_priors.unsqueeze(0)
|
||||
return torch.cat([
|
||||
(center_form_boxes[..., :2] - center_form_priors[..., :2]) / center_form_priors[..., 2:] / center_variance,
|
||||
torch.log(center_form_boxes[..., 2:] / center_form_priors[..., 2:]) / size_variance
|
||||
], dim=center_form_boxes.dim() - 1)
|
||||
|
||||
|
||||
def area_of(left_top, right_bottom) -> torch.Tensor:
|
||||
"""Compute the areas of rectangles given two corners.
|
||||
|
||||
Args:
|
||||
left_top (N, 2): left top corner.
|
||||
right_bottom (N, 2): right bottom corner.
|
||||
|
||||
Returns:
|
||||
area (N): return the area.
|
||||
"""
|
||||
hw = torch.clamp(right_bottom - left_top, min=0.0)
|
||||
return hw[..., 0] * hw[..., 1]
|
||||
|
||||
|
||||
def iou_of(boxes0, boxes1, eps=1e-5):
|
||||
"""Return intersection-over-union (Jaccard index) of boxes.
|
||||
|
||||
Args:
|
||||
boxes0 (N, 4): ground truth boxes.
|
||||
boxes1 (N or 1, 4): predicted boxes.
|
||||
eps: a small number to avoid 0 as denominator.
|
||||
Returns:
|
||||
iou (N): IoU values.
|
||||
"""
|
||||
overlap_left_top = torch.max(boxes0[..., :2], boxes1[..., :2])
|
||||
overlap_right_bottom = torch.min(boxes0[..., 2:], boxes1[..., 2:])
|
||||
|
||||
overlap_area = area_of(overlap_left_top, overlap_right_bottom)
|
||||
area0 = area_of(boxes0[..., :2], boxes0[..., 2:])
|
||||
area1 = area_of(boxes1[..., :2], boxes1[..., 2:])
|
||||
return overlap_area / (area0 + area1 - overlap_area + eps)
|
||||
|
||||
|
||||
def assign_priors(gt_boxes, gt_labels, corner_form_priors,
|
||||
iou_threshold):
|
||||
"""Assign ground truth boxes and targets to priors.
|
||||
|
||||
Args:
|
||||
gt_boxes (num_targets, 4): ground truth boxes.
|
||||
gt_labels (num_targets): labels of targets.
|
||||
priors (num_priors, 4): corner form priors
|
||||
Returns:
|
||||
boxes (num_priors, 4): real values for priors.
|
||||
labels (num_priros): labels for priors.
|
||||
"""
|
||||
# size: num_priors x num_targets
|
||||
ious = iou_of(gt_boxes.unsqueeze(0), corner_form_priors.unsqueeze(1))
|
||||
# size: num_priors
|
||||
best_target_per_prior, best_target_per_prior_index = ious.max(1)
|
||||
# size: num_targets
|
||||
best_prior_per_target, best_prior_per_target_index = ious.max(0)
|
||||
|
||||
for target_index, prior_index in enumerate(best_prior_per_target_index):
|
||||
best_target_per_prior_index[prior_index] = target_index
|
||||
# 2.0 is used to make sure every target has a prior assigned
|
||||
best_target_per_prior.index_fill_(0, best_prior_per_target_index, 2)
|
||||
# size: num_priors
|
||||
labels = gt_labels[best_target_per_prior_index]
|
||||
labels[best_target_per_prior < iou_threshold] = 0 # the backgournd id
|
||||
boxes = gt_boxes[best_target_per_prior_index]
|
||||
return boxes, labels
|
||||
|
||||
|
||||
def hard_negative_mining(loss, labels, neg_pos_ratio):
|
||||
"""
|
||||
It used to suppress the presence of a large number of negative prediction.
|
||||
It works on image level not batch level.
|
||||
For any example/image, it keeps all the positive predictions and
|
||||
cut the number of negative predictions to make sure the ratio
|
||||
between the negative examples and positive examples is no more
|
||||
the given ratio for an image.
|
||||
|
||||
Args:
|
||||
loss (N, num_priors): the loss for each example.
|
||||
labels (N, num_priors): the labels.
|
||||
neg_pos_ratio: the ratio between the negative examples and positive examples.
|
||||
"""
|
||||
pos_mask = labels > 0
|
||||
num_pos = pos_mask.long().sum(dim=1, keepdim=True)
|
||||
num_neg = num_pos * neg_pos_ratio
|
||||
|
||||
loss[pos_mask] = -math.inf
|
||||
_, indexes = loss.sort(dim=1, descending=True)
|
||||
_, orders = indexes.sort(dim=1)
|
||||
neg_mask = orders < num_neg
|
||||
return pos_mask | neg_mask
|
||||
|
||||
|
||||
def center_form_to_corner_form(locations):
|
||||
return torch.cat([locations[..., :2] - locations[..., 2:] / 2,
|
||||
locations[..., :2] + locations[..., 2:] / 2], locations.dim() - 1)
|
||||
|
||||
|
||||
def corner_form_to_center_form(boxes):
|
||||
return torch.cat([
|
||||
(boxes[..., :2] + boxes[..., 2:]) / 2,
|
||||
boxes[..., 2:] - boxes[..., :2]
|
||||
], boxes.dim() - 1)
|
||||
Reference in new issue
Block a user