SuyeonJ's picture
Upload folder using huggingface_hub
daac507 verified
import torch
import torch.nn as nn
from .blocks.warp import warp
from .blocks.raft import (
coords_grid,
SmallUpdateBlock, BidirCorrBlock, BasicUpdateBlock
)
from .blocks.feat_enc import (
SmallEncoder,
BasicEncoder,
LargeEncoder
)
from .blocks.ifrnet import (
resize,
Encoder,
InitDecoder,
IntermediateDecoder
)
from .blocks.multi_flow import (
multi_flow_combine,
MultiFlowDecoder
)
from ..components import register
from utils.padder import InputPadder
def photometric_consistency(img0, img1, flow01):
return (img0 - warp(img1, flow01)).abs().sum(dim=1, keepdims=True)
def flow_consistency(flow01, flow10):
return (flow01 + warp(flow10, flow01)).abs().sum(dim=1, keepdims=True)
gaussian_kernel = torch.tensor([[1, 2, 1],
[2, 4, 2],
[1, 2, 1]]) / 16
gaussian_kernel = gaussian_kernel.repeat(2, 1, 1, 1)
gaussian_kernel = gaussian_kernel.to("cpu")#torch.cuda.current_device())
def gaussian(x):
x = torch.nn.functional.pad(x, (1, 1, 1, 1), mode='reflect')
out = torch.nn.functional.conv2d(x, gaussian_kernel, groups=x.shape[1])
# out = TF.gaussian_blur(x, [3, 3], sigma=[2, 2])
return out
def variance_flow(flow):
flow = flow * torch.tensor(data=[2.0 / (flow.shape[3] - 1.0), 2.0 / (flow.shape[2] - 1.0)], dtype=flow.dtype,
device=flow.device).view(1, 2, 1, 1)
return (gaussian(flow ** 2) - gaussian(flow) ** 2 + 1e-4).sqrt().abs().sum(dim=1, keepdim=True)
@register('amt_splat')
class Model(nn.Module):
def __init__(self,
model_size='S',
corr_radius=3,
corr_lvls=4,
num_flows=3,
channels=[20, 32, 44, 56],
skip_channels=20,
scale_factor=1):
super(Model, self).__init__()
self.model_size = model_size
self.radius = corr_radius
self.corr_levels = corr_lvls
self.num_flows = num_flows
self.channels = channels
self.skip_channels = skip_channels
self.scale_factor = scale_factor
if self.model_size == 'S':
self.feat_encoder = SmallEncoder(output_dim=84, norm_fn='instance', dropout=0.)
elif self.model_size == 'L':
self.feat_encoder = BasicEncoder(output_dim=128, norm_fn='instance', dropout=0.)
elif self.model_size == 'G':
self.feat_encoder = LargeEncoder(output_dim=128, norm_fn='instance', dropout=0.)
self.encoder = Encoder(channels, large=True)
# self.decoder4 = InitDecoder(channels[3], channels[2], skip_channels)
self.decoder3 = IntermediateDecoder(channels[2], channels[1], skip_channels)
self.decoder2 = IntermediateDecoder(channels[1] * 2, channels[0], skip_channels)
self.decoder1 = MultiFlowDecoder(channels[0] * 2, skip_channels, num_flows)
self.update4 = self._get_updateblock(channels[2])
self.update3_low = self._get_updateblock(channels[1] * 2, 2)
self.update2_low = self._get_updateblock(channels[0] * 2, 4)
if self.model_size == 'G':
self.update3_high = self._get_updateblock(channels[1] * 2, None)
self.update2_high = self._get_updateblock(channels[0] * 2, None)
# self.alpha = torch.nn.Parameter(torch.ones(1, 1, 1, 1))
# self.alpha_splat_photo_consistency = torch.nn.Parameter(torch.ones(1, 1, 1, 1))
# self.alpha_splat_flow_consistency = torch.nn.Parameter(torch.ones(1, 1, 1, 1))
# self.alpha_splat_variation_flow = torch.nn.Parameter(torch.ones(1, 1, 1, 1))
# self.comb_block = nn.Sequential(
# nn.Conv2d(3 * self.num_flows, 6 * self.num_flows, 7, 1, 3),
# nn.PReLU(6 * self.num_flows),
# nn.Conv2d(6 * self.num_flows, 3, 7, 1, 3),
# )
def _get_updateblock(self, cdim, scale_factor=None):
return BasicUpdateBlock(cdim=cdim, hidden_dim=192, flow_dim=64,
corr_dim=256, corr_dim2=192, fc_dim=188,
scale_factor=scale_factor, corr_levels=self.corr_levels,
radius=self.radius)
def _corr_scale_lookup(self, corr_fn, coord, flow_fwd, flow_bwd, embt, downsample=1):
# convert t -> 0 to 0 -> 1 | convert t -> 1 to 1 -> 0
# based on linear assumption
t1_scale = 1. / embt
t0_scale = 1. / (1. - embt)
if downsample != 1:
inv = 1 / downsample
flow_fwd = inv * resize(flow_fwd, scale_factor=inv)
flow_bwd = inv * resize(flow_bwd, scale_factor=inv)
corr_fwd, corr_bwd = corr_fn(coord + flow_fwd, coord + flow_bwd)
return corr_fwd, corr_bwd, flow_fwd, flow_bwd
def get_splat_weight(self, img0, img1, flow01, flow10):
M_splat = 1 / (1 + self.alpha_splat_photo_consistency * photometric_consistency(img0, img1, flow01).detach()) + \
1 / (1 + self.alpha_splat_flow_consistency * flow_consistency(flow01, flow10).detach()) + \
1 / (1 + self.alpha_splat_variation_flow * variance_flow(flow01).detach())
return M_splat * self.alpha
def forward(self, img0, img1, time_step, scale_factor=1.0, eval=False, **kwargs):
scale_factor = self.scale_factor
padder = InputPadder(img0.shape, divisor=int(16 / scale_factor))
img0, img1 = padder.pad(img0, img1)
mean_ = torch.cat([img0, img1], 2).mean(1, keepdim=True).mean(2, keepdim=True).mean(3, keepdim=True)
img0 = img0 - mean_
img1 = img1 - mean_
img0_ = resize(img0, scale_factor) if scale_factor != 1.0 else img0
img1_ = resize(img1, scale_factor) if scale_factor != 1.0 else img1
b, _, h, w = img0_.shape
coords = coords_grid(b, h // 8, w // 8, img0.device)
flow_fwd_4, flow_bwd_4 = torch.zeros(b, 2, h // 8, w // 8), torch.zeros(b, 2, h // 8, w // 8)#.cuda()#.cuda(), torch.zeros(b, 2, h // 8, w // 8)#.cuda()
fmap0, fmap1 = self.feat_encoder([img0_, img1_]) # [1, 128, H//8, W//8]
corr_fn = BidirCorrBlock(fmap0, fmap1, radius=self.radius, num_levels=self.corr_levels)
# f0_1: [1, c0, H//2, W//2] | f0_2: [1, c1, H//4, W//4]
# f0_3: [1, c2, H//8, W//8] | f0_4: [1, c3, H//16, W//16]
f0_1, f0_2, f0_3 = self.encoder(img0_)
f1_1, f1_2, f1_3 = self.encoder(img1_)
######################################### the 4th decoder #########################################
corr_fwd_4, corr_bwd_4, _, _ = self._corr_scale_lookup(corr_fn, coords, flow_fwd_4, flow_bwd_4, time_step)
# residue update with lookup corr
delta_f0_3_, delta_flow_fwd_4 = self.update4(f0_3, flow_fwd_4, corr_fwd_4)
delta_f1_3_, delta_flow_bwd_4 = self.update4(f0_3, flow_bwd_4, corr_bwd_4)
up_f0_3 = f0_3 + delta_f0_3_
up_f1_3 = f1_3 + delta_f1_3_
flow_fwd_4 = flow_fwd_4 + delta_flow_fwd_4
flow_bwd_4 = flow_bwd_4 + delta_flow_bwd_4
######################################### the 3rd decoder #########################################
flow_fwd_3, flow_bwd_3, f0_2_, f1_2_ = self.decoder3(up_f0_3, up_f1_3, flow_fwd_4, flow_bwd_4)
corr_fwd_3, corr_bwd_3, flow_fwd_3_, flow_bwd_3_ = self._corr_scale_lookup(corr_fn,
coords, flow_fwd_3, flow_bwd_3,
time_step, downsample=2)
# residue update with lookup corr
f0_2 = torch.cat([f0_2, f0_2_], dim=1)
f1_2 = torch.cat([f1_2, f1_2_], dim=1)
delta_f0_2_, delta_flow_fwd_3 = self.update3_low(f0_2, flow_fwd_3_, corr_fwd_3)
delta_f1_2_, delta_flow_bwd_3 = self.update3_low(f1_2, flow_bwd_3_, corr_bwd_3)
f0_2 = f0_2 + delta_f0_2_
f1_2 = f1_2 + delta_f1_2_
flow_fwd_3 = flow_fwd_3 + delta_flow_fwd_3
flow_bwd_3 = flow_bwd_3 + delta_flow_bwd_3
if self.model_size == 'G':
# residue update with lookup corr (hr)
corr_fwd_3 = resize(corr_fwd_3, scale_factor=2.0)
corr_bwd_3 = resize(corr_bwd_3, scale_factor=2.0)
delta_f0_2_, delta_flow_fwd_3 = self.update3_high(f0_2, flow_fwd_3, corr_fwd_3)
delta_f1_2_, delta_flow_bwd_3 = self.update3_high(f1_2, flow_bwd_3, corr_bwd_3)
up_f0_2 = f0_2 + delta_f0_2_
up_f1_2 = f1_2 + delta_f1_2_
flow_fwd_3 = flow_fwd_3 + delta_flow_fwd_3
flow_bwd_3 = flow_bwd_3 + delta_flow_bwd_3
######################################### the 2nd decoder #########################################
flow_fwd_2, flow_bwd_2, f0_1_, f1_1_ = self.decoder2(up_f0_2, up_f1_2, flow_fwd_3, flow_bwd_3)
corr_fwd_2, corr_bwd_2, flow_fwd_2_, flow_bwd_2_ = self._corr_scale_lookup(corr_fn,
coords, flow_fwd_2, flow_bwd_2,
time_step, downsample=4)
# residue update with lookup corr
f0_1 = torch.cat([f0_1, f0_1_], dim=1)
f1_1 = torch.cat([f1_1, f1_1_], dim=1)
delta_f0_1_, delta_flow_fwd_2 = self.update2_low(f0_1, flow_fwd_2_, corr_fwd_2)
delta_f1_1_, delta_flow_bwd_2 = self.update2_low(f1_1, flow_bwd_2_, corr_bwd_2)
f0_1 = f0_1 + delta_f0_1_
f1_1 = f1_1 + delta_f1_1_
flow_fwd_2 = flow_fwd_2 + delta_flow_fwd_2
flow_bwd_2 = flow_bwd_2 + delta_flow_bwd_2
if self.model_size == 'G':
# residue update with lookup corr (hr)
corr_fwd_2 = resize(corr_fwd_2, scale_factor=4.0)
corr_bwd_2 = resize(corr_bwd_2, scale_factor=4.0)
delta_f0_1_, delta_flow_fwd_2 = self.update2_high(f0_1, flow_fwd_2, corr_fwd_2)
delta_f1_1_, delta_flow_bwd_2 = self.update2_high(f1_1, flow_bwd_2, corr_bwd_2)
f0_1 = f0_1 + delta_f0_1_
f1_1 = f1_1 + delta_f1_1_
flow_fwd_2 = flow_fwd_2 + delta_flow_fwd_2
flow_bwd_2 = flow_bwd_2 + delta_flow_bwd_2
######################################### the 1st decoder #########################################
flow_fwd_1, flow_bwd_1, mask_fwd, mask_bwd = self.decoder1(f0_1, f1_1, flow_fwd_2, flow_bwd_2)
if scale_factor != 1.0:
flow_fwd_1 = resize(flow_fwd_1, scale_factor=(1.0 / scale_factor)) * (1.0 / scale_factor)
flow_bwd_1 = resize(flow_bwd_1, scale_factor=(1.0 / scale_factor)) * (1.0 / scale_factor)
mask_fwd = resize(mask_fwd, scale_factor=(1.0 / scale_factor))
mask_bwd = resize(mask_bwd, scale_factor=(1.0 / scale_factor))
# Merge multiple predictions
# img0_ = img0.repeat(1, self.num_flows, 1, 1).view(b * self.num_flows, h, w)
# img1_ = img1.repeat(1, self.num_flows, 1, 1).view(b * self.num_flows, h, w)
# metric0 = self.get_splat_weight(img0_, img1_, flow_fwd_1_, flow_bwd_1_)
# metric1 = self.get_splat_weight(img1_, img0_, flow_bwd_1_, flow_fwd_1_)
imgt_pred = multi_flow_combine(img0, img1, flow_fwd_1, flow_bwd_1,
mask_fwd, mask_bwd, time_step, mean_)
imgt_pred = torch.clamp(imgt_pred, 0, 1)
imgt_pred = padder.unpad(imgt_pred)
if eval:
return {'imgt_pred': imgt_pred, }
else:
flow_fwd_1 = flow_fwd_1.reshape(b, self.num_flows, 2, int(h / scale_factor), int(w / scale_factor))
flow_bwd_1 = flow_bwd_1.reshape(b, self.num_flows, 2, int(h / scale_factor), int(w / scale_factor))
return {
'imgt_pred': imgt_pred,
'flow0_pred': [flow_fwd_1 * 0.5, flow_fwd_2 * 0.5, flow_fwd_3 * 0.5, flow_fwd_4 * 0.5],
'flow1_pred': [flow_bwd_1 * 0.5, flow_bwd_2 * 0.5, flow_bwd_3 * 0.5, flow_bwd_4 * 0.5],
'flowfwd': flow_fwd_1[:, 0] * 0.5,
'flowbwd': flow_bwd_1[:, 0] * 0.5
}