sid385 commited on
Commit
21d5f99
·
1 Parent(s): 807f26f

feat: port RIFE architectures and modify for 1-channel TIR

Browse files
Files changed (3) hide show
  1. src/model/ifnet.py +176 -0
  2. src/model/refine.py +147 -0
  3. src/model/warplayer.py +22 -0
src/model/ifnet.py CHANGED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ from src.model.refine import *
6
+ from src.model.warplayer import warp
7
+
8
+
9
+ def deconv(in_planes, out_planes, kernel_size=4, stride=2, padding=1):
10
+ return nn.Sequential(
11
+ torch.nn.ConvTranspose2d(
12
+ in_channels=in_planes,
13
+ out_channels=out_planes,
14
+ kernel_size=4,
15
+ stride=2,
16
+ padding=1,
17
+ ),
18
+ nn.PReLU(out_planes),
19
+ )
20
+
21
+
22
+ def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1):
23
+ return nn.Sequential(
24
+ nn.Conv2d(
25
+ in_planes,
26
+ out_planes,
27
+ kernel_size=kernel_size,
28
+ stride=stride,
29
+ padding=padding,
30
+ dilation=dilation,
31
+ bias=True,
32
+ ),
33
+ nn.PReLU(out_planes),
34
+ )
35
+
36
+
37
+ class IFBlock(nn.Module):
38
+ def __init__(self, in_planes, c=64):
39
+ super(IFBlock, self).__init__()
40
+ self.conv0 = nn.Sequential(
41
+ conv(in_planes, c // 2, 3, 2, 1),
42
+ conv(c // 2, c, 3, 2, 1),
43
+ )
44
+ self.convblock = nn.Sequential(
45
+ conv(c, c),
46
+ conv(c, c),
47
+ conv(c, c),
48
+ conv(c, c),
49
+ conv(c, c),
50
+ conv(c, c),
51
+ conv(c, c),
52
+ conv(c, c),
53
+ )
54
+ self.lastconv = nn.ConvTranspose2d(c, 5, 4, 2, 1)
55
+
56
+ def forward(self, x, flow, scale):
57
+ if scale != 1:
58
+ x = F.interpolate(
59
+ x, scale_factor=1.0 / scale, mode="bilinear", align_corners=False
60
+ )
61
+ if flow != None:
62
+ flow = (
63
+ F.interpolate(
64
+ flow, scale_factor=1.0 / scale, mode="bilinear", align_corners=False
65
+ )
66
+ * 1.0
67
+ / scale
68
+ )
69
+ x = torch.cat((x, flow), 1)
70
+ x = self.conv0(x)
71
+ x = self.convblock(x) + x
72
+ tmp = self.lastconv(x)
73
+ tmp = F.interpolate(
74
+ tmp, scale_factor=scale * 2, mode="bilinear", align_corners=False
75
+ )
76
+ flow = tmp[:, :4] * scale * 2
77
+ mask = tmp[:, 4:5]
78
+ return flow, mask
79
+
80
+
81
+ class IFNet(nn.Module):
82
+ def __init__(self):
83
+ super(IFNet, self).__init__()
84
+ # 1-channel Grayscale (TIR) ke hisaab se updated channels
85
+ self.block0 = IFBlock(9, c=240)
86
+ self.block1 = IFBlock(9 + 4, c=150)
87
+ self.block2 = IFBlock(9 + 4, c=90)
88
+ self.block_tea = IFBlock(6 + 4, c=90)
89
+ self.contextnet = Contextnet()
90
+ self.unet = Unet()
91
+
92
+ def forward(self, x, scale=[4, 2, 1], timestep=0.5):
93
+ # 1-channel slicing
94
+ img0 = x[:, 0:1]
95
+ img1 = x[:, 1:2]
96
+ gt = x[:, 2:]
97
+
98
+ flow_list = []
99
+ merged = []
100
+ mask_list = []
101
+ warped_img0 = img0
102
+ warped_img1 = img1
103
+ flow = None
104
+ loss_distill = 0
105
+ stu = [self.block0, self.block1, self.block2]
106
+
107
+ for i in range(3):
108
+ if flow != None:
109
+ flow_d, mask_d = stu[i](
110
+ torch.cat((img0, img1, warped_img0, warped_img1, mask), 1),
111
+ flow,
112
+ scale=scale[i],
113
+ )
114
+ flow = flow + flow_d
115
+ mask = mask + mask_d
116
+ else:
117
+ flow, mask = stu[i](torch.cat((img0, img1), 1), None, scale=scale[i])
118
+ mask_list.append(torch.sigmoid(mask))
119
+ flow_list.append(flow)
120
+ warped_img0 = warp(img0, flow[:, :2])
121
+ warped_img1 = warp(img1, flow[:, 2:4])
122
+ merged_student = (warped_img0, warped_img1)
123
+ merged.append(merged_student)
124
+
125
+ # Teacher model condition updated for 1-channel GT
126
+ if gt.shape[1] == 1:
127
+ flow_d, mask_d = self.block_tea(
128
+ torch.cat((img0, img1, warped_img0, warped_img1, mask, gt), 1),
129
+ flow,
130
+ scale=1,
131
+ )
132
+ flow_teacher = flow + flow_d
133
+ warped_img0_teacher = warp(img0, flow_teacher[:, :2])
134
+ warped_img1_teacher = warp(img1, flow_teacher[:, 2:4])
135
+ mask_teacher = torch.sigmoid(mask + mask_d)
136
+ merged_teacher = (
137
+ warped_img0_teacher * mask_teacher
138
+ + warped_img1_teacher * (1 - mask_teacher)
139
+ )
140
+ else:
141
+ flow_teacher = None
142
+ merged_teacher = None
143
+
144
+ for i in range(3):
145
+ merged[i] = merged[i][0] * mask_list[i] + merged[i][1] * (1 - mask_list[i])
146
+ if gt.shape[1] == 1:
147
+ loss_mask = (
148
+ (
149
+ (merged[i] - gt).abs().mean(1, True)
150
+ > (merged_teacher - gt).abs().mean(1, True) + 0.01
151
+ )
152
+ .float()
153
+ .detach()
154
+ )
155
+ loss_distill += (
156
+ ((flow_teacher.detach() - flow_list[i]) ** 2).mean(1, True) ** 0.5
157
+ * loss_mask
158
+ ).mean()
159
+
160
+ c0 = self.contextnet(img0, flow[:, :2])
161
+ c1 = self.contextnet(img1, flow[:, 2:4])
162
+ tmp = self.unet(img0, img1, warped_img0, warped_img1, mask, flow, c0, c1)
163
+
164
+ # UNet output se sirf 1 channel nikalna
165
+ res = tmp[:, :1] * 2 - 1
166
+ merged[2] = torch.clamp(merged[2] + res, 0, 1)
167
+
168
+ return (
169
+ flow_list,
170
+ mask_list[2],
171
+ merged,
172
+ flow_teacher,
173
+ merged_teacher,
174
+ loss_distill,
175
+ )
176
+
src/model/refine.py CHANGED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import itertools
2
+
3
+ import numpy as np
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ import torch.optim as optim
8
+
9
+ from model.warplayer import warp
10
+
11
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
+
13
+
14
+ def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1):
15
+ return nn.Sequential(
16
+ nn.Conv2d(
17
+ in_planes,
18
+ out_planes,
19
+ kernel_size=kernel_size,
20
+ stride=stride,
21
+ padding=padding,
22
+ dilation=dilation,
23
+ bias=True,
24
+ ),
25
+ nn.PReLU(out_planes),
26
+ )
27
+
28
+
29
+ def deconv(in_planes, out_planes, kernel_size=4, stride=2, padding=1):
30
+ return nn.Sequential(
31
+ torch.nn.ConvTranspose2d(
32
+ in_channels=in_planes,
33
+ out_channels=out_planes,
34
+ kernel_size=4,
35
+ stride=2,
36
+ padding=1,
37
+ bias=True,
38
+ ),
39
+ nn.PReLU(out_planes),
40
+ )
41
+
42
+
43
+ class Conv2(nn.Module):
44
+ def __init__(self, in_planes, out_planes, stride=2):
45
+ super(Conv2, self).__init__()
46
+ self.conv1 = conv(in_planes, out_planes, 3, stride, 1)
47
+ self.conv2 = conv(out_planes, out_planes, 3, 1, 1)
48
+
49
+ def forward(self, x):
50
+ x = self.conv1(x)
51
+ x = self.conv2(x)
52
+ return x
53
+
54
+
55
+ c = 16
56
+
57
+
58
+ class Contextnet(nn.Module):
59
+ def __init__(self):
60
+ super(Contextnet, self).__init__()
61
+ # --- CHANGE 1: 3 channels (RGB) ki jagah 1 channel (TIR) ---
62
+ self.conv1 = Conv2(1, c)
63
+ self.conv2 = Conv2(c, 2 * c)
64
+ self.conv3 = Conv2(2 * c, 4 * c)
65
+ self.conv4 = Conv2(4 * c, 8 * c)
66
+
67
+ def forward(self, x, flow):
68
+ x = self.conv1(x)
69
+ flow = (
70
+ F.interpolate(
71
+ flow,
72
+ scale_factor=0.5,
73
+ mode="bilinear",
74
+ align_corners=False,
75
+ recompute_scale_factor=False,
76
+ )
77
+ * 0.5
78
+ )
79
+ f1 = warp(x, flow)
80
+ x = self.conv2(x)
81
+ flow = (
82
+ F.interpolate(
83
+ flow,
84
+ scale_factor=0.5,
85
+ mode="bilinear",
86
+ align_corners=False,
87
+ recompute_scale_factor=False,
88
+ )
89
+ * 0.5
90
+ )
91
+ f2 = warp(x, flow)
92
+ x = self.conv3(x)
93
+ flow = (
94
+ F.interpolate(
95
+ flow,
96
+ scale_factor=0.5,
97
+ mode="bilinear",
98
+ align_corners=False,
99
+ recompute_scale_factor=False,
100
+ )
101
+ * 0.5
102
+ )
103
+ f3 = warp(x, flow)
104
+ x = self.conv4(x)
105
+ flow = (
106
+ F.interpolate(
107
+ flow,
108
+ scale_factor=0.5,
109
+ mode="bilinear",
110
+ align_corners=False,
111
+ recompute_scale_factor=False,
112
+ )
113
+ * 0.5
114
+ )
115
+ f4 = warp(x, flow)
116
+ return [f1, f2, f3, f4]
117
+
118
+
119
+ class Unet(nn.Module):
120
+ def __init__(self):
121
+ super(Unet, self).__init__()
122
+ # --- CHANGE 2: 17 channels ki jagah 9 channels ---
123
+ self.down0 = Conv2(9, 2 * c)
124
+ self.down1 = Conv2(4 * c, 4 * c)
125
+ self.down2 = Conv2(8 * c, 8 * c)
126
+ self.down3 = Conv2(16 * c, 16 * c)
127
+ self.up0 = deconv(32 * c, 8 * c)
128
+ self.up1 = deconv(16 * c, 4 * c)
129
+ self.up2 = deconv(8 * c, 2 * c)
130
+ self.up3 = deconv(4 * c, c)
131
+ # --- CHANGE 3: Output 3 channels ki jagah 1 channel ---
132
+ self.conv = nn.Conv2d(c, 1, 3, 1, 1)
133
+
134
+ def forward(self, img0, img1, warped_img0, warped_img1, mask, flow, c0, c1):
135
+ s0 = self.down0(
136
+ torch.cat((img0, img1, warped_img0, warped_img1, mask, flow), 1)
137
+ )
138
+ s1 = self.down1(torch.cat((s0, c0[0], c1[0]), 1))
139
+ s2 = self.down2(torch.cat((s1, c0[1], c1[1]), 1))
140
+ s3 = self.down3(torch.cat((s2, c0[2], c1[2]), 1))
141
+ x = self.up0(torch.cat((s3, c0[3], c1[3]), 1))
142
+ x = self.up1(torch.cat((x, s2), 1))
143
+ x = self.up2(torch.cat((x, s1), 1))
144
+ x = self.up3(torch.cat((x, s0), 1))
145
+ x = self.conv(x)
146
+ return torch.sigmoid(x)
147
+
src/model/warplayer.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
5
+ backwarp_tenGrid = {}
6
+
7
+
8
+ def warp(tenInput, tenFlow):
9
+ k = (str(tenFlow.device), str(tenFlow.size()))
10
+ if k not in backwarp_tenGrid:
11
+ tenHorizontal = torch.linspace(-1.0, 1.0, tenFlow.shape[3], device=device).view(
12
+ 1, 1, 1, tenFlow.shape[3]).expand(tenFlow.shape[0], -1, tenFlow.shape[2], -1)
13
+ tenVertical = torch.linspace(-1.0, 1.0, tenFlow.shape[2], device=device).view(
14
+ 1, 1, tenFlow.shape[2], 1).expand(tenFlow.shape[0], -1, -1, tenFlow.shape[3])
15
+ backwarp_tenGrid[k] = torch.cat(
16
+ [tenHorizontal, tenVertical], 1).to(device)
17
+
18
+ tenFlow = torch.cat([tenFlow[:, 0:1, :, :] / ((tenInput.shape[3] - 1.0) / 2.0),
19
+ tenFlow[:, 1:2, :, :] / ((tenInput.shape[2] - 1.0) / 2.0)], 1)
20
+
21
+ g = (backwarp_tenGrid[k] + tenFlow).permute(0, 2, 3, 1)
22
+ return torch.nn.functional.grid_sample(input=tenInput, grid=g, mode='bilinear', padding_mode='border', align_corners=True)