Zai
test
06db6e9
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])))