parent
9f8b043408
commit
040f00aebf
@ -0,0 +1,255 @@
|
||||
import os
|
||||
from math import ceil
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
from torch import nn
|
||||
from torch.autograd import Variable
|
||||
|
||||
|
||||
def check_mkdir(dir_name):
|
||||
if not os.path.exists(dir_name):
|
||||
os.mkdir(dir_name)
|
||||
|
||||
|
||||
def initialize_weights(*models):
|
||||
for model in models:
|
||||
for module in model.modules():
|
||||
if isinstance(module, nn.Conv2d) or isinstance(module, nn.Linear):
|
||||
nn.init.kaiming_normal(module.weight)
|
||||
if module.bias is not None:
|
||||
module.bias.data.zero_()
|
||||
elif isinstance(module, nn.BatchNorm2d):
|
||||
module.weight.data.fill_(1)
|
||||
module.bias.data.zero_()
|
||||
|
||||
|
||||
def get_upsampling_weight(in_channels, out_channels, kernel_size):
|
||||
factor = (kernel_size + 1) // 2
|
||||
if kernel_size % 2 == 1:
|
||||
center = factor - 1
|
||||
else:
|
||||
center = factor - 0.5
|
||||
og = np.ogrid[:kernel_size, :kernel_size]
|
||||
filt = (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)
|
||||
weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size), dtype=np.float64)
|
||||
weight[list(range(in_channels)), list(range(out_channels)), :, :] = filt
|
||||
return torch.from_numpy(weight).float()
|
||||
|
||||
|
||||
class CrossEntropyLoss2d(nn.Module):
|
||||
def __init__(self, weight=None, size_average=True, ignore_index=255):
|
||||
super(CrossEntropyLoss2d, self).__init__()
|
||||
self.nll_loss = nn.NLLLoss2d(weight, size_average, ignore_index)
|
||||
|
||||
def forward(self, inputs, targets):
|
||||
return self.nll_loss(F.log_softmax(inputs), targets)
|
||||
|
||||
|
||||
class FocalLoss2d(nn.Module):
|
||||
def __init__(self, gamma=2, weight=None, size_average=True, ignore_index=255):
|
||||
super(FocalLoss2d, self).__init__()
|
||||
self.gamma = gamma
|
||||
self.nll_loss = nn.NLLLoss2d(weight, size_average, ignore_index)
|
||||
|
||||
def forward(self, inputs, targets):
|
||||
return self.nll_loss((1 - F.softmax(inputs)) ** self.gamma * F.log_softmax(inputs), targets)
|
||||
|
||||
|
||||
def _fast_hist(label_pred, label_true, num_classes):
|
||||
mask = (label_true >= 0) & (label_true < num_classes)
|
||||
hist = np.bincount(
|
||||
num_classes * label_true[mask].astype(int) +
|
||||
label_pred[mask], minlength=num_classes ** 2).reshape(num_classes, num_classes)
|
||||
return hist
|
||||
|
||||
|
||||
def evaluate(predictions, gts, num_classes):
|
||||
hist = np.zeros((num_classes, num_classes))
|
||||
for lp, lt in zip(predictions, gts):
|
||||
hist += _fast_hist(lp.flatten(), lt.flatten(), num_classes)
|
||||
# axis 0: gt, axis 1: prediction
|
||||
acc = np.diag(hist).sum() / hist.sum()
|
||||
acc_cls = np.diag(hist) / hist.sum(axis=1)
|
||||
acc_cls = np.nanmean(acc_cls)
|
||||
iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))
|
||||
mean_iu = np.nanmean(iu)
|
||||
freq = hist.sum(axis=1) / hist.sum()
|
||||
fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()
|
||||
return acc, acc_cls, mean_iu, fwavacc
|
||||
|
||||
|
||||
class AverageMeter(object):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.val = 0
|
||||
self.avg = 0
|
||||
self.sum = 0
|
||||
self.count = 0
|
||||
|
||||
def update(self, val, n=1):
|
||||
self.val = val
|
||||
self.sum += val * n
|
||||
self.count += n
|
||||
self.avg = self.sum / self.count
|
||||
|
||||
|
||||
class PolyLR(object):
|
||||
def __init__(self, optimizer, curr_iter, max_iter, lr_decay):
|
||||
self.max_iter = float(max_iter)
|
||||
self.init_lr_groups = []
|
||||
for p in optimizer.param_groups:
|
||||
self.init_lr_groups.append(p['lr'])
|
||||
self.param_groups = optimizer.param_groups
|
||||
self.curr_iter = curr_iter
|
||||
self.lr_decay = lr_decay
|
||||
|
||||
def step(self):
|
||||
for idx, p in enumerate(self.param_groups):
|
||||
p['lr'] = self.init_lr_groups[idx] * (1 - self.curr_iter / self.max_iter) ** self.lr_decay
|
||||
|
||||
|
||||
# just a try, not recommend to use
|
||||
class Conv2dDeformable(nn.Module):
|
||||
def __init__(self, regular_filter, cuda=True):
|
||||
super(Conv2dDeformable, self).__init__()
|
||||
assert isinstance(regular_filter, nn.Conv2d)
|
||||
self.regular_filter = regular_filter
|
||||
self.offset_filter = nn.Conv2d(regular_filter.in_channels, 2 * regular_filter.in_channels, kernel_size=3,
|
||||
padding=1, bias=False)
|
||||
self.offset_filter.weight.data.normal_(0, 0.0005)
|
||||
self.input_shape = None
|
||||
self.grid_w = None
|
||||
self.grid_h = None
|
||||
self.cuda = cuda
|
||||
|
||||
def forward(self, x):
|
||||
x_shape = x.size() # (b, c, h, w)
|
||||
offset = self.offset_filter(x) # (b, 2*c, h, w)
|
||||
offset_w, offset_h = torch.split(offset, self.regular_filter.in_channels, 1) # (b, c, h, w)
|
||||
offset_w = offset_w.contiguous().view(-1, int(x_shape[2]), int(x_shape[3])) # (b*c, h, w)
|
||||
offset_h = offset_h.contiguous().view(-1, int(x_shape[2]), int(x_shape[3])) # (b*c, h, w)
|
||||
if not self.input_shape or self.input_shape != x_shape:
|
||||
self.input_shape = x_shape
|
||||
grid_w, grid_h = np.meshgrid(np.linspace(-1, 1, x_shape[3]), np.linspace(-1, 1, x_shape[2])) # (h, w)
|
||||
grid_w = torch.Tensor(grid_w)
|
||||
grid_h = torch.Tensor(grid_h)
|
||||
if self.cuda:
|
||||
grid_w = grid_w.cuda()
|
||||
grid_h = grid_h.cuda()
|
||||
self.grid_w = nn.Parameter(grid_w)
|
||||
self.grid_h = nn.Parameter(grid_h)
|
||||
offset_w = offset_w + self.grid_w # (b*c, h, w)
|
||||
offset_h = offset_h + self.grid_h # (b*c, h, w)
|
||||
x = x.contiguous().view(-1, int(x_shape[2]), int(x_shape[3])).unsqueeze(1) # (b*c, 1, h, w)
|
||||
x = F.grid_sample(x, torch.stack((offset_h, offset_w), 3)) # (b*c, h, w)
|
||||
x = x.contiguous().view(-1, int(x_shape[1]), int(x_shape[2]), int(x_shape[3])) # (b, c, h, w)
|
||||
x = self.regular_filter(x)
|
||||
return x
|
||||
|
||||
|
||||
def sliced_forward(single_forward):
|
||||
def _pad(x, crop_size):
|
||||
h, w = x.size()[2:]
|
||||
pad_h = max(crop_size - h, 0)
|
||||
pad_w = max(crop_size - w, 0)
|
||||
x = F.pad(x, (0, pad_w, 0, pad_h))
|
||||
return x, pad_h, pad_w
|
||||
|
||||
def wrapper(self, x):
|
||||
batch_size, _, ori_h, ori_w = x.size()
|
||||
if self.training and self.use_aux:
|
||||
outputs_all_scales = Variable(torch.zeros((batch_size, self.num_classes, ori_h, ori_w))).cuda()
|
||||
aux_all_scales = Variable(torch.zeros((batch_size, self.num_classes, ori_h, ori_w))).cuda()
|
||||
for s in self.scales:
|
||||
new_size = (int(ori_h * s), int(ori_w * s))
|
||||
scaled_x = F.upsample(x, size=new_size, mode='bilinear')
|
||||
scaled_x = Variable(scaled_x).cuda()
|
||||
scaled_h, scaled_w = scaled_x.size()[2:]
|
||||
long_size = max(scaled_h, scaled_w)
|
||||
print(scaled_x.size())
|
||||
|
||||
if long_size > self.crop_size:
|
||||
count = torch.zeros((scaled_h, scaled_w))
|
||||
outputs = Variable(torch.zeros((batch_size, self.num_classes, scaled_h, scaled_w))).cuda()
|
||||
aux_outputs = Variable(torch.zeros((batch_size, self.num_classes, scaled_h, scaled_w))).cuda()
|
||||
stride = int(ceil(self.crop_size * self.stride_rate))
|
||||
h_step_num = int(ceil((scaled_h - self.crop_size) / stride)) + 1
|
||||
w_step_num = int(ceil((scaled_w - self.crop_size) / stride)) + 1
|
||||
for yy in range(h_step_num):
|
||||
for xx in range(w_step_num):
|
||||
sy, sx = yy * stride, xx * stride
|
||||
ey, ex = sy + self.crop_size, sx + self.crop_size
|
||||
x_sub = scaled_x[:, :, sy: ey, sx: ex]
|
||||
x_sub, pad_h, pad_w = _pad(x_sub, self.crop_size)
|
||||
print(x_sub.size())
|
||||
outputs_sub, aux_sub = single_forward(self, x_sub)
|
||||
|
||||
if sy + self.crop_size > scaled_h:
|
||||
outputs_sub = outputs_sub[:, :, : -pad_h, :]
|
||||
aux_sub = aux_sub[:, :, : -pad_h, :]
|
||||
|
||||
if sx + self.crop_size > scaled_w:
|
||||
outputs_sub = outputs_sub[:, :, :, : -pad_w]
|
||||
aux_sub = aux_sub[:, :, :, : -pad_w]
|
||||
|
||||
outputs[:, :, sy: ey, sx: ex] = outputs_sub
|
||||
aux_outputs[:, :, sy: ey, sx: ex] = aux_sub
|
||||
|
||||
count[sy: ey, sx: ex] += 1
|
||||
count = Variable(count).cuda()
|
||||
outputs = (outputs / count)
|
||||
aux_outputs = (outputs / count)
|
||||
else:
|
||||
scaled_x, pad_h, pad_w = _pad(scaled_x, self.crop_size)
|
||||
outputs, aux_outputs = single_forward(self, scaled_x)
|
||||
outputs = outputs[:, :, : -pad_h, : -pad_w]
|
||||
aux_outputs = aux_outputs[:, :, : -pad_h, : -pad_w]
|
||||
outputs_all_scales += outputs
|
||||
aux_all_scales += aux_outputs
|
||||
return outputs_all_scales / len(self.scales), aux_all_scales
|
||||
else:
|
||||
outputs_all_scales = Variable(torch.zeros((batch_size, self.num_classes, ori_h, ori_w))).cuda()
|
||||
for s in self.scales:
|
||||
new_size = (int(ori_h * s), int(ori_w * s))
|
||||
scaled_x = F.upsample(x, size=new_size, mode='bilinear')
|
||||
scaled_h, scaled_w = scaled_x.size()[2:]
|
||||
long_size = max(scaled_h, scaled_w)
|
||||
|
||||
if long_size > self.crop_size:
|
||||
count = torch.zeros((scaled_h, scaled_w))
|
||||
outputs = Variable(torch.zeros((batch_size, self.num_classes, scaled_h, scaled_w))).cuda()
|
||||
stride = int(ceil(self.crop_size * self.stride_rate))
|
||||
h_step_num = int(ceil((scaled_h - self.crop_size) / stride)) + 1
|
||||
w_step_num = int(ceil((scaled_w - self.crop_size) / stride)) + 1
|
||||
for yy in range(h_step_num):
|
||||
for xx in range(w_step_num):
|
||||
sy, sx = yy * stride, xx * stride
|
||||
ey, ex = sy + self.crop_size, sx + self.crop_size
|
||||
x_sub = scaled_x[:, :, sy: ey, sx: ex]
|
||||
x_sub, pad_h, pad_w = _pad(x_sub, self.crop_size)
|
||||
|
||||
outputs_sub = single_forward(self, x_sub)
|
||||
|
||||
if sy + self.crop_size > scaled_h:
|
||||
outputs_sub = outputs_sub[:, :, : -pad_h, :]
|
||||
|
||||
if sx + self.crop_size > scaled_w:
|
||||
outputs_sub = outputs_sub[:, :, :, : -pad_w]
|
||||
|
||||
outputs[:, :, sy: ey, sx: ex] = outputs_sub
|
||||
|
||||
count[sy: ey, sx: ex] += 1
|
||||
count = Variable(count).cuda()
|
||||
outputs = (outputs / count)
|
||||
else:
|
||||
scaled_x, pad_h, pad_w = _pad(scaled_x, self.crop_size)
|
||||
outputs = single_forward(self, scaled_x)
|
||||
outputs = outputs[:, :, : -pad_h, : -pad_w]
|
||||
outputs_all_scales += outputs
|
||||
return outputs_all_scales
|
||||
|
||||
return wrapper
|
||||
Loading…
Reference in new issue