Instructions to use XXXpilar/Fastfill-test with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use XXXpilar/Fastfill-test with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
File size: 5,541 Bytes
e6f80f3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | """Piecewise differentiable BEV oriented GIoU; convex hull enclosure of both boxes.
Sutherland-Hodgman intersection and a monotone-chain convex hull select topology
with detached comparisons. Original vertices retain autograd. Derivatives exist
within each topology; contacts, coincident edges and hull changes are nonsmooth.
No vertical supervision is supplied by this operator. Uses no compiled extension.
Metal inputs use CPU float64 polygon arithmetic and return float32 on Metal;
device transfers preserve autograd, at the cost of synchronization and transfer.
"""
from __future__ import annotations
import torch
from fastfill.v2.geometry import bev_corners
def _cross(a, b):
return a[0] * b[1] - a[1] * b[0]
def _area(points, zero):
if len(points) < 3:
return zero
p = torch.stack(points)
p = p - p[0] # translation invariant area, avoids cancellation of global offsets
return (_cross_batch(p, p.roll(-1, 0)).sum() / 2).abs()
def _cross_batch(a, b):
return a[..., 0] * b[..., 1] - a[..., 1] * b[..., 0]
def _clip(subject, clip):
output = list(subject.unbind(0))
for a, b in zip(clip, clip.roll(-1, 0)):
source, output = output, []
if not source:
break
previous = source[-1]
prev_side = _cross(b - a, previous - a)
for current in source:
side = _cross(b - a, current - a)
inside, was_inside = bool(side.detach() >= 0), bool(prev_side.detach() >= 0)
if inside != was_inside:
# Signed distances have opposite signs; denominator is nonzero.
fraction = prev_side / (prev_side - side)
output.append(previous + fraction * (current - previous))
if inside:
output.append(current)
previous, prev_side = current, side
return output
def _hull(points):
ordered = sorted(range(len(points)), key=lambda i: tuple(points[i].detach().cpu().tolist()))
# Remove identical points using topology comparisons only.
ordered = [i for k, i in enumerate(ordered) if k == 0 or not torch.equal(points[i].detach(), points[ordered[k - 1]].detach())]
def chain(order):
result = []
for i in order:
while len(result) >= 2 and bool(_cross(points[result[-1]] - points[result[-2]], points[i] - points[result[-1]]).detach() <= 0):
result = result[:-1]
result.append(i)
return result
indices = chain(ordered)[:-1] + chain(list(reversed(ordered)))[:-1]
return [points[i] for i in indices]
def _corners(p, s, yaw):
if p.shape != (3,) or s.shape != (3,) or yaw.ndim != 0:
raise ValueError("BEV operator accepts individual 3D full-size boxes")
if not all(torch.isfinite(t).all() for t in (p, s, yaw)) or (s <= 0).any():
raise ValueError("box geometry must be finite and positive")
return bev_corners(p, s, yaw)
def _working_pair(position, size, yaw, other_position, other_size, other_yaw):
# Polygon topology is numerically fragile in float16/float32, especially for
# tiny boxes far from the origin. Cast before constructing any vertices and
# subtract a common origin. Autograd propagates through casts/subtractions.
_corners(position, size, yaw)
_corners(other_position, other_size, other_yaw)
if position.device.type == "mps":
position, size, yaw, other_position, other_size, other_yaw = (
value.cpu().double()
for value in (position, size, yaw, other_position, other_size, other_yaw))
offset = position.detach().double()
p, q = position.double() - offset, other_position.double() - offset
s, t, y, z = size.double(), other_size.double(), yaw.double(), other_yaw.double()
return _corners(p, s, y), _corners(q, t, z), s, t
def _result_on_input_device(result, position):
return result.float().to(position.device) if position.device.type == "mps" else result
def intersection_area(position, size, yaw, other_position, other_size, other_yaw):
a, b, _, _ = _working_pair(position, size, yaw, other_position, other_size, other_yaw)
return _result_on_input_device(_area(_clip(a, b), (a.sum() + b.sum()) * 0), position)
def _overlap(position, size, yaw, other_position, other_size, other_yaw):
a, b, size, other_size = _working_pair(position, size, yaw, other_position, other_size, other_yaw)
zero = (a.sum() + b.sum()) * 0
intersection = _area(_clip(a, b), zero)
union = size[0] * size[1] + other_size[0] * other_size[1] - intersection
if not torch.isfinite(union) or not bool(union.detach() > 0):
raise ValueError("box union area must be finite and positive")
return a, b, intersection, union, zero
def bev_iou(position, size, yaw, other_position, other_size, other_yaw):
"""Actual BEV IoU, kept distinct from generalized IoU."""
_, _, intersection, union, _ = _overlap(position, size, yaw, other_position, other_size, other_yaw)
return _result_on_input_device(intersection / union, position)
def bev_giou(position, size, yaw, other_position, other_size, other_yaw):
a, b, intersection, union, zero = _overlap(position, size, yaw, other_position, other_size, other_yaw)
enclosure = _area(_hull(torch.cat((a, b), 0)), zero)
if not torch.isfinite(enclosure) or not bool(enclosure.detach() > 0):
raise ValueError("box convex enclosure area must be finite and positive")
return _result_on_input_device(intersection / union - (enclosure - union) / enclosure, position)
|