forked from IQ.Lvbs/IQ.Pilot
IQ.Pilot Release Commit @ f2a861c
This commit is contained in:
89
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/coco_utils.py
vendored
Normal file
89
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/coco_utils.py
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/coco_utils.py
|
||||
|
||||
import os
|
||||
import torch
|
||||
import torchvision
|
||||
|
||||
from test.external.mlperf_retinanet import transforms as T
|
||||
|
||||
class ConvertCocoPolysToMask(object):
|
||||
def __init__(self, filter_iscrowd=True):
|
||||
self.filter_iscrowd = filter_iscrowd
|
||||
|
||||
def __call__(self, image, target):
|
||||
w, h = image.size
|
||||
|
||||
image_id = target["image_id"]
|
||||
image_id = torch.tensor([image_id])
|
||||
|
||||
anno = target["annotations"]
|
||||
|
||||
if self.filter_iscrowd:
|
||||
anno = [obj for obj in anno if obj['iscrowd'] == 0]
|
||||
|
||||
boxes = [obj["bbox"] for obj in anno]
|
||||
# guard against no boxes via resizing
|
||||
boxes = torch.as_tensor(boxes, dtype=torch.float32).reshape(-1, 4)
|
||||
boxes[:, 2:] += boxes[:, :2]
|
||||
boxes[:, 0::2].clamp_(min=0, max=w)
|
||||
boxes[:, 1::2].clamp_(min=0, max=h)
|
||||
|
||||
classes = [obj["category_id"] for obj in anno]
|
||||
classes = torch.tensor(classes, dtype=torch.int64)
|
||||
|
||||
keypoints = None
|
||||
if anno and "keypoints" in anno[0]:
|
||||
keypoints = [obj["keypoints"] for obj in anno]
|
||||
keypoints = torch.as_tensor(keypoints, dtype=torch.float32)
|
||||
num_keypoints = keypoints.shape[0]
|
||||
if num_keypoints:
|
||||
keypoints = keypoints.view(num_keypoints, -1, 3)
|
||||
|
||||
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
|
||||
boxes = boxes[keep]
|
||||
classes = classes[keep]
|
||||
|
||||
target = {}
|
||||
target["boxes"] = boxes
|
||||
target["labels"] = classes
|
||||
target["image_id"] = image_id
|
||||
|
||||
# for conversion to coco api
|
||||
area = torch.tensor([obj["area"] for obj in anno])
|
||||
iscrowd = torch.tensor([obj["iscrowd"] for obj in anno])
|
||||
target["area"] = area
|
||||
target["iscrowd"] = iscrowd
|
||||
|
||||
return image, target
|
||||
|
||||
class CocoDetection(torchvision.datasets.CocoDetection):
|
||||
def __init__(self, img_folder, ann_file, transforms):
|
||||
super(CocoDetection, self).__init__(img_folder, ann_file)
|
||||
self._transforms = transforms
|
||||
|
||||
def __getitem__(self, idx):
|
||||
img, target = super(CocoDetection, self).__getitem__(idx)
|
||||
image_id = self.ids[idx]
|
||||
target = dict(image_id=image_id, annotations=target)
|
||||
if self._transforms is not None:
|
||||
img, target = self._transforms(img, target)
|
||||
return img, target
|
||||
|
||||
def get_openimages(name, root, image_set, transforms):
|
||||
PATHS = {
|
||||
"train": os.path.join(root, "train"),
|
||||
"val": os.path.join(root, "validation"),
|
||||
}
|
||||
|
||||
t = [ConvertCocoPolysToMask(filter_iscrowd=False)]
|
||||
|
||||
if transforms is not None:
|
||||
t.append(transforms)
|
||||
transforms = T.Compose(t)
|
||||
|
||||
img_folder = os.path.join(PATHS[image_set], "data")
|
||||
ann_file = os.path.join(PATHS[image_set], "labels", f"{name}.json")
|
||||
|
||||
dataset = CocoDetection(img_folder, ann_file, transforms=transforms)
|
||||
|
||||
return dataset
|
||||
51
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/focal_loss.py
vendored
Normal file
51
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/focal_loss.py
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/cdd928d4596c142c15a7d86b2eeadbac718c8da2/single_stage_detector/ssd/model/focal_loss.py
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
def sigmoid_focal_loss(
|
||||
inputs: torch.Tensor,
|
||||
targets: torch.Tensor,
|
||||
alpha: float = 0.25,
|
||||
gamma: float = 2,
|
||||
reduction: str = "none",
|
||||
):
|
||||
"""
|
||||
Original implementation from https://github.com/facebookresearch/fvcore/blob/master/fvcore/nn/focal_loss.py .
|
||||
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 or -1 for ignore. Default = 0.25
|
||||
gamma: Exponent of the modulating factor (1 - p_t) to
|
||||
balance easy vs hard examples.
|
||||
reduction: 'none' | 'mean' | 'sum'
|
||||
'none': No reduction will be applied to the output.
|
||||
'mean': The output will be averaged.
|
||||
'sum': The output will be summed.
|
||||
Returns:
|
||||
Loss tensor with the reduction option applied.
|
||||
"""
|
||||
p = torch.sigmoid(inputs)
|
||||
ce_loss = F.binary_cross_entropy_with_logits(
|
||||
inputs, targets, reduction="none"
|
||||
)
|
||||
p_t = p * targets + (1 - p) * (1 - targets)
|
||||
loss = ce_loss * ((1 - p_t) ** gamma)
|
||||
|
||||
if alpha >= 0:
|
||||
alpha_t = alpha * targets + (1 - alpha) * (1 - targets)
|
||||
loss = alpha_t * loss
|
||||
|
||||
if reduction == "mean":
|
||||
loss = loss.mean()
|
||||
elif reduction == "sum":
|
||||
loss = loss.sum()
|
||||
|
||||
return loss
|
||||
65
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/boxes.py
vendored
Normal file
65
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/boxes.py
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/model/boxes.py
|
||||
|
||||
import torch
|
||||
from torch import Tensor
|
||||
from typing import Tuple
|
||||
|
||||
def _upcast(t: Tensor) -> Tensor:
|
||||
# Protects from numerical overflows in multiplications by upcasting to the equivalent higher type
|
||||
if t.is_floating_point():
|
||||
return t if t.dtype in (torch.float32, torch.float64) else t.float()
|
||||
else:
|
||||
return t if t.dtype in (torch.int32, torch.int64) else t.int()
|
||||
|
||||
|
||||
def box_area(boxes: Tensor) -> Tensor:
|
||||
"""
|
||||
Computes the area of a set of bounding boxes, which are specified by their
|
||||
(x1, y1, x2, y2) coordinates.
|
||||
|
||||
Args:
|
||||
boxes (Tensor[N, 4]): boxes for which the area will be computed. They
|
||||
are expected to be in (x1, y1, x2, y2) format with
|
||||
``0 <= x1 < x2`` and ``0 <= y1 < y2``.
|
||||
|
||||
Returns:
|
||||
Tensor[N]: the area for each box
|
||||
"""
|
||||
boxes = _upcast(boxes)
|
||||
return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
|
||||
|
||||
|
||||
# implementation from https://github.com/kuangliu/torchcv/blob/master/torchcv/utils/box.py
|
||||
# with slight modifications
|
||||
def _box_inter_union(boxes1: Tensor, boxes2: Tensor) -> Tuple[Tensor, Tensor]:
|
||||
area1 = box_area(boxes1)
|
||||
area2 = box_area(boxes2)
|
||||
|
||||
lt = torch.max(boxes1[:, None, :2], boxes2[:, :2]) # [N,M,2]
|
||||
rb = torch.min(boxes1[:, None, 2:], boxes2[:, 2:]) # [N,M,2]
|
||||
|
||||
wh = _upcast(rb - lt).clamp(min=0) # [N,M,2]
|
||||
inter = wh[:, :, 0] * wh[:, :, 1] # [N,M]
|
||||
|
||||
union = area1[:, None] + area2 - inter
|
||||
|
||||
return inter, union
|
||||
|
||||
|
||||
def box_iou(boxes1: Tensor, boxes2: Tensor) -> Tensor:
|
||||
"""
|
||||
Return intersection-over-union (Jaccard index) between two sets of boxes.
|
||||
|
||||
Both sets of boxes are expected to be in ``(x1, y1, x2, y2)`` format with
|
||||
``0 <= x1 < x2`` and ``0 <= y1 < y2``.
|
||||
|
||||
Args:
|
||||
boxes1 (Tensor[N, 4]): first set of boxes
|
||||
boxes2 (Tensor[M, 4]): second set of boxes
|
||||
|
||||
Returns:
|
||||
Tensor[N, M]: the NxM matrix containing the pairwise IoU values for every element in boxes1 and boxes2
|
||||
"""
|
||||
inter, union = _box_inter_union(boxes1, boxes2)
|
||||
iou = inter / union
|
||||
return iou
|
||||
27
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/image_list.py
vendored
Normal file
27
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/image_list.py
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/model/image_list.py
|
||||
|
||||
import torch
|
||||
from torch import Tensor
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
class ImageList(object):
|
||||
"""
|
||||
Structure that holds a list of images (of possibly
|
||||
varying sizes) as a single tensor.
|
||||
This works by padding the images to the same size,
|
||||
and storing in a field the original sizes of each image
|
||||
"""
|
||||
|
||||
def __init__(self, tensors: Tensor, image_sizes: List[Tuple[int, int]]):
|
||||
"""
|
||||
Args:
|
||||
tensors (tensor)
|
||||
image_sizes (list[tuple[int, int]])
|
||||
"""
|
||||
self.tensors = tensors
|
||||
self.image_sizes = image_sizes
|
||||
|
||||
def to(self, device: torch.device) -> 'ImageList':
|
||||
cast_tensor = self.tensors.to(device)
|
||||
return ImageList(cast_tensor, self.image_sizes)
|
||||
163
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/transform.py
vendored
Normal file
163
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/transform.py
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/model/transform.py
|
||||
|
||||
import torch
|
||||
|
||||
from torch import nn, Tensor
|
||||
from typing import List, Tuple, Dict, Optional
|
||||
|
||||
from test.external.mlperf_retinanet.model.image_list import ImageList
|
||||
|
||||
@torch.jit.unused
|
||||
def _get_shape_onnx(image: Tensor) -> Tensor:
|
||||
from torch.onnx import operators
|
||||
return operators.shape_as_tensor(image)[-2:]
|
||||
|
||||
def _resize_image_and_masks(image: Tensor,
|
||||
target: Optional[Dict[str, Tensor]] = None,
|
||||
image_size: Optional[Tuple[int, int]] = None,
|
||||
) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]:
|
||||
image = torch.nn.functional.interpolate(image[None], size=image_size, scale_factor=None, mode='bilinear',
|
||||
recompute_scale_factor=None, align_corners=False)[0]
|
||||
|
||||
if target is None:
|
||||
return image, target
|
||||
|
||||
if "masks" in target:
|
||||
mask = target["masks"]
|
||||
mask = torch.nn.functional.interpolate(mask[:, None].float(), size=image_size, scale_factor=None,
|
||||
recompute_scale_factor=None)[:, 0].byte()
|
||||
target["masks"] = mask
|
||||
return image, target
|
||||
|
||||
class GeneralizedRCNNTransform(nn.Module):
|
||||
"""
|
||||
Performs input / target transformation before feeding the data to a GeneralizedRCNN
|
||||
model.
|
||||
|
||||
The transformations it perform are:
|
||||
- input normalization (mean subtraction and std division)
|
||||
- input / target resizing to match image_size
|
||||
|
||||
It returns a ImageList for the inputs, and a List[Dict[Tensor]] for the targets
|
||||
"""
|
||||
|
||||
def __init__(self, image_size: Optional[Tuple[int, int]],
|
||||
image_mean: List[float], image_std: List[float],):
|
||||
super(GeneralizedRCNNTransform, self).__init__()
|
||||
self.image_size = image_size
|
||||
self.image_mean = image_mean
|
||||
self.image_std = image_std
|
||||
|
||||
def forward(self,
|
||||
images: List[Tensor],
|
||||
targets: Optional[List[Dict[str, Tensor]]] = None
|
||||
) -> Tuple[ImageList, Optional[List[Dict[str, Tensor]]]]:
|
||||
images = list(img for img in images)
|
||||
if targets is not None:
|
||||
# make a copy of targets to avoid modifying it in-place
|
||||
# once torchscript supports dict comprehension
|
||||
# this can be simplified as follows
|
||||
# targets = [{k: v for k,v in t.items()} for t in targets]
|
||||
targets_copy: List[Dict[str, Tensor]] = []
|
||||
for t in targets:
|
||||
data: Dict[str, Tensor] = {}
|
||||
for k, v in t.items():
|
||||
data[k] = v
|
||||
targets_copy.append(data)
|
||||
targets = targets_copy
|
||||
for i in range(len(images)):
|
||||
image = images[i]
|
||||
target_index = targets[i] if targets is not None else None
|
||||
|
||||
if image.dim() != 3:
|
||||
raise ValueError("images is expected to be a list of 3d tensors "
|
||||
"of shape [C, H, W], got {}".format(image.shape))
|
||||
image = self.normalize(image)
|
||||
image, target_index = self.resize(image, target_index)
|
||||
images[i] = image
|
||||
if targets is not None and target_index is not None:
|
||||
targets[i] = target_index
|
||||
|
||||
image_sizes = [img.shape[-2:] for img in images]
|
||||
images = torch.stack(images)
|
||||
image_sizes_list: List[Tuple[int, int]] = []
|
||||
for image_size in image_sizes:
|
||||
assert len(image_size) == 2
|
||||
image_sizes_list.append((image_size[0], image_size[1]))
|
||||
|
||||
image_list = ImageList(images, image_sizes_list)
|
||||
return image_list, targets
|
||||
|
||||
def normalize(self, image: Tensor) -> Tensor:
|
||||
if not image.is_floating_point():
|
||||
raise TypeError(
|
||||
f"Expected input images to be of floating type (in range [0, 1]), "
|
||||
f"but found type {image.dtype} instead"
|
||||
)
|
||||
dtype, device = image.dtype, image.device
|
||||
mean = torch.as_tensor(self.image_mean, dtype=dtype, device=device)
|
||||
std = torch.as_tensor(self.image_std, dtype=dtype, device=device)
|
||||
return (image - mean[:, None, None]) / std[:, None, None]
|
||||
|
||||
def torch_choice(self, k: List[int]) -> int:
|
||||
"""
|
||||
Implements `random.choice` via torch ops so it can be compiled with
|
||||
TorchScript. Remove if https://github.com/pytorch/pytorch/issues/25803
|
||||
is fixed.
|
||||
"""
|
||||
index = int(torch.empty(1).uniform_(0., float(len(k))).item())
|
||||
return k[index]
|
||||
|
||||
def resize(self,
|
||||
image: Tensor,
|
||||
target: Optional[Dict[str, Tensor]] = None,
|
||||
) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]:
|
||||
h, w = image.shape[-2:]
|
||||
image, target = _resize_image_and_masks(image, target, self.image_size)
|
||||
|
||||
if target is None:
|
||||
return image, target
|
||||
|
||||
bbox = target["boxes"]
|
||||
bbox = resize_boxes(bbox, (h, w), image.shape[-2:])
|
||||
target["boxes"] = bbox
|
||||
|
||||
return image, target
|
||||
|
||||
def postprocess(self,
|
||||
result: List[Dict[str, Tensor]],
|
||||
image_shapes: List[Tuple[int, int]],
|
||||
original_image_sizes: List[Tuple[int, int]]
|
||||
) -> List[Dict[str, Tensor]]:
|
||||
if self.training:
|
||||
return result
|
||||
for i, (pred, im_s, o_im_s) in enumerate(zip(result, image_shapes, original_image_sizes)):
|
||||
boxes = pred["boxes"]
|
||||
boxes = resize_boxes(boxes, im_s, o_im_s)
|
||||
result[i]["boxes"] = boxes
|
||||
return result
|
||||
|
||||
def __repr__(self) -> str:
|
||||
format_string = self.__class__.__name__ + '('
|
||||
_indent = '\n '
|
||||
format_string += "{0}Normalize(mean={1}, std={2})".format(_indent, self.image_mean, self.image_std)
|
||||
format_string += "{0}Resize(height={1}, width={2}, mode='bilinear')".format(_indent, self.image_size[0],
|
||||
self.image_size[1])
|
||||
format_string += '\n)'
|
||||
return format_string
|
||||
|
||||
def resize_boxes(boxes: Tensor, original_size: List[int], new_size: List[int]) -> Tensor:
|
||||
ratios = [
|
||||
torch.tensor(s, dtype=torch.float32, device=boxes.device) /
|
||||
torch.tensor(s_orig, dtype=torch.float32, device=boxes.device)
|
||||
for s, s_orig in zip(new_size, original_size)
|
||||
]
|
||||
ratio_height, ratio_width = ratios
|
||||
xmin, ymin, xmax, ymax = boxes.unbind(1)
|
||||
|
||||
xmin = xmin * ratio_width
|
||||
xmax = xmax * ratio_width
|
||||
ymin = ymin * ratio_height
|
||||
ymax = ymax * ratio_height
|
||||
res = torch.stack((xmin, ymin, xmax, ymax), dim=1)
|
||||
return res
|
||||
123
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/utils.py
vendored
Normal file
123
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/model/utils.py
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/model/utils.py
|
||||
|
||||
import torch
|
||||
|
||||
class Matcher(object):
|
||||
"""
|
||||
This class assigns to each predicted "element" (e.g., a box) a ground-truth
|
||||
element. Each predicted element will have exactly zero or one matches; each
|
||||
ground-truth element may be assigned to zero or more predicted elements.
|
||||
|
||||
Matching is based on the MxN match_quality_matrix, that characterizes how well
|
||||
each (ground-truth, predicted)-pair match. For example, if the elements are
|
||||
boxes, the matrix may contain box IoU overlap values.
|
||||
|
||||
The matcher returns a tensor of size N containing the index of the ground-truth
|
||||
element m that matches to prediction n. If there is no match, a negative value
|
||||
is returned.
|
||||
"""
|
||||
|
||||
BELOW_LOW_THRESHOLD = -1
|
||||
BETWEEN_THRESHOLDS = -2
|
||||
|
||||
__annotations__ = {
|
||||
'BELOW_LOW_THRESHOLD': int,
|
||||
'BETWEEN_THRESHOLDS': int,
|
||||
}
|
||||
|
||||
def __init__(self, high_threshold, low_threshold, allow_low_quality_matches=False):
|
||||
# type: (float, float, bool) -> None
|
||||
"""
|
||||
Args:
|
||||
high_threshold (float): quality values greater than or equal to
|
||||
this value are candidate matches.
|
||||
low_threshold (float): a lower quality threshold used to stratify
|
||||
matches into three levels:
|
||||
1) matches >= high_threshold
|
||||
2) BETWEEN_THRESHOLDS matches in [low_threshold, high_threshold)
|
||||
3) BELOW_LOW_THRESHOLD matches in [0, low_threshold)
|
||||
allow_low_quality_matches (bool): if True, produce additional matches
|
||||
for predictions that have only low-quality match candidates. See
|
||||
set_low_quality_matches_ for more details.
|
||||
"""
|
||||
self.BELOW_LOW_THRESHOLD = -1
|
||||
self.BETWEEN_THRESHOLDS = -2
|
||||
assert low_threshold <= high_threshold
|
||||
self.high_threshold = high_threshold
|
||||
self.low_threshold = low_threshold
|
||||
self.allow_low_quality_matches = allow_low_quality_matches
|
||||
|
||||
def __call__(self, match_quality_matrix):
|
||||
"""
|
||||
Args:
|
||||
match_quality_matrix (Tensor[float]): an MxN tensor, containing the
|
||||
pairwise quality between M ground-truth elements and N predicted elements.
|
||||
|
||||
Returns:
|
||||
matches (Tensor[int64]): an N tensor where N[i] is a matched gt in
|
||||
[0, M - 1] or a negative value indicating that prediction i could not
|
||||
be matched.
|
||||
"""
|
||||
if match_quality_matrix.numel() == 0:
|
||||
# empty targets or proposals not supported during training
|
||||
if match_quality_matrix.shape[0] == 0:
|
||||
raise ValueError(
|
||||
"No ground-truth boxes available for one of the images "
|
||||
"during training")
|
||||
|
||||
raise ValueError(
|
||||
"No proposal boxes available for one of the images "
|
||||
"during training")
|
||||
|
||||
# match_quality_matrix is M (gt) x N (predicted)
|
||||
# Max over gt elements (dim 0) to find best gt candidate for each prediction
|
||||
matched_vals, matches = match_quality_matrix.max(dim=0)
|
||||
if self.allow_low_quality_matches:
|
||||
all_matches = matches.clone()
|
||||
else:
|
||||
all_matches = None
|
||||
|
||||
# Assign candidate matches with low quality to negative (unassigned) values
|
||||
below_low_threshold = matched_vals < self.low_threshold
|
||||
between_thresholds = (matched_vals >= self.low_threshold) & (
|
||||
matched_vals < self.high_threshold
|
||||
)
|
||||
matches[below_low_threshold] = self.BELOW_LOW_THRESHOLD
|
||||
matches[between_thresholds] = self.BETWEEN_THRESHOLDS
|
||||
|
||||
if self.allow_low_quality_matches:
|
||||
assert all_matches is not None
|
||||
self.set_low_quality_matches_(matches, all_matches, match_quality_matrix)
|
||||
|
||||
return matches
|
||||
|
||||
def set_low_quality_matches_(self, matches, all_matches, match_quality_matrix):
|
||||
"""
|
||||
Produce additional matches for predictions that have only low-quality matches.
|
||||
Specifically, for each ground-truth find the set of predictions that have
|
||||
maximum overlap with it (including ties); for each prediction in that set, if
|
||||
it is unmatched, then match it to the ground-truth with which it has the highest
|
||||
quality value.
|
||||
"""
|
||||
# For each gt, find the prediction with which it has highest quality
|
||||
highest_quality_foreach_gt, _ = match_quality_matrix.max(dim=1)
|
||||
# Find highest quality match available, even if it is low, including ties
|
||||
gt_pred_pairs_of_highest_quality = torch.where(
|
||||
match_quality_matrix == highest_quality_foreach_gt[:, None]
|
||||
)
|
||||
# Example gt_pred_pairs_of_highest_quality:
|
||||
# tensor([[ 0, 39796],
|
||||
# [ 1, 32055],
|
||||
# [ 1, 32070],
|
||||
# [ 2, 39190],
|
||||
# [ 2, 40255],
|
||||
# [ 3, 40390],
|
||||
# [ 3, 41455],
|
||||
# [ 4, 45470],
|
||||
# [ 5, 45325],
|
||||
# [ 5, 46390]])
|
||||
# Each row is a (gt index, prediction index)
|
||||
# Note how gt items 1, 2, 3, and 5 each have two ties
|
||||
|
||||
pred_inds_to_update = gt_pred_pairs_of_highest_quality[1]
|
||||
matches[pred_inds_to_update] = all_matches[pred_inds_to_update]
|
||||
25
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/openimages.py
vendored
Normal file
25
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/openimages.py
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
from test.external.mlperf_retinanet.model.boxes import box_iou
|
||||
from test.external.mlperf_retinanet.model.utils import Matcher
|
||||
|
||||
import torch
|
||||
|
||||
# This applies the filtering in https://github.com/mlcommons/training/blob/cdd928d4596c142c15a7d86b2eeadbac718c8da2/single_stage_detector/ssd/model/retinanet.py#L117
|
||||
# and https://github.com/mlcommons/training/blob/cdd928d4596c142c15a7d86b2eeadbac718c8da2/single_stage_detector/ssd/model/retinanet.py#L203
|
||||
# to match with tinygrad's dataloader implementation.
|
||||
def postprocess_targets(targets, anchors):
|
||||
proposal_matcher, matched_idxs = Matcher(0.5, 0.4, allow_low_quality_matches=True), []
|
||||
for anchors_per_image, targets_per_image in zip(anchors, targets):
|
||||
if targets_per_image['boxes'].numel() == 0:
|
||||
matched_idxs.append(torch.full((anchors_per_image.size(0),), -1, dtype=torch.int64,
|
||||
device=anchors_per_image.device))
|
||||
continue
|
||||
|
||||
match_quality_matrix = box_iou(targets_per_image['boxes'], anchors_per_image)
|
||||
matched_idxs.append(proposal_matcher(match_quality_matrix))
|
||||
|
||||
for targets_per_image, matched_idxs_per_image in zip(targets, matched_idxs):
|
||||
foreground_idxs_per_image = matched_idxs_per_image >= 0
|
||||
targets_per_image["boxes"] = targets_per_image["boxes"][matched_idxs_per_image[foreground_idxs_per_image]]
|
||||
targets_per_image["labels"] = targets_per_image["labels"][matched_idxs_per_image[foreground_idxs_per_image]]
|
||||
|
||||
return targets
|
||||
24
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/presets.py
vendored
Normal file
24
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/presets.py
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/presets.py
|
||||
|
||||
from test.external.mlperf_retinanet import transforms as T
|
||||
|
||||
class DetectionPresetTrain:
|
||||
def __init__(self, data_augmentation, hflip_prob=0.5, mean=(123., 117., 104.)):
|
||||
if data_augmentation == 'hflip':
|
||||
self.transforms = T.Compose([
|
||||
T.RandomHorizontalFlip(p=hflip_prob),
|
||||
T.ToTensor(),
|
||||
])
|
||||
else:
|
||||
raise ValueError(f'Unknown data augmentation policy "{data_augmentation}"')
|
||||
|
||||
def __call__(self, img, target):
|
||||
return self.transforms(img, target)
|
||||
|
||||
|
||||
class DetectionPresetEval:
|
||||
def __init__(self):
|
||||
self.transforms = T.ToTensor()
|
||||
|
||||
def __call__(self, img, target):
|
||||
return self.transforms(img, target)
|
||||
77
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/transforms.py
vendored
Normal file
77
artifacts/package_sources/tinygrad/test/external/mlperf_retinanet/transforms.py
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# Copied from https://github.com/mlcommons/training/blob/637c82f9e699cd6caf108f92efb2c1d446b630e0/single_stage_detector/ssd/transforms.py
|
||||
|
||||
import torch
|
||||
import torchvision
|
||||
|
||||
from torch import nn, Tensor
|
||||
from torchvision.transforms import functional as F
|
||||
from torchvision.transforms import transforms as T
|
||||
from typing import List, Tuple, Dict, Optional
|
||||
|
||||
from PIL import Image
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import accimage
|
||||
except ImportError:
|
||||
accimage = None
|
||||
|
||||
@torch.jit.unused
|
||||
def _is_pil_image(img: Any) -> bool:
|
||||
if accimage is not None:
|
||||
return isinstance(img, (Image.Image, accimage.Image))
|
||||
else:
|
||||
return isinstance(img, Image.Image)
|
||||
|
||||
def get_image_size_tensor(img: Tensor) -> List[int]:
|
||||
# Returns (w, h) of tensor image
|
||||
torchvision.transforms._functional_tensor._assert_image_tensor(img)
|
||||
return [img.shape[-1], img.shape[-2]]
|
||||
|
||||
@torch.jit.unused
|
||||
def get_image_size_pil(img: Any) -> List[int]:
|
||||
if _is_pil_image(img):
|
||||
return list(img.size)
|
||||
raise TypeError("Unexpected type {}".format(type(img)))
|
||||
|
||||
def get_image_size(img: Tensor) -> List[int]:
|
||||
"""Returns the size of an image as [width, height].
|
||||
Args:
|
||||
img (PIL Image or Tensor): The image to be checked.
|
||||
Returns:
|
||||
List[int]: The image size.
|
||||
"""
|
||||
if isinstance(img, torch.Tensor):
|
||||
return get_image_size_tensor(img)
|
||||
|
||||
return get_image_size_pil(img)
|
||||
|
||||
class Compose(object):
|
||||
def __init__(self, transforms):
|
||||
self.transforms = transforms
|
||||
|
||||
def __call__(self, image, target):
|
||||
for t in self.transforms:
|
||||
image, target = t(image, target)
|
||||
return image, target
|
||||
|
||||
|
||||
class RandomHorizontalFlip(T.RandomHorizontalFlip):
|
||||
def forward(self, image: Tensor,
|
||||
target: Optional[Dict[str, Tensor]] = None) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]:
|
||||
if torch.rand(1) < self.p:
|
||||
image = F.hflip(image)
|
||||
if target is not None:
|
||||
width, _ = get_image_size(image)
|
||||
target["boxes"][:, [0, 2]] = width - target["boxes"][:, [2, 0]]
|
||||
if "masks" in target:
|
||||
target["masks"] = target["masks"].flip(-1)
|
||||
return image, target
|
||||
|
||||
|
||||
class ToTensor(nn.Module):
|
||||
def forward(self, image: Tensor,
|
||||
target: Optional[Dict[str, Tensor]] = None) -> Tuple[Tensor, Optional[Dict[str, Tensor]]]:
|
||||
image = F.to_tensor(image)
|
||||
return image, target
|
||||
Reference in New Issue
Block a user