Spaces:
Runtime error
Runtime error
import torch | |
from torch import nn | |
import math | |
import model.box_utils as box_utils | |
# fragment | |
# boundary | |
def cropped_box_iou(bboxes_pred,bboxes_gt,mask): | |
H,W = mask.shape | |
bboxes_pred = box_utils.norms_to_indices(bboxes_pred,W,H) | |
bboxes_gt = box_utils.norms_to_indices(bboxes_gt,W,H) | |
ious = torch.zeros(len(bboxes_pred)).to(bboxes_pred).float() | |
for i in range(len(bboxes_pred)): | |
box_pred = bboxes_pred[i] | |
box_gt = bboxes_gt[i] | |
mask_pred = mask.new_zeros(H,W) | |
mask_gt = mask.new_zeros(H,W) | |
mask_pred[box_pred[1]:box_pred[3],box_pred[0]:box_pred[2]]=1 | |
mask_gt[box_gt[1]:box_gt[3],box_gt[0]:box_gt[2]]=1 | |
mask_pred = mask_pred*mask | |
mask_gt = mask_gt*mask | |
union = (mask_pred+mask_gt) | |
intersection = (mask_pred*mask_gt) | |
ious[i] = len(intersection.nonzero())/len(union.nonzero()) | |
return ious | |
def compose_by_cateogry(boxes,objs,category): | |
H,W = category.shape | |
image = torch.zeros_like(category).to(category) | |
boxes = box_utils.norms_to_indices(boxes,H,W) | |
overlaps = category.new_zeros(H,W,len(boxes)) | |
for i,box in enumerate(boxes): | |
#overlap = image[box[1]:box[3],box[0]:box[2]].nonzero()+box[[1,0]] | |
overlaps[box[1]:box[3],box[0]:box[2],i] = 1 | |
image[box[1]:box[3],box[0]:box[2]] = objs[i] | |
overlap_vectors = overlaps.view(-1,len(boxes)).unique(dim=0) | |
for vector in overlap_vectors: | |
if vector.sum()<2: continue | |
overlap_region = (overlaps==vector).prod(-1).nonzero() | |
unique,count = category[overlap_region[:,0],overlap_region[:,1]].unique(return_counts=True) | |
overlap_objs = objs[vector.bool()] | |
valid_u = [True if u in overlap_objs else False for u in unique] | |
count = count[valid_u] | |
unique = unique[valid_u] | |
if len(unique)>0: | |
winner = unique[count.argmax()] | |
image[overlap_region[:,0],overlap_region[:,1]] = winner | |
return image | |
def sample_fragment(step=2): | |
""" | |
Parameters: | |
---------- | |
step: int, sample step in linspace [0,1] | |
Returns: | |
---------- | |
ret: [step^step,2] | |
""" | |
return torch.stack( | |
torch.meshgrid( | |
torch.linspace(0,1,step), | |
torch.linspace(0,1,step) | |
) | |
,dim=-1).reshape(-1,2) | |
def sample_boundary(step=2): | |
""" | |
Parameters: | |
---------- | |
step: int, sample step in linspace [0,1] | |
Returns: | |
---------- | |
ret: [step*4,2] | |
""" | |
return torch.cat([ | |
torch.stack(torch.meshgrid( | |
torch.linspace(0,1,2), | |
torch.linspace(0,1,step) | |
),dim=-1).reshape(-1,2), | |
torch.stack(torch.meshgrid( | |
torch.linspace(0,1,step), | |
torch.linspace(0,1,2) | |
),dim=-1).reshape(-1,2) | |
]) | |
def fragment_outside_box(fragments,boxes): | |
""" | |
if points in fragment outside box | |
Calculate line distance among points of fragment i and lines of box j, get [P,B,4] | |
if all 4 values of a point are great than or equal to 0, the point is inside the box | |
else the point is in outside the box | |
Parameters: | |
---------- | |
fragments: [F,FP,2] | |
boxes: [B,4] | |
Return: | |
---------- | |
ret: [F,FP,B] | |
""" | |
assert fragments.dim()==3 | |
F,FP,_ = fragments.shape | |
B,_ = boxes.shape | |
diff = torch.cat([ | |
fragments.view(F,FP,1,2)-boxes[:,:2].view(1,1,B,2), | |
boxes[:,2:].view(1,1,B,2)-fragments.view(F,FP,1,2) | |
],dim=-1) | |
return ((diff>=0).sum(-1)!=4).float() | |
def fragment_box_distance(fragments,box_points): | |
""" | |
calcuate distance among fragments of fragmaent_i and box_points of box_j | |
get the smallest distance for each point of box_i to box_j | |
Parameters: | |
---------- | |
fragments: [F,FP,2] | |
box_points: [B,BP,2] | |
Return: | |
---------- | |
ret: [F,FP,B] | |
""" | |
F,FP,_ = fragments.shape | |
B,BP,_ = box_points.shape | |
# [F,FP,B,BP] -> [F,FP,B] | |
#return (fragments.view(F,FP,1,1,2)-box_points.view(1,1,B,BP,2)).norm(dim=-1).min(-1)[0] | |
return (fragments.view(F,FP,1,1,2)-box_points.view(1,1,B,BP,2)).pow(2).sum(-1).min(-1)[0] | |
def coverage_loss(boxes,fragments,step=2): | |
""" | |
boxes can cover all points in fragments | |
Parameters: | |
---------- | |
boxes: [B,4], NBoxes with (x0,y0,x1,y1) | |
fragments: [F,FP,2], NBox wit (x,y) | |
""" | |
BP = step*4 | |
B, _ = boxes.shape | |
F,FP, _ = fragments.shape | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
# [B,BP,2] | |
box_points = sample_boundary(step=step).view(1,BP,2)*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [F,FP,B] | |
f_out_box = fragment_outside_box(fragments,boxes) | |
# [F,FP,B] | |
f_b_dist = fragment_box_distance(fragments,box_points) | |
# [F,FP] | |
return (f_b_dist*f_out_box).min(-1)[0].sum()/FP | |
def inside_loss(boxes,fragment_boxes,step=2): | |
""" | |
all points on the boundary of boxes are inside fragment_boxes | |
Parameters: | |
---------- | |
boxes: [B,4], NBoxes with (x0,y0,x1,y1) | |
fragment_boxes: [F,4], NBox wit (x,y) | |
""" | |
B, _ = boxes.shape | |
P = step*4 | |
F, _ = fragment_boxes.shape | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
fragment_wh = fragment_boxes[:,2:]-fragment_boxes[:,:2] | |
# [B,BP,2] | |
box_fragments = sample_boundary(step=step).view(1,P,2)*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [F,FP,2] | |
fragment_boundaries = sample_boundary(step=step).view(1,P,2)*fragment_wh.view(F,1,2)+fragment_boxes[:,:2].view(F,1,2) | |
# [B,BP,F] | |
f_out_box = fragment_outside_box(box_fragments,fragment_boxes) | |
# [B,BP,F] | |
f_b_dist = fragment_box_distance(box_fragments,fragment_boundaries) | |
# [B,BP] | |
return (f_b_dist*f_out_box).sum()/(B*P) | |
def mutex_loss(boxes,step=2): | |
""" | |
sum of min-pixel-boundary distance / sum of pixels in boxes | |
Parameters: | |
---------- | |
boxes: B*4, bboxes with (x0,y0,x1,y1) | |
ref_points: P*2, bbox wit (x,y) | |
""" | |
B = boxes.shape[0] | |
BP = step*4 | |
FP = step*step | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
# [B,FP,2] | |
fragments = sample_fragment(step=step).view(1,FP,2)*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,BP,2] | |
box_points = sample_boundary(step=step).view(1,BP,2)*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,FP,B] | |
f_out_box = fragment_outside_box(fragments,boxes) | |
# [B,FP,B] B个Box的PP个点与B个Box的最小距离 | |
f_b_dist = fragment_box_distance(fragments,box_points) | |
return (f_b_dist*f_out_box).sum()/(B*FP-B) | |
class InsideLoss(nn.Module): | |
def __init__(self,nsample=100,cuda=True): | |
super(InsideLoss,self).__init__() | |
self.bstep = round(nsample/4) | |
self.fstep = round(math.sqrt(nsample)) | |
self.BP = self.bstep*4 | |
self.FP = self.fstep*self.fstep | |
self.boundary = sample_boundary(step=self.bstep).view(1,self.BP,2) | |
self.fragment = sample_fragment(step=self.fstep).view(1,self.FP,2) | |
if cuda: | |
self.boundary=self.boundary.cuda() | |
self.fragment=self.fragment.cuda() | |
def _inside_loss(self,boxes,fragment_boxes): | |
B, _ = boxes.shape | |
F, _ = fragment_boxes.shape | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
fragment_wh = fragment_boxes[:,2:]-fragment_boxes[:,:2] | |
# [B,FP,2] | |
box_fragments = self.fragment*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [F,BP,2] | |
fragment_boundaries = self.boundary*fragment_wh.view(F,1,2)+fragment_boxes[:,:2].view(F,1,2) | |
# [B,FP,F] | |
f_out_box = fragment_outside_box(box_fragments,fragment_boxes) | |
# [B,FP,F] | |
f_b_dist = fragment_box_distance(box_fragments,fragment_boundaries) | |
# [B,FP] | |
return (f_b_dist*f_out_box).sum()/(B*self.FP) | |
def test(self,boxes,fragment_boxes): | |
with torch.no_grad(): | |
return self._inside_loss(boxes,fragment_boxes) | |
def forward(self,boxes,fragment_boxes,obj_to_img,reduction="mean"): | |
N = obj_to_img.data.max().item() + 1 | |
boxes = box_utils.centers_to_extents(boxes) | |
losses = [] | |
for i in range(N): | |
obj_to_i = (obj_to_img==i).nonzero().view(-1) | |
loss = self._inside_loss(boxes[obj_to_i],fragment_boxes[[i]]) | |
losses.append(loss) | |
return torch.mean(torch.stack(losses)) | |
class CoverageLoss(nn.Module): | |
def __init__(self,nsample=100,cuda=True): | |
super(CoverageLoss,self).__init__() | |
self.step = round(nsample/4) | |
self.BP = self.step*4 | |
self.boundary = sample_boundary(step=self.step).view(1,self.BP,2) | |
self.boundary = self.boundary.cuda() | |
def _coverage_loss(self,boxes,fragments): | |
B, _ = boxes.shape | |
F,FP, _ = fragments.shape | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
# [B,BP,2] | |
box_points = self.boundary*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [F,FP,B] | |
f_out_box = fragment_outside_box(fragments,boxes) | |
# [F,FP,B] | |
f_b_dist = fragment_box_distance(fragments,box_points) | |
# [F,FP] | |
return (f_b_dist*f_out_box).min(-1)[0].sum()/FP | |
def test(self,boxes,fragments): | |
with torch.no_grad(): | |
return self._coverage_loss(boxes,fragments) | |
def forward(self,boxes,fragments,obj_to_img,reduction="mean"): | |
N = obj_to_img.data.max().item() + 1 | |
boxes = box_utils.centers_to_extents(boxes) | |
losses = [] | |
for i in range(N): | |
obj_to_i = (obj_to_img==i).nonzero().view(-1) | |
loss = self._coverage_loss(boxes[obj_to_i],fragments[i]) | |
losses.append(loss) | |
return torch.mean(torch.stack(losses)) | |
class MutexLoss(nn.Module): | |
def __init__(self,nsample=100,cuda=True): | |
super(MutexLoss,self).__init__() | |
self.bstep = round(nsample/4) | |
self.fstep = round(math.sqrt(nsample)) | |
self.BP = self.bstep*4 | |
self.FP = self.fstep*self.fstep | |
self.boundary = sample_boundary(step=self.bstep).view(1,self.BP,2) | |
self.fragment = sample_fragment(step=self.fstep).view(1,self.FP,2) | |
if cuda: | |
self.boundary=self.boundary.cuda() | |
self.fragment=self.fragment.cuda() | |
def _mutex_loss(self,boxes): | |
B = boxes.shape[0] | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
# [B,FP,2] | |
fragments = self.fragment*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,BP,2] | |
box_points = self.boundary*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,FP,B] | |
f_in_box = 1-fragment_outside_box(fragments,boxes) | |
# clear dist to self | |
f_in_box[range(B),:,range(B)]=0 | |
# [B,FP,B] B个Box的PP个点与B个Box的最小距离 | |
f_b_dist = fragment_box_distance(fragments,box_points) | |
return (f_b_dist*f_in_box).sum()/(B*self.FP-B) | |
def test(self,boxes): | |
with torch.no_grad(): | |
return self._mutex_loss(boxes) | |
def forward(self,boxes,obj_to_img,objs=None,reduction="mean"): | |
N = obj_to_img.data.max().item() + 1 | |
boxes = box_utils.centers_to_extents(boxes) | |
losses = [] | |
for i in range(N): | |
obj_to_i = ((obj_to_img==i)*(objs!=0)).nonzero().view(-1) | |
loss = self._mutex_loss(boxes[obj_to_i]) | |
losses.append(loss) | |
return torch.mean(torch.stack(losses)) | |
class BoxRenderLoss(nn.Module): | |
def __init__(self,nsample=100,cuda=True): | |
super(BoxRenderLoss,self).__init__() | |
self.bstep = round(nsample/4) | |
self.fstep = round(math.sqrt(nsample)) | |
self.BP = self.bstep*4 | |
self.FP = self.fstep*self.fstep | |
self.boundary = sample_boundary(step=self.bstep).view(1,self.BP,2) | |
self.fragment = sample_fragment(step=self.fstep).view(1,self.FP,2) | |
if cuda: | |
self.boundary=self.boundary.cuda() | |
self.fragment=self.fragment.cuda() | |
def _fragment_outside_box(self,fragments,boxes): | |
assert fragments.dim()==3 | |
F,FP,_ = fragments.shape | |
diff = torch.cat([ | |
fragments.view(F,FP,2)-boxes[:,:2].view(F,1,2), | |
boxes[:,2:].view(F,1,2)-fragments.view(F,FP,2) | |
],dim=-1) | |
return ((diff>=0).sum(-1)!=4).float() | |
def _fragment_box_distance(self,fragments,box_points): | |
F,FP,_ = fragments.shape | |
B,BP,_ = box_points.shape | |
return (fragments.view(F,FP,1,2)-box_points.view(B,1,BP,2)).pow(2).sum(-1).min(-1)[0] | |
def _render_loss(self,boxes,targets): | |
B = boxes.shape[0] | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
target_wh=targets[:,2:]-targets[:,:2] | |
# [B,FP,2] | |
box_fragments = self.fragment*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,BP,2] | |
box_points = self.boundary*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [B,FP,2] | |
target_fragments = self.fragment*target_wh.view(B,1,2)+targets[:,:2].view(B,1,2) | |
# [B,BP,2] | |
target_points = self.boundary*target_wh.view(B,1,2)+targets[:,:2].view(B,1,2) | |
# [B,FP] | |
b_out_t = self._fragment_outside_box(box_fragments,targets) | |
t_out_b = self._fragment_outside_box(target_fragments,boxes) | |
# [B,FP] B个Box的PP个点与B个Box的最小距离 | |
b_t_dist = self._fragment_box_distance(box_fragments,target_points) | |
t_b_dist = self._fragment_box_distance(target_fragments,box_points) | |
return ((b_t_dist*b_out_t).sum()+(t_b_dist*t_out_b).sum())/(2*B*self.FP) | |
def test(self,boxes,targets): | |
with torch.no_grad(): | |
return _render_loss(self,boxes,targets) | |
def forward(self,boxes,targets,reduction="mean"): | |
return torch.mean(self._render_loss(boxes,targets)) | |
class DoorLoss(nn.Module): | |
def __init__(self,nsample=100,cuda=True): | |
super(DoorLoss,self).__init__() | |
self.bstep = round(nsample/4) | |
self.fstep = round(math.sqrt(nsample)) | |
self.BP = self.bstep*4 | |
self.FP = self.fstep*self.fstep | |
self.boundary = sample_boundary(step=self.bstep).view(1,self.BP,2) | |
self.fragment = sample_fragment(step=self.fstep).view(1,self.FP,2) | |
if cuda: | |
self.boundary=self.boundary.cuda() | |
self.fragment=self.fragment.cuda() | |
def _door_loss(self,boxes,doors,objs): | |
B, _ = boxes.shape | |
F, _ = doors.shape | |
box_wh=boxes[:,2:]-boxes[:,:2] | |
door_wh = doors[:,2:]-doors[:,:2] | |
# [B,BP,2] | |
box_boundaries = self.boundary*box_wh.view(B,1,2)+boxes[:,:2].view(B,1,2) | |
# [F,FP,2] | |
door_fragments = self.fragment*door_wh.view(F,1,2)+doors[:,:2].view(F,1,2) | |
# [F,FP,B] | |
f_out_box = (objs-fragment_outside_box(door_fragments,boxes)).abs() | |
# [F,FP,B] | |
f_b_dist = fragment_box_distance(door_fragments,box_boundaries) | |
# [F,FP] | |
return (f_b_dist*f_out_box).sum()/(F*self.FP) | |
def forward(self,boxes,doors,obj_to_img,objs=None,reduction="mean"): | |
N = obj_to_img.data.max().item() + 1 | |
boxes = box_utils.centers_to_extents(boxes) | |
losses = [] | |
for i in range(N): | |
obj_to_i = ((obj_to_img==i)).nonzero().view(-1) | |
objs_i = (objs[obj_to_img==i]!=0).long() | |
loss = self._door_loss(boxes[obj_to_i],doors[[i]],objs_i) | |
losses.append(loss) | |
return torch.mean(torch.stack(losses)) | |
if __name__ == "__main__": | |
# [4] | |
fragment_box = torch.tensor( | |
[0.25,0.25,0.75,0.75] | |
).view(1,4) | |
# [B,4] | |
boxes = torch.tensor([ | |
[0.25,0.00,0.50,0.50], | |
[0.50,0.50,1.00,0.75] | |
],requires_grad=True) | |
# (0.25**2*2+(0.25*sqrt(2))**2*2)/(8*2)=0.046875 | |
loss = inside_loss(boxes,fragment_box,step=2) | |
print(loss) | |
insideL = InsideLoss(cuda=False) | |
print(insideL(boxes,fragment_box,torch.tensor([0,0]))) | |
boxes = torch.tensor([ | |
[0.25,0.00,0.50,0.50], | |
[0.50,0.50,1.00,0.75] | |
],requires_grad=True) | |
# | |
X = torch.linspace(0.,1.,4) | |
Y = torch.linspace(0.,1.,4) | |
# P,2 | |
fragment_points = torch.tensor([ (X[x],Y[y]) for x in range(1,3) for y in range(1,3)]).view(1,4,2) | |
# (0.09**2+0.16**2+0.16**2*2)/4=0.021225 | |
loss = coverage_loss(boxes,fragment_points) | |
print(loss) | |
coverageL = CoverageLoss(cuda=False) | |
print(coverageL(boxes,fragment_points,torch.tensor([0,0]))) | |
# B,4 | |
boxes = torch.tensor([ | |
[0.25,0.00,0.49,0.49], #0 | |
[0.00,0.25,0.49,0.49], #1 | |
[0.51,0.51,1.00,0.75], #2 | |
[0.51,0.51,0.75,1.00] #3 | |
],requires_grad=True) | |
# (( ( (0.24**2+0.25**2) + (0.51**2+0.26**2)*2 ) | |
# +(0.25**2+ (0.51**2+0.02**2)*2 ) | |
# +((0.26**2+0.02**2)*2) | |
# +((0.02**2*2)*2))*4) | |
# /(4*4-4) = 0.4988666 | |
loss = mutex_loss(boxes,step=2) | |
print(loss) | |
mutexL = MutexLoss(cuda=False) | |
print(mutexL(boxes,torch.tensor([0,0,1,1]))) |