ckyrkou commited on
Commit
10f9a52
·
verified ·
1 Parent(s): b00c9f5

Upload model.py

Browse files
Files changed (1) hide show
  1. model.py +344 -0
model.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.init as init
4
+ import math
5
+
6
+ # class Net(nn.Module):
7
+ # def __init__(self, upscale_factor):
8
+ # super(Net, self).__init__()
9
+ #
10
+ # self.relu = nn.ReLU()
11
+ # self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
12
+ # self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
13
+ # self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
14
+ # self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
15
+ # self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
16
+ #
17
+ # self._initialize_weights()
18
+ #
19
+ # def forward(self, x):
20
+ # x = self.relu(self.conv1(x))
21
+ # x = self.relu(self.conv2(x))
22
+ # x = self.relu(self.conv3(x))
23
+ # x = self.pixel_shuffle(self.conv4(x))
24
+ # return x
25
+ #
26
+ # def _initialize_weights(self):
27
+ # init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
28
+ # init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
29
+ # init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
30
+ # init.orthogonal_(self.conv4.weight)
31
+
32
+ # class Net(nn.Module):
33
+ # def __init__(self, upscale_factor=1):
34
+ # super(Net, self).__init__()
35
+ #
36
+ # self.relu = nn.ReLU()
37
+ # self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
38
+ # self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
39
+ # self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
40
+ # self.conv4 = nn.Conv2d(32, 3, (3, 3), (1, 1), (1, 1))
41
+ # #self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
42
+ # self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
43
+ #
44
+ # self._initialize_weights()
45
+ #
46
+ # def forward(self, x):
47
+ # x = self.relu(self.conv1(x))
48
+ # x = self.relu(self.conv2(x))
49
+ # x = self.upsample(self.relu(self.conv3(x)))
50
+ # x = self.relu(self.conv4(x))
51
+ # return x
52
+ #
53
+ # def _initialize_weights(self):
54
+ # init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
55
+ # init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
56
+ # init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
57
+ # init.orthogonal_(self.conv4.weight)
58
+
59
+ # class Net(nn.Module):
60
+ # def __init__(self, upscale_factor=1):
61
+ # super(Net, self).__init__()
62
+ #
63
+ # self.relu = nn.ReLU()
64
+ # self.conv1 = nn.Conv2d(3, 64, (5, 5), (1, 1), (2, 2))
65
+ # self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
66
+ # self.conv3 = nn.Conv2d(64, 128, (3, 3), (1, 1), (1, 1))
67
+ # self.conv4 = nn.Conv2d(128, 64, (3, 3), (1, 1), (1, 1))
68
+ # self.conv5 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
69
+ # self.conv6 = nn.Conv2d(32, 3, (3, 3), (1, 1), (1, 1))
70
+ # #self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
71
+ # self.upsample = nn.Upsample(scale_factor=2, mode='nearest')
72
+ #
73
+ # self._initialize_weights()
74
+ #
75
+ #
76
+ # def forward(self, x):
77
+ # x = self.relu(self.conv1(x))
78
+ # x = self.relu(self.conv2(x))
79
+ # x = self.upsample(self.relu(self.conv3(x)))
80
+ # x = self.relu(self.conv4(x))
81
+ # x = self.upsample(self.relu(self.conv5(x)))
82
+ # x = self.relu(self.conv6(x))
83
+ # return x
84
+ #
85
+ # def _initialize_weights(self):
86
+ # init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
87
+ # init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
88
+ # init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
89
+ # init.orthogonal_(self.conv4.weight, init.calculate_gain('relu'))
90
+ # init.orthogonal_(self.conv5.weight, init.calculate_gain('relu'))
91
+ # init.orthogonal_(self.conv6.weight, init.calculate_gain('relu'))
92
+
93
+ class block(nn.Module):
94
+ def __init__(self,channels_in,channels_out,kernel,stride,pad):
95
+ super(block, self).__init__()
96
+ self.conv = nn.Conv2d(channels_in, channels_out, kernel, stride, pad)
97
+ self.act = nn.LeakyReLU(0.1)
98
+ self.norm = nn.InstanceNorm2d(channels_out)
99
+
100
+ def forward(self, x):
101
+ x = self.conv(x)
102
+ #x = self.norm(x)
103
+ x = self.act(x)
104
+
105
+ return x
106
+
107
+ class SubPixelConvolutionalBlock(nn.Module):
108
+ """
109
+ A subpixel convolutional block, comprising convolutional, pixel-shuffle, and PReLU activation layers.
110
+ """
111
+
112
+ def __init__(self, kernel_size=3, n_channels=64, scaling_factor=2):
113
+ """
114
+ :param kernel_size: kernel size of the convolution
115
+ :param n_channels: number of input and output channels
116
+ :param scaling_factor: factor to scale input images by (along both dimensions)
117
+ """
118
+ super(SubPixelConvolutionalBlock, self).__init__()
119
+
120
+ # A convolutional layer that increases the number of channels by scaling factor^2, followed by pixel shuffle and PReLU
121
+ self.conv = nn.Conv2d(in_channels=n_channels, out_channels=n_channels * (scaling_factor ** 2),
122
+ kernel_size=kernel_size, padding=kernel_size // 2)
123
+ # These additional channels are shuffled to form additional pixels, upscaling each dimension by the scaling factor
124
+ self.pixel_shuffle = nn.PixelShuffle(upscale_factor=scaling_factor)
125
+ self.lrelu = nn.LeakyReLU(0.1)
126
+
127
+ def forward(self, input):
128
+ """
129
+ Forward propagation.
130
+
131
+ :param input: input images, a tensor of size (N, n_channels, w, h)
132
+ :return: scaled output images, a tensor of size (N, n_channels, w * scaling factor, h * scaling factor)
133
+ """
134
+ output = self.conv(input) # (N, n_channels * scaling factor^2, w, h)
135
+ output = self.pixel_shuffle(output) # (N, n_channels, w * scaling factor, h * scaling factor)
136
+ output = self.lrelu(output) # (N, n_channels, w * scaling factor, h * scaling factor)
137
+
138
+ return output
139
+
140
+ class Net(nn.Module):
141
+ def __init__(self, upscale_factor=1):
142
+ super(Net, self).__init__()
143
+
144
+ self.conv1 = block(3, 64, (7, 7), (1, 1), (3, 3))
145
+ self.conv2 = block(64, 64, (5, 5), (1, 1), (2, 2))
146
+ self.conv3 = block(64, 128, (5, 5), (1, 1), (2, 2))
147
+ self.conv4 = block(128, 256, (5, 5), (1, 1), (2, 2))
148
+ self.conv4_1 = block(256, 256, (5, 5), (1, 1), (2, 2))
149
+ self.conv5 = block(256, 128, (5, 5), (1, 1), (2, 2))
150
+ self.conv6 = block(128, 64, (3, 3), (1, 1), (1, 1))
151
+ self.conv7 = block(64, 32, (3, 3), (1, 1), (1, 1))
152
+ self.conv7_1 = block(32, 16, (3, 3), (1, 1), (1, 1))
153
+ self.conv8 = nn.Conv2d(16, 3, (1, 1), (1, 1), (0, 0))
154
+ #self.pixel_shuffle = nn.PixelShuffle(upscale_factor)
155
+ self.relu = nn.ReLU()
156
+ #self.upsample = nn.Upsample(scale_factor=2, mode='bicubic')
157
+ self.spc1 = SubPixelConvolutionalBlock( kernel_size=3, n_channels=128, scaling_factor=2)
158
+ #self.spc1 = nn.Upsample(scale_factor=2, mode='bicubic')
159
+ self.spc2 = SubPixelConvolutionalBlock( kernel_size=3, n_channels=128, scaling_factor=2)
160
+ #self.spc2 = nn.Upsample(scale_factor=2, mode='bicubic')
161
+
162
+ self.spc3 = SubPixelConvolutionalBlock(kernel_size=3, n_channels=128, scaling_factor=4)
163
+
164
+ #self._initialize_weights()
165
+
166
+ def forward(self, x):
167
+ x =self.conv1(x)
168
+ x = self.conv2(x)
169
+ x = self.conv3(x)
170
+ x = self.spc1(x)
171
+ x = self.conv4(x)
172
+ x = self.conv4_1(x)
173
+ x = self.conv5(x)
174
+ x = self.spc2(x)
175
+ x = self.conv6(x)
176
+ x = self.conv7(x)
177
+ x = self.conv7_1(x)
178
+ x = self.relu(self.conv8(x))
179
+ return x
180
+
181
+ def _initialize_weights(self):
182
+ init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
183
+ init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
184
+ init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
185
+ init.orthogonal_(self.conv4.weight, init.calculate_gain('relu'))
186
+ init.orthogonal_(self.conv4_1.weight, init.calculate_gain('relu'))
187
+ init.orthogonal_(self.conv5.weight, init.calculate_gain('relu'))
188
+ init.orthogonal_(self.conv6.weight, init.calculate_gain('relu'))
189
+ init.orthogonal_(self.conv7.weight, init.calculate_gain('relu'))
190
+ init.orthogonal_(self.conv7_1.weight, init.calculate_gain('relu'))
191
+ init.orthogonal_(self.conv8.weight, init.calculate_gain('relu'))
192
+
193
+
194
+
195
+
196
+
197
+ class ConvolutionalBlock(nn.Module):
198
+ """
199
+ A convolutional block, comprising convolutional, BN, activation layers.
200
+ """
201
+
202
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, batch_norm=False, activation=None):
203
+ """
204
+ :param in_channels: number of input channels
205
+ :param out_channels: number of output channe;s
206
+ :param kernel_size: kernel size
207
+ :param stride: stride
208
+ :param batch_norm: include a BN layer?
209
+ :param activation: Type of activation; None if none
210
+ """
211
+ super(ConvolutionalBlock, self).__init__()
212
+
213
+ if activation is not None:
214
+ activation = activation.lower()
215
+ assert activation in {'prelu', 'leakyrelu', 'tanh'}
216
+
217
+ # A container that will hold the layers in this convolutional block
218
+ layers = list()
219
+
220
+ # A convolutional layer
221
+ layers.append(
222
+ nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,
223
+ padding=kernel_size // 2))
224
+
225
+ # A batch normalization (BN) layer, if wanted
226
+ if batch_norm is True:
227
+ layers.append(nn.BatchNorm2d(num_features=out_channels))
228
+
229
+ # An activation layer, if wanted
230
+ if activation == 'prelu':
231
+ layers.append(nn.PReLU())
232
+ elif activation == 'leakyrelu':
233
+ layers.append(nn.LeakyReLU(0.2))
234
+ elif activation == 'tanh':
235
+ layers.append(nn.Tanh())
236
+
237
+ # Put together the convolutional block as a sequence of the layers in this container
238
+ self.conv_block = nn.Sequential(*layers)
239
+
240
+ def forward(self, input):
241
+ """
242
+ Forward propagation.
243
+
244
+ :param input: input images, a tensor of size (N, in_channels, w, h)
245
+ :return: output images, a tensor of size (N, out_channels, w, h)
246
+ """
247
+ output = self.conv_block(input) # (N, out_channels, w, h)
248
+
249
+ return output
250
+
251
+
252
+ class ResidualBlock(nn.Module):
253
+ """
254
+ A residual block, comprising two convolutional blocks with a residual connection across them.
255
+ """
256
+
257
+ def __init__(self, kernel_size=3, n_channels=64):
258
+ """
259
+ :param kernel_size: kernel size
260
+ :param n_channels: number of input and output channels (same because the input must be added to the output)
261
+ """
262
+ super(ResidualBlock, self).__init__()
263
+
264
+ # The first convolutional block
265
+ self.conv_block1 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels, kernel_size=kernel_size,
266
+ batch_norm=True, activation='PReLu')
267
+
268
+ # The second convolutional block
269
+ self.conv_block2 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels, kernel_size=kernel_size,
270
+ batch_norm=True, activation=None)
271
+
272
+ def forward(self, input):
273
+ """
274
+ Forward propagation.
275
+
276
+ :param input: input images, a tensor of size (N, n_channels, w, h)
277
+ :return: output images, a tensor of size (N, n_channels, w, h)
278
+ """
279
+ residual = input # (N, n_channels, w, h)
280
+ output = self.conv_block1(input) # (N, n_channels, w, h)
281
+ output = self.conv_block2(output) # (N, n_channels, w, h)
282
+ output = output + residual # (N, n_channels, w, h)
283
+
284
+ return output
285
+
286
+
287
+ class SRResNet(nn.Module):
288
+ """
289
+ The SRResNet, as defined in the paper.
290
+ """
291
+
292
+ def __init__(self, large_kernel_size=9, small_kernel_size=3, n_channels=64, n_blocks=16, scaling_factor=4):
293
+ """
294
+ :param large_kernel_size: kernel size of the first and last convolutions which transform the inputs and outputs
295
+ :param small_kernel_size: kernel size of all convolutions in-between, i.e. those in the residual and subpixel convolutional blocks
296
+ :param n_channels: number of channels in-between, i.e. the input and output channels for the residual and subpixel convolutional blocks
297
+ :param n_blocks: number of residual blocks
298
+ :param scaling_factor: factor to scale input images by (along both dimensions) in the subpixel convolutional block
299
+ """
300
+ super(SRResNet, self).__init__()
301
+
302
+ # Scaling factor must be 2, 4, or 8
303
+ scaling_factor = int(scaling_factor)
304
+ assert scaling_factor in {2, 4, 8}, "The scaling factor must be 2, 4, or 8!"
305
+
306
+ # The first convolutional block
307
+ self.conv_block1 = ConvolutionalBlock(in_channels=3, out_channels=n_channels, kernel_size=large_kernel_size,
308
+ batch_norm=False, activation='PReLu')
309
+
310
+ # A sequence of n_blocks residual blocks, each containing a skip-connection across the block
311
+ self.residual_blocks = nn.Sequential(
312
+ *[ResidualBlock(kernel_size=small_kernel_size, n_channels=n_channels) for i in range(n_blocks)])
313
+
314
+ # Another convolutional block
315
+ self.conv_block2 = ConvolutionalBlock(in_channels=n_channels, out_channels=n_channels,
316
+ kernel_size=small_kernel_size,
317
+ batch_norm=True, activation=None)
318
+
319
+ # Upscaling is done by sub-pixel convolution, with each such block upscaling by a factor of 2
320
+ n_subpixel_convolution_blocks = int(math.log2(scaling_factor))
321
+ self.subpixel_convolutional_blocks = nn.Sequential(
322
+ *[SubPixelConvolutionalBlock(kernel_size=small_kernel_size, n_channels=n_channels, scaling_factor=2) for i
323
+ in range(n_subpixel_convolution_blocks)])
324
+
325
+ # The last convolutional block
326
+ self.conv_block3 = ConvolutionalBlock(in_channels=n_channels, out_channels=3, kernel_size=large_kernel_size,
327
+ batch_norm=False, activation='Tanh')
328
+
329
+ def forward(self, lr_imgs):
330
+ """
331
+ Forward prop.
332
+
333
+ :param lr_imgs: low-resolution input images, a tensor of size (N, 3, w, h)
334
+ :return: super-resolution output images, a tensor of size (N, 3, w * scaling factor, h * scaling factor)
335
+ """
336
+ output = self.conv_block1(lr_imgs) # (N, 3, w, h)
337
+ residual = output # (N, n_channels, w, h)
338
+ output = self.residual_blocks(output) # (N, n_channels, w, h)
339
+ output = self.conv_block2(output) # (N, n_channels, w, h)
340
+ output = output + residual # (N, n_channels, w, h)
341
+ output = self.subpixel_convolutional_blocks(output) # (N, n_channels, w * scaling factor, h * scaling factor)
342
+ sr_imgs = self.conv_block3(output) # (N, 3, w * scaling factor, h * scaling factor)
343
+
344
+ return sr_imgs