Skip to content

Instantly share code, notes, and snippets.

@MarcoForte
Created May 6, 2020 21:50
Show Gist options
  • Save MarcoForte/a07c40a2b721739bb5c5987671aa5270 to your computer and use it in GitHub Desktop.
Save MarcoForte/a07c40a2b721739bb5c5987671aa5270 to your computer and use it in GitHub Desktop.
laplacian loss used in fba matting
########################
# https://gist.github.com/alper111/b9c6d80e2dba1ee0bfac15eb7dad09c8
def gauss_kernel(size=5, device=torch.device('cpu'), channels=3):
kernel = torch.tensor([[1., 4., 6., 4., 1],
[4., 16., 24., 16., 4.],
[6., 24., 36., 24., 6.],
[4., 16., 24., 16., 4.],
[1., 4., 6., 4., 1.]])
kernel /= 256.
kernel = kernel.repeat(channels, 1, 1, 1)
kernel = kernel.to(device)
return kernel
def downsample(x):
return x[:, :, ::2, ::2]
def upsample(x):
cc = torch.cat([x, torch.zeros(x.shape[0], x.shape[1], x.shape[2], x.shape[3], device=x.device)], dim=3)
cc = cc.view(x.shape[0], x.shape[1], x.shape[2] * 2, x.shape[3])
cc = cc.permute(0, 1, 3, 2)
# cc = torch.cat([cc, torch.zeros(x.shape[0], x.shape[1], x.shape[2], x.shape[3] * 2, device=x.device)], dim=3)
# cc = cc.view(x.shape[0], x.shape[1], x.shape[2] * 2, x.shape[3] * 2)
cc = torch.cat([cc, torch.zeros(x.shape[0], x.shape[1], x.shape[3], x.shape[2] * 2, device=x.device)], dim=3)
cc = cc.view(x.shape[0], x.shape[1], x.shape[3] * 2, x.shape[2] * 2)
x_up = cc.permute(0, 1, 3, 2)
return conv_gauss(x_up, 4 * gauss_kernel(channels=x.shape[1], device=x.device))
def conv_gauss(img, kernel):
img = torch.nn.functional.pad(img, (2, 2, 2, 2), mode='reflect')
out = torch.nn.functional.conv2d(img, kernel, groups=img.shape[1])
return out
def laplacian_pyramid(img, kernel, max_levels=3):
current = img
pyr = []
for level in range(max_levels):
filtered = conv_gauss(current, kernel)
down = downsample(filtered)
up = upsample(down)
diff = current - up
pyr.append(diff)
current = down
return pyr
def weight_pyramid(img, max_levels=3):
current = img
pyr = []
for level in range(max_levels):
down = downsample(current)
pyr.append(current)
current = down
return pyr
class LapLoss(torch.nn.Module):
def __init__(self, max_levels=5, channels=1, device=torch.device('cuda')):
super(LapLoss, self).__init__()
self.max_levels = max_levels
self.gauss_kernel = gauss_kernel(channels=channels, device=device)
def forward(self, input, target, weight):
pyr_input = laplacian_pyramid(img=input, kernel=self.gauss_kernel, max_levels=self.max_levels)
pyr_target = laplacian_pyramid(img=target, kernel=self.gauss_kernel, max_levels=self.max_levels)
pyr_weight = weight_pyramid(img=weight, max_levels=self.max_levels)
# return sum(L1_loss(a, b, c) for a, b, c in zip(pyr_input, pyr_target,pyr_weight))
return sum(L1_loss(A[0], A[1], A[2]) * (2**(i)) for i, A in enumerate(zip(pyr_input, pyr_target, pyr_weight)))
###########################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment