myniu
init
12f772a
import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import random
import math
def MultiChannelSoftBinaryCrossEntropy(input, target, reduction='mean'):
'''
input: N x 38 x H x W --> 19N x 2 x H x W
target: N x 19 x H x W --> 19N x 1 x H x W
'''
input = input.view(-1, 2, input.size(2), input.size(3))
target = target.view(-1, 1, input.size(2), input.size(3))
logsoftmax = nn.LogSoftmax(dim=1)
if reduction == 'mean':
return torch.mean(torch.sum(-target * logsoftmax(input), dim=1))
else:
return torch.sum(torch.sum(-target * logsoftmax(input), dim=1))
class EdgeAwareLoss():
def __init__(self, nc=2, loss_type="L1", reduction='mean'):
assert loss_type in ['L1', 'BCE'], "Undefined loss type: {}".format(loss_type)
self.nc = nc
self.loss_type = loss_type
self.kernelx = Variable(torch.Tensor([[1,0,-1],[2,0,-2],[1,0,-1]]).cuda())
self.kernelx = self.kernelx.repeat(nc,1,1,1)
self.kernely = Variable(torch.Tensor([[1,2,1],[0,0,0],[-1,-2,-1]]).cuda())
self.kernely = self.kernely.repeat(nc,1,1,1)
self.bias = Variable(torch.zeros(nc).cuda())
self.reduction = reduction
if loss_type == 'L1':
self.loss = nn.SmoothL1Loss(reduction=reduction)
elif loss_type == 'BCE':
self.loss = self.bce2d
def bce2d(self, input, target):
assert not target.requires_grad
beta = 1 - torch.mean(target)
weights = 1 - beta + (2 * beta - 1) * target
loss = nn.functional.binary_cross_entropy(input, target, weights, reduction=self.reduction)
return loss
def get_edge(self, var):
assert var.size(1) == self.nc, \
"input size at dim 1 should be consistent with nc, {} vs {}".format(var.size(1), self.nc)
outputx = nn.functional.conv2d(var, self.kernelx, bias=self.bias, padding=1, groups=self.nc)
outputy = nn.functional.conv2d(var, self.kernely, bias=self.bias, padding=1, groups=self.nc)
eps=1e-05
return torch.sqrt(outputx.pow(2) + outputy.pow(2) + eps).mean(dim=1, keepdim=True)
def __call__(self, input, target):
size = target.shape[2:4]
input = nn.functional.interpolate(input, size=size, mode="bilinear", align_corners=True)
target_edge = self.get_edge(target)
if self.loss_type == 'L1':
return self.loss(self.get_edge(input), target_edge)
elif self.loss_type == 'BCE':
raise NotImplemented
#target_edge = torch.sign(target_edge - 0.1)
#pred = self.get_edge(nn.functional.sigmoid(input))
#return self.loss(pred, target_edge)
def KLD(mean, logvar):
return -0.5 * torch.sum(1 + logvar - mean.pow(2) - logvar.exp())
class DiscreteLoss(nn.Module):
def __init__(self, nbins, fmax):
super().__init__()
self.loss = nn.CrossEntropyLoss()
assert nbins % 2 == 1, "nbins should be odd"
self.nbins = nbins
self.fmax = fmax
self.step = 2 * fmax / float(nbins)
def tobin(self, target):
target = torch.clamp(target, -self.fmax + 1e-3, self.fmax - 1e-3)
quantized_target = torch.floor((target + self.fmax) / self.step)
return quantized_target.type(torch.cuda.LongTensor)
def __call__(self, input, target):
size = target.shape[2:4]
if input.shape[2] != size[0] or input.shape[3] != size[1]:
input = nn.functional.interpolate(input, size=size, mode="bilinear", align_corners=True)
target = self.tobin(target)
assert input.size(1) == self.nbins * 2
# print(target.shape)
# print(input.shape)
# print(torch.max(target))
target[target>=99]=98 # odd bugs of the training loss. We have [0 ~ 99] in GT flow, but nbins = 99
return self.loss(input[:,:self.nbins,...], target[:,0,...]) + self.loss(input[:,self.nbins:,...], target[:,1,...])
class MultiDiscreteLoss():
def __init__(self, nbins=19, fmax=47.5, reduction='mean', xy_weight=(1., 1.), quantize_strategy='linear'):
self.loss = nn.CrossEntropyLoss(reduction=reduction)
assert nbins % 2 == 1, "nbins should be odd"
self.nbins = nbins
self.fmax = fmax
self.step = 2 * fmax / float(nbins)
self.x_weight, self.y_weight = xy_weight
self.quantize_strategy = quantize_strategy
def tobin(self, target):
target = torch.clamp(target, -self.fmax + 1e-3, self.fmax - 1e-3)
if self.quantize_strategy == "linear":
quantized_target = torch.floor((target + self.fmax) / self.step)
elif self.quantize_strategy == "quadratic":
ind = target.data > 0
quantized_target = target.clone()
quantized_target[ind] = torch.floor(self.nbins * torch.sqrt(target[ind] / (4 * self.fmax)) + self.nbins / 2.)
quantized_target[~ind] = torch.floor(-self.nbins * torch.sqrt(-target[~ind] / (4 * self.fmax)) + self.nbins / 2.)
return quantized_target.type(torch.cuda.LongTensor)
def __call__(self, input, target):
size = target.shape[2:4]
target = self.tobin(target)
if isinstance(input, list):
input = [nn.functional.interpolate(ip, size=size, mode="bilinear", align_corners=True) for ip in input]
return sum([self.x_weight * self.loss(input[k][:,:self.nbins,...], target[:,0,...]) + self.y_weight * self.loss(input[k][:,self.nbins:,...], target[:,1,...]) for k in range(len(input))]) / float(len(input))
else:
input = nn.functional.interpolate(input, size=size, mode="bilinear", align_corners=True)
return self.x_weight * self.loss(input[:,:self.nbins,...], target[:,0,...]) + self.y_weight * self.loss(input[:,self.nbins:,...], target[:,1,...])
class MultiL1Loss():
def __init__(self, reduction='mean'):
self.loss = nn.SmoothL1Loss(reduction=reduction)
def __call__(self, input, target):
size = target.shape[2:4]
if isinstance(input, list):
input = [nn.functional.interpolate(ip, size=size, mode="bilinear", align_corners=True) for ip in input]
return sum([self.loss(input[k], target) for k in range(len(input))]) / float(len(input))
else:
input = nn.functional.interpolate(input, size=size, mode="bilinear", align_corners=True)
return self.loss(input, target)
class MultiMSELoss():
def __init__(self):
self.loss = nn.MSELoss()
def __call__(self, predicts, targets):
loss = 0
for predict, target in zip(predicts, targets):
loss += self.loss(predict, target)
return loss
class JointDiscreteLoss():
def __init__(self, nbins=19, fmax=47.5, reduction='mean', quantize_strategy='linear'):
self.loss = nn.CrossEntropyLoss(reduction=reduction)
assert nbins % 2 == 1, "nbins should be odd"
self.nbins = nbins
self.fmax = fmax
self.step = 2 * fmax / float(nbins)
self.quantize_strategy = quantize_strategy
def tobin(self, target):
target = torch.clamp(target, -self.fmax + 1e-3, self.fmax - 1e-3)
if self.quantize_strategy == "linear":
quantized_target = torch.floor((target + self.fmax) / self.step)
elif self.quantize_strategy == "quadratic":
ind = target.data > 0
quantized_target = target.clone()
quantized_target[ind] = torch.floor(self.nbins * torch.sqrt(target[ind] / (4 * self.fmax)) + self.nbins / 2.)
quantized_target[~ind] = torch.floor(-self.nbins * torch.sqrt(-target[~ind] / (4 * self.fmax)) + self.nbins / 2.)
else:
raise Exception("No such quantize strategy: {}".format(self.quantize_strategy))
joint_target = quantized_target[:,0,:,:] * self.nbins + quantized_target[:,1,:,:]
return joint_target.type(torch.cuda.LongTensor)
def __call__(self, input, target):
target = self.tobin(target)
assert input.size(1) == self.nbins ** 2
return self.loss(input, target)
class PolarDiscreteLoss():
def __init__(self, abins=30, rbins=20, fmax=50., reduction='mean', ar_weight=(1., 1.), quantize_strategy='linear'):
self.loss = nn.CrossEntropyLoss(reduction=reduction)
self.fmax = fmax
self.rbins = rbins
self.abins = abins
self.a_weight, self.r_weight = ar_weight
self.quantize_strategy = quantize_strategy
def tobin(self, target):
indxneg = target.data[:,0,:,:] < 0
eps = torch.zeros(target.data[:,0,:,:].size()).cuda()
epsind = target.data[:,0,:,:] == 0
eps[epsind] += 1e-5
angle = torch.atan(target.data[:,1,:,:] / (target.data[:,0,:,:] + eps))
angle[indxneg] += np.pi
angle += np.pi / 2 # 0 to 2pi
angle = torch.clamp(angle, 0, 2 * np.pi - 1e-3)
radius = torch.sqrt(target.data[:,0,:,:] ** 2 + target.data[:,1,:,:] ** 2)
radius = torch.clamp(radius, 0, self.fmax - 1e-3)
quantized_angle = torch.floor(self.abins * angle / (2 * np.pi))
if self.quantize_strategy == 'linear':
quantized_radius = torch.floor(self.rbins * radius / self.fmax)
elif self.quantize_strategy == 'quadratic':
quantized_radius = torch.floor(self.rbins * torch.sqrt(radius / self.fmax))
else:
raise Exception("No such quantize strategy: {}".format(self.quantize_strategy))
quantized_target = torch.autograd.Variable(torch.cat([torch.unsqueeze(quantized_angle, 1), torch.unsqueeze(quantized_radius, 1)], dim=1))
return quantized_target.type(torch.cuda.LongTensor)
def __call__(self, input, target):
target = self.tobin(target)
assert (target >= 0).all() and (target[:,0,:,:] < self.abins).all() and (target[:,1,:,:] < self.rbins).all()
return self.a_weight * self.loss(input[:,:self.abins,...], target[:,0,...]) + self.r_weight * self.loss(input[:,self.abins:,...], target[:,1,...])
class WeightedDiscreteLoss():
def __init__(self, nbins=19, fmax=47.5, reduction='mean'):
self.loss = CrossEntropy2d(reduction=reduction)
assert nbins % 2 == 1, "nbins should be odd"
self.nbins = nbins
self.fmax = fmax
self.step = 2 * fmax / float(nbins)
self.weight = np.ones((nbins), dtype=np.float32)
self.weight[int(self.fmax / self.step)] = 0.01
self.weight = torch.from_numpy(self.weight).cuda()
def tobin(self, target):
target = torch.clamp(target, -self.fmax + 1e-3, self.fmax - 1e-3)
return torch.floor((target + self.fmax) / self.step).type(torch.cuda.LongTensor)
def __call__(self, input, target):
target = self.tobin(target)
assert (target >= 0).all() and (target < self.nbins).all()
return self.loss(input[:,:self.nbins,...], target[:,0,...]) + self.loss(input[:,self.nbins:,...], target[:,1,...], self.weight)
class CrossEntropy2d(nn.Module):
def __init__(self, reduction='mean', ignore_label=-1):
super(CrossEntropy2d, self).__init__()
self.ignore_label = ignore_label
self.reduction = reduction
def forward(self, predict, target, weight=None):
"""
Args:
predict:(n, c, h, w)
target:(n, h, w)
weight (Tensor, optional): a manual rescaling weight given to each class.
If given, has to be a Tensor of size "nclasses"
"""
assert not target.requires_grad
assert predict.dim() == 4
assert target.dim() == 3
assert predict.size(0) == target.size(0), "{0} vs {1} ".format(predict.size(0), target.size(0))
assert predict.size(2) == target.size(1), "{0} vs {1} ".format(predict.size(2), target.size(1))
assert predict.size(3) == target.size(2), "{0} vs {1} ".format(predict.size(3), target.size(3))
n, c, h, w = predict.size()
target_mask = (target >= 0) * (target != self.ignore_label)
target = target[target_mask]
predict = predict.transpose(1, 2).transpose(2, 3).contiguous()
predict = predict[target_mask.view(n, h, w, 1).repeat(1, 1, 1, c)].view(-1, c)
loss = F.cross_entropy(predict, target, weight=weight, reduction=self.reduction)
return loss
#class CrossPixelSimilarityLoss():
# '''
# Modified from: https://github.com/lppllppl920/Challenge2018/blob/master/loss.py
# '''
# def __init__(self, sigma=0.0036, sampling_size=512):
# self.sigma = sigma
# self.sampling_size = sampling_size
# self.epsilon = 1.0e-15
# self.embed_norm = True # loss does not decrease no matter it is true or false.
#
# def __call__(self, embeddings, flows):
# '''
# embedding: Variable Nx256xHxW (not hyper-column)
# flows: Variable Nx2xHxW
# '''
# assert flows.size(1) == 2
#
# # flow normalization
# positive_mask = (flows > 0)
# flows = -torch.clamp(torch.log(torch.abs(flows) + 1) / math.log(50. + 1), max=1.)
# flows[positive_mask] = -flows[positive_mask]
#
# # embedding normalization
# if self.embed_norm:
# embeddings /= torch.norm(embeddings, p=2, dim=1, keepdim=True)
#
# # Spatially random sampling (512 samples)
# flows_flatten = flows.view(flows.shape[0], 2, -1)
# random_locations = Variable(torch.from_numpy(np.array(random.sample(range(flows_flatten.shape[2]), self.sampling_size))).long().cuda())
# flows_sample = torch.index_select(flows_flatten, 2, random_locations)
#
# # K_f
# k_f = self.epsilon + torch.norm(torch.unsqueeze(flows_sample, dim=-1).permute(0, 3, 2, 1) -
# torch.unsqueeze(flows_sample, dim=-1).permute(0, 2, 3, 1), p=2, dim=3,
# keepdim=False) ** 2
# exp_k_f = torch.exp(-k_f / 2. / self.sigma)
#
#
# # mask
# eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda())
# mask = torch.ones_like(exp_k_f) - eye
#
# # S_f
# masked_exp_k_f = torch.mul(mask, exp_k_f) + eye
# s_f = masked_exp_k_f / torch.sum(masked_exp_k_f, dim=1, keepdim=True)
#
# # K_theta
# embeddings_flatten = embeddings.view(embeddings.shape[0], embeddings.shape[1], -1)
# embeddings_sample = torch.index_select(embeddings_flatten, 2, random_locations)
# embeddings_sample_norm = torch.norm(embeddings_sample, p=2, dim=1, keepdim=True)
# k_theta = 0.25 * (torch.matmul(embeddings_sample.permute(0, 2, 1), embeddings_sample)) / (self.epsilon + torch.matmul(embeddings_sample_norm.permute(0, 2, 1), embeddings_sample_norm))
# exp_k_theta = torch.exp(k_theta)
#
# # S_theta
# masked_exp_k_theta = torch.mul(mask, exp_k_theta) + math.exp(-0.75) * eye
# s_theta = masked_exp_k_theta / torch.sum(masked_exp_k_theta, dim=1, keepdim=True)
#
# # loss
# loss = -torch.mean(torch.mul(s_f, torch.log(s_theta)))
#
# return loss
class CrossPixelSimilarityLoss():
'''
Modified from: https://github.com/lppllppl920/Challenge2018/blob/master/loss.py
'''
def __init__(self, sigma=0.01, sampling_size=512):
self.sigma = sigma
self.sampling_size = sampling_size
self.epsilon = 1.0e-15
self.embed_norm = True # loss does not decrease no matter it is true or false.
def __call__(self, embeddings, flows):
'''
embedding: Variable Nx256xHxW (not hyper-column)
flows: Variable Nx2xHxW
'''
assert flows.size(1) == 2
# flow normalization
positive_mask = (flows > 0)
flows = -torch.clamp(torch.log(torch.abs(flows) + 1) / math.log(50. + 1), max=1.)
flows[positive_mask] = -flows[positive_mask]
# embedding normalization
if self.embed_norm:
embeddings /= torch.norm(embeddings, p=2, dim=1, keepdim=True)
# Spatially random sampling (512 samples)
flows_flatten = flows.view(flows.shape[0], 2, -1)
random_locations = Variable(torch.from_numpy(np.array(random.sample(range(flows_flatten.shape[2]), self.sampling_size))).long().cuda())
flows_sample = torch.index_select(flows_flatten, 2, random_locations)
# K_f
k_f = self.epsilon + torch.norm(torch.unsqueeze(flows_sample, dim=-1).permute(0, 3, 2, 1) -
torch.unsqueeze(flows_sample, dim=-1).permute(0, 2, 3, 1), p=2, dim=3,
keepdim=False) ** 2
exp_k_f = torch.exp(-k_f / 2. / self.sigma)
# mask
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda())
mask = torch.ones_like(exp_k_f) - eye
# S_f
masked_exp_k_f = torch.mul(mask, exp_k_f) + eye
s_f = masked_exp_k_f / torch.sum(masked_exp_k_f, dim=1, keepdim=True)
# K_theta
embeddings_flatten = embeddings.view(embeddings.shape[0], embeddings.shape[1], -1)
embeddings_sample = torch.index_select(embeddings_flatten, 2, random_locations)
embeddings_sample_norm = torch.norm(embeddings_sample, p=2, dim=1, keepdim=True)
k_theta = 0.25 * (torch.matmul(embeddings_sample.permute(0, 2, 1), embeddings_sample)) / (self.epsilon + torch.matmul(embeddings_sample_norm.permute(0, 2, 1), embeddings_sample_norm))
exp_k_theta = torch.exp(k_theta)
# S_theta
masked_exp_k_theta = torch.mul(mask, exp_k_theta) + eye
s_theta = masked_exp_k_theta / torch.sum(masked_exp_k_theta, dim=1, keepdim=True)
# loss
loss = -torch.mean(torch.mul(s_f, torch.log(s_theta)))
return loss
class CrossPixelSimilarityFullLoss():
'''
Modified from: https://github.com/lppllppl920/Challenge2018/blob/master/loss.py
'''
def __init__(self, sigma=0.01):
self.sigma = sigma
self.epsilon = 1.0e-15
self.embed_norm = True # loss does not decrease no matter it is true or false.
def __call__(self, embeddings, flows):
'''
embedding: Variable Nx256xHxW (not hyper-column)
flows: Variable Nx2xHxW
'''
assert flows.size(1) == 2
# downsample flow
factor = flows.shape[2] // embeddings.shape[2]
flows = nn.functional.avg_pool2d(flows, factor, factor)
assert flows.shape[2] == embeddings.shape[2]
# flow normalization
positive_mask = (flows > 0)
flows = -torch.clamp(torch.log(torch.abs(flows) + 1) / math.log(50. + 1), max=1.)
flows[positive_mask] = -flows[positive_mask]
# embedding normalization
if self.embed_norm:
embeddings /= torch.norm(embeddings, p=2, dim=1, keepdim=True)
# Spatially random sampling (512 samples)
flows_flatten = flows.view(flows.shape[0], 2, -1)
#random_locations = Variable(torch.from_numpy(np.array(random.sample(range(flows_flatten.shape[2]), self.sampling_size))).long().cuda())
#flows_sample = torch.index_select(flows_flatten, 2, random_locations)
# K_f
k_f = self.epsilon + torch.norm(torch.unsqueeze(flows_flatten, dim=-1).permute(0, 3, 2, 1) -
torch.unsqueeze(flows_flatten, dim=-1).permute(0, 2, 3, 1), p=2, dim=3,
keepdim=False) ** 2
exp_k_f = torch.exp(-k_f / 2. / self.sigma)
# mask
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda())
mask = torch.ones_like(exp_k_f) - eye
# S_f
masked_exp_k_f = torch.mul(mask, exp_k_f) + eye
s_f = masked_exp_k_f / torch.sum(masked_exp_k_f, dim=1, keepdim=True)
# K_theta
embeddings_flatten = embeddings.view(embeddings.shape[0], embeddings.shape[1], -1)
#embeddings_sample = torch.index_select(embeddings_flatten, 2, random_locations)
embeddings_flatten_norm = torch.norm(embeddings_flatten, p=2, dim=1, keepdim=True)
k_theta = 0.25 * (torch.matmul(embeddings_flatten.permute(0, 2, 1), embeddings_flatten)) / (self.epsilon + torch.matmul(embeddings_flatten_norm.permute(0, 2, 1), embeddings_flatten_norm))
exp_k_theta = torch.exp(k_theta)
# S_theta
masked_exp_k_theta = torch.mul(mask, exp_k_theta) + eye
s_theta = masked_exp_k_theta / torch.sum(masked_exp_k_theta, dim=1, keepdim=True)
# loss
loss = -torch.mean(torch.mul(s_f, torch.log(s_theta)))
return loss
def get_column(embeddings, index, full_size):
col = []
for embd in embeddings:
ind = (index.float() / full_size * embd.size(2)).long()
col.append(torch.index_select(embd.view(embd.shape[0], embd.shape[1], -1), 2, ind))
return torch.cat(col, dim=1) # N x coldim x sparsenum
class CrossPixelSimilarityColumnLoss(nn.Module):
'''
Modified from: https://github.com/lppllppl920/Challenge2018/blob/master/loss.py
'''
def __init__(self, sigma=0.0036, sampling_size=512):
super(CrossPixelSimilarityColumnLoss, self).__init__()
self.sigma = sigma
self.sampling_size = sampling_size
self.epsilon = 1.0e-15
self.embed_norm = True # loss does not decrease no matter it is true or false.
self.mlp = nn.Sequential(
nn.Linear(96 + 96 + 384 + 256 + 4096, 256),
nn.ReLU(inplace=True),
nn.Linear(256, 16))
def forward(self, feats, flows):
'''
embedding: Variable Nx256xHxW (not hyper-column)
flows: Variable Nx2xHxW
'''
assert flows.size(1) == 2
# flow normalization
positive_mask = (flows > 0)
flows = -torch.clamp(torch.log(torch.abs(flows) + 1) / math.log(50. + 1), max=1.)
flows[positive_mask] = -flows[positive_mask]
# Spatially random sampling (512 samples)
flows_flatten = flows.view(flows.shape[0], 2, -1)
random_locations = Variable(torch.from_numpy(np.array(random.sample(range(flows_flatten.shape[2]), self.sampling_size))).long().cuda())
flows_sample = torch.index_select(flows_flatten, 2, random_locations)
# K_f
k_f = self.epsilon + torch.norm(torch.unsqueeze(flows_sample, dim=-1).permute(0, 3, 2, 1) -
torch.unsqueeze(flows_sample, dim=-1).permute(0, 2, 3, 1), p=2, dim=3,
keepdim=False) ** 2
exp_k_f = torch.exp(-k_f / 2. / self.sigma)
# mask
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda())
mask = torch.ones_like(exp_k_f) - eye
# S_f
masked_exp_k_f = torch.mul(mask, exp_k_f) + eye
s_f = masked_exp_k_f / torch.sum(masked_exp_k_f, dim=1, keepdim=True)
# column
column = get_column(feats, random_locations, flows.shape[2])
embedding = self.mlp(column)
# K_theta
embedding_norm = torch.norm(embedding, p=2, dim=1, keepdim=True)
k_theta = 0.25 * (torch.matmul(embedding.permute(0, 2, 1), embedding)) / (self.epsilon + torch.matmul(embedding_norm.permute(0, 2, 1), embedding_norm))
exp_k_theta = torch.exp(k_theta)
# S_theta
masked_exp_k_theta = torch.mul(mask, exp_k_theta) + math.exp(-0.75) * eye
s_theta = masked_exp_k_theta / torch.sum(masked_exp_k_theta, dim=1, keepdim=True)
# loss
loss = -torch.mean(torch.mul(s_f, torch.log(s_theta)))
return loss
def print_info(name, var):
print(name, var.size(), torch.max(var).data.cpu()[0], torch.min(var).data.cpu()[0], torch.mean(var).data.cpu()[0])
def MaskL1Loss(input, target, mask):
input_size = input.size()
res = torch.sum(torch.abs(input * mask - target * mask))
total = torch.sum(mask).item()
if total > 0:
res = res / (total * input_size[1])
return res