|
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 |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
target[target>=99]=98 |
|
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 |
|
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.01, sampling_size=512): |
|
self.sigma = sigma |
|
self.sampling_size = sampling_size |
|
self.epsilon = 1.0e-15 |
|
self.embed_norm = True |
|
|
|
def __call__(self, embeddings, flows): |
|
''' |
|
embedding: Variable Nx256xHxW (not hyper-column) |
|
flows: Variable Nx2xHxW |
|
''' |
|
assert flows.size(1) == 2 |
|
|
|
|
|
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] |
|
|
|
|
|
if self.embed_norm: |
|
embeddings /= torch.norm(embeddings, p=2, dim=1, keepdim=True) |
|
|
|
|
|
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 = 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) |
|
|
|
|
|
|
|
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda()) |
|
mask = torch.ones_like(exp_k_f) - eye |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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 = -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 |
|
|
|
def __call__(self, embeddings, flows): |
|
''' |
|
embedding: Variable Nx256xHxW (not hyper-column) |
|
flows: Variable Nx2xHxW |
|
''' |
|
assert flows.size(1) == 2 |
|
|
|
|
|
factor = flows.shape[2] // embeddings.shape[2] |
|
flows = nn.functional.avg_pool2d(flows, factor, factor) |
|
assert flows.shape[2] == embeddings.shape[2] |
|
|
|
|
|
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] |
|
|
|
|
|
if self.embed_norm: |
|
embeddings /= torch.norm(embeddings, p=2, dim=1, keepdim=True) |
|
|
|
|
|
flows_flatten = flows.view(flows.shape[0], 2, -1) |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda()) |
|
mask = torch.ones_like(exp_k_f) - eye |
|
|
|
|
|
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) |
|
|
|
|
|
embeddings_flatten = embeddings.view(embeddings.shape[0], embeddings.shape[1], -1) |
|
|
|
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) |
|
|
|
|
|
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 = -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) |
|
|
|
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 |
|
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 |
|
|
|
|
|
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] |
|
|
|
|
|
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 = 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) |
|
|
|
|
|
|
|
eye = Variable(torch.unsqueeze(torch.eye(k_f.shape[1]), dim=0).cuda()) |
|
mask = torch.ones_like(exp_k_f) - eye |
|
|
|
|
|
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 = get_column(feats, random_locations, flows.shape[2]) |
|
embedding = self.mlp(column) |
|
|
|
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) |
|
|
|
|
|
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 = -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 |
|
|