lixiang46 commited on
Commit
a64b7d4
β€’
1 Parent(s): 91bcacf

fix basicsr bug

Browse files
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. basicsr/__init__.py +12 -0
  2. basicsr/archs/__init__.py +24 -0
  3. basicsr/archs/arch_util.py +313 -0
  4. basicsr/archs/basicvsr_arch.py +336 -0
  5. basicsr/archs/basicvsrpp_arch.py +417 -0
  6. basicsr/archs/dfdnet_arch.py +169 -0
  7. basicsr/archs/dfdnet_util.py +162 -0
  8. basicsr/archs/discriminator_arch.py +150 -0
  9. basicsr/archs/duf_arch.py +276 -0
  10. basicsr/archs/ecbsr_arch.py +275 -0
  11. basicsr/archs/edsr_arch.py +61 -0
  12. basicsr/archs/edvr_arch.py +382 -0
  13. basicsr/archs/hifacegan_arch.py +260 -0
  14. basicsr/archs/hifacegan_util.py +255 -0
  15. basicsr/archs/inception.py +307 -0
  16. basicsr/archs/rcan_arch.py +135 -0
  17. basicsr/archs/ridnet_arch.py +180 -0
  18. basicsr/archs/rrdbnet_arch.py +119 -0
  19. basicsr/archs/spynet_arch.py +96 -0
  20. basicsr/archs/srresnet_arch.py +65 -0
  21. basicsr/archs/srvgg_arch.py +70 -0
  22. basicsr/archs/stylegan2_arch.py +799 -0
  23. basicsr/archs/stylegan2_bilinear_arch.py +614 -0
  24. basicsr/archs/swinir_arch.py +956 -0
  25. basicsr/archs/tof_arch.py +172 -0
  26. basicsr/archs/vgg_arch.py +161 -0
  27. basicsr/data/__init__.py +101 -0
  28. basicsr/data/data_sampler.py +48 -0
  29. basicsr/data/data_util.py +315 -0
  30. basicsr/data/degradations.py +764 -0
  31. basicsr/data/ffhq_dataset.py +80 -0
  32. basicsr/data/meta_info/meta_info_DIV2K800sub_GT.txt +0 -0
  33. basicsr/data/meta_info/meta_info_REDS4_test_GT.txt +4 -0
  34. basicsr/data/meta_info/meta_info_REDS_GT.txt +270 -0
  35. basicsr/data/meta_info/meta_info_REDSofficial4_test_GT.txt +4 -0
  36. basicsr/data/meta_info/meta_info_REDSval_official_test_GT.txt +30 -0
  37. basicsr/data/meta_info/meta_info_Vimeo90K_test_GT.txt +0 -0
  38. basicsr/data/meta_info/meta_info_Vimeo90K_test_fast_GT.txt +1225 -0
  39. basicsr/data/meta_info/meta_info_Vimeo90K_test_medium_GT.txt +0 -0
  40. basicsr/data/meta_info/meta_info_Vimeo90K_test_slow_GT.txt +1613 -0
  41. basicsr/data/meta_info/meta_info_Vimeo90K_train_GT.txt +0 -0
  42. basicsr/data/paired_image_dataset.py +106 -0
  43. basicsr/data/prefetch_dataloader.py +122 -0
  44. basicsr/data/realesrgan_dataset.py +193 -0
  45. basicsr/data/realesrgan_paired_dataset.py +106 -0
  46. basicsr/data/reds_dataset.py +352 -0
  47. basicsr/data/single_image_dataset.py +68 -0
  48. basicsr/data/transforms.py +179 -0
  49. basicsr/data/video_test_dataset.py +283 -0
  50. basicsr/data/vimeo90k_dataset.py +199 -0
basicsr/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # https://github.com/xinntao/BasicSR
2
+ # flake8: noqa
3
+ from .archs import *
4
+ from .data import *
5
+ from .losses import *
6
+ from .metrics import *
7
+ from .models import *
8
+ from .ops import *
9
+ from .test import *
10
+ from .train import *
11
+ from .utils import *
12
+ from .version import __gitsha__, __version__
basicsr/archs/__init__.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import importlib
2
+ from copy import deepcopy
3
+ from os import path as osp
4
+
5
+ from basicsr.utils import get_root_logger, scandir
6
+ from basicsr.utils.registry import ARCH_REGISTRY
7
+
8
+ __all__ = ['build_network']
9
+
10
+ # automatically scan and import arch modules for registry
11
+ # scan all the files under the 'archs' folder and collect files ending with '_arch.py'
12
+ arch_folder = osp.dirname(osp.abspath(__file__))
13
+ arch_filenames = [osp.splitext(osp.basename(v))[0] for v in scandir(arch_folder) if v.endswith('_arch.py')]
14
+ # import all the arch modules
15
+ _arch_modules = [importlib.import_module(f'basicsr.archs.{file_name}') for file_name in arch_filenames]
16
+
17
+
18
+ def build_network(opt):
19
+ opt = deepcopy(opt)
20
+ network_type = opt.pop('type')
21
+ net = ARCH_REGISTRY.get(network_type)(**opt)
22
+ logger = get_root_logger()
23
+ logger.info(f'Network [{net.__class__.__name__}] is created.')
24
+ return net
basicsr/archs/arch_util.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import collections.abc
2
+ import math
3
+ import torch
4
+ import torchvision
5
+ import warnings
6
+ from distutils.version import LooseVersion
7
+ from itertools import repeat
8
+ from torch import nn as nn
9
+ from torch.nn import functional as F
10
+ from torch.nn import init as init
11
+ from torch.nn.modules.batchnorm import _BatchNorm
12
+
13
+ from basicsr.ops.dcn import ModulatedDeformConvPack, modulated_deform_conv
14
+ from basicsr.utils import get_root_logger
15
+
16
+
17
+ @torch.no_grad()
18
+ def default_init_weights(module_list, scale=1, bias_fill=0, **kwargs):
19
+ """Initialize network weights.
20
+
21
+ Args:
22
+ module_list (list[nn.Module] | nn.Module): Modules to be initialized.
23
+ scale (float): Scale initialized weights, especially for residual
24
+ blocks. Default: 1.
25
+ bias_fill (float): The value to fill bias. Default: 0
26
+ kwargs (dict): Other arguments for initialization function.
27
+ """
28
+ if not isinstance(module_list, list):
29
+ module_list = [module_list]
30
+ for module in module_list:
31
+ for m in module.modules():
32
+ if isinstance(m, nn.Conv2d):
33
+ init.kaiming_normal_(m.weight, **kwargs)
34
+ m.weight.data *= scale
35
+ if m.bias is not None:
36
+ m.bias.data.fill_(bias_fill)
37
+ elif isinstance(m, nn.Linear):
38
+ init.kaiming_normal_(m.weight, **kwargs)
39
+ m.weight.data *= scale
40
+ if m.bias is not None:
41
+ m.bias.data.fill_(bias_fill)
42
+ elif isinstance(m, _BatchNorm):
43
+ init.constant_(m.weight, 1)
44
+ if m.bias is not None:
45
+ m.bias.data.fill_(bias_fill)
46
+
47
+
48
+ def make_layer(basic_block, num_basic_block, **kwarg):
49
+ """Make layers by stacking the same blocks.
50
+
51
+ Args:
52
+ basic_block (nn.module): nn.module class for basic block.
53
+ num_basic_block (int): number of blocks.
54
+
55
+ Returns:
56
+ nn.Sequential: Stacked blocks in nn.Sequential.
57
+ """
58
+ layers = []
59
+ for _ in range(num_basic_block):
60
+ layers.append(basic_block(**kwarg))
61
+ return nn.Sequential(*layers)
62
+
63
+
64
+ class ResidualBlockNoBN(nn.Module):
65
+ """Residual block without BN.
66
+
67
+ Args:
68
+ num_feat (int): Channel number of intermediate features.
69
+ Default: 64.
70
+ res_scale (float): Residual scale. Default: 1.
71
+ pytorch_init (bool): If set to True, use pytorch default init,
72
+ otherwise, use default_init_weights. Default: False.
73
+ """
74
+
75
+ def __init__(self, num_feat=64, res_scale=1, pytorch_init=False):
76
+ super(ResidualBlockNoBN, self).__init__()
77
+ self.res_scale = res_scale
78
+ self.conv1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1, bias=True)
79
+ self.conv2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1, bias=True)
80
+ self.relu = nn.ReLU(inplace=True)
81
+
82
+ if not pytorch_init:
83
+ default_init_weights([self.conv1, self.conv2], 0.1)
84
+
85
+ def forward(self, x):
86
+ identity = x
87
+ out = self.conv2(self.relu(self.conv1(x)))
88
+ return identity + out * self.res_scale
89
+
90
+
91
+ class Upsample(nn.Sequential):
92
+ """Upsample module.
93
+
94
+ Args:
95
+ scale (int): Scale factor. Supported scales: 2^n and 3.
96
+ num_feat (int): Channel number of intermediate features.
97
+ """
98
+
99
+ def __init__(self, scale, num_feat):
100
+ m = []
101
+ if (scale & (scale - 1)) == 0: # scale = 2^n
102
+ for _ in range(int(math.log(scale, 2))):
103
+ m.append(nn.Conv2d(num_feat, 4 * num_feat, 3, 1, 1))
104
+ m.append(nn.PixelShuffle(2))
105
+ elif scale == 3:
106
+ m.append(nn.Conv2d(num_feat, 9 * num_feat, 3, 1, 1))
107
+ m.append(nn.PixelShuffle(3))
108
+ else:
109
+ raise ValueError(f'scale {scale} is not supported. Supported scales: 2^n and 3.')
110
+ super(Upsample, self).__init__(*m)
111
+
112
+
113
+ def flow_warp(x, flow, interp_mode='bilinear', padding_mode='zeros', align_corners=True):
114
+ """Warp an image or feature map with optical flow.
115
+
116
+ Args:
117
+ x (Tensor): Tensor with size (n, c, h, w).
118
+ flow (Tensor): Tensor with size (n, h, w, 2), normal value.
119
+ interp_mode (str): 'nearest' or 'bilinear'. Default: 'bilinear'.
120
+ padding_mode (str): 'zeros' or 'border' or 'reflection'.
121
+ Default: 'zeros'.
122
+ align_corners (bool): Before pytorch 1.3, the default value is
123
+ align_corners=True. After pytorch 1.3, the default value is
124
+ align_corners=False. Here, we use the True as default.
125
+
126
+ Returns:
127
+ Tensor: Warped image or feature map.
128
+ """
129
+ assert x.size()[-2:] == flow.size()[1:3]
130
+ _, _, h, w = x.size()
131
+ # create mesh grid
132
+ grid_y, grid_x = torch.meshgrid(torch.arange(0, h).type_as(x), torch.arange(0, w).type_as(x))
133
+ grid = torch.stack((grid_x, grid_y), 2).float() # W(x), H(y), 2
134
+ grid.requires_grad = False
135
+
136
+ vgrid = grid + flow
137
+ # scale grid to [-1,1]
138
+ vgrid_x = 2.0 * vgrid[:, :, :, 0] / max(w - 1, 1) - 1.0
139
+ vgrid_y = 2.0 * vgrid[:, :, :, 1] / max(h - 1, 1) - 1.0
140
+ vgrid_scaled = torch.stack((vgrid_x, vgrid_y), dim=3)
141
+ output = F.grid_sample(x, vgrid_scaled, mode=interp_mode, padding_mode=padding_mode, align_corners=align_corners)
142
+
143
+ # TODO, what if align_corners=False
144
+ return output
145
+
146
+
147
+ def resize_flow(flow, size_type, sizes, interp_mode='bilinear', align_corners=False):
148
+ """Resize a flow according to ratio or shape.
149
+
150
+ Args:
151
+ flow (Tensor): Precomputed flow. shape [N, 2, H, W].
152
+ size_type (str): 'ratio' or 'shape'.
153
+ sizes (list[int | float]): the ratio for resizing or the final output
154
+ shape.
155
+ 1) The order of ratio should be [ratio_h, ratio_w]. For
156
+ downsampling, the ratio should be smaller than 1.0 (i.e., ratio
157
+ < 1.0). For upsampling, the ratio should be larger than 1.0 (i.e.,
158
+ ratio > 1.0).
159
+ 2) The order of output_size should be [out_h, out_w].
160
+ interp_mode (str): The mode of interpolation for resizing.
161
+ Default: 'bilinear'.
162
+ align_corners (bool): Whether align corners. Default: False.
163
+
164
+ Returns:
165
+ Tensor: Resized flow.
166
+ """
167
+ _, _, flow_h, flow_w = flow.size()
168
+ if size_type == 'ratio':
169
+ output_h, output_w = int(flow_h * sizes[0]), int(flow_w * sizes[1])
170
+ elif size_type == 'shape':
171
+ output_h, output_w = sizes[0], sizes[1]
172
+ else:
173
+ raise ValueError(f'Size type should be ratio or shape, but got type {size_type}.')
174
+
175
+ input_flow = flow.clone()
176
+ ratio_h = output_h / flow_h
177
+ ratio_w = output_w / flow_w
178
+ input_flow[:, 0, :, :] *= ratio_w
179
+ input_flow[:, 1, :, :] *= ratio_h
180
+ resized_flow = F.interpolate(
181
+ input=input_flow, size=(output_h, output_w), mode=interp_mode, align_corners=align_corners)
182
+ return resized_flow
183
+
184
+
185
+ # TODO: may write a cpp file
186
+ def pixel_unshuffle(x, scale):
187
+ """ Pixel unshuffle.
188
+
189
+ Args:
190
+ x (Tensor): Input feature with shape (b, c, hh, hw).
191
+ scale (int): Downsample ratio.
192
+
193
+ Returns:
194
+ Tensor: the pixel unshuffled feature.
195
+ """
196
+ b, c, hh, hw = x.size()
197
+ out_channel = c * (scale**2)
198
+ assert hh % scale == 0 and hw % scale == 0
199
+ h = hh // scale
200
+ w = hw // scale
201
+ x_view = x.view(b, c, h, scale, w, scale)
202
+ return x_view.permute(0, 1, 3, 5, 2, 4).reshape(b, out_channel, h, w)
203
+
204
+
205
+ class DCNv2Pack(ModulatedDeformConvPack):
206
+ """Modulated deformable conv for deformable alignment.
207
+
208
+ Different from the official DCNv2Pack, which generates offsets and masks
209
+ from the preceding features, this DCNv2Pack takes another different
210
+ features to generate offsets and masks.
211
+
212
+ ``Paper: Delving Deep into Deformable Alignment in Video Super-Resolution``
213
+ """
214
+
215
+ def forward(self, x, feat):
216
+ out = self.conv_offset(feat)
217
+ o1, o2, mask = torch.chunk(out, 3, dim=1)
218
+ offset = torch.cat((o1, o2), dim=1)
219
+ mask = torch.sigmoid(mask)
220
+
221
+ offset_absmean = torch.mean(torch.abs(offset))
222
+ if offset_absmean > 50:
223
+ logger = get_root_logger()
224
+ logger.warning(f'Offset abs mean is {offset_absmean}, larger than 50.')
225
+
226
+ if LooseVersion(torchvision.__version__) >= LooseVersion('0.9.0'):
227
+ return torchvision.ops.deform_conv2d(x, offset, self.weight, self.bias, self.stride, self.padding,
228
+ self.dilation, mask)
229
+ else:
230
+ return modulated_deform_conv(x, offset, mask, self.weight, self.bias, self.stride, self.padding,
231
+ self.dilation, self.groups, self.deformable_groups)
232
+
233
+
234
+ def _no_grad_trunc_normal_(tensor, mean, std, a, b):
235
+ # From: https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/weight_init.py
236
+ # Cut & paste from PyTorch official master until it's in a few official releases - RW
237
+ # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
238
+ def norm_cdf(x):
239
+ # Computes standard normal cumulative distribution function
240
+ return (1. + math.erf(x / math.sqrt(2.))) / 2.
241
+
242
+ if (mean < a - 2 * std) or (mean > b + 2 * std):
243
+ warnings.warn(
244
+ 'mean is more than 2 std from [a, b] in nn.init.trunc_normal_. '
245
+ 'The distribution of values may be incorrect.',
246
+ stacklevel=2)
247
+
248
+ with torch.no_grad():
249
+ # Values are generated by using a truncated uniform distribution and
250
+ # then using the inverse CDF for the normal distribution.
251
+ # Get upper and lower cdf values
252
+ low = norm_cdf((a - mean) / std)
253
+ up = norm_cdf((b - mean) / std)
254
+
255
+ # Uniformly fill tensor with values from [low, up], then translate to
256
+ # [2l-1, 2u-1].
257
+ tensor.uniform_(2 * low - 1, 2 * up - 1)
258
+
259
+ # Use inverse cdf transform for normal distribution to get truncated
260
+ # standard normal
261
+ tensor.erfinv_()
262
+
263
+ # Transform to proper mean, std
264
+ tensor.mul_(std * math.sqrt(2.))
265
+ tensor.add_(mean)
266
+
267
+ # Clamp to ensure it's in the proper range
268
+ tensor.clamp_(min=a, max=b)
269
+ return tensor
270
+
271
+
272
+ def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
273
+ r"""Fills the input Tensor with values drawn from a truncated
274
+ normal distribution.
275
+
276
+ From: https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/weight_init.py
277
+
278
+ The values are effectively drawn from the
279
+ normal distribution :math:`\mathcal{N}(\text{mean}, \text{std}^2)`
280
+ with values outside :math:`[a, b]` redrawn until they are within
281
+ the bounds. The method used for generating the random values works
282
+ best when :math:`a \leq \text{mean} \leq b`.
283
+
284
+ Args:
285
+ tensor: an n-dimensional `torch.Tensor`
286
+ mean: the mean of the normal distribution
287
+ std: the standard deviation of the normal distribution
288
+ a: the minimum cutoff value
289
+ b: the maximum cutoff value
290
+
291
+ Examples:
292
+ >>> w = torch.empty(3, 5)
293
+ >>> nn.init.trunc_normal_(w)
294
+ """
295
+ return _no_grad_trunc_normal_(tensor, mean, std, a, b)
296
+
297
+
298
+ # From PyTorch
299
+ def _ntuple(n):
300
+
301
+ def parse(x):
302
+ if isinstance(x, collections.abc.Iterable):
303
+ return x
304
+ return tuple(repeat(x, n))
305
+
306
+ return parse
307
+
308
+
309
+ to_1tuple = _ntuple(1)
310
+ to_2tuple = _ntuple(2)
311
+ to_3tuple = _ntuple(3)
312
+ to_4tuple = _ntuple(4)
313
+ to_ntuple = _ntuple
basicsr/archs/basicvsr_arch.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+ from torch.nn import functional as F
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+ from .arch_util import ResidualBlockNoBN, flow_warp, make_layer
7
+ from .edvr_arch import PCDAlignment, TSAFusion
8
+ from .spynet_arch import SpyNet
9
+
10
+
11
+ @ARCH_REGISTRY.register()
12
+ class BasicVSR(nn.Module):
13
+ """A recurrent network for video SR. Now only x4 is supported.
14
+
15
+ Args:
16
+ num_feat (int): Number of channels. Default: 64.
17
+ num_block (int): Number of residual blocks for each branch. Default: 15
18
+ spynet_path (str): Path to the pretrained weights of SPyNet. Default: None.
19
+ """
20
+
21
+ def __init__(self, num_feat=64, num_block=15, spynet_path=None):
22
+ super().__init__()
23
+ self.num_feat = num_feat
24
+
25
+ # alignment
26
+ self.spynet = SpyNet(spynet_path)
27
+
28
+ # propagation
29
+ self.backward_trunk = ConvResidualBlocks(num_feat + 3, num_feat, num_block)
30
+ self.forward_trunk = ConvResidualBlocks(num_feat + 3, num_feat, num_block)
31
+
32
+ # reconstruction
33
+ self.fusion = nn.Conv2d(num_feat * 2, num_feat, 1, 1, 0, bias=True)
34
+ self.upconv1 = nn.Conv2d(num_feat, num_feat * 4, 3, 1, 1, bias=True)
35
+ self.upconv2 = nn.Conv2d(num_feat, 64 * 4, 3, 1, 1, bias=True)
36
+ self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1)
37
+ self.conv_last = nn.Conv2d(64, 3, 3, 1, 1)
38
+
39
+ self.pixel_shuffle = nn.PixelShuffle(2)
40
+
41
+ # activation functions
42
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
43
+
44
+ def get_flow(self, x):
45
+ b, n, c, h, w = x.size()
46
+
47
+ x_1 = x[:, :-1, :, :, :].reshape(-1, c, h, w)
48
+ x_2 = x[:, 1:, :, :, :].reshape(-1, c, h, w)
49
+
50
+ flows_backward = self.spynet(x_1, x_2).view(b, n - 1, 2, h, w)
51
+ flows_forward = self.spynet(x_2, x_1).view(b, n - 1, 2, h, w)
52
+
53
+ return flows_forward, flows_backward
54
+
55
+ def forward(self, x):
56
+ """Forward function of BasicVSR.
57
+
58
+ Args:
59
+ x: Input frames with shape (b, n, c, h, w). n is the temporal dimension / number of frames.
60
+ """
61
+ flows_forward, flows_backward = self.get_flow(x)
62
+ b, n, _, h, w = x.size()
63
+
64
+ # backward branch
65
+ out_l = []
66
+ feat_prop = x.new_zeros(b, self.num_feat, h, w)
67
+ for i in range(n - 1, -1, -1):
68
+ x_i = x[:, i, :, :, :]
69
+ if i < n - 1:
70
+ flow = flows_backward[:, i, :, :, :]
71
+ feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1))
72
+ feat_prop = torch.cat([x_i, feat_prop], dim=1)
73
+ feat_prop = self.backward_trunk(feat_prop)
74
+ out_l.insert(0, feat_prop)
75
+
76
+ # forward branch
77
+ feat_prop = torch.zeros_like(feat_prop)
78
+ for i in range(0, n):
79
+ x_i = x[:, i, :, :, :]
80
+ if i > 0:
81
+ flow = flows_forward[:, i - 1, :, :, :]
82
+ feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1))
83
+
84
+ feat_prop = torch.cat([x_i, feat_prop], dim=1)
85
+ feat_prop = self.forward_trunk(feat_prop)
86
+
87
+ # upsample
88
+ out = torch.cat([out_l[i], feat_prop], dim=1)
89
+ out = self.lrelu(self.fusion(out))
90
+ out = self.lrelu(self.pixel_shuffle(self.upconv1(out)))
91
+ out = self.lrelu(self.pixel_shuffle(self.upconv2(out)))
92
+ out = self.lrelu(self.conv_hr(out))
93
+ out = self.conv_last(out)
94
+ base = F.interpolate(x_i, scale_factor=4, mode='bilinear', align_corners=False)
95
+ out += base
96
+ out_l[i] = out
97
+
98
+ return torch.stack(out_l, dim=1)
99
+
100
+
101
+ class ConvResidualBlocks(nn.Module):
102
+ """Conv and residual block used in BasicVSR.
103
+
104
+ Args:
105
+ num_in_ch (int): Number of input channels. Default: 3.
106
+ num_out_ch (int): Number of output channels. Default: 64.
107
+ num_block (int): Number of residual blocks. Default: 15.
108
+ """
109
+
110
+ def __init__(self, num_in_ch=3, num_out_ch=64, num_block=15):
111
+ super().__init__()
112
+ self.main = nn.Sequential(
113
+ nn.Conv2d(num_in_ch, num_out_ch, 3, 1, 1, bias=True), nn.LeakyReLU(negative_slope=0.1, inplace=True),
114
+ make_layer(ResidualBlockNoBN, num_block, num_feat=num_out_ch))
115
+
116
+ def forward(self, fea):
117
+ return self.main(fea)
118
+
119
+
120
+ @ARCH_REGISTRY.register()
121
+ class IconVSR(nn.Module):
122
+ """IconVSR, proposed also in the BasicVSR paper.
123
+
124
+ Args:
125
+ num_feat (int): Number of channels. Default: 64.
126
+ num_block (int): Number of residual blocks for each branch. Default: 15.
127
+ keyframe_stride (int): Keyframe stride. Default: 5.
128
+ temporal_padding (int): Temporal padding. Default: 2.
129
+ spynet_path (str): Path to the pretrained weights of SPyNet. Default: None.
130
+ edvr_path (str): Path to the pretrained EDVR model. Default: None.
131
+ """
132
+
133
+ def __init__(self,
134
+ num_feat=64,
135
+ num_block=15,
136
+ keyframe_stride=5,
137
+ temporal_padding=2,
138
+ spynet_path=None,
139
+ edvr_path=None):
140
+ super().__init__()
141
+
142
+ self.num_feat = num_feat
143
+ self.temporal_padding = temporal_padding
144
+ self.keyframe_stride = keyframe_stride
145
+
146
+ # keyframe_branch
147
+ self.edvr = EDVRFeatureExtractor(temporal_padding * 2 + 1, num_feat, edvr_path)
148
+ # alignment
149
+ self.spynet = SpyNet(spynet_path)
150
+
151
+ # propagation
152
+ self.backward_fusion = nn.Conv2d(2 * num_feat, num_feat, 3, 1, 1, bias=True)
153
+ self.backward_trunk = ConvResidualBlocks(num_feat + 3, num_feat, num_block)
154
+
155
+ self.forward_fusion = nn.Conv2d(2 * num_feat, num_feat, 3, 1, 1, bias=True)
156
+ self.forward_trunk = ConvResidualBlocks(2 * num_feat + 3, num_feat, num_block)
157
+
158
+ # reconstruction
159
+ self.upconv1 = nn.Conv2d(num_feat, num_feat * 4, 3, 1, 1, bias=True)
160
+ self.upconv2 = nn.Conv2d(num_feat, 64 * 4, 3, 1, 1, bias=True)
161
+ self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1)
162
+ self.conv_last = nn.Conv2d(64, 3, 3, 1, 1)
163
+
164
+ self.pixel_shuffle = nn.PixelShuffle(2)
165
+
166
+ # activation functions
167
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
168
+
169
+ def pad_spatial(self, x):
170
+ """Apply padding spatially.
171
+
172
+ Since the PCD module in EDVR requires that the resolution is a multiple
173
+ of 4, we apply padding to the input LR images if their resolution is
174
+ not divisible by 4.
175
+
176
+ Args:
177
+ x (Tensor): Input LR sequence with shape (n, t, c, h, w).
178
+ Returns:
179
+ Tensor: Padded LR sequence with shape (n, t, c, h_pad, w_pad).
180
+ """
181
+ n, t, c, h, w = x.size()
182
+
183
+ pad_h = (4 - h % 4) % 4
184
+ pad_w = (4 - w % 4) % 4
185
+
186
+ # padding
187
+ x = x.view(-1, c, h, w)
188
+ x = F.pad(x, [0, pad_w, 0, pad_h], mode='reflect')
189
+
190
+ return x.view(n, t, c, h + pad_h, w + pad_w)
191
+
192
+ def get_flow(self, x):
193
+ b, n, c, h, w = x.size()
194
+
195
+ x_1 = x[:, :-1, :, :, :].reshape(-1, c, h, w)
196
+ x_2 = x[:, 1:, :, :, :].reshape(-1, c, h, w)
197
+
198
+ flows_backward = self.spynet(x_1, x_2).view(b, n - 1, 2, h, w)
199
+ flows_forward = self.spynet(x_2, x_1).view(b, n - 1, 2, h, w)
200
+
201
+ return flows_forward, flows_backward
202
+
203
+ def get_keyframe_feature(self, x, keyframe_idx):
204
+ if self.temporal_padding == 2:
205
+ x = [x[:, [4, 3]], x, x[:, [-4, -5]]]
206
+ elif self.temporal_padding == 3:
207
+ x = [x[:, [6, 5, 4]], x, x[:, [-5, -6, -7]]]
208
+ x = torch.cat(x, dim=1)
209
+
210
+ num_frames = 2 * self.temporal_padding + 1
211
+ feats_keyframe = {}
212
+ for i in keyframe_idx:
213
+ feats_keyframe[i] = self.edvr(x[:, i:i + num_frames].contiguous())
214
+ return feats_keyframe
215
+
216
+ def forward(self, x):
217
+ b, n, _, h_input, w_input = x.size()
218
+
219
+ x = self.pad_spatial(x)
220
+ h, w = x.shape[3:]
221
+
222
+ keyframe_idx = list(range(0, n, self.keyframe_stride))
223
+ if keyframe_idx[-1] != n - 1:
224
+ keyframe_idx.append(n - 1) # last frame is a keyframe
225
+
226
+ # compute flow and keyframe features
227
+ flows_forward, flows_backward = self.get_flow(x)
228
+ feats_keyframe = self.get_keyframe_feature(x, keyframe_idx)
229
+
230
+ # backward branch
231
+ out_l = []
232
+ feat_prop = x.new_zeros(b, self.num_feat, h, w)
233
+ for i in range(n - 1, -1, -1):
234
+ x_i = x[:, i, :, :, :]
235
+ if i < n - 1:
236
+ flow = flows_backward[:, i, :, :, :]
237
+ feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1))
238
+ if i in keyframe_idx:
239
+ feat_prop = torch.cat([feat_prop, feats_keyframe[i]], dim=1)
240
+ feat_prop = self.backward_fusion(feat_prop)
241
+ feat_prop = torch.cat([x_i, feat_prop], dim=1)
242
+ feat_prop = self.backward_trunk(feat_prop)
243
+ out_l.insert(0, feat_prop)
244
+
245
+ # forward branch
246
+ feat_prop = torch.zeros_like(feat_prop)
247
+ for i in range(0, n):
248
+ x_i = x[:, i, :, :, :]
249
+ if i > 0:
250
+ flow = flows_forward[:, i - 1, :, :, :]
251
+ feat_prop = flow_warp(feat_prop, flow.permute(0, 2, 3, 1))
252
+ if i in keyframe_idx:
253
+ feat_prop = torch.cat([feat_prop, feats_keyframe[i]], dim=1)
254
+ feat_prop = self.forward_fusion(feat_prop)
255
+
256
+ feat_prop = torch.cat([x_i, out_l[i], feat_prop], dim=1)
257
+ feat_prop = self.forward_trunk(feat_prop)
258
+
259
+ # upsample
260
+ out = self.lrelu(self.pixel_shuffle(self.upconv1(feat_prop)))
261
+ out = self.lrelu(self.pixel_shuffle(self.upconv2(out)))
262
+ out = self.lrelu(self.conv_hr(out))
263
+ out = self.conv_last(out)
264
+ base = F.interpolate(x_i, scale_factor=4, mode='bilinear', align_corners=False)
265
+ out += base
266
+ out_l[i] = out
267
+
268
+ return torch.stack(out_l, dim=1)[..., :4 * h_input, :4 * w_input]
269
+
270
+
271
+ class EDVRFeatureExtractor(nn.Module):
272
+ """EDVR feature extractor used in IconVSR.
273
+
274
+ Args:
275
+ num_input_frame (int): Number of input frames.
276
+ num_feat (int): Number of feature channels
277
+ load_path (str): Path to the pretrained weights of EDVR. Default: None.
278
+ """
279
+
280
+ def __init__(self, num_input_frame, num_feat, load_path):
281
+
282
+ super(EDVRFeatureExtractor, self).__init__()
283
+
284
+ self.center_frame_idx = num_input_frame // 2
285
+
286
+ # extract pyramid features
287
+ self.conv_first = nn.Conv2d(3, num_feat, 3, 1, 1)
288
+ self.feature_extraction = make_layer(ResidualBlockNoBN, 5, num_feat=num_feat)
289
+ self.conv_l2_1 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
290
+ self.conv_l2_2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
291
+ self.conv_l3_1 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
292
+ self.conv_l3_2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
293
+
294
+ # pcd and tsa module
295
+ self.pcd_align = PCDAlignment(num_feat=num_feat, deformable_groups=8)
296
+ self.fusion = TSAFusion(num_feat=num_feat, num_frame=num_input_frame, center_frame_idx=self.center_frame_idx)
297
+
298
+ # activation function
299
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
300
+
301
+ if load_path:
302
+ self.load_state_dict(torch.load(load_path, map_location=lambda storage, loc: storage)['params'])
303
+
304
+ def forward(self, x):
305
+ b, n, c, h, w = x.size()
306
+
307
+ # extract features for each frame
308
+ # L1
309
+ feat_l1 = self.lrelu(self.conv_first(x.view(-1, c, h, w)))
310
+ feat_l1 = self.feature_extraction(feat_l1)
311
+ # L2
312
+ feat_l2 = self.lrelu(self.conv_l2_1(feat_l1))
313
+ feat_l2 = self.lrelu(self.conv_l2_2(feat_l2))
314
+ # L3
315
+ feat_l3 = self.lrelu(self.conv_l3_1(feat_l2))
316
+ feat_l3 = self.lrelu(self.conv_l3_2(feat_l3))
317
+
318
+ feat_l1 = feat_l1.view(b, n, -1, h, w)
319
+ feat_l2 = feat_l2.view(b, n, -1, h // 2, w // 2)
320
+ feat_l3 = feat_l3.view(b, n, -1, h // 4, w // 4)
321
+
322
+ # PCD alignment
323
+ ref_feat_l = [ # reference feature list
324
+ feat_l1[:, self.center_frame_idx, :, :, :].clone(), feat_l2[:, self.center_frame_idx, :, :, :].clone(),
325
+ feat_l3[:, self.center_frame_idx, :, :, :].clone()
326
+ ]
327
+ aligned_feat = []
328
+ for i in range(n):
329
+ nbr_feat_l = [ # neighboring feature list
330
+ feat_l1[:, i, :, :, :].clone(), feat_l2[:, i, :, :, :].clone(), feat_l3[:, i, :, :, :].clone()
331
+ ]
332
+ aligned_feat.append(self.pcd_align(nbr_feat_l, ref_feat_l))
333
+ aligned_feat = torch.stack(aligned_feat, dim=1) # (b, t, c, h, w)
334
+
335
+ # TSA fusion
336
+ return self.fusion(aligned_feat)
basicsr/archs/basicvsrpp_arch.py ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ import torchvision
5
+ import warnings
6
+
7
+ from basicsr.archs.arch_util import flow_warp
8
+ from basicsr.archs.basicvsr_arch import ConvResidualBlocks
9
+ from basicsr.archs.spynet_arch import SpyNet
10
+ from basicsr.ops.dcn import ModulatedDeformConvPack
11
+ from basicsr.utils.registry import ARCH_REGISTRY
12
+
13
+
14
+ @ARCH_REGISTRY.register()
15
+ class BasicVSRPlusPlus(nn.Module):
16
+ """BasicVSR++ network structure.
17
+
18
+ Support either x4 upsampling or same size output. Since DCN is used in this
19
+ model, it can only be used with CUDA enabled. If CUDA is not enabled,
20
+ feature alignment will be skipped. Besides, we adopt the official DCN
21
+ implementation and the version of torch need to be higher than 1.9.
22
+
23
+ ``Paper: BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment``
24
+
25
+ Args:
26
+ mid_channels (int, optional): Channel number of the intermediate
27
+ features. Default: 64.
28
+ num_blocks (int, optional): The number of residual blocks in each
29
+ propagation branch. Default: 7.
30
+ max_residue_magnitude (int): The maximum magnitude of the offset
31
+ residue (Eq. 6 in paper). Default: 10.
32
+ is_low_res_input (bool, optional): Whether the input is low-resolution
33
+ or not. If False, the output resolution is equal to the input
34
+ resolution. Default: True.
35
+ spynet_path (str): Path to the pretrained weights of SPyNet. Default: None.
36
+ cpu_cache_length (int, optional): When the length of sequence is larger
37
+ than this value, the intermediate features are sent to CPU. This
38
+ saves GPU memory, but slows down the inference speed. You can
39
+ increase this number if you have a GPU with large memory.
40
+ Default: 100.
41
+ """
42
+
43
+ def __init__(self,
44
+ mid_channels=64,
45
+ num_blocks=7,
46
+ max_residue_magnitude=10,
47
+ is_low_res_input=True,
48
+ spynet_path=None,
49
+ cpu_cache_length=100):
50
+
51
+ super().__init__()
52
+ self.mid_channels = mid_channels
53
+ self.is_low_res_input = is_low_res_input
54
+ self.cpu_cache_length = cpu_cache_length
55
+
56
+ # optical flow
57
+ self.spynet = SpyNet(spynet_path)
58
+
59
+ # feature extraction module
60
+ if is_low_res_input:
61
+ self.feat_extract = ConvResidualBlocks(3, mid_channels, 5)
62
+ else:
63
+ self.feat_extract = nn.Sequential(
64
+ nn.Conv2d(3, mid_channels, 3, 2, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True),
65
+ nn.Conv2d(mid_channels, mid_channels, 3, 2, 1), nn.LeakyReLU(negative_slope=0.1, inplace=True),
66
+ ConvResidualBlocks(mid_channels, mid_channels, 5))
67
+
68
+ # propagation branches
69
+ self.deform_align = nn.ModuleDict()
70
+ self.backbone = nn.ModuleDict()
71
+ modules = ['backward_1', 'forward_1', 'backward_2', 'forward_2']
72
+ for i, module in enumerate(modules):
73
+ if torch.cuda.is_available():
74
+ self.deform_align[module] = SecondOrderDeformableAlignment(
75
+ 2 * mid_channels,
76
+ mid_channels,
77
+ 3,
78
+ padding=1,
79
+ deformable_groups=16,
80
+ max_residue_magnitude=max_residue_magnitude)
81
+ self.backbone[module] = ConvResidualBlocks((2 + i) * mid_channels, mid_channels, num_blocks)
82
+
83
+ # upsampling module
84
+ self.reconstruction = ConvResidualBlocks(5 * mid_channels, mid_channels, 5)
85
+
86
+ self.upconv1 = nn.Conv2d(mid_channels, mid_channels * 4, 3, 1, 1, bias=True)
87
+ self.upconv2 = nn.Conv2d(mid_channels, 64 * 4, 3, 1, 1, bias=True)
88
+
89
+ self.pixel_shuffle = nn.PixelShuffle(2)
90
+
91
+ self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1)
92
+ self.conv_last = nn.Conv2d(64, 3, 3, 1, 1)
93
+ self.img_upsample = nn.Upsample(scale_factor=4, mode='bilinear', align_corners=False)
94
+
95
+ # activation function
96
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
97
+
98
+ # check if the sequence is augmented by flipping
99
+ self.is_mirror_extended = False
100
+
101
+ if len(self.deform_align) > 0:
102
+ self.is_with_alignment = True
103
+ else:
104
+ self.is_with_alignment = False
105
+ warnings.warn('Deformable alignment module is not added. '
106
+ 'Probably your CUDA is not configured correctly. DCN can only '
107
+ 'be used with CUDA enabled. Alignment is skipped now.')
108
+
109
+ def check_if_mirror_extended(self, lqs):
110
+ """Check whether the input is a mirror-extended sequence.
111
+
112
+ If mirror-extended, the i-th (i=0, ..., t-1) frame is equal to the (t-1-i)-th frame.
113
+
114
+ Args:
115
+ lqs (tensor): Input low quality (LQ) sequence with shape (n, t, c, h, w).
116
+ """
117
+
118
+ if lqs.size(1) % 2 == 0:
119
+ lqs_1, lqs_2 = torch.chunk(lqs, 2, dim=1)
120
+ if torch.norm(lqs_1 - lqs_2.flip(1)) == 0:
121
+ self.is_mirror_extended = True
122
+
123
+ def compute_flow(self, lqs):
124
+ """Compute optical flow using SPyNet for feature alignment.
125
+
126
+ Note that if the input is an mirror-extended sequence, 'flows_forward'
127
+ is not needed, since it is equal to 'flows_backward.flip(1)'.
128
+
129
+ Args:
130
+ lqs (tensor): Input low quality (LQ) sequence with
131
+ shape (n, t, c, h, w).
132
+
133
+ Return:
134
+ tuple(Tensor): Optical flow. 'flows_forward' corresponds to the flows used for forward-time propagation \
135
+ (current to previous). 'flows_backward' corresponds to the flows used for backward-time \
136
+ propagation (current to next).
137
+ """
138
+
139
+ n, t, c, h, w = lqs.size()
140
+ lqs_1 = lqs[:, :-1, :, :, :].reshape(-1, c, h, w)
141
+ lqs_2 = lqs[:, 1:, :, :, :].reshape(-1, c, h, w)
142
+
143
+ flows_backward = self.spynet(lqs_1, lqs_2).view(n, t - 1, 2, h, w)
144
+
145
+ if self.is_mirror_extended: # flows_forward = flows_backward.flip(1)
146
+ flows_forward = flows_backward.flip(1)
147
+ else:
148
+ flows_forward = self.spynet(lqs_2, lqs_1).view(n, t - 1, 2, h, w)
149
+
150
+ if self.cpu_cache:
151
+ flows_backward = flows_backward.cpu()
152
+ flows_forward = flows_forward.cpu()
153
+
154
+ return flows_forward, flows_backward
155
+
156
+ def propagate(self, feats, flows, module_name):
157
+ """Propagate the latent features throughout the sequence.
158
+
159
+ Args:
160
+ feats dict(list[tensor]): Features from previous branches. Each
161
+ component is a list of tensors with shape (n, c, h, w).
162
+ flows (tensor): Optical flows with shape (n, t - 1, 2, h, w).
163
+ module_name (str): The name of the propgation branches. Can either
164
+ be 'backward_1', 'forward_1', 'backward_2', 'forward_2'.
165
+
166
+ Return:
167
+ dict(list[tensor]): A dictionary containing all the propagated \
168
+ features. Each key in the dictionary corresponds to a \
169
+ propagation branch, which is represented by a list of tensors.
170
+ """
171
+
172
+ n, t, _, h, w = flows.size()
173
+
174
+ frame_idx = range(0, t + 1)
175
+ flow_idx = range(-1, t)
176
+ mapping_idx = list(range(0, len(feats['spatial'])))
177
+ mapping_idx += mapping_idx[::-1]
178
+
179
+ if 'backward' in module_name:
180
+ frame_idx = frame_idx[::-1]
181
+ flow_idx = frame_idx
182
+
183
+ feat_prop = flows.new_zeros(n, self.mid_channels, h, w)
184
+ for i, idx in enumerate(frame_idx):
185
+ feat_current = feats['spatial'][mapping_idx[idx]]
186
+ if self.cpu_cache:
187
+ feat_current = feat_current.cuda()
188
+ feat_prop = feat_prop.cuda()
189
+ # second-order deformable alignment
190
+ if i > 0 and self.is_with_alignment:
191
+ flow_n1 = flows[:, flow_idx[i], :, :, :]
192
+ if self.cpu_cache:
193
+ flow_n1 = flow_n1.cuda()
194
+
195
+ cond_n1 = flow_warp(feat_prop, flow_n1.permute(0, 2, 3, 1))
196
+
197
+ # initialize second-order features
198
+ feat_n2 = torch.zeros_like(feat_prop)
199
+ flow_n2 = torch.zeros_like(flow_n1)
200
+ cond_n2 = torch.zeros_like(cond_n1)
201
+
202
+ if i > 1: # second-order features
203
+ feat_n2 = feats[module_name][-2]
204
+ if self.cpu_cache:
205
+ feat_n2 = feat_n2.cuda()
206
+
207
+ flow_n2 = flows[:, flow_idx[i - 1], :, :, :]
208
+ if self.cpu_cache:
209
+ flow_n2 = flow_n2.cuda()
210
+
211
+ flow_n2 = flow_n1 + flow_warp(flow_n2, flow_n1.permute(0, 2, 3, 1))
212
+ cond_n2 = flow_warp(feat_n2, flow_n2.permute(0, 2, 3, 1))
213
+
214
+ # flow-guided deformable convolution
215
+ cond = torch.cat([cond_n1, feat_current, cond_n2], dim=1)
216
+ feat_prop = torch.cat([feat_prop, feat_n2], dim=1)
217
+ feat_prop = self.deform_align[module_name](feat_prop, cond, flow_n1, flow_n2)
218
+
219
+ # concatenate and residual blocks
220
+ feat = [feat_current] + [feats[k][idx] for k in feats if k not in ['spatial', module_name]] + [feat_prop]
221
+ if self.cpu_cache:
222
+ feat = [f.cuda() for f in feat]
223
+
224
+ feat = torch.cat(feat, dim=1)
225
+ feat_prop = feat_prop + self.backbone[module_name](feat)
226
+ feats[module_name].append(feat_prop)
227
+
228
+ if self.cpu_cache:
229
+ feats[module_name][-1] = feats[module_name][-1].cpu()
230
+ torch.cuda.empty_cache()
231
+
232
+ if 'backward' in module_name:
233
+ feats[module_name] = feats[module_name][::-1]
234
+
235
+ return feats
236
+
237
+ def upsample(self, lqs, feats):
238
+ """Compute the output image given the features.
239
+
240
+ Args:
241
+ lqs (tensor): Input low quality (LQ) sequence with
242
+ shape (n, t, c, h, w).
243
+ feats (dict): The features from the propagation branches.
244
+
245
+ Returns:
246
+ Tensor: Output HR sequence with shape (n, t, c, 4h, 4w).
247
+ """
248
+
249
+ outputs = []
250
+ num_outputs = len(feats['spatial'])
251
+
252
+ mapping_idx = list(range(0, num_outputs))
253
+ mapping_idx += mapping_idx[::-1]
254
+
255
+ for i in range(0, lqs.size(1)):
256
+ hr = [feats[k].pop(0) for k in feats if k != 'spatial']
257
+ hr.insert(0, feats['spatial'][mapping_idx[i]])
258
+ hr = torch.cat(hr, dim=1)
259
+ if self.cpu_cache:
260
+ hr = hr.cuda()
261
+
262
+ hr = self.reconstruction(hr)
263
+ hr = self.lrelu(self.pixel_shuffle(self.upconv1(hr)))
264
+ hr = self.lrelu(self.pixel_shuffle(self.upconv2(hr)))
265
+ hr = self.lrelu(self.conv_hr(hr))
266
+ hr = self.conv_last(hr)
267
+ if self.is_low_res_input:
268
+ hr += self.img_upsample(lqs[:, i, :, :, :])
269
+ else:
270
+ hr += lqs[:, i, :, :, :]
271
+
272
+ if self.cpu_cache:
273
+ hr = hr.cpu()
274
+ torch.cuda.empty_cache()
275
+
276
+ outputs.append(hr)
277
+
278
+ return torch.stack(outputs, dim=1)
279
+
280
+ def forward(self, lqs):
281
+ """Forward function for BasicVSR++.
282
+
283
+ Args:
284
+ lqs (tensor): Input low quality (LQ) sequence with
285
+ shape (n, t, c, h, w).
286
+
287
+ Returns:
288
+ Tensor: Output HR sequence with shape (n, t, c, 4h, 4w).
289
+ """
290
+
291
+ n, t, c, h, w = lqs.size()
292
+
293
+ # whether to cache the features in CPU
294
+ self.cpu_cache = True if t > self.cpu_cache_length else False
295
+
296
+ if self.is_low_res_input:
297
+ lqs_downsample = lqs.clone()
298
+ else:
299
+ lqs_downsample = F.interpolate(
300
+ lqs.view(-1, c, h, w), scale_factor=0.25, mode='bicubic').view(n, t, c, h // 4, w // 4)
301
+
302
+ # check whether the input is an extended sequence
303
+ self.check_if_mirror_extended(lqs)
304
+
305
+ feats = {}
306
+ # compute spatial features
307
+ if self.cpu_cache:
308
+ feats['spatial'] = []
309
+ for i in range(0, t):
310
+ feat = self.feat_extract(lqs[:, i, :, :, :]).cpu()
311
+ feats['spatial'].append(feat)
312
+ torch.cuda.empty_cache()
313
+ else:
314
+ feats_ = self.feat_extract(lqs.view(-1, c, h, w))
315
+ h, w = feats_.shape[2:]
316
+ feats_ = feats_.view(n, t, -1, h, w)
317
+ feats['spatial'] = [feats_[:, i, :, :, :] for i in range(0, t)]
318
+
319
+ # compute optical flow using the low-res inputs
320
+ assert lqs_downsample.size(3) >= 64 and lqs_downsample.size(4) >= 64, (
321
+ 'The height and width of low-res inputs must be at least 64, '
322
+ f'but got {h} and {w}.')
323
+ flows_forward, flows_backward = self.compute_flow(lqs_downsample)
324
+
325
+ # feature propgation
326
+ for iter_ in [1, 2]:
327
+ for direction in ['backward', 'forward']:
328
+ module = f'{direction}_{iter_}'
329
+
330
+ feats[module] = []
331
+
332
+ if direction == 'backward':
333
+ flows = flows_backward
334
+ elif flows_forward is not None:
335
+ flows = flows_forward
336
+ else:
337
+ flows = flows_backward.flip(1)
338
+
339
+ feats = self.propagate(feats, flows, module)
340
+ if self.cpu_cache:
341
+ del flows
342
+ torch.cuda.empty_cache()
343
+
344
+ return self.upsample(lqs, feats)
345
+
346
+
347
+ class SecondOrderDeformableAlignment(ModulatedDeformConvPack):
348
+ """Second-order deformable alignment module.
349
+
350
+ Args:
351
+ in_channels (int): Same as nn.Conv2d.
352
+ out_channels (int): Same as nn.Conv2d.
353
+ kernel_size (int or tuple[int]): Same as nn.Conv2d.
354
+ stride (int or tuple[int]): Same as nn.Conv2d.
355
+ padding (int or tuple[int]): Same as nn.Conv2d.
356
+ dilation (int or tuple[int]): Same as nn.Conv2d.
357
+ groups (int): Same as nn.Conv2d.
358
+ bias (bool or str): If specified as `auto`, it will be decided by the
359
+ norm_cfg. Bias will be set as True if norm_cfg is None, otherwise
360
+ False.
361
+ max_residue_magnitude (int): The maximum magnitude of the offset
362
+ residue (Eq. 6 in paper). Default: 10.
363
+ """
364
+
365
+ def __init__(self, *args, **kwargs):
366
+ self.max_residue_magnitude = kwargs.pop('max_residue_magnitude', 10)
367
+
368
+ super(SecondOrderDeformableAlignment, self).__init__(*args, **kwargs)
369
+
370
+ self.conv_offset = nn.Sequential(
371
+ nn.Conv2d(3 * self.out_channels + 4, self.out_channels, 3, 1, 1),
372
+ nn.LeakyReLU(negative_slope=0.1, inplace=True),
373
+ nn.Conv2d(self.out_channels, self.out_channels, 3, 1, 1),
374
+ nn.LeakyReLU(negative_slope=0.1, inplace=True),
375
+ nn.Conv2d(self.out_channels, self.out_channels, 3, 1, 1),
376
+ nn.LeakyReLU(negative_slope=0.1, inplace=True),
377
+ nn.Conv2d(self.out_channels, 27 * self.deformable_groups, 3, 1, 1),
378
+ )
379
+
380
+ self.init_offset()
381
+
382
+ def init_offset(self):
383
+
384
+ def _constant_init(module, val, bias=0):
385
+ if hasattr(module, 'weight') and module.weight is not None:
386
+ nn.init.constant_(module.weight, val)
387
+ if hasattr(module, 'bias') and module.bias is not None:
388
+ nn.init.constant_(module.bias, bias)
389
+
390
+ _constant_init(self.conv_offset[-1], val=0, bias=0)
391
+
392
+ def forward(self, x, extra_feat, flow_1, flow_2):
393
+ extra_feat = torch.cat([extra_feat, flow_1, flow_2], dim=1)
394
+ out = self.conv_offset(extra_feat)
395
+ o1, o2, mask = torch.chunk(out, 3, dim=1)
396
+
397
+ # offset
398
+ offset = self.max_residue_magnitude * torch.tanh(torch.cat((o1, o2), dim=1))
399
+ offset_1, offset_2 = torch.chunk(offset, 2, dim=1)
400
+ offset_1 = offset_1 + flow_1.flip(1).repeat(1, offset_1.size(1) // 2, 1, 1)
401
+ offset_2 = offset_2 + flow_2.flip(1).repeat(1, offset_2.size(1) // 2, 1, 1)
402
+ offset = torch.cat([offset_1, offset_2], dim=1)
403
+
404
+ # mask
405
+ mask = torch.sigmoid(mask)
406
+
407
+ return torchvision.ops.deform_conv2d(x, offset, self.weight, self.bias, self.stride, self.padding,
408
+ self.dilation, mask)
409
+
410
+
411
+ # if __name__ == '__main__':
412
+ # spynet_path = 'experiments/pretrained_models/flownet/spynet_sintel_final-3d2a1287.pth'
413
+ # model = BasicVSRPlusPlus(spynet_path=spynet_path).cuda()
414
+ # input = torch.rand(1, 2, 3, 64, 64).cuda()
415
+ # output = model(input)
416
+ # print('===================')
417
+ # print(output.shape)
basicsr/archs/dfdnet_arch.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from torch.nn.utils.spectral_norm import spectral_norm
6
+
7
+ from basicsr.utils.registry import ARCH_REGISTRY
8
+ from .dfdnet_util import AttentionBlock, Blur, MSDilationBlock, UpResBlock, adaptive_instance_normalization
9
+ from .vgg_arch import VGGFeatureExtractor
10
+
11
+
12
+ class SFTUpBlock(nn.Module):
13
+ """Spatial feature transform (SFT) with upsampling block.
14
+
15
+ Args:
16
+ in_channel (int): Number of input channels.
17
+ out_channel (int): Number of output channels.
18
+ kernel_size (int): Kernel size in convolutions. Default: 3.
19
+ padding (int): Padding in convolutions. Default: 1.
20
+ """
21
+
22
+ def __init__(self, in_channel, out_channel, kernel_size=3, padding=1):
23
+ super(SFTUpBlock, self).__init__()
24
+ self.conv1 = nn.Sequential(
25
+ Blur(in_channel),
26
+ spectral_norm(nn.Conv2d(in_channel, out_channel, kernel_size, padding=padding)),
27
+ nn.LeakyReLU(0.04, True),
28
+ # The official codes use two LeakyReLU here, so 0.04 for equivalent
29
+ )
30
+ self.convup = nn.Sequential(
31
+ nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False),
32
+ spectral_norm(nn.Conv2d(out_channel, out_channel, kernel_size, padding=padding)),
33
+ nn.LeakyReLU(0.2, True),
34
+ )
35
+
36
+ # for SFT scale and shift
37
+ self.scale_block = nn.Sequential(
38
+ spectral_norm(nn.Conv2d(in_channel, out_channel, 3, 1, 1)), nn.LeakyReLU(0.2, True),
39
+ spectral_norm(nn.Conv2d(out_channel, out_channel, 3, 1, 1)))
40
+ self.shift_block = nn.Sequential(
41
+ spectral_norm(nn.Conv2d(in_channel, out_channel, 3, 1, 1)), nn.LeakyReLU(0.2, True),
42
+ spectral_norm(nn.Conv2d(out_channel, out_channel, 3, 1, 1)), nn.Sigmoid())
43
+ # The official codes use sigmoid for shift block, do not know why
44
+
45
+ def forward(self, x, updated_feat):
46
+ out = self.conv1(x)
47
+ # SFT
48
+ scale = self.scale_block(updated_feat)
49
+ shift = self.shift_block(updated_feat)
50
+ out = out * scale + shift
51
+ # upsample
52
+ out = self.convup(out)
53
+ return out
54
+
55
+
56
+ @ARCH_REGISTRY.register()
57
+ class DFDNet(nn.Module):
58
+ """DFDNet: Deep Face Dictionary Network.
59
+
60
+ It only processes faces with 512x512 size.
61
+
62
+ Args:
63
+ num_feat (int): Number of feature channels.
64
+ dict_path (str): Path to the facial component dictionary.
65
+ """
66
+
67
+ def __init__(self, num_feat, dict_path):
68
+ super().__init__()
69
+ self.parts = ['left_eye', 'right_eye', 'nose', 'mouth']
70
+ # part_sizes: [80, 80, 50, 110]
71
+ channel_sizes = [128, 256, 512, 512]
72
+ self.feature_sizes = np.array([256, 128, 64, 32])
73
+ self.vgg_layers = ['relu2_2', 'relu3_4', 'relu4_4', 'conv5_4']
74
+ self.flag_dict_device = False
75
+
76
+ # dict
77
+ self.dict = torch.load(dict_path)
78
+
79
+ # vgg face extractor
80
+ self.vgg_extractor = VGGFeatureExtractor(
81
+ layer_name_list=self.vgg_layers,
82
+ vgg_type='vgg19',
83
+ use_input_norm=True,
84
+ range_norm=True,
85
+ requires_grad=False)
86
+
87
+ # attention block for fusing dictionary features and input features
88
+ self.attn_blocks = nn.ModuleDict()
89
+ for idx, feat_size in enumerate(self.feature_sizes):
90
+ for name in self.parts:
91
+ self.attn_blocks[f'{name}_{feat_size}'] = AttentionBlock(channel_sizes[idx])
92
+
93
+ # multi scale dilation block
94
+ self.multi_scale_dilation = MSDilationBlock(num_feat * 8, dilation=[4, 3, 2, 1])
95
+
96
+ # upsampling and reconstruction
97
+ self.upsample0 = SFTUpBlock(num_feat * 8, num_feat * 8)
98
+ self.upsample1 = SFTUpBlock(num_feat * 8, num_feat * 4)
99
+ self.upsample2 = SFTUpBlock(num_feat * 4, num_feat * 2)
100
+ self.upsample3 = SFTUpBlock(num_feat * 2, num_feat)
101
+ self.upsample4 = nn.Sequential(
102
+ spectral_norm(nn.Conv2d(num_feat, num_feat, 3, 1, 1)), nn.LeakyReLU(0.2, True), UpResBlock(num_feat),
103
+ UpResBlock(num_feat), nn.Conv2d(num_feat, 3, kernel_size=3, stride=1, padding=1), nn.Tanh())
104
+
105
+ def swap_feat(self, vgg_feat, updated_feat, dict_feat, location, part_name, f_size):
106
+ """swap the features from the dictionary."""
107
+ # get the original vgg features
108
+ part_feat = vgg_feat[:, :, location[1]:location[3], location[0]:location[2]].clone()
109
+ # resize original vgg features
110
+ part_resize_feat = F.interpolate(part_feat, dict_feat.size()[2:4], mode='bilinear', align_corners=False)
111
+ # use adaptive instance normalization to adjust color and illuminations
112
+ dict_feat = adaptive_instance_normalization(dict_feat, part_resize_feat)
113
+ # get similarity scores
114
+ similarity_score = F.conv2d(part_resize_feat, dict_feat)
115
+ similarity_score = F.softmax(similarity_score.view(-1), dim=0)
116
+ # select the most similar features in the dict (after norm)
117
+ select_idx = torch.argmax(similarity_score)
118
+ swap_feat = F.interpolate(dict_feat[select_idx:select_idx + 1], part_feat.size()[2:4])
119
+ # attention
120
+ attn = self.attn_blocks[f'{part_name}_' + str(f_size)](swap_feat - part_feat)
121
+ attn_feat = attn * swap_feat
122
+ # update features
123
+ updated_feat[:, :, location[1]:location[3], location[0]:location[2]] = attn_feat + part_feat
124
+ return updated_feat
125
+
126
+ def put_dict_to_device(self, x):
127
+ if self.flag_dict_device is False:
128
+ for k, v in self.dict.items():
129
+ for kk, vv in v.items():
130
+ self.dict[k][kk] = vv.to(x)
131
+ self.flag_dict_device = True
132
+
133
+ def forward(self, x, part_locations):
134
+ """
135
+ Now only support testing with batch size = 0.
136
+
137
+ Args:
138
+ x (Tensor): Input faces with shape (b, c, 512, 512).
139
+ part_locations (list[Tensor]): Part locations.
140
+ """
141
+ self.put_dict_to_device(x)
142
+ # extract vggface features
143
+ vgg_features = self.vgg_extractor(x)
144
+ # update vggface features using the dictionary for each part
145
+ updated_vgg_features = []
146
+ batch = 0 # only supports testing with batch size = 0
147
+ for vgg_layer, f_size in zip(self.vgg_layers, self.feature_sizes):
148
+ dict_features = self.dict[f'{f_size}']
149
+ vgg_feat = vgg_features[vgg_layer]
150
+ updated_feat = vgg_feat.clone()
151
+
152
+ # swap features from dictionary
153
+ for part_idx, part_name in enumerate(self.parts):
154
+ location = (part_locations[part_idx][batch] // (512 / f_size)).int()
155
+ updated_feat = self.swap_feat(vgg_feat, updated_feat, dict_features[part_name], location, part_name,
156
+ f_size)
157
+
158
+ updated_vgg_features.append(updated_feat)
159
+
160
+ vgg_feat_dilation = self.multi_scale_dilation(vgg_features['conv5_4'])
161
+ # use updated vgg features to modulate the upsampled features with
162
+ # SFT (Spatial Feature Transform) scaling and shifting manner.
163
+ upsampled_feat = self.upsample0(vgg_feat_dilation, updated_vgg_features[3])
164
+ upsampled_feat = self.upsample1(upsampled_feat, updated_vgg_features[2])
165
+ upsampled_feat = self.upsample2(upsampled_feat, updated_vgg_features[1])
166
+ upsampled_feat = self.upsample3(upsampled_feat, updated_vgg_features[0])
167
+ out = self.upsample4(upsampled_feat)
168
+
169
+ return out
basicsr/archs/dfdnet_util.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ from torch.autograd import Function
5
+ from torch.nn.utils.spectral_norm import spectral_norm
6
+
7
+
8
+ class BlurFunctionBackward(Function):
9
+
10
+ @staticmethod
11
+ def forward(ctx, grad_output, kernel, kernel_flip):
12
+ ctx.save_for_backward(kernel, kernel_flip)
13
+ grad_input = F.conv2d(grad_output, kernel_flip, padding=1, groups=grad_output.shape[1])
14
+ return grad_input
15
+
16
+ @staticmethod
17
+ def backward(ctx, gradgrad_output):
18
+ kernel, _ = ctx.saved_tensors
19
+ grad_input = F.conv2d(gradgrad_output, kernel, padding=1, groups=gradgrad_output.shape[1])
20
+ return grad_input, None, None
21
+
22
+
23
+ class BlurFunction(Function):
24
+
25
+ @staticmethod
26
+ def forward(ctx, x, kernel, kernel_flip):
27
+ ctx.save_for_backward(kernel, kernel_flip)
28
+ output = F.conv2d(x, kernel, padding=1, groups=x.shape[1])
29
+ return output
30
+
31
+ @staticmethod
32
+ def backward(ctx, grad_output):
33
+ kernel, kernel_flip = ctx.saved_tensors
34
+ grad_input = BlurFunctionBackward.apply(grad_output, kernel, kernel_flip)
35
+ return grad_input, None, None
36
+
37
+
38
+ blur = BlurFunction.apply
39
+
40
+
41
+ class Blur(nn.Module):
42
+
43
+ def __init__(self, channel):
44
+ super().__init__()
45
+ kernel = torch.tensor([[1, 2, 1], [2, 4, 2], [1, 2, 1]], dtype=torch.float32)
46
+ kernel = kernel.view(1, 1, 3, 3)
47
+ kernel = kernel / kernel.sum()
48
+ kernel_flip = torch.flip(kernel, [2, 3])
49
+
50
+ self.kernel = kernel.repeat(channel, 1, 1, 1)
51
+ self.kernel_flip = kernel_flip.repeat(channel, 1, 1, 1)
52
+
53
+ def forward(self, x):
54
+ return blur(x, self.kernel.type_as(x), self.kernel_flip.type_as(x))
55
+
56
+
57
+ def calc_mean_std(feat, eps=1e-5):
58
+ """Calculate mean and std for adaptive_instance_normalization.
59
+
60
+ Args:
61
+ feat (Tensor): 4D tensor.
62
+ eps (float): A small value added to the variance to avoid
63
+ divide-by-zero. Default: 1e-5.
64
+ """
65
+ size = feat.size()
66
+ assert len(size) == 4, 'The input feature should be 4D tensor.'
67
+ n, c = size[:2]
68
+ feat_var = feat.view(n, c, -1).var(dim=2) + eps
69
+ feat_std = feat_var.sqrt().view(n, c, 1, 1)
70
+ feat_mean = feat.view(n, c, -1).mean(dim=2).view(n, c, 1, 1)
71
+ return feat_mean, feat_std
72
+
73
+
74
+ def adaptive_instance_normalization(content_feat, style_feat):
75
+ """Adaptive instance normalization.
76
+
77
+ Adjust the reference features to have the similar color and illuminations
78
+ as those in the degradate features.
79
+
80
+ Args:
81
+ content_feat (Tensor): The reference feature.
82
+ style_feat (Tensor): The degradate features.
83
+ """
84
+ size = content_feat.size()
85
+ style_mean, style_std = calc_mean_std(style_feat)
86
+ content_mean, content_std = calc_mean_std(content_feat)
87
+ normalized_feat = (content_feat - content_mean.expand(size)) / content_std.expand(size)
88
+ return normalized_feat * style_std.expand(size) + style_mean.expand(size)
89
+
90
+
91
+ def AttentionBlock(in_channel):
92
+ return nn.Sequential(
93
+ spectral_norm(nn.Conv2d(in_channel, in_channel, 3, 1, 1)), nn.LeakyReLU(0.2, True),
94
+ spectral_norm(nn.Conv2d(in_channel, in_channel, 3, 1, 1)))
95
+
96
+
97
+ def conv_block(in_channels, out_channels, kernel_size=3, stride=1, dilation=1, bias=True):
98
+ """Conv block used in MSDilationBlock."""
99
+
100
+ return nn.Sequential(
101
+ spectral_norm(
102
+ nn.Conv2d(
103
+ in_channels,
104
+ out_channels,
105
+ kernel_size=kernel_size,
106
+ stride=stride,
107
+ dilation=dilation,
108
+ padding=((kernel_size - 1) // 2) * dilation,
109
+ bias=bias)),
110
+ nn.LeakyReLU(0.2),
111
+ spectral_norm(
112
+ nn.Conv2d(
113
+ out_channels,
114
+ out_channels,
115
+ kernel_size=kernel_size,
116
+ stride=stride,
117
+ dilation=dilation,
118
+ padding=((kernel_size - 1) // 2) * dilation,
119
+ bias=bias)),
120
+ )
121
+
122
+
123
+ class MSDilationBlock(nn.Module):
124
+ """Multi-scale dilation block."""
125
+
126
+ def __init__(self, in_channels, kernel_size=3, dilation=(1, 1, 1, 1), bias=True):
127
+ super(MSDilationBlock, self).__init__()
128
+
129
+ self.conv_blocks = nn.ModuleList()
130
+ for i in range(4):
131
+ self.conv_blocks.append(conv_block(in_channels, in_channels, kernel_size, dilation=dilation[i], bias=bias))
132
+ self.conv_fusion = spectral_norm(
133
+ nn.Conv2d(
134
+ in_channels * 4,
135
+ in_channels,
136
+ kernel_size=kernel_size,
137
+ stride=1,
138
+ padding=(kernel_size - 1) // 2,
139
+ bias=bias))
140
+
141
+ def forward(self, x):
142
+ out = []
143
+ for i in range(4):
144
+ out.append(self.conv_blocks[i](x))
145
+ out = torch.cat(out, 1)
146
+ out = self.conv_fusion(out) + x
147
+ return out
148
+
149
+
150
+ class UpResBlock(nn.Module):
151
+
152
+ def __init__(self, in_channel):
153
+ super(UpResBlock, self).__init__()
154
+ self.body = nn.Sequential(
155
+ nn.Conv2d(in_channel, in_channel, 3, 1, 1),
156
+ nn.LeakyReLU(0.2, True),
157
+ nn.Conv2d(in_channel, in_channel, 3, 1, 1),
158
+ )
159
+
160
+ def forward(self, x):
161
+ out = x + self.body(x)
162
+ return out
basicsr/archs/discriminator_arch.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn as nn
2
+ from torch.nn import functional as F
3
+ from torch.nn.utils import spectral_norm
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+
7
+
8
+ @ARCH_REGISTRY.register()
9
+ class VGGStyleDiscriminator(nn.Module):
10
+ """VGG style discriminator with input size 128 x 128 or 256 x 256.
11
+
12
+ It is used to train SRGAN, ESRGAN, and VideoGAN.
13
+
14
+ Args:
15
+ num_in_ch (int): Channel number of inputs. Default: 3.
16
+ num_feat (int): Channel number of base intermediate features.Default: 64.
17
+ """
18
+
19
+ def __init__(self, num_in_ch, num_feat, input_size=128):
20
+ super(VGGStyleDiscriminator, self).__init__()
21
+ self.input_size = input_size
22
+ assert self.input_size == 128 or self.input_size == 256, (
23
+ f'input size must be 128 or 256, but received {input_size}')
24
+
25
+ self.conv0_0 = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1, bias=True)
26
+ self.conv0_1 = nn.Conv2d(num_feat, num_feat, 4, 2, 1, bias=False)
27
+ self.bn0_1 = nn.BatchNorm2d(num_feat, affine=True)
28
+
29
+ self.conv1_0 = nn.Conv2d(num_feat, num_feat * 2, 3, 1, 1, bias=False)
30
+ self.bn1_0 = nn.BatchNorm2d(num_feat * 2, affine=True)
31
+ self.conv1_1 = nn.Conv2d(num_feat * 2, num_feat * 2, 4, 2, 1, bias=False)
32
+ self.bn1_1 = nn.BatchNorm2d(num_feat * 2, affine=True)
33
+
34
+ self.conv2_0 = nn.Conv2d(num_feat * 2, num_feat * 4, 3, 1, 1, bias=False)
35
+ self.bn2_0 = nn.BatchNorm2d(num_feat * 4, affine=True)
36
+ self.conv2_1 = nn.Conv2d(num_feat * 4, num_feat * 4, 4, 2, 1, bias=False)
37
+ self.bn2_1 = nn.BatchNorm2d(num_feat * 4, affine=True)
38
+
39
+ self.conv3_0 = nn.Conv2d(num_feat * 4, num_feat * 8, 3, 1, 1, bias=False)
40
+ self.bn3_0 = nn.BatchNorm2d(num_feat * 8, affine=True)
41
+ self.conv3_1 = nn.Conv2d(num_feat * 8, num_feat * 8, 4, 2, 1, bias=False)
42
+ self.bn3_1 = nn.BatchNorm2d(num_feat * 8, affine=True)
43
+
44
+ self.conv4_0 = nn.Conv2d(num_feat * 8, num_feat * 8, 3, 1, 1, bias=False)
45
+ self.bn4_0 = nn.BatchNorm2d(num_feat * 8, affine=True)
46
+ self.conv4_1 = nn.Conv2d(num_feat * 8, num_feat * 8, 4, 2, 1, bias=False)
47
+ self.bn4_1 = nn.BatchNorm2d(num_feat * 8, affine=True)
48
+
49
+ if self.input_size == 256:
50
+ self.conv5_0 = nn.Conv2d(num_feat * 8, num_feat * 8, 3, 1, 1, bias=False)
51
+ self.bn5_0 = nn.BatchNorm2d(num_feat * 8, affine=True)
52
+ self.conv5_1 = nn.Conv2d(num_feat * 8, num_feat * 8, 4, 2, 1, bias=False)
53
+ self.bn5_1 = nn.BatchNorm2d(num_feat * 8, affine=True)
54
+
55
+ self.linear1 = nn.Linear(num_feat * 8 * 4 * 4, 100)
56
+ self.linear2 = nn.Linear(100, 1)
57
+
58
+ # activation function
59
+ self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
60
+
61
+ def forward(self, x):
62
+ assert x.size(2) == self.input_size, (f'Input size must be identical to input_size, but received {x.size()}.')
63
+
64
+ feat = self.lrelu(self.conv0_0(x))
65
+ feat = self.lrelu(self.bn0_1(self.conv0_1(feat))) # output spatial size: /2
66
+
67
+ feat = self.lrelu(self.bn1_0(self.conv1_0(feat)))
68
+ feat = self.lrelu(self.bn1_1(self.conv1_1(feat))) # output spatial size: /4
69
+
70
+ feat = self.lrelu(self.bn2_0(self.conv2_0(feat)))
71
+ feat = self.lrelu(self.bn2_1(self.conv2_1(feat))) # output spatial size: /8
72
+
73
+ feat = self.lrelu(self.bn3_0(self.conv3_0(feat)))
74
+ feat = self.lrelu(self.bn3_1(self.conv3_1(feat))) # output spatial size: /16
75
+
76
+ feat = self.lrelu(self.bn4_0(self.conv4_0(feat)))
77
+ feat = self.lrelu(self.bn4_1(self.conv4_1(feat))) # output spatial size: /32
78
+
79
+ if self.input_size == 256:
80
+ feat = self.lrelu(self.bn5_0(self.conv5_0(feat)))
81
+ feat = self.lrelu(self.bn5_1(self.conv5_1(feat))) # output spatial size: / 64
82
+
83
+ # spatial size: (4, 4)
84
+ feat = feat.view(feat.size(0), -1)
85
+ feat = self.lrelu(self.linear1(feat))
86
+ out = self.linear2(feat)
87
+ return out
88
+
89
+
90
+ @ARCH_REGISTRY.register(suffix='basicsr')
91
+ class UNetDiscriminatorSN(nn.Module):
92
+ """Defines a U-Net discriminator with spectral normalization (SN)
93
+
94
+ It is used in Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data.
95
+
96
+ Arg:
97
+ num_in_ch (int): Channel number of inputs. Default: 3.
98
+ num_feat (int): Channel number of base intermediate features. Default: 64.
99
+ skip_connection (bool): Whether to use skip connections between U-Net. Default: True.
100
+ """
101
+
102
+ def __init__(self, num_in_ch, num_feat=64, skip_connection=True):
103
+ super(UNetDiscriminatorSN, self).__init__()
104
+ self.skip_connection = skip_connection
105
+ norm = spectral_norm
106
+ # the first convolution
107
+ self.conv0 = nn.Conv2d(num_in_ch, num_feat, kernel_size=3, stride=1, padding=1)
108
+ # downsample
109
+ self.conv1 = norm(nn.Conv2d(num_feat, num_feat * 2, 4, 2, 1, bias=False))
110
+ self.conv2 = norm(nn.Conv2d(num_feat * 2, num_feat * 4, 4, 2, 1, bias=False))
111
+ self.conv3 = norm(nn.Conv2d(num_feat * 4, num_feat * 8, 4, 2, 1, bias=False))
112
+ # upsample
113
+ self.conv4 = norm(nn.Conv2d(num_feat * 8, num_feat * 4, 3, 1, 1, bias=False))
114
+ self.conv5 = norm(nn.Conv2d(num_feat * 4, num_feat * 2, 3, 1, 1, bias=False))
115
+ self.conv6 = norm(nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1, bias=False))
116
+ # extra convolutions
117
+ self.conv7 = norm(nn.Conv2d(num_feat, num_feat, 3, 1, 1, bias=False))
118
+ self.conv8 = norm(nn.Conv2d(num_feat, num_feat, 3, 1, 1, bias=False))
119
+ self.conv9 = nn.Conv2d(num_feat, 1, 3, 1, 1)
120
+
121
+ def forward(self, x):
122
+ # downsample
123
+ x0 = F.leaky_relu(self.conv0(x), negative_slope=0.2, inplace=True)
124
+ x1 = F.leaky_relu(self.conv1(x0), negative_slope=0.2, inplace=True)
125
+ x2 = F.leaky_relu(self.conv2(x1), negative_slope=0.2, inplace=True)
126
+ x3 = F.leaky_relu(self.conv3(x2), negative_slope=0.2, inplace=True)
127
+
128
+ # upsample
129
+ x3 = F.interpolate(x3, scale_factor=2, mode='bilinear', align_corners=False)
130
+ x4 = F.leaky_relu(self.conv4(x3), negative_slope=0.2, inplace=True)
131
+
132
+ if self.skip_connection:
133
+ x4 = x4 + x2
134
+ x4 = F.interpolate(x4, scale_factor=2, mode='bilinear', align_corners=False)
135
+ x5 = F.leaky_relu(self.conv5(x4), negative_slope=0.2, inplace=True)
136
+
137
+ if self.skip_connection:
138
+ x5 = x5 + x1
139
+ x5 = F.interpolate(x5, scale_factor=2, mode='bilinear', align_corners=False)
140
+ x6 = F.leaky_relu(self.conv6(x5), negative_slope=0.2, inplace=True)
141
+
142
+ if self.skip_connection:
143
+ x6 = x6 + x0
144
+
145
+ # extra convolutions
146
+ out = F.leaky_relu(self.conv7(x6), negative_slope=0.2, inplace=True)
147
+ out = F.leaky_relu(self.conv8(out), negative_slope=0.2, inplace=True)
148
+ out = self.conv9(out)
149
+
150
+ return out
basicsr/archs/duf_arch.py ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ from torch import nn as nn
4
+ from torch.nn import functional as F
5
+
6
+ from basicsr.utils.registry import ARCH_REGISTRY
7
+
8
+
9
+ class DenseBlocksTemporalReduce(nn.Module):
10
+ """A concatenation of 3 dense blocks with reduction in temporal dimension.
11
+
12
+ Note that the output temporal dimension is 6 fewer the input temporal dimension, since there are 3 blocks.
13
+
14
+ Args:
15
+ num_feat (int): Number of channels in the blocks. Default: 64.
16
+ num_grow_ch (int): Growing factor of the dense blocks. Default: 32
17
+ adapt_official_weights (bool): Whether to adapt the weights translated from the official implementation.
18
+ Set to false if you want to train from scratch. Default: False.
19
+ """
20
+
21
+ def __init__(self, num_feat=64, num_grow_ch=32, adapt_official_weights=False):
22
+ super(DenseBlocksTemporalReduce, self).__init__()
23
+ if adapt_official_weights:
24
+ eps = 1e-3
25
+ momentum = 1e-3
26
+ else: # pytorch default values
27
+ eps = 1e-05
28
+ momentum = 0.1
29
+
30
+ self.temporal_reduce1 = nn.Sequential(
31
+ nn.BatchNorm3d(num_feat, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
32
+ nn.Conv3d(num_feat, num_feat, (1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=True),
33
+ nn.BatchNorm3d(num_feat, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
34
+ nn.Conv3d(num_feat, num_grow_ch, (3, 3, 3), stride=(1, 1, 1), padding=(0, 1, 1), bias=True))
35
+
36
+ self.temporal_reduce2 = nn.Sequential(
37
+ nn.BatchNorm3d(num_feat + num_grow_ch, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
38
+ nn.Conv3d(
39
+ num_feat + num_grow_ch,
40
+ num_feat + num_grow_ch, (1, 1, 1),
41
+ stride=(1, 1, 1),
42
+ padding=(0, 0, 0),
43
+ bias=True), nn.BatchNorm3d(num_feat + num_grow_ch, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
44
+ nn.Conv3d(num_feat + num_grow_ch, num_grow_ch, (3, 3, 3), stride=(1, 1, 1), padding=(0, 1, 1), bias=True))
45
+
46
+ self.temporal_reduce3 = nn.Sequential(
47
+ nn.BatchNorm3d(num_feat + 2 * num_grow_ch, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
48
+ nn.Conv3d(
49
+ num_feat + 2 * num_grow_ch,
50
+ num_feat + 2 * num_grow_ch, (1, 1, 1),
51
+ stride=(1, 1, 1),
52
+ padding=(0, 0, 0),
53
+ bias=True), nn.BatchNorm3d(num_feat + 2 * num_grow_ch, eps=eps, momentum=momentum),
54
+ nn.ReLU(inplace=True),
55
+ nn.Conv3d(
56
+ num_feat + 2 * num_grow_ch, num_grow_ch, (3, 3, 3), stride=(1, 1, 1), padding=(0, 1, 1), bias=True))
57
+
58
+ def forward(self, x):
59
+ """
60
+ Args:
61
+ x (Tensor): Input tensor with shape (b, num_feat, t, h, w).
62
+
63
+ Returns:
64
+ Tensor: Output with shape (b, num_feat + num_grow_ch * 3, 1, h, w).
65
+ """
66
+ x1 = self.temporal_reduce1(x)
67
+ x1 = torch.cat((x[:, :, 1:-1, :, :], x1), 1)
68
+
69
+ x2 = self.temporal_reduce2(x1)
70
+ x2 = torch.cat((x1[:, :, 1:-1, :, :], x2), 1)
71
+
72
+ x3 = self.temporal_reduce3(x2)
73
+ x3 = torch.cat((x2[:, :, 1:-1, :, :], x3), 1)
74
+
75
+ return x3
76
+
77
+
78
+ class DenseBlocks(nn.Module):
79
+ """ A concatenation of N dense blocks.
80
+
81
+ Args:
82
+ num_feat (int): Number of channels in the blocks. Default: 64.
83
+ num_grow_ch (int): Growing factor of the dense blocks. Default: 32.
84
+ num_block (int): Number of dense blocks. The values are:
85
+ DUF-S (16 layers): 3
86
+ DUF-M (18 layers): 9
87
+ DUF-L (52 layers): 21
88
+ adapt_official_weights (bool): Whether to adapt the weights translated from the official implementation.
89
+ Set to false if you want to train from scratch. Default: False.
90
+ """
91
+
92
+ def __init__(self, num_block, num_feat=64, num_grow_ch=16, adapt_official_weights=False):
93
+ super(DenseBlocks, self).__init__()
94
+ if adapt_official_weights:
95
+ eps = 1e-3
96
+ momentum = 1e-3
97
+ else: # pytorch default values
98
+ eps = 1e-05
99
+ momentum = 0.1
100
+
101
+ self.dense_blocks = nn.ModuleList()
102
+ for i in range(0, num_block):
103
+ self.dense_blocks.append(
104
+ nn.Sequential(
105
+ nn.BatchNorm3d(num_feat + i * num_grow_ch, eps=eps, momentum=momentum), nn.ReLU(inplace=True),
106
+ nn.Conv3d(
107
+ num_feat + i * num_grow_ch,
108
+ num_feat + i * num_grow_ch, (1, 1, 1),
109
+ stride=(1, 1, 1),
110
+ padding=(0, 0, 0),
111
+ bias=True), nn.BatchNorm3d(num_feat + i * num_grow_ch, eps=eps, momentum=momentum),
112
+ nn.ReLU(inplace=True),
113
+ nn.Conv3d(
114
+ num_feat + i * num_grow_ch,
115
+ num_grow_ch, (3, 3, 3),
116
+ stride=(1, 1, 1),
117
+ padding=(1, 1, 1),
118
+ bias=True)))
119
+
120
+ def forward(self, x):
121
+ """
122
+ Args:
123
+ x (Tensor): Input tensor with shape (b, num_feat, t, h, w).
124
+
125
+ Returns:
126
+ Tensor: Output with shape (b, num_feat + num_block * num_grow_ch, t, h, w).
127
+ """
128
+ for i in range(0, len(self.dense_blocks)):
129
+ y = self.dense_blocks[i](x)
130
+ x = torch.cat((x, y), 1)
131
+ return x
132
+
133
+
134
+ class DynamicUpsamplingFilter(nn.Module):
135
+ """Dynamic upsampling filter used in DUF.
136
+
137
+ Reference: https://github.com/yhjo09/VSR-DUF
138
+
139
+ It only supports input with 3 channels. And it applies the same filters to 3 channels.
140
+
141
+ Args:
142
+ filter_size (tuple): Filter size of generated filters. The shape is (kh, kw). Default: (5, 5).
143
+ """
144
+
145
+ def __init__(self, filter_size=(5, 5)):
146
+ super(DynamicUpsamplingFilter, self).__init__()
147
+ if not isinstance(filter_size, tuple):
148
+ raise TypeError(f'The type of filter_size must be tuple, but got type{filter_size}')
149
+ if len(filter_size) != 2:
150
+ raise ValueError(f'The length of filter size must be 2, but got {len(filter_size)}.')
151
+ # generate a local expansion filter, similar to im2col
152
+ self.filter_size = filter_size
153
+ filter_prod = np.prod(filter_size)
154
+ expansion_filter = torch.eye(int(filter_prod)).view(filter_prod, 1, *filter_size) # (kh*kw, 1, kh, kw)
155
+ self.expansion_filter = expansion_filter.repeat(3, 1, 1, 1) # repeat for all the 3 channels
156
+
157
+ def forward(self, x, filters):
158
+ """Forward function for DynamicUpsamplingFilter.
159
+
160
+ Args:
161
+ x (Tensor): Input image with 3 channels. The shape is (n, 3, h, w).
162
+ filters (Tensor): Generated dynamic filters. The shape is (n, filter_prod, upsampling_square, h, w).
163
+ filter_prod: prod of filter kernel size, e.g., 1*5*5=25.
164
+ upsampling_square: similar to pixel shuffle, upsampling_square = upsampling * upsampling.
165
+ e.g., for x 4 upsampling, upsampling_square= 4*4 = 16
166
+
167
+ Returns:
168
+ Tensor: Filtered image with shape (n, 3*upsampling_square, h, w)
169
+ """
170
+ n, filter_prod, upsampling_square, h, w = filters.size()
171
+ kh, kw = self.filter_size
172
+ expanded_input = F.conv2d(
173
+ x, self.expansion_filter.to(x), padding=(kh // 2, kw // 2), groups=3) # (n, 3*filter_prod, h, w)
174
+ expanded_input = expanded_input.view(n, 3, filter_prod, h, w).permute(0, 3, 4, 1,
175
+ 2) # (n, h, w, 3, filter_prod)
176
+ filters = filters.permute(0, 3, 4, 1, 2) # (n, h, w, filter_prod, upsampling_square]
177
+ out = torch.matmul(expanded_input, filters) # (n, h, w, 3, upsampling_square)
178
+ return out.permute(0, 3, 4, 1, 2).view(n, 3 * upsampling_square, h, w)
179
+
180
+
181
+ @ARCH_REGISTRY.register()
182
+ class DUF(nn.Module):
183
+ """Network architecture for DUF
184
+
185
+ ``Paper: Deep Video Super-Resolution Network Using Dynamic Upsampling Filters Without Explicit Motion Compensation``
186
+
187
+ Reference: https://github.com/yhjo09/VSR-DUF
188
+
189
+ For all the models below, 'adapt_official_weights' is only necessary when
190
+ loading the weights converted from the official TensorFlow weights.
191
+ Please set it to False if you are training the model from scratch.
192
+
193
+ There are three models with different model size: DUF16Layers, DUF28Layers,
194
+ and DUF52Layers. This class is the base class for these models.
195
+
196
+ Args:
197
+ scale (int): The upsampling factor. Default: 4.
198
+ num_layer (int): The number of layers. Default: 52.
199
+ adapt_official_weights_weights (bool): Whether to adapt the weights
200
+ translated from the official implementation. Set to false if you
201
+ want to train from scratch. Default: False.
202
+ """
203
+
204
+ def __init__(self, scale=4, num_layer=52, adapt_official_weights=False):
205
+ super(DUF, self).__init__()
206
+ self.scale = scale
207
+ if adapt_official_weights:
208
+ eps = 1e-3
209
+ momentum = 1e-3
210
+ else: # pytorch default values
211
+ eps = 1e-05
212
+ momentum = 0.1
213
+
214
+ self.conv3d1 = nn.Conv3d(3, 64, (1, 3, 3), stride=(1, 1, 1), padding=(0, 1, 1), bias=True)
215
+ self.dynamic_filter = DynamicUpsamplingFilter((5, 5))
216
+
217
+ if num_layer == 16:
218
+ num_block = 3
219
+ num_grow_ch = 32
220
+ elif num_layer == 28:
221
+ num_block = 9
222
+ num_grow_ch = 16
223
+ elif num_layer == 52:
224
+ num_block = 21
225
+ num_grow_ch = 16
226
+ else:
227
+ raise ValueError(f'Only supported (16, 28, 52) layers, but got {num_layer}.')
228
+
229
+ self.dense_block1 = DenseBlocks(
230
+ num_block=num_block, num_feat=64, num_grow_ch=num_grow_ch,
231
+ adapt_official_weights=adapt_official_weights) # T = 7
232
+ self.dense_block2 = DenseBlocksTemporalReduce(
233
+ 64 + num_grow_ch * num_block, num_grow_ch, adapt_official_weights=adapt_official_weights) # T = 1
234
+ channels = 64 + num_grow_ch * num_block + num_grow_ch * 3
235
+ self.bn3d2 = nn.BatchNorm3d(channels, eps=eps, momentum=momentum)
236
+ self.conv3d2 = nn.Conv3d(channels, 256, (1, 3, 3), stride=(1, 1, 1), padding=(0, 1, 1), bias=True)
237
+
238
+ self.conv3d_r1 = nn.Conv3d(256, 256, (1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=True)
239
+ self.conv3d_r2 = nn.Conv3d(256, 3 * (scale**2), (1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=True)
240
+
241
+ self.conv3d_f1 = nn.Conv3d(256, 512, (1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=True)
242
+ self.conv3d_f2 = nn.Conv3d(
243
+ 512, 1 * 5 * 5 * (scale**2), (1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=True)
244
+
245
+ def forward(self, x):
246
+ """
247
+ Args:
248
+ x (Tensor): Input with shape (b, 7, c, h, w)
249
+
250
+ Returns:
251
+ Tensor: Output with shape (b, c, h * scale, w * scale)
252
+ """
253
+ num_batches, num_imgs, _, h, w = x.size()
254
+
255
+ x = x.permute(0, 2, 1, 3, 4) # (b, c, 7, h, w) for Conv3D
256
+ x_center = x[:, :, num_imgs // 2, :, :]
257
+
258
+ x = self.conv3d1(x)
259
+ x = self.dense_block1(x)
260
+ x = self.dense_block2(x)
261
+ x = F.relu(self.bn3d2(x), inplace=True)
262
+ x = F.relu(self.conv3d2(x), inplace=True)
263
+
264
+ # residual image
265
+ res = self.conv3d_r2(F.relu(self.conv3d_r1(x), inplace=True))
266
+
267
+ # filter
268
+ filter_ = self.conv3d_f2(F.relu(self.conv3d_f1(x), inplace=True))
269
+ filter_ = F.softmax(filter_.view(num_batches, 25, self.scale**2, h, w), dim=1)
270
+
271
+ # dynamic filter
272
+ out = self.dynamic_filter(x_center, filter_)
273
+ out += res.squeeze_(2)
274
+ out = F.pixel_shuffle(out, self.scale)
275
+
276
+ return out
basicsr/archs/ecbsr_arch.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+
7
+
8
+ class SeqConv3x3(nn.Module):
9
+ """The re-parameterizable block used in the ECBSR architecture.
10
+
11
+ ``Paper: Edge-oriented Convolution Block for Real-time Super Resolution on Mobile Devices``
12
+
13
+ Reference: https://github.com/xindongzhang/ECBSR
14
+
15
+ Args:
16
+ seq_type (str): Sequence type, option: conv1x1-conv3x3 | conv1x1-sobelx | conv1x1-sobely | conv1x1-laplacian.
17
+ in_channels (int): Channel number of input.
18
+ out_channels (int): Channel number of output.
19
+ depth_multiplier (int): Width multiplier in the expand-and-squeeze conv. Default: 1.
20
+ """
21
+
22
+ def __init__(self, seq_type, in_channels, out_channels, depth_multiplier=1):
23
+ super(SeqConv3x3, self).__init__()
24
+ self.seq_type = seq_type
25
+ self.in_channels = in_channels
26
+ self.out_channels = out_channels
27
+
28
+ if self.seq_type == 'conv1x1-conv3x3':
29
+ self.mid_planes = int(out_channels * depth_multiplier)
30
+ conv0 = torch.nn.Conv2d(self.in_channels, self.mid_planes, kernel_size=1, padding=0)
31
+ self.k0 = conv0.weight
32
+ self.b0 = conv0.bias
33
+
34
+ conv1 = torch.nn.Conv2d(self.mid_planes, self.out_channels, kernel_size=3)
35
+ self.k1 = conv1.weight
36
+ self.b1 = conv1.bias
37
+
38
+ elif self.seq_type == 'conv1x1-sobelx':
39
+ conv0 = torch.nn.Conv2d(self.in_channels, self.out_channels, kernel_size=1, padding=0)
40
+ self.k0 = conv0.weight
41
+ self.b0 = conv0.bias
42
+
43
+ # init scale and bias
44
+ scale = torch.randn(size=(self.out_channels, 1, 1, 1)) * 1e-3
45
+ self.scale = nn.Parameter(scale)
46
+ bias = torch.randn(self.out_channels) * 1e-3
47
+ bias = torch.reshape(bias, (self.out_channels, ))
48
+ self.bias = nn.Parameter(bias)
49
+ # init mask
50
+ self.mask = torch.zeros((self.out_channels, 1, 3, 3), dtype=torch.float32)
51
+ for i in range(self.out_channels):
52
+ self.mask[i, 0, 0, 0] = 1.0
53
+ self.mask[i, 0, 1, 0] = 2.0
54
+ self.mask[i, 0, 2, 0] = 1.0
55
+ self.mask[i, 0, 0, 2] = -1.0
56
+ self.mask[i, 0, 1, 2] = -2.0
57
+ self.mask[i, 0, 2, 2] = -1.0
58
+ self.mask = nn.Parameter(data=self.mask, requires_grad=False)
59
+
60
+ elif self.seq_type == 'conv1x1-sobely':
61
+ conv0 = torch.nn.Conv2d(self.in_channels, self.out_channels, kernel_size=1, padding=0)
62
+ self.k0 = conv0.weight
63
+ self.b0 = conv0.bias
64
+
65
+ # init scale and bias
66
+ scale = torch.randn(size=(self.out_channels, 1, 1, 1)) * 1e-3
67
+ self.scale = nn.Parameter(torch.FloatTensor(scale))
68
+ bias = torch.randn(self.out_channels) * 1e-3
69
+ bias = torch.reshape(bias, (self.out_channels, ))
70
+ self.bias = nn.Parameter(torch.FloatTensor(bias))
71
+ # init mask
72
+ self.mask = torch.zeros((self.out_channels, 1, 3, 3), dtype=torch.float32)
73
+ for i in range(self.out_channels):
74
+ self.mask[i, 0, 0, 0] = 1.0
75
+ self.mask[i, 0, 0, 1] = 2.0
76
+ self.mask[i, 0, 0, 2] = 1.0
77
+ self.mask[i, 0, 2, 0] = -1.0
78
+ self.mask[i, 0, 2, 1] = -2.0
79
+ self.mask[i, 0, 2, 2] = -1.0
80
+ self.mask = nn.Parameter(data=self.mask, requires_grad=False)
81
+
82
+ elif self.seq_type == 'conv1x1-laplacian':
83
+ conv0 = torch.nn.Conv2d(self.in_channels, self.out_channels, kernel_size=1, padding=0)
84
+ self.k0 = conv0.weight
85
+ self.b0 = conv0.bias
86
+
87
+ # init scale and bias
88
+ scale = torch.randn(size=(self.out_channels, 1, 1, 1)) * 1e-3
89
+ self.scale = nn.Parameter(torch.FloatTensor(scale))
90
+ bias = torch.randn(self.out_channels) * 1e-3
91
+ bias = torch.reshape(bias, (self.out_channels, ))
92
+ self.bias = nn.Parameter(torch.FloatTensor(bias))
93
+ # init mask
94
+ self.mask = torch.zeros((self.out_channels, 1, 3, 3), dtype=torch.float32)
95
+ for i in range(self.out_channels):
96
+ self.mask[i, 0, 0, 1] = 1.0
97
+ self.mask[i, 0, 1, 0] = 1.0
98
+ self.mask[i, 0, 1, 2] = 1.0
99
+ self.mask[i, 0, 2, 1] = 1.0
100
+ self.mask[i, 0, 1, 1] = -4.0
101
+ self.mask = nn.Parameter(data=self.mask, requires_grad=False)
102
+ else:
103
+ raise ValueError('The type of seqconv is not supported!')
104
+
105
+ def forward(self, x):
106
+ if self.seq_type == 'conv1x1-conv3x3':
107
+ # conv-1x1
108
+ y0 = F.conv2d(input=x, weight=self.k0, bias=self.b0, stride=1)
109
+ # explicitly padding with bias
110
+ y0 = F.pad(y0, (1, 1, 1, 1), 'constant', 0)
111
+ b0_pad = self.b0.view(1, -1, 1, 1)
112
+ y0[:, :, 0:1, :] = b0_pad
113
+ y0[:, :, -1:, :] = b0_pad
114
+ y0[:, :, :, 0:1] = b0_pad
115
+ y0[:, :, :, -1:] = b0_pad
116
+ # conv-3x3
117
+ y1 = F.conv2d(input=y0, weight=self.k1, bias=self.b1, stride=1)
118
+ else:
119
+ y0 = F.conv2d(input=x, weight=self.k0, bias=self.b0, stride=1)
120
+ # explicitly padding with bias
121
+ y0 = F.pad(y0, (1, 1, 1, 1), 'constant', 0)
122
+ b0_pad = self.b0.view(1, -1, 1, 1)
123
+ y0[:, :, 0:1, :] = b0_pad
124
+ y0[:, :, -1:, :] = b0_pad
125
+ y0[:, :, :, 0:1] = b0_pad
126
+ y0[:, :, :, -1:] = b0_pad
127
+ # conv-3x3
128
+ y1 = F.conv2d(input=y0, weight=self.scale * self.mask, bias=self.bias, stride=1, groups=self.out_channels)
129
+ return y1
130
+
131
+ def rep_params(self):
132
+ device = self.k0.get_device()
133
+ if device < 0:
134
+ device = None
135
+
136
+ if self.seq_type == 'conv1x1-conv3x3':
137
+ # re-param conv kernel
138
+ rep_weight = F.conv2d(input=self.k1, weight=self.k0.permute(1, 0, 2, 3))
139
+ # re-param conv bias
140
+ rep_bias = torch.ones(1, self.mid_planes, 3, 3, device=device) * self.b0.view(1, -1, 1, 1)
141
+ rep_bias = F.conv2d(input=rep_bias, weight=self.k1).view(-1, ) + self.b1
142
+ else:
143
+ tmp = self.scale * self.mask
144
+ k1 = torch.zeros((self.out_channels, self.out_channels, 3, 3), device=device)
145
+ for i in range(self.out_channels):
146
+ k1[i, i, :, :] = tmp[i, 0, :, :]
147
+ b1 = self.bias
148
+ # re-param conv kernel
149
+ rep_weight = F.conv2d(input=k1, weight=self.k0.permute(1, 0, 2, 3))
150
+ # re-param conv bias
151
+ rep_bias = torch.ones(1, self.out_channels, 3, 3, device=device) * self.b0.view(1, -1, 1, 1)
152
+ rep_bias = F.conv2d(input=rep_bias, weight=k1).view(-1, ) + b1
153
+ return rep_weight, rep_bias
154
+
155
+
156
+ class ECB(nn.Module):
157
+ """The ECB block used in the ECBSR architecture.
158
+
159
+ Paper: Edge-oriented Convolution Block for Real-time Super Resolution on Mobile Devices
160
+ Ref git repo: https://github.com/xindongzhang/ECBSR
161
+
162
+ Args:
163
+ in_channels (int): Channel number of input.
164
+ out_channels (int): Channel number of output.
165
+ depth_multiplier (int): Width multiplier in the expand-and-squeeze conv. Default: 1.
166
+ act_type (str): Activation type. Option: prelu | relu | rrelu | softplus | linear. Default: prelu.
167
+ with_idt (bool): Whether to use identity connection. Default: False.
168
+ """
169
+
170
+ def __init__(self, in_channels, out_channels, depth_multiplier, act_type='prelu', with_idt=False):
171
+ super(ECB, self).__init__()
172
+
173
+ self.depth_multiplier = depth_multiplier
174
+ self.in_channels = in_channels
175
+ self.out_channels = out_channels
176
+ self.act_type = act_type
177
+
178
+ if with_idt and (self.in_channels == self.out_channels):
179
+ self.with_idt = True
180
+ else:
181
+ self.with_idt = False
182
+
183
+ self.conv3x3 = torch.nn.Conv2d(self.in_channels, self.out_channels, kernel_size=3, padding=1)
184
+ self.conv1x1_3x3 = SeqConv3x3('conv1x1-conv3x3', self.in_channels, self.out_channels, self.depth_multiplier)
185
+ self.conv1x1_sbx = SeqConv3x3('conv1x1-sobelx', self.in_channels, self.out_channels)
186
+ self.conv1x1_sby = SeqConv3x3('conv1x1-sobely', self.in_channels, self.out_channels)
187
+ self.conv1x1_lpl = SeqConv3x3('conv1x1-laplacian', self.in_channels, self.out_channels)
188
+
189
+ if self.act_type == 'prelu':
190
+ self.act = nn.PReLU(num_parameters=self.out_channels)
191
+ elif self.act_type == 'relu':
192
+ self.act = nn.ReLU(inplace=True)
193
+ elif self.act_type == 'rrelu':
194
+ self.act = nn.RReLU(lower=-0.05, upper=0.05)
195
+ elif self.act_type == 'softplus':
196
+ self.act = nn.Softplus()
197
+ elif self.act_type == 'linear':
198
+ pass
199
+ else:
200
+ raise ValueError('The type of activation if not support!')
201
+
202
+ def forward(self, x):
203
+ if self.training:
204
+ y = self.conv3x3(x) + self.conv1x1_3x3(x) + self.conv1x1_sbx(x) + self.conv1x1_sby(x) + self.conv1x1_lpl(x)
205
+ if self.with_idt:
206
+ y += x
207
+ else:
208
+ rep_weight, rep_bias = self.rep_params()
209
+ y = F.conv2d(input=x, weight=rep_weight, bias=rep_bias, stride=1, padding=1)
210
+ if self.act_type != 'linear':
211
+ y = self.act(y)
212
+ return y
213
+
214
+ def rep_params(self):
215
+ weight0, bias0 = self.conv3x3.weight, self.conv3x3.bias
216
+ weight1, bias1 = self.conv1x1_3x3.rep_params()
217
+ weight2, bias2 = self.conv1x1_sbx.rep_params()
218
+ weight3, bias3 = self.conv1x1_sby.rep_params()
219
+ weight4, bias4 = self.conv1x1_lpl.rep_params()
220
+ rep_weight, rep_bias = (weight0 + weight1 + weight2 + weight3 + weight4), (
221
+ bias0 + bias1 + bias2 + bias3 + bias4)
222
+
223
+ if self.with_idt:
224
+ device = rep_weight.get_device()
225
+ if device < 0:
226
+ device = None
227
+ weight_idt = torch.zeros(self.out_channels, self.out_channels, 3, 3, device=device)
228
+ for i in range(self.out_channels):
229
+ weight_idt[i, i, 1, 1] = 1.0
230
+ bias_idt = 0.0
231
+ rep_weight, rep_bias = rep_weight + weight_idt, rep_bias + bias_idt
232
+ return rep_weight, rep_bias
233
+
234
+
235
+ @ARCH_REGISTRY.register()
236
+ class ECBSR(nn.Module):
237
+ """ECBSR architecture.
238
+
239
+ Paper: Edge-oriented Convolution Block for Real-time Super Resolution on Mobile Devices
240
+ Ref git repo: https://github.com/xindongzhang/ECBSR
241
+
242
+ Args:
243
+ num_in_ch (int): Channel number of inputs.
244
+ num_out_ch (int): Channel number of outputs.
245
+ num_block (int): Block number in the trunk network.
246
+ num_channel (int): Channel number.
247
+ with_idt (bool): Whether use identity in convolution layers.
248
+ act_type (str): Activation type.
249
+ scale (int): Upsampling factor.
250
+ """
251
+
252
+ def __init__(self, num_in_ch, num_out_ch, num_block, num_channel, with_idt, act_type, scale):
253
+ super(ECBSR, self).__init__()
254
+ self.num_in_ch = num_in_ch
255
+ self.scale = scale
256
+
257
+ backbone = []
258
+ backbone += [ECB(num_in_ch, num_channel, depth_multiplier=2.0, act_type=act_type, with_idt=with_idt)]
259
+ for _ in range(num_block):
260
+ backbone += [ECB(num_channel, num_channel, depth_multiplier=2.0, act_type=act_type, with_idt=with_idt)]
261
+ backbone += [
262
+ ECB(num_channel, num_out_ch * scale * scale, depth_multiplier=2.0, act_type='linear', with_idt=with_idt)
263
+ ]
264
+
265
+ self.backbone = nn.Sequential(*backbone)
266
+ self.upsampler = nn.PixelShuffle(scale)
267
+
268
+ def forward(self, x):
269
+ if self.num_in_ch > 1:
270
+ shortcut = torch.repeat_interleave(x, self.scale * self.scale, dim=1)
271
+ else:
272
+ shortcut = x # will repeat the input in the channel dimension (repeat scale * scale times)
273
+ y = self.backbone(x) + shortcut
274
+ y = self.upsampler(y)
275
+ return y
basicsr/archs/edsr_arch.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+
4
+ from basicsr.archs.arch_util import ResidualBlockNoBN, Upsample, make_layer
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+
7
+
8
+ @ARCH_REGISTRY.register()
9
+ class EDSR(nn.Module):
10
+ """EDSR network structure.
11
+
12
+ Paper: Enhanced Deep Residual Networks for Single Image Super-Resolution.
13
+ Ref git repo: https://github.com/thstkdgus35/EDSR-PyTorch
14
+
15
+ Args:
16
+ num_in_ch (int): Channel number of inputs.
17
+ num_out_ch (int): Channel number of outputs.
18
+ num_feat (int): Channel number of intermediate features.
19
+ Default: 64.
20
+ num_block (int): Block number in the trunk network. Default: 16.
21
+ upscale (int): Upsampling factor. Support 2^n and 3.
22
+ Default: 4.
23
+ res_scale (float): Used to scale the residual in residual block.
24
+ Default: 1.
25
+ img_range (float): Image range. Default: 255.
26
+ rgb_mean (tuple[float]): Image mean in RGB orders.
27
+ Default: (0.4488, 0.4371, 0.4040), calculated from DIV2K dataset.
28
+ """
29
+
30
+ def __init__(self,
31
+ num_in_ch,
32
+ num_out_ch,
33
+ num_feat=64,
34
+ num_block=16,
35
+ upscale=4,
36
+ res_scale=1,
37
+ img_range=255.,
38
+ rgb_mean=(0.4488, 0.4371, 0.4040)):
39
+ super(EDSR, self).__init__()
40
+
41
+ self.img_range = img_range
42
+ self.mean = torch.Tensor(rgb_mean).view(1, 3, 1, 1)
43
+
44
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
45
+ self.body = make_layer(ResidualBlockNoBN, num_block, num_feat=num_feat, res_scale=res_scale, pytorch_init=True)
46
+ self.conv_after_body = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
47
+ self.upsample = Upsample(upscale, num_feat)
48
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
49
+
50
+ def forward(self, x):
51
+ self.mean = self.mean.type_as(x)
52
+
53
+ x = (x - self.mean) * self.img_range
54
+ x = self.conv_first(x)
55
+ res = self.conv_after_body(self.body(x))
56
+ res += x
57
+
58
+ x = self.conv_last(self.upsample(res))
59
+ x = x / self.img_range + self.mean
60
+
61
+ return x
basicsr/archs/edvr_arch.py ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+ from torch.nn import functional as F
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+ from .arch_util import DCNv2Pack, ResidualBlockNoBN, make_layer
7
+
8
+
9
+ class PCDAlignment(nn.Module):
10
+ """Alignment module using Pyramid, Cascading and Deformable convolution
11
+ (PCD). It is used in EDVR.
12
+
13
+ ``Paper: EDVR: Video Restoration with Enhanced Deformable Convolutional Networks``
14
+
15
+ Args:
16
+ num_feat (int): Channel number of middle features. Default: 64.
17
+ deformable_groups (int): Deformable groups. Defaults: 8.
18
+ """
19
+
20
+ def __init__(self, num_feat=64, deformable_groups=8):
21
+ super(PCDAlignment, self).__init__()
22
+
23
+ # Pyramid has three levels:
24
+ # L3: level 3, 1/4 spatial size
25
+ # L2: level 2, 1/2 spatial size
26
+ # L1: level 1, original spatial size
27
+ self.offset_conv1 = nn.ModuleDict()
28
+ self.offset_conv2 = nn.ModuleDict()
29
+ self.offset_conv3 = nn.ModuleDict()
30
+ self.dcn_pack = nn.ModuleDict()
31
+ self.feat_conv = nn.ModuleDict()
32
+
33
+ # Pyramids
34
+ for i in range(3, 0, -1):
35
+ level = f'l{i}'
36
+ self.offset_conv1[level] = nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1)
37
+ if i == 3:
38
+ self.offset_conv2[level] = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
39
+ else:
40
+ self.offset_conv2[level] = nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1)
41
+ self.offset_conv3[level] = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
42
+ self.dcn_pack[level] = DCNv2Pack(num_feat, num_feat, 3, padding=1, deformable_groups=deformable_groups)
43
+
44
+ if i < 3:
45
+ self.feat_conv[level] = nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1)
46
+
47
+ # Cascading dcn
48
+ self.cas_offset_conv1 = nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1)
49
+ self.cas_offset_conv2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
50
+ self.cas_dcnpack = DCNv2Pack(num_feat, num_feat, 3, padding=1, deformable_groups=deformable_groups)
51
+
52
+ self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
53
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
54
+
55
+ def forward(self, nbr_feat_l, ref_feat_l):
56
+ """Align neighboring frame features to the reference frame features.
57
+
58
+ Args:
59
+ nbr_feat_l (list[Tensor]): Neighboring feature list. It
60
+ contains three pyramid levels (L1, L2, L3),
61
+ each with shape (b, c, h, w).
62
+ ref_feat_l (list[Tensor]): Reference feature list. It
63
+ contains three pyramid levels (L1, L2, L3),
64
+ each with shape (b, c, h, w).
65
+
66
+ Returns:
67
+ Tensor: Aligned features.
68
+ """
69
+ # Pyramids
70
+ upsampled_offset, upsampled_feat = None, None
71
+ for i in range(3, 0, -1):
72
+ level = f'l{i}'
73
+ offset = torch.cat([nbr_feat_l[i - 1], ref_feat_l[i - 1]], dim=1)
74
+ offset = self.lrelu(self.offset_conv1[level](offset))
75
+ if i == 3:
76
+ offset = self.lrelu(self.offset_conv2[level](offset))
77
+ else:
78
+ offset = self.lrelu(self.offset_conv2[level](torch.cat([offset, upsampled_offset], dim=1)))
79
+ offset = self.lrelu(self.offset_conv3[level](offset))
80
+
81
+ feat = self.dcn_pack[level](nbr_feat_l[i - 1], offset)
82
+ if i < 3:
83
+ feat = self.feat_conv[level](torch.cat([feat, upsampled_feat], dim=1))
84
+ if i > 1:
85
+ feat = self.lrelu(feat)
86
+
87
+ if i > 1: # upsample offset and features
88
+ # x2: when we upsample the offset, we should also enlarge
89
+ # the magnitude.
90
+ upsampled_offset = self.upsample(offset) * 2
91
+ upsampled_feat = self.upsample(feat)
92
+
93
+ # Cascading
94
+ offset = torch.cat([feat, ref_feat_l[0]], dim=1)
95
+ offset = self.lrelu(self.cas_offset_conv2(self.lrelu(self.cas_offset_conv1(offset))))
96
+ feat = self.lrelu(self.cas_dcnpack(feat, offset))
97
+ return feat
98
+
99
+
100
+ class TSAFusion(nn.Module):
101
+ """Temporal Spatial Attention (TSA) fusion module.
102
+
103
+ Temporal: Calculate the correlation between center frame and
104
+ neighboring frames;
105
+ Spatial: It has 3 pyramid levels, the attention is similar to SFT.
106
+ (SFT: Recovering realistic texture in image super-resolution by deep
107
+ spatial feature transform.)
108
+
109
+ Args:
110
+ num_feat (int): Channel number of middle features. Default: 64.
111
+ num_frame (int): Number of frames. Default: 5.
112
+ center_frame_idx (int): The index of center frame. Default: 2.
113
+ """
114
+
115
+ def __init__(self, num_feat=64, num_frame=5, center_frame_idx=2):
116
+ super(TSAFusion, self).__init__()
117
+ self.center_frame_idx = center_frame_idx
118
+ # temporal attention (before fusion conv)
119
+ self.temporal_attn1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
120
+ self.temporal_attn2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
121
+ self.feat_fusion = nn.Conv2d(num_frame * num_feat, num_feat, 1, 1)
122
+
123
+ # spatial attention (after fusion conv)
124
+ self.max_pool = nn.MaxPool2d(3, stride=2, padding=1)
125
+ self.avg_pool = nn.AvgPool2d(3, stride=2, padding=1)
126
+ self.spatial_attn1 = nn.Conv2d(num_frame * num_feat, num_feat, 1)
127
+ self.spatial_attn2 = nn.Conv2d(num_feat * 2, num_feat, 1)
128
+ self.spatial_attn3 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
129
+ self.spatial_attn4 = nn.Conv2d(num_feat, num_feat, 1)
130
+ self.spatial_attn5 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
131
+ self.spatial_attn_l1 = nn.Conv2d(num_feat, num_feat, 1)
132
+ self.spatial_attn_l2 = nn.Conv2d(num_feat * 2, num_feat, 3, 1, 1)
133
+ self.spatial_attn_l3 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
134
+ self.spatial_attn_add1 = nn.Conv2d(num_feat, num_feat, 1)
135
+ self.spatial_attn_add2 = nn.Conv2d(num_feat, num_feat, 1)
136
+
137
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
138
+ self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
139
+
140
+ def forward(self, aligned_feat):
141
+ """
142
+ Args:
143
+ aligned_feat (Tensor): Aligned features with shape (b, t, c, h, w).
144
+
145
+ Returns:
146
+ Tensor: Features after TSA with the shape (b, c, h, w).
147
+ """
148
+ b, t, c, h, w = aligned_feat.size()
149
+ # temporal attention
150
+ embedding_ref = self.temporal_attn1(aligned_feat[:, self.center_frame_idx, :, :, :].clone())
151
+ embedding = self.temporal_attn2(aligned_feat.view(-1, c, h, w))
152
+ embedding = embedding.view(b, t, -1, h, w) # (b, t, c, h, w)
153
+
154
+ corr_l = [] # correlation list
155
+ for i in range(t):
156
+ emb_neighbor = embedding[:, i, :, :, :]
157
+ corr = torch.sum(emb_neighbor * embedding_ref, 1) # (b, h, w)
158
+ corr_l.append(corr.unsqueeze(1)) # (b, 1, h, w)
159
+ corr_prob = torch.sigmoid(torch.cat(corr_l, dim=1)) # (b, t, h, w)
160
+ corr_prob = corr_prob.unsqueeze(2).expand(b, t, c, h, w)
161
+ corr_prob = corr_prob.contiguous().view(b, -1, h, w) # (b, t*c, h, w)
162
+ aligned_feat = aligned_feat.view(b, -1, h, w) * corr_prob
163
+
164
+ # fusion
165
+ feat = self.lrelu(self.feat_fusion(aligned_feat))
166
+
167
+ # spatial attention
168
+ attn = self.lrelu(self.spatial_attn1(aligned_feat))
169
+ attn_max = self.max_pool(attn)
170
+ attn_avg = self.avg_pool(attn)
171
+ attn = self.lrelu(self.spatial_attn2(torch.cat([attn_max, attn_avg], dim=1)))
172
+ # pyramid levels
173
+ attn_level = self.lrelu(self.spatial_attn_l1(attn))
174
+ attn_max = self.max_pool(attn_level)
175
+ attn_avg = self.avg_pool(attn_level)
176
+ attn_level = self.lrelu(self.spatial_attn_l2(torch.cat([attn_max, attn_avg], dim=1)))
177
+ attn_level = self.lrelu(self.spatial_attn_l3(attn_level))
178
+ attn_level = self.upsample(attn_level)
179
+
180
+ attn = self.lrelu(self.spatial_attn3(attn)) + attn_level
181
+ attn = self.lrelu(self.spatial_attn4(attn))
182
+ attn = self.upsample(attn)
183
+ attn = self.spatial_attn5(attn)
184
+ attn_add = self.spatial_attn_add2(self.lrelu(self.spatial_attn_add1(attn)))
185
+ attn = torch.sigmoid(attn)
186
+
187
+ # after initialization, * 2 makes (attn * 2) to be close to 1.
188
+ feat = feat * attn * 2 + attn_add
189
+ return feat
190
+
191
+
192
+ class PredeblurModule(nn.Module):
193
+ """Pre-dublur module.
194
+
195
+ Args:
196
+ num_in_ch (int): Channel number of input image. Default: 3.
197
+ num_feat (int): Channel number of intermediate features. Default: 64.
198
+ hr_in (bool): Whether the input has high resolution. Default: False.
199
+ """
200
+
201
+ def __init__(self, num_in_ch=3, num_feat=64, hr_in=False):
202
+ super(PredeblurModule, self).__init__()
203
+ self.hr_in = hr_in
204
+
205
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
206
+ if self.hr_in:
207
+ # downsample x4 by stride conv
208
+ self.stride_conv_hr1 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
209
+ self.stride_conv_hr2 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
210
+
211
+ # generate feature pyramid
212
+ self.stride_conv_l2 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
213
+ self.stride_conv_l3 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
214
+
215
+ self.resblock_l3 = ResidualBlockNoBN(num_feat=num_feat)
216
+ self.resblock_l2_1 = ResidualBlockNoBN(num_feat=num_feat)
217
+ self.resblock_l2_2 = ResidualBlockNoBN(num_feat=num_feat)
218
+ self.resblock_l1 = nn.ModuleList([ResidualBlockNoBN(num_feat=num_feat) for i in range(5)])
219
+
220
+ self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
221
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
222
+
223
+ def forward(self, x):
224
+ feat_l1 = self.lrelu(self.conv_first(x))
225
+ if self.hr_in:
226
+ feat_l1 = self.lrelu(self.stride_conv_hr1(feat_l1))
227
+ feat_l1 = self.lrelu(self.stride_conv_hr2(feat_l1))
228
+
229
+ # generate feature pyramid
230
+ feat_l2 = self.lrelu(self.stride_conv_l2(feat_l1))
231
+ feat_l3 = self.lrelu(self.stride_conv_l3(feat_l2))
232
+
233
+ feat_l3 = self.upsample(self.resblock_l3(feat_l3))
234
+ feat_l2 = self.resblock_l2_1(feat_l2) + feat_l3
235
+ feat_l2 = self.upsample(self.resblock_l2_2(feat_l2))
236
+
237
+ for i in range(2):
238
+ feat_l1 = self.resblock_l1[i](feat_l1)
239
+ feat_l1 = feat_l1 + feat_l2
240
+ for i in range(2, 5):
241
+ feat_l1 = self.resblock_l1[i](feat_l1)
242
+ return feat_l1
243
+
244
+
245
+ @ARCH_REGISTRY.register()
246
+ class EDVR(nn.Module):
247
+ """EDVR network structure for video super-resolution.
248
+
249
+ Now only support X4 upsampling factor.
250
+
251
+ ``Paper: EDVR: Video Restoration with Enhanced Deformable Convolutional Networks``
252
+
253
+ Args:
254
+ num_in_ch (int): Channel number of input image. Default: 3.
255
+ num_out_ch (int): Channel number of output image. Default: 3.
256
+ num_feat (int): Channel number of intermediate features. Default: 64.
257
+ num_frame (int): Number of input frames. Default: 5.
258
+ deformable_groups (int): Deformable groups. Defaults: 8.
259
+ num_extract_block (int): Number of blocks for feature extraction.
260
+ Default: 5.
261
+ num_reconstruct_block (int): Number of blocks for reconstruction.
262
+ Default: 10.
263
+ center_frame_idx (int): The index of center frame. Frame counting from
264
+ 0. Default: Middle of input frames.
265
+ hr_in (bool): Whether the input has high resolution. Default: False.
266
+ with_predeblur (bool): Whether has predeblur module.
267
+ Default: False.
268
+ with_tsa (bool): Whether has TSA module. Default: True.
269
+ """
270
+
271
+ def __init__(self,
272
+ num_in_ch=3,
273
+ num_out_ch=3,
274
+ num_feat=64,
275
+ num_frame=5,
276
+ deformable_groups=8,
277
+ num_extract_block=5,
278
+ num_reconstruct_block=10,
279
+ center_frame_idx=None,
280
+ hr_in=False,
281
+ with_predeblur=False,
282
+ with_tsa=True):
283
+ super(EDVR, self).__init__()
284
+ if center_frame_idx is None:
285
+ self.center_frame_idx = num_frame // 2
286
+ else:
287
+ self.center_frame_idx = center_frame_idx
288
+ self.hr_in = hr_in
289
+ self.with_predeblur = with_predeblur
290
+ self.with_tsa = with_tsa
291
+
292
+ # extract features for each frame
293
+ if self.with_predeblur:
294
+ self.predeblur = PredeblurModule(num_feat=num_feat, hr_in=self.hr_in)
295
+ self.conv_1x1 = nn.Conv2d(num_feat, num_feat, 1, 1)
296
+ else:
297
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
298
+
299
+ # extract pyramid features
300
+ self.feature_extraction = make_layer(ResidualBlockNoBN, num_extract_block, num_feat=num_feat)
301
+ self.conv_l2_1 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
302
+ self.conv_l2_2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
303
+ self.conv_l3_1 = nn.Conv2d(num_feat, num_feat, 3, 2, 1)
304
+ self.conv_l3_2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
305
+
306
+ # pcd and tsa module
307
+ self.pcd_align = PCDAlignment(num_feat=num_feat, deformable_groups=deformable_groups)
308
+ if self.with_tsa:
309
+ self.fusion = TSAFusion(num_feat=num_feat, num_frame=num_frame, center_frame_idx=self.center_frame_idx)
310
+ else:
311
+ self.fusion = nn.Conv2d(num_frame * num_feat, num_feat, 1, 1)
312
+
313
+ # reconstruction
314
+ self.reconstruction = make_layer(ResidualBlockNoBN, num_reconstruct_block, num_feat=num_feat)
315
+ # upsample
316
+ self.upconv1 = nn.Conv2d(num_feat, num_feat * 4, 3, 1, 1)
317
+ self.upconv2 = nn.Conv2d(num_feat, 64 * 4, 3, 1, 1)
318
+ self.pixel_shuffle = nn.PixelShuffle(2)
319
+ self.conv_hr = nn.Conv2d(64, 64, 3, 1, 1)
320
+ self.conv_last = nn.Conv2d(64, 3, 3, 1, 1)
321
+
322
+ # activation function
323
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
324
+
325
+ def forward(self, x):
326
+ b, t, c, h, w = x.size()
327
+ if self.hr_in:
328
+ assert h % 16 == 0 and w % 16 == 0, ('The height and width must be multiple of 16.')
329
+ else:
330
+ assert h % 4 == 0 and w % 4 == 0, ('The height and width must be multiple of 4.')
331
+
332
+ x_center = x[:, self.center_frame_idx, :, :, :].contiguous()
333
+
334
+ # extract features for each frame
335
+ # L1
336
+ if self.with_predeblur:
337
+ feat_l1 = self.conv_1x1(self.predeblur(x.view(-1, c, h, w)))
338
+ if self.hr_in:
339
+ h, w = h // 4, w // 4
340
+ else:
341
+ feat_l1 = self.lrelu(self.conv_first(x.view(-1, c, h, w)))
342
+
343
+ feat_l1 = self.feature_extraction(feat_l1)
344
+ # L2
345
+ feat_l2 = self.lrelu(self.conv_l2_1(feat_l1))
346
+ feat_l2 = self.lrelu(self.conv_l2_2(feat_l2))
347
+ # L3
348
+ feat_l3 = self.lrelu(self.conv_l3_1(feat_l2))
349
+ feat_l3 = self.lrelu(self.conv_l3_2(feat_l3))
350
+
351
+ feat_l1 = feat_l1.view(b, t, -1, h, w)
352
+ feat_l2 = feat_l2.view(b, t, -1, h // 2, w // 2)
353
+ feat_l3 = feat_l3.view(b, t, -1, h // 4, w // 4)
354
+
355
+ # PCD alignment
356
+ ref_feat_l = [ # reference feature list
357
+ feat_l1[:, self.center_frame_idx, :, :, :].clone(), feat_l2[:, self.center_frame_idx, :, :, :].clone(),
358
+ feat_l3[:, self.center_frame_idx, :, :, :].clone()
359
+ ]
360
+ aligned_feat = []
361
+ for i in range(t):
362
+ nbr_feat_l = [ # neighboring feature list
363
+ feat_l1[:, i, :, :, :].clone(), feat_l2[:, i, :, :, :].clone(), feat_l3[:, i, :, :, :].clone()
364
+ ]
365
+ aligned_feat.append(self.pcd_align(nbr_feat_l, ref_feat_l))
366
+ aligned_feat = torch.stack(aligned_feat, dim=1) # (b, t, c, h, w)
367
+
368
+ if not self.with_tsa:
369
+ aligned_feat = aligned_feat.view(b, -1, h, w)
370
+ feat = self.fusion(aligned_feat)
371
+
372
+ out = self.reconstruction(feat)
373
+ out = self.lrelu(self.pixel_shuffle(self.upconv1(out)))
374
+ out = self.lrelu(self.pixel_shuffle(self.upconv2(out)))
375
+ out = self.lrelu(self.conv_hr(out))
376
+ out = self.conv_last(out)
377
+ if self.hr_in:
378
+ base = x_center
379
+ else:
380
+ base = F.interpolate(x_center, scale_factor=4, mode='bilinear', align_corners=False)
381
+ out += base
382
+ return out
basicsr/archs/hifacegan_arch.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+
6
+ from basicsr.utils.registry import ARCH_REGISTRY
7
+ from .hifacegan_util import BaseNetwork, LIPEncoder, SPADEResnetBlock, get_nonspade_norm_layer
8
+
9
+
10
+ class SPADEGenerator(BaseNetwork):
11
+ """Generator with SPADEResBlock"""
12
+
13
+ def __init__(self,
14
+ num_in_ch=3,
15
+ num_feat=64,
16
+ use_vae=False,
17
+ z_dim=256,
18
+ crop_size=512,
19
+ norm_g='spectralspadesyncbatch3x3',
20
+ is_train=True,
21
+ init_train_phase=3): # progressive training disabled
22
+ super().__init__()
23
+ self.nf = num_feat
24
+ self.input_nc = num_in_ch
25
+ self.is_train = is_train
26
+ self.train_phase = init_train_phase
27
+
28
+ self.scale_ratio = 5 # hardcoded now
29
+ self.sw = crop_size // (2**self.scale_ratio)
30
+ self.sh = self.sw # 20210519: By default use square image, aspect_ratio = 1.0
31
+
32
+ if use_vae:
33
+ # In case of VAE, we will sample from random z vector
34
+ self.fc = nn.Linear(z_dim, 16 * self.nf * self.sw * self.sh)
35
+ else:
36
+ # Otherwise, we make the network deterministic by starting with
37
+ # downsampled segmentation map instead of random z
38
+ self.fc = nn.Conv2d(num_in_ch, 16 * self.nf, 3, padding=1)
39
+
40
+ self.head_0 = SPADEResnetBlock(16 * self.nf, 16 * self.nf, norm_g)
41
+
42
+ self.g_middle_0 = SPADEResnetBlock(16 * self.nf, 16 * self.nf, norm_g)
43
+ self.g_middle_1 = SPADEResnetBlock(16 * self.nf, 16 * self.nf, norm_g)
44
+
45
+ self.ups = nn.ModuleList([
46
+ SPADEResnetBlock(16 * self.nf, 8 * self.nf, norm_g),
47
+ SPADEResnetBlock(8 * self.nf, 4 * self.nf, norm_g),
48
+ SPADEResnetBlock(4 * self.nf, 2 * self.nf, norm_g),
49
+ SPADEResnetBlock(2 * self.nf, 1 * self.nf, norm_g)
50
+ ])
51
+
52
+ self.to_rgbs = nn.ModuleList([
53
+ nn.Conv2d(8 * self.nf, 3, 3, padding=1),
54
+ nn.Conv2d(4 * self.nf, 3, 3, padding=1),
55
+ nn.Conv2d(2 * self.nf, 3, 3, padding=1),
56
+ nn.Conv2d(1 * self.nf, 3, 3, padding=1)
57
+ ])
58
+
59
+ self.up = nn.Upsample(scale_factor=2)
60
+
61
+ def encode(self, input_tensor):
62
+ """
63
+ Encode input_tensor into feature maps, can be overridden in derived classes
64
+ Default: nearest downsampling of 2**5 = 32 times
65
+ """
66
+ h, w = input_tensor.size()[-2:]
67
+ sh, sw = h // 2**self.scale_ratio, w // 2**self.scale_ratio
68
+ x = F.interpolate(input_tensor, size=(sh, sw))
69
+ return self.fc(x)
70
+
71
+ def forward(self, x):
72
+ # In oroginal SPADE, seg means a segmentation map, but here we use x instead.
73
+ seg = x
74
+
75
+ x = self.encode(x)
76
+ x = self.head_0(x, seg)
77
+
78
+ x = self.up(x)
79
+ x = self.g_middle_0(x, seg)
80
+ x = self.g_middle_1(x, seg)
81
+
82
+ if self.is_train:
83
+ phase = self.train_phase + 1
84
+ else:
85
+ phase = len(self.to_rgbs)
86
+
87
+ for i in range(phase):
88
+ x = self.up(x)
89
+ x = self.ups[i](x, seg)
90
+
91
+ x = self.to_rgbs[phase - 1](F.leaky_relu(x, 2e-1))
92
+ x = torch.tanh(x)
93
+
94
+ return x
95
+
96
+ def mixed_guidance_forward(self, input_x, seg=None, n=0, mode='progressive'):
97
+ """
98
+ A helper class for subspace visualization. Input and seg are different images.
99
+ For the first n levels (including encoder) we use input, for the rest we use seg.
100
+
101
+ If mode = 'progressive', the output's like: AAABBB
102
+ If mode = 'one_plug', the output's like: AAABAA
103
+ If mode = 'one_ablate', the output's like: BBBABB
104
+ """
105
+
106
+ if seg is None:
107
+ return self.forward(input_x)
108
+
109
+ if self.is_train:
110
+ phase = self.train_phase + 1
111
+ else:
112
+ phase = len(self.to_rgbs)
113
+
114
+ if mode == 'progressive':
115
+ n = max(min(n, 4 + phase), 0)
116
+ guide_list = [input_x] * n + [seg] * (4 + phase - n)
117
+ elif mode == 'one_plug':
118
+ n = max(min(n, 4 + phase - 1), 0)
119
+ guide_list = [seg] * (4 + phase)
120
+ guide_list[n] = input_x
121
+ elif mode == 'one_ablate':
122
+ if n > 3 + phase:
123
+ return self.forward(input_x)
124
+ guide_list = [input_x] * (4 + phase)
125
+ guide_list[n] = seg
126
+
127
+ x = self.encode(guide_list[0])
128
+ x = self.head_0(x, guide_list[1])
129
+
130
+ x = self.up(x)
131
+ x = self.g_middle_0(x, guide_list[2])
132
+ x = self.g_middle_1(x, guide_list[3])
133
+
134
+ for i in range(phase):
135
+ x = self.up(x)
136
+ x = self.ups[i](x, guide_list[4 + i])
137
+
138
+ x = self.to_rgbs[phase - 1](F.leaky_relu(x, 2e-1))
139
+ x = torch.tanh(x)
140
+
141
+ return x
142
+
143
+
144
+ @ARCH_REGISTRY.register()
145
+ class HiFaceGAN(SPADEGenerator):
146
+ """
147
+ HiFaceGAN: SPADEGenerator with a learnable feature encoder
148
+ Current encoder design: LIPEncoder
149
+ """
150
+
151
+ def __init__(self,
152
+ num_in_ch=3,
153
+ num_feat=64,
154
+ use_vae=False,
155
+ z_dim=256,
156
+ crop_size=512,
157
+ norm_g='spectralspadesyncbatch3x3',
158
+ is_train=True,
159
+ init_train_phase=3):
160
+ super().__init__(num_in_ch, num_feat, use_vae, z_dim, crop_size, norm_g, is_train, init_train_phase)
161
+ self.lip_encoder = LIPEncoder(num_in_ch, num_feat, self.sw, self.sh, self.scale_ratio)
162
+
163
+ def encode(self, input_tensor):
164
+ return self.lip_encoder(input_tensor)
165
+
166
+
167
+ @ARCH_REGISTRY.register()
168
+ class HiFaceGANDiscriminator(BaseNetwork):
169
+ """
170
+ Inspired by pix2pixHD multiscale discriminator.
171
+
172
+ Args:
173
+ num_in_ch (int): Channel number of inputs. Default: 3.
174
+ num_out_ch (int): Channel number of outputs. Default: 3.
175
+ conditional_d (bool): Whether use conditional discriminator.
176
+ Default: True.
177
+ num_d (int): Number of Multiscale discriminators. Default: 3.
178
+ n_layers_d (int): Number of downsample layers in each D. Default: 4.
179
+ num_feat (int): Channel number of base intermediate features.
180
+ Default: 64.
181
+ norm_d (str): String to determine normalization layers in D.
182
+ Choices: [spectral][instance/batch/syncbatch]
183
+ Default: 'spectralinstance'.
184
+ keep_features (bool): Keep intermediate features for matching loss, etc.
185
+ Default: True.
186
+ """
187
+
188
+ def __init__(self,
189
+ num_in_ch=3,
190
+ num_out_ch=3,
191
+ conditional_d=True,
192
+ num_d=2,
193
+ n_layers_d=4,
194
+ num_feat=64,
195
+ norm_d='spectralinstance',
196
+ keep_features=True):
197
+ super().__init__()
198
+ self.num_d = num_d
199
+
200
+ input_nc = num_in_ch
201
+ if conditional_d:
202
+ input_nc += num_out_ch
203
+
204
+ for i in range(num_d):
205
+ subnet_d = NLayerDiscriminator(input_nc, n_layers_d, num_feat, norm_d, keep_features)
206
+ self.add_module(f'discriminator_{i}', subnet_d)
207
+
208
+ def downsample(self, x):
209
+ return F.avg_pool2d(x, kernel_size=3, stride=2, padding=[1, 1], count_include_pad=False)
210
+
211
+ # Returns list of lists of discriminator outputs.
212
+ # The final result is of size opt.num_d x opt.n_layers_D
213
+ def forward(self, x):
214
+ result = []
215
+ for _, _net_d in self.named_children():
216
+ out = _net_d(x)
217
+ result.append(out)
218
+ x = self.downsample(x)
219
+
220
+ return result
221
+
222
+
223
+ class NLayerDiscriminator(BaseNetwork):
224
+ """Defines the PatchGAN discriminator with the specified arguments."""
225
+
226
+ def __init__(self, input_nc, n_layers_d, num_feat, norm_d, keep_features):
227
+ super().__init__()
228
+ kw = 4
229
+ padw = int(np.ceil((kw - 1.0) / 2))
230
+ nf = num_feat
231
+ self.keep_features = keep_features
232
+
233
+ norm_layer = get_nonspade_norm_layer(norm_d)
234
+ sequence = [[nn.Conv2d(input_nc, nf, kernel_size=kw, stride=2, padding=padw), nn.LeakyReLU(0.2, False)]]
235
+
236
+ for n in range(1, n_layers_d):
237
+ nf_prev = nf
238
+ nf = min(nf * 2, 512)
239
+ stride = 1 if n == n_layers_d - 1 else 2
240
+ sequence += [[
241
+ norm_layer(nn.Conv2d(nf_prev, nf, kernel_size=kw, stride=stride, padding=padw)),
242
+ nn.LeakyReLU(0.2, False)
243
+ ]]
244
+
245
+ sequence += [[nn.Conv2d(nf, 1, kernel_size=kw, stride=1, padding=padw)]]
246
+
247
+ # We divide the layers into groups to extract intermediate layer outputs
248
+ for n in range(len(sequence)):
249
+ self.add_module('model' + str(n), nn.Sequential(*sequence[n]))
250
+
251
+ def forward(self, x):
252
+ results = [x]
253
+ for submodel in self.children():
254
+ intermediate_output = submodel(results[-1])
255
+ results.append(intermediate_output)
256
+
257
+ if self.keep_features:
258
+ return results[1:]
259
+ else:
260
+ return results[-1]
basicsr/archs/hifacegan_util.py ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from torch.nn import init
6
+ # Warning: spectral norm could be buggy
7
+ # under eval mode and multi-GPU inference
8
+ # A workaround is sticking to single-GPU inference and train mode
9
+ from torch.nn.utils import spectral_norm
10
+
11
+
12
+ class SPADE(nn.Module):
13
+
14
+ def __init__(self, config_text, norm_nc, label_nc):
15
+ super().__init__()
16
+
17
+ assert config_text.startswith('spade')
18
+ parsed = re.search('spade(\\D+)(\\d)x\\d', config_text)
19
+ param_free_norm_type = str(parsed.group(1))
20
+ ks = int(parsed.group(2))
21
+
22
+ if param_free_norm_type == 'instance':
23
+ self.param_free_norm = nn.InstanceNorm2d(norm_nc)
24
+ elif param_free_norm_type == 'syncbatch':
25
+ print('SyncBatchNorm is currently not supported under single-GPU mode, switch to "instance" instead')
26
+ self.param_free_norm = nn.InstanceNorm2d(norm_nc)
27
+ elif param_free_norm_type == 'batch':
28
+ self.param_free_norm = nn.BatchNorm2d(norm_nc, affine=False)
29
+ else:
30
+ raise ValueError(f'{param_free_norm_type} is not a recognized param-free norm type in SPADE')
31
+
32
+ # The dimension of the intermediate embedding space. Yes, hardcoded.
33
+ nhidden = 128 if norm_nc > 128 else norm_nc
34
+
35
+ pw = ks // 2
36
+ self.mlp_shared = nn.Sequential(nn.Conv2d(label_nc, nhidden, kernel_size=ks, padding=pw), nn.ReLU())
37
+ self.mlp_gamma = nn.Conv2d(nhidden, norm_nc, kernel_size=ks, padding=pw, bias=False)
38
+ self.mlp_beta = nn.Conv2d(nhidden, norm_nc, kernel_size=ks, padding=pw, bias=False)
39
+
40
+ def forward(self, x, segmap):
41
+
42
+ # Part 1. generate parameter-free normalized activations
43
+ normalized = self.param_free_norm(x)
44
+
45
+ # Part 2. produce scaling and bias conditioned on semantic map
46
+ segmap = F.interpolate(segmap, size=x.size()[2:], mode='nearest')
47
+ actv = self.mlp_shared(segmap)
48
+ gamma = self.mlp_gamma(actv)
49
+ beta = self.mlp_beta(actv)
50
+
51
+ # apply scale and bias
52
+ out = normalized * gamma + beta
53
+
54
+ return out
55
+
56
+
57
+ class SPADEResnetBlock(nn.Module):
58
+ """
59
+ ResNet block that uses SPADE. It differs from the ResNet block of pix2pixHD in that
60
+ it takes in the segmentation map as input, learns the skip connection if necessary,
61
+ and applies normalization first and then convolution.
62
+ This architecture seemed like a standard architecture for unconditional or
63
+ class-conditional GAN architecture using residual block.
64
+ The code was inspired from https://github.com/LMescheder/GAN_stability.
65
+ """
66
+
67
+ def __init__(self, fin, fout, norm_g='spectralspadesyncbatch3x3', semantic_nc=3):
68
+ super().__init__()
69
+ # Attributes
70
+ self.learned_shortcut = (fin != fout)
71
+ fmiddle = min(fin, fout)
72
+
73
+ # create conv layers
74
+ self.conv_0 = nn.Conv2d(fin, fmiddle, kernel_size=3, padding=1)
75
+ self.conv_1 = nn.Conv2d(fmiddle, fout, kernel_size=3, padding=1)
76
+ if self.learned_shortcut:
77
+ self.conv_s = nn.Conv2d(fin, fout, kernel_size=1, bias=False)
78
+
79
+ # apply spectral norm if specified
80
+ if 'spectral' in norm_g:
81
+ self.conv_0 = spectral_norm(self.conv_0)
82
+ self.conv_1 = spectral_norm(self.conv_1)
83
+ if self.learned_shortcut:
84
+ self.conv_s = spectral_norm(self.conv_s)
85
+
86
+ # define normalization layers
87
+ spade_config_str = norm_g.replace('spectral', '')
88
+ self.norm_0 = SPADE(spade_config_str, fin, semantic_nc)
89
+ self.norm_1 = SPADE(spade_config_str, fmiddle, semantic_nc)
90
+ if self.learned_shortcut:
91
+ self.norm_s = SPADE(spade_config_str, fin, semantic_nc)
92
+
93
+ # note the resnet block with SPADE also takes in |seg|,
94
+ # the semantic segmentation map as input
95
+ def forward(self, x, seg):
96
+ x_s = self.shortcut(x, seg)
97
+ dx = self.conv_0(self.act(self.norm_0(x, seg)))
98
+ dx = self.conv_1(self.act(self.norm_1(dx, seg)))
99
+ out = x_s + dx
100
+ return out
101
+
102
+ def shortcut(self, x, seg):
103
+ if self.learned_shortcut:
104
+ x_s = self.conv_s(self.norm_s(x, seg))
105
+ else:
106
+ x_s = x
107
+ return x_s
108
+
109
+ def act(self, x):
110
+ return F.leaky_relu(x, 2e-1)
111
+
112
+
113
+ class BaseNetwork(nn.Module):
114
+ """ A basis for hifacegan archs with custom initialization """
115
+
116
+ def init_weights(self, init_type='normal', gain=0.02):
117
+
118
+ def init_func(m):
119
+ classname = m.__class__.__name__
120
+ if classname.find('BatchNorm2d') != -1:
121
+ if hasattr(m, 'weight') and m.weight is not None:
122
+ init.normal_(m.weight.data, 1.0, gain)
123
+ if hasattr(m, 'bias') and m.bias is not None:
124
+ init.constant_(m.bias.data, 0.0)
125
+ elif hasattr(m, 'weight') and (classname.find('Conv') != -1 or classname.find('Linear') != -1):
126
+ if init_type == 'normal':
127
+ init.normal_(m.weight.data, 0.0, gain)
128
+ elif init_type == 'xavier':
129
+ init.xavier_normal_(m.weight.data, gain=gain)
130
+ elif init_type == 'xavier_uniform':
131
+ init.xavier_uniform_(m.weight.data, gain=1.0)
132
+ elif init_type == 'kaiming':
133
+ init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')
134
+ elif init_type == 'orthogonal':
135
+ init.orthogonal_(m.weight.data, gain=gain)
136
+ elif init_type == 'none': # uses pytorch's default init method
137
+ m.reset_parameters()
138
+ else:
139
+ raise NotImplementedError(f'initialization method [{init_type}] is not implemented')
140
+ if hasattr(m, 'bias') and m.bias is not None:
141
+ init.constant_(m.bias.data, 0.0)
142
+
143
+ self.apply(init_func)
144
+
145
+ # propagate to children
146
+ for m in self.children():
147
+ if hasattr(m, 'init_weights'):
148
+ m.init_weights(init_type, gain)
149
+
150
+ def forward(self, x):
151
+ pass
152
+
153
+
154
+ def lip2d(x, logit, kernel=3, stride=2, padding=1):
155
+ weight = logit.exp()
156
+ return F.avg_pool2d(x * weight, kernel, stride, padding) / F.avg_pool2d(weight, kernel, stride, padding)
157
+
158
+
159
+ class SoftGate(nn.Module):
160
+ COEFF = 12.0
161
+
162
+ def forward(self, x):
163
+ return torch.sigmoid(x).mul(self.COEFF)
164
+
165
+
166
+ class SimplifiedLIP(nn.Module):
167
+
168
+ def __init__(self, channels):
169
+ super(SimplifiedLIP, self).__init__()
170
+ self.logit = nn.Sequential(
171
+ nn.Conv2d(channels, channels, 3, padding=1, bias=False), nn.InstanceNorm2d(channels, affine=True),
172
+ SoftGate())
173
+
174
+ def init_layer(self):
175
+ self.logit[0].weight.data.fill_(0.0)
176
+
177
+ def forward(self, x):
178
+ frac = lip2d(x, self.logit(x))
179
+ return frac
180
+
181
+
182
+ class LIPEncoder(BaseNetwork):
183
+ """Local Importance-based Pooling (Ziteng Gao et.al.,ICCV 2019)"""
184
+
185
+ def __init__(self, input_nc, ngf, sw, sh, n_2xdown, norm_layer=nn.InstanceNorm2d):
186
+ super().__init__()
187
+ self.sw = sw
188
+ self.sh = sh
189
+ self.max_ratio = 16
190
+ # 20200310: Several Convolution (stride 1) + LIP blocks, 4 fold
191
+ kw = 3
192
+ pw = (kw - 1) // 2
193
+
194
+ model = [
195
+ nn.Conv2d(input_nc, ngf, kw, stride=1, padding=pw, bias=False),
196
+ norm_layer(ngf),
197
+ nn.ReLU(),
198
+ ]
199
+ cur_ratio = 1
200
+ for i in range(n_2xdown):
201
+ next_ratio = min(cur_ratio * 2, self.max_ratio)
202
+ model += [
203
+ SimplifiedLIP(ngf * cur_ratio),
204
+ nn.Conv2d(ngf * cur_ratio, ngf * next_ratio, kw, stride=1, padding=pw),
205
+ norm_layer(ngf * next_ratio),
206
+ ]
207
+ cur_ratio = next_ratio
208
+ if i < n_2xdown - 1:
209
+ model += [nn.ReLU(inplace=True)]
210
+
211
+ self.model = nn.Sequential(*model)
212
+
213
+ def forward(self, x):
214
+ return self.model(x)
215
+
216
+
217
+ def get_nonspade_norm_layer(norm_type='instance'):
218
+ # helper function to get # output channels of the previous layer
219
+ def get_out_channel(layer):
220
+ if hasattr(layer, 'out_channels'):
221
+ return getattr(layer, 'out_channels')
222
+ return layer.weight.size(0)
223
+
224
+ # this function will be returned
225
+ def add_norm_layer(layer):
226
+ nonlocal norm_type
227
+ if norm_type.startswith('spectral'):
228
+ layer = spectral_norm(layer)
229
+ subnorm_type = norm_type[len('spectral'):]
230
+
231
+ if subnorm_type == 'none' or len(subnorm_type) == 0:
232
+ return layer
233
+
234
+ # remove bias in the previous layer, which is meaningless
235
+ # since it has no effect after normalization
236
+ if getattr(layer, 'bias', None) is not None:
237
+ delattr(layer, 'bias')
238
+ layer.register_parameter('bias', None)
239
+
240
+ if subnorm_type == 'batch':
241
+ norm_layer = nn.BatchNorm2d(get_out_channel(layer), affine=True)
242
+ elif subnorm_type == 'sync_batch':
243
+ print('SyncBatchNorm is currently not supported under single-GPU mode, switch to "instance" instead')
244
+ # norm_layer = SynchronizedBatchNorm2d(
245
+ # get_out_channel(layer), affine=True)
246
+ norm_layer = nn.InstanceNorm2d(get_out_channel(layer), affine=False)
247
+ elif subnorm_type == 'instance':
248
+ norm_layer = nn.InstanceNorm2d(get_out_channel(layer), affine=False)
249
+ else:
250
+ raise ValueError(f'normalization layer {subnorm_type} is not recognized')
251
+
252
+ return nn.Sequential(layer, norm_layer)
253
+
254
+ print('This is a legacy from nvlabs/SPADE, and will be removed in future versions.')
255
+ return add_norm_layer
basicsr/archs/inception.py ADDED
@@ -0,0 +1,307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Modified from https://github.com/mseitzer/pytorch-fid/blob/master/pytorch_fid/inception.py # noqa: E501
2
+ # For FID metric
3
+
4
+ import os
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from torch.utils.model_zoo import load_url
9
+ from torchvision import models
10
+
11
+ # Inception weights ported to Pytorch from
12
+ # http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz
13
+ FID_WEIGHTS_URL = 'https://github.com/mseitzer/pytorch-fid/releases/download/fid_weights/pt_inception-2015-12-05-6726825d.pth' # noqa: E501
14
+ LOCAL_FID_WEIGHTS = 'experiments/pretrained_models/pt_inception-2015-12-05-6726825d.pth' # noqa: E501
15
+
16
+
17
+ class InceptionV3(nn.Module):
18
+ """Pretrained InceptionV3 network returning feature maps"""
19
+
20
+ # Index of default block of inception to return,
21
+ # corresponds to output of final average pooling
22
+ DEFAULT_BLOCK_INDEX = 3
23
+
24
+ # Maps feature dimensionality to their output blocks indices
25
+ BLOCK_INDEX_BY_DIM = {
26
+ 64: 0, # First max pooling features
27
+ 192: 1, # Second max pooling features
28
+ 768: 2, # Pre-aux classifier features
29
+ 2048: 3 # Final average pooling features
30
+ }
31
+
32
+ def __init__(self,
33
+ output_blocks=(DEFAULT_BLOCK_INDEX),
34
+ resize_input=True,
35
+ normalize_input=True,
36
+ requires_grad=False,
37
+ use_fid_inception=True):
38
+ """Build pretrained InceptionV3.
39
+
40
+ Args:
41
+ output_blocks (list[int]): Indices of blocks to return features of.
42
+ Possible values are:
43
+ - 0: corresponds to output of first max pooling
44
+ - 1: corresponds to output of second max pooling
45
+ - 2: corresponds to output which is fed to aux classifier
46
+ - 3: corresponds to output of final average pooling
47
+ resize_input (bool): If true, bilinearly resizes input to width and
48
+ height 299 before feeding input to model. As the network
49
+ without fully connected layers is fully convolutional, it
50
+ should be able to handle inputs of arbitrary size, so resizing
51
+ might not be strictly needed. Default: True.
52
+ normalize_input (bool): If true, scales the input from range (0, 1)
53
+ to the range the pretrained Inception network expects,
54
+ namely (-1, 1). Default: True.
55
+ requires_grad (bool): If true, parameters of the model require
56
+ gradients. Possibly useful for finetuning the network.
57
+ Default: False.
58
+ use_fid_inception (bool): If true, uses the pretrained Inception
59
+ model used in Tensorflow's FID implementation.
60
+ If false, uses the pretrained Inception model available in
61
+ torchvision. The FID Inception model has different weights
62
+ and a slightly different structure from torchvision's
63
+ Inception model. If you want to compute FID scores, you are
64
+ strongly advised to set this parameter to true to get
65
+ comparable results. Default: True.
66
+ """
67
+ super(InceptionV3, self).__init__()
68
+
69
+ self.resize_input = resize_input
70
+ self.normalize_input = normalize_input
71
+ self.output_blocks = sorted(output_blocks)
72
+ self.last_needed_block = max(output_blocks)
73
+
74
+ assert self.last_needed_block <= 3, ('Last possible output block index is 3')
75
+
76
+ self.blocks = nn.ModuleList()
77
+
78
+ if use_fid_inception:
79
+ inception = fid_inception_v3()
80
+ else:
81
+ try:
82
+ inception = models.inception_v3(pretrained=True, init_weights=False)
83
+ except TypeError:
84
+ # pytorch < 1.5 does not have init_weights for inception_v3
85
+ inception = models.inception_v3(pretrained=True)
86
+
87
+ # Block 0: input to maxpool1
88
+ block0 = [
89
+ inception.Conv2d_1a_3x3, inception.Conv2d_2a_3x3, inception.Conv2d_2b_3x3,
90
+ nn.MaxPool2d(kernel_size=3, stride=2)
91
+ ]
92
+ self.blocks.append(nn.Sequential(*block0))
93
+
94
+ # Block 1: maxpool1 to maxpool2
95
+ if self.last_needed_block >= 1:
96
+ block1 = [inception.Conv2d_3b_1x1, inception.Conv2d_4a_3x3, nn.MaxPool2d(kernel_size=3, stride=2)]
97
+ self.blocks.append(nn.Sequential(*block1))
98
+
99
+ # Block 2: maxpool2 to aux classifier
100
+ if self.last_needed_block >= 2:
101
+ block2 = [
102
+ inception.Mixed_5b,
103
+ inception.Mixed_5c,
104
+ inception.Mixed_5d,
105
+ inception.Mixed_6a,
106
+ inception.Mixed_6b,
107
+ inception.Mixed_6c,
108
+ inception.Mixed_6d,
109
+ inception.Mixed_6e,
110
+ ]
111
+ self.blocks.append(nn.Sequential(*block2))
112
+
113
+ # Block 3: aux classifier to final avgpool
114
+ if self.last_needed_block >= 3:
115
+ block3 = [
116
+ inception.Mixed_7a, inception.Mixed_7b, inception.Mixed_7c,
117
+ nn.AdaptiveAvgPool2d(output_size=(1, 1))
118
+ ]
119
+ self.blocks.append(nn.Sequential(*block3))
120
+
121
+ for param in self.parameters():
122
+ param.requires_grad = requires_grad
123
+
124
+ def forward(self, x):
125
+ """Get Inception feature maps.
126
+
127
+ Args:
128
+ x (Tensor): Input tensor of shape (b, 3, h, w).
129
+ Values are expected to be in range (-1, 1). You can also input
130
+ (0, 1) with setting normalize_input = True.
131
+
132
+ Returns:
133
+ list[Tensor]: Corresponding to the selected output block, sorted
134
+ ascending by index.
135
+ """
136
+ output = []
137
+
138
+ if self.resize_input:
139
+ x = F.interpolate(x, size=(299, 299), mode='bilinear', align_corners=False)
140
+
141
+ if self.normalize_input:
142
+ x = 2 * x - 1 # Scale from range (0, 1) to range (-1, 1)
143
+
144
+ for idx, block in enumerate(self.blocks):
145
+ x = block(x)
146
+ if idx in self.output_blocks:
147
+ output.append(x)
148
+
149
+ if idx == self.last_needed_block:
150
+ break
151
+
152
+ return output
153
+
154
+
155
+ def fid_inception_v3():
156
+ """Build pretrained Inception model for FID computation.
157
+
158
+ The Inception model for FID computation uses a different set of weights
159
+ and has a slightly different structure than torchvision's Inception.
160
+
161
+ This method first constructs torchvision's Inception and then patches the
162
+ necessary parts that are different in the FID Inception model.
163
+ """
164
+ try:
165
+ inception = models.inception_v3(num_classes=1008, aux_logits=False, pretrained=False, init_weights=False)
166
+ except TypeError:
167
+ # pytorch < 1.5 does not have init_weights for inception_v3
168
+ inception = models.inception_v3(num_classes=1008, aux_logits=False, pretrained=False)
169
+
170
+ inception.Mixed_5b = FIDInceptionA(192, pool_features=32)
171
+ inception.Mixed_5c = FIDInceptionA(256, pool_features=64)
172
+ inception.Mixed_5d = FIDInceptionA(288, pool_features=64)
173
+ inception.Mixed_6b = FIDInceptionC(768, channels_7x7=128)
174
+ inception.Mixed_6c = FIDInceptionC(768, channels_7x7=160)
175
+ inception.Mixed_6d = FIDInceptionC(768, channels_7x7=160)
176
+ inception.Mixed_6e = FIDInceptionC(768, channels_7x7=192)
177
+ inception.Mixed_7b = FIDInceptionE_1(1280)
178
+ inception.Mixed_7c = FIDInceptionE_2(2048)
179
+
180
+ if os.path.exists(LOCAL_FID_WEIGHTS):
181
+ state_dict = torch.load(LOCAL_FID_WEIGHTS, map_location=lambda storage, loc: storage)
182
+ else:
183
+ state_dict = load_url(FID_WEIGHTS_URL, progress=True)
184
+
185
+ inception.load_state_dict(state_dict)
186
+ return inception
187
+
188
+
189
+ class FIDInceptionA(models.inception.InceptionA):
190
+ """InceptionA block patched for FID computation"""
191
+
192
+ def __init__(self, in_channels, pool_features):
193
+ super(FIDInceptionA, self).__init__(in_channels, pool_features)
194
+
195
+ def forward(self, x):
196
+ branch1x1 = self.branch1x1(x)
197
+
198
+ branch5x5 = self.branch5x5_1(x)
199
+ branch5x5 = self.branch5x5_2(branch5x5)
200
+
201
+ branch3x3dbl = self.branch3x3dbl_1(x)
202
+ branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
203
+ branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)
204
+
205
+ # Patch: Tensorflow's average pool does not use the padded zero's in
206
+ # its average calculation
207
+ branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1, count_include_pad=False)
208
+ branch_pool = self.branch_pool(branch_pool)
209
+
210
+ outputs = [branch1x1, branch5x5, branch3x3dbl, branch_pool]
211
+ return torch.cat(outputs, 1)
212
+
213
+
214
+ class FIDInceptionC(models.inception.InceptionC):
215
+ """InceptionC block patched for FID computation"""
216
+
217
+ def __init__(self, in_channels, channels_7x7):
218
+ super(FIDInceptionC, self).__init__(in_channels, channels_7x7)
219
+
220
+ def forward(self, x):
221
+ branch1x1 = self.branch1x1(x)
222
+
223
+ branch7x7 = self.branch7x7_1(x)
224
+ branch7x7 = self.branch7x7_2(branch7x7)
225
+ branch7x7 = self.branch7x7_3(branch7x7)
226
+
227
+ branch7x7dbl = self.branch7x7dbl_1(x)
228
+ branch7x7dbl = self.branch7x7dbl_2(branch7x7dbl)
229
+ branch7x7dbl = self.branch7x7dbl_3(branch7x7dbl)
230
+ branch7x7dbl = self.branch7x7dbl_4(branch7x7dbl)
231
+ branch7x7dbl = self.branch7x7dbl_5(branch7x7dbl)
232
+
233
+ # Patch: Tensorflow's average pool does not use the padded zero's in
234
+ # its average calculation
235
+ branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1, count_include_pad=False)
236
+ branch_pool = self.branch_pool(branch_pool)
237
+
238
+ outputs = [branch1x1, branch7x7, branch7x7dbl, branch_pool]
239
+ return torch.cat(outputs, 1)
240
+
241
+
242
+ class FIDInceptionE_1(models.inception.InceptionE):
243
+ """First InceptionE block patched for FID computation"""
244
+
245
+ def __init__(self, in_channels):
246
+ super(FIDInceptionE_1, self).__init__(in_channels)
247
+
248
+ def forward(self, x):
249
+ branch1x1 = self.branch1x1(x)
250
+
251
+ branch3x3 = self.branch3x3_1(x)
252
+ branch3x3 = [
253
+ self.branch3x3_2a(branch3x3),
254
+ self.branch3x3_2b(branch3x3),
255
+ ]
256
+ branch3x3 = torch.cat(branch3x3, 1)
257
+
258
+ branch3x3dbl = self.branch3x3dbl_1(x)
259
+ branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
260
+ branch3x3dbl = [
261
+ self.branch3x3dbl_3a(branch3x3dbl),
262
+ self.branch3x3dbl_3b(branch3x3dbl),
263
+ ]
264
+ branch3x3dbl = torch.cat(branch3x3dbl, 1)
265
+
266
+ # Patch: Tensorflow's average pool does not use the padded zero's in
267
+ # its average calculation
268
+ branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1, count_include_pad=False)
269
+ branch_pool = self.branch_pool(branch_pool)
270
+
271
+ outputs = [branch1x1, branch3x3, branch3x3dbl, branch_pool]
272
+ return torch.cat(outputs, 1)
273
+
274
+
275
+ class FIDInceptionE_2(models.inception.InceptionE):
276
+ """Second InceptionE block patched for FID computation"""
277
+
278
+ def __init__(self, in_channels):
279
+ super(FIDInceptionE_2, self).__init__(in_channels)
280
+
281
+ def forward(self, x):
282
+ branch1x1 = self.branch1x1(x)
283
+
284
+ branch3x3 = self.branch3x3_1(x)
285
+ branch3x3 = [
286
+ self.branch3x3_2a(branch3x3),
287
+ self.branch3x3_2b(branch3x3),
288
+ ]
289
+ branch3x3 = torch.cat(branch3x3, 1)
290
+
291
+ branch3x3dbl = self.branch3x3dbl_1(x)
292
+ branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)
293
+ branch3x3dbl = [
294
+ self.branch3x3dbl_3a(branch3x3dbl),
295
+ self.branch3x3dbl_3b(branch3x3dbl),
296
+ ]
297
+ branch3x3dbl = torch.cat(branch3x3dbl, 1)
298
+
299
+ # Patch: The FID Inception model uses max pooling instead of average
300
+ # pooling. This is likely an error in this specific Inception
301
+ # implementation, as other Inception models use average pooling here
302
+ # (which matches the description in the paper).
303
+ branch_pool = F.max_pool2d(x, kernel_size=3, stride=1, padding=1)
304
+ branch_pool = self.branch_pool(branch_pool)
305
+
306
+ outputs = [branch1x1, branch3x3, branch3x3dbl, branch_pool]
307
+ return torch.cat(outputs, 1)
basicsr/archs/rcan_arch.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+
4
+ from basicsr.utils.registry import ARCH_REGISTRY
5
+ from .arch_util import Upsample, make_layer
6
+
7
+
8
+ class ChannelAttention(nn.Module):
9
+ """Channel attention used in RCAN.
10
+
11
+ Args:
12
+ num_feat (int): Channel number of intermediate features.
13
+ squeeze_factor (int): Channel squeeze factor. Default: 16.
14
+ """
15
+
16
+ def __init__(self, num_feat, squeeze_factor=16):
17
+ super(ChannelAttention, self).__init__()
18
+ self.attention = nn.Sequential(
19
+ nn.AdaptiveAvgPool2d(1), nn.Conv2d(num_feat, num_feat // squeeze_factor, 1, padding=0),
20
+ nn.ReLU(inplace=True), nn.Conv2d(num_feat // squeeze_factor, num_feat, 1, padding=0), nn.Sigmoid())
21
+
22
+ def forward(self, x):
23
+ y = self.attention(x)
24
+ return x * y
25
+
26
+
27
+ class RCAB(nn.Module):
28
+ """Residual Channel Attention Block (RCAB) used in RCAN.
29
+
30
+ Args:
31
+ num_feat (int): Channel number of intermediate features.
32
+ squeeze_factor (int): Channel squeeze factor. Default: 16.
33
+ res_scale (float): Scale the residual. Default: 1.
34
+ """
35
+
36
+ def __init__(self, num_feat, squeeze_factor=16, res_scale=1):
37
+ super(RCAB, self).__init__()
38
+ self.res_scale = res_scale
39
+
40
+ self.rcab = nn.Sequential(
41
+ nn.Conv2d(num_feat, num_feat, 3, 1, 1), nn.ReLU(True), nn.Conv2d(num_feat, num_feat, 3, 1, 1),
42
+ ChannelAttention(num_feat, squeeze_factor))
43
+
44
+ def forward(self, x):
45
+ res = self.rcab(x) * self.res_scale
46
+ return res + x
47
+
48
+
49
+ class ResidualGroup(nn.Module):
50
+ """Residual Group of RCAB.
51
+
52
+ Args:
53
+ num_feat (int): Channel number of intermediate features.
54
+ num_block (int): Block number in the body network.
55
+ squeeze_factor (int): Channel squeeze factor. Default: 16.
56
+ res_scale (float): Scale the residual. Default: 1.
57
+ """
58
+
59
+ def __init__(self, num_feat, num_block, squeeze_factor=16, res_scale=1):
60
+ super(ResidualGroup, self).__init__()
61
+
62
+ self.residual_group = make_layer(
63
+ RCAB, num_block, num_feat=num_feat, squeeze_factor=squeeze_factor, res_scale=res_scale)
64
+ self.conv = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
65
+
66
+ def forward(self, x):
67
+ res = self.conv(self.residual_group(x))
68
+ return res + x
69
+
70
+
71
+ @ARCH_REGISTRY.register()
72
+ class RCAN(nn.Module):
73
+ """Residual Channel Attention Networks.
74
+
75
+ ``Paper: Image Super-Resolution Using Very Deep Residual Channel Attention Networks``
76
+
77
+ Reference: https://github.com/yulunzhang/RCAN
78
+
79
+ Args:
80
+ num_in_ch (int): Channel number of inputs.
81
+ num_out_ch (int): Channel number of outputs.
82
+ num_feat (int): Channel number of intermediate features.
83
+ Default: 64.
84
+ num_group (int): Number of ResidualGroup. Default: 10.
85
+ num_block (int): Number of RCAB in ResidualGroup. Default: 16.
86
+ squeeze_factor (int): Channel squeeze factor. Default: 16.
87
+ upscale (int): Upsampling factor. Support 2^n and 3.
88
+ Default: 4.
89
+ res_scale (float): Used to scale the residual in residual block.
90
+ Default: 1.
91
+ img_range (float): Image range. Default: 255.
92
+ rgb_mean (tuple[float]): Image mean in RGB orders.
93
+ Default: (0.4488, 0.4371, 0.4040), calculated from DIV2K dataset.
94
+ """
95
+
96
+ def __init__(self,
97
+ num_in_ch,
98
+ num_out_ch,
99
+ num_feat=64,
100
+ num_group=10,
101
+ num_block=16,
102
+ squeeze_factor=16,
103
+ upscale=4,
104
+ res_scale=1,
105
+ img_range=255.,
106
+ rgb_mean=(0.4488, 0.4371, 0.4040)):
107
+ super(RCAN, self).__init__()
108
+
109
+ self.img_range = img_range
110
+ self.mean = torch.Tensor(rgb_mean).view(1, 3, 1, 1)
111
+
112
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
113
+ self.body = make_layer(
114
+ ResidualGroup,
115
+ num_group,
116
+ num_feat=num_feat,
117
+ num_block=num_block,
118
+ squeeze_factor=squeeze_factor,
119
+ res_scale=res_scale)
120
+ self.conv_after_body = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
121
+ self.upsample = Upsample(upscale, num_feat)
122
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
123
+
124
+ def forward(self, x):
125
+ self.mean = self.mean.type_as(x)
126
+
127
+ x = (x - self.mean) * self.img_range
128
+ x = self.conv_first(x)
129
+ res = self.conv_after_body(self.body(x))
130
+ res += x
131
+
132
+ x = self.conv_last(self.upsample(res))
133
+ x = x / self.img_range + self.mean
134
+
135
+ return x
basicsr/archs/ridnet_arch.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ from basicsr.utils.registry import ARCH_REGISTRY
5
+ from .arch_util import ResidualBlockNoBN, make_layer
6
+
7
+
8
+ class MeanShift(nn.Conv2d):
9
+ """ Data normalization with mean and std.
10
+
11
+ Args:
12
+ rgb_range (int): Maximum value of RGB.
13
+ rgb_mean (list[float]): Mean for RGB channels.
14
+ rgb_std (list[float]): Std for RGB channels.
15
+ sign (int): For subtraction, sign is -1, for addition, sign is 1.
16
+ Default: -1.
17
+ requires_grad (bool): Whether to update the self.weight and self.bias.
18
+ Default: True.
19
+ """
20
+
21
+ def __init__(self, rgb_range, rgb_mean, rgb_std, sign=-1, requires_grad=True):
22
+ super(MeanShift, self).__init__(3, 3, kernel_size=1)
23
+ std = torch.Tensor(rgb_std)
24
+ self.weight.data = torch.eye(3).view(3, 3, 1, 1)
25
+ self.weight.data.div_(std.view(3, 1, 1, 1))
26
+ self.bias.data = sign * rgb_range * torch.Tensor(rgb_mean)
27
+ self.bias.data.div_(std)
28
+ self.requires_grad = requires_grad
29
+
30
+
31
+ class EResidualBlockNoBN(nn.Module):
32
+ """Enhanced Residual block without BN.
33
+
34
+ There are three convolution layers in residual branch.
35
+ """
36
+
37
+ def __init__(self, in_channels, out_channels):
38
+ super(EResidualBlockNoBN, self).__init__()
39
+
40
+ self.body = nn.Sequential(
41
+ nn.Conv2d(in_channels, out_channels, 3, 1, 1),
42
+ nn.ReLU(inplace=True),
43
+ nn.Conv2d(out_channels, out_channels, 3, 1, 1),
44
+ nn.ReLU(inplace=True),
45
+ nn.Conv2d(out_channels, out_channels, 1, 1, 0),
46
+ )
47
+ self.relu = nn.ReLU(inplace=True)
48
+
49
+ def forward(self, x):
50
+ out = self.body(x)
51
+ out = self.relu(out + x)
52
+ return out
53
+
54
+
55
+ class MergeRun(nn.Module):
56
+ """ Merge-and-run unit.
57
+
58
+ This unit contains two branches with different dilated convolutions,
59
+ followed by a convolution to process the concatenated features.
60
+
61
+ Paper: Real Image Denoising with Feature Attention
62
+ Ref git repo: https://github.com/saeed-anwar/RIDNet
63
+ """
64
+
65
+ def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1):
66
+ super(MergeRun, self).__init__()
67
+
68
+ self.dilation1 = nn.Sequential(
69
+ nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding), nn.ReLU(inplace=True),
70
+ nn.Conv2d(out_channels, out_channels, kernel_size, stride, 2, 2), nn.ReLU(inplace=True))
71
+ self.dilation2 = nn.Sequential(
72
+ nn.Conv2d(in_channels, out_channels, kernel_size, stride, 3, 3), nn.ReLU(inplace=True),
73
+ nn.Conv2d(out_channels, out_channels, kernel_size, stride, 4, 4), nn.ReLU(inplace=True))
74
+
75
+ self.aggregation = nn.Sequential(
76
+ nn.Conv2d(out_channels * 2, out_channels, kernel_size, stride, padding), nn.ReLU(inplace=True))
77
+
78
+ def forward(self, x):
79
+ dilation1 = self.dilation1(x)
80
+ dilation2 = self.dilation2(x)
81
+ out = torch.cat([dilation1, dilation2], dim=1)
82
+ out = self.aggregation(out)
83
+ out = out + x
84
+ return out
85
+
86
+
87
+ class ChannelAttention(nn.Module):
88
+ """Channel attention.
89
+
90
+ Args:
91
+ num_feat (int): Channel number of intermediate features.
92
+ squeeze_factor (int): Channel squeeze factor. Default:
93
+ """
94
+
95
+ def __init__(self, mid_channels, squeeze_factor=16):
96
+ super(ChannelAttention, self).__init__()
97
+ self.attention = nn.Sequential(
98
+ nn.AdaptiveAvgPool2d(1), nn.Conv2d(mid_channels, mid_channels // squeeze_factor, 1, padding=0),
99
+ nn.ReLU(inplace=True), nn.Conv2d(mid_channels // squeeze_factor, mid_channels, 1, padding=0), nn.Sigmoid())
100
+
101
+ def forward(self, x):
102
+ y = self.attention(x)
103
+ return x * y
104
+
105
+
106
+ class EAM(nn.Module):
107
+ """Enhancement attention modules (EAM) in RIDNet.
108
+
109
+ This module contains a merge-and-run unit, a residual block,
110
+ an enhanced residual block and a feature attention unit.
111
+
112
+ Attributes:
113
+ merge: The merge-and-run unit.
114
+ block1: The residual block.
115
+ block2: The enhanced residual block.
116
+ ca: The feature/channel attention unit.
117
+ """
118
+
119
+ def __init__(self, in_channels, mid_channels, out_channels):
120
+ super(EAM, self).__init__()
121
+
122
+ self.merge = MergeRun(in_channels, mid_channels)
123
+ self.block1 = ResidualBlockNoBN(mid_channels)
124
+ self.block2 = EResidualBlockNoBN(mid_channels, out_channels)
125
+ self.ca = ChannelAttention(out_channels)
126
+ # The residual block in the paper contains a relu after addition.
127
+ self.relu = nn.ReLU(inplace=True)
128
+
129
+ def forward(self, x):
130
+ out = self.merge(x)
131
+ out = self.relu(self.block1(out))
132
+ out = self.block2(out)
133
+ out = self.ca(out)
134
+ return out
135
+
136
+
137
+ @ARCH_REGISTRY.register()
138
+ class RIDNet(nn.Module):
139
+ """RIDNet: Real Image Denoising with Feature Attention.
140
+
141
+ Ref git repo: https://github.com/saeed-anwar/RIDNet
142
+
143
+ Args:
144
+ in_channels (int): Channel number of inputs.
145
+ mid_channels (int): Channel number of EAM modules.
146
+ Default: 64.
147
+ out_channels (int): Channel number of outputs.
148
+ num_block (int): Number of EAM. Default: 4.
149
+ img_range (float): Image range. Default: 255.
150
+ rgb_mean (tuple[float]): Image mean in RGB orders.
151
+ Default: (0.4488, 0.4371, 0.4040), calculated from DIV2K dataset.
152
+ """
153
+
154
+ def __init__(self,
155
+ in_channels,
156
+ mid_channels,
157
+ out_channels,
158
+ num_block=4,
159
+ img_range=255.,
160
+ rgb_mean=(0.4488, 0.4371, 0.4040),
161
+ rgb_std=(1.0, 1.0, 1.0)):
162
+ super(RIDNet, self).__init__()
163
+
164
+ self.sub_mean = MeanShift(img_range, rgb_mean, rgb_std)
165
+ self.add_mean = MeanShift(img_range, rgb_mean, rgb_std, 1)
166
+
167
+ self.head = nn.Conv2d(in_channels, mid_channels, 3, 1, 1)
168
+ self.body = make_layer(
169
+ EAM, num_block, in_channels=mid_channels, mid_channels=mid_channels, out_channels=mid_channels)
170
+ self.tail = nn.Conv2d(mid_channels, out_channels, 3, 1, 1)
171
+
172
+ self.relu = nn.ReLU(inplace=True)
173
+
174
+ def forward(self, x):
175
+ res = self.sub_mean(x)
176
+ res = self.tail(self.body(self.relu(self.head(res))))
177
+ res = self.add_mean(res)
178
+
179
+ out = x + res
180
+ return out
basicsr/archs/rrdbnet_arch.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+ from torch.nn import functional as F
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+ from .arch_util import default_init_weights, make_layer, pixel_unshuffle
7
+
8
+
9
+ class ResidualDenseBlock(nn.Module):
10
+ """Residual Dense Block.
11
+
12
+ Used in RRDB block in ESRGAN.
13
+
14
+ Args:
15
+ num_feat (int): Channel number of intermediate features.
16
+ num_grow_ch (int): Channels for each growth.
17
+ """
18
+
19
+ def __init__(self, num_feat=64, num_grow_ch=32):
20
+ super(ResidualDenseBlock, self).__init__()
21
+ self.conv1 = nn.Conv2d(num_feat, num_grow_ch, 3, 1, 1)
22
+ self.conv2 = nn.Conv2d(num_feat + num_grow_ch, num_grow_ch, 3, 1, 1)
23
+ self.conv3 = nn.Conv2d(num_feat + 2 * num_grow_ch, num_grow_ch, 3, 1, 1)
24
+ self.conv4 = nn.Conv2d(num_feat + 3 * num_grow_ch, num_grow_ch, 3, 1, 1)
25
+ self.conv5 = nn.Conv2d(num_feat + 4 * num_grow_ch, num_feat, 3, 1, 1)
26
+
27
+ self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
28
+
29
+ # initialization
30
+ default_init_weights([self.conv1, self.conv2, self.conv3, self.conv4, self.conv5], 0.1)
31
+
32
+ def forward(self, x):
33
+ x1 = self.lrelu(self.conv1(x))
34
+ x2 = self.lrelu(self.conv2(torch.cat((x, x1), 1)))
35
+ x3 = self.lrelu(self.conv3(torch.cat((x, x1, x2), 1)))
36
+ x4 = self.lrelu(self.conv4(torch.cat((x, x1, x2, x3), 1)))
37
+ x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
38
+ # Empirically, we use 0.2 to scale the residual for better performance
39
+ return x5 * 0.2 + x
40
+
41
+
42
+ class RRDB(nn.Module):
43
+ """Residual in Residual Dense Block.
44
+
45
+ Used in RRDB-Net in ESRGAN.
46
+
47
+ Args:
48
+ num_feat (int): Channel number of intermediate features.
49
+ num_grow_ch (int): Channels for each growth.
50
+ """
51
+
52
+ def __init__(self, num_feat, num_grow_ch=32):
53
+ super(RRDB, self).__init__()
54
+ self.rdb1 = ResidualDenseBlock(num_feat, num_grow_ch)
55
+ self.rdb2 = ResidualDenseBlock(num_feat, num_grow_ch)
56
+ self.rdb3 = ResidualDenseBlock(num_feat, num_grow_ch)
57
+
58
+ def forward(self, x):
59
+ out = self.rdb1(x)
60
+ out = self.rdb2(out)
61
+ out = self.rdb3(out)
62
+ # Empirically, we use 0.2 to scale the residual for better performance
63
+ return out * 0.2 + x
64
+
65
+
66
+ @ARCH_REGISTRY.register()
67
+ class RRDBNet(nn.Module):
68
+ """Networks consisting of Residual in Residual Dense Block, which is used
69
+ in ESRGAN.
70
+
71
+ ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks.
72
+
73
+ We extend ESRGAN for scale x2 and scale x1.
74
+ Note: This is one option for scale 1, scale 2 in RRDBNet.
75
+ We first employ the pixel-unshuffle (an inverse operation of pixelshuffle to reduce the spatial size
76
+ and enlarge the channel size before feeding inputs into the main ESRGAN architecture.
77
+
78
+ Args:
79
+ num_in_ch (int): Channel number of inputs.
80
+ num_out_ch (int): Channel number of outputs.
81
+ num_feat (int): Channel number of intermediate features.
82
+ Default: 64
83
+ num_block (int): Block number in the trunk network. Defaults: 23
84
+ num_grow_ch (int): Channels for each growth. Default: 32.
85
+ """
86
+
87
+ def __init__(self, num_in_ch, num_out_ch, scale=4, num_feat=64, num_block=23, num_grow_ch=32):
88
+ super(RRDBNet, self).__init__()
89
+ self.scale = scale
90
+ if scale == 2:
91
+ num_in_ch = num_in_ch * 4
92
+ elif scale == 1:
93
+ num_in_ch = num_in_ch * 16
94
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
95
+ self.body = make_layer(RRDB, num_block, num_feat=num_feat, num_grow_ch=num_grow_ch)
96
+ self.conv_body = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
97
+ # upsample
98
+ self.conv_up1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
99
+ self.conv_up2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
100
+ self.conv_hr = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
101
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
102
+
103
+ self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
104
+
105
+ def forward(self, x):
106
+ if self.scale == 2:
107
+ feat = pixel_unshuffle(x, scale=2)
108
+ elif self.scale == 1:
109
+ feat = pixel_unshuffle(x, scale=4)
110
+ else:
111
+ feat = x
112
+ feat = self.conv_first(feat)
113
+ body_feat = self.conv_body(self.body(feat))
114
+ feat = feat + body_feat
115
+ # upsample
116
+ feat = self.lrelu(self.conv_up1(F.interpolate(feat, scale_factor=2, mode='nearest')))
117
+ feat = self.lrelu(self.conv_up2(F.interpolate(feat, scale_factor=2, mode='nearest')))
118
+ out = self.conv_last(self.lrelu(self.conv_hr(feat)))
119
+ return out
basicsr/archs/spynet_arch.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch import nn as nn
4
+ from torch.nn import functional as F
5
+
6
+ from basicsr.utils.registry import ARCH_REGISTRY
7
+ from .arch_util import flow_warp
8
+
9
+
10
+ class BasicModule(nn.Module):
11
+ """Basic Module for SpyNet.
12
+ """
13
+
14
+ def __init__(self):
15
+ super(BasicModule, self).__init__()
16
+
17
+ self.basic_module = nn.Sequential(
18
+ nn.Conv2d(in_channels=8, out_channels=32, kernel_size=7, stride=1, padding=3), nn.ReLU(inplace=False),
19
+ nn.Conv2d(in_channels=32, out_channels=64, kernel_size=7, stride=1, padding=3), nn.ReLU(inplace=False),
20
+ nn.Conv2d(in_channels=64, out_channels=32, kernel_size=7, stride=1, padding=3), nn.ReLU(inplace=False),
21
+ nn.Conv2d(in_channels=32, out_channels=16, kernel_size=7, stride=1, padding=3), nn.ReLU(inplace=False),
22
+ nn.Conv2d(in_channels=16, out_channels=2, kernel_size=7, stride=1, padding=3))
23
+
24
+ def forward(self, tensor_input):
25
+ return self.basic_module(tensor_input)
26
+
27
+
28
+ @ARCH_REGISTRY.register()
29
+ class SpyNet(nn.Module):
30
+ """SpyNet architecture.
31
+
32
+ Args:
33
+ load_path (str): path for pretrained SpyNet. Default: None.
34
+ """
35
+
36
+ def __init__(self, load_path=None):
37
+ super(SpyNet, self).__init__()
38
+ self.basic_module = nn.ModuleList([BasicModule() for _ in range(6)])
39
+ if load_path:
40
+ self.load_state_dict(torch.load(load_path, map_location=lambda storage, loc: storage)['params'])
41
+
42
+ self.register_buffer('mean', torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
43
+ self.register_buffer('std', torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))
44
+
45
+ def preprocess(self, tensor_input):
46
+ tensor_output = (tensor_input - self.mean) / self.std
47
+ return tensor_output
48
+
49
+ def process(self, ref, supp):
50
+ flow = []
51
+
52
+ ref = [self.preprocess(ref)]
53
+ supp = [self.preprocess(supp)]
54
+
55
+ for level in range(5):
56
+ ref.insert(0, F.avg_pool2d(input=ref[0], kernel_size=2, stride=2, count_include_pad=False))
57
+ supp.insert(0, F.avg_pool2d(input=supp[0], kernel_size=2, stride=2, count_include_pad=False))
58
+
59
+ flow = ref[0].new_zeros(
60
+ [ref[0].size(0), 2,
61
+ int(math.floor(ref[0].size(2) / 2.0)),
62
+ int(math.floor(ref[0].size(3) / 2.0))])
63
+
64
+ for level in range(len(ref)):
65
+ upsampled_flow = F.interpolate(input=flow, scale_factor=2, mode='bilinear', align_corners=True) * 2.0
66
+
67
+ if upsampled_flow.size(2) != ref[level].size(2):
68
+ upsampled_flow = F.pad(input=upsampled_flow, pad=[0, 0, 0, 1], mode='replicate')
69
+ if upsampled_flow.size(3) != ref[level].size(3):
70
+ upsampled_flow = F.pad(input=upsampled_flow, pad=[0, 1, 0, 0], mode='replicate')
71
+
72
+ flow = self.basic_module[level](torch.cat([
73
+ ref[level],
74
+ flow_warp(
75
+ supp[level], upsampled_flow.permute(0, 2, 3, 1), interp_mode='bilinear', padding_mode='border'),
76
+ upsampled_flow
77
+ ], 1)) + upsampled_flow
78
+
79
+ return flow
80
+
81
+ def forward(self, ref, supp):
82
+ assert ref.size() == supp.size()
83
+
84
+ h, w = ref.size(2), ref.size(3)
85
+ w_floor = math.floor(math.ceil(w / 32.0) * 32.0)
86
+ h_floor = math.floor(math.ceil(h / 32.0) * 32.0)
87
+
88
+ ref = F.interpolate(input=ref, size=(h_floor, w_floor), mode='bilinear', align_corners=False)
89
+ supp = F.interpolate(input=supp, size=(h_floor, w_floor), mode='bilinear', align_corners=False)
90
+
91
+ flow = F.interpolate(input=self.process(ref, supp), size=(h, w), mode='bilinear', align_corners=False)
92
+
93
+ flow[:, 0, :, :] *= float(w) / float(w_floor)
94
+ flow[:, 1, :, :] *= float(h) / float(h_floor)
95
+
96
+ return flow
basicsr/archs/srresnet_arch.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn as nn
2
+ from torch.nn import functional as F
3
+
4
+ from basicsr.utils.registry import ARCH_REGISTRY
5
+ from .arch_util import ResidualBlockNoBN, default_init_weights, make_layer
6
+
7
+
8
+ @ARCH_REGISTRY.register()
9
+ class MSRResNet(nn.Module):
10
+ """Modified SRResNet.
11
+
12
+ A compacted version modified from SRResNet in
13
+ "Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network"
14
+ It uses residual blocks without BN, similar to EDSR.
15
+ Currently, it supports x2, x3 and x4 upsampling scale factor.
16
+
17
+ Args:
18
+ num_in_ch (int): Channel number of inputs. Default: 3.
19
+ num_out_ch (int): Channel number of outputs. Default: 3.
20
+ num_feat (int): Channel number of intermediate features. Default: 64.
21
+ num_block (int): Block number in the body network. Default: 16.
22
+ upscale (int): Upsampling factor. Support x2, x3 and x4. Default: 4.
23
+ """
24
+
25
+ def __init__(self, num_in_ch=3, num_out_ch=3, num_feat=64, num_block=16, upscale=4):
26
+ super(MSRResNet, self).__init__()
27
+ self.upscale = upscale
28
+
29
+ self.conv_first = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1)
30
+ self.body = make_layer(ResidualBlockNoBN, num_block, num_feat=num_feat)
31
+
32
+ # upsampling
33
+ if self.upscale in [2, 3]:
34
+ self.upconv1 = nn.Conv2d(num_feat, num_feat * self.upscale * self.upscale, 3, 1, 1)
35
+ self.pixel_shuffle = nn.PixelShuffle(self.upscale)
36
+ elif self.upscale == 4:
37
+ self.upconv1 = nn.Conv2d(num_feat, num_feat * 4, 3, 1, 1)
38
+ self.upconv2 = nn.Conv2d(num_feat, num_feat * 4, 3, 1, 1)
39
+ self.pixel_shuffle = nn.PixelShuffle(2)
40
+
41
+ self.conv_hr = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
42
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
43
+
44
+ # activation function
45
+ self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
46
+
47
+ # initialization
48
+ default_init_weights([self.conv_first, self.upconv1, self.conv_hr, self.conv_last], 0.1)
49
+ if self.upscale == 4:
50
+ default_init_weights(self.upconv2, 0.1)
51
+
52
+ def forward(self, x):
53
+ feat = self.lrelu(self.conv_first(x))
54
+ out = self.body(feat)
55
+
56
+ if self.upscale == 4:
57
+ out = self.lrelu(self.pixel_shuffle(self.upconv1(out)))
58
+ out = self.lrelu(self.pixel_shuffle(self.upconv2(out)))
59
+ elif self.upscale in [2, 3]:
60
+ out = self.lrelu(self.pixel_shuffle(self.upconv1(out)))
61
+
62
+ out = self.conv_last(self.lrelu(self.conv_hr(out)))
63
+ base = F.interpolate(x, scale_factor=self.upscale, mode='bilinear', align_corners=False)
64
+ out += base
65
+ return out
basicsr/archs/srvgg_arch.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn as nn
2
+ from torch.nn import functional as F
3
+
4
+ from basicsr.utils.registry import ARCH_REGISTRY
5
+
6
+
7
+ @ARCH_REGISTRY.register(suffix='basicsr')
8
+ class SRVGGNetCompact(nn.Module):
9
+ """A compact VGG-style network structure for super-resolution.
10
+
11
+ It is a compact network structure, which performs upsampling in the last layer and no convolution is
12
+ conducted on the HR feature space.
13
+
14
+ Args:
15
+ num_in_ch (int): Channel number of inputs. Default: 3.
16
+ num_out_ch (int): Channel number of outputs. Default: 3.
17
+ num_feat (int): Channel number of intermediate features. Default: 64.
18
+ num_conv (int): Number of convolution layers in the body network. Default: 16.
19
+ upscale (int): Upsampling factor. Default: 4.
20
+ act_type (str): Activation type, options: 'relu', 'prelu', 'leakyrelu'. Default: prelu.
21
+ """
22
+
23
+ def __init__(self, num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=16, upscale=4, act_type='prelu'):
24
+ super(SRVGGNetCompact, self).__init__()
25
+ self.num_in_ch = num_in_ch
26
+ self.num_out_ch = num_out_ch
27
+ self.num_feat = num_feat
28
+ self.num_conv = num_conv
29
+ self.upscale = upscale
30
+ self.act_type = act_type
31
+
32
+ self.body = nn.ModuleList()
33
+ # the first conv
34
+ self.body.append(nn.Conv2d(num_in_ch, num_feat, 3, 1, 1))
35
+ # the first activation
36
+ if act_type == 'relu':
37
+ activation = nn.ReLU(inplace=True)
38
+ elif act_type == 'prelu':
39
+ activation = nn.PReLU(num_parameters=num_feat)
40
+ elif act_type == 'leakyrelu':
41
+ activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
42
+ self.body.append(activation)
43
+
44
+ # the body structure
45
+ for _ in range(num_conv):
46
+ self.body.append(nn.Conv2d(num_feat, num_feat, 3, 1, 1))
47
+ # activation
48
+ if act_type == 'relu':
49
+ activation = nn.ReLU(inplace=True)
50
+ elif act_type == 'prelu':
51
+ activation = nn.PReLU(num_parameters=num_feat)
52
+ elif act_type == 'leakyrelu':
53
+ activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
54
+ self.body.append(activation)
55
+
56
+ # the last conv
57
+ self.body.append(nn.Conv2d(num_feat, num_out_ch * upscale * upscale, 3, 1, 1))
58
+ # upsample
59
+ self.upsampler = nn.PixelShuffle(upscale)
60
+
61
+ def forward(self, x):
62
+ out = x
63
+ for i in range(0, len(self.body)):
64
+ out = self.body[i](out)
65
+
66
+ out = self.upsampler(out)
67
+ # add the nearest upsampled image, so that the network learns the residual
68
+ base = F.interpolate(x, scale_factor=self.upscale, mode='nearest')
69
+ out += base
70
+ return out
basicsr/archs/stylegan2_arch.py ADDED
@@ -0,0 +1,799 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import random
3
+ import torch
4
+ from torch import nn
5
+ from torch.nn import functional as F
6
+
7
+ from basicsr.ops.fused_act import FusedLeakyReLU, fused_leaky_relu
8
+ from basicsr.ops.upfirdn2d import upfirdn2d
9
+ from basicsr.utils.registry import ARCH_REGISTRY
10
+
11
+
12
+ class NormStyleCode(nn.Module):
13
+
14
+ def forward(self, x):
15
+ """Normalize the style codes.
16
+
17
+ Args:
18
+ x (Tensor): Style codes with shape (b, c).
19
+
20
+ Returns:
21
+ Tensor: Normalized tensor.
22
+ """
23
+ return x * torch.rsqrt(torch.mean(x**2, dim=1, keepdim=True) + 1e-8)
24
+
25
+
26
+ def make_resample_kernel(k):
27
+ """Make resampling kernel for UpFirDn.
28
+
29
+ Args:
30
+ k (list[int]): A list indicating the 1D resample kernel magnitude.
31
+
32
+ Returns:
33
+ Tensor: 2D resampled kernel.
34
+ """
35
+ k = torch.tensor(k, dtype=torch.float32)
36
+ if k.ndim == 1:
37
+ k = k[None, :] * k[:, None] # to 2D kernel, outer product
38
+ # normalize
39
+ k /= k.sum()
40
+ return k
41
+
42
+
43
+ class UpFirDnUpsample(nn.Module):
44
+ """Upsample, FIR filter, and downsample (upsampole version).
45
+
46
+ References:
47
+ 1. https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.upfirdn.html # noqa: E501
48
+ 2. http://www.ece.northwestern.edu/local-apps/matlabhelp/toolbox/signal/upfirdn.html # noqa: E501
49
+
50
+ Args:
51
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
52
+ magnitude.
53
+ factor (int): Upsampling scale factor. Default: 2.
54
+ """
55
+
56
+ def __init__(self, resample_kernel, factor=2):
57
+ super(UpFirDnUpsample, self).__init__()
58
+ self.kernel = make_resample_kernel(resample_kernel) * (factor**2)
59
+ self.factor = factor
60
+
61
+ pad = self.kernel.shape[0] - factor
62
+ self.pad = ((pad + 1) // 2 + factor - 1, pad // 2)
63
+
64
+ def forward(self, x):
65
+ out = upfirdn2d(x, self.kernel.type_as(x), up=self.factor, down=1, pad=self.pad)
66
+ return out
67
+
68
+ def __repr__(self):
69
+ return (f'{self.__class__.__name__}(factor={self.factor})')
70
+
71
+
72
+ class UpFirDnDownsample(nn.Module):
73
+ """Upsample, FIR filter, and downsample (downsampole version).
74
+
75
+ Args:
76
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
77
+ magnitude.
78
+ factor (int): Downsampling scale factor. Default: 2.
79
+ """
80
+
81
+ def __init__(self, resample_kernel, factor=2):
82
+ super(UpFirDnDownsample, self).__init__()
83
+ self.kernel = make_resample_kernel(resample_kernel)
84
+ self.factor = factor
85
+
86
+ pad = self.kernel.shape[0] - factor
87
+ self.pad = ((pad + 1) // 2, pad // 2)
88
+
89
+ def forward(self, x):
90
+ out = upfirdn2d(x, self.kernel.type_as(x), up=1, down=self.factor, pad=self.pad)
91
+ return out
92
+
93
+ def __repr__(self):
94
+ return (f'{self.__class__.__name__}(factor={self.factor})')
95
+
96
+
97
+ class UpFirDnSmooth(nn.Module):
98
+ """Upsample, FIR filter, and downsample (smooth version).
99
+
100
+ Args:
101
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
102
+ magnitude.
103
+ upsample_factor (int): Upsampling scale factor. Default: 1.
104
+ downsample_factor (int): Downsampling scale factor. Default: 1.
105
+ kernel_size (int): Kernel size: Default: 1.
106
+ """
107
+
108
+ def __init__(self, resample_kernel, upsample_factor=1, downsample_factor=1, kernel_size=1):
109
+ super(UpFirDnSmooth, self).__init__()
110
+ self.upsample_factor = upsample_factor
111
+ self.downsample_factor = downsample_factor
112
+ self.kernel = make_resample_kernel(resample_kernel)
113
+ if upsample_factor > 1:
114
+ self.kernel = self.kernel * (upsample_factor**2)
115
+
116
+ if upsample_factor > 1:
117
+ pad = (self.kernel.shape[0] - upsample_factor) - (kernel_size - 1)
118
+ self.pad = ((pad + 1) // 2 + upsample_factor - 1, pad // 2 + 1)
119
+ elif downsample_factor > 1:
120
+ pad = (self.kernel.shape[0] - downsample_factor) + (kernel_size - 1)
121
+ self.pad = ((pad + 1) // 2, pad // 2)
122
+ else:
123
+ raise NotImplementedError
124
+
125
+ def forward(self, x):
126
+ out = upfirdn2d(x, self.kernel.type_as(x), up=1, down=1, pad=self.pad)
127
+ return out
128
+
129
+ def __repr__(self):
130
+ return (f'{self.__class__.__name__}(upsample_factor={self.upsample_factor}'
131
+ f', downsample_factor={self.downsample_factor})')
132
+
133
+
134
+ class EqualLinear(nn.Module):
135
+ """Equalized Linear as StyleGAN2.
136
+
137
+ Args:
138
+ in_channels (int): Size of each sample.
139
+ out_channels (int): Size of each output sample.
140
+ bias (bool): If set to ``False``, the layer will not learn an additive
141
+ bias. Default: ``True``.
142
+ bias_init_val (float): Bias initialized value. Default: 0.
143
+ lr_mul (float): Learning rate multiplier. Default: 1.
144
+ activation (None | str): The activation after ``linear`` operation.
145
+ Supported: 'fused_lrelu', None. Default: None.
146
+ """
147
+
148
+ def __init__(self, in_channels, out_channels, bias=True, bias_init_val=0, lr_mul=1, activation=None):
149
+ super(EqualLinear, self).__init__()
150
+ self.in_channels = in_channels
151
+ self.out_channels = out_channels
152
+ self.lr_mul = lr_mul
153
+ self.activation = activation
154
+ if self.activation not in ['fused_lrelu', None]:
155
+ raise ValueError(f'Wrong activation value in EqualLinear: {activation}'
156
+ "Supported ones are: ['fused_lrelu', None].")
157
+ self.scale = (1 / math.sqrt(in_channels)) * lr_mul
158
+
159
+ self.weight = nn.Parameter(torch.randn(out_channels, in_channels).div_(lr_mul))
160
+ if bias:
161
+ self.bias = nn.Parameter(torch.zeros(out_channels).fill_(bias_init_val))
162
+ else:
163
+ self.register_parameter('bias', None)
164
+
165
+ def forward(self, x):
166
+ if self.bias is None:
167
+ bias = None
168
+ else:
169
+ bias = self.bias * self.lr_mul
170
+ if self.activation == 'fused_lrelu':
171
+ out = F.linear(x, self.weight * self.scale)
172
+ out = fused_leaky_relu(out, bias)
173
+ else:
174
+ out = F.linear(x, self.weight * self.scale, bias=bias)
175
+ return out
176
+
177
+ def __repr__(self):
178
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
179
+ f'out_channels={self.out_channels}, bias={self.bias is not None})')
180
+
181
+
182
+ class ModulatedConv2d(nn.Module):
183
+ """Modulated Conv2d used in StyleGAN2.
184
+
185
+ There is no bias in ModulatedConv2d.
186
+
187
+ Args:
188
+ in_channels (int): Channel number of the input.
189
+ out_channels (int): Channel number of the output.
190
+ kernel_size (int): Size of the convolving kernel.
191
+ num_style_feat (int): Channel number of style features.
192
+ demodulate (bool): Whether to demodulate in the conv layer.
193
+ Default: True.
194
+ sample_mode (str | None): Indicating 'upsample', 'downsample' or None.
195
+ Default: None.
196
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
197
+ magnitude. Default: (1, 3, 3, 1).
198
+ eps (float): A value added to the denominator for numerical stability.
199
+ Default: 1e-8.
200
+ """
201
+
202
+ def __init__(self,
203
+ in_channels,
204
+ out_channels,
205
+ kernel_size,
206
+ num_style_feat,
207
+ demodulate=True,
208
+ sample_mode=None,
209
+ resample_kernel=(1, 3, 3, 1),
210
+ eps=1e-8):
211
+ super(ModulatedConv2d, self).__init__()
212
+ self.in_channels = in_channels
213
+ self.out_channels = out_channels
214
+ self.kernel_size = kernel_size
215
+ self.demodulate = demodulate
216
+ self.sample_mode = sample_mode
217
+ self.eps = eps
218
+
219
+ if self.sample_mode == 'upsample':
220
+ self.smooth = UpFirDnSmooth(
221
+ resample_kernel, upsample_factor=2, downsample_factor=1, kernel_size=kernel_size)
222
+ elif self.sample_mode == 'downsample':
223
+ self.smooth = UpFirDnSmooth(
224
+ resample_kernel, upsample_factor=1, downsample_factor=2, kernel_size=kernel_size)
225
+ elif self.sample_mode is None:
226
+ pass
227
+ else:
228
+ raise ValueError(f'Wrong sample mode {self.sample_mode}, '
229
+ "supported ones are ['upsample', 'downsample', None].")
230
+
231
+ self.scale = 1 / math.sqrt(in_channels * kernel_size**2)
232
+ # modulation inside each modulated conv
233
+ self.modulation = EqualLinear(
234
+ num_style_feat, in_channels, bias=True, bias_init_val=1, lr_mul=1, activation=None)
235
+
236
+ self.weight = nn.Parameter(torch.randn(1, out_channels, in_channels, kernel_size, kernel_size))
237
+ self.padding = kernel_size // 2
238
+
239
+ def forward(self, x, style):
240
+ """Forward function.
241
+
242
+ Args:
243
+ x (Tensor): Tensor with shape (b, c, h, w).
244
+ style (Tensor): Tensor with shape (b, num_style_feat).
245
+
246
+ Returns:
247
+ Tensor: Modulated tensor after convolution.
248
+ """
249
+ b, c, h, w = x.shape # c = c_in
250
+ # weight modulation
251
+ style = self.modulation(style).view(b, 1, c, 1, 1)
252
+ # self.weight: (1, c_out, c_in, k, k); style: (b, 1, c, 1, 1)
253
+ weight = self.scale * self.weight * style # (b, c_out, c_in, k, k)
254
+
255
+ if self.demodulate:
256
+ demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps)
257
+ weight = weight * demod.view(b, self.out_channels, 1, 1, 1)
258
+
259
+ weight = weight.view(b * self.out_channels, c, self.kernel_size, self.kernel_size)
260
+
261
+ if self.sample_mode == 'upsample':
262
+ x = x.view(1, b * c, h, w)
263
+ weight = weight.view(b, self.out_channels, c, self.kernel_size, self.kernel_size)
264
+ weight = weight.transpose(1, 2).reshape(b * c, self.out_channels, self.kernel_size, self.kernel_size)
265
+ out = F.conv_transpose2d(x, weight, padding=0, stride=2, groups=b)
266
+ out = out.view(b, self.out_channels, *out.shape[2:4])
267
+ out = self.smooth(out)
268
+ elif self.sample_mode == 'downsample':
269
+ x = self.smooth(x)
270
+ x = x.view(1, b * c, *x.shape[2:4])
271
+ out = F.conv2d(x, weight, padding=0, stride=2, groups=b)
272
+ out = out.view(b, self.out_channels, *out.shape[2:4])
273
+ else:
274
+ x = x.view(1, b * c, h, w)
275
+ # weight: (b*c_out, c_in, k, k), groups=b
276
+ out = F.conv2d(x, weight, padding=self.padding, groups=b)
277
+ out = out.view(b, self.out_channels, *out.shape[2:4])
278
+
279
+ return out
280
+
281
+ def __repr__(self):
282
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
283
+ f'out_channels={self.out_channels}, '
284
+ f'kernel_size={self.kernel_size}, '
285
+ f'demodulate={self.demodulate}, sample_mode={self.sample_mode})')
286
+
287
+
288
+ class StyleConv(nn.Module):
289
+ """Style conv.
290
+
291
+ Args:
292
+ in_channels (int): Channel number of the input.
293
+ out_channels (int): Channel number of the output.
294
+ kernel_size (int): Size of the convolving kernel.
295
+ num_style_feat (int): Channel number of style features.
296
+ demodulate (bool): Whether demodulate in the conv layer. Default: True.
297
+ sample_mode (str | None): Indicating 'upsample', 'downsample' or None.
298
+ Default: None.
299
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
300
+ magnitude. Default: (1, 3, 3, 1).
301
+ """
302
+
303
+ def __init__(self,
304
+ in_channels,
305
+ out_channels,
306
+ kernel_size,
307
+ num_style_feat,
308
+ demodulate=True,
309
+ sample_mode=None,
310
+ resample_kernel=(1, 3, 3, 1)):
311
+ super(StyleConv, self).__init__()
312
+ self.modulated_conv = ModulatedConv2d(
313
+ in_channels,
314
+ out_channels,
315
+ kernel_size,
316
+ num_style_feat,
317
+ demodulate=demodulate,
318
+ sample_mode=sample_mode,
319
+ resample_kernel=resample_kernel)
320
+ self.weight = nn.Parameter(torch.zeros(1)) # for noise injection
321
+ self.activate = FusedLeakyReLU(out_channels)
322
+
323
+ def forward(self, x, style, noise=None):
324
+ # modulate
325
+ out = self.modulated_conv(x, style)
326
+ # noise injection
327
+ if noise is None:
328
+ b, _, h, w = out.shape
329
+ noise = out.new_empty(b, 1, h, w).normal_()
330
+ out = out + self.weight * noise
331
+ # activation (with bias)
332
+ out = self.activate(out)
333
+ return out
334
+
335
+
336
+ class ToRGB(nn.Module):
337
+ """To RGB from features.
338
+
339
+ Args:
340
+ in_channels (int): Channel number of input.
341
+ num_style_feat (int): Channel number of style features.
342
+ upsample (bool): Whether to upsample. Default: True.
343
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
344
+ magnitude. Default: (1, 3, 3, 1).
345
+ """
346
+
347
+ def __init__(self, in_channels, num_style_feat, upsample=True, resample_kernel=(1, 3, 3, 1)):
348
+ super(ToRGB, self).__init__()
349
+ if upsample:
350
+ self.upsample = UpFirDnUpsample(resample_kernel, factor=2)
351
+ else:
352
+ self.upsample = None
353
+ self.modulated_conv = ModulatedConv2d(
354
+ in_channels, 3, kernel_size=1, num_style_feat=num_style_feat, demodulate=False, sample_mode=None)
355
+ self.bias = nn.Parameter(torch.zeros(1, 3, 1, 1))
356
+
357
+ def forward(self, x, style, skip=None):
358
+ """Forward function.
359
+
360
+ Args:
361
+ x (Tensor): Feature tensor with shape (b, c, h, w).
362
+ style (Tensor): Tensor with shape (b, num_style_feat).
363
+ skip (Tensor): Base/skip tensor. Default: None.
364
+
365
+ Returns:
366
+ Tensor: RGB images.
367
+ """
368
+ out = self.modulated_conv(x, style)
369
+ out = out + self.bias
370
+ if skip is not None:
371
+ if self.upsample:
372
+ skip = self.upsample(skip)
373
+ out = out + skip
374
+ return out
375
+
376
+
377
+ class ConstantInput(nn.Module):
378
+ """Constant input.
379
+
380
+ Args:
381
+ num_channel (int): Channel number of constant input.
382
+ size (int): Spatial size of constant input.
383
+ """
384
+
385
+ def __init__(self, num_channel, size):
386
+ super(ConstantInput, self).__init__()
387
+ self.weight = nn.Parameter(torch.randn(1, num_channel, size, size))
388
+
389
+ def forward(self, batch):
390
+ out = self.weight.repeat(batch, 1, 1, 1)
391
+ return out
392
+
393
+
394
+ @ARCH_REGISTRY.register()
395
+ class StyleGAN2Generator(nn.Module):
396
+ """StyleGAN2 Generator.
397
+
398
+ Args:
399
+ out_size (int): The spatial size of outputs.
400
+ num_style_feat (int): Channel number of style features. Default: 512.
401
+ num_mlp (int): Layer number of MLP style layers. Default: 8.
402
+ channel_multiplier (int): Channel multiplier for large networks of
403
+ StyleGAN2. Default: 2.
404
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
405
+ magnitude. A cross production will be applied to extent 1D resample
406
+ kernel to 2D resample kernel. Default: (1, 3, 3, 1).
407
+ lr_mlp (float): Learning rate multiplier for mlp layers. Default: 0.01.
408
+ narrow (float): Narrow ratio for channels. Default: 1.0.
409
+ """
410
+
411
+ def __init__(self,
412
+ out_size,
413
+ num_style_feat=512,
414
+ num_mlp=8,
415
+ channel_multiplier=2,
416
+ resample_kernel=(1, 3, 3, 1),
417
+ lr_mlp=0.01,
418
+ narrow=1):
419
+ super(StyleGAN2Generator, self).__init__()
420
+ # Style MLP layers
421
+ self.num_style_feat = num_style_feat
422
+ style_mlp_layers = [NormStyleCode()]
423
+ for i in range(num_mlp):
424
+ style_mlp_layers.append(
425
+ EqualLinear(
426
+ num_style_feat, num_style_feat, bias=True, bias_init_val=0, lr_mul=lr_mlp,
427
+ activation='fused_lrelu'))
428
+ self.style_mlp = nn.Sequential(*style_mlp_layers)
429
+
430
+ channels = {
431
+ '4': int(512 * narrow),
432
+ '8': int(512 * narrow),
433
+ '16': int(512 * narrow),
434
+ '32': int(512 * narrow),
435
+ '64': int(256 * channel_multiplier * narrow),
436
+ '128': int(128 * channel_multiplier * narrow),
437
+ '256': int(64 * channel_multiplier * narrow),
438
+ '512': int(32 * channel_multiplier * narrow),
439
+ '1024': int(16 * channel_multiplier * narrow)
440
+ }
441
+ self.channels = channels
442
+
443
+ self.constant_input = ConstantInput(channels['4'], size=4)
444
+ self.style_conv1 = StyleConv(
445
+ channels['4'],
446
+ channels['4'],
447
+ kernel_size=3,
448
+ num_style_feat=num_style_feat,
449
+ demodulate=True,
450
+ sample_mode=None,
451
+ resample_kernel=resample_kernel)
452
+ self.to_rgb1 = ToRGB(channels['4'], num_style_feat, upsample=False, resample_kernel=resample_kernel)
453
+
454
+ self.log_size = int(math.log(out_size, 2))
455
+ self.num_layers = (self.log_size - 2) * 2 + 1
456
+ self.num_latent = self.log_size * 2 - 2
457
+
458
+ self.style_convs = nn.ModuleList()
459
+ self.to_rgbs = nn.ModuleList()
460
+ self.noises = nn.Module()
461
+
462
+ in_channels = channels['4']
463
+ # noise
464
+ for layer_idx in range(self.num_layers):
465
+ resolution = 2**((layer_idx + 5) // 2)
466
+ shape = [1, 1, resolution, resolution]
467
+ self.noises.register_buffer(f'noise{layer_idx}', torch.randn(*shape))
468
+ # style convs and to_rgbs
469
+ for i in range(3, self.log_size + 1):
470
+ out_channels = channels[f'{2**i}']
471
+ self.style_convs.append(
472
+ StyleConv(
473
+ in_channels,
474
+ out_channels,
475
+ kernel_size=3,
476
+ num_style_feat=num_style_feat,
477
+ demodulate=True,
478
+ sample_mode='upsample',
479
+ resample_kernel=resample_kernel,
480
+ ))
481
+ self.style_convs.append(
482
+ StyleConv(
483
+ out_channels,
484
+ out_channels,
485
+ kernel_size=3,
486
+ num_style_feat=num_style_feat,
487
+ demodulate=True,
488
+ sample_mode=None,
489
+ resample_kernel=resample_kernel))
490
+ self.to_rgbs.append(ToRGB(out_channels, num_style_feat, upsample=True, resample_kernel=resample_kernel))
491
+ in_channels = out_channels
492
+
493
+ def make_noise(self):
494
+ """Make noise for noise injection."""
495
+ device = self.constant_input.weight.device
496
+ noises = [torch.randn(1, 1, 4, 4, device=device)]
497
+
498
+ for i in range(3, self.log_size + 1):
499
+ for _ in range(2):
500
+ noises.append(torch.randn(1, 1, 2**i, 2**i, device=device))
501
+
502
+ return noises
503
+
504
+ def get_latent(self, x):
505
+ return self.style_mlp(x)
506
+
507
+ def mean_latent(self, num_latent):
508
+ latent_in = torch.randn(num_latent, self.num_style_feat, device=self.constant_input.weight.device)
509
+ latent = self.style_mlp(latent_in).mean(0, keepdim=True)
510
+ return latent
511
+
512
+ def forward(self,
513
+ styles,
514
+ input_is_latent=False,
515
+ noise=None,
516
+ randomize_noise=True,
517
+ truncation=1,
518
+ truncation_latent=None,
519
+ inject_index=None,
520
+ return_latents=False):
521
+ """Forward function for StyleGAN2Generator.
522
+
523
+ Args:
524
+ styles (list[Tensor]): Sample codes of styles.
525
+ input_is_latent (bool): Whether input is latent style.
526
+ Default: False.
527
+ noise (Tensor | None): Input noise or None. Default: None.
528
+ randomize_noise (bool): Randomize noise, used when 'noise' is
529
+ False. Default: True.
530
+ truncation (float): TODO. Default: 1.
531
+ truncation_latent (Tensor | None): TODO. Default: None.
532
+ inject_index (int | None): The injection index for mixing noise.
533
+ Default: None.
534
+ return_latents (bool): Whether to return style latents.
535
+ Default: False.
536
+ """
537
+ # style codes -> latents with Style MLP layer
538
+ if not input_is_latent:
539
+ styles = [self.style_mlp(s) for s in styles]
540
+ # noises
541
+ if noise is None:
542
+ if randomize_noise:
543
+ noise = [None] * self.num_layers # for each style conv layer
544
+ else: # use the stored noise
545
+ noise = [getattr(self.noises, f'noise{i}') for i in range(self.num_layers)]
546
+ # style truncation
547
+ if truncation < 1:
548
+ style_truncation = []
549
+ for style in styles:
550
+ style_truncation.append(truncation_latent + truncation * (style - truncation_latent))
551
+ styles = style_truncation
552
+ # get style latent with injection
553
+ if len(styles) == 1:
554
+ inject_index = self.num_latent
555
+
556
+ if styles[0].ndim < 3:
557
+ # repeat latent code for all the layers
558
+ latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
559
+ else: # used for encoder with different latent code for each layer
560
+ latent = styles[0]
561
+ elif len(styles) == 2: # mixing noises
562
+ if inject_index is None:
563
+ inject_index = random.randint(1, self.num_latent - 1)
564
+ latent1 = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
565
+ latent2 = styles[1].unsqueeze(1).repeat(1, self.num_latent - inject_index, 1)
566
+ latent = torch.cat([latent1, latent2], 1)
567
+
568
+ # main generation
569
+ out = self.constant_input(latent.shape[0])
570
+ out = self.style_conv1(out, latent[:, 0], noise=noise[0])
571
+ skip = self.to_rgb1(out, latent[:, 1])
572
+
573
+ i = 1
574
+ for conv1, conv2, noise1, noise2, to_rgb in zip(self.style_convs[::2], self.style_convs[1::2], noise[1::2],
575
+ noise[2::2], self.to_rgbs):
576
+ out = conv1(out, latent[:, i], noise=noise1)
577
+ out = conv2(out, latent[:, i + 1], noise=noise2)
578
+ skip = to_rgb(out, latent[:, i + 2], skip)
579
+ i += 2
580
+
581
+ image = skip
582
+
583
+ if return_latents:
584
+ return image, latent
585
+ else:
586
+ return image, None
587
+
588
+
589
+ class ScaledLeakyReLU(nn.Module):
590
+ """Scaled LeakyReLU.
591
+
592
+ Args:
593
+ negative_slope (float): Negative slope. Default: 0.2.
594
+ """
595
+
596
+ def __init__(self, negative_slope=0.2):
597
+ super(ScaledLeakyReLU, self).__init__()
598
+ self.negative_slope = negative_slope
599
+
600
+ def forward(self, x):
601
+ out = F.leaky_relu(x, negative_slope=self.negative_slope)
602
+ return out * math.sqrt(2)
603
+
604
+
605
+ class EqualConv2d(nn.Module):
606
+ """Equalized Linear as StyleGAN2.
607
+
608
+ Args:
609
+ in_channels (int): Channel number of the input.
610
+ out_channels (int): Channel number of the output.
611
+ kernel_size (int): Size of the convolving kernel.
612
+ stride (int): Stride of the convolution. Default: 1
613
+ padding (int): Zero-padding added to both sides of the input.
614
+ Default: 0.
615
+ bias (bool): If ``True``, adds a learnable bias to the output.
616
+ Default: ``True``.
617
+ bias_init_val (float): Bias initialized value. Default: 0.
618
+ """
619
+
620
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True, bias_init_val=0):
621
+ super(EqualConv2d, self).__init__()
622
+ self.in_channels = in_channels
623
+ self.out_channels = out_channels
624
+ self.kernel_size = kernel_size
625
+ self.stride = stride
626
+ self.padding = padding
627
+ self.scale = 1 / math.sqrt(in_channels * kernel_size**2)
628
+
629
+ self.weight = nn.Parameter(torch.randn(out_channels, in_channels, kernel_size, kernel_size))
630
+ if bias:
631
+ self.bias = nn.Parameter(torch.zeros(out_channels).fill_(bias_init_val))
632
+ else:
633
+ self.register_parameter('bias', None)
634
+
635
+ def forward(self, x):
636
+ out = F.conv2d(
637
+ x,
638
+ self.weight * self.scale,
639
+ bias=self.bias,
640
+ stride=self.stride,
641
+ padding=self.padding,
642
+ )
643
+
644
+ return out
645
+
646
+ def __repr__(self):
647
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
648
+ f'out_channels={self.out_channels}, '
649
+ f'kernel_size={self.kernel_size},'
650
+ f' stride={self.stride}, padding={self.padding}, '
651
+ f'bias={self.bias is not None})')
652
+
653
+
654
+ class ConvLayer(nn.Sequential):
655
+ """Conv Layer used in StyleGAN2 Discriminator.
656
+
657
+ Args:
658
+ in_channels (int): Channel number of the input.
659
+ out_channels (int): Channel number of the output.
660
+ kernel_size (int): Kernel size.
661
+ downsample (bool): Whether downsample by a factor of 2.
662
+ Default: False.
663
+ resample_kernel (list[int]): A list indicating the 1D resample
664
+ kernel magnitude. A cross production will be applied to
665
+ extent 1D resample kernel to 2D resample kernel.
666
+ Default: (1, 3, 3, 1).
667
+ bias (bool): Whether with bias. Default: True.
668
+ activate (bool): Whether use activateion. Default: True.
669
+ """
670
+
671
+ def __init__(self,
672
+ in_channels,
673
+ out_channels,
674
+ kernel_size,
675
+ downsample=False,
676
+ resample_kernel=(1, 3, 3, 1),
677
+ bias=True,
678
+ activate=True):
679
+ layers = []
680
+ # downsample
681
+ if downsample:
682
+ layers.append(
683
+ UpFirDnSmooth(resample_kernel, upsample_factor=1, downsample_factor=2, kernel_size=kernel_size))
684
+ stride = 2
685
+ self.padding = 0
686
+ else:
687
+ stride = 1
688
+ self.padding = kernel_size // 2
689
+ # conv
690
+ layers.append(
691
+ EqualConv2d(
692
+ in_channels, out_channels, kernel_size, stride=stride, padding=self.padding, bias=bias
693
+ and not activate))
694
+ # activation
695
+ if activate:
696
+ if bias:
697
+ layers.append(FusedLeakyReLU(out_channels))
698
+ else:
699
+ layers.append(ScaledLeakyReLU(0.2))
700
+
701
+ super(ConvLayer, self).__init__(*layers)
702
+
703
+
704
+ class ResBlock(nn.Module):
705
+ """Residual block used in StyleGAN2 Discriminator.
706
+
707
+ Args:
708
+ in_channels (int): Channel number of the input.
709
+ out_channels (int): Channel number of the output.
710
+ resample_kernel (list[int]): A list indicating the 1D resample
711
+ kernel magnitude. A cross production will be applied to
712
+ extent 1D resample kernel to 2D resample kernel.
713
+ Default: (1, 3, 3, 1).
714
+ """
715
+
716
+ def __init__(self, in_channels, out_channels, resample_kernel=(1, 3, 3, 1)):
717
+ super(ResBlock, self).__init__()
718
+
719
+ self.conv1 = ConvLayer(in_channels, in_channels, 3, bias=True, activate=True)
720
+ self.conv2 = ConvLayer(
721
+ in_channels, out_channels, 3, downsample=True, resample_kernel=resample_kernel, bias=True, activate=True)
722
+ self.skip = ConvLayer(
723
+ in_channels, out_channels, 1, downsample=True, resample_kernel=resample_kernel, bias=False, activate=False)
724
+
725
+ def forward(self, x):
726
+ out = self.conv1(x)
727
+ out = self.conv2(out)
728
+ skip = self.skip(x)
729
+ out = (out + skip) / math.sqrt(2)
730
+ return out
731
+
732
+
733
+ @ARCH_REGISTRY.register()
734
+ class StyleGAN2Discriminator(nn.Module):
735
+ """StyleGAN2 Discriminator.
736
+
737
+ Args:
738
+ out_size (int): The spatial size of outputs.
739
+ channel_multiplier (int): Channel multiplier for large networks of
740
+ StyleGAN2. Default: 2.
741
+ resample_kernel (list[int]): A list indicating the 1D resample kernel
742
+ magnitude. A cross production will be applied to extent 1D resample
743
+ kernel to 2D resample kernel. Default: (1, 3, 3, 1).
744
+ stddev_group (int): For group stddev statistics. Default: 4.
745
+ narrow (float): Narrow ratio for channels. Default: 1.0.
746
+ """
747
+
748
+ def __init__(self, out_size, channel_multiplier=2, resample_kernel=(1, 3, 3, 1), stddev_group=4, narrow=1):
749
+ super(StyleGAN2Discriminator, self).__init__()
750
+
751
+ channels = {
752
+ '4': int(512 * narrow),
753
+ '8': int(512 * narrow),
754
+ '16': int(512 * narrow),
755
+ '32': int(512 * narrow),
756
+ '64': int(256 * channel_multiplier * narrow),
757
+ '128': int(128 * channel_multiplier * narrow),
758
+ '256': int(64 * channel_multiplier * narrow),
759
+ '512': int(32 * channel_multiplier * narrow),
760
+ '1024': int(16 * channel_multiplier * narrow)
761
+ }
762
+
763
+ log_size = int(math.log(out_size, 2))
764
+
765
+ conv_body = [ConvLayer(3, channels[f'{out_size}'], 1, bias=True, activate=True)]
766
+
767
+ in_channels = channels[f'{out_size}']
768
+ for i in range(log_size, 2, -1):
769
+ out_channels = channels[f'{2**(i - 1)}']
770
+ conv_body.append(ResBlock(in_channels, out_channels, resample_kernel))
771
+ in_channels = out_channels
772
+ self.conv_body = nn.Sequential(*conv_body)
773
+
774
+ self.final_conv = ConvLayer(in_channels + 1, channels['4'], 3, bias=True, activate=True)
775
+ self.final_linear = nn.Sequential(
776
+ EqualLinear(
777
+ channels['4'] * 4 * 4, channels['4'], bias=True, bias_init_val=0, lr_mul=1, activation='fused_lrelu'),
778
+ EqualLinear(channels['4'], 1, bias=True, bias_init_val=0, lr_mul=1, activation=None),
779
+ )
780
+ self.stddev_group = stddev_group
781
+ self.stddev_feat = 1
782
+
783
+ def forward(self, x):
784
+ out = self.conv_body(x)
785
+
786
+ b, c, h, w = out.shape
787
+ # concatenate a group stddev statistics to out
788
+ group = min(b, self.stddev_group) # Minibatch must be divisible by (or smaller than) group_size
789
+ stddev = out.view(group, -1, self.stddev_feat, c // self.stddev_feat, h, w)
790
+ stddev = torch.sqrt(stddev.var(0, unbiased=False) + 1e-8)
791
+ stddev = stddev.mean([2, 3, 4], keepdims=True).squeeze(2)
792
+ stddev = stddev.repeat(group, 1, h, w)
793
+ out = torch.cat([out, stddev], 1)
794
+
795
+ out = self.final_conv(out)
796
+ out = out.view(b, -1)
797
+ out = self.final_linear(out)
798
+
799
+ return out
basicsr/archs/stylegan2_bilinear_arch.py ADDED
@@ -0,0 +1,614 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import random
3
+ import torch
4
+ from torch import nn
5
+ from torch.nn import functional as F
6
+
7
+ from basicsr.ops.fused_act import FusedLeakyReLU, fused_leaky_relu
8
+ from basicsr.utils.registry import ARCH_REGISTRY
9
+
10
+
11
+ class NormStyleCode(nn.Module):
12
+
13
+ def forward(self, x):
14
+ """Normalize the style codes.
15
+
16
+ Args:
17
+ x (Tensor): Style codes with shape (b, c).
18
+
19
+ Returns:
20
+ Tensor: Normalized tensor.
21
+ """
22
+ return x * torch.rsqrt(torch.mean(x**2, dim=1, keepdim=True) + 1e-8)
23
+
24
+
25
+ class EqualLinear(nn.Module):
26
+ """Equalized Linear as StyleGAN2.
27
+
28
+ Args:
29
+ in_channels (int): Size of each sample.
30
+ out_channels (int): Size of each output sample.
31
+ bias (bool): If set to ``False``, the layer will not learn an additive
32
+ bias. Default: ``True``.
33
+ bias_init_val (float): Bias initialized value. Default: 0.
34
+ lr_mul (float): Learning rate multiplier. Default: 1.
35
+ activation (None | str): The activation after ``linear`` operation.
36
+ Supported: 'fused_lrelu', None. Default: None.
37
+ """
38
+
39
+ def __init__(self, in_channels, out_channels, bias=True, bias_init_val=0, lr_mul=1, activation=None):
40
+ super(EqualLinear, self).__init__()
41
+ self.in_channels = in_channels
42
+ self.out_channels = out_channels
43
+ self.lr_mul = lr_mul
44
+ self.activation = activation
45
+ if self.activation not in ['fused_lrelu', None]:
46
+ raise ValueError(f'Wrong activation value in EqualLinear: {activation}'
47
+ "Supported ones are: ['fused_lrelu', None].")
48
+ self.scale = (1 / math.sqrt(in_channels)) * lr_mul
49
+
50
+ self.weight = nn.Parameter(torch.randn(out_channels, in_channels).div_(lr_mul))
51
+ if bias:
52
+ self.bias = nn.Parameter(torch.zeros(out_channels).fill_(bias_init_val))
53
+ else:
54
+ self.register_parameter('bias', None)
55
+
56
+ def forward(self, x):
57
+ if self.bias is None:
58
+ bias = None
59
+ else:
60
+ bias = self.bias * self.lr_mul
61
+ if self.activation == 'fused_lrelu':
62
+ out = F.linear(x, self.weight * self.scale)
63
+ out = fused_leaky_relu(out, bias)
64
+ else:
65
+ out = F.linear(x, self.weight * self.scale, bias=bias)
66
+ return out
67
+
68
+ def __repr__(self):
69
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
70
+ f'out_channels={self.out_channels}, bias={self.bias is not None})')
71
+
72
+
73
+ class ModulatedConv2d(nn.Module):
74
+ """Modulated Conv2d used in StyleGAN2.
75
+
76
+ There is no bias in ModulatedConv2d.
77
+
78
+ Args:
79
+ in_channels (int): Channel number of the input.
80
+ out_channels (int): Channel number of the output.
81
+ kernel_size (int): Size of the convolving kernel.
82
+ num_style_feat (int): Channel number of style features.
83
+ demodulate (bool): Whether to demodulate in the conv layer.
84
+ Default: True.
85
+ sample_mode (str | None): Indicating 'upsample', 'downsample' or None.
86
+ Default: None.
87
+ eps (float): A value added to the denominator for numerical stability.
88
+ Default: 1e-8.
89
+ """
90
+
91
+ def __init__(self,
92
+ in_channels,
93
+ out_channels,
94
+ kernel_size,
95
+ num_style_feat,
96
+ demodulate=True,
97
+ sample_mode=None,
98
+ eps=1e-8,
99
+ interpolation_mode='bilinear'):
100
+ super(ModulatedConv2d, self).__init__()
101
+ self.in_channels = in_channels
102
+ self.out_channels = out_channels
103
+ self.kernel_size = kernel_size
104
+ self.demodulate = demodulate
105
+ self.sample_mode = sample_mode
106
+ self.eps = eps
107
+ self.interpolation_mode = interpolation_mode
108
+ if self.interpolation_mode == 'nearest':
109
+ self.align_corners = None
110
+ else:
111
+ self.align_corners = False
112
+
113
+ self.scale = 1 / math.sqrt(in_channels * kernel_size**2)
114
+ # modulation inside each modulated conv
115
+ self.modulation = EqualLinear(
116
+ num_style_feat, in_channels, bias=True, bias_init_val=1, lr_mul=1, activation=None)
117
+
118
+ self.weight = nn.Parameter(torch.randn(1, out_channels, in_channels, kernel_size, kernel_size))
119
+ self.padding = kernel_size // 2
120
+
121
+ def forward(self, x, style):
122
+ """Forward function.
123
+
124
+ Args:
125
+ x (Tensor): Tensor with shape (b, c, h, w).
126
+ style (Tensor): Tensor with shape (b, num_style_feat).
127
+
128
+ Returns:
129
+ Tensor: Modulated tensor after convolution.
130
+ """
131
+ b, c, h, w = x.shape # c = c_in
132
+ # weight modulation
133
+ style = self.modulation(style).view(b, 1, c, 1, 1)
134
+ # self.weight: (1, c_out, c_in, k, k); style: (b, 1, c, 1, 1)
135
+ weight = self.scale * self.weight * style # (b, c_out, c_in, k, k)
136
+
137
+ if self.demodulate:
138
+ demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps)
139
+ weight = weight * demod.view(b, self.out_channels, 1, 1, 1)
140
+
141
+ weight = weight.view(b * self.out_channels, c, self.kernel_size, self.kernel_size)
142
+
143
+ if self.sample_mode == 'upsample':
144
+ x = F.interpolate(x, scale_factor=2, mode=self.interpolation_mode, align_corners=self.align_corners)
145
+ elif self.sample_mode == 'downsample':
146
+ x = F.interpolate(x, scale_factor=0.5, mode=self.interpolation_mode, align_corners=self.align_corners)
147
+
148
+ b, c, h, w = x.shape
149
+ x = x.view(1, b * c, h, w)
150
+ # weight: (b*c_out, c_in, k, k), groups=b
151
+ out = F.conv2d(x, weight, padding=self.padding, groups=b)
152
+ out = out.view(b, self.out_channels, *out.shape[2:4])
153
+
154
+ return out
155
+
156
+ def __repr__(self):
157
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
158
+ f'out_channels={self.out_channels}, '
159
+ f'kernel_size={self.kernel_size}, '
160
+ f'demodulate={self.demodulate}, sample_mode={self.sample_mode})')
161
+
162
+
163
+ class StyleConv(nn.Module):
164
+ """Style conv.
165
+
166
+ Args:
167
+ in_channels (int): Channel number of the input.
168
+ out_channels (int): Channel number of the output.
169
+ kernel_size (int): Size of the convolving kernel.
170
+ num_style_feat (int): Channel number of style features.
171
+ demodulate (bool): Whether demodulate in the conv layer. Default: True.
172
+ sample_mode (str | None): Indicating 'upsample', 'downsample' or None.
173
+ Default: None.
174
+ """
175
+
176
+ def __init__(self,
177
+ in_channels,
178
+ out_channels,
179
+ kernel_size,
180
+ num_style_feat,
181
+ demodulate=True,
182
+ sample_mode=None,
183
+ interpolation_mode='bilinear'):
184
+ super(StyleConv, self).__init__()
185
+ self.modulated_conv = ModulatedConv2d(
186
+ in_channels,
187
+ out_channels,
188
+ kernel_size,
189
+ num_style_feat,
190
+ demodulate=demodulate,
191
+ sample_mode=sample_mode,
192
+ interpolation_mode=interpolation_mode)
193
+ self.weight = nn.Parameter(torch.zeros(1)) # for noise injection
194
+ self.activate = FusedLeakyReLU(out_channels)
195
+
196
+ def forward(self, x, style, noise=None):
197
+ # modulate
198
+ out = self.modulated_conv(x, style)
199
+ # noise injection
200
+ if noise is None:
201
+ b, _, h, w = out.shape
202
+ noise = out.new_empty(b, 1, h, w).normal_()
203
+ out = out + self.weight * noise
204
+ # activation (with bias)
205
+ out = self.activate(out)
206
+ return out
207
+
208
+
209
+ class ToRGB(nn.Module):
210
+ """To RGB from features.
211
+
212
+ Args:
213
+ in_channels (int): Channel number of input.
214
+ num_style_feat (int): Channel number of style features.
215
+ upsample (bool): Whether to upsample. Default: True.
216
+ """
217
+
218
+ def __init__(self, in_channels, num_style_feat, upsample=True, interpolation_mode='bilinear'):
219
+ super(ToRGB, self).__init__()
220
+ self.upsample = upsample
221
+ self.interpolation_mode = interpolation_mode
222
+ if self.interpolation_mode == 'nearest':
223
+ self.align_corners = None
224
+ else:
225
+ self.align_corners = False
226
+ self.modulated_conv = ModulatedConv2d(
227
+ in_channels,
228
+ 3,
229
+ kernel_size=1,
230
+ num_style_feat=num_style_feat,
231
+ demodulate=False,
232
+ sample_mode=None,
233
+ interpolation_mode=interpolation_mode)
234
+ self.bias = nn.Parameter(torch.zeros(1, 3, 1, 1))
235
+
236
+ def forward(self, x, style, skip=None):
237
+ """Forward function.
238
+
239
+ Args:
240
+ x (Tensor): Feature tensor with shape (b, c, h, w).
241
+ style (Tensor): Tensor with shape (b, num_style_feat).
242
+ skip (Tensor): Base/skip tensor. Default: None.
243
+
244
+ Returns:
245
+ Tensor: RGB images.
246
+ """
247
+ out = self.modulated_conv(x, style)
248
+ out = out + self.bias
249
+ if skip is not None:
250
+ if self.upsample:
251
+ skip = F.interpolate(
252
+ skip, scale_factor=2, mode=self.interpolation_mode, align_corners=self.align_corners)
253
+ out = out + skip
254
+ return out
255
+
256
+
257
+ class ConstantInput(nn.Module):
258
+ """Constant input.
259
+
260
+ Args:
261
+ num_channel (int): Channel number of constant input.
262
+ size (int): Spatial size of constant input.
263
+ """
264
+
265
+ def __init__(self, num_channel, size):
266
+ super(ConstantInput, self).__init__()
267
+ self.weight = nn.Parameter(torch.randn(1, num_channel, size, size))
268
+
269
+ def forward(self, batch):
270
+ out = self.weight.repeat(batch, 1, 1, 1)
271
+ return out
272
+
273
+
274
+ @ARCH_REGISTRY.register(suffix='basicsr')
275
+ class StyleGAN2GeneratorBilinear(nn.Module):
276
+ """StyleGAN2 Generator.
277
+
278
+ Args:
279
+ out_size (int): The spatial size of outputs.
280
+ num_style_feat (int): Channel number of style features. Default: 512.
281
+ num_mlp (int): Layer number of MLP style layers. Default: 8.
282
+ channel_multiplier (int): Channel multiplier for large networks of
283
+ StyleGAN2. Default: 2.
284
+ lr_mlp (float): Learning rate multiplier for mlp layers. Default: 0.01.
285
+ narrow (float): Narrow ratio for channels. Default: 1.0.
286
+ """
287
+
288
+ def __init__(self,
289
+ out_size,
290
+ num_style_feat=512,
291
+ num_mlp=8,
292
+ channel_multiplier=2,
293
+ lr_mlp=0.01,
294
+ narrow=1,
295
+ interpolation_mode='bilinear'):
296
+ super(StyleGAN2GeneratorBilinear, self).__init__()
297
+ # Style MLP layers
298
+ self.num_style_feat = num_style_feat
299
+ style_mlp_layers = [NormStyleCode()]
300
+ for i in range(num_mlp):
301
+ style_mlp_layers.append(
302
+ EqualLinear(
303
+ num_style_feat, num_style_feat, bias=True, bias_init_val=0, lr_mul=lr_mlp,
304
+ activation='fused_lrelu'))
305
+ self.style_mlp = nn.Sequential(*style_mlp_layers)
306
+
307
+ channels = {
308
+ '4': int(512 * narrow),
309
+ '8': int(512 * narrow),
310
+ '16': int(512 * narrow),
311
+ '32': int(512 * narrow),
312
+ '64': int(256 * channel_multiplier * narrow),
313
+ '128': int(128 * channel_multiplier * narrow),
314
+ '256': int(64 * channel_multiplier * narrow),
315
+ '512': int(32 * channel_multiplier * narrow),
316
+ '1024': int(16 * channel_multiplier * narrow)
317
+ }
318
+ self.channels = channels
319
+
320
+ self.constant_input = ConstantInput(channels['4'], size=4)
321
+ self.style_conv1 = StyleConv(
322
+ channels['4'],
323
+ channels['4'],
324
+ kernel_size=3,
325
+ num_style_feat=num_style_feat,
326
+ demodulate=True,
327
+ sample_mode=None,
328
+ interpolation_mode=interpolation_mode)
329
+ self.to_rgb1 = ToRGB(channels['4'], num_style_feat, upsample=False, interpolation_mode=interpolation_mode)
330
+
331
+ self.log_size = int(math.log(out_size, 2))
332
+ self.num_layers = (self.log_size - 2) * 2 + 1
333
+ self.num_latent = self.log_size * 2 - 2
334
+
335
+ self.style_convs = nn.ModuleList()
336
+ self.to_rgbs = nn.ModuleList()
337
+ self.noises = nn.Module()
338
+
339
+ in_channels = channels['4']
340
+ # noise
341
+ for layer_idx in range(self.num_layers):
342
+ resolution = 2**((layer_idx + 5) // 2)
343
+ shape = [1, 1, resolution, resolution]
344
+ self.noises.register_buffer(f'noise{layer_idx}', torch.randn(*shape))
345
+ # style convs and to_rgbs
346
+ for i in range(3, self.log_size + 1):
347
+ out_channels = channels[f'{2**i}']
348
+ self.style_convs.append(
349
+ StyleConv(
350
+ in_channels,
351
+ out_channels,
352
+ kernel_size=3,
353
+ num_style_feat=num_style_feat,
354
+ demodulate=True,
355
+ sample_mode='upsample',
356
+ interpolation_mode=interpolation_mode))
357
+ self.style_convs.append(
358
+ StyleConv(
359
+ out_channels,
360
+ out_channels,
361
+ kernel_size=3,
362
+ num_style_feat=num_style_feat,
363
+ demodulate=True,
364
+ sample_mode=None,
365
+ interpolation_mode=interpolation_mode))
366
+ self.to_rgbs.append(
367
+ ToRGB(out_channels, num_style_feat, upsample=True, interpolation_mode=interpolation_mode))
368
+ in_channels = out_channels
369
+
370
+ def make_noise(self):
371
+ """Make noise for noise injection."""
372
+ device = self.constant_input.weight.device
373
+ noises = [torch.randn(1, 1, 4, 4, device=device)]
374
+
375
+ for i in range(3, self.log_size + 1):
376
+ for _ in range(2):
377
+ noises.append(torch.randn(1, 1, 2**i, 2**i, device=device))
378
+
379
+ return noises
380
+
381
+ def get_latent(self, x):
382
+ return self.style_mlp(x)
383
+
384
+ def mean_latent(self, num_latent):
385
+ latent_in = torch.randn(num_latent, self.num_style_feat, device=self.constant_input.weight.device)
386
+ latent = self.style_mlp(latent_in).mean(0, keepdim=True)
387
+ return latent
388
+
389
+ def forward(self,
390
+ styles,
391
+ input_is_latent=False,
392
+ noise=None,
393
+ randomize_noise=True,
394
+ truncation=1,
395
+ truncation_latent=None,
396
+ inject_index=None,
397
+ return_latents=False):
398
+ """Forward function for StyleGAN2Generator.
399
+
400
+ Args:
401
+ styles (list[Tensor]): Sample codes of styles.
402
+ input_is_latent (bool): Whether input is latent style.
403
+ Default: False.
404
+ noise (Tensor | None): Input noise or None. Default: None.
405
+ randomize_noise (bool): Randomize noise, used when 'noise' is
406
+ False. Default: True.
407
+ truncation (float): TODO. Default: 1.
408
+ truncation_latent (Tensor | None): TODO. Default: None.
409
+ inject_index (int | None): The injection index for mixing noise.
410
+ Default: None.
411
+ return_latents (bool): Whether to return style latents.
412
+ Default: False.
413
+ """
414
+ # style codes -> latents with Style MLP layer
415
+ if not input_is_latent:
416
+ styles = [self.style_mlp(s) for s in styles]
417
+ # noises
418
+ if noise is None:
419
+ if randomize_noise:
420
+ noise = [None] * self.num_layers # for each style conv layer
421
+ else: # use the stored noise
422
+ noise = [getattr(self.noises, f'noise{i}') for i in range(self.num_layers)]
423
+ # style truncation
424
+ if truncation < 1:
425
+ style_truncation = []
426
+ for style in styles:
427
+ style_truncation.append(truncation_latent + truncation * (style - truncation_latent))
428
+ styles = style_truncation
429
+ # get style latent with injection
430
+ if len(styles) == 1:
431
+ inject_index = self.num_latent
432
+
433
+ if styles[0].ndim < 3:
434
+ # repeat latent code for all the layers
435
+ latent = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
436
+ else: # used for encoder with different latent code for each layer
437
+ latent = styles[0]
438
+ elif len(styles) == 2: # mixing noises
439
+ if inject_index is None:
440
+ inject_index = random.randint(1, self.num_latent - 1)
441
+ latent1 = styles[0].unsqueeze(1).repeat(1, inject_index, 1)
442
+ latent2 = styles[1].unsqueeze(1).repeat(1, self.num_latent - inject_index, 1)
443
+ latent = torch.cat([latent1, latent2], 1)
444
+
445
+ # main generation
446
+ out = self.constant_input(latent.shape[0])
447
+ out = self.style_conv1(out, latent[:, 0], noise=noise[0])
448
+ skip = self.to_rgb1(out, latent[:, 1])
449
+
450
+ i = 1
451
+ for conv1, conv2, noise1, noise2, to_rgb in zip(self.style_convs[::2], self.style_convs[1::2], noise[1::2],
452
+ noise[2::2], self.to_rgbs):
453
+ out = conv1(out, latent[:, i], noise=noise1)
454
+ out = conv2(out, latent[:, i + 1], noise=noise2)
455
+ skip = to_rgb(out, latent[:, i + 2], skip)
456
+ i += 2
457
+
458
+ image = skip
459
+
460
+ if return_latents:
461
+ return image, latent
462
+ else:
463
+ return image, None
464
+
465
+
466
+ class ScaledLeakyReLU(nn.Module):
467
+ """Scaled LeakyReLU.
468
+
469
+ Args:
470
+ negative_slope (float): Negative slope. Default: 0.2.
471
+ """
472
+
473
+ def __init__(self, negative_slope=0.2):
474
+ super(ScaledLeakyReLU, self).__init__()
475
+ self.negative_slope = negative_slope
476
+
477
+ def forward(self, x):
478
+ out = F.leaky_relu(x, negative_slope=self.negative_slope)
479
+ return out * math.sqrt(2)
480
+
481
+
482
+ class EqualConv2d(nn.Module):
483
+ """Equalized Linear as StyleGAN2.
484
+
485
+ Args:
486
+ in_channels (int): Channel number of the input.
487
+ out_channels (int): Channel number of the output.
488
+ kernel_size (int): Size of the convolving kernel.
489
+ stride (int): Stride of the convolution. Default: 1
490
+ padding (int): Zero-padding added to both sides of the input.
491
+ Default: 0.
492
+ bias (bool): If ``True``, adds a learnable bias to the output.
493
+ Default: ``True``.
494
+ bias_init_val (float): Bias initialized value. Default: 0.
495
+ """
496
+
497
+ def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, bias=True, bias_init_val=0):
498
+ super(EqualConv2d, self).__init__()
499
+ self.in_channels = in_channels
500
+ self.out_channels = out_channels
501
+ self.kernel_size = kernel_size
502
+ self.stride = stride
503
+ self.padding = padding
504
+ self.scale = 1 / math.sqrt(in_channels * kernel_size**2)
505
+
506
+ self.weight = nn.Parameter(torch.randn(out_channels, in_channels, kernel_size, kernel_size))
507
+ if bias:
508
+ self.bias = nn.Parameter(torch.zeros(out_channels).fill_(bias_init_val))
509
+ else:
510
+ self.register_parameter('bias', None)
511
+
512
+ def forward(self, x):
513
+ out = F.conv2d(
514
+ x,
515
+ self.weight * self.scale,
516
+ bias=self.bias,
517
+ stride=self.stride,
518
+ padding=self.padding,
519
+ )
520
+
521
+ return out
522
+
523
+ def __repr__(self):
524
+ return (f'{self.__class__.__name__}(in_channels={self.in_channels}, '
525
+ f'out_channels={self.out_channels}, '
526
+ f'kernel_size={self.kernel_size},'
527
+ f' stride={self.stride}, padding={self.padding}, '
528
+ f'bias={self.bias is not None})')
529
+
530
+
531
+ class ConvLayer(nn.Sequential):
532
+ """Conv Layer used in StyleGAN2 Discriminator.
533
+
534
+ Args:
535
+ in_channels (int): Channel number of the input.
536
+ out_channels (int): Channel number of the output.
537
+ kernel_size (int): Kernel size.
538
+ downsample (bool): Whether downsample by a factor of 2.
539
+ Default: False.
540
+ bias (bool): Whether with bias. Default: True.
541
+ activate (bool): Whether use activateion. Default: True.
542
+ """
543
+
544
+ def __init__(self,
545
+ in_channels,
546
+ out_channels,
547
+ kernel_size,
548
+ downsample=False,
549
+ bias=True,
550
+ activate=True,
551
+ interpolation_mode='bilinear'):
552
+ layers = []
553
+ self.interpolation_mode = interpolation_mode
554
+ # downsample
555
+ if downsample:
556
+ if self.interpolation_mode == 'nearest':
557
+ self.align_corners = None
558
+ else:
559
+ self.align_corners = False
560
+
561
+ layers.append(
562
+ torch.nn.Upsample(scale_factor=0.5, mode=interpolation_mode, align_corners=self.align_corners))
563
+ stride = 1
564
+ self.padding = kernel_size // 2
565
+ # conv
566
+ layers.append(
567
+ EqualConv2d(
568
+ in_channels, out_channels, kernel_size, stride=stride, padding=self.padding, bias=bias
569
+ and not activate))
570
+ # activation
571
+ if activate:
572
+ if bias:
573
+ layers.append(FusedLeakyReLU(out_channels))
574
+ else:
575
+ layers.append(ScaledLeakyReLU(0.2))
576
+
577
+ super(ConvLayer, self).__init__(*layers)
578
+
579
+
580
+ class ResBlock(nn.Module):
581
+ """Residual block used in StyleGAN2 Discriminator.
582
+
583
+ Args:
584
+ in_channels (int): Channel number of the input.
585
+ out_channels (int): Channel number of the output.
586
+ """
587
+
588
+ def __init__(self, in_channels, out_channels, interpolation_mode='bilinear'):
589
+ super(ResBlock, self).__init__()
590
+
591
+ self.conv1 = ConvLayer(in_channels, in_channels, 3, bias=True, activate=True)
592
+ self.conv2 = ConvLayer(
593
+ in_channels,
594
+ out_channels,
595
+ 3,
596
+ downsample=True,
597
+ interpolation_mode=interpolation_mode,
598
+ bias=True,
599
+ activate=True)
600
+ self.skip = ConvLayer(
601
+ in_channels,
602
+ out_channels,
603
+ 1,
604
+ downsample=True,
605
+ interpolation_mode=interpolation_mode,
606
+ bias=False,
607
+ activate=False)
608
+
609
+ def forward(self, x):
610
+ out = self.conv1(x)
611
+ out = self.conv2(out)
612
+ skip = self.skip(x)
613
+ out = (out + skip) / math.sqrt(2)
614
+ return out
basicsr/archs/swinir_arch.py ADDED
@@ -0,0 +1,956 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Modified from https://github.com/JingyunLiang/SwinIR
2
+ # SwinIR: Image Restoration Using Swin Transformer, https://arxiv.org/abs/2108.10257
3
+ # Originally Written by Ze Liu, Modified by Jingyun Liang.
4
+
5
+ import math
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.utils.checkpoint as checkpoint
9
+
10
+ from basicsr.utils.registry import ARCH_REGISTRY
11
+ from .arch_util import to_2tuple, trunc_normal_
12
+
13
+
14
+ def drop_path(x, drop_prob: float = 0., training: bool = False):
15
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
16
+
17
+ From: https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/drop.py
18
+ """
19
+ if drop_prob == 0. or not training:
20
+ return x
21
+ keep_prob = 1 - drop_prob
22
+ shape = (x.shape[0], ) + (1, ) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
23
+ random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
24
+ random_tensor.floor_() # binarize
25
+ output = x.div(keep_prob) * random_tensor
26
+ return output
27
+
28
+
29
+ class DropPath(nn.Module):
30
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
31
+
32
+ From: https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/drop.py
33
+ """
34
+
35
+ def __init__(self, drop_prob=None):
36
+ super(DropPath, self).__init__()
37
+ self.drop_prob = drop_prob
38
+
39
+ def forward(self, x):
40
+ return drop_path(x, self.drop_prob, self.training)
41
+
42
+
43
+ class Mlp(nn.Module):
44
+
45
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
46
+ super().__init__()
47
+ out_features = out_features or in_features
48
+ hidden_features = hidden_features or in_features
49
+ self.fc1 = nn.Linear(in_features, hidden_features)
50
+ self.act = act_layer()
51
+ self.fc2 = nn.Linear(hidden_features, out_features)
52
+ self.drop = nn.Dropout(drop)
53
+
54
+ def forward(self, x):
55
+ x = self.fc1(x)
56
+ x = self.act(x)
57
+ x = self.drop(x)
58
+ x = self.fc2(x)
59
+ x = self.drop(x)
60
+ return x
61
+
62
+
63
+ def window_partition(x, window_size):
64
+ """
65
+ Args:
66
+ x: (b, h, w, c)
67
+ window_size (int): window size
68
+
69
+ Returns:
70
+ windows: (num_windows*b, window_size, window_size, c)
71
+ """
72
+ b, h, w, c = x.shape
73
+ x = x.view(b, h // window_size, window_size, w // window_size, window_size, c)
74
+ windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, c)
75
+ return windows
76
+
77
+
78
+ def window_reverse(windows, window_size, h, w):
79
+ """
80
+ Args:
81
+ windows: (num_windows*b, window_size, window_size, c)
82
+ window_size (int): Window size
83
+ h (int): Height of image
84
+ w (int): Width of image
85
+
86
+ Returns:
87
+ x: (b, h, w, c)
88
+ """
89
+ b = int(windows.shape[0] / (h * w / window_size / window_size))
90
+ x = windows.view(b, h // window_size, w // window_size, window_size, window_size, -1)
91
+ x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(b, h, w, -1)
92
+ return x
93
+
94
+
95
+ class WindowAttention(nn.Module):
96
+ r""" Window based multi-head self attention (W-MSA) module with relative position bias.
97
+ It supports both of shifted and non-shifted window.
98
+
99
+ Args:
100
+ dim (int): Number of input channels.
101
+ window_size (tuple[int]): The height and width of the window.
102
+ num_heads (int): Number of attention heads.
103
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
104
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set
105
+ attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0
106
+ proj_drop (float, optional): Dropout ratio of output. Default: 0.0
107
+ """
108
+
109
+ def __init__(self, dim, window_size, num_heads, qkv_bias=True, qk_scale=None, attn_drop=0., proj_drop=0.):
110
+
111
+ super().__init__()
112
+ self.dim = dim
113
+ self.window_size = window_size # Wh, Ww
114
+ self.num_heads = num_heads
115
+ head_dim = dim // num_heads
116
+ self.scale = qk_scale or head_dim**-0.5
117
+
118
+ # define a parameter table of relative position bias
119
+ self.relative_position_bias_table = nn.Parameter(
120
+ torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)) # 2*Wh-1 * 2*Ww-1, nH
121
+
122
+ # get pair-wise relative position index for each token inside the window
123
+ coords_h = torch.arange(self.window_size[0])
124
+ coords_w = torch.arange(self.window_size[1])
125
+ coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww
126
+ coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww
127
+ relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww
128
+ relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2
129
+ relative_coords[:, :, 0] += self.window_size[0] - 1 # shift to start from 0
130
+ relative_coords[:, :, 1] += self.window_size[1] - 1
131
+ relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1
132
+ relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww
133
+ self.register_buffer('relative_position_index', relative_position_index)
134
+
135
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
136
+ self.attn_drop = nn.Dropout(attn_drop)
137
+ self.proj = nn.Linear(dim, dim)
138
+
139
+ self.proj_drop = nn.Dropout(proj_drop)
140
+
141
+ trunc_normal_(self.relative_position_bias_table, std=.02)
142
+ self.softmax = nn.Softmax(dim=-1)
143
+
144
+ def forward(self, x, mask=None):
145
+ """
146
+ Args:
147
+ x: input features with shape of (num_windows*b, n, c)
148
+ mask: (0/-inf) mask with shape of (num_windows, Wh*Ww, Wh*Ww) or None
149
+ """
150
+ b_, n, c = x.shape
151
+ qkv = self.qkv(x).reshape(b_, n, 3, self.num_heads, c // self.num_heads).permute(2, 0, 3, 1, 4)
152
+ q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
153
+
154
+ q = q * self.scale
155
+ attn = (q @ k.transpose(-2, -1))
156
+
157
+ relative_position_bias = self.relative_position_bias_table[self.relative_position_index.view(-1)].view(
158
+ self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1) # Wh*Ww,Wh*Ww,nH
159
+ relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww
160
+ attn = attn + relative_position_bias.unsqueeze(0)
161
+
162
+ if mask is not None:
163
+ nw = mask.shape[0]
164
+ attn = attn.view(b_ // nw, nw, self.num_heads, n, n) + mask.unsqueeze(1).unsqueeze(0)
165
+ attn = attn.view(-1, self.num_heads, n, n)
166
+ attn = self.softmax(attn)
167
+ else:
168
+ attn = self.softmax(attn)
169
+
170
+ attn = self.attn_drop(attn)
171
+
172
+ x = (attn @ v).transpose(1, 2).reshape(b_, n, c)
173
+ x = self.proj(x)
174
+ x = self.proj_drop(x)
175
+ return x
176
+
177
+ def extra_repr(self) -> str:
178
+ return f'dim={self.dim}, window_size={self.window_size}, num_heads={self.num_heads}'
179
+
180
+ def flops(self, n):
181
+ # calculate flops for 1 window with token length of n
182
+ flops = 0
183
+ # qkv = self.qkv(x)
184
+ flops += n * self.dim * 3 * self.dim
185
+ # attn = (q @ k.transpose(-2, -1))
186
+ flops += self.num_heads * n * (self.dim // self.num_heads) * n
187
+ # x = (attn @ v)
188
+ flops += self.num_heads * n * n * (self.dim // self.num_heads)
189
+ # x = self.proj(x)
190
+ flops += n * self.dim * self.dim
191
+ return flops
192
+
193
+
194
+ class SwinTransformerBlock(nn.Module):
195
+ r""" Swin Transformer Block.
196
+
197
+ Args:
198
+ dim (int): Number of input channels.
199
+ input_resolution (tuple[int]): Input resolution.
200
+ num_heads (int): Number of attention heads.
201
+ window_size (int): Window size.
202
+ shift_size (int): Shift size for SW-MSA.
203
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim.
204
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
205
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set.
206
+ drop (float, optional): Dropout rate. Default: 0.0
207
+ attn_drop (float, optional): Attention dropout rate. Default: 0.0
208
+ drop_path (float, optional): Stochastic depth rate. Default: 0.0
209
+ act_layer (nn.Module, optional): Activation layer. Default: nn.GELU
210
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
211
+ """
212
+
213
+ def __init__(self,
214
+ dim,
215
+ input_resolution,
216
+ num_heads,
217
+ window_size=7,
218
+ shift_size=0,
219
+ mlp_ratio=4.,
220
+ qkv_bias=True,
221
+ qk_scale=None,
222
+ drop=0.,
223
+ attn_drop=0.,
224
+ drop_path=0.,
225
+ act_layer=nn.GELU,
226
+ norm_layer=nn.LayerNorm):
227
+ super().__init__()
228
+ self.dim = dim
229
+ self.input_resolution = input_resolution
230
+ self.num_heads = num_heads
231
+ self.window_size = window_size
232
+ self.shift_size = shift_size
233
+ self.mlp_ratio = mlp_ratio
234
+ if min(self.input_resolution) <= self.window_size:
235
+ # if window size is larger than input resolution, we don't partition windows
236
+ self.shift_size = 0
237
+ self.window_size = min(self.input_resolution)
238
+ assert 0 <= self.shift_size < self.window_size, 'shift_size must in 0-window_size'
239
+
240
+ self.norm1 = norm_layer(dim)
241
+ self.attn = WindowAttention(
242
+ dim,
243
+ window_size=to_2tuple(self.window_size),
244
+ num_heads=num_heads,
245
+ qkv_bias=qkv_bias,
246
+ qk_scale=qk_scale,
247
+ attn_drop=attn_drop,
248
+ proj_drop=drop)
249
+
250
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
251
+ self.norm2 = norm_layer(dim)
252
+ mlp_hidden_dim = int(dim * mlp_ratio)
253
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
254
+
255
+ if self.shift_size > 0:
256
+ attn_mask = self.calculate_mask(self.input_resolution)
257
+ else:
258
+ attn_mask = None
259
+
260
+ self.register_buffer('attn_mask', attn_mask)
261
+
262
+ def calculate_mask(self, x_size):
263
+ # calculate attention mask for SW-MSA
264
+ h, w = x_size
265
+ img_mask = torch.zeros((1, h, w, 1)) # 1 h w 1
266
+ h_slices = (slice(0, -self.window_size), slice(-self.window_size,
267
+ -self.shift_size), slice(-self.shift_size, None))
268
+ w_slices = (slice(0, -self.window_size), slice(-self.window_size,
269
+ -self.shift_size), slice(-self.shift_size, None))
270
+ cnt = 0
271
+ for h in h_slices:
272
+ for w in w_slices:
273
+ img_mask[:, h, w, :] = cnt
274
+ cnt += 1
275
+
276
+ mask_windows = window_partition(img_mask, self.window_size) # nw, window_size, window_size, 1
277
+ mask_windows = mask_windows.view(-1, self.window_size * self.window_size)
278
+ attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2)
279
+ attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill(attn_mask == 0, float(0.0))
280
+
281
+ return attn_mask
282
+
283
+ def forward(self, x, x_size):
284
+ h, w = x_size
285
+ b, _, c = x.shape
286
+ # assert seq_len == h * w, "input feature has wrong size"
287
+
288
+ shortcut = x
289
+ x = self.norm1(x)
290
+ x = x.view(b, h, w, c)
291
+
292
+ # cyclic shift
293
+ if self.shift_size > 0:
294
+ shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2))
295
+ else:
296
+ shifted_x = x
297
+
298
+ # partition windows
299
+ x_windows = window_partition(shifted_x, self.window_size) # nw*b, window_size, window_size, c
300
+ x_windows = x_windows.view(-1, self.window_size * self.window_size, c) # nw*b, window_size*window_size, c
301
+
302
+ # W-MSA/SW-MSA (to be compatible for testing on images whose shapes are the multiple of window size
303
+ if self.input_resolution == x_size:
304
+ attn_windows = self.attn(x_windows, mask=self.attn_mask) # nw*b, window_size*window_size, c
305
+ else:
306
+ attn_windows = self.attn(x_windows, mask=self.calculate_mask(x_size).to(x.device))
307
+
308
+ # merge windows
309
+ attn_windows = attn_windows.view(-1, self.window_size, self.window_size, c)
310
+ shifted_x = window_reverse(attn_windows, self.window_size, h, w) # b h' w' c
311
+
312
+ # reverse cyclic shift
313
+ if self.shift_size > 0:
314
+ x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2))
315
+ else:
316
+ x = shifted_x
317
+ x = x.view(b, h * w, c)
318
+
319
+ # FFN
320
+ x = shortcut + self.drop_path(x)
321
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
322
+
323
+ return x
324
+
325
+ def extra_repr(self) -> str:
326
+ return (f'dim={self.dim}, input_resolution={self.input_resolution}, num_heads={self.num_heads}, '
327
+ f'window_size={self.window_size}, shift_size={self.shift_size}, mlp_ratio={self.mlp_ratio}')
328
+
329
+ def flops(self):
330
+ flops = 0
331
+ h, w = self.input_resolution
332
+ # norm1
333
+ flops += self.dim * h * w
334
+ # W-MSA/SW-MSA
335
+ nw = h * w / self.window_size / self.window_size
336
+ flops += nw * self.attn.flops(self.window_size * self.window_size)
337
+ # mlp
338
+ flops += 2 * h * w * self.dim * self.dim * self.mlp_ratio
339
+ # norm2
340
+ flops += self.dim * h * w
341
+ return flops
342
+
343
+
344
+ class PatchMerging(nn.Module):
345
+ r""" Patch Merging Layer.
346
+
347
+ Args:
348
+ input_resolution (tuple[int]): Resolution of input feature.
349
+ dim (int): Number of input channels.
350
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
351
+ """
352
+
353
+ def __init__(self, input_resolution, dim, norm_layer=nn.LayerNorm):
354
+ super().__init__()
355
+ self.input_resolution = input_resolution
356
+ self.dim = dim
357
+ self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False)
358
+ self.norm = norm_layer(4 * dim)
359
+
360
+ def forward(self, x):
361
+ """
362
+ x: b, h*w, c
363
+ """
364
+ h, w = self.input_resolution
365
+ b, seq_len, c = x.shape
366
+ assert seq_len == h * w, 'input feature has wrong size'
367
+ assert h % 2 == 0 and w % 2 == 0, f'x size ({h}*{w}) are not even.'
368
+
369
+ x = x.view(b, h, w, c)
370
+
371
+ x0 = x[:, 0::2, 0::2, :] # b h/2 w/2 c
372
+ x1 = x[:, 1::2, 0::2, :] # b h/2 w/2 c
373
+ x2 = x[:, 0::2, 1::2, :] # b h/2 w/2 c
374
+ x3 = x[:, 1::2, 1::2, :] # b h/2 w/2 c
375
+ x = torch.cat([x0, x1, x2, x3], -1) # b h/2 w/2 4*c
376
+ x = x.view(b, -1, 4 * c) # b h/2*w/2 4*c
377
+
378
+ x = self.norm(x)
379
+ x = self.reduction(x)
380
+
381
+ return x
382
+
383
+ def extra_repr(self) -> str:
384
+ return f'input_resolution={self.input_resolution}, dim={self.dim}'
385
+
386
+ def flops(self):
387
+ h, w = self.input_resolution
388
+ flops = h * w * self.dim
389
+ flops += (h // 2) * (w // 2) * 4 * self.dim * 2 * self.dim
390
+ return flops
391
+
392
+
393
+ class BasicLayer(nn.Module):
394
+ """ A basic Swin Transformer layer for one stage.
395
+
396
+ Args:
397
+ dim (int): Number of input channels.
398
+ input_resolution (tuple[int]): Input resolution.
399
+ depth (int): Number of blocks.
400
+ num_heads (int): Number of attention heads.
401
+ window_size (int): Local window size.
402
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim.
403
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
404
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set.
405
+ drop (float, optional): Dropout rate. Default: 0.0
406
+ attn_drop (float, optional): Attention dropout rate. Default: 0.0
407
+ drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0
408
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
409
+ downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None
410
+ use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False.
411
+ """
412
+
413
+ def __init__(self,
414
+ dim,
415
+ input_resolution,
416
+ depth,
417
+ num_heads,
418
+ window_size,
419
+ mlp_ratio=4.,
420
+ qkv_bias=True,
421
+ qk_scale=None,
422
+ drop=0.,
423
+ attn_drop=0.,
424
+ drop_path=0.,
425
+ norm_layer=nn.LayerNorm,
426
+ downsample=None,
427
+ use_checkpoint=False):
428
+
429
+ super().__init__()
430
+ self.dim = dim
431
+ self.input_resolution = input_resolution
432
+ self.depth = depth
433
+ self.use_checkpoint = use_checkpoint
434
+
435
+ # build blocks
436
+ self.blocks = nn.ModuleList([
437
+ SwinTransformerBlock(
438
+ dim=dim,
439
+ input_resolution=input_resolution,
440
+ num_heads=num_heads,
441
+ window_size=window_size,
442
+ shift_size=0 if (i % 2 == 0) else window_size // 2,
443
+ mlp_ratio=mlp_ratio,
444
+ qkv_bias=qkv_bias,
445
+ qk_scale=qk_scale,
446
+ drop=drop,
447
+ attn_drop=attn_drop,
448
+ drop_path=drop_path[i] if isinstance(drop_path, list) else drop_path,
449
+ norm_layer=norm_layer) for i in range(depth)
450
+ ])
451
+
452
+ # patch merging layer
453
+ if downsample is not None:
454
+ self.downsample = downsample(input_resolution, dim=dim, norm_layer=norm_layer)
455
+ else:
456
+ self.downsample = None
457
+
458
+ def forward(self, x, x_size):
459
+ for blk in self.blocks:
460
+ if self.use_checkpoint:
461
+ x = checkpoint.checkpoint(blk, x)
462
+ else:
463
+ x = blk(x, x_size)
464
+ if self.downsample is not None:
465
+ x = self.downsample(x)
466
+ return x
467
+
468
+ def extra_repr(self) -> str:
469
+ return f'dim={self.dim}, input_resolution={self.input_resolution}, depth={self.depth}'
470
+
471
+ def flops(self):
472
+ flops = 0
473
+ for blk in self.blocks:
474
+ flops += blk.flops()
475
+ if self.downsample is not None:
476
+ flops += self.downsample.flops()
477
+ return flops
478
+
479
+
480
+ class RSTB(nn.Module):
481
+ """Residual Swin Transformer Block (RSTB).
482
+
483
+ Args:
484
+ dim (int): Number of input channels.
485
+ input_resolution (tuple[int]): Input resolution.
486
+ depth (int): Number of blocks.
487
+ num_heads (int): Number of attention heads.
488
+ window_size (int): Local window size.
489
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim.
490
+ qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True
491
+ qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set.
492
+ drop (float, optional): Dropout rate. Default: 0.0
493
+ attn_drop (float, optional): Attention dropout rate. Default: 0.0
494
+ drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0
495
+ norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm
496
+ downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None
497
+ use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False.
498
+ img_size: Input image size.
499
+ patch_size: Patch size.
500
+ resi_connection: The convolutional block before residual connection.
501
+ """
502
+
503
+ def __init__(self,
504
+ dim,
505
+ input_resolution,
506
+ depth,
507
+ num_heads,
508
+ window_size,
509
+ mlp_ratio=4.,
510
+ qkv_bias=True,
511
+ qk_scale=None,
512
+ drop=0.,
513
+ attn_drop=0.,
514
+ drop_path=0.,
515
+ norm_layer=nn.LayerNorm,
516
+ downsample=None,
517
+ use_checkpoint=False,
518
+ img_size=224,
519
+ patch_size=4,
520
+ resi_connection='1conv'):
521
+ super(RSTB, self).__init__()
522
+
523
+ self.dim = dim
524
+ self.input_resolution = input_resolution
525
+
526
+ self.residual_group = BasicLayer(
527
+ dim=dim,
528
+ input_resolution=input_resolution,
529
+ depth=depth,
530
+ num_heads=num_heads,
531
+ window_size=window_size,
532
+ mlp_ratio=mlp_ratio,
533
+ qkv_bias=qkv_bias,
534
+ qk_scale=qk_scale,
535
+ drop=drop,
536
+ attn_drop=attn_drop,
537
+ drop_path=drop_path,
538
+ norm_layer=norm_layer,
539
+ downsample=downsample,
540
+ use_checkpoint=use_checkpoint)
541
+
542
+ if resi_connection == '1conv':
543
+ self.conv = nn.Conv2d(dim, dim, 3, 1, 1)
544
+ elif resi_connection == '3conv':
545
+ # to save parameters and memory
546
+ self.conv = nn.Sequential(
547
+ nn.Conv2d(dim, dim // 4, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True),
548
+ nn.Conv2d(dim // 4, dim // 4, 1, 1, 0), nn.LeakyReLU(negative_slope=0.2, inplace=True),
549
+ nn.Conv2d(dim // 4, dim, 3, 1, 1))
550
+
551
+ self.patch_embed = PatchEmbed(
552
+ img_size=img_size, patch_size=patch_size, in_chans=0, embed_dim=dim, norm_layer=None)
553
+
554
+ self.patch_unembed = PatchUnEmbed(
555
+ img_size=img_size, patch_size=patch_size, in_chans=0, embed_dim=dim, norm_layer=None)
556
+
557
+ def forward(self, x, x_size):
558
+ return self.patch_embed(self.conv(self.patch_unembed(self.residual_group(x, x_size), x_size))) + x
559
+
560
+ def flops(self):
561
+ flops = 0
562
+ flops += self.residual_group.flops()
563
+ h, w = self.input_resolution
564
+ flops += h * w * self.dim * self.dim * 9
565
+ flops += self.patch_embed.flops()
566
+ flops += self.patch_unembed.flops()
567
+
568
+ return flops
569
+
570
+
571
+ class PatchEmbed(nn.Module):
572
+ r""" Image to Patch Embedding
573
+
574
+ Args:
575
+ img_size (int): Image size. Default: 224.
576
+ patch_size (int): Patch token size. Default: 4.
577
+ in_chans (int): Number of input image channels. Default: 3.
578
+ embed_dim (int): Number of linear projection output channels. Default: 96.
579
+ norm_layer (nn.Module, optional): Normalization layer. Default: None
580
+ """
581
+
582
+ def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None):
583
+ super().__init__()
584
+ img_size = to_2tuple(img_size)
585
+ patch_size = to_2tuple(patch_size)
586
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
587
+ self.img_size = img_size
588
+ self.patch_size = patch_size
589
+ self.patches_resolution = patches_resolution
590
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
591
+
592
+ self.in_chans = in_chans
593
+ self.embed_dim = embed_dim
594
+
595
+ if norm_layer is not None:
596
+ self.norm = norm_layer(embed_dim)
597
+ else:
598
+ self.norm = None
599
+
600
+ def forward(self, x):
601
+ x = x.flatten(2).transpose(1, 2) # b Ph*Pw c
602
+ if self.norm is not None:
603
+ x = self.norm(x)
604
+ return x
605
+
606
+ def flops(self):
607
+ flops = 0
608
+ h, w = self.img_size
609
+ if self.norm is not None:
610
+ flops += h * w * self.embed_dim
611
+ return flops
612
+
613
+
614
+ class PatchUnEmbed(nn.Module):
615
+ r""" Image to Patch Unembedding
616
+
617
+ Args:
618
+ img_size (int): Image size. Default: 224.
619
+ patch_size (int): Patch token size. Default: 4.
620
+ in_chans (int): Number of input image channels. Default: 3.
621
+ embed_dim (int): Number of linear projection output channels. Default: 96.
622
+ norm_layer (nn.Module, optional): Normalization layer. Default: None
623
+ """
624
+
625
+ def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None):
626
+ super().__init__()
627
+ img_size = to_2tuple(img_size)
628
+ patch_size = to_2tuple(patch_size)
629
+ patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]]
630
+ self.img_size = img_size
631
+ self.patch_size = patch_size
632
+ self.patches_resolution = patches_resolution
633
+ self.num_patches = patches_resolution[0] * patches_resolution[1]
634
+
635
+ self.in_chans = in_chans
636
+ self.embed_dim = embed_dim
637
+
638
+ def forward(self, x, x_size):
639
+ x = x.transpose(1, 2).view(x.shape[0], self.embed_dim, x_size[0], x_size[1]) # b Ph*Pw c
640
+ return x
641
+
642
+ def flops(self):
643
+ flops = 0
644
+ return flops
645
+
646
+
647
+ class Upsample(nn.Sequential):
648
+ """Upsample module.
649
+
650
+ Args:
651
+ scale (int): Scale factor. Supported scales: 2^n and 3.
652
+ num_feat (int): Channel number of intermediate features.
653
+ """
654
+
655
+ def __init__(self, scale, num_feat):
656
+ m = []
657
+ if (scale & (scale - 1)) == 0: # scale = 2^n
658
+ for _ in range(int(math.log(scale, 2))):
659
+ m.append(nn.Conv2d(num_feat, 4 * num_feat, 3, 1, 1))
660
+ m.append(nn.PixelShuffle(2))
661
+ elif scale == 3:
662
+ m.append(nn.Conv2d(num_feat, 9 * num_feat, 3, 1, 1))
663
+ m.append(nn.PixelShuffle(3))
664
+ else:
665
+ raise ValueError(f'scale {scale} is not supported. Supported scales: 2^n and 3.')
666
+ super(Upsample, self).__init__(*m)
667
+
668
+
669
+ class UpsampleOneStep(nn.Sequential):
670
+ """UpsampleOneStep module (the difference with Upsample is that it always only has 1conv + 1pixelshuffle)
671
+ Used in lightweight SR to save parameters.
672
+
673
+ Args:
674
+ scale (int): Scale factor. Supported scales: 2^n and 3.
675
+ num_feat (int): Channel number of intermediate features.
676
+
677
+ """
678
+
679
+ def __init__(self, scale, num_feat, num_out_ch, input_resolution=None):
680
+ self.num_feat = num_feat
681
+ self.input_resolution = input_resolution
682
+ m = []
683
+ m.append(nn.Conv2d(num_feat, (scale**2) * num_out_ch, 3, 1, 1))
684
+ m.append(nn.PixelShuffle(scale))
685
+ super(UpsampleOneStep, self).__init__(*m)
686
+
687
+ def flops(self):
688
+ h, w = self.input_resolution
689
+ flops = h * w * self.num_feat * 3 * 9
690
+ return flops
691
+
692
+
693
+ @ARCH_REGISTRY.register()
694
+ class SwinIR(nn.Module):
695
+ r""" SwinIR
696
+ A PyTorch impl of : `SwinIR: Image Restoration Using Swin Transformer`, based on Swin Transformer.
697
+
698
+ Args:
699
+ img_size (int | tuple(int)): Input image size. Default 64
700
+ patch_size (int | tuple(int)): Patch size. Default: 1
701
+ in_chans (int): Number of input image channels. Default: 3
702
+ embed_dim (int): Patch embedding dimension. Default: 96
703
+ depths (tuple(int)): Depth of each Swin Transformer layer.
704
+ num_heads (tuple(int)): Number of attention heads in different layers.
705
+ window_size (int): Window size. Default: 7
706
+ mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4
707
+ qkv_bias (bool): If True, add a learnable bias to query, key, value. Default: True
708
+ qk_scale (float): Override default qk scale of head_dim ** -0.5 if set. Default: None
709
+ drop_rate (float): Dropout rate. Default: 0
710
+ attn_drop_rate (float): Attention dropout rate. Default: 0
711
+ drop_path_rate (float): Stochastic depth rate. Default: 0.1
712
+ norm_layer (nn.Module): Normalization layer. Default: nn.LayerNorm.
713
+ ape (bool): If True, add absolute position embedding to the patch embedding. Default: False
714
+ patch_norm (bool): If True, add normalization after patch embedding. Default: True
715
+ use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False
716
+ upscale: Upscale factor. 2/3/4/8 for image SR, 1 for denoising and compress artifact reduction
717
+ img_range: Image range. 1. or 255.
718
+ upsampler: The reconstruction reconstruction module. 'pixelshuffle'/'pixelshuffledirect'/'nearest+conv'/None
719
+ resi_connection: The convolutional block before residual connection. '1conv'/'3conv'
720
+ """
721
+
722
+ def __init__(self,
723
+ img_size=64,
724
+ patch_size=1,
725
+ in_chans=3,
726
+ embed_dim=96,
727
+ depths=(6, 6, 6, 6),
728
+ num_heads=(6, 6, 6, 6),
729
+ window_size=7,
730
+ mlp_ratio=4.,
731
+ qkv_bias=True,
732
+ qk_scale=None,
733
+ drop_rate=0.,
734
+ attn_drop_rate=0.,
735
+ drop_path_rate=0.1,
736
+ norm_layer=nn.LayerNorm,
737
+ ape=False,
738
+ patch_norm=True,
739
+ use_checkpoint=False,
740
+ upscale=2,
741
+ img_range=1.,
742
+ upsampler='',
743
+ resi_connection='1conv',
744
+ **kwargs):
745
+ super(SwinIR, self).__init__()
746
+ num_in_ch = in_chans
747
+ num_out_ch = in_chans
748
+ num_feat = 64
749
+ self.img_range = img_range
750
+ if in_chans == 3:
751
+ rgb_mean = (0.4488, 0.4371, 0.4040)
752
+ self.mean = torch.Tensor(rgb_mean).view(1, 3, 1, 1)
753
+ else:
754
+ self.mean = torch.zeros(1, 1, 1, 1)
755
+ self.upscale = upscale
756
+ self.upsampler = upsampler
757
+
758
+ # ------------------------- 1, shallow feature extraction ------------------------- #
759
+ self.conv_first = nn.Conv2d(num_in_ch, embed_dim, 3, 1, 1)
760
+
761
+ # ------------------------- 2, deep feature extraction ------------------------- #
762
+ self.num_layers = len(depths)
763
+ self.embed_dim = embed_dim
764
+ self.ape = ape
765
+ self.patch_norm = patch_norm
766
+ self.num_features = embed_dim
767
+ self.mlp_ratio = mlp_ratio
768
+
769
+ # split image into non-overlapping patches
770
+ self.patch_embed = PatchEmbed(
771
+ img_size=img_size,
772
+ patch_size=patch_size,
773
+ in_chans=embed_dim,
774
+ embed_dim=embed_dim,
775
+ norm_layer=norm_layer if self.patch_norm else None)
776
+ num_patches = self.patch_embed.num_patches
777
+ patches_resolution = self.patch_embed.patches_resolution
778
+ self.patches_resolution = patches_resolution
779
+
780
+ # merge non-overlapping patches into image
781
+ self.patch_unembed = PatchUnEmbed(
782
+ img_size=img_size,
783
+ patch_size=patch_size,
784
+ in_chans=embed_dim,
785
+ embed_dim=embed_dim,
786
+ norm_layer=norm_layer if self.patch_norm else None)
787
+
788
+ # absolute position embedding
789
+ if self.ape:
790
+ self.absolute_pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim))
791
+ trunc_normal_(self.absolute_pos_embed, std=.02)
792
+
793
+ self.pos_drop = nn.Dropout(p=drop_rate)
794
+
795
+ # stochastic depth
796
+ dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rule
797
+
798
+ # build Residual Swin Transformer blocks (RSTB)
799
+ self.layers = nn.ModuleList()
800
+ for i_layer in range(self.num_layers):
801
+ layer = RSTB(
802
+ dim=embed_dim,
803
+ input_resolution=(patches_resolution[0], patches_resolution[1]),
804
+ depth=depths[i_layer],
805
+ num_heads=num_heads[i_layer],
806
+ window_size=window_size,
807
+ mlp_ratio=self.mlp_ratio,
808
+ qkv_bias=qkv_bias,
809
+ qk_scale=qk_scale,
810
+ drop=drop_rate,
811
+ attn_drop=attn_drop_rate,
812
+ drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])], # no impact on SR results
813
+ norm_layer=norm_layer,
814
+ downsample=None,
815
+ use_checkpoint=use_checkpoint,
816
+ img_size=img_size,
817
+ patch_size=patch_size,
818
+ resi_connection=resi_connection)
819
+ self.layers.append(layer)
820
+ self.norm = norm_layer(self.num_features)
821
+
822
+ # build the last conv layer in deep feature extraction
823
+ if resi_connection == '1conv':
824
+ self.conv_after_body = nn.Conv2d(embed_dim, embed_dim, 3, 1, 1)
825
+ elif resi_connection == '3conv':
826
+ # to save parameters and memory
827
+ self.conv_after_body = nn.Sequential(
828
+ nn.Conv2d(embed_dim, embed_dim // 4, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True),
829
+ nn.Conv2d(embed_dim // 4, embed_dim // 4, 1, 1, 0), nn.LeakyReLU(negative_slope=0.2, inplace=True),
830
+ nn.Conv2d(embed_dim // 4, embed_dim, 3, 1, 1))
831
+
832
+ # ------------------------- 3, high quality image reconstruction ------------------------- #
833
+ if self.upsampler == 'pixelshuffle':
834
+ # for classical SR
835
+ self.conv_before_upsample = nn.Sequential(
836
+ nn.Conv2d(embed_dim, num_feat, 3, 1, 1), nn.LeakyReLU(inplace=True))
837
+ self.upsample = Upsample(upscale, num_feat)
838
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
839
+ elif self.upsampler == 'pixelshuffledirect':
840
+ # for lightweight SR (to save parameters)
841
+ self.upsample = UpsampleOneStep(upscale, embed_dim, num_out_ch,
842
+ (patches_resolution[0], patches_resolution[1]))
843
+ elif self.upsampler == 'nearest+conv':
844
+ # for real-world SR (less artifacts)
845
+ assert self.upscale == 4, 'only support x4 now.'
846
+ self.conv_before_upsample = nn.Sequential(
847
+ nn.Conv2d(embed_dim, num_feat, 3, 1, 1), nn.LeakyReLU(inplace=True))
848
+ self.conv_up1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
849
+ self.conv_up2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
850
+ self.conv_hr = nn.Conv2d(num_feat, num_feat, 3, 1, 1)
851
+ self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1)
852
+ self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
853
+ else:
854
+ # for image denoising and JPEG compression artifact reduction
855
+ self.conv_last = nn.Conv2d(embed_dim, num_out_ch, 3, 1, 1)
856
+
857
+ self.apply(self._init_weights)
858
+
859
+ def _init_weights(self, m):
860
+ if isinstance(m, nn.Linear):
861
+ trunc_normal_(m.weight, std=.02)
862
+ if isinstance(m, nn.Linear) and m.bias is not None:
863
+ nn.init.constant_(m.bias, 0)
864
+ elif isinstance(m, nn.LayerNorm):
865
+ nn.init.constant_(m.bias, 0)
866
+ nn.init.constant_(m.weight, 1.0)
867
+
868
+ @torch.jit.ignore
869
+ def no_weight_decay(self):
870
+ return {'absolute_pos_embed'}
871
+
872
+ @torch.jit.ignore
873
+ def no_weight_decay_keywords(self):
874
+ return {'relative_position_bias_table'}
875
+
876
+ def forward_features(self, x):
877
+ x_size = (x.shape[2], x.shape[3])
878
+ x = self.patch_embed(x)
879
+ if self.ape:
880
+ x = x + self.absolute_pos_embed
881
+ x = self.pos_drop(x)
882
+
883
+ for layer in self.layers:
884
+ x = layer(x, x_size)
885
+
886
+ x = self.norm(x) # b seq_len c
887
+ x = self.patch_unembed(x, x_size)
888
+
889
+ return x
890
+
891
+ def forward(self, x):
892
+ self.mean = self.mean.type_as(x)
893
+ x = (x - self.mean) * self.img_range
894
+
895
+ if self.upsampler == 'pixelshuffle':
896
+ # for classical SR
897
+ x = self.conv_first(x)
898
+ x = self.conv_after_body(self.forward_features(x)) + x
899
+ x = self.conv_before_upsample(x)
900
+ x = self.conv_last(self.upsample(x))
901
+ elif self.upsampler == 'pixelshuffledirect':
902
+ # for lightweight SR
903
+ x = self.conv_first(x)
904
+ x = self.conv_after_body(self.forward_features(x)) + x
905
+ x = self.upsample(x)
906
+ elif self.upsampler == 'nearest+conv':
907
+ # for real-world SR
908
+ x = self.conv_first(x)
909
+ x = self.conv_after_body(self.forward_features(x)) + x
910
+ x = self.conv_before_upsample(x)
911
+ x = self.lrelu(self.conv_up1(torch.nn.functional.interpolate(x, scale_factor=2, mode='nearest')))
912
+ x = self.lrelu(self.conv_up2(torch.nn.functional.interpolate(x, scale_factor=2, mode='nearest')))
913
+ x = self.conv_last(self.lrelu(self.conv_hr(x)))
914
+ else:
915
+ # for image denoising and JPEG compression artifact reduction
916
+ x_first = self.conv_first(x)
917
+ res = self.conv_after_body(self.forward_features(x_first)) + x_first
918
+ x = x + self.conv_last(res)
919
+
920
+ x = x / self.img_range + self.mean
921
+
922
+ return x
923
+
924
+ def flops(self):
925
+ flops = 0
926
+ h, w = self.patches_resolution
927
+ flops += h * w * 3 * self.embed_dim * 9
928
+ flops += self.patch_embed.flops()
929
+ for layer in self.layers:
930
+ flops += layer.flops()
931
+ flops += h * w * 3 * self.embed_dim * self.embed_dim
932
+ flops += self.upsample.flops()
933
+ return flops
934
+
935
+
936
+ if __name__ == '__main__':
937
+ upscale = 4
938
+ window_size = 8
939
+ height = (1024 // upscale // window_size + 1) * window_size
940
+ width = (720 // upscale // window_size + 1) * window_size
941
+ model = SwinIR(
942
+ upscale=2,
943
+ img_size=(height, width),
944
+ window_size=window_size,
945
+ img_range=1.,
946
+ depths=[6, 6, 6, 6],
947
+ embed_dim=60,
948
+ num_heads=[6, 6, 6, 6],
949
+ mlp_ratio=2,
950
+ upsampler='pixelshuffledirect')
951
+ print(model)
952
+ print(height, width, model.flops() / 1e9)
953
+
954
+ x = torch.randn((1, 3, height, width))
955
+ x = model(x)
956
+ print(x.shape)
basicsr/archs/tof_arch.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn as nn
3
+ from torch.nn import functional as F
4
+
5
+ from basicsr.utils.registry import ARCH_REGISTRY
6
+ from .arch_util import flow_warp
7
+
8
+
9
+ class BasicModule(nn.Module):
10
+ """Basic module of SPyNet.
11
+
12
+ Note that unlike the architecture in spynet_arch.py, the basic module
13
+ here contains batch normalization.
14
+ """
15
+
16
+ def __init__(self):
17
+ super(BasicModule, self).__init__()
18
+ self.basic_module = nn.Sequential(
19
+ nn.Conv2d(in_channels=8, out_channels=32, kernel_size=7, stride=1, padding=3, bias=False),
20
+ nn.BatchNorm2d(32), nn.ReLU(inplace=True),
21
+ nn.Conv2d(in_channels=32, out_channels=64, kernel_size=7, stride=1, padding=3, bias=False),
22
+ nn.BatchNorm2d(64), nn.ReLU(inplace=True),
23
+ nn.Conv2d(in_channels=64, out_channels=32, kernel_size=7, stride=1, padding=3, bias=False),
24
+ nn.BatchNorm2d(32), nn.ReLU(inplace=True),
25
+ nn.Conv2d(in_channels=32, out_channels=16, kernel_size=7, stride=1, padding=3, bias=False),
26
+ nn.BatchNorm2d(16), nn.ReLU(inplace=True),
27
+ nn.Conv2d(in_channels=16, out_channels=2, kernel_size=7, stride=1, padding=3))
28
+
29
+ def forward(self, tensor_input):
30
+ """
31
+ Args:
32
+ tensor_input (Tensor): Input tensor with shape (b, 8, h, w).
33
+ 8 channels contain:
34
+ [reference image (3), neighbor image (3), initial flow (2)].
35
+
36
+ Returns:
37
+ Tensor: Estimated flow with shape (b, 2, h, w)
38
+ """
39
+ return self.basic_module(tensor_input)
40
+
41
+
42
+ class SPyNetTOF(nn.Module):
43
+ """SPyNet architecture for TOF.
44
+
45
+ Note that this implementation is specifically for TOFlow. Please use :file:`spynet_arch.py` for general use.
46
+ They differ in the following aspects:
47
+
48
+ 1. The basic modules here contain BatchNorm.
49
+ 2. Normalization and denormalization are not done here, as they are done in TOFlow.
50
+
51
+ ``Paper: Optical Flow Estimation using a Spatial Pyramid Network``
52
+
53
+ Reference: https://github.com/Coldog2333/pytoflow
54
+
55
+ Args:
56
+ load_path (str): Path for pretrained SPyNet. Default: None.
57
+ """
58
+
59
+ def __init__(self, load_path=None):
60
+ super(SPyNetTOF, self).__init__()
61
+
62
+ self.basic_module = nn.ModuleList([BasicModule() for _ in range(4)])
63
+ if load_path:
64
+ self.load_state_dict(torch.load(load_path, map_location=lambda storage, loc: storage)['params'])
65
+
66
+ def forward(self, ref, supp):
67
+ """
68
+ Args:
69
+ ref (Tensor): Reference image with shape of (b, 3, h, w).
70
+ supp: The supporting image to be warped: (b, 3, h, w).
71
+
72
+ Returns:
73
+ Tensor: Estimated optical flow: (b, 2, h, w).
74
+ """
75
+ num_batches, _, h, w = ref.size()
76
+ ref = [ref]
77
+ supp = [supp]
78
+
79
+ # generate downsampled frames
80
+ for _ in range(3):
81
+ ref.insert(0, F.avg_pool2d(input=ref[0], kernel_size=2, stride=2, count_include_pad=False))
82
+ supp.insert(0, F.avg_pool2d(input=supp[0], kernel_size=2, stride=2, count_include_pad=False))
83
+
84
+ # flow computation
85
+ flow = ref[0].new_zeros(num_batches, 2, h // 16, w // 16)
86
+ for i in range(4):
87
+ flow_up = F.interpolate(input=flow, scale_factor=2, mode='bilinear', align_corners=True) * 2.0
88
+ flow = flow_up + self.basic_module[i](
89
+ torch.cat([ref[i], flow_warp(supp[i], flow_up.permute(0, 2, 3, 1)), flow_up], 1))
90
+ return flow
91
+
92
+
93
+ @ARCH_REGISTRY.register()
94
+ class TOFlow(nn.Module):
95
+ """PyTorch implementation of TOFlow.
96
+
97
+ In TOFlow, the LR frames are pre-upsampled and have the same size with the GT frames.
98
+
99
+ ``Paper: Video Enhancement with Task-Oriented Flow``
100
+
101
+ Reference: https://github.com/anchen1011/toflow
102
+
103
+ Reference: https://github.com/Coldog2333/pytoflow
104
+
105
+ Args:
106
+ adapt_official_weights (bool): Whether to adapt the weights translated
107
+ from the official implementation. Set to false if you want to
108
+ train from scratch. Default: False
109
+ """
110
+
111
+ def __init__(self, adapt_official_weights=False):
112
+ super(TOFlow, self).__init__()
113
+ self.adapt_official_weights = adapt_official_weights
114
+ self.ref_idx = 0 if adapt_official_weights else 3
115
+
116
+ self.register_buffer('mean', torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
117
+ self.register_buffer('std', torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))
118
+
119
+ # flow estimation module
120
+ self.spynet = SPyNetTOF()
121
+
122
+ # reconstruction module
123
+ self.conv_1 = nn.Conv2d(3 * 7, 64, 9, 1, 4)
124
+ self.conv_2 = nn.Conv2d(64, 64, 9, 1, 4)
125
+ self.conv_3 = nn.Conv2d(64, 64, 1)
126
+ self.conv_4 = nn.Conv2d(64, 3, 1)
127
+
128
+ # activation function
129
+ self.relu = nn.ReLU(inplace=True)
130
+
131
+ def normalize(self, img):
132
+ return (img - self.mean) / self.std
133
+
134
+ def denormalize(self, img):
135
+ return img * self.std + self.mean
136
+
137
+ def forward(self, lrs):
138
+ """
139
+ Args:
140
+ lrs: Input lr frames: (b, 7, 3, h, w).
141
+
142
+ Returns:
143
+ Tensor: SR frame: (b, 3, h, w).
144
+ """
145
+ # In the official implementation, the 0-th frame is the reference frame
146
+ if self.adapt_official_weights:
147
+ lrs = lrs[:, [3, 0, 1, 2, 4, 5, 6], :, :, :]
148
+
149
+ num_batches, num_lrs, _, h, w = lrs.size()
150
+
151
+ lrs = self.normalize(lrs.view(-1, 3, h, w))
152
+ lrs = lrs.view(num_batches, num_lrs, 3, h, w)
153
+
154
+ lr_ref = lrs[:, self.ref_idx, :, :, :]
155
+ lr_aligned = []
156
+ for i in range(7): # 7 frames
157
+ if i == self.ref_idx:
158
+ lr_aligned.append(lr_ref)
159
+ else:
160
+ lr_supp = lrs[:, i, :, :, :]
161
+ flow = self.spynet(lr_ref, lr_supp)
162
+ lr_aligned.append(flow_warp(lr_supp, flow.permute(0, 2, 3, 1)))
163
+
164
+ # reconstruction
165
+ hr = torch.stack(lr_aligned, dim=1)
166
+ hr = hr.view(num_batches, -1, h, w)
167
+ hr = self.relu(self.conv_1(hr))
168
+ hr = self.relu(self.conv_2(hr))
169
+ hr = self.relu(self.conv_3(hr))
170
+ hr = self.conv_4(hr) + lr_ref
171
+
172
+ return self.denormalize(hr)
basicsr/archs/vgg_arch.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ from collections import OrderedDict
4
+ from torch import nn as nn
5
+ from torchvision.models import vgg as vgg
6
+
7
+ from basicsr.utils.registry import ARCH_REGISTRY
8
+
9
+ VGG_PRETRAIN_PATH = 'experiments/pretrained_models/vgg19-dcbb9e9d.pth'
10
+ NAMES = {
11
+ 'vgg11': [
12
+ 'conv1_1', 'relu1_1', 'pool1', 'conv2_1', 'relu2_1', 'pool2', 'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2',
13
+ 'pool3', 'conv4_1', 'relu4_1', 'conv4_2', 'relu4_2', 'pool4', 'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2',
14
+ 'pool5'
15
+ ],
16
+ 'vgg13': [
17
+ 'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1', 'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',
18
+ 'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'pool3', 'conv4_1', 'relu4_1', 'conv4_2', 'relu4_2', 'pool4',
19
+ 'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2', 'pool5'
20
+ ],
21
+ 'vgg16': [
22
+ 'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1', 'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',
23
+ 'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3', 'relu3_3', 'pool3', 'conv4_1', 'relu4_1', 'conv4_2',
24
+ 'relu4_2', 'conv4_3', 'relu4_3', 'pool4', 'conv5_1', 'relu5_1', 'conv5_2', 'relu5_2', 'conv5_3', 'relu5_3',
25
+ 'pool5'
26
+ ],
27
+ 'vgg19': [
28
+ 'conv1_1', 'relu1_1', 'conv1_2', 'relu1_2', 'pool1', 'conv2_1', 'relu2_1', 'conv2_2', 'relu2_2', 'pool2',
29
+ 'conv3_1', 'relu3_1', 'conv3_2', 'relu3_2', 'conv3_3', 'relu3_3', 'conv3_4', 'relu3_4', 'pool3', 'conv4_1',
30
+ 'relu4_1', 'conv4_2', 'relu4_2', 'conv4_3', 'relu4_3', 'conv4_4', 'relu4_4', 'pool4', 'conv5_1', 'relu5_1',
31
+ 'conv5_2', 'relu5_2', 'conv5_3', 'relu5_3', 'conv5_4', 'relu5_4', 'pool5'
32
+ ]
33
+ }
34
+
35
+
36
+ def insert_bn(names):
37
+ """Insert bn layer after each conv.
38
+
39
+ Args:
40
+ names (list): The list of layer names.
41
+
42
+ Returns:
43
+ list: The list of layer names with bn layers.
44
+ """
45
+ names_bn = []
46
+ for name in names:
47
+ names_bn.append(name)
48
+ if 'conv' in name:
49
+ position = name.replace('conv', '')
50
+ names_bn.append('bn' + position)
51
+ return names_bn
52
+
53
+
54
+ @ARCH_REGISTRY.register()
55
+ class VGGFeatureExtractor(nn.Module):
56
+ """VGG network for feature extraction.
57
+
58
+ In this implementation, we allow users to choose whether use normalization
59
+ in the input feature and the type of vgg network. Note that the pretrained
60
+ path must fit the vgg type.
61
+
62
+ Args:
63
+ layer_name_list (list[str]): Forward function returns the corresponding
64
+ features according to the layer_name_list.
65
+ Example: {'relu1_1', 'relu2_1', 'relu3_1'}.
66
+ vgg_type (str): Set the type of vgg network. Default: 'vgg19'.
67
+ use_input_norm (bool): If True, normalize the input image. Importantly,
68
+ the input feature must in the range [0, 1]. Default: True.
69
+ range_norm (bool): If True, norm images with range [-1, 1] to [0, 1].
70
+ Default: False.
71
+ requires_grad (bool): If true, the parameters of VGG network will be
72
+ optimized. Default: False.
73
+ remove_pooling (bool): If true, the max pooling operations in VGG net
74
+ will be removed. Default: False.
75
+ pooling_stride (int): The stride of max pooling operation. Default: 2.
76
+ """
77
+
78
+ def __init__(self,
79
+ layer_name_list,
80
+ vgg_type='vgg19',
81
+ use_input_norm=True,
82
+ range_norm=False,
83
+ requires_grad=False,
84
+ remove_pooling=False,
85
+ pooling_stride=2):
86
+ super(VGGFeatureExtractor, self).__init__()
87
+
88
+ self.layer_name_list = layer_name_list
89
+ self.use_input_norm = use_input_norm
90
+ self.range_norm = range_norm
91
+
92
+ self.names = NAMES[vgg_type.replace('_bn', '')]
93
+ if 'bn' in vgg_type:
94
+ self.names = insert_bn(self.names)
95
+
96
+ # only borrow layers that will be used to avoid unused params
97
+ max_idx = 0
98
+ for v in layer_name_list:
99
+ idx = self.names.index(v)
100
+ if idx > max_idx:
101
+ max_idx = idx
102
+
103
+ if os.path.exists(VGG_PRETRAIN_PATH):
104
+ vgg_net = getattr(vgg, vgg_type)(pretrained=False)
105
+ state_dict = torch.load(VGG_PRETRAIN_PATH, map_location=lambda storage, loc: storage)
106
+ vgg_net.load_state_dict(state_dict)
107
+ else:
108
+ vgg_net = getattr(vgg, vgg_type)(pretrained=True)
109
+
110
+ features = vgg_net.features[:max_idx + 1]
111
+
112
+ modified_net = OrderedDict()
113
+ for k, v in zip(self.names, features):
114
+ if 'pool' in k:
115
+ # if remove_pooling is true, pooling operation will be removed
116
+ if remove_pooling:
117
+ continue
118
+ else:
119
+ # in some cases, we may want to change the default stride
120
+ modified_net[k] = nn.MaxPool2d(kernel_size=2, stride=pooling_stride)
121
+ else:
122
+ modified_net[k] = v
123
+
124
+ self.vgg_net = nn.Sequential(modified_net)
125
+
126
+ if not requires_grad:
127
+ self.vgg_net.eval()
128
+ for param in self.parameters():
129
+ param.requires_grad = False
130
+ else:
131
+ self.vgg_net.train()
132
+ for param in self.parameters():
133
+ param.requires_grad = True
134
+
135
+ if self.use_input_norm:
136
+ # the mean is for image with range [0, 1]
137
+ self.register_buffer('mean', torch.Tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1))
138
+ # the std is for image with range [0, 1]
139
+ self.register_buffer('std', torch.Tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1))
140
+
141
+ def forward(self, x):
142
+ """Forward function.
143
+
144
+ Args:
145
+ x (Tensor): Input tensor with shape (n, c, h, w).
146
+
147
+ Returns:
148
+ Tensor: Forward results.
149
+ """
150
+ if self.range_norm:
151
+ x = (x + 1) / 2
152
+ if self.use_input_norm:
153
+ x = (x - self.mean) / self.std
154
+
155
+ output = {}
156
+ for key, layer in self.vgg_net._modules.items():
157
+ x = layer(x)
158
+ if key in self.layer_name_list:
159
+ output[key] = x.clone()
160
+
161
+ return output
basicsr/data/__init__.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import importlib
2
+ import numpy as np
3
+ import random
4
+ import torch
5
+ import torch.utils.data
6
+ from copy import deepcopy
7
+ from functools import partial
8
+ from os import path as osp
9
+
10
+ from basicsr.data.prefetch_dataloader import PrefetchDataLoader
11
+ from basicsr.utils import get_root_logger, scandir
12
+ from basicsr.utils.dist_util import get_dist_info
13
+ from basicsr.utils.registry import DATASET_REGISTRY
14
+
15
+ __all__ = ['build_dataset', 'build_dataloader']
16
+
17
+ # automatically scan and import dataset modules for registry
18
+ # scan all the files under the data folder with '_dataset' in file names
19
+ data_folder = osp.dirname(osp.abspath(__file__))
20
+ dataset_filenames = [osp.splitext(osp.basename(v))[0] for v in scandir(data_folder) if v.endswith('_dataset.py')]
21
+ # import all the dataset modules
22
+ _dataset_modules = [importlib.import_module(f'basicsr.data.{file_name}') for file_name in dataset_filenames]
23
+
24
+
25
+ def build_dataset(dataset_opt):
26
+ """Build dataset from options.
27
+
28
+ Args:
29
+ dataset_opt (dict): Configuration for dataset. It must contain:
30
+ name (str): Dataset name.
31
+ type (str): Dataset type.
32
+ """
33
+ dataset_opt = deepcopy(dataset_opt)
34
+ dataset = DATASET_REGISTRY.get(dataset_opt['type'])(dataset_opt)
35
+ logger = get_root_logger()
36
+ logger.info(f'Dataset [{dataset.__class__.__name__}] - {dataset_opt["name"]} is built.')
37
+ return dataset
38
+
39
+
40
+ def build_dataloader(dataset, dataset_opt, num_gpu=1, dist=False, sampler=None, seed=None):
41
+ """Build dataloader.
42
+
43
+ Args:
44
+ dataset (torch.utils.data.Dataset): Dataset.
45
+ dataset_opt (dict): Dataset options. It contains the following keys:
46
+ phase (str): 'train' or 'val'.
47
+ num_worker_per_gpu (int): Number of workers for each GPU.
48
+ batch_size_per_gpu (int): Training batch size for each GPU.
49
+ num_gpu (int): Number of GPUs. Used only in the train phase.
50
+ Default: 1.
51
+ dist (bool): Whether in distributed training. Used only in the train
52
+ phase. Default: False.
53
+ sampler (torch.utils.data.sampler): Data sampler. Default: None.
54
+ seed (int | None): Seed. Default: None
55
+ """
56
+ phase = dataset_opt['phase']
57
+ rank, _ = get_dist_info()
58
+ if phase == 'train':
59
+ if dist: # distributed training
60
+ batch_size = dataset_opt['batch_size_per_gpu']
61
+ num_workers = dataset_opt['num_worker_per_gpu']
62
+ else: # non-distributed training
63
+ multiplier = 1 if num_gpu == 0 else num_gpu
64
+ batch_size = dataset_opt['batch_size_per_gpu'] * multiplier
65
+ num_workers = dataset_opt['num_worker_per_gpu'] * multiplier
66
+ dataloader_args = dict(
67
+ dataset=dataset,
68
+ batch_size=batch_size,
69
+ shuffle=False,
70
+ num_workers=num_workers,
71
+ sampler=sampler,
72
+ drop_last=True)
73
+ if sampler is None:
74
+ dataloader_args['shuffle'] = True
75
+ dataloader_args['worker_init_fn'] = partial(
76
+ worker_init_fn, num_workers=num_workers, rank=rank, seed=seed) if seed is not None else None
77
+ elif phase in ['val', 'test']: # validation
78
+ dataloader_args = dict(dataset=dataset, batch_size=1, shuffle=False, num_workers=0)
79
+ else:
80
+ raise ValueError(f"Wrong dataset phase: {phase}. Supported ones are 'train', 'val' and 'test'.")
81
+
82
+ dataloader_args['pin_memory'] = dataset_opt.get('pin_memory', False)
83
+ dataloader_args['persistent_workers'] = dataset_opt.get('persistent_workers', False)
84
+
85
+ prefetch_mode = dataset_opt.get('prefetch_mode')
86
+ if prefetch_mode == 'cpu': # CPUPrefetcher
87
+ num_prefetch_queue = dataset_opt.get('num_prefetch_queue', 1)
88
+ logger = get_root_logger()
89
+ logger.info(f'Use {prefetch_mode} prefetch dataloader: num_prefetch_queue = {num_prefetch_queue}')
90
+ return PrefetchDataLoader(num_prefetch_queue=num_prefetch_queue, **dataloader_args)
91
+ else:
92
+ # prefetch_mode=None: Normal dataloader
93
+ # prefetch_mode='cuda': dataloader for CUDAPrefetcher
94
+ return torch.utils.data.DataLoader(**dataloader_args)
95
+
96
+
97
+ def worker_init_fn(worker_id, num_workers, rank, seed):
98
+ # Set the worker seed to num_workers * rank + worker_id + seed
99
+ worker_seed = num_workers * rank + worker_id + seed
100
+ np.random.seed(worker_seed)
101
+ random.seed(worker_seed)
basicsr/data/data_sampler.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch.utils.data.sampler import Sampler
4
+
5
+
6
+ class EnlargedSampler(Sampler):
7
+ """Sampler that restricts data loading to a subset of the dataset.
8
+
9
+ Modified from torch.utils.data.distributed.DistributedSampler
10
+ Support enlarging the dataset for iteration-based training, for saving
11
+ time when restart the dataloader after each epoch
12
+
13
+ Args:
14
+ dataset (torch.utils.data.Dataset): Dataset used for sampling.
15
+ num_replicas (int | None): Number of processes participating in
16
+ the training. It is usually the world_size.
17
+ rank (int | None): Rank of the current process within num_replicas.
18
+ ratio (int): Enlarging ratio. Default: 1.
19
+ """
20
+
21
+ def __init__(self, dataset, num_replicas, rank, ratio=1):
22
+ self.dataset = dataset
23
+ self.num_replicas = num_replicas
24
+ self.rank = rank
25
+ self.epoch = 0
26
+ self.num_samples = math.ceil(len(self.dataset) * ratio / self.num_replicas)
27
+ self.total_size = self.num_samples * self.num_replicas
28
+
29
+ def __iter__(self):
30
+ # deterministically shuffle based on epoch
31
+ g = torch.Generator()
32
+ g.manual_seed(self.epoch)
33
+ indices = torch.randperm(self.total_size, generator=g).tolist()
34
+
35
+ dataset_size = len(self.dataset)
36
+ indices = [v % dataset_size for v in indices]
37
+
38
+ # subsample
39
+ indices = indices[self.rank:self.total_size:self.num_replicas]
40
+ assert len(indices) == self.num_samples
41
+
42
+ return iter(indices)
43
+
44
+ def __len__(self):
45
+ return self.num_samples
46
+
47
+ def set_epoch(self, epoch):
48
+ self.epoch = epoch
basicsr/data/data_util.py ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import torch
4
+ from os import path as osp
5
+ from torch.nn import functional as F
6
+
7
+ from basicsr.data.transforms import mod_crop
8
+ from basicsr.utils import img2tensor, scandir
9
+
10
+
11
+ def read_img_seq(path, require_mod_crop=False, scale=1, return_imgname=False):
12
+ """Read a sequence of images from a given folder path.
13
+
14
+ Args:
15
+ path (list[str] | str): List of image paths or image folder path.
16
+ require_mod_crop (bool): Require mod crop for each image.
17
+ Default: False.
18
+ scale (int): Scale factor for mod_crop. Default: 1.
19
+ return_imgname(bool): Whether return image names. Default False.
20
+
21
+ Returns:
22
+ Tensor: size (t, c, h, w), RGB, [0, 1].
23
+ list[str]: Returned image name list.
24
+ """
25
+ if isinstance(path, list):
26
+ img_paths = path
27
+ else:
28
+ img_paths = sorted(list(scandir(path, full_path=True)))
29
+ imgs = [cv2.imread(v).astype(np.float32) / 255. for v in img_paths]
30
+
31
+ if require_mod_crop:
32
+ imgs = [mod_crop(img, scale) for img in imgs]
33
+ imgs = img2tensor(imgs, bgr2rgb=True, float32=True)
34
+ imgs = torch.stack(imgs, dim=0)
35
+
36
+ if return_imgname:
37
+ imgnames = [osp.splitext(osp.basename(path))[0] for path in img_paths]
38
+ return imgs, imgnames
39
+ else:
40
+ return imgs
41
+
42
+
43
+ def generate_frame_indices(crt_idx, max_frame_num, num_frames, padding='reflection'):
44
+ """Generate an index list for reading `num_frames` frames from a sequence
45
+ of images.
46
+
47
+ Args:
48
+ crt_idx (int): Current center index.
49
+ max_frame_num (int): Max number of the sequence of images (from 1).
50
+ num_frames (int): Reading num_frames frames.
51
+ padding (str): Padding mode, one of
52
+ 'replicate' | 'reflection' | 'reflection_circle' | 'circle'
53
+ Examples: current_idx = 0, num_frames = 5
54
+ The generated frame indices under different padding mode:
55
+ replicate: [0, 0, 0, 1, 2]
56
+ reflection: [2, 1, 0, 1, 2]
57
+ reflection_circle: [4, 3, 0, 1, 2]
58
+ circle: [3, 4, 0, 1, 2]
59
+
60
+ Returns:
61
+ list[int]: A list of indices.
62
+ """
63
+ assert num_frames % 2 == 1, 'num_frames should be an odd number.'
64
+ assert padding in ('replicate', 'reflection', 'reflection_circle', 'circle'), f'Wrong padding mode: {padding}.'
65
+
66
+ max_frame_num = max_frame_num - 1 # start from 0
67
+ num_pad = num_frames // 2
68
+
69
+ indices = []
70
+ for i in range(crt_idx - num_pad, crt_idx + num_pad + 1):
71
+ if i < 0:
72
+ if padding == 'replicate':
73
+ pad_idx = 0
74
+ elif padding == 'reflection':
75
+ pad_idx = -i
76
+ elif padding == 'reflection_circle':
77
+ pad_idx = crt_idx + num_pad - i
78
+ else:
79
+ pad_idx = num_frames + i
80
+ elif i > max_frame_num:
81
+ if padding == 'replicate':
82
+ pad_idx = max_frame_num
83
+ elif padding == 'reflection':
84
+ pad_idx = max_frame_num * 2 - i
85
+ elif padding == 'reflection_circle':
86
+ pad_idx = (crt_idx - num_pad) - (i - max_frame_num)
87
+ else:
88
+ pad_idx = i - num_frames
89
+ else:
90
+ pad_idx = i
91
+ indices.append(pad_idx)
92
+ return indices
93
+
94
+
95
+ def paired_paths_from_lmdb(folders, keys):
96
+ """Generate paired paths from lmdb files.
97
+
98
+ Contents of lmdb. Taking the `lq.lmdb` for example, the file structure is:
99
+
100
+ ::
101
+
102
+ lq.lmdb
103
+ β”œβ”€β”€ data.mdb
104
+ β”œβ”€β”€ lock.mdb
105
+ β”œβ”€β”€ meta_info.txt
106
+
107
+ The data.mdb and lock.mdb are standard lmdb files and you can refer to
108
+ https://lmdb.readthedocs.io/en/release/ for more details.
109
+
110
+ The meta_info.txt is a specified txt file to record the meta information
111
+ of our datasets. It will be automatically created when preparing
112
+ datasets by our provided dataset tools.
113
+ Each line in the txt file records
114
+ 1)image name (with extension),
115
+ 2)image shape,
116
+ 3)compression level, separated by a white space.
117
+ Example: `baboon.png (120,125,3) 1`
118
+
119
+ We use the image name without extension as the lmdb key.
120
+ Note that we use the same key for the corresponding lq and gt images.
121
+
122
+ Args:
123
+ folders (list[str]): A list of folder path. The order of list should
124
+ be [input_folder, gt_folder].
125
+ keys (list[str]): A list of keys identifying folders. The order should
126
+ be in consistent with folders, e.g., ['lq', 'gt'].
127
+ Note that this key is different from lmdb keys.
128
+
129
+ Returns:
130
+ list[str]: Returned path list.
131
+ """
132
+ assert len(folders) == 2, ('The len of folders should be 2 with [input_folder, gt_folder]. '
133
+ f'But got {len(folders)}')
134
+ assert len(keys) == 2, f'The len of keys should be 2 with [input_key, gt_key]. But got {len(keys)}'
135
+ input_folder, gt_folder = folders
136
+ input_key, gt_key = keys
137
+
138
+ if not (input_folder.endswith('.lmdb') and gt_folder.endswith('.lmdb')):
139
+ raise ValueError(f'{input_key} folder and {gt_key} folder should both in lmdb '
140
+ f'formats. But received {input_key}: {input_folder}; '
141
+ f'{gt_key}: {gt_folder}')
142
+ # ensure that the two meta_info files are the same
143
+ with open(osp.join(input_folder, 'meta_info.txt')) as fin:
144
+ input_lmdb_keys = [line.split('.')[0] for line in fin]
145
+ with open(osp.join(gt_folder, 'meta_info.txt')) as fin:
146
+ gt_lmdb_keys = [line.split('.')[0] for line in fin]
147
+ if set(input_lmdb_keys) != set(gt_lmdb_keys):
148
+ raise ValueError(f'Keys in {input_key}_folder and {gt_key}_folder are different.')
149
+ else:
150
+ paths = []
151
+ for lmdb_key in sorted(input_lmdb_keys):
152
+ paths.append(dict([(f'{input_key}_path', lmdb_key), (f'{gt_key}_path', lmdb_key)]))
153
+ return paths
154
+
155
+
156
+ def paired_paths_from_meta_info_file(folders, keys, meta_info_file, filename_tmpl):
157
+ """Generate paired paths from an meta information file.
158
+
159
+ Each line in the meta information file contains the image names and
160
+ image shape (usually for gt), separated by a white space.
161
+
162
+ Example of an meta information file:
163
+ ```
164
+ 0001_s001.png (480,480,3)
165
+ 0001_s002.png (480,480,3)
166
+ ```
167
+
168
+ Args:
169
+ folders (list[str]): A list of folder path. The order of list should
170
+ be [input_folder, gt_folder].
171
+ keys (list[str]): A list of keys identifying folders. The order should
172
+ be in consistent with folders, e.g., ['lq', 'gt'].
173
+ meta_info_file (str): Path to the meta information file.
174
+ filename_tmpl (str): Template for each filename. Note that the
175
+ template excludes the file extension. Usually the filename_tmpl is
176
+ for files in the input folder.
177
+
178
+ Returns:
179
+ list[str]: Returned path list.
180
+ """
181
+ assert len(folders) == 2, ('The len of folders should be 2 with [input_folder, gt_folder]. '
182
+ f'But got {len(folders)}')
183
+ assert len(keys) == 2, f'The len of keys should be 2 with [input_key, gt_key]. But got {len(keys)}'
184
+ input_folder, gt_folder = folders
185
+ input_key, gt_key = keys
186
+
187
+ with open(meta_info_file, 'r') as fin:
188
+ gt_names = [line.strip().split(' ')[0] for line in fin]
189
+
190
+ paths = []
191
+ for gt_name in gt_names:
192
+ basename, ext = osp.splitext(osp.basename(gt_name))
193
+ input_name = f'{filename_tmpl.format(basename)}{ext}'
194
+ input_path = osp.join(input_folder, input_name)
195
+ gt_path = osp.join(gt_folder, gt_name)
196
+ paths.append(dict([(f'{input_key}_path', input_path), (f'{gt_key}_path', gt_path)]))
197
+ return paths
198
+
199
+
200
+ def paired_paths_from_folder(folders, keys, filename_tmpl):
201
+ """Generate paired paths from folders.
202
+
203
+ Args:
204
+ folders (list[str]): A list of folder path. The order of list should
205
+ be [input_folder, gt_folder].
206
+ keys (list[str]): A list of keys identifying folders. The order should
207
+ be in consistent with folders, e.g., ['lq', 'gt'].
208
+ filename_tmpl (str): Template for each filename. Note that the
209
+ template excludes the file extension. Usually the filename_tmpl is
210
+ for files in the input folder.
211
+
212
+ Returns:
213
+ list[str]: Returned path list.
214
+ """
215
+ assert len(folders) == 2, ('The len of folders should be 2 with [input_folder, gt_folder]. '
216
+ f'But got {len(folders)}')
217
+ assert len(keys) == 2, f'The len of keys should be 2 with [input_key, gt_key]. But got {len(keys)}'
218
+ input_folder, gt_folder = folders
219
+ input_key, gt_key = keys
220
+
221
+ input_paths = list(scandir(input_folder))
222
+ gt_paths = list(scandir(gt_folder))
223
+ assert len(input_paths) == len(gt_paths), (f'{input_key} and {gt_key} datasets have different number of images: '
224
+ f'{len(input_paths)}, {len(gt_paths)}.')
225
+ paths = []
226
+ for gt_path in gt_paths:
227
+ basename, ext = osp.splitext(osp.basename(gt_path))
228
+ input_name = f'{filename_tmpl.format(basename)}{ext}'
229
+ input_path = osp.join(input_folder, input_name)
230
+ assert input_name in input_paths, f'{input_name} is not in {input_key}_paths.'
231
+ gt_path = osp.join(gt_folder, gt_path)
232
+ paths.append(dict([(f'{input_key}_path', input_path), (f'{gt_key}_path', gt_path)]))
233
+ return paths
234
+
235
+
236
+ def paths_from_folder(folder):
237
+ """Generate paths from folder.
238
+
239
+ Args:
240
+ folder (str): Folder path.
241
+
242
+ Returns:
243
+ list[str]: Returned path list.
244
+ """
245
+
246
+ paths = list(scandir(folder))
247
+ paths = [osp.join(folder, path) for path in paths]
248
+ return paths
249
+
250
+
251
+ def paths_from_lmdb(folder):
252
+ """Generate paths from lmdb.
253
+
254
+ Args:
255
+ folder (str): Folder path.
256
+
257
+ Returns:
258
+ list[str]: Returned path list.
259
+ """
260
+ if not folder.endswith('.lmdb'):
261
+ raise ValueError(f'Folder {folder}folder should in lmdb format.')
262
+ with open(osp.join(folder, 'meta_info.txt')) as fin:
263
+ paths = [line.split('.')[0] for line in fin]
264
+ return paths
265
+
266
+
267
+ def generate_gaussian_kernel(kernel_size=13, sigma=1.6):
268
+ """Generate Gaussian kernel used in `duf_downsample`.
269
+
270
+ Args:
271
+ kernel_size (int): Kernel size. Default: 13.
272
+ sigma (float): Sigma of the Gaussian kernel. Default: 1.6.
273
+
274
+ Returns:
275
+ np.array: The Gaussian kernel.
276
+ """
277
+ from scipy.ndimage import filters as filters
278
+ kernel = np.zeros((kernel_size, kernel_size))
279
+ # set element at the middle to one, a dirac delta
280
+ kernel[kernel_size // 2, kernel_size // 2] = 1
281
+ # gaussian-smooth the dirac, resulting in a gaussian filter
282
+ return filters.gaussian_filter(kernel, sigma)
283
+
284
+
285
+ def duf_downsample(x, kernel_size=13, scale=4):
286
+ """Downsamping with Gaussian kernel used in the DUF official code.
287
+
288
+ Args:
289
+ x (Tensor): Frames to be downsampled, with shape (b, t, c, h, w).
290
+ kernel_size (int): Kernel size. Default: 13.
291
+ scale (int): Downsampling factor. Supported scale: (2, 3, 4).
292
+ Default: 4.
293
+
294
+ Returns:
295
+ Tensor: DUF downsampled frames.
296
+ """
297
+ assert scale in (2, 3, 4), f'Only support scale (2, 3, 4), but got {scale}.'
298
+
299
+ squeeze_flag = False
300
+ if x.ndim == 4:
301
+ squeeze_flag = True
302
+ x = x.unsqueeze(0)
303
+ b, t, c, h, w = x.size()
304
+ x = x.view(-1, 1, h, w)
305
+ pad_w, pad_h = kernel_size // 2 + scale * 2, kernel_size // 2 + scale * 2
306
+ x = F.pad(x, (pad_w, pad_w, pad_h, pad_h), 'reflect')
307
+
308
+ gaussian_filter = generate_gaussian_kernel(kernel_size, 0.4 * scale)
309
+ gaussian_filter = torch.from_numpy(gaussian_filter).type_as(x).unsqueeze(0).unsqueeze(0)
310
+ x = F.conv2d(x, gaussian_filter, stride=scale)
311
+ x = x[:, :, 2:-2, 2:-2]
312
+ x = x.view(b, t, c, x.size(2), x.size(3))
313
+ if squeeze_flag:
314
+ x = x.squeeze(0)
315
+ return x
basicsr/data/degradations.py ADDED
@@ -0,0 +1,764 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import math
3
+ import numpy as np
4
+ import random
5
+ import torch
6
+ from scipy import special
7
+ from scipy.stats import multivariate_normal
8
+ from torchvision.transforms.functional import rgb_to_grayscale
9
+
10
+ # -------------------------------------------------------------------- #
11
+ # --------------------------- blur kernels --------------------------- #
12
+ # -------------------------------------------------------------------- #
13
+
14
+
15
+ # --------------------------- util functions --------------------------- #
16
+ def sigma_matrix2(sig_x, sig_y, theta):
17
+ """Calculate the rotated sigma matrix (two dimensional matrix).
18
+
19
+ Args:
20
+ sig_x (float):
21
+ sig_y (float):
22
+ theta (float): Radian measurement.
23
+
24
+ Returns:
25
+ ndarray: Rotated sigma matrix.
26
+ """
27
+ d_matrix = np.array([[sig_x**2, 0], [0, sig_y**2]])
28
+ u_matrix = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
29
+ return np.dot(u_matrix, np.dot(d_matrix, u_matrix.T))
30
+
31
+
32
+ def mesh_grid(kernel_size):
33
+ """Generate the mesh grid, centering at zero.
34
+
35
+ Args:
36
+ kernel_size (int):
37
+
38
+ Returns:
39
+ xy (ndarray): with the shape (kernel_size, kernel_size, 2)
40
+ xx (ndarray): with the shape (kernel_size, kernel_size)
41
+ yy (ndarray): with the shape (kernel_size, kernel_size)
42
+ """
43
+ ax = np.arange(-kernel_size // 2 + 1., kernel_size // 2 + 1.)
44
+ xx, yy = np.meshgrid(ax, ax)
45
+ xy = np.hstack((xx.reshape((kernel_size * kernel_size, 1)), yy.reshape(kernel_size * kernel_size,
46
+ 1))).reshape(kernel_size, kernel_size, 2)
47
+ return xy, xx, yy
48
+
49
+
50
+ def pdf2(sigma_matrix, grid):
51
+ """Calculate PDF of the bivariate Gaussian distribution.
52
+
53
+ Args:
54
+ sigma_matrix (ndarray): with the shape (2, 2)
55
+ grid (ndarray): generated by :func:`mesh_grid`,
56
+ with the shape (K, K, 2), K is the kernel size.
57
+
58
+ Returns:
59
+ kernel (ndarrray): un-normalized kernel.
60
+ """
61
+ inverse_sigma = np.linalg.inv(sigma_matrix)
62
+ kernel = np.exp(-0.5 * np.sum(np.dot(grid, inverse_sigma) * grid, 2))
63
+ return kernel
64
+
65
+
66
+ def cdf2(d_matrix, grid):
67
+ """Calculate the CDF of the standard bivariate Gaussian distribution.
68
+ Used in skewed Gaussian distribution.
69
+
70
+ Args:
71
+ d_matrix (ndarrasy): skew matrix.
72
+ grid (ndarray): generated by :func:`mesh_grid`,
73
+ with the shape (K, K, 2), K is the kernel size.
74
+
75
+ Returns:
76
+ cdf (ndarray): skewed cdf.
77
+ """
78
+ rv = multivariate_normal([0, 0], [[1, 0], [0, 1]])
79
+ grid = np.dot(grid, d_matrix)
80
+ cdf = rv.cdf(grid)
81
+ return cdf
82
+
83
+
84
+ def bivariate_Gaussian(kernel_size, sig_x, sig_y, theta, grid=None, isotropic=True):
85
+ """Generate a bivariate isotropic or anisotropic Gaussian kernel.
86
+
87
+ In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.
88
+
89
+ Args:
90
+ kernel_size (int):
91
+ sig_x (float):
92
+ sig_y (float):
93
+ theta (float): Radian measurement.
94
+ grid (ndarray, optional): generated by :func:`mesh_grid`,
95
+ with the shape (K, K, 2), K is the kernel size. Default: None
96
+ isotropic (bool):
97
+
98
+ Returns:
99
+ kernel (ndarray): normalized kernel.
100
+ """
101
+ if grid is None:
102
+ grid, _, _ = mesh_grid(kernel_size)
103
+ if isotropic:
104
+ sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]])
105
+ else:
106
+ sigma_matrix = sigma_matrix2(sig_x, sig_y, theta)
107
+ kernel = pdf2(sigma_matrix, grid)
108
+ kernel = kernel / np.sum(kernel)
109
+ return kernel
110
+
111
+
112
+ def bivariate_generalized_Gaussian(kernel_size, sig_x, sig_y, theta, beta, grid=None, isotropic=True):
113
+ """Generate a bivariate generalized Gaussian kernel.
114
+
115
+ ``Paper: Parameter Estimation For Multivariate Generalized Gaussian Distributions``
116
+
117
+ In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.
118
+
119
+ Args:
120
+ kernel_size (int):
121
+ sig_x (float):
122
+ sig_y (float):
123
+ theta (float): Radian measurement.
124
+ beta (float): shape parameter, beta = 1 is the normal distribution.
125
+ grid (ndarray, optional): generated by :func:`mesh_grid`,
126
+ with the shape (K, K, 2), K is the kernel size. Default: None
127
+
128
+ Returns:
129
+ kernel (ndarray): normalized kernel.
130
+ """
131
+ if grid is None:
132
+ grid, _, _ = mesh_grid(kernel_size)
133
+ if isotropic:
134
+ sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]])
135
+ else:
136
+ sigma_matrix = sigma_matrix2(sig_x, sig_y, theta)
137
+ inverse_sigma = np.linalg.inv(sigma_matrix)
138
+ kernel = np.exp(-0.5 * np.power(np.sum(np.dot(grid, inverse_sigma) * grid, 2), beta))
139
+ kernel = kernel / np.sum(kernel)
140
+ return kernel
141
+
142
+
143
+ def bivariate_plateau(kernel_size, sig_x, sig_y, theta, beta, grid=None, isotropic=True):
144
+ """Generate a plateau-like anisotropic kernel.
145
+
146
+ 1 / (1+x^(beta))
147
+
148
+ Reference: https://stats.stackexchange.com/questions/203629/is-there-a-plateau-shaped-distribution
149
+
150
+ In the isotropic mode, only `sig_x` is used. `sig_y` and `theta` is ignored.
151
+
152
+ Args:
153
+ kernel_size (int):
154
+ sig_x (float):
155
+ sig_y (float):
156
+ theta (float): Radian measurement.
157
+ beta (float): shape parameter, beta = 1 is the normal distribution.
158
+ grid (ndarray, optional): generated by :func:`mesh_grid`,
159
+ with the shape (K, K, 2), K is the kernel size. Default: None
160
+
161
+ Returns:
162
+ kernel (ndarray): normalized kernel.
163
+ """
164
+ if grid is None:
165
+ grid, _, _ = mesh_grid(kernel_size)
166
+ if isotropic:
167
+ sigma_matrix = np.array([[sig_x**2, 0], [0, sig_x**2]])
168
+ else:
169
+ sigma_matrix = sigma_matrix2(sig_x, sig_y, theta)
170
+ inverse_sigma = np.linalg.inv(sigma_matrix)
171
+ kernel = np.reciprocal(np.power(np.sum(np.dot(grid, inverse_sigma) * grid, 2), beta) + 1)
172
+ kernel = kernel / np.sum(kernel)
173
+ return kernel
174
+
175
+
176
+ def random_bivariate_Gaussian(kernel_size,
177
+ sigma_x_range,
178
+ sigma_y_range,
179
+ rotation_range,
180
+ noise_range=None,
181
+ isotropic=True):
182
+ """Randomly generate bivariate isotropic or anisotropic Gaussian kernels.
183
+
184
+ In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.
185
+
186
+ Args:
187
+ kernel_size (int):
188
+ sigma_x_range (tuple): [0.6, 5]
189
+ sigma_y_range (tuple): [0.6, 5]
190
+ rotation range (tuple): [-math.pi, math.pi]
191
+ noise_range(tuple, optional): multiplicative kernel noise,
192
+ [0.75, 1.25]. Default: None
193
+
194
+ Returns:
195
+ kernel (ndarray):
196
+ """
197
+ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.'
198
+ assert sigma_x_range[0] < sigma_x_range[1], 'Wrong sigma_x_range.'
199
+ sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1])
200
+ if isotropic is False:
201
+ assert sigma_y_range[0] < sigma_y_range[1], 'Wrong sigma_y_range.'
202
+ assert rotation_range[0] < rotation_range[1], 'Wrong rotation_range.'
203
+ sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1])
204
+ rotation = np.random.uniform(rotation_range[0], rotation_range[1])
205
+ else:
206
+ sigma_y = sigma_x
207
+ rotation = 0
208
+
209
+ kernel = bivariate_Gaussian(kernel_size, sigma_x, sigma_y, rotation, isotropic=isotropic)
210
+
211
+ # add multiplicative noise
212
+ if noise_range is not None:
213
+ assert noise_range[0] < noise_range[1], 'Wrong noise range.'
214
+ noise = np.random.uniform(noise_range[0], noise_range[1], size=kernel.shape)
215
+ kernel = kernel * noise
216
+ kernel = kernel / np.sum(kernel)
217
+ return kernel
218
+
219
+
220
+ def random_bivariate_generalized_Gaussian(kernel_size,
221
+ sigma_x_range,
222
+ sigma_y_range,
223
+ rotation_range,
224
+ beta_range,
225
+ noise_range=None,
226
+ isotropic=True):
227
+ """Randomly generate bivariate generalized Gaussian kernels.
228
+
229
+ In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.
230
+
231
+ Args:
232
+ kernel_size (int):
233
+ sigma_x_range (tuple): [0.6, 5]
234
+ sigma_y_range (tuple): [0.6, 5]
235
+ rotation range (tuple): [-math.pi, math.pi]
236
+ beta_range (tuple): [0.5, 8]
237
+ noise_range(tuple, optional): multiplicative kernel noise,
238
+ [0.75, 1.25]. Default: None
239
+
240
+ Returns:
241
+ kernel (ndarray):
242
+ """
243
+ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.'
244
+ assert sigma_x_range[0] < sigma_x_range[1], 'Wrong sigma_x_range.'
245
+ sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1])
246
+ if isotropic is False:
247
+ assert sigma_y_range[0] < sigma_y_range[1], 'Wrong sigma_y_range.'
248
+ assert rotation_range[0] < rotation_range[1], 'Wrong rotation_range.'
249
+ sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1])
250
+ rotation = np.random.uniform(rotation_range[0], rotation_range[1])
251
+ else:
252
+ sigma_y = sigma_x
253
+ rotation = 0
254
+
255
+ # assume beta_range[0] < 1 < beta_range[1]
256
+ if np.random.uniform() < 0.5:
257
+ beta = np.random.uniform(beta_range[0], 1)
258
+ else:
259
+ beta = np.random.uniform(1, beta_range[1])
260
+
261
+ kernel = bivariate_generalized_Gaussian(kernel_size, sigma_x, sigma_y, rotation, beta, isotropic=isotropic)
262
+
263
+ # add multiplicative noise
264
+ if noise_range is not None:
265
+ assert noise_range[0] < noise_range[1], 'Wrong noise range.'
266
+ noise = np.random.uniform(noise_range[0], noise_range[1], size=kernel.shape)
267
+ kernel = kernel * noise
268
+ kernel = kernel / np.sum(kernel)
269
+ return kernel
270
+
271
+
272
+ def random_bivariate_plateau(kernel_size,
273
+ sigma_x_range,
274
+ sigma_y_range,
275
+ rotation_range,
276
+ beta_range,
277
+ noise_range=None,
278
+ isotropic=True):
279
+ """Randomly generate bivariate plateau kernels.
280
+
281
+ In the isotropic mode, only `sigma_x_range` is used. `sigma_y_range` and `rotation_range` is ignored.
282
+
283
+ Args:
284
+ kernel_size (int):
285
+ sigma_x_range (tuple): [0.6, 5]
286
+ sigma_y_range (tuple): [0.6, 5]
287
+ rotation range (tuple): [-math.pi/2, math.pi/2]
288
+ beta_range (tuple): [1, 4]
289
+ noise_range(tuple, optional): multiplicative kernel noise,
290
+ [0.75, 1.25]. Default: None
291
+
292
+ Returns:
293
+ kernel (ndarray):
294
+ """
295
+ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.'
296
+ assert sigma_x_range[0] < sigma_x_range[1], 'Wrong sigma_x_range.'
297
+ sigma_x = np.random.uniform(sigma_x_range[0], sigma_x_range[1])
298
+ if isotropic is False:
299
+ assert sigma_y_range[0] < sigma_y_range[1], 'Wrong sigma_y_range.'
300
+ assert rotation_range[0] < rotation_range[1], 'Wrong rotation_range.'
301
+ sigma_y = np.random.uniform(sigma_y_range[0], sigma_y_range[1])
302
+ rotation = np.random.uniform(rotation_range[0], rotation_range[1])
303
+ else:
304
+ sigma_y = sigma_x
305
+ rotation = 0
306
+
307
+ # TODO: this may be not proper
308
+ if np.random.uniform() < 0.5:
309
+ beta = np.random.uniform(beta_range[0], 1)
310
+ else:
311
+ beta = np.random.uniform(1, beta_range[1])
312
+
313
+ kernel = bivariate_plateau(kernel_size, sigma_x, sigma_y, rotation, beta, isotropic=isotropic)
314
+ # add multiplicative noise
315
+ if noise_range is not None:
316
+ assert noise_range[0] < noise_range[1], 'Wrong noise range.'
317
+ noise = np.random.uniform(noise_range[0], noise_range[1], size=kernel.shape)
318
+ kernel = kernel * noise
319
+ kernel = kernel / np.sum(kernel)
320
+
321
+ return kernel
322
+
323
+
324
+ def random_mixed_kernels(kernel_list,
325
+ kernel_prob,
326
+ kernel_size=21,
327
+ sigma_x_range=(0.6, 5),
328
+ sigma_y_range=(0.6, 5),
329
+ rotation_range=(-math.pi, math.pi),
330
+ betag_range=(0.5, 8),
331
+ betap_range=(0.5, 8),
332
+ noise_range=None):
333
+ """Randomly generate mixed kernels.
334
+
335
+ Args:
336
+ kernel_list (tuple): a list name of kernel types,
337
+ support ['iso', 'aniso', 'skew', 'generalized', 'plateau_iso',
338
+ 'plateau_aniso']
339
+ kernel_prob (tuple): corresponding kernel probability for each
340
+ kernel type
341
+ kernel_size (int):
342
+ sigma_x_range (tuple): [0.6, 5]
343
+ sigma_y_range (tuple): [0.6, 5]
344
+ rotation range (tuple): [-math.pi, math.pi]
345
+ beta_range (tuple): [0.5, 8]
346
+ noise_range(tuple, optional): multiplicative kernel noise,
347
+ [0.75, 1.25]. Default: None
348
+
349
+ Returns:
350
+ kernel (ndarray):
351
+ """
352
+ kernel_type = random.choices(kernel_list, kernel_prob)[0]
353
+ if kernel_type == 'iso':
354
+ kernel = random_bivariate_Gaussian(
355
+ kernel_size, sigma_x_range, sigma_y_range, rotation_range, noise_range=noise_range, isotropic=True)
356
+ elif kernel_type == 'aniso':
357
+ kernel = random_bivariate_Gaussian(
358
+ kernel_size, sigma_x_range, sigma_y_range, rotation_range, noise_range=noise_range, isotropic=False)
359
+ elif kernel_type == 'generalized_iso':
360
+ kernel = random_bivariate_generalized_Gaussian(
361
+ kernel_size,
362
+ sigma_x_range,
363
+ sigma_y_range,
364
+ rotation_range,
365
+ betag_range,
366
+ noise_range=noise_range,
367
+ isotropic=True)
368
+ elif kernel_type == 'generalized_aniso':
369
+ kernel = random_bivariate_generalized_Gaussian(
370
+ kernel_size,
371
+ sigma_x_range,
372
+ sigma_y_range,
373
+ rotation_range,
374
+ betag_range,
375
+ noise_range=noise_range,
376
+ isotropic=False)
377
+ elif kernel_type == 'plateau_iso':
378
+ kernel = random_bivariate_plateau(
379
+ kernel_size, sigma_x_range, sigma_y_range, rotation_range, betap_range, noise_range=None, isotropic=True)
380
+ elif kernel_type == 'plateau_aniso':
381
+ kernel = random_bivariate_plateau(
382
+ kernel_size, sigma_x_range, sigma_y_range, rotation_range, betap_range, noise_range=None, isotropic=False)
383
+ return kernel
384
+
385
+
386
+ np.seterr(divide='ignore', invalid='ignore')
387
+
388
+
389
+ def circular_lowpass_kernel(cutoff, kernel_size, pad_to=0):
390
+ """2D sinc filter
391
+
392
+ Reference: https://dsp.stackexchange.com/questions/58301/2-d-circularly-symmetric-low-pass-filter
393
+
394
+ Args:
395
+ cutoff (float): cutoff frequency in radians (pi is max)
396
+ kernel_size (int): horizontal and vertical size, must be odd.
397
+ pad_to (int): pad kernel size to desired size, must be odd or zero.
398
+ """
399
+ assert kernel_size % 2 == 1, 'Kernel size must be an odd number.'
400
+ kernel = np.fromfunction(
401
+ lambda x, y: cutoff * special.j1(cutoff * np.sqrt(
402
+ (x - (kernel_size - 1) / 2)**2 + (y - (kernel_size - 1) / 2)**2)) / (2 * np.pi * np.sqrt(
403
+ (x - (kernel_size - 1) / 2)**2 + (y - (kernel_size - 1) / 2)**2)), [kernel_size, kernel_size])
404
+ kernel[(kernel_size - 1) // 2, (kernel_size - 1) // 2] = cutoff**2 / (4 * np.pi)
405
+ kernel = kernel / np.sum(kernel)
406
+ if pad_to > kernel_size:
407
+ pad_size = (pad_to - kernel_size) // 2
408
+ kernel = np.pad(kernel, ((pad_size, pad_size), (pad_size, pad_size)))
409
+ return kernel
410
+
411
+
412
+ # ------------------------------------------------------------- #
413
+ # --------------------------- noise --------------------------- #
414
+ # ------------------------------------------------------------- #
415
+
416
+ # ----------------------- Gaussian Noise ----------------------- #
417
+
418
+
419
+ def generate_gaussian_noise(img, sigma=10, gray_noise=False):
420
+ """Generate Gaussian noise.
421
+
422
+ Args:
423
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
424
+ sigma (float): Noise scale (measured in range 255). Default: 10.
425
+
426
+ Returns:
427
+ (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
428
+ float32.
429
+ """
430
+ if gray_noise:
431
+ noise = np.float32(np.random.randn(*(img.shape[0:2]))) * sigma / 255.
432
+ noise = np.expand_dims(noise, axis=2).repeat(3, axis=2)
433
+ else:
434
+ noise = np.float32(np.random.randn(*(img.shape))) * sigma / 255.
435
+ return noise
436
+
437
+
438
+ def add_gaussian_noise(img, sigma=10, clip=True, rounds=False, gray_noise=False):
439
+ """Add Gaussian noise.
440
+
441
+ Args:
442
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
443
+ sigma (float): Noise scale (measured in range 255). Default: 10.
444
+
445
+ Returns:
446
+ (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
447
+ float32.
448
+ """
449
+ noise = generate_gaussian_noise(img, sigma, gray_noise)
450
+ out = img + noise
451
+ if clip and rounds:
452
+ out = np.clip((out * 255.0).round(), 0, 255) / 255.
453
+ elif clip:
454
+ out = np.clip(out, 0, 1)
455
+ elif rounds:
456
+ out = (out * 255.0).round() / 255.
457
+ return out
458
+
459
+
460
+ def generate_gaussian_noise_pt(img, sigma=10, gray_noise=0):
461
+ """Add Gaussian noise (PyTorch version).
462
+
463
+ Args:
464
+ img (Tensor): Shape (b, c, h, w), range[0, 1], float32.
465
+ scale (float | Tensor): Noise scale. Default: 1.0.
466
+
467
+ Returns:
468
+ (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
469
+ float32.
470
+ """
471
+ b, _, h, w = img.size()
472
+ if not isinstance(sigma, (float, int)):
473
+ sigma = sigma.view(img.size(0), 1, 1, 1)
474
+ if isinstance(gray_noise, (float, int)):
475
+ cal_gray_noise = gray_noise > 0
476
+ else:
477
+ gray_noise = gray_noise.view(b, 1, 1, 1)
478
+ cal_gray_noise = torch.sum(gray_noise) > 0
479
+
480
+ if cal_gray_noise:
481
+ noise_gray = torch.randn(*img.size()[2:4], dtype=img.dtype, device=img.device) * sigma / 255.
482
+ noise_gray = noise_gray.view(b, 1, h, w)
483
+
484
+ # always calculate color noise
485
+ noise = torch.randn(*img.size(), dtype=img.dtype, device=img.device) * sigma / 255.
486
+
487
+ if cal_gray_noise:
488
+ noise = noise * (1 - gray_noise) + noise_gray * gray_noise
489
+ return noise
490
+
491
+
492
+ def add_gaussian_noise_pt(img, sigma=10, gray_noise=0, clip=True, rounds=False):
493
+ """Add Gaussian noise (PyTorch version).
494
+
495
+ Args:
496
+ img (Tensor): Shape (b, c, h, w), range[0, 1], float32.
497
+ scale (float | Tensor): Noise scale. Default: 1.0.
498
+
499
+ Returns:
500
+ (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
501
+ float32.
502
+ """
503
+ noise = generate_gaussian_noise_pt(img, sigma, gray_noise)
504
+ out = img + noise
505
+ if clip and rounds:
506
+ out = torch.clamp((out * 255.0).round(), 0, 255) / 255.
507
+ elif clip:
508
+ out = torch.clamp(out, 0, 1)
509
+ elif rounds:
510
+ out = (out * 255.0).round() / 255.
511
+ return out
512
+
513
+
514
+ # ----------------------- Random Gaussian Noise ----------------------- #
515
+ def random_generate_gaussian_noise(img, sigma_range=(0, 10), gray_prob=0):
516
+ sigma = np.random.uniform(sigma_range[0], sigma_range[1])
517
+ if np.random.uniform() < gray_prob:
518
+ gray_noise = True
519
+ else:
520
+ gray_noise = False
521
+ return generate_gaussian_noise(img, sigma, gray_noise)
522
+
523
+
524
+ def random_add_gaussian_noise(img, sigma_range=(0, 1.0), gray_prob=0, clip=True, rounds=False):
525
+ noise = random_generate_gaussian_noise(img, sigma_range, gray_prob)
526
+ out = img + noise
527
+ if clip and rounds:
528
+ out = np.clip((out * 255.0).round(), 0, 255) / 255.
529
+ elif clip:
530
+ out = np.clip(out, 0, 1)
531
+ elif rounds:
532
+ out = (out * 255.0).round() / 255.
533
+ return out
534
+
535
+
536
+ def random_generate_gaussian_noise_pt(img, sigma_range=(0, 10), gray_prob=0):
537
+ sigma = torch.rand(
538
+ img.size(0), dtype=img.dtype, device=img.device) * (sigma_range[1] - sigma_range[0]) + sigma_range[0]
539
+ gray_noise = torch.rand(img.size(0), dtype=img.dtype, device=img.device)
540
+ gray_noise = (gray_noise < gray_prob).float()
541
+ return generate_gaussian_noise_pt(img, sigma, gray_noise)
542
+
543
+
544
+ def random_add_gaussian_noise_pt(img, sigma_range=(0, 1.0), gray_prob=0, clip=True, rounds=False):
545
+ noise = random_generate_gaussian_noise_pt(img, sigma_range, gray_prob)
546
+ out = img + noise
547
+ if clip and rounds:
548
+ out = torch.clamp((out * 255.0).round(), 0, 255) / 255.
549
+ elif clip:
550
+ out = torch.clamp(out, 0, 1)
551
+ elif rounds:
552
+ out = (out * 255.0).round() / 255.
553
+ return out
554
+
555
+
556
+ # ----------------------- Poisson (Shot) Noise ----------------------- #
557
+
558
+
559
+ def generate_poisson_noise(img, scale=1.0, gray_noise=False):
560
+ """Generate poisson noise.
561
+
562
+ Reference: https://github.com/scikit-image/scikit-image/blob/main/skimage/util/noise.py#L37-L219
563
+
564
+ Args:
565
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
566
+ scale (float): Noise scale. Default: 1.0.
567
+ gray_noise (bool): Whether generate gray noise. Default: False.
568
+
569
+ Returns:
570
+ (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
571
+ float32.
572
+ """
573
+ if gray_noise:
574
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
575
+ # round and clip image for counting vals correctly
576
+ img = np.clip((img * 255.0).round(), 0, 255) / 255.
577
+ vals = len(np.unique(img))
578
+ vals = 2**np.ceil(np.log2(vals))
579
+ out = np.float32(np.random.poisson(img * vals) / float(vals))
580
+ noise = out - img
581
+ if gray_noise:
582
+ noise = np.repeat(noise[:, :, np.newaxis], 3, axis=2)
583
+ return noise * scale
584
+
585
+
586
+ def add_poisson_noise(img, scale=1.0, clip=True, rounds=False, gray_noise=False):
587
+ """Add poisson noise.
588
+
589
+ Args:
590
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
591
+ scale (float): Noise scale. Default: 1.0.
592
+ gray_noise (bool): Whether generate gray noise. Default: False.
593
+
594
+ Returns:
595
+ (Numpy array): Returned noisy image, shape (h, w, c), range[0, 1],
596
+ float32.
597
+ """
598
+ noise = generate_poisson_noise(img, scale, gray_noise)
599
+ out = img + noise
600
+ if clip and rounds:
601
+ out = np.clip((out * 255.0).round(), 0, 255) / 255.
602
+ elif clip:
603
+ out = np.clip(out, 0, 1)
604
+ elif rounds:
605
+ out = (out * 255.0).round() / 255.
606
+ return out
607
+
608
+
609
+ def generate_poisson_noise_pt(img, scale=1.0, gray_noise=0):
610
+ """Generate a batch of poisson noise (PyTorch version)
611
+
612
+ Args:
613
+ img (Tensor): Input image, shape (b, c, h, w), range [0, 1], float32.
614
+ scale (float | Tensor): Noise scale. Number or Tensor with shape (b).
615
+ Default: 1.0.
616
+ gray_noise (float | Tensor): 0-1 number or Tensor with shape (b).
617
+ 0 for False, 1 for True. Default: 0.
618
+
619
+ Returns:
620
+ (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
621
+ float32.
622
+ """
623
+ b, _, h, w = img.size()
624
+ if isinstance(gray_noise, (float, int)):
625
+ cal_gray_noise = gray_noise > 0
626
+ else:
627
+ gray_noise = gray_noise.view(b, 1, 1, 1)
628
+ cal_gray_noise = torch.sum(gray_noise) > 0
629
+ if cal_gray_noise:
630
+ img_gray = rgb_to_grayscale(img, num_output_channels=1)
631
+ # round and clip image for counting vals correctly
632
+ img_gray = torch.clamp((img_gray * 255.0).round(), 0, 255) / 255.
633
+ # use for-loop to get the unique values for each sample
634
+ vals_list = [len(torch.unique(img_gray[i, :, :, :])) for i in range(b)]
635
+ vals_list = [2**np.ceil(np.log2(vals)) for vals in vals_list]
636
+ vals = img_gray.new_tensor(vals_list).view(b, 1, 1, 1)
637
+ out = torch.poisson(img_gray * vals) / vals
638
+ noise_gray = out - img_gray
639
+ noise_gray = noise_gray.expand(b, 3, h, w)
640
+
641
+ # always calculate color noise
642
+ # round and clip image for counting vals correctly
643
+ img = torch.clamp((img * 255.0).round(), 0, 255) / 255.
644
+ # use for-loop to get the unique values for each sample
645
+ vals_list = [len(torch.unique(img[i, :, :, :])) for i in range(b)]
646
+ vals_list = [2**np.ceil(np.log2(vals)) for vals in vals_list]
647
+ vals = img.new_tensor(vals_list).view(b, 1, 1, 1)
648
+ out = torch.poisson(img * vals) / vals
649
+ noise = out - img
650
+ if cal_gray_noise:
651
+ noise = noise * (1 - gray_noise) + noise_gray * gray_noise
652
+ if not isinstance(scale, (float, int)):
653
+ scale = scale.view(b, 1, 1, 1)
654
+ return noise * scale
655
+
656
+
657
+ def add_poisson_noise_pt(img, scale=1.0, clip=True, rounds=False, gray_noise=0):
658
+ """Add poisson noise to a batch of images (PyTorch version).
659
+
660
+ Args:
661
+ img (Tensor): Input image, shape (b, c, h, w), range [0, 1], float32.
662
+ scale (float | Tensor): Noise scale. Number or Tensor with shape (b).
663
+ Default: 1.0.
664
+ gray_noise (float | Tensor): 0-1 number or Tensor with shape (b).
665
+ 0 for False, 1 for True. Default: 0.
666
+
667
+ Returns:
668
+ (Tensor): Returned noisy image, shape (b, c, h, w), range[0, 1],
669
+ float32.
670
+ """
671
+ noise = generate_poisson_noise_pt(img, scale, gray_noise)
672
+ out = img + noise
673
+ if clip and rounds:
674
+ out = torch.clamp((out * 255.0).round(), 0, 255) / 255.
675
+ elif clip:
676
+ out = torch.clamp(out, 0, 1)
677
+ elif rounds:
678
+ out = (out * 255.0).round() / 255.
679
+ return out
680
+
681
+
682
+ # ----------------------- Random Poisson (Shot) Noise ----------------------- #
683
+
684
+
685
+ def random_generate_poisson_noise(img, scale_range=(0, 1.0), gray_prob=0):
686
+ scale = np.random.uniform(scale_range[0], scale_range[1])
687
+ if np.random.uniform() < gray_prob:
688
+ gray_noise = True
689
+ else:
690
+ gray_noise = False
691
+ return generate_poisson_noise(img, scale, gray_noise)
692
+
693
+
694
+ def random_add_poisson_noise(img, scale_range=(0, 1.0), gray_prob=0, clip=True, rounds=False):
695
+ noise = random_generate_poisson_noise(img, scale_range, gray_prob)
696
+ out = img + noise
697
+ if clip and rounds:
698
+ out = np.clip((out * 255.0).round(), 0, 255) / 255.
699
+ elif clip:
700
+ out = np.clip(out, 0, 1)
701
+ elif rounds:
702
+ out = (out * 255.0).round() / 255.
703
+ return out
704
+
705
+
706
+ def random_generate_poisson_noise_pt(img, scale_range=(0, 1.0), gray_prob=0):
707
+ scale = torch.rand(
708
+ img.size(0), dtype=img.dtype, device=img.device) * (scale_range[1] - scale_range[0]) + scale_range[0]
709
+ gray_noise = torch.rand(img.size(0), dtype=img.dtype, device=img.device)
710
+ gray_noise = (gray_noise < gray_prob).float()
711
+ return generate_poisson_noise_pt(img, scale, gray_noise)
712
+
713
+
714
+ def random_add_poisson_noise_pt(img, scale_range=(0, 1.0), gray_prob=0, clip=True, rounds=False):
715
+ noise = random_generate_poisson_noise_pt(img, scale_range, gray_prob)
716
+ out = img + noise
717
+ if clip and rounds:
718
+ out = torch.clamp((out * 255.0).round(), 0, 255) / 255.
719
+ elif clip:
720
+ out = torch.clamp(out, 0, 1)
721
+ elif rounds:
722
+ out = (out * 255.0).round() / 255.
723
+ return out
724
+
725
+
726
+ # ------------------------------------------------------------------------ #
727
+ # --------------------------- JPEG compression --------------------------- #
728
+ # ------------------------------------------------------------------------ #
729
+
730
+
731
+ def add_jpg_compression(img, quality=90):
732
+ """Add JPG compression artifacts.
733
+
734
+ Args:
735
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
736
+ quality (float): JPG compression quality. 0 for lowest quality, 100 for
737
+ best quality. Default: 90.
738
+
739
+ Returns:
740
+ (Numpy array): Returned image after JPG, shape (h, w, c), range[0, 1],
741
+ float32.
742
+ """
743
+ img = np.clip(img, 0, 1)
744
+ encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), quality]
745
+ _, encimg = cv2.imencode('.jpg', img * 255., encode_param)
746
+ img = np.float32(cv2.imdecode(encimg, 1)) / 255.
747
+ return img
748
+
749
+
750
+ def random_add_jpg_compression(img, quality_range=(90, 100)):
751
+ """Randomly add JPG compression artifacts.
752
+
753
+ Args:
754
+ img (Numpy array): Input image, shape (h, w, c), range [0, 1], float32.
755
+ quality_range (tuple[float] | list[float]): JPG compression quality
756
+ range. 0 for lowest quality, 100 for best quality.
757
+ Default: (90, 100).
758
+
759
+ Returns:
760
+ (Numpy array): Returned image after JPG, shape (h, w, c), range[0, 1],
761
+ float32.
762
+ """
763
+ quality = np.random.uniform(quality_range[0], quality_range[1])
764
+ return add_jpg_compression(img, quality)
basicsr/data/ffhq_dataset.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import time
3
+ from os import path as osp
4
+ from torch.utils import data as data
5
+ from torchvision.transforms.functional import normalize
6
+
7
+ from basicsr.data.transforms import augment
8
+ from basicsr.utils import FileClient, get_root_logger, imfrombytes, img2tensor
9
+ from basicsr.utils.registry import DATASET_REGISTRY
10
+
11
+
12
+ @DATASET_REGISTRY.register()
13
+ class FFHQDataset(data.Dataset):
14
+ """FFHQ dataset for StyleGAN.
15
+
16
+ Args:
17
+ opt (dict): Config for train datasets. It contains the following keys:
18
+ dataroot_gt (str): Data root path for gt.
19
+ io_backend (dict): IO backend type and other kwarg.
20
+ mean (list | tuple): Image mean.
21
+ std (list | tuple): Image std.
22
+ use_hflip (bool): Whether to horizontally flip.
23
+
24
+ """
25
+
26
+ def __init__(self, opt):
27
+ super(FFHQDataset, self).__init__()
28
+ self.opt = opt
29
+ # file client (io backend)
30
+ self.file_client = None
31
+ self.io_backend_opt = opt['io_backend']
32
+
33
+ self.gt_folder = opt['dataroot_gt']
34
+ self.mean = opt['mean']
35
+ self.std = opt['std']
36
+
37
+ if self.io_backend_opt['type'] == 'lmdb':
38
+ self.io_backend_opt['db_paths'] = self.gt_folder
39
+ if not self.gt_folder.endswith('.lmdb'):
40
+ raise ValueError("'dataroot_gt' should end with '.lmdb', but received {self.gt_folder}")
41
+ with open(osp.join(self.gt_folder, 'meta_info.txt')) as fin:
42
+ self.paths = [line.split('.')[0] for line in fin]
43
+ else:
44
+ # FFHQ has 70000 images in total
45
+ self.paths = [osp.join(self.gt_folder, f'{v:08d}.png') for v in range(70000)]
46
+
47
+ def __getitem__(self, index):
48
+ if self.file_client is None:
49
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
50
+
51
+ # load gt image
52
+ gt_path = self.paths[index]
53
+ # avoid errors caused by high latency in reading files
54
+ retry = 3
55
+ while retry > 0:
56
+ try:
57
+ img_bytes = self.file_client.get(gt_path)
58
+ except Exception as e:
59
+ logger = get_root_logger()
60
+ logger.warning(f'File client error: {e}, remaining retry times: {retry - 1}')
61
+ # change another file to read
62
+ index = random.randint(0, self.__len__())
63
+ gt_path = self.paths[index]
64
+ time.sleep(1) # sleep 1s for occasional server congestion
65
+ else:
66
+ break
67
+ finally:
68
+ retry -= 1
69
+ img_gt = imfrombytes(img_bytes, float32=True)
70
+
71
+ # random horizontal flip
72
+ img_gt = augment(img_gt, hflip=self.opt['use_hflip'], rotation=False)
73
+ # BGR to RGB, HWC to CHW, numpy to tensor
74
+ img_gt = img2tensor(img_gt, bgr2rgb=True, float32=True)
75
+ # normalize
76
+ normalize(img_gt, self.mean, self.std, inplace=True)
77
+ return {'gt': img_gt, 'gt_path': gt_path}
78
+
79
+ def __len__(self):
80
+ return len(self.paths)
basicsr/data/meta_info/meta_info_DIV2K800sub_GT.txt ADDED
The diff for this file is too large to render. See raw diff
 
basicsr/data/meta_info/meta_info_REDS4_test_GT.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ 000 100 (720,1280,3)
2
+ 011 100 (720,1280,3)
3
+ 015 100 (720,1280,3)
4
+ 020 100 (720,1280,3)
basicsr/data/meta_info/meta_info_REDS_GT.txt ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 000 100 (720,1280,3)
2
+ 001 100 (720,1280,3)
3
+ 002 100 (720,1280,3)
4
+ 003 100 (720,1280,3)
5
+ 004 100 (720,1280,3)
6
+ 005 100 (720,1280,3)
7
+ 006 100 (720,1280,3)
8
+ 007 100 (720,1280,3)
9
+ 008 100 (720,1280,3)
10
+ 009 100 (720,1280,3)
11
+ 010 100 (720,1280,3)
12
+ 011 100 (720,1280,3)
13
+ 012 100 (720,1280,3)
14
+ 013 100 (720,1280,3)
15
+ 014 100 (720,1280,3)
16
+ 015 100 (720,1280,3)
17
+ 016 100 (720,1280,3)
18
+ 017 100 (720,1280,3)
19
+ 018 100 (720,1280,3)
20
+ 019 100 (720,1280,3)
21
+ 020 100 (720,1280,3)
22
+ 021 100 (720,1280,3)
23
+ 022 100 (720,1280,3)
24
+ 023 100 (720,1280,3)
25
+ 024 100 (720,1280,3)
26
+ 025 100 (720,1280,3)
27
+ 026 100 (720,1280,3)
28
+ 027 100 (720,1280,3)
29
+ 028 100 (720,1280,3)
30
+ 029 100 (720,1280,3)
31
+ 030 100 (720,1280,3)
32
+ 031 100 (720,1280,3)
33
+ 032 100 (720,1280,3)
34
+ 033 100 (720,1280,3)
35
+ 034 100 (720,1280,3)
36
+ 035 100 (720,1280,3)
37
+ 036 100 (720,1280,3)
38
+ 037 100 (720,1280,3)
39
+ 038 100 (720,1280,3)
40
+ 039 100 (720,1280,3)
41
+ 040 100 (720,1280,3)
42
+ 041 100 (720,1280,3)
43
+ 042 100 (720,1280,3)
44
+ 043 100 (720,1280,3)
45
+ 044 100 (720,1280,3)
46
+ 045 100 (720,1280,3)
47
+ 046 100 (720,1280,3)
48
+ 047 100 (720,1280,3)
49
+ 048 100 (720,1280,3)
50
+ 049 100 (720,1280,3)
51
+ 050 100 (720,1280,3)
52
+ 051 100 (720,1280,3)
53
+ 052 100 (720,1280,3)
54
+ 053 100 (720,1280,3)
55
+ 054 100 (720,1280,3)
56
+ 055 100 (720,1280,3)
57
+ 056 100 (720,1280,3)
58
+ 057 100 (720,1280,3)
59
+ 058 100 (720,1280,3)
60
+ 059 100 (720,1280,3)
61
+ 060 100 (720,1280,3)
62
+ 061 100 (720,1280,3)
63
+ 062 100 (720,1280,3)
64
+ 063 100 (720,1280,3)
65
+ 064 100 (720,1280,3)
66
+ 065 100 (720,1280,3)
67
+ 066 100 (720,1280,3)
68
+ 067 100 (720,1280,3)
69
+ 068 100 (720,1280,3)
70
+ 069 100 (720,1280,3)
71
+ 070 100 (720,1280,3)
72
+ 071 100 (720,1280,3)
73
+ 072 100 (720,1280,3)
74
+ 073 100 (720,1280,3)
75
+ 074 100 (720,1280,3)
76
+ 075 100 (720,1280,3)
77
+ 076 100 (720,1280,3)
78
+ 077 100 (720,1280,3)
79
+ 078 100 (720,1280,3)
80
+ 079 100 (720,1280,3)
81
+ 080 100 (720,1280,3)
82
+ 081 100 (720,1280,3)
83
+ 082 100 (720,1280,3)
84
+ 083 100 (720,1280,3)
85
+ 084 100 (720,1280,3)
86
+ 085 100 (720,1280,3)
87
+ 086 100 (720,1280,3)
88
+ 087 100 (720,1280,3)
89
+ 088 100 (720,1280,3)
90
+ 089 100 (720,1280,3)
91
+ 090 100 (720,1280,3)
92
+ 091 100 (720,1280,3)
93
+ 092 100 (720,1280,3)
94
+ 093 100 (720,1280,3)
95
+ 094 100 (720,1280,3)
96
+ 095 100 (720,1280,3)
97
+ 096 100 (720,1280,3)
98
+ 097 100 (720,1280,3)
99
+ 098 100 (720,1280,3)
100
+ 099 100 (720,1280,3)
101
+ 100 100 (720,1280,3)
102
+ 101 100 (720,1280,3)
103
+ 102 100 (720,1280,3)
104
+ 103 100 (720,1280,3)
105
+ 104 100 (720,1280,3)
106
+ 105 100 (720,1280,3)
107
+ 106 100 (720,1280,3)
108
+ 107 100 (720,1280,3)
109
+ 108 100 (720,1280,3)
110
+ 109 100 (720,1280,3)
111
+ 110 100 (720,1280,3)
112
+ 111 100 (720,1280,3)
113
+ 112 100 (720,1280,3)
114
+ 113 100 (720,1280,3)
115
+ 114 100 (720,1280,3)
116
+ 115 100 (720,1280,3)
117
+ 116 100 (720,1280,3)
118
+ 117 100 (720,1280,3)
119
+ 118 100 (720,1280,3)
120
+ 119 100 (720,1280,3)
121
+ 120 100 (720,1280,3)
122
+ 121 100 (720,1280,3)
123
+ 122 100 (720,1280,3)
124
+ 123 100 (720,1280,3)
125
+ 124 100 (720,1280,3)
126
+ 125 100 (720,1280,3)
127
+ 126 100 (720,1280,3)
128
+ 127 100 (720,1280,3)
129
+ 128 100 (720,1280,3)
130
+ 129 100 (720,1280,3)
131
+ 130 100 (720,1280,3)
132
+ 131 100 (720,1280,3)
133
+ 132 100 (720,1280,3)
134
+ 133 100 (720,1280,3)
135
+ 134 100 (720,1280,3)
136
+ 135 100 (720,1280,3)
137
+ 136 100 (720,1280,3)
138
+ 137 100 (720,1280,3)
139
+ 138 100 (720,1280,3)
140
+ 139 100 (720,1280,3)
141
+ 140 100 (720,1280,3)
142
+ 141 100 (720,1280,3)
143
+ 142 100 (720,1280,3)
144
+ 143 100 (720,1280,3)
145
+ 144 100 (720,1280,3)
146
+ 145 100 (720,1280,3)
147
+ 146 100 (720,1280,3)
148
+ 147 100 (720,1280,3)
149
+ 148 100 (720,1280,3)
150
+ 149 100 (720,1280,3)
151
+ 150 100 (720,1280,3)
152
+ 151 100 (720,1280,3)
153
+ 152 100 (720,1280,3)
154
+ 153 100 (720,1280,3)
155
+ 154 100 (720,1280,3)
156
+ 155 100 (720,1280,3)
157
+ 156 100 (720,1280,3)
158
+ 157 100 (720,1280,3)
159
+ 158 100 (720,1280,3)
160
+ 159 100 (720,1280,3)
161
+ 160 100 (720,1280,3)
162
+ 161 100 (720,1280,3)
163
+ 162 100 (720,1280,3)
164
+ 163 100 (720,1280,3)
165
+ 164 100 (720,1280,3)
166
+ 165 100 (720,1280,3)
167
+ 166 100 (720,1280,3)
168
+ 167 100 (720,1280,3)
169
+ 168 100 (720,1280,3)
170
+ 169 100 (720,1280,3)
171
+ 170 100 (720,1280,3)
172
+ 171 100 (720,1280,3)
173
+ 172 100 (720,1280,3)
174
+ 173 100 (720,1280,3)
175
+ 174 100 (720,1280,3)
176
+ 175 100 (720,1280,3)
177
+ 176 100 (720,1280,3)
178
+ 177 100 (720,1280,3)
179
+ 178 100 (720,1280,3)
180
+ 179 100 (720,1280,3)
181
+ 180 100 (720,1280,3)
182
+ 181 100 (720,1280,3)
183
+ 182 100 (720,1280,3)
184
+ 183 100 (720,1280,3)
185
+ 184 100 (720,1280,3)
186
+ 185 100 (720,1280,3)
187
+ 186 100 (720,1280,3)
188
+ 187 100 (720,1280,3)
189
+ 188 100 (720,1280,3)
190
+ 189 100 (720,1280,3)
191
+ 190 100 (720,1280,3)
192
+ 191 100 (720,1280,3)
193
+ 192 100 (720,1280,3)
194
+ 193 100 (720,1280,3)
195
+ 194 100 (720,1280,3)
196
+ 195 100 (720,1280,3)
197
+ 196 100 (720,1280,3)
198
+ 197 100 (720,1280,3)
199
+ 198 100 (720,1280,3)
200
+ 199 100 (720,1280,3)
201
+ 200 100 (720,1280,3)
202
+ 201 100 (720,1280,3)
203
+ 202 100 (720,1280,3)
204
+ 203 100 (720,1280,3)
205
+ 204 100 (720,1280,3)
206
+ 205 100 (720,1280,3)
207
+ 206 100 (720,1280,3)
208
+ 207 100 (720,1280,3)
209
+ 208 100 (720,1280,3)
210
+ 209 100 (720,1280,3)
211
+ 210 100 (720,1280,3)
212
+ 211 100 (720,1280,3)
213
+ 212 100 (720,1280,3)
214
+ 213 100 (720,1280,3)
215
+ 214 100 (720,1280,3)
216
+ 215 100 (720,1280,3)
217
+ 216 100 (720,1280,3)
218
+ 217 100 (720,1280,3)
219
+ 218 100 (720,1280,3)
220
+ 219 100 (720,1280,3)
221
+ 220 100 (720,1280,3)
222
+ 221 100 (720,1280,3)
223
+ 222 100 (720,1280,3)
224
+ 223 100 (720,1280,3)
225
+ 224 100 (720,1280,3)
226
+ 225 100 (720,1280,3)
227
+ 226 100 (720,1280,3)
228
+ 227 100 (720,1280,3)
229
+ 228 100 (720,1280,3)
230
+ 229 100 (720,1280,3)
231
+ 230 100 (720,1280,3)
232
+ 231 100 (720,1280,3)
233
+ 232 100 (720,1280,3)
234
+ 233 100 (720,1280,3)
235
+ 234 100 (720,1280,3)
236
+ 235 100 (720,1280,3)
237
+ 236 100 (720,1280,3)
238
+ 237 100 (720,1280,3)
239
+ 238 100 (720,1280,3)
240
+ 239 100 (720,1280,3)
241
+ 240 100 (720,1280,3)
242
+ 241 100 (720,1280,3)
243
+ 242 100 (720,1280,3)
244
+ 243 100 (720,1280,3)
245
+ 244 100 (720,1280,3)
246
+ 245 100 (720,1280,3)
247
+ 246 100 (720,1280,3)
248
+ 247 100 (720,1280,3)
249
+ 248 100 (720,1280,3)
250
+ 249 100 (720,1280,3)
251
+ 250 100 (720,1280,3)
252
+ 251 100 (720,1280,3)
253
+ 252 100 (720,1280,3)
254
+ 253 100 (720,1280,3)
255
+ 254 100 (720,1280,3)
256
+ 255 100 (720,1280,3)
257
+ 256 100 (720,1280,3)
258
+ 257 100 (720,1280,3)
259
+ 258 100 (720,1280,3)
260
+ 259 100 (720,1280,3)
261
+ 260 100 (720,1280,3)
262
+ 261 100 (720,1280,3)
263
+ 262 100 (720,1280,3)
264
+ 263 100 (720,1280,3)
265
+ 264 100 (720,1280,3)
266
+ 265 100 (720,1280,3)
267
+ 266 100 (720,1280,3)
268
+ 267 100 (720,1280,3)
269
+ 268 100 (720,1280,3)
270
+ 269 100 (720,1280,3)
basicsr/data/meta_info/meta_info_REDSofficial4_test_GT.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ 240 100 (720,1280,3)
2
+ 241 100 (720,1280,3)
3
+ 246 100 (720,1280,3)
4
+ 257 100 (720,1280,3)
basicsr/data/meta_info/meta_info_REDSval_official_test_GT.txt ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 240 100 (720,1280,3)
2
+ 241 100 (720,1280,3)
3
+ 242 100 (720,1280,3)
4
+ 243 100 (720,1280,3)
5
+ 244 100 (720,1280,3)
6
+ 245 100 (720,1280,3)
7
+ 246 100 (720,1280,3)
8
+ 247 100 (720,1280,3)
9
+ 248 100 (720,1280,3)
10
+ 249 100 (720,1280,3)
11
+ 250 100 (720,1280,3)
12
+ 251 100 (720,1280,3)
13
+ 252 100 (720,1280,3)
14
+ 253 100 (720,1280,3)
15
+ 254 100 (720,1280,3)
16
+ 255 100 (720,1280,3)
17
+ 256 100 (720,1280,3)
18
+ 257 100 (720,1280,3)
19
+ 258 100 (720,1280,3)
20
+ 259 100 (720,1280,3)
21
+ 260 100 (720,1280,3)
22
+ 261 100 (720,1280,3)
23
+ 262 100 (720,1280,3)
24
+ 263 100 (720,1280,3)
25
+ 264 100 (720,1280,3)
26
+ 265 100 (720,1280,3)
27
+ 266 100 (720,1280,3)
28
+ 267 100 (720,1280,3)
29
+ 268 100 (720,1280,3)
30
+ 269 100 (720,1280,3)
basicsr/data/meta_info/meta_info_Vimeo90K_test_GT.txt ADDED
The diff for this file is too large to render. See raw diff
 
basicsr/data/meta_info/meta_info_Vimeo90K_test_fast_GT.txt ADDED
@@ -0,0 +1,1225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 00001/0625 7 (256,448,3)
2
+ 00001/0632 7 (256,448,3)
3
+ 00001/0807 7 (256,448,3)
4
+ 00001/0832 7 (256,448,3)
5
+ 00001/0834 7 (256,448,3)
6
+ 00001/0836 7 (256,448,3)
7
+ 00002/0004 7 (256,448,3)
8
+ 00002/0112 7 (256,448,3)
9
+ 00002/0116 7 (256,448,3)
10
+ 00002/0123 7 (256,448,3)
11
+ 00002/0455 7 (256,448,3)
12
+ 00002/0602 7 (256,448,3)
13
+ 00002/0976 7 (256,448,3)
14
+ 00002/0980 7 (256,448,3)
15
+ 00002/0983 7 (256,448,3)
16
+ 00002/1000 7 (256,448,3)
17
+ 00003/0022 7 (256,448,3)
18
+ 00003/0031 7 (256,448,3)
19
+ 00003/0035 7 (256,448,3)
20
+ 00003/0041 7 (256,448,3)
21
+ 00003/0073 7 (256,448,3)
22
+ 00003/0107 7 (256,448,3)
23
+ 00003/0111 7 (256,448,3)
24
+ 00003/0114 7 (256,448,3)
25
+ 00003/0117 7 (256,448,3)
26
+ 00003/0121 7 (256,448,3)
27
+ 00003/0499 7 (256,448,3)
28
+ 00003/0501 7 (256,448,3)
29
+ 00003/0507 7 (256,448,3)
30
+ 00003/0510 7 (256,448,3)
31
+ 00003/0517 7 (256,448,3)
32
+ 00003/0522 7 (256,448,3)
33
+ 00003/0531 7 (256,448,3)
34
+ 00003/0533 7 (256,448,3)
35
+ 00003/0534 7 (256,448,3)
36
+ 00003/0682 7 (256,448,3)
37
+ 00003/0687 7 (256,448,3)
38
+ 00003/0715 7 (256,448,3)
39
+ 00003/0742 7 (256,448,3)
40
+ 00003/0751 7 (256,448,3)
41
+ 00003/0984 7 (256,448,3)
42
+ 00004/0042 7 (256,448,3)
43
+ 00004/0165 7 (256,448,3)
44
+ 00004/0321 7 (256,448,3)
45
+ 00004/0569 7 (256,448,3)
46
+ 00004/0572 7 (256,448,3)
47
+ 00004/0619 7 (256,448,3)
48
+ 00004/0776 7 (256,448,3)
49
+ 00004/0780 7 (256,448,3)
50
+ 00004/0825 7 (256,448,3)
51
+ 00004/0832 7 (256,448,3)
52
+ 00004/0853 7 (256,448,3)
53
+ 00004/0876 7 (256,448,3)
54
+ 00004/0888 7 (256,448,3)
55
+ 00005/0015 7 (256,448,3)
56
+ 00005/0021 7 (256,448,3)
57
+ 00005/0022 7 (256,448,3)
58
+ 00005/0024 7 (256,448,3)
59
+ 00005/0026 7 (256,448,3)
60
+ 00005/0394 7 (256,448,3)
61
+ 00005/0403 7 (256,448,3)
62
+ 00005/0531 7 (256,448,3)
63
+ 00005/0546 7 (256,448,3)
64
+ 00005/0554 7 (256,448,3)
65
+ 00005/0694 7 (256,448,3)
66
+ 00005/0700 7 (256,448,3)
67
+ 00005/0740 7 (256,448,3)
68
+ 00005/0826 7 (256,448,3)
69
+ 00005/0832 7 (256,448,3)
70
+ 00005/0834 7 (256,448,3)
71
+ 00005/0943 7 (256,448,3)
72
+ 00006/0184 7 (256,448,3)
73
+ 00006/0205 7 (256,448,3)
74
+ 00006/0206 7 (256,448,3)
75
+ 00006/0211 7 (256,448,3)
76
+ 00006/0271 7 (256,448,3)
77
+ 00006/0273 7 (256,448,3)
78
+ 00006/0277 7 (256,448,3)
79
+ 00006/0283 7 (256,448,3)
80
+ 00006/0287 7 (256,448,3)
81
+ 00006/0298 7 (256,448,3)
82
+ 00006/0310 7 (256,448,3)
83
+ 00006/0356 7 (256,448,3)
84
+ 00006/0357 7 (256,448,3)
85
+ 00006/0544 7 (256,448,3)
86
+ 00006/0565 7 (256,448,3)
87
+ 00006/0569 7 (256,448,3)
88
+ 00006/0573 7 (256,448,3)
89
+ 00006/0592 7 (256,448,3)
90
+ 00006/0613 7 (256,448,3)
91
+ 00006/0633 7 (256,448,3)
92
+ 00006/0637 7 (256,448,3)
93
+ 00006/0646 7 (256,448,3)
94
+ 00006/0649 7 (256,448,3)
95
+ 00006/0655 7 (256,448,3)
96
+ 00006/0658 7 (256,448,3)
97
+ 00006/0662 7 (256,448,3)
98
+ 00006/0666 7 (256,448,3)
99
+ 00006/0673 7 (256,448,3)
100
+ 00007/0248 7 (256,448,3)
101
+ 00007/0253 7 (256,448,3)
102
+ 00007/0430 7 (256,448,3)
103
+ 00007/0434 7 (256,448,3)
104
+ 00007/0436 7 (256,448,3)
105
+ 00007/0452 7 (256,448,3)
106
+ 00007/0464 7 (256,448,3)
107
+ 00007/0470 7 (256,448,3)
108
+ 00007/0472 7 (256,448,3)
109
+ 00007/0483 7 (256,448,3)
110
+ 00007/0484 7 (256,448,3)
111
+ 00007/0493 7 (256,448,3)
112
+ 00007/0508 7 (256,448,3)
113
+ 00007/0514 7 (256,448,3)
114
+ 00007/0697 7 (256,448,3)
115
+ 00007/0698 7 (256,448,3)
116
+ 00007/0744 7 (256,448,3)
117
+ 00007/0775 7 (256,448,3)
118
+ 00007/0786 7 (256,448,3)
119
+ 00007/0790 7 (256,448,3)
120
+ 00007/0800 7 (256,448,3)
121
+ 00007/0833 7 (256,448,3)
122
+ 00007/0867 7 (256,448,3)
123
+ 00007/0879 7 (256,448,3)
124
+ 00007/0899 7 (256,448,3)
125
+ 00008/0251 7 (256,448,3)
126
+ 00008/0322 7 (256,448,3)
127
+ 00008/0971 7 (256,448,3)
128
+ 00008/0976 7 (256,448,3)
129
+ 00009/0016 7 (256,448,3)
130
+ 00009/0036 7 (256,448,3)
131
+ 00009/0037 7 (256,448,3)
132
+ 00009/0609 7 (256,448,3)
133
+ 00009/0812 7 (256,448,3)
134
+ 00009/0821 7 (256,448,3)
135
+ 00009/0947 7 (256,448,3)
136
+ 00009/0952 7 (256,448,3)
137
+ 00009/0955 7 (256,448,3)
138
+ 00009/0970 7 (256,448,3)
139
+ 00010/0072 7 (256,448,3)
140
+ 00010/0074 7 (256,448,3)
141
+ 00010/0079 7 (256,448,3)
142
+ 00010/0085 7 (256,448,3)
143
+ 00010/0139 7 (256,448,3)
144
+ 00010/0140 7 (256,448,3)
145
+ 00010/0183 7 (256,448,3)
146
+ 00010/0200 7 (256,448,3)
147
+ 00010/0223 7 (256,448,3)
148
+ 00010/0305 7 (256,448,3)
149
+ 00010/0323 7 (256,448,3)
150
+ 00010/0338 7 (256,448,3)
151
+ 00010/0342 7 (256,448,3)
152
+ 00010/0350 7 (256,448,3)
153
+ 00010/0356 7 (256,448,3)
154
+ 00010/0362 7 (256,448,3)
155
+ 00010/0366 7 (256,448,3)
156
+ 00010/0375 7 (256,448,3)
157
+ 00010/0404 7 (256,448,3)
158
+ 00010/0407 7 (256,448,3)
159
+ 00010/0414 7 (256,448,3)
160
+ 00010/0418 7 (256,448,3)
161
+ 00010/0429 7 (256,448,3)
162
+ 00010/0557 7 (256,448,3)
163
+ 00010/0564 7 (256,448,3)
164
+ 00010/0733 7 (256,448,3)
165
+ 00010/0935 7 (256,448,3)
166
+ 00010/0939 7 (256,448,3)
167
+ 00010/0943 7 (256,448,3)
168
+ 00011/0242 7 (256,448,3)
169
+ 00011/0259 7 (256,448,3)
170
+ 00011/0263 7 (256,448,3)
171
+ 00011/0266 7 (256,448,3)
172
+ 00011/0278 7 (256,448,3)
173
+ 00011/0890 7 (256,448,3)
174
+ 00011/0894 7 (256,448,3)
175
+ 00011/0903 7 (256,448,3)
176
+ 00011/0906 7 (256,448,3)
177
+ 00011/0913 7 (256,448,3)
178
+ 00012/0011 7 (256,448,3)
179
+ 00012/0014 7 (256,448,3)
180
+ 00012/0126 7 (256,448,3)
181
+ 00012/0127 7 (256,448,3)
182
+ 00012/0526 7 (256,448,3)
183
+ 00012/0551 7 (256,448,3)
184
+ 00012/0896 7 (256,448,3)
185
+ 00012/0910 7 (256,448,3)
186
+ 00012/0915 7 (256,448,3)
187
+ 00013/0167 7 (256,448,3)
188
+ 00013/0794 7 (256,448,3)
189
+ 00013/0807 7 (256,448,3)
190
+ 00013/0846 7 (256,448,3)
191
+ 00013/0882 7 (256,448,3)
192
+ 00013/0889 7 (256,448,3)
193
+ 00013/0910 7 (256,448,3)
194
+ 00013/0913 7 (256,448,3)
195
+ 00013/0924 7 (256,448,3)
196
+ 00013/0931 7 (256,448,3)
197
+ 00013/0944 7 (256,448,3)
198
+ 00013/0955 7 (256,448,3)
199
+ 00013/0962 7 (256,448,3)
200
+ 00013/0969 7 (256,448,3)
201
+ 00014/0012 7 (256,448,3)
202
+ 00014/0025 7 (256,448,3)
203
+ 00014/0473 7 (256,448,3)
204
+ 00014/0499 7 (256,448,3)
205
+ 00014/0524 7 (256,448,3)
206
+ 00014/0739 7 (256,448,3)
207
+ 00014/0753 7 (256,448,3)
208
+ 00014/0771 7 (256,448,3)
209
+ 00014/0832 7 (256,448,3)
210
+ 00014/0836 7 (256,448,3)
211
+ 00014/0838 7 (256,448,3)
212
+ 00014/0839 7 (256,448,3)
213
+ 00014/0843 7 (256,448,3)
214
+ 00014/0846 7 (256,448,3)
215
+ 00014/0849 7 (256,448,3)
216
+ 00014/0859 7 (256,448,3)
217
+ 00014/0880 7 (256,448,3)
218
+ 00014/0906 7 (256,448,3)
219
+ 00015/0030 7 (256,448,3)
220
+ 00015/0067 7 (256,448,3)
221
+ 00015/0084 7 (256,448,3)
222
+ 00015/0190 7 (256,448,3)
223
+ 00015/0575 7 (256,448,3)
224
+ 00015/0784 7 (256,448,3)
225
+ 00015/0855 7 (256,448,3)
226
+ 00015/0904 7 (256,448,3)
227
+ 00015/0914 7 (256,448,3)
228
+ 00015/0936 7 (256,448,3)
229
+ 00015/0939 7 (256,448,3)
230
+ 00015/0943 7 (256,448,3)
231
+ 00015/0957 7 (256,448,3)
232
+ 00016/0131 7 (256,448,3)
233
+ 00016/0173 7 (256,448,3)
234
+ 00016/0320 7 (256,448,3)
235
+ 00016/0328 7 (256,448,3)
236
+ 00016/0334 7 (256,448,3)
237
+ 00016/0338 7 (256,448,3)
238
+ 00016/0339 7 (256,448,3)
239
+ 00016/0345 7 (256,448,3)
240
+ 00016/0365 7 (256,448,3)
241
+ 00016/0584 7 (256,448,3)
242
+ 00016/0634 7 (256,448,3)
243
+ 00017/0342 7 (256,448,3)
244
+ 00017/0346 7 (256,448,3)
245
+ 00017/0350 7 (256,448,3)
246
+ 00017/0766 7 (256,448,3)
247
+ 00017/0786 7 (256,448,3)
248
+ 00017/0911 7 (256,448,3)
249
+ 00017/0914 7 (256,448,3)
250
+ 00018/0217 7 (256,448,3)
251
+ 00018/0258 7 (256,448,3)
252
+ 00018/0307 7 (256,448,3)
253
+ 00018/0480 7 (256,448,3)
254
+ 00018/0491 7 (256,448,3)
255
+ 00018/0994 7 (256,448,3)
256
+ 00018/0995 7 (256,448,3)
257
+ 00018/0997 7 (256,448,3)
258
+ 00018/1000 7 (256,448,3)
259
+ 00019/0007 7 (256,448,3)
260
+ 00019/0016 7 (256,448,3)
261
+ 00019/0026 7 (256,448,3)
262
+ 00019/0030 7 (256,448,3)
263
+ 00019/0086 7 (256,448,3)
264
+ 00019/0089 7 (256,448,3)
265
+ 00019/0111 7 (256,448,3)
266
+ 00019/0285 7 (256,448,3)
267
+ 00019/0415 7 (256,448,3)
268
+ 00019/0434 7 (256,448,3)
269
+ 00019/0437 7 (256,448,3)
270
+ 00019/0568 7 (256,448,3)
271
+ 00019/0570 7 (256,448,3)
272
+ 00019/0591 7 (256,448,3)
273
+ 00019/0596 7 (256,448,3)
274
+ 00019/0603 7 (256,448,3)
275
+ 00019/0607 7 (256,448,3)
276
+ 00019/0637 7 (256,448,3)
277
+ 00019/0644 7 (256,448,3)
278
+ 00019/0647 7 (256,448,3)
279
+ 00019/0787 7 (256,448,3)
280
+ 00019/0993 7 (256,448,3)
281
+ 00019/0998 7 (256,448,3)
282
+ 00021/0232 7 (256,448,3)
283
+ 00021/0255 7 (256,448,3)
284
+ 00021/0646 7 (256,448,3)
285
+ 00021/0653 7 (256,448,3)
286
+ 00021/0657 7 (256,448,3)
287
+ 00021/0668 7 (256,448,3)
288
+ 00021/0672 7 (256,448,3)
289
+ 00021/0725 7 (256,448,3)
290
+ 00021/0750 7 (256,448,3)
291
+ 00021/0764 7 (256,448,3)
292
+ 00021/0821 7 (256,448,3)
293
+ 00022/0192 7 (256,448,3)
294
+ 00022/0391 7 (256,448,3)
295
+ 00022/0514 7 (256,448,3)
296
+ 00022/0567 7 (256,448,3)
297
+ 00022/0674 7 (256,448,3)
298
+ 00022/0686 7 (256,448,3)
299
+ 00022/0700 7 (256,448,3)
300
+ 00023/0020 7 (256,448,3)
301
+ 00023/0024 7 (256,448,3)
302
+ 00023/0025 7 (256,448,3)
303
+ 00023/0042 7 (256,448,3)
304
+ 00023/0050 7 (256,448,3)
305
+ 00023/0094 7 (256,448,3)
306
+ 00023/0107 7 (256,448,3)
307
+ 00023/0635 7 (256,448,3)
308
+ 00023/0698 7 (256,448,3)
309
+ 00023/0774 7 (256,448,3)
310
+ 00023/0795 7 (256,448,3)
311
+ 00023/0821 7 (256,448,3)
312
+ 00023/0839 7 (256,448,3)
313
+ 00023/0846 7 (256,448,3)
314
+ 00023/0869 7 (256,448,3)
315
+ 00023/0879 7 (256,448,3)
316
+ 00023/0887 7 (256,448,3)
317
+ 00023/0899 7 (256,448,3)
318
+ 00023/0910 7 (256,448,3)
319
+ 00023/0920 7 (256,448,3)
320
+ 00023/0929 7 (256,448,3)
321
+ 00023/0941 7 (256,448,3)
322
+ 00023/0942 7 (256,448,3)
323
+ 00023/0952 7 (256,448,3)
324
+ 00024/0066 7 (256,448,3)
325
+ 00024/0072 7 (256,448,3)
326
+ 00024/0080 7 (256,448,3)
327
+ 00024/0093 7 (256,448,3)
328
+ 00024/0107 7 (256,448,3)
329
+ 00024/0262 7 (256,448,3)
330
+ 00024/0283 7 (256,448,3)
331
+ 00024/0294 7 (256,448,3)
332
+ 00024/0296 7 (256,448,3)
333
+ 00024/0304 7 (256,448,3)
334
+ 00024/0315 7 (256,448,3)
335
+ 00024/0322 7 (256,448,3)
336
+ 00024/0648 7 (256,448,3)
337
+ 00024/0738 7 (256,448,3)
338
+ 00024/0743 7 (256,448,3)
339
+ 00025/0542 7 (256,448,3)
340
+ 00025/0769 7 (256,448,3)
341
+ 00025/0984 7 (256,448,3)
342
+ 00025/0985 7 (256,448,3)
343
+ 00025/0989 7 (256,448,3)
344
+ 00025/0991 7 (256,448,3)
345
+ 00026/0009 7 (256,448,3)
346
+ 00026/0013 7 (256,448,3)
347
+ 00026/0020 7 (256,448,3)
348
+ 00026/0021 7 (256,448,3)
349
+ 00026/0025 7 (256,448,3)
350
+ 00026/0135 7 (256,448,3)
351
+ 00026/0200 7 (256,448,3)
352
+ 00026/0297 7 (256,448,3)
353
+ 00026/0306 7 (256,448,3)
354
+ 00026/0444 7 (256,448,3)
355
+ 00026/0450 7 (256,448,3)
356
+ 00026/0453 7 (256,448,3)
357
+ 00026/0464 7 (256,448,3)
358
+ 00026/0486 7 (256,448,3)
359
+ 00026/0773 7 (256,448,3)
360
+ 00026/0785 7 (256,448,3)
361
+ 00026/0836 7 (256,448,3)
362
+ 00026/0838 7 (256,448,3)
363
+ 00026/0848 7 (256,448,3)
364
+ 00026/0885 7 (256,448,3)
365
+ 00026/0893 7 (256,448,3)
366
+ 00026/0939 7 (256,448,3)
367
+ 00026/0942 7 (256,448,3)
368
+ 00027/0092 7 (256,448,3)
369
+ 00027/0112 7 (256,448,3)
370
+ 00027/0115 7 (256,448,3)
371
+ 00027/0143 7 (256,448,3)
372
+ 00027/0175 7 (256,448,3)
373
+ 00027/0179 7 (256,448,3)
374
+ 00027/0183 7 (256,448,3)
375
+ 00027/0197 7 (256,448,3)
376
+ 00027/0199 7 (256,448,3)
377
+ 00027/0300 7 (256,448,3)
378
+ 00028/0015 7 (256,448,3)
379
+ 00028/0032 7 (256,448,3)
380
+ 00028/0048 7 (256,448,3)
381
+ 00028/0068 7 (256,448,3)
382
+ 00028/0219 7 (256,448,3)
383
+ 00028/0606 7 (256,448,3)
384
+ 00028/0626 7 (256,448,3)
385
+ 00028/0748 7 (256,448,3)
386
+ 00028/0764 7 (256,448,3)
387
+ 00028/0772 7 (256,448,3)
388
+ 00028/0780 7 (256,448,3)
389
+ 00028/0926 7 (256,448,3)
390
+ 00028/0947 7 (256,448,3)
391
+ 00028/0962 7 (256,448,3)
392
+ 00029/0085 7 (256,448,3)
393
+ 00029/0281 7 (256,448,3)
394
+ 00029/0284 7 (256,448,3)
395
+ 00029/0288 7 (256,448,3)
396
+ 00029/0294 7 (256,448,3)
397
+ 00029/0364 7 (256,448,3)
398
+ 00029/0369 7 (256,448,3)
399
+ 00029/0421 7 (256,448,3)
400
+ 00029/0425 7 (256,448,3)
401
+ 00029/0550 7 (256,448,3)
402
+ 00030/0014 7 (256,448,3)
403
+ 00030/0101 7 (256,448,3)
404
+ 00030/0143 7 (256,448,3)
405
+ 00030/0351 7 (256,448,3)
406
+ 00030/0356 7 (256,448,3)
407
+ 00030/0371 7 (256,448,3)
408
+ 00030/0484 7 (256,448,3)
409
+ 00030/0492 7 (256,448,3)
410
+ 00030/0503 7 (256,448,3)
411
+ 00030/0682 7 (256,448,3)
412
+ 00030/0696 7 (256,448,3)
413
+ 00030/0735 7 (256,448,3)
414
+ 00030/0737 7 (256,448,3)
415
+ 00030/0868 7 (256,448,3)
416
+ 00031/0161 7 (256,448,3)
417
+ 00031/0180 7 (256,448,3)
418
+ 00031/0194 7 (256,448,3)
419
+ 00031/0253 7 (256,448,3)
420
+ 00031/0293 7 (256,448,3)
421
+ 00031/0466 7 (256,448,3)
422
+ 00031/0477 7 (256,448,3)
423
+ 00031/0549 7 (256,448,3)
424
+ 00031/0600 7 (256,448,3)
425
+ 00031/0617 7 (256,448,3)
426
+ 00031/0649 7 (256,448,3)
427
+ 00032/0015 7 (256,448,3)
428
+ 00032/0020 7 (256,448,3)
429
+ 00032/0023 7 (256,448,3)
430
+ 00032/0048 7 (256,448,3)
431
+ 00032/0056 7 (256,448,3)
432
+ 00032/0872 7 (256,448,3)
433
+ 00033/0069 7 (256,448,3)
434
+ 00033/0073 7 (256,448,3)
435
+ 00033/0078 7 (256,448,3)
436
+ 00033/0079 7 (256,448,3)
437
+ 00033/0086 7 (256,448,3)
438
+ 00033/0088 7 (256,448,3)
439
+ 00033/0091 7 (256,448,3)
440
+ 00033/0096 7 (256,448,3)
441
+ 00033/0607 7 (256,448,3)
442
+ 00033/0613 7 (256,448,3)
443
+ 00033/0616 7 (256,448,3)
444
+ 00033/0619 7 (256,448,3)
445
+ 00033/0626 7 (256,448,3)
446
+ 00033/0628 7 (256,448,3)
447
+ 00033/0637 7 (256,448,3)
448
+ 00033/0686 7 (256,448,3)
449
+ 00033/0842 7 (256,448,3)
450
+ 00034/0261 7 (256,448,3)
451
+ 00034/0265 7 (256,448,3)
452
+ 00034/0269 7 (256,448,3)
453
+ 00034/0275 7 (256,448,3)
454
+ 00034/0286 7 (256,448,3)
455
+ 00034/0294 7 (256,448,3)
456
+ 00034/0431 7 (256,448,3)
457
+ 00034/0577 7 (256,448,3)
458
+ 00034/0685 7 (256,448,3)
459
+ 00034/0687 7 (256,448,3)
460
+ 00034/0703 7 (256,448,3)
461
+ 00034/0715 7 (256,448,3)
462
+ 00034/0935 7 (256,448,3)
463
+ 00034/0943 7 (256,448,3)
464
+ 00034/0963 7 (256,448,3)
465
+ 00034/0979 7 (256,448,3)
466
+ 00034/0990 7 (256,448,3)
467
+ 00035/0129 7 (256,448,3)
468
+ 00035/0153 7 (256,448,3)
469
+ 00035/0156 7 (256,448,3)
470
+ 00035/0474 7 (256,448,3)
471
+ 00035/0507 7 (256,448,3)
472
+ 00035/0532 7 (256,448,3)
473
+ 00035/0560 7 (256,448,3)
474
+ 00035/0572 7 (256,448,3)
475
+ 00035/0587 7 (256,448,3)
476
+ 00035/0588 7 (256,448,3)
477
+ 00035/0640 7 (256,448,3)
478
+ 00035/0654 7 (256,448,3)
479
+ 00035/0655 7 (256,448,3)
480
+ 00035/0737 7 (256,448,3)
481
+ 00035/0843 7 (256,448,3)
482
+ 00035/0932 7 (256,448,3)
483
+ 00035/0957 7 (256,448,3)
484
+ 00036/0029 7 (256,448,3)
485
+ 00036/0266 7 (256,448,3)
486
+ 00036/0276 7 (256,448,3)
487
+ 00036/0310 7 (256,448,3)
488
+ 00036/0314 7 (256,448,3)
489
+ 00036/0320 7 (256,448,3)
490
+ 00036/0333 7 (256,448,3)
491
+ 00036/0348 7 (256,448,3)
492
+ 00036/0357 7 (256,448,3)
493
+ 00036/0360 7 (256,448,3)
494
+ 00036/0368 7 (256,448,3)
495
+ 00036/0371 7 (256,448,3)
496
+ 00036/0378 7 (256,448,3)
497
+ 00036/0391 7 (256,448,3)
498
+ 00036/0440 7 (256,448,3)
499
+ 00036/0731 7 (256,448,3)
500
+ 00036/0733 7 (256,448,3)
501
+ 00036/0741 7 (256,448,3)
502
+ 00036/0743 7 (256,448,3)
503
+ 00036/0927 7 (256,448,3)
504
+ 00036/0931 7 (256,448,3)
505
+ 00036/0933 7 (256,448,3)
506
+ 00036/0938 7 (256,448,3)
507
+ 00036/0944 7 (256,448,3)
508
+ 00036/0946 7 (256,448,3)
509
+ 00036/0951 7 (256,448,3)
510
+ 00036/0953 7 (256,448,3)
511
+ 00036/0963 7 (256,448,3)
512
+ 00036/0964 7 (256,448,3)
513
+ 00036/0981 7 (256,448,3)
514
+ 00036/0991 7 (256,448,3)
515
+ 00037/0072 7 (256,448,3)
516
+ 00037/0079 7 (256,448,3)
517
+ 00037/0132 7 (256,448,3)
518
+ 00037/0135 7 (256,448,3)
519
+ 00037/0137 7 (256,448,3)
520
+ 00037/0141 7 (256,448,3)
521
+ 00037/0229 7 (256,448,3)
522
+ 00037/0234 7 (256,448,3)
523
+ 00037/0239 7 (256,448,3)
524
+ 00037/0242 7 (256,448,3)
525
+ 00037/0254 7 (256,448,3)
526
+ 00037/0269 7 (256,448,3)
527
+ 00037/0276 7 (256,448,3)
528
+ 00037/0279 7 (256,448,3)
529
+ 00037/0286 7 (256,448,3)
530
+ 00037/0345 7 (256,448,3)
531
+ 00037/0449 7 (256,448,3)
532
+ 00037/0450 7 (256,448,3)
533
+ 00037/0820 7 (256,448,3)
534
+ 00037/0824 7 (256,448,3)
535
+ 00037/0859 7 (256,448,3)
536
+ 00037/0899 7 (256,448,3)
537
+ 00037/0906 7 (256,448,3)
538
+ 00038/0535 7 (256,448,3)
539
+ 00038/0572 7 (256,448,3)
540
+ 00038/0675 7 (256,448,3)
541
+ 00038/0731 7 (256,448,3)
542
+ 00038/0732 7 (256,448,3)
543
+ 00038/0744 7 (256,448,3)
544
+ 00038/0755 7 (256,448,3)
545
+ 00039/0002 7 (256,448,3)
546
+ 00039/0013 7 (256,448,3)
547
+ 00039/0247 7 (256,448,3)
548
+ 00039/0489 7 (256,448,3)
549
+ 00039/0504 7 (256,448,3)
550
+ 00039/0558 7 (256,448,3)
551
+ 00039/0686 7 (256,448,3)
552
+ 00039/0727 7 (256,448,3)
553
+ 00039/0769 7 (256,448,3)
554
+ 00040/0081 7 (256,448,3)
555
+ 00040/0082 7 (256,448,3)
556
+ 00040/0402 7 (256,448,3)
557
+ 00040/0407 7 (256,448,3)
558
+ 00040/0408 7 (256,448,3)
559
+ 00040/0410 7 (256,448,3)
560
+ 00040/0411 7 (256,448,3)
561
+ 00040/0412 7 (256,448,3)
562
+ 00040/0413 7 (256,448,3)
563
+ 00040/0415 7 (256,448,3)
564
+ 00040/0421 7 (256,448,3)
565
+ 00040/0422 7 (256,448,3)
566
+ 00040/0426 7 (256,448,3)
567
+ 00040/0438 7 (256,448,3)
568
+ 00040/0439 7 (256,448,3)
569
+ 00040/0440 7 (256,448,3)
570
+ 00040/0443 7 (256,448,3)
571
+ 00040/0457 7 (256,448,3)
572
+ 00040/0459 7 (256,448,3)
573
+ 00040/0725 7 (256,448,3)
574
+ 00040/0727 7 (256,448,3)
575
+ 00040/0936 7 (256,448,3)
576
+ 00040/0959 7 (256,448,3)
577
+ 00040/0964 7 (256,448,3)
578
+ 00040/0968 7 (256,448,3)
579
+ 00040/0974 7 (256,448,3)
580
+ 00040/0978 7 (256,448,3)
581
+ 00040/0979 7 (256,448,3)
582
+ 00040/0989 7 (256,448,3)
583
+ 00040/0993 7 (256,448,3)
584
+ 00040/0994 7 (256,448,3)
585
+ 00040/0997 7 (256,448,3)
586
+ 00041/0001 7 (256,448,3)
587
+ 00041/0007 7 (256,448,3)
588
+ 00041/0019 7 (256,448,3)
589
+ 00041/0040 7 (256,448,3)
590
+ 00041/0350 7 (256,448,3)
591
+ 00041/0357 7 (256,448,3)
592
+ 00041/0393 7 (256,448,3)
593
+ 00041/0890 7 (256,448,3)
594
+ 00041/0909 7 (256,448,3)
595
+ 00041/0915 7 (256,448,3)
596
+ 00041/0933 7 (256,448,3)
597
+ 00042/0017 7 (256,448,3)
598
+ 00042/0332 7 (256,448,3)
599
+ 00042/0346 7 (256,448,3)
600
+ 00042/0350 7 (256,448,3)
601
+ 00042/0356 7 (256,448,3)
602
+ 00042/0382 7 (256,448,3)
603
+ 00042/0389 7 (256,448,3)
604
+ 00042/0539 7 (256,448,3)
605
+ 00042/0546 7 (256,448,3)
606
+ 00042/0550 7 (256,448,3)
607
+ 00042/0553 7 (256,448,3)
608
+ 00042/0555 7 (256,448,3)
609
+ 00042/0560 7 (256,448,3)
610
+ 00042/0570 7 (256,448,3)
611
+ 00043/0119 7 (256,448,3)
612
+ 00043/0122 7 (256,448,3)
613
+ 00043/0168 7 (256,448,3)
614
+ 00043/0274 7 (256,448,3)
615
+ 00043/0304 7 (256,448,3)
616
+ 00043/0731 7 (256,448,3)
617
+ 00043/0735 7 (256,448,3)
618
+ 00043/0739 7 (256,448,3)
619
+ 00043/0740 7 (256,448,3)
620
+ 00044/0212 7 (256,448,3)
621
+ 00044/0432 7 (256,448,3)
622
+ 00044/0934 7 (256,448,3)
623
+ 00044/0940 7 (256,448,3)
624
+ 00044/0987 7 (256,448,3)
625
+ 00045/0004 7 (256,448,3)
626
+ 00045/0009 7 (256,448,3)
627
+ 00045/0011 7 (256,448,3)
628
+ 00045/0019 7 (256,448,3)
629
+ 00045/0023 7 (256,448,3)
630
+ 00045/0289 7 (256,448,3)
631
+ 00045/0760 7 (256,448,3)
632
+ 00045/0779 7 (256,448,3)
633
+ 00045/0816 7 (256,448,3)
634
+ 00045/0820 7 (256,448,3)
635
+ 00046/0132 7 (256,448,3)
636
+ 00046/0350 7 (256,448,3)
637
+ 00046/0356 7 (256,448,3)
638
+ 00046/0357 7 (256,448,3)
639
+ 00046/0379 7 (256,448,3)
640
+ 00046/0410 7 (256,448,3)
641
+ 00046/0412 7 (256,448,3)
642
+ 00046/0481 7 (256,448,3)
643
+ 00046/0497 7 (256,448,3)
644
+ 00046/0510 7 (256,448,3)
645
+ 00046/0515 7 (256,448,3)
646
+ 00046/0529 7 (256,448,3)
647
+ 00046/0544 7 (256,448,3)
648
+ 00046/0545 7 (256,448,3)
649
+ 00046/0552 7 (256,448,3)
650
+ 00046/0559 7 (256,448,3)
651
+ 00046/0589 7 (256,448,3)
652
+ 00046/0642 7 (256,448,3)
653
+ 00046/0724 7 (256,448,3)
654
+ 00046/0758 7 (256,448,3)
655
+ 00046/0930 7 (256,448,3)
656
+ 00046/0953 7 (256,448,3)
657
+ 00047/0013 7 (256,448,3)
658
+ 00047/0014 7 (256,448,3)
659
+ 00047/0017 7 (256,448,3)
660
+ 00047/0076 7 (256,448,3)
661
+ 00047/0151 7 (256,448,3)
662
+ 00047/0797 7 (256,448,3)
663
+ 00048/0014 7 (256,448,3)
664
+ 00048/0021 7 (256,448,3)
665
+ 00048/0026 7 (256,448,3)
666
+ 00048/0030 7 (256,448,3)
667
+ 00048/0039 7 (256,448,3)
668
+ 00048/0045 7 (256,448,3)
669
+ 00048/0049 7 (256,448,3)
670
+ 00048/0145 7 (256,448,3)
671
+ 00048/0188 7 (256,448,3)
672
+ 00048/0302 7 (256,448,3)
673
+ 00048/0361 7 (256,448,3)
674
+ 00048/0664 7 (256,448,3)
675
+ 00048/0672 7 (256,448,3)
676
+ 00048/0681 7 (256,448,3)
677
+ 00048/0689 7 (256,448,3)
678
+ 00048/0690 7 (256,448,3)
679
+ 00048/0691 7 (256,448,3)
680
+ 00048/0711 7 (256,448,3)
681
+ 00049/0085 7 (256,448,3)
682
+ 00049/0810 7 (256,448,3)
683
+ 00049/0858 7 (256,448,3)
684
+ 00049/0865 7 (256,448,3)
685
+ 00049/0871 7 (256,448,3)
686
+ 00049/0903 7 (256,448,3)
687
+ 00049/0928 7 (256,448,3)
688
+ 00050/0092 7 (256,448,3)
689
+ 00050/0101 7 (256,448,3)
690
+ 00050/0108 7 (256,448,3)
691
+ 00050/0112 7 (256,448,3)
692
+ 00050/0120 7 (256,448,3)
693
+ 00050/0128 7 (256,448,3)
694
+ 00050/0383 7 (256,448,3)
695
+ 00050/0395 7 (256,448,3)
696
+ 00050/0405 7 (256,448,3)
697
+ 00050/0632 7 (256,448,3)
698
+ 00050/0648 7 (256,448,3)
699
+ 00050/0649 7 (256,448,3)
700
+ 00050/0659 7 (256,448,3)
701
+ 00050/0699 7 (256,448,3)
702
+ 00050/0708 7 (256,448,3)
703
+ 00050/0716 7 (256,448,3)
704
+ 00050/0758 7 (256,448,3)
705
+ 00050/0761 7 (256,448,3)
706
+ 00051/0572 7 (256,448,3)
707
+ 00052/0163 7 (256,448,3)
708
+ 00052/0242 7 (256,448,3)
709
+ 00052/0260 7 (256,448,3)
710
+ 00052/0322 7 (256,448,3)
711
+ 00052/0333 7 (256,448,3)
712
+ 00052/0806 7 (256,448,3)
713
+ 00052/0813 7 (256,448,3)
714
+ 00052/0821 7 (256,448,3)
715
+ 00052/0830 7 (256,448,3)
716
+ 00052/0914 7 (256,448,3)
717
+ 00052/0923 7 (256,448,3)
718
+ 00052/0959 7 (256,448,3)
719
+ 00053/0288 7 (256,448,3)
720
+ 00053/0290 7 (256,448,3)
721
+ 00053/0323 7 (256,448,3)
722
+ 00053/0337 7 (256,448,3)
723
+ 00053/0340 7 (256,448,3)
724
+ 00053/0437 7 (256,448,3)
725
+ 00053/0595 7 (256,448,3)
726
+ 00053/0739 7 (256,448,3)
727
+ 00053/0761 7 (256,448,3)
728
+ 00054/0014 7 (256,448,3)
729
+ 00054/0017 7 (256,448,3)
730
+ 00054/0178 7 (256,448,3)
731
+ 00054/0183 7 (256,448,3)
732
+ 00054/0196 7 (256,448,3)
733
+ 00054/0205 7 (256,448,3)
734
+ 00054/0214 7 (256,448,3)
735
+ 00054/0289 7 (256,448,3)
736
+ 00054/0453 7 (256,448,3)
737
+ 00054/0498 7 (256,448,3)
738
+ 00054/0502 7 (256,448,3)
739
+ 00054/0514 7 (256,448,3)
740
+ 00054/0773 7 (256,448,3)
741
+ 00055/0001 7 (256,448,3)
742
+ 00055/0115 7 (256,448,3)
743
+ 00055/0118 7 (256,448,3)
744
+ 00055/0171 7 (256,448,3)
745
+ 00055/0214 7 (256,448,3)
746
+ 00055/0354 7 (256,448,3)
747
+ 00055/0449 7 (256,448,3)
748
+ 00055/0473 7 (256,448,3)
749
+ 00055/0649 7 (256,448,3)
750
+ 00055/0800 7 (256,448,3)
751
+ 00055/0803 7 (256,448,3)
752
+ 00055/0990 7 (256,448,3)
753
+ 00056/0041 7 (256,448,3)
754
+ 00056/0120 7 (256,448,3)
755
+ 00056/0293 7 (256,448,3)
756
+ 00056/0357 7 (256,448,3)
757
+ 00056/0506 7 (256,448,3)
758
+ 00056/0561 7 (256,448,3)
759
+ 00056/0567 7 (256,448,3)
760
+ 00056/0575 7 (256,448,3)
761
+ 00057/0175 7 (256,448,3)
762
+ 00057/0495 7 (256,448,3)
763
+ 00057/0498 7 (256,448,3)
764
+ 00057/0506 7 (256,448,3)
765
+ 00057/0612 7 (256,448,3)
766
+ 00057/0620 7 (256,448,3)
767
+ 00057/0623 7 (256,448,3)
768
+ 00057/0635 7 (256,448,3)
769
+ 00057/0773 7 (256,448,3)
770
+ 00057/0778 7 (256,448,3)
771
+ 00057/0867 7 (256,448,3)
772
+ 00057/0976 7 (256,448,3)
773
+ 00057/0980 7 (256,448,3)
774
+ 00057/0985 7 (256,448,3)
775
+ 00057/0992 7 (256,448,3)
776
+ 00058/0009 7 (256,448,3)
777
+ 00058/0076 7 (256,448,3)
778
+ 00058/0078 7 (256,448,3)
779
+ 00058/0279 7 (256,448,3)
780
+ 00058/0283 7 (256,448,3)
781
+ 00058/0286 7 (256,448,3)
782
+ 00058/0350 7 (256,448,3)
783
+ 00058/0380 7 (256,448,3)
784
+ 00061/0132 7 (256,448,3)
785
+ 00061/0141 7 (256,448,3)
786
+ 00061/0156 7 (256,448,3)
787
+ 00061/0159 7 (256,448,3)
788
+ 00061/0168 7 (256,448,3)
789
+ 00061/0170 7 (256,448,3)
790
+ 00061/0186 7 (256,448,3)
791
+ 00061/0219 7 (256,448,3)
792
+ 00061/0227 7 (256,448,3)
793
+ 00061/0238 7 (256,448,3)
794
+ 00061/0256 7 (256,448,3)
795
+ 00061/0303 7 (256,448,3)
796
+ 00061/0312 7 (256,448,3)
797
+ 00061/0313 7 (256,448,3)
798
+ 00061/0325 7 (256,448,3)
799
+ 00061/0367 7 (256,448,3)
800
+ 00061/0369 7 (256,448,3)
801
+ 00061/0387 7 (256,448,3)
802
+ 00061/0396 7 (256,448,3)
803
+ 00061/0486 7 (256,448,3)
804
+ 00061/0895 7 (256,448,3)
805
+ 00061/0897 7 (256,448,3)
806
+ 00062/0846 7 (256,448,3)
807
+ 00063/0156 7 (256,448,3)
808
+ 00063/0184 7 (256,448,3)
809
+ 00063/0191 7 (256,448,3)
810
+ 00063/0334 7 (256,448,3)
811
+ 00063/0350 7 (256,448,3)
812
+ 00063/0499 7 (256,448,3)
813
+ 00063/0878 7 (256,448,3)
814
+ 00064/0004 7 (256,448,3)
815
+ 00064/0264 7 (256,448,3)
816
+ 00064/0735 7 (256,448,3)
817
+ 00064/0738 7 (256,448,3)
818
+ 00065/0105 7 (256,448,3)
819
+ 00065/0169 7 (256,448,3)
820
+ 00065/0305 7 (256,448,3)
821
+ 00065/0324 7 (256,448,3)
822
+ 00065/0353 7 (256,448,3)
823
+ 00065/0520 7 (256,448,3)
824
+ 00065/0533 7 (256,448,3)
825
+ 00065/0545 7 (256,448,3)
826
+ 00065/0551 7 (256,448,3)
827
+ 00065/0568 7 (256,448,3)
828
+ 00065/0603 7 (256,448,3)
829
+ 00065/0884 7 (256,448,3)
830
+ 00065/0988 7 (256,448,3)
831
+ 00066/0002 7 (256,448,3)
832
+ 00066/0011 7 (256,448,3)
833
+ 00066/0031 7 (256,448,3)
834
+ 00066/0037 7 (256,448,3)
835
+ 00066/0136 7 (256,448,3)
836
+ 00066/0137 7 (256,448,3)
837
+ 00066/0150 7 (256,448,3)
838
+ 00066/0166 7 (256,448,3)
839
+ 00066/0178 7 (256,448,3)
840
+ 00066/0357 7 (256,448,3)
841
+ 00066/0428 7 (256,448,3)
842
+ 00066/0483 7 (256,448,3)
843
+ 00066/0600 7 (256,448,3)
844
+ 00066/0863 7 (256,448,3)
845
+ 00066/0873 7 (256,448,3)
846
+ 00066/0875 7 (256,448,3)
847
+ 00066/0899 7 (256,448,3)
848
+ 00067/0020 7 (256,448,3)
849
+ 00067/0025 7 (256,448,3)
850
+ 00067/0132 7 (256,448,3)
851
+ 00067/0492 7 (256,448,3)
852
+ 00067/0726 7 (256,448,3)
853
+ 00067/0734 7 (256,448,3)
854
+ 00067/0744 7 (256,448,3)
855
+ 00067/0754 7 (256,448,3)
856
+ 00067/0779 7 (256,448,3)
857
+ 00068/0078 7 (256,448,3)
858
+ 00068/0083 7 (256,448,3)
859
+ 00068/0113 7 (256,448,3)
860
+ 00068/0117 7 (256,448,3)
861
+ 00068/0121 7 (256,448,3)
862
+ 00068/0206 7 (256,448,3)
863
+ 00068/0261 7 (256,448,3)
864
+ 00068/0321 7 (256,448,3)
865
+ 00068/0354 7 (256,448,3)
866
+ 00068/0380 7 (256,448,3)
867
+ 00068/0419 7 (256,448,3)
868
+ 00068/0547 7 (256,448,3)
869
+ 00068/0561 7 (256,448,3)
870
+ 00068/0565 7 (256,448,3)
871
+ 00068/0583 7 (256,448,3)
872
+ 00068/0599 7 (256,448,3)
873
+ 00068/0739 7 (256,448,3)
874
+ 00068/0743 7 (256,448,3)
875
+ 00068/0754 7 (256,448,3)
876
+ 00068/0812 7 (256,448,3)
877
+ 00069/0178 7 (256,448,3)
878
+ 00070/0025 7 (256,448,3)
879
+ 00070/0030 7 (256,448,3)
880
+ 00070/0036 7 (256,448,3)
881
+ 00070/0042 7 (256,448,3)
882
+ 00070/0078 7 (256,448,3)
883
+ 00070/0079 7 (256,448,3)
884
+ 00070/0362 7 (256,448,3)
885
+ 00071/0195 7 (256,448,3)
886
+ 00071/0210 7 (256,448,3)
887
+ 00071/0211 7 (256,448,3)
888
+ 00071/0221 7 (256,448,3)
889
+ 00071/0352 7 (256,448,3)
890
+ 00071/0354 7 (256,448,3)
891
+ 00071/0366 7 (256,448,3)
892
+ 00071/0454 7 (256,448,3)
893
+ 00071/0464 7 (256,448,3)
894
+ 00071/0487 7 (256,448,3)
895
+ 00071/0502 7 (256,448,3)
896
+ 00071/0561 7 (256,448,3)
897
+ 00071/0676 7 (256,448,3)
898
+ 00071/0808 7 (256,448,3)
899
+ 00071/0813 7 (256,448,3)
900
+ 00071/0836 7 (256,448,3)
901
+ 00072/0286 7 (256,448,3)
902
+ 00072/0290 7 (256,448,3)
903
+ 00072/0298 7 (256,448,3)
904
+ 00072/0302 7 (256,448,3)
905
+ 00072/0333 7 (256,448,3)
906
+ 00072/0590 7 (256,448,3)
907
+ 00072/0793 7 (256,448,3)
908
+ 00072/0803 7 (256,448,3)
909
+ 00072/0833 7 (256,448,3)
910
+ 00073/0049 7 (256,448,3)
911
+ 00073/0050 7 (256,448,3)
912
+ 00073/0388 7 (256,448,3)
913
+ 00073/0480 7 (256,448,3)
914
+ 00073/0485 7 (256,448,3)
915
+ 00073/0611 7 (256,448,3)
916
+ 00073/0616 7 (256,448,3)
917
+ 00073/0714 7 (256,448,3)
918
+ 00073/0724 7 (256,448,3)
919
+ 00073/0730 7 (256,448,3)
920
+ 00074/0034 7 (256,448,3)
921
+ 00074/0228 7 (256,448,3)
922
+ 00074/0239 7 (256,448,3)
923
+ 00074/0275 7 (256,448,3)
924
+ 00074/0527 7 (256,448,3)
925
+ 00074/0620 7 (256,448,3)
926
+ 00074/0764 7 (256,448,3)
927
+ 00074/0849 7 (256,448,3)
928
+ 00074/0893 7 (256,448,3)
929
+ 00075/0333 7 (256,448,3)
930
+ 00075/0339 7 (256,448,3)
931
+ 00075/0347 7 (256,448,3)
932
+ 00075/0399 7 (256,448,3)
933
+ 00075/0478 7 (256,448,3)
934
+ 00075/0494 7 (256,448,3)
935
+ 00075/0678 7 (256,448,3)
936
+ 00075/0688 7 (256,448,3)
937
+ 00075/0706 7 (256,448,3)
938
+ 00075/0709 7 (256,448,3)
939
+ 00075/0748 7 (256,448,3)
940
+ 00075/0769 7 (256,448,3)
941
+ 00075/0777 7 (256,448,3)
942
+ 00075/0781 7 (256,448,3)
943
+ 00076/0151 7 (256,448,3)
944
+ 00076/0159 7 (256,448,3)
945
+ 00076/0164 7 (256,448,3)
946
+ 00076/0265 7 (256,448,3)
947
+ 00076/0269 7 (256,448,3)
948
+ 00076/0433 7 (256,448,3)
949
+ 00076/0813 7 (256,448,3)
950
+ 00076/0817 7 (256,448,3)
951
+ 00076/0818 7 (256,448,3)
952
+ 00076/0827 7 (256,448,3)
953
+ 00076/0874 7 (256,448,3)
954
+ 00076/0880 7 (256,448,3)
955
+ 00076/0891 7 (256,448,3)
956
+ 00076/0894 7 (256,448,3)
957
+ 00076/0909 7 (256,448,3)
958
+ 00076/0913 7 (256,448,3)
959
+ 00076/0926 7 (256,448,3)
960
+ 00076/0962 7 (256,448,3)
961
+ 00076/0973 7 (256,448,3)
962
+ 00076/0986 7 (256,448,3)
963
+ 00077/0617 7 (256,448,3)
964
+ 00077/0623 7 (256,448,3)
965
+ 00077/0628 7 (256,448,3)
966
+ 00077/0629 7 (256,448,3)
967
+ 00077/0631 7 (256,448,3)
968
+ 00077/0639 7 (256,448,3)
969
+ 00077/0982 7 (256,448,3)
970
+ 00077/0984 7 (256,448,3)
971
+ 00077/0995 7 (256,448,3)
972
+ 00077/0998 7 (256,448,3)
973
+ 00078/0001 7 (256,448,3)
974
+ 00078/0015 7 (256,448,3)
975
+ 00078/0157 7 (256,448,3)
976
+ 00078/0161 7 (256,448,3)
977
+ 00078/0175 7 (256,448,3)
978
+ 00078/0178 7 (256,448,3)
979
+ 00078/0189 7 (256,448,3)
980
+ 00078/0192 7 (256,448,3)
981
+ 00078/0229 7 (256,448,3)
982
+ 00078/0237 7 (256,448,3)
983
+ 00078/0241 7 (256,448,3)
984
+ 00078/0249 7 (256,448,3)
985
+ 00078/0251 7 (256,448,3)
986
+ 00078/0254 7 (256,448,3)
987
+ 00078/0258 7 (256,448,3)
988
+ 00078/0311 7 (256,448,3)
989
+ 00078/0603 7 (256,448,3)
990
+ 00078/0607 7 (256,448,3)
991
+ 00078/0824 7 (256,448,3)
992
+ 00079/0045 7 (256,448,3)
993
+ 00079/0048 7 (256,448,3)
994
+ 00079/0054 7 (256,448,3)
995
+ 00080/0050 7 (256,448,3)
996
+ 00080/0488 7 (256,448,3)
997
+ 00080/0494 7 (256,448,3)
998
+ 00080/0496 7 (256,448,3)
999
+ 00080/0499 7 (256,448,3)
1000
+ 00080/0502 7 (256,448,3)
1001
+ 00080/0510 7 (256,448,3)
1002
+ 00080/0534 7 (256,448,3)
1003
+ 00080/0558 7 (256,448,3)
1004
+ 00080/0571 7 (256,448,3)
1005
+ 00080/0709 7 (256,448,3)
1006
+ 00080/0882 7 (256,448,3)
1007
+ 00081/0322 7 (256,448,3)
1008
+ 00081/0428 7 (256,448,3)
1009
+ 00081/0700 7 (256,448,3)
1010
+ 00081/0706 7 (256,448,3)
1011
+ 00081/0707 7 (256,448,3)
1012
+ 00081/0937 7 (256,448,3)
1013
+ 00082/0021 7 (256,448,3)
1014
+ 00082/0424 7 (256,448,3)
1015
+ 00082/0794 7 (256,448,3)
1016
+ 00082/0807 7 (256,448,3)
1017
+ 00082/0810 7 (256,448,3)
1018
+ 00082/0824 7 (256,448,3)
1019
+ 00083/0129 7 (256,448,3)
1020
+ 00083/0131 7 (256,448,3)
1021
+ 00083/0249 7 (256,448,3)
1022
+ 00083/0250 7 (256,448,3)
1023
+ 00083/0656 7 (256,448,3)
1024
+ 00083/0812 7 (256,448,3)
1025
+ 00083/0819 7 (256,448,3)
1026
+ 00083/0824 7 (256,448,3)
1027
+ 00083/0827 7 (256,448,3)
1028
+ 00083/0841 7 (256,448,3)
1029
+ 00083/0963 7 (256,448,3)
1030
+ 00084/0047 7 (256,448,3)
1031
+ 00084/0319 7 (256,448,3)
1032
+ 00084/0334 7 (256,448,3)
1033
+ 00084/0363 7 (256,448,3)
1034
+ 00084/0493 7 (256,448,3)
1035
+ 00084/0655 7 (256,448,3)
1036
+ 00084/0752 7 (256,448,3)
1037
+ 00084/0813 7 (256,448,3)
1038
+ 00084/0886 7 (256,448,3)
1039
+ 00084/0948 7 (256,448,3)
1040
+ 00084/0976 7 (256,448,3)
1041
+ 00085/0512 7 (256,448,3)
1042
+ 00085/0641 7 (256,448,3)
1043
+ 00085/0653 7 (256,448,3)
1044
+ 00085/0655 7 (256,448,3)
1045
+ 00085/0697 7 (256,448,3)
1046
+ 00085/0698 7 (256,448,3)
1047
+ 00085/0700 7 (256,448,3)
1048
+ 00085/0703 7 (256,448,3)
1049
+ 00085/0705 7 (256,448,3)
1050
+ 00085/0709 7 (256,448,3)
1051
+ 00085/0713 7 (256,448,3)
1052
+ 00085/0739 7 (256,448,3)
1053
+ 00085/0750 7 (256,448,3)
1054
+ 00085/0763 7 (256,448,3)
1055
+ 00085/0765 7 (256,448,3)
1056
+ 00085/0769 7 (256,448,3)
1057
+ 00085/0863 7 (256,448,3)
1058
+ 00085/0868 7 (256,448,3)
1059
+ 00085/0927 7 (256,448,3)
1060
+ 00085/0936 7 (256,448,3)
1061
+ 00085/0965 7 (256,448,3)
1062
+ 00085/0969 7 (256,448,3)
1063
+ 00085/0974 7 (256,448,3)
1064
+ 00085/0981 7 (256,448,3)
1065
+ 00085/0982 7 (256,448,3)
1066
+ 00085/1000 7 (256,448,3)
1067
+ 00086/0003 7 (256,448,3)
1068
+ 00086/0009 7 (256,448,3)
1069
+ 00086/0011 7 (256,448,3)
1070
+ 00086/0028 7 (256,448,3)
1071
+ 00086/0032 7 (256,448,3)
1072
+ 00086/0034 7 (256,448,3)
1073
+ 00086/0035 7 (256,448,3)
1074
+ 00086/0042 7 (256,448,3)
1075
+ 00086/0064 7 (256,448,3)
1076
+ 00086/0066 7 (256,448,3)
1077
+ 00086/0095 7 (256,448,3)
1078
+ 00086/0099 7 (256,448,3)
1079
+ 00086/0101 7 (256,448,3)
1080
+ 00086/0104 7 (256,448,3)
1081
+ 00086/0115 7 (256,448,3)
1082
+ 00086/0116 7 (256,448,3)
1083
+ 00086/0284 7 (256,448,3)
1084
+ 00086/0291 7 (256,448,3)
1085
+ 00086/0295 7 (256,448,3)
1086
+ 00086/0302 7 (256,448,3)
1087
+ 00086/0318 7 (256,448,3)
1088
+ 00086/0666 7 (256,448,3)
1089
+ 00086/0797 7 (256,448,3)
1090
+ 00086/0851 7 (256,448,3)
1091
+ 00086/0855 7 (256,448,3)
1092
+ 00086/0874 7 (256,448,3)
1093
+ 00086/0878 7 (256,448,3)
1094
+ 00086/0881 7 (256,448,3)
1095
+ 00086/0883 7 (256,448,3)
1096
+ 00086/0896 7 (256,448,3)
1097
+ 00086/0899 7 (256,448,3)
1098
+ 00086/0903 7 (256,448,3)
1099
+ 00086/0989 7 (256,448,3)
1100
+ 00087/0008 7 (256,448,3)
1101
+ 00087/0429 7 (256,448,3)
1102
+ 00087/0511 7 (256,448,3)
1103
+ 00088/0241 7 (256,448,3)
1104
+ 00088/0319 7 (256,448,3)
1105
+ 00088/0323 7 (256,448,3)
1106
+ 00088/0411 7 (256,448,3)
1107
+ 00088/0427 7 (256,448,3)
1108
+ 00088/0452 7 (256,448,3)
1109
+ 00088/0463 7 (256,448,3)
1110
+ 00088/0476 7 (256,448,3)
1111
+ 00088/0496 7 (256,448,3)
1112
+ 00088/0559 7 (256,448,3)
1113
+ 00089/0058 7 (256,448,3)
1114
+ 00089/0061 7 (256,448,3)
1115
+ 00089/0069 7 (256,448,3)
1116
+ 00089/0077 7 (256,448,3)
1117
+ 00089/0096 7 (256,448,3)
1118
+ 00089/0099 7 (256,448,3)
1119
+ 00089/0100 7 (256,448,3)
1120
+ 00089/0211 7 (256,448,3)
1121
+ 00089/0380 7 (256,448,3)
1122
+ 00089/0381 7 (256,448,3)
1123
+ 00089/0384 7 (256,448,3)
1124
+ 00089/0390 7 (256,448,3)
1125
+ 00089/0393 7 (256,448,3)
1126
+ 00089/0394 7 (256,448,3)
1127
+ 00089/0395 7 (256,448,3)
1128
+ 00089/0406 7 (256,448,3)
1129
+ 00089/0410 7 (256,448,3)
1130
+ 00089/0412 7 (256,448,3)
1131
+ 00089/0703 7 (256,448,3)
1132
+ 00089/0729 7 (256,448,3)
1133
+ 00089/0930 7 (256,448,3)
1134
+ 00089/0952 7 (256,448,3)
1135
+ 00090/0062 7 (256,448,3)
1136
+ 00090/0101 7 (256,448,3)
1137
+ 00090/0213 7 (256,448,3)
1138
+ 00090/0216 7 (256,448,3)
1139
+ 00090/0268 7 (256,448,3)
1140
+ 00090/0406 7 (256,448,3)
1141
+ 00090/0411 7 (256,448,3)
1142
+ 00090/0442 7 (256,448,3)
1143
+ 00090/0535 7 (256,448,3)
1144
+ 00090/0542 7 (256,448,3)
1145
+ 00090/0571 7 (256,448,3)
1146
+ 00090/0934 7 (256,448,3)
1147
+ 00090/0938 7 (256,448,3)
1148
+ 00090/0947 7 (256,448,3)
1149
+ 00091/0066 7 (256,448,3)
1150
+ 00091/0448 7 (256,448,3)
1151
+ 00091/0451 7 (256,448,3)
1152
+ 00091/0454 7 (256,448,3)
1153
+ 00091/0457 7 (256,448,3)
1154
+ 00091/0467 7 (256,448,3)
1155
+ 00091/0470 7 (256,448,3)
1156
+ 00091/0477 7 (256,448,3)
1157
+ 00091/0583 7 (256,448,3)
1158
+ 00091/0981 7 (256,448,3)
1159
+ 00091/0994 7 (256,448,3)
1160
+ 00092/0112 7 (256,448,3)
1161
+ 00092/0119 7 (256,448,3)
1162
+ 00092/0129 7 (256,448,3)
1163
+ 00092/0146 7 (256,448,3)
1164
+ 00092/0149 7 (256,448,3)
1165
+ 00092/0608 7 (256,448,3)
1166
+ 00092/0643 7 (256,448,3)
1167
+ 00092/0646 7 (256,448,3)
1168
+ 00092/0766 7 (256,448,3)
1169
+ 00092/0768 7 (256,448,3)
1170
+ 00092/0779 7 (256,448,3)
1171
+ 00093/0081 7 (256,448,3)
1172
+ 00093/0085 7 (256,448,3)
1173
+ 00093/0135 7 (256,448,3)
1174
+ 00093/0241 7 (256,448,3)
1175
+ 00093/0277 7 (256,448,3)
1176
+ 00093/0283 7 (256,448,3)
1177
+ 00093/0320 7 (256,448,3)
1178
+ 00093/0598 7 (256,448,3)
1179
+ 00094/0159 7 (256,448,3)
1180
+ 00094/0253 7 (256,448,3)
1181
+ 00094/0265 7 (256,448,3)
1182
+ 00094/0267 7 (256,448,3)
1183
+ 00094/0269 7 (256,448,3)
1184
+ 00094/0281 7 (256,448,3)
1185
+ 00094/0293 7 (256,448,3)
1186
+ 00094/0404 7 (256,448,3)
1187
+ 00094/0593 7 (256,448,3)
1188
+ 00094/0612 7 (256,448,3)
1189
+ 00094/0638 7 (256,448,3)
1190
+ 00094/0656 7 (256,448,3)
1191
+ 00094/0668 7 (256,448,3)
1192
+ 00094/0786 7 (256,448,3)
1193
+ 00094/0870 7 (256,448,3)
1194
+ 00094/0897 7 (256,448,3)
1195
+ 00094/0900 7 (256,448,3)
1196
+ 00094/0944 7 (256,448,3)
1197
+ 00094/0946 7 (256,448,3)
1198
+ 00094/0952 7 (256,448,3)
1199
+ 00094/0969 7 (256,448,3)
1200
+ 00094/0973 7 (256,448,3)
1201
+ 00094/0981 7 (256,448,3)
1202
+ 00095/0088 7 (256,448,3)
1203
+ 00095/0125 7 (256,448,3)
1204
+ 00095/0130 7 (256,448,3)
1205
+ 00095/0142 7 (256,448,3)
1206
+ 00095/0151 7 (256,448,3)
1207
+ 00095/0180 7 (256,448,3)
1208
+ 00095/0192 7 (256,448,3)
1209
+ 00095/0194 7 (256,448,3)
1210
+ 00095/0195 7 (256,448,3)
1211
+ 00095/0204 7 (256,448,3)
1212
+ 00095/0245 7 (256,448,3)
1213
+ 00095/0315 7 (256,448,3)
1214
+ 00095/0321 7 (256,448,3)
1215
+ 00095/0324 7 (256,448,3)
1216
+ 00095/0327 7 (256,448,3)
1217
+ 00095/0730 7 (256,448,3)
1218
+ 00095/0731 7 (256,448,3)
1219
+ 00095/0741 7 (256,448,3)
1220
+ 00095/0948 7 (256,448,3)
1221
+ 00096/0407 7 (256,448,3)
1222
+ 00096/0420 7 (256,448,3)
1223
+ 00096/0435 7 (256,448,3)
1224
+ 00096/0682 7 (256,448,3)
1225
+ 00096/0865 7 (256,448,3)
basicsr/data/meta_info/meta_info_Vimeo90K_test_medium_GT.txt ADDED
The diff for this file is too large to render. See raw diff
 
basicsr/data/meta_info/meta_info_Vimeo90K_test_slow_GT.txt ADDED
@@ -0,0 +1,1613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 00001/0266 7 (256,448,3)
2
+ 00001/0268 7 (256,448,3)
3
+ 00001/0275 7 (256,448,3)
4
+ 00001/0278 7 (256,448,3)
5
+ 00001/0287 7 (256,448,3)
6
+ 00001/0291 7 (256,448,3)
7
+ 00001/0627 7 (256,448,3)
8
+ 00001/0636 7 (256,448,3)
9
+ 00001/0804 7 (256,448,3)
10
+ 00001/0837 7 (256,448,3)
11
+ 00001/0849 7 (256,448,3)
12
+ 00001/0851 7 (256,448,3)
13
+ 00001/0852 7 (256,448,3)
14
+ 00001/0986 7 (256,448,3)
15
+ 00001/0991 7 (256,448,3)
16
+ 00002/0007 7 (256,448,3)
17
+ 00002/0008 7 (256,448,3)
18
+ 00002/0016 7 (256,448,3)
19
+ 00002/0036 7 (256,448,3)
20
+ 00002/0091 7 (256,448,3)
21
+ 00002/0093 7 (256,448,3)
22
+ 00002/0209 7 (256,448,3)
23
+ 00002/0235 7 (256,448,3)
24
+ 00002/0236 7 (256,448,3)
25
+ 00002/0241 7 (256,448,3)
26
+ 00002/0466 7 (256,448,3)
27
+ 00002/0504 7 (256,448,3)
28
+ 00002/0960 7 (256,448,3)
29
+ 00002/0961 7 (256,448,3)
30
+ 00002/0964 7 (256,448,3)
31
+ 00003/0007 7 (256,448,3)
32
+ 00003/0069 7 (256,448,3)
33
+ 00003/0345 7 (256,448,3)
34
+ 00003/0347 7 (256,448,3)
35
+ 00003/0372 7 (256,448,3)
36
+ 00003/0525 7 (256,448,3)
37
+ 00003/0652 7 (256,448,3)
38
+ 00003/0667 7 (256,448,3)
39
+ 00003/0669 7 (256,448,3)
40
+ 00003/0706 7 (256,448,3)
41
+ 00003/0713 7 (256,448,3)
42
+ 00003/0721 7 (256,448,3)
43
+ 00003/0747 7 (256,448,3)
44
+ 00003/0829 7 (256,448,3)
45
+ 00003/0916 7 (256,448,3)
46
+ 00003/0918 7 (256,448,3)
47
+ 00003/0924 7 (256,448,3)
48
+ 00003/0926 7 (256,448,3)
49
+ 00003/0927 7 (256,448,3)
50
+ 00004/0288 7 (256,448,3)
51
+ 00004/0303 7 (256,448,3)
52
+ 00004/0307 7 (256,448,3)
53
+ 00004/0628 7 (256,448,3)
54
+ 00004/0713 7 (256,448,3)
55
+ 00004/0715 7 (256,448,3)
56
+ 00004/0719 7 (256,448,3)
57
+ 00004/0727 7 (256,448,3)
58
+ 00004/0821 7 (256,448,3)
59
+ 00005/0006 7 (256,448,3)
60
+ 00005/0007 7 (256,448,3)
61
+ 00005/0012 7 (256,448,3)
62
+ 00005/0013 7 (256,448,3)
63
+ 00005/0040 7 (256,448,3)
64
+ 00005/0055 7 (256,448,3)
65
+ 00005/0119 7 (256,448,3)
66
+ 00005/0130 7 (256,448,3)
67
+ 00005/0185 7 (256,448,3)
68
+ 00005/0198 7 (256,448,3)
69
+ 00005/0270 7 (256,448,3)
70
+ 00005/0541 7 (256,448,3)
71
+ 00005/0560 7 (256,448,3)
72
+ 00005/0660 7 (256,448,3)
73
+ 00005/0682 7 (256,448,3)
74
+ 00005/0683 7 (256,448,3)
75
+ 00005/0688 7 (256,448,3)
76
+ 00005/0706 7 (256,448,3)
77
+ 00005/0728 7 (256,448,3)
78
+ 00005/0732 7 (256,448,3)
79
+ 00005/0739 7 (256,448,3)
80
+ 00005/0804 7 (256,448,3)
81
+ 00005/0805 7 (256,448,3)
82
+ 00005/0827 7 (256,448,3)
83
+ 00005/0828 7 (256,448,3)
84
+ 00005/0857 7 (256,448,3)
85
+ 00005/0861 7 (256,448,3)
86
+ 00005/0862 7 (256,448,3)
87
+ 00005/0868 7 (256,448,3)
88
+ 00005/0872 7 (256,448,3)
89
+ 00005/0933 7 (256,448,3)
90
+ 00005/0958 7 (256,448,3)
91
+ 00005/0960 7 (256,448,3)
92
+ 00006/0087 7 (256,448,3)
93
+ 00006/0090 7 (256,448,3)
94
+ 00006/0351 7 (256,448,3)
95
+ 00006/0353 7 (256,448,3)
96
+ 00006/0558 7 (256,448,3)
97
+ 00006/0588 7 (256,448,3)
98
+ 00006/0619 7 (256,448,3)
99
+ 00006/0621 7 (256,448,3)
100
+ 00006/0748 7 (256,448,3)
101
+ 00006/0796 7 (256,448,3)
102
+ 00006/0805 7 (256,448,3)
103
+ 00006/0807 7 (256,448,3)
104
+ 00007/0236 7 (256,448,3)
105
+ 00007/0240 7 (256,448,3)
106
+ 00007/0243 7 (256,448,3)
107
+ 00007/0246 7 (256,448,3)
108
+ 00007/0247 7 (256,448,3)
109
+ 00007/0252 7 (256,448,3)
110
+ 00007/0322 7 (256,448,3)
111
+ 00007/0458 7 (256,448,3)
112
+ 00007/0492 7 (256,448,3)
113
+ 00007/0658 7 (256,448,3)
114
+ 00007/0717 7 (256,448,3)
115
+ 00007/0722 7 (256,448,3)
116
+ 00007/0725 7 (256,448,3)
117
+ 00007/0740 7 (256,448,3)
118
+ 00007/0748 7 (256,448,3)
119
+ 00007/0749 7 (256,448,3)
120
+ 00007/0759 7 (256,448,3)
121
+ 00007/0772 7 (256,448,3)
122
+ 00007/0783 7 (256,448,3)
123
+ 00007/0787 7 (256,448,3)
124
+ 00007/0883 7 (256,448,3)
125
+ 00008/0033 7 (256,448,3)
126
+ 00008/0035 7 (256,448,3)
127
+ 00008/0091 7 (256,448,3)
128
+ 00008/0154 7 (256,448,3)
129
+ 00008/0966 7 (256,448,3)
130
+ 00008/0987 7 (256,448,3)
131
+ 00009/0108 7 (256,448,3)
132
+ 00009/0607 7 (256,448,3)
133
+ 00009/0668 7 (256,448,3)
134
+ 00009/0683 7 (256,448,3)
135
+ 00009/0941 7 (256,448,3)
136
+ 00009/0949 7 (256,448,3)
137
+ 00009/0962 7 (256,448,3)
138
+ 00009/0972 7 (256,448,3)
139
+ 00009/0974 7 (256,448,3)
140
+ 00010/0014 7 (256,448,3)
141
+ 00010/0018 7 (256,448,3)
142
+ 00010/0043 7 (256,448,3)
143
+ 00010/0099 7 (256,448,3)
144
+ 00010/0252 7 (256,448,3)
145
+ 00010/0296 7 (256,448,3)
146
+ 00010/0413 7 (256,448,3)
147
+ 00010/0422 7 (256,448,3)
148
+ 00010/0516 7 (256,448,3)
149
+ 00010/0525 7 (256,448,3)
150
+ 00010/0556 7 (256,448,3)
151
+ 00010/0701 7 (256,448,3)
152
+ 00010/0740 7 (256,448,3)
153
+ 00010/0772 7 (256,448,3)
154
+ 00010/0831 7 (256,448,3)
155
+ 00010/0925 7 (256,448,3)
156
+ 00011/0013 7 (256,448,3)
157
+ 00011/0016 7 (256,448,3)
158
+ 00011/0017 7 (256,448,3)
159
+ 00011/0249 7 (256,448,3)
160
+ 00011/0826 7 (256,448,3)
161
+ 00011/0827 7 (256,448,3)
162
+ 00011/0831 7 (256,448,3)
163
+ 00011/0833 7 (256,448,3)
164
+ 00011/0835 7 (256,448,3)
165
+ 00011/0998 7 (256,448,3)
166
+ 00012/0023 7 (256,448,3)
167
+ 00012/0024 7 (256,448,3)
168
+ 00012/0027 7 (256,448,3)
169
+ 00012/0037 7 (256,448,3)
170
+ 00012/0444 7 (256,448,3)
171
+ 00012/0445 7 (256,448,3)
172
+ 00012/0451 7 (256,448,3)
173
+ 00012/0461 7 (256,448,3)
174
+ 00012/0521 7 (256,448,3)
175
+ 00012/0758 7 (256,448,3)
176
+ 00012/0760 7 (256,448,3)
177
+ 00012/0771 7 (256,448,3)
178
+ 00012/0903 7 (256,448,3)
179
+ 00012/0909 7 (256,448,3)
180
+ 00013/0581 7 (256,448,3)
181
+ 00013/0786 7 (256,448,3)
182
+ 00013/0789 7 (256,448,3)
183
+ 00013/0791 7 (256,448,3)
184
+ 00013/0798 7 (256,448,3)
185
+ 00013/0802 7 (256,448,3)
186
+ 00013/0820 7 (256,448,3)
187
+ 00013/0850 7 (256,448,3)
188
+ 00013/0854 7 (256,448,3)
189
+ 00013/0894 7 (256,448,3)
190
+ 00013/0919 7 (256,448,3)
191
+ 00013/0999 7 (256,448,3)
192
+ 00014/0001 7 (256,448,3)
193
+ 00014/0014 7 (256,448,3)
194
+ 00014/0018 7 (256,448,3)
195
+ 00014/0244 7 (256,448,3)
196
+ 00014/0475 7 (256,448,3)
197
+ 00014/0483 7 (256,448,3)
198
+ 00014/0680 7 (256,448,3)
199
+ 00014/0700 7 (256,448,3)
200
+ 00014/0701 7 (256,448,3)
201
+ 00014/0706 7 (256,448,3)
202
+ 00014/0712 7 (256,448,3)
203
+ 00014/0713 7 (256,448,3)
204
+ 00014/0717 7 (256,448,3)
205
+ 00014/0719 7 (256,448,3)
206
+ 00014/0728 7 (256,448,3)
207
+ 00014/0734 7 (256,448,3)
208
+ 00014/0736 7 (256,448,3)
209
+ 00014/0738 7 (256,448,3)
210
+ 00014/0742 7 (256,448,3)
211
+ 00014/0745 7 (256,448,3)
212
+ 00014/0746 7 (256,448,3)
213
+ 00014/0750 7 (256,448,3)
214
+ 00014/0769 7 (256,448,3)
215
+ 00014/0774 7 (256,448,3)
216
+ 00014/0781 7 (256,448,3)
217
+ 00014/0782 7 (256,448,3)
218
+ 00014/0852 7 (256,448,3)
219
+ 00014/0853 7 (256,448,3)
220
+ 00014/0855 7 (256,448,3)
221
+ 00014/0867 7 (256,448,3)
222
+ 00014/0876 7 (256,448,3)
223
+ 00014/0881 7 (256,448,3)
224
+ 00014/0890 7 (256,448,3)
225
+ 00014/0914 7 (256,448,3)
226
+ 00015/0033 7 (256,448,3)
227
+ 00015/0113 7 (256,448,3)
228
+ 00015/0125 7 (256,448,3)
229
+ 00015/0185 7 (256,448,3)
230
+ 00015/0194 7 (256,448,3)
231
+ 00015/0202 7 (256,448,3)
232
+ 00015/0312 7 (256,448,3)
233
+ 00015/0688 7 (256,448,3)
234
+ 00015/0698 7 (256,448,3)
235
+ 00015/0788 7 (256,448,3)
236
+ 00015/0854 7 (256,448,3)
237
+ 00015/0863 7 (256,448,3)
238
+ 00015/0864 7 (256,448,3)
239
+ 00015/0918 7 (256,448,3)
240
+ 00015/0931 7 (256,448,3)
241
+ 00016/0276 7 (256,448,3)
242
+ 00016/0301 7 (256,448,3)
243
+ 00016/0306 7 (256,448,3)
244
+ 00016/0324 7 (256,448,3)
245
+ 00016/0362 7 (256,448,3)
246
+ 00016/0364 7 (256,448,3)
247
+ 00016/0370 7 (256,448,3)
248
+ 00016/0378 7 (256,448,3)
249
+ 00016/0379 7 (256,448,3)
250
+ 00016/0402 7 (256,448,3)
251
+ 00016/0405 7 (256,448,3)
252
+ 00016/0418 7 (256,448,3)
253
+ 00016/0419 7 (256,448,3)
254
+ 00016/0435 7 (256,448,3)
255
+ 00016/0501 7 (256,448,3)
256
+ 00016/0561 7 (256,448,3)
257
+ 00016/0562 7 (256,448,3)
258
+ 00016/0569 7 (256,448,3)
259
+ 00016/0591 7 (256,448,3)
260
+ 00016/0599 7 (256,448,3)
261
+ 00016/0711 7 (256,448,3)
262
+ 00016/0713 7 (256,448,3)
263
+ 00016/0813 7 (256,448,3)
264
+ 00016/0953 7 (256,448,3)
265
+ 00016/0960 7 (256,448,3)
266
+ 00016/0961 7 (256,448,3)
267
+ 00017/0519 7 (256,448,3)
268
+ 00017/0523 7 (256,448,3)
269
+ 00017/0588 7 (256,448,3)
270
+ 00017/0608 7 (256,448,3)
271
+ 00017/0609 7 (256,448,3)
272
+ 00017/0719 7 (256,448,3)
273
+ 00017/0721 7 (256,448,3)
274
+ 00017/0727 7 (256,448,3)
275
+ 00017/0728 7 (256,448,3)
276
+ 00017/0769 7 (256,448,3)
277
+ 00017/0775 7 (256,448,3)
278
+ 00017/0787 7 (256,448,3)
279
+ 00017/0797 7 (256,448,3)
280
+ 00018/0043 7 (256,448,3)
281
+ 00018/0206 7 (256,448,3)
282
+ 00018/0209 7 (256,448,3)
283
+ 00018/0211 7 (256,448,3)
284
+ 00018/0216 7 (256,448,3)
285
+ 00018/0220 7 (256,448,3)
286
+ 00018/0221 7 (256,448,3)
287
+ 00018/0252 7 (256,448,3)
288
+ 00018/0260 7 (256,448,3)
289
+ 00018/0331 7 (256,448,3)
290
+ 00018/0333 7 (256,448,3)
291
+ 00018/0447 7 (256,448,3)
292
+ 00018/0523 7 (256,448,3)
293
+ 00019/0014 7 (256,448,3)
294
+ 00019/0015 7 (256,448,3)
295
+ 00019/0019 7 (256,448,3)
296
+ 00019/0049 7 (256,448,3)
297
+ 00019/0109 7 (256,448,3)
298
+ 00019/0114 7 (256,448,3)
299
+ 00019/0125 7 (256,448,3)
300
+ 00019/0137 7 (256,448,3)
301
+ 00019/0140 7 (256,448,3)
302
+ 00019/0148 7 (256,448,3)
303
+ 00019/0153 7 (256,448,3)
304
+ 00019/0155 7 (256,448,3)
305
+ 00019/0158 7 (256,448,3)
306
+ 00019/0159 7 (256,448,3)
307
+ 00019/0160 7 (256,448,3)
308
+ 00019/0162 7 (256,448,3)
309
+ 00019/0279 7 (256,448,3)
310
+ 00019/0282 7 (256,448,3)
311
+ 00019/0409 7 (256,448,3)
312
+ 00019/0427 7 (256,448,3)
313
+ 00019/0430 7 (256,448,3)
314
+ 00019/0545 7 (256,448,3)
315
+ 00019/0555 7 (256,448,3)
316
+ 00019/0558 7 (256,448,3)
317
+ 00019/0650 7 (256,448,3)
318
+ 00019/0681 7 (256,448,3)
319
+ 00019/0747 7 (256,448,3)
320
+ 00019/0748 7 (256,448,3)
321
+ 00019/0749 7 (256,448,3)
322
+ 00019/0752 7 (256,448,3)
323
+ 00019/0768 7 (256,448,3)
324
+ 00019/0772 7 (256,448,3)
325
+ 00019/0773 7 (256,448,3)
326
+ 00019/0777 7 (256,448,3)
327
+ 00019/0795 7 (256,448,3)
328
+ 00019/0806 7 (256,448,3)
329
+ 00019/0815 7 (256,448,3)
330
+ 00019/0840 7 (256,448,3)
331
+ 00019/0844 7 (256,448,3)
332
+ 00019/0848 7 (256,448,3)
333
+ 00019/0853 7 (256,448,3)
334
+ 00019/0863 7 (256,448,3)
335
+ 00019/0888 7 (256,448,3)
336
+ 00019/0894 7 (256,448,3)
337
+ 00019/0901 7 (256,448,3)
338
+ 00019/0995 7 (256,448,3)
339
+ 00021/0030 7 (256,448,3)
340
+ 00021/0035 7 (256,448,3)
341
+ 00021/0039 7 (256,448,3)
342
+ 00021/0041 7 (256,448,3)
343
+ 00021/0044 7 (256,448,3)
344
+ 00021/0045 7 (256,448,3)
345
+ 00021/0264 7 (256,448,3)
346
+ 00021/0330 7 (256,448,3)
347
+ 00021/0332 7 (256,448,3)
348
+ 00021/0333 7 (256,448,3)
349
+ 00021/0336 7 (256,448,3)
350
+ 00021/0337 7 (256,448,3)
351
+ 00021/0338 7 (256,448,3)
352
+ 00021/0343 7 (256,448,3)
353
+ 00021/0472 7 (256,448,3)
354
+ 00021/0667 7 (256,448,3)
355
+ 00021/0731 7 (256,448,3)
356
+ 00021/0779 7 (256,448,3)
357
+ 00021/0805 7 (256,448,3)
358
+ 00021/0814 7 (256,448,3)
359
+ 00021/0818 7 (256,448,3)
360
+ 00021/0874 7 (256,448,3)
361
+ 00022/0008 7 (256,448,3)
362
+ 00022/0010 7 (256,448,3)
363
+ 00022/0231 7 (256,448,3)
364
+ 00022/0323 7 (256,448,3)
365
+ 00022/0337 7 (256,448,3)
366
+ 00022/0359 7 (256,448,3)
367
+ 00022/0377 7 (256,448,3)
368
+ 00022/0378 7 (256,448,3)
369
+ 00022/0385 7 (256,448,3)
370
+ 00022/0393 7 (256,448,3)
371
+ 00022/0424 7 (256,448,3)
372
+ 00022/0582 7 (256,448,3)
373
+ 00022/0583 7 (256,448,3)
374
+ 00022/0605 7 (256,448,3)
375
+ 00022/0632 7 (256,448,3)
376
+ 00022/0633 7 (256,448,3)
377
+ 00022/0666 7 (256,448,3)
378
+ 00022/0671 7 (256,448,3)
379
+ 00022/0673 7 (256,448,3)
380
+ 00022/0702 7 (256,448,3)
381
+ 00022/0852 7 (256,448,3)
382
+ 00022/0853 7 (256,448,3)
383
+ 00022/0971 7 (256,448,3)
384
+ 00023/0037 7 (256,448,3)
385
+ 00023/0224 7 (256,448,3)
386
+ 00023/0308 7 (256,448,3)
387
+ 00023/0393 7 (256,448,3)
388
+ 00023/0633 7 (256,448,3)
389
+ 00023/0637 7 (256,448,3)
390
+ 00023/0638 7 (256,448,3)
391
+ 00023/0770 7 (256,448,3)
392
+ 00023/0786 7 (256,448,3)
393
+ 00023/0898 7 (256,448,3)
394
+ 00024/0247 7 (256,448,3)
395
+ 00024/0251 7 (256,448,3)
396
+ 00024/0267 7 (256,448,3)
397
+ 00024/0288 7 (256,448,3)
398
+ 00024/0530 7 (256,448,3)
399
+ 00024/0569 7 (256,448,3)
400
+ 00024/0587 7 (256,448,3)
401
+ 00024/0730 7 (256,448,3)
402
+ 00024/0736 7 (256,448,3)
403
+ 00024/0742 7 (256,448,3)
404
+ 00024/0832 7 (256,448,3)
405
+ 00024/0936 7 (256,448,3)
406
+ 00025/0044 7 (256,448,3)
407
+ 00025/0047 7 (256,448,3)
408
+ 00025/0540 7 (256,448,3)
409
+ 00025/0552 7 (256,448,3)
410
+ 00025/0554 7 (256,448,3)
411
+ 00025/0559 7 (256,448,3)
412
+ 00025/0572 7 (256,448,3)
413
+ 00025/0576 7 (256,448,3)
414
+ 00025/0699 7 (256,448,3)
415
+ 00025/0709 7 (256,448,3)
416
+ 00025/0743 7 (256,448,3)
417
+ 00025/0767 7 (256,448,3)
418
+ 00025/0780 7 (256,448,3)
419
+ 00025/0782 7 (256,448,3)
420
+ 00025/0784 7 (256,448,3)
421
+ 00025/0791 7 (256,448,3)
422
+ 00025/0889 7 (256,448,3)
423
+ 00025/0890 7 (256,448,3)
424
+ 00025/0894 7 (256,448,3)
425
+ 00025/0896 7 (256,448,3)
426
+ 00025/0898 7 (256,448,3)
427
+ 00025/0905 7 (256,448,3)
428
+ 00025/0999 7 (256,448,3)
429
+ 00026/0003 7 (256,448,3)
430
+ 00026/0005 7 (256,448,3)
431
+ 00026/0011 7 (256,448,3)
432
+ 00026/0017 7 (256,448,3)
433
+ 00026/0036 7 (256,448,3)
434
+ 00026/0129 7 (256,448,3)
435
+ 00026/0131 7 (256,448,3)
436
+ 00026/0161 7 (256,448,3)
437
+ 00026/0177 7 (256,448,3)
438
+ 00026/0178 7 (256,448,3)
439
+ 00026/0180 7 (256,448,3)
440
+ 00026/0298 7 (256,448,3)
441
+ 00026/0307 7 (256,448,3)
442
+ 00026/0308 7 (256,448,3)
443
+ 00026/0312 7 (256,448,3)
444
+ 00026/0352 7 (256,448,3)
445
+ 00026/0440 7 (256,448,3)
446
+ 00026/0706 7 (256,448,3)
447
+ 00026/0708 7 (256,448,3)
448
+ 00026/0715 7 (256,448,3)
449
+ 00026/0769 7 (256,448,3)
450
+ 00026/0777 7 (256,448,3)
451
+ 00026/0779 7 (256,448,3)
452
+ 00026/0789 7 (256,448,3)
453
+ 00026/0924 7 (256,448,3)
454
+ 00026/0928 7 (256,448,3)
455
+ 00026/0932 7 (256,448,3)
456
+ 00026/0935 7 (256,448,3)
457
+ 00027/0118 7 (256,448,3)
458
+ 00027/0121 7 (256,448,3)
459
+ 00027/0155 7 (256,448,3)
460
+ 00027/0168 7 (256,448,3)
461
+ 00027/0196 7 (256,448,3)
462
+ 00027/0289 7 (256,448,3)
463
+ 00027/0294 7 (256,448,3)
464
+ 00027/0803 7 (256,448,3)
465
+ 00028/0016 7 (256,448,3)
466
+ 00028/0045 7 (256,448,3)
467
+ 00028/0063 7 (256,448,3)
468
+ 00028/0601 7 (256,448,3)
469
+ 00028/0638 7 (256,448,3)
470
+ 00028/0733 7 (256,448,3)
471
+ 00028/0736 7 (256,448,3)
472
+ 00028/0741 7 (256,448,3)
473
+ 00028/0753 7 (256,448,3)
474
+ 00028/0770 7 (256,448,3)
475
+ 00028/0771 7 (256,448,3)
476
+ 00028/0777 7 (256,448,3)
477
+ 00028/0950 7 (256,448,3)
478
+ 00028/0951 7 (256,448,3)
479
+ 00029/0048 7 (256,448,3)
480
+ 00029/0060 7 (256,448,3)
481
+ 00029/0362 7 (256,448,3)
482
+ 00029/0399 7 (256,448,3)
483
+ 00029/0404 7 (256,448,3)
484
+ 00029/0412 7 (256,448,3)
485
+ 00029/0416 7 (256,448,3)
486
+ 00029/0418 7 (256,448,3)
487
+ 00029/0428 7 (256,448,3)
488
+ 00030/0131 7 (256,448,3)
489
+ 00030/0135 7 (256,448,3)
490
+ 00030/0150 7 (256,448,3)
491
+ 00030/0245 7 (256,448,3)
492
+ 00030/0339 7 (256,448,3)
493
+ 00030/0472 7 (256,448,3)
494
+ 00030/0482 7 (256,448,3)
495
+ 00030/0500 7 (256,448,3)
496
+ 00030/0501 7 (256,448,3)
497
+ 00030/0697 7 (256,448,3)
498
+ 00030/0707 7 (256,448,3)
499
+ 00030/0733 7 (256,448,3)
500
+ 00030/0743 7 (256,448,3)
501
+ 00030/0747 7 (256,448,3)
502
+ 00030/0754 7 (256,448,3)
503
+ 00030/0755 7 (256,448,3)
504
+ 00030/0759 7 (256,448,3)
505
+ 00030/0762 7 (256,448,3)
506
+ 00030/0764 7 (256,448,3)
507
+ 00030/0767 7 (256,448,3)
508
+ 00030/0794 7 (256,448,3)
509
+ 00030/0796 7 (256,448,3)
510
+ 00030/0799 7 (256,448,3)
511
+ 00030/0814 7 (256,448,3)
512
+ 00030/0823 7 (256,448,3)
513
+ 00030/0829 7 (256,448,3)
514
+ 00030/0833 7 (256,448,3)
515
+ 00030/0848 7 (256,448,3)
516
+ 00030/0853 7 (256,448,3)
517
+ 00030/0861 7 (256,448,3)
518
+ 00031/0182 7 (256,448,3)
519
+ 00031/0275 7 (256,448,3)
520
+ 00031/0279 7 (256,448,3)
521
+ 00031/0555 7 (256,448,3)
522
+ 00031/0648 7 (256,448,3)
523
+ 00031/0663 7 (256,448,3)
524
+ 00031/0680 7 (256,448,3)
525
+ 00031/0880 7 (256,448,3)
526
+ 00031/0922 7 (256,448,3)
527
+ 00031/0925 7 (256,448,3)
528
+ 00031/0928 7 (256,448,3)
529
+ 00032/0025 7 (256,448,3)
530
+ 00032/0377 7 (256,448,3)
531
+ 00032/0378 7 (256,448,3)
532
+ 00032/0382 7 (256,448,3)
533
+ 00032/0384 7 (256,448,3)
534
+ 00032/0386 7 (256,448,3)
535
+ 00032/0389 7 (256,448,3)
536
+ 00032/0391 7 (256,448,3)
537
+ 00032/0393 7 (256,448,3)
538
+ 00032/0492 7 (256,448,3)
539
+ 00032/0497 7 (256,448,3)
540
+ 00032/0505 7 (256,448,3)
541
+ 00032/0523 7 (256,448,3)
542
+ 00032/0542 7 (256,448,3)
543
+ 00032/0544 7 (256,448,3)
544
+ 00032/0712 7 (256,448,3)
545
+ 00032/0847 7 (256,448,3)
546
+ 00032/0850 7 (256,448,3)
547
+ 00032/0875 7 (256,448,3)
548
+ 00033/0062 7 (256,448,3)
549
+ 00033/0063 7 (256,448,3)
550
+ 00033/0098 7 (256,448,3)
551
+ 00033/0101 7 (256,448,3)
552
+ 00033/0105 7 (256,448,3)
553
+ 00033/0114 7 (256,448,3)
554
+ 00033/0432 7 (256,448,3)
555
+ 00033/0441 7 (256,448,3)
556
+ 00033/0606 7 (256,448,3)
557
+ 00033/0611 7 (256,448,3)
558
+ 00033/0634 7 (256,448,3)
559
+ 00033/0787 7 (256,448,3)
560
+ 00033/0792 7 (256,448,3)
561
+ 00033/0802 7 (256,448,3)
562
+ 00033/0825 7 (256,448,3)
563
+ 00033/0835 7 (256,448,3)
564
+ 00034/0249 7 (256,448,3)
565
+ 00034/0253 7 (256,448,3)
566
+ 00034/0254 7 (256,448,3)
567
+ 00034/0282 7 (256,448,3)
568
+ 00034/0318 7 (256,448,3)
569
+ 00034/0319 7 (256,448,3)
570
+ 00034/0323 7 (256,448,3)
571
+ 00034/0336 7 (256,448,3)
572
+ 00034/0348 7 (256,448,3)
573
+ 00034/0356 7 (256,448,3)
574
+ 00034/0379 7 (256,448,3)
575
+ 00034/0387 7 (256,448,3)
576
+ 00034/0575 7 (256,448,3)
577
+ 00034/0608 7 (256,448,3)
578
+ 00034/0663 7 (256,448,3)
579
+ 00034/0811 7 (256,448,3)
580
+ 00034/0812 7 (256,448,3)
581
+ 00034/0946 7 (256,448,3)
582
+ 00034/0948 7 (256,448,3)
583
+ 00034/0950 7 (256,448,3)
584
+ 00035/0204 7 (256,448,3)
585
+ 00035/0243 7 (256,448,3)
586
+ 00035/0308 7 (256,448,3)
587
+ 00035/0465 7 (256,448,3)
588
+ 00035/0478 7 (256,448,3)
589
+ 00035/0523 7 (256,448,3)
590
+ 00035/0540 7 (256,448,3)
591
+ 00035/0544 7 (256,448,3)
592
+ 00035/0556 7 (256,448,3)
593
+ 00035/0568 7 (256,448,3)
594
+ 00035/0570 7 (256,448,3)
595
+ 00035/0609 7 (256,448,3)
596
+ 00035/0643 7 (256,448,3)
597
+ 00035/0644 7 (256,448,3)
598
+ 00035/0645 7 (256,448,3)
599
+ 00035/0646 7 (256,448,3)
600
+ 00035/0650 7 (256,448,3)
601
+ 00035/0661 7 (256,448,3)
602
+ 00035/0724 7 (256,448,3)
603
+ 00035/0725 7 (256,448,3)
604
+ 00035/0850 7 (256,448,3)
605
+ 00035/0863 7 (256,448,3)
606
+ 00035/0870 7 (256,448,3)
607
+ 00035/0951 7 (256,448,3)
608
+ 00036/0038 7 (256,448,3)
609
+ 00036/0062 7 (256,448,3)
610
+ 00036/0423 7 (256,448,3)
611
+ 00036/0737 7 (256,448,3)
612
+ 00036/0750 7 (256,448,3)
613
+ 00036/0751 7 (256,448,3)
614
+ 00036/0754 7 (256,448,3)
615
+ 00036/0929 7 (256,448,3)
616
+ 00037/0085 7 (256,448,3)
617
+ 00037/0113 7 (256,448,3)
618
+ 00037/0130 7 (256,448,3)
619
+ 00037/0153 7 (256,448,3)
620
+ 00037/0169 7 (256,448,3)
621
+ 00037/0263 7 (256,448,3)
622
+ 00037/0272 7 (256,448,3)
623
+ 00037/0273 7 (256,448,3)
624
+ 00037/0275 7 (256,448,3)
625
+ 00037/0280 7 (256,448,3)
626
+ 00037/0399 7 (256,448,3)
627
+ 00037/0456 7 (256,448,3)
628
+ 00037/0853 7 (256,448,3)
629
+ 00037/0855 7 (256,448,3)
630
+ 00037/0856 7 (256,448,3)
631
+ 00037/0857 7 (256,448,3)
632
+ 00037/0925 7 (256,448,3)
633
+ 00037/0947 7 (256,448,3)
634
+ 00038/0148 7 (256,448,3)
635
+ 00038/0533 7 (256,448,3)
636
+ 00038/0534 7 (256,448,3)
637
+ 00038/0560 7 (256,448,3)
638
+ 00038/0562 7 (256,448,3)
639
+ 00038/0566 7 (256,448,3)
640
+ 00038/0578 7 (256,448,3)
641
+ 00038/0652 7 (256,448,3)
642
+ 00038/0674 7 (256,448,3)
643
+ 00038/0685 7 (256,448,3)
644
+ 00038/0686 7 (256,448,3)
645
+ 00038/0692 7 (256,448,3)
646
+ 00038/0736 7 (256,448,3)
647
+ 00039/0035 7 (256,448,3)
648
+ 00039/0105 7 (256,448,3)
649
+ 00039/0109 7 (256,448,3)
650
+ 00039/0121 7 (256,448,3)
651
+ 00039/0128 7 (256,448,3)
652
+ 00039/0129 7 (256,448,3)
653
+ 00039/0132 7 (256,448,3)
654
+ 00039/0137 7 (256,448,3)
655
+ 00039/0157 7 (256,448,3)
656
+ 00039/0496 7 (256,448,3)
657
+ 00039/0502 7 (256,448,3)
658
+ 00039/0526 7 (256,448,3)
659
+ 00039/0529 7 (256,448,3)
660
+ 00039/0682 7 (256,448,3)
661
+ 00039/0690 7 (256,448,3)
662
+ 00039/0693 7 (256,448,3)
663
+ 00039/0703 7 (256,448,3)
664
+ 00039/0725 7 (256,448,3)
665
+ 00039/0734 7 (256,448,3)
666
+ 00040/0518 7 (256,448,3)
667
+ 00040/0728 7 (256,448,3)
668
+ 00040/0774 7 (256,448,3)
669
+ 00040/0812 7 (256,448,3)
670
+ 00040/0818 7 (256,448,3)
671
+ 00040/0827 7 (256,448,3)
672
+ 00040/0914 7 (256,448,3)
673
+ 00040/0917 7 (256,448,3)
674
+ 00040/0918 7 (256,448,3)
675
+ 00040/0924 7 (256,448,3)
676
+ 00040/0925 7 (256,448,3)
677
+ 00041/0004 7 (256,448,3)
678
+ 00041/0006 7 (256,448,3)
679
+ 00041/0013 7 (256,448,3)
680
+ 00041/0059 7 (256,448,3)
681
+ 00041/0110 7 (256,448,3)
682
+ 00041/0291 7 (256,448,3)
683
+ 00041/0366 7 (256,448,3)
684
+ 00041/0388 7 (256,448,3)
685
+ 00041/0434 7 (256,448,3)
686
+ 00041/0436 7 (256,448,3)
687
+ 00041/0450 7 (256,448,3)
688
+ 00041/0457 7 (256,448,3)
689
+ 00041/0460 7 (256,448,3)
690
+ 00041/0468 7 (256,448,3)
691
+ 00041/0471 7 (256,448,3)
692
+ 00041/0474 7 (256,448,3)
693
+ 00041/0809 7 (256,448,3)
694
+ 00041/0844 7 (256,448,3)
695
+ 00041/0858 7 (256,448,3)
696
+ 00041/0874 7 (256,448,3)
697
+ 00041/0876 7 (256,448,3)
698
+ 00042/0020 7 (256,448,3)
699
+ 00042/0205 7 (256,448,3)
700
+ 00042/0206 7 (256,448,3)
701
+ 00042/0432 7 (256,448,3)
702
+ 00042/0563 7 (256,448,3)
703
+ 00042/0569 7 (256,448,3)
704
+ 00042/0575 7 (256,448,3)
705
+ 00042/0576 7 (256,448,3)
706
+ 00042/0888 7 (256,448,3)
707
+ 00042/0892 7 (256,448,3)
708
+ 00042/0943 7 (256,448,3)
709
+ 00042/0944 7 (256,448,3)
710
+ 00043/0126 7 (256,448,3)
711
+ 00043/0130 7 (256,448,3)
712
+ 00043/0136 7 (256,448,3)
713
+ 00043/0233 7 (256,448,3)
714
+ 00043/0235 7 (256,448,3)
715
+ 00043/0237 7 (256,448,3)
716
+ 00043/0277 7 (256,448,3)
717
+ 00043/0301 7 (256,448,3)
718
+ 00043/0302 7 (256,448,3)
719
+ 00043/0303 7 (256,448,3)
720
+ 00043/0308 7 (256,448,3)
721
+ 00043/0309 7 (256,448,3)
722
+ 00043/0314 7 (256,448,3)
723
+ 00043/0713 7 (256,448,3)
724
+ 00043/0715 7 (256,448,3)
725
+ 00043/0923 7 (256,448,3)
726
+ 00044/0095 7 (256,448,3)
727
+ 00044/0255 7 (256,448,3)
728
+ 00044/0864 7 (256,448,3)
729
+ 00044/0892 7 (256,448,3)
730
+ 00044/0898 7 (256,448,3)
731
+ 00044/0993 7 (256,448,3)
732
+ 00044/0995 7 (256,448,3)
733
+ 00044/0997 7 (256,448,3)
734
+ 00045/0001 7 (256,448,3)
735
+ 00045/0006 7 (256,448,3)
736
+ 00045/0269 7 (256,448,3)
737
+ 00045/0276 7 (256,448,3)
738
+ 00045/0280 7 (256,448,3)
739
+ 00045/0281 7 (256,448,3)
740
+ 00045/0282 7 (256,448,3)
741
+ 00045/0284 7 (256,448,3)
742
+ 00045/0550 7 (256,448,3)
743
+ 00045/0571 7 (256,448,3)
744
+ 00045/0629 7 (256,448,3)
745
+ 00045/0631 7 (256,448,3)
746
+ 00045/0659 7 (256,448,3)
747
+ 00045/0693 7 (256,448,3)
748
+ 00045/0807 7 (256,448,3)
749
+ 00045/0810 7 (256,448,3)
750
+ 00045/0826 7 (256,448,3)
751
+ 00045/0849 7 (256,448,3)
752
+ 00045/0946 7 (256,448,3)
753
+ 00045/0987 7 (256,448,3)
754
+ 00045/0990 7 (256,448,3)
755
+ 00046/0104 7 (256,448,3)
756
+ 00046/0477 7 (256,448,3)
757
+ 00046/0490 7 (256,448,3)
758
+ 00046/0491 7 (256,448,3)
759
+ 00046/0509 7 (256,448,3)
760
+ 00046/0513 7 (256,448,3)
761
+ 00046/0603 7 (256,448,3)
762
+ 00046/0723 7 (256,448,3)
763
+ 00046/0744 7 (256,448,3)
764
+ 00046/0746 7 (256,448,3)
765
+ 00046/0750 7 (256,448,3)
766
+ 00046/0852 7 (256,448,3)
767
+ 00046/0927 7 (256,448,3)
768
+ 00046/0928 7 (256,448,3)
769
+ 00046/0929 7 (256,448,3)
770
+ 00046/0931 7 (256,448,3)
771
+ 00046/0936 7 (256,448,3)
772
+ 00046/0939 7 (256,448,3)
773
+ 00046/0947 7 (256,448,3)
774
+ 00046/0948 7 (256,448,3)
775
+ 00046/0950 7 (256,448,3)
776
+ 00046/0955 7 (256,448,3)
777
+ 00046/0961 7 (256,448,3)
778
+ 00047/0023 7 (256,448,3)
779
+ 00047/0029 7 (256,448,3)
780
+ 00047/0035 7 (256,448,3)
781
+ 00047/0058 7 (256,448,3)
782
+ 00047/0061 7 (256,448,3)
783
+ 00047/0065 7 (256,448,3)
784
+ 00047/0068 7 (256,448,3)
785
+ 00047/0072 7 (256,448,3)
786
+ 00047/0074 7 (256,448,3)
787
+ 00047/0148 7 (256,448,3)
788
+ 00047/0594 7 (256,448,3)
789
+ 00047/0782 7 (256,448,3)
790
+ 00047/0787 7 (256,448,3)
791
+ 00047/0860 7 (256,448,3)
792
+ 00047/0889 7 (256,448,3)
793
+ 00047/0893 7 (256,448,3)
794
+ 00047/0894 7 (256,448,3)
795
+ 00047/0902 7 (256,448,3)
796
+ 00047/0975 7 (256,448,3)
797
+ 00047/0995 7 (256,448,3)
798
+ 00048/0033 7 (256,448,3)
799
+ 00048/0113 7 (256,448,3)
800
+ 00048/0115 7 (256,448,3)
801
+ 00048/0120 7 (256,448,3)
802
+ 00048/0129 7 (256,448,3)
803
+ 00048/0136 7 (256,448,3)
804
+ 00048/0327 7 (256,448,3)
805
+ 00048/0329 7 (256,448,3)
806
+ 00048/0341 7 (256,448,3)
807
+ 00048/0343 7 (256,448,3)
808
+ 00048/0345 7 (256,448,3)
809
+ 00048/0346 7 (256,448,3)
810
+ 00048/0355 7 (256,448,3)
811
+ 00048/0359 7 (256,448,3)
812
+ 00048/0363 7 (256,448,3)
813
+ 00048/0378 7 (256,448,3)
814
+ 00048/0386 7 (256,448,3)
815
+ 00048/0387 7 (256,448,3)
816
+ 00048/0388 7 (256,448,3)
817
+ 00048/0428 7 (256,448,3)
818
+ 00048/0439 7 (256,448,3)
819
+ 00048/0507 7 (256,448,3)
820
+ 00048/0510 7 (256,448,3)
821
+ 00048/0512 7 (256,448,3)
822
+ 00048/0514 7 (256,448,3)
823
+ 00048/0539 7 (256,448,3)
824
+ 00048/0542 7 (256,448,3)
825
+ 00048/0544 7 (256,448,3)
826
+ 00048/0631 7 (256,448,3)
827
+ 00048/0632 7 (256,448,3)
828
+ 00048/0636 7 (256,448,3)
829
+ 00048/0640 7 (256,448,3)
830
+ 00048/0644 7 (256,448,3)
831
+ 00048/0653 7 (256,448,3)
832
+ 00048/0655 7 (256,448,3)
833
+ 00048/0658 7 (256,448,3)
834
+ 00048/0667 7 (256,448,3)
835
+ 00048/0688 7 (256,448,3)
836
+ 00048/0708 7 (256,448,3)
837
+ 00049/0005 7 (256,448,3)
838
+ 00049/0074 7 (256,448,3)
839
+ 00049/0077 7 (256,448,3)
840
+ 00049/0084 7 (256,448,3)
841
+ 00049/0516 7 (256,448,3)
842
+ 00049/0800 7 (256,448,3)
843
+ 00049/0900 7 (256,448,3)
844
+ 00050/0607 7 (256,448,3)
845
+ 00050/0661 7 (256,448,3)
846
+ 00050/0665 7 (256,448,3)
847
+ 00050/0685 7 (256,448,3)
848
+ 00050/0711 7 (256,448,3)
849
+ 00051/0068 7 (256,448,3)
850
+ 00051/0069 7 (256,448,3)
851
+ 00051/0076 7 (256,448,3)
852
+ 00051/0569 7 (256,448,3)
853
+ 00051/0801 7 (256,448,3)
854
+ 00051/0927 7 (256,448,3)
855
+ 00051/0945 7 (256,448,3)
856
+ 00051/0952 7 (256,448,3)
857
+ 00051/0976 7 (256,448,3)
858
+ 00051/0985 7 (256,448,3)
859
+ 00052/0012 7 (256,448,3)
860
+ 00052/0015 7 (256,448,3)
861
+ 00052/0052 7 (256,448,3)
862
+ 00052/0056 7 (256,448,3)
863
+ 00052/0060 7 (256,448,3)
864
+ 00052/0157 7 (256,448,3)
865
+ 00052/0265 7 (256,448,3)
866
+ 00052/0788 7 (256,448,3)
867
+ 00052/0790 7 (256,448,3)
868
+ 00052/0793 7 (256,448,3)
869
+ 00052/0816 7 (256,448,3)
870
+ 00052/0824 7 (256,448,3)
871
+ 00052/0918 7 (256,448,3)
872
+ 00052/0933 7 (256,448,3)
873
+ 00052/0947 7 (256,448,3)
874
+ 00053/0232 7 (256,448,3)
875
+ 00053/0277 7 (256,448,3)
876
+ 00053/0362 7 (256,448,3)
877
+ 00053/0577 7 (256,448,3)
878
+ 00053/0609 7 (256,448,3)
879
+ 00053/0612 7 (256,448,3)
880
+ 00053/0628 7 (256,448,3)
881
+ 00053/0629 7 (256,448,3)
882
+ 00053/0633 7 (256,448,3)
883
+ 00053/0659 7 (256,448,3)
884
+ 00053/0667 7 (256,448,3)
885
+ 00053/0671 7 (256,448,3)
886
+ 00053/0797 7 (256,448,3)
887
+ 00053/0804 7 (256,448,3)
888
+ 00053/0807 7 (256,448,3)
889
+ 00053/0952 7 (256,448,3)
890
+ 00053/0970 7 (256,448,3)
891
+ 00053/0981 7 (256,448,3)
892
+ 00053/0999 7 (256,448,3)
893
+ 00054/0003 7 (256,448,3)
894
+ 00054/0013 7 (256,448,3)
895
+ 00054/0020 7 (256,448,3)
896
+ 00054/0022 7 (256,448,3)
897
+ 00054/0023 7 (256,448,3)
898
+ 00054/0044 7 (256,448,3)
899
+ 00054/0051 7 (256,448,3)
900
+ 00054/0063 7 (256,448,3)
901
+ 00054/0065 7 (256,448,3)
902
+ 00054/0145 7 (256,448,3)
903
+ 00054/0153 7 (256,448,3)
904
+ 00054/0203 7 (256,448,3)
905
+ 00054/0325 7 (256,448,3)
906
+ 00054/0445 7 (256,448,3)
907
+ 00054/0448 7 (256,448,3)
908
+ 00054/0456 7 (256,448,3)
909
+ 00054/0457 7 (256,448,3)
910
+ 00054/0519 7 (256,448,3)
911
+ 00054/0524 7 (256,448,3)
912
+ 00054/0530 7 (256,448,3)
913
+ 00054/0532 7 (256,448,3)
914
+ 00054/0535 7 (256,448,3)
915
+ 00054/0574 7 (256,448,3)
916
+ 00054/0760 7 (256,448,3)
917
+ 00054/0767 7 (256,448,3)
918
+ 00054/0837 7 (256,448,3)
919
+ 00055/0011 7 (256,448,3)
920
+ 00055/0109 7 (256,448,3)
921
+ 00055/0111 7 (256,448,3)
922
+ 00055/0117 7 (256,448,3)
923
+ 00055/0119 7 (256,448,3)
924
+ 00055/0182 7 (256,448,3)
925
+ 00055/0192 7 (256,448,3)
926
+ 00055/0193 7 (256,448,3)
927
+ 00055/0200 7 (256,448,3)
928
+ 00055/0204 7 (256,448,3)
929
+ 00055/0207 7 (256,448,3)
930
+ 00055/0212 7 (256,448,3)
931
+ 00055/0213 7 (256,448,3)
932
+ 00055/0348 7 (256,448,3)
933
+ 00055/0423 7 (256,448,3)
934
+ 00055/0427 7 (256,448,3)
935
+ 00055/0456 7 (256,448,3)
936
+ 00055/0489 7 (256,448,3)
937
+ 00055/0689 7 (256,448,3)
938
+ 00055/0753 7 (256,448,3)
939
+ 00055/0802 7 (256,448,3)
940
+ 00055/0844 7 (256,448,3)
941
+ 00055/0850 7 (256,448,3)
942
+ 00055/0982 7 (256,448,3)
943
+ 00055/0993 7 (256,448,3)
944
+ 00056/0113 7 (256,448,3)
945
+ 00056/0148 7 (256,448,3)
946
+ 00056/0151 7 (256,448,3)
947
+ 00056/0316 7 (256,448,3)
948
+ 00056/0379 7 (256,448,3)
949
+ 00056/0380 7 (256,448,3)
950
+ 00056/0385 7 (256,448,3)
951
+ 00056/0505 7 (256,448,3)
952
+ 00056/0579 7 (256,448,3)
953
+ 00057/0254 7 (256,448,3)
954
+ 00057/0264 7 (256,448,3)
955
+ 00057/0272 7 (256,448,3)
956
+ 00057/0403 7 (256,448,3)
957
+ 00057/0501 7 (256,448,3)
958
+ 00057/0503 7 (256,448,3)
959
+ 00057/0884 7 (256,448,3)
960
+ 00058/0026 7 (256,448,3)
961
+ 00058/0029 7 (256,448,3)
962
+ 00058/0104 7 (256,448,3)
963
+ 00058/0124 7 (256,448,3)
964
+ 00058/0162 7 (256,448,3)
965
+ 00058/0288 7 (256,448,3)
966
+ 00058/0289 7 (256,448,3)
967
+ 00058/0323 7 (256,448,3)
968
+ 00058/0328 7 (256,448,3)
969
+ 00058/0329 7 (256,448,3)
970
+ 00058/0337 7 (256,448,3)
971
+ 00058/0367 7 (256,448,3)
972
+ 00058/0383 7 (256,448,3)
973
+ 00058/0395 7 (256,448,3)
974
+ 00060/0178 7 (256,448,3)
975
+ 00060/0182 7 (256,448,3)
976
+ 00061/0001 7 (256,448,3)
977
+ 00061/0003 7 (256,448,3)
978
+ 00061/0006 7 (256,448,3)
979
+ 00061/0443 7 (256,448,3)
980
+ 00061/0586 7 (256,448,3)
981
+ 00061/0587 7 (256,448,3)
982
+ 00061/0774 7 (256,448,3)
983
+ 00061/0789 7 (256,448,3)
984
+ 00061/0815 7 (256,448,3)
985
+ 00061/0817 7 (256,448,3)
986
+ 00061/0826 7 (256,448,3)
987
+ 00061/0829 7 (256,448,3)
988
+ 00061/0830 7 (256,448,3)
989
+ 00061/0832 7 (256,448,3)
990
+ 00061/0833 7 (256,448,3)
991
+ 00061/0836 7 (256,448,3)
992
+ 00061/0837 7 (256,448,3)
993
+ 00061/0839 7 (256,448,3)
994
+ 00061/0843 7 (256,448,3)
995
+ 00061/0849 7 (256,448,3)
996
+ 00061/0859 7 (256,448,3)
997
+ 00061/0861 7 (256,448,3)
998
+ 00061/0868 7 (256,448,3)
999
+ 00061/0877 7 (256,448,3)
1000
+ 00061/0889 7 (256,448,3)
1001
+ 00061/0905 7 (256,448,3)
1002
+ 00062/0115 7 (256,448,3)
1003
+ 00062/0118 7 (256,448,3)
1004
+ 00062/0125 7 (256,448,3)
1005
+ 00062/0134 7 (256,448,3)
1006
+ 00062/0142 7 (256,448,3)
1007
+ 00062/0400 7 (256,448,3)
1008
+ 00062/0457 7 (256,448,3)
1009
+ 00062/0459 7 (256,448,3)
1010
+ 00062/0560 7 (256,448,3)
1011
+ 00062/0650 7 (256,448,3)
1012
+ 00062/0655 7 (256,448,3)
1013
+ 00062/0715 7 (256,448,3)
1014
+ 00062/0847 7 (256,448,3)
1015
+ 00062/0905 7 (256,448,3)
1016
+ 00062/0981 7 (256,448,3)
1017
+ 00063/0177 7 (256,448,3)
1018
+ 00063/0230 7 (256,448,3)
1019
+ 00063/0253 7 (256,448,3)
1020
+ 00063/0257 7 (256,448,3)
1021
+ 00063/0326 7 (256,448,3)
1022
+ 00063/0530 7 (256,448,3)
1023
+ 00063/0677 7 (256,448,3)
1024
+ 00063/0759 7 (256,448,3)
1025
+ 00063/0761 7 (256,448,3)
1026
+ 00063/0777 7 (256,448,3)
1027
+ 00063/0842 7 (256,448,3)
1028
+ 00063/0900 7 (256,448,3)
1029
+ 00064/0014 7 (256,448,3)
1030
+ 00064/0028 7 (256,448,3)
1031
+ 00064/0029 7 (256,448,3)
1032
+ 00064/0030 7 (256,448,3)
1033
+ 00064/0037 7 (256,448,3)
1034
+ 00064/0044 7 (256,448,3)
1035
+ 00064/0280 7 (256,448,3)
1036
+ 00064/0285 7 (256,448,3)
1037
+ 00064/0286 7 (256,448,3)
1038
+ 00064/0291 7 (256,448,3)
1039
+ 00064/0300 7 (256,448,3)
1040
+ 00064/0303 7 (256,448,3)
1041
+ 00064/0308 7 (256,448,3)
1042
+ 00064/0314 7 (256,448,3)
1043
+ 00064/0316 7 (256,448,3)
1044
+ 00064/0317 7 (256,448,3)
1045
+ 00064/0323 7 (256,448,3)
1046
+ 00064/0435 7 (256,448,3)
1047
+ 00064/0733 7 (256,448,3)
1048
+ 00064/0848 7 (256,448,3)
1049
+ 00064/0868 7 (256,448,3)
1050
+ 00064/0888 7 (256,448,3)
1051
+ 00064/0898 7 (256,448,3)
1052
+ 00065/0116 7 (256,448,3)
1053
+ 00065/0121 7 (256,448,3)
1054
+ 00065/0122 7 (256,448,3)
1055
+ 00065/0124 7 (256,448,3)
1056
+ 00065/0125 7 (256,448,3)
1057
+ 00065/0126 7 (256,448,3)
1058
+ 00065/0136 7 (256,448,3)
1059
+ 00065/0146 7 (256,448,3)
1060
+ 00065/0147 7 (256,448,3)
1061
+ 00065/0163 7 (256,448,3)
1062
+ 00065/0170 7 (256,448,3)
1063
+ 00065/0175 7 (256,448,3)
1064
+ 00065/0176 7 (256,448,3)
1065
+ 00065/0180 7 (256,448,3)
1066
+ 00065/0184 7 (256,448,3)
1067
+ 00065/0186 7 (256,448,3)
1068
+ 00065/0332 7 (256,448,3)
1069
+ 00065/0343 7 (256,448,3)
1070
+ 00065/0365 7 (256,448,3)
1071
+ 00065/0393 7 (256,448,3)
1072
+ 00065/0394 7 (256,448,3)
1073
+ 00065/0442 7 (256,448,3)
1074
+ 00065/0459 7 (256,448,3)
1075
+ 00065/0462 7 (256,448,3)
1076
+ 00065/0476 7 (256,448,3)
1077
+ 00065/0483 7 (256,448,3)
1078
+ 00065/0590 7 (256,448,3)
1079
+ 00065/0593 7 (256,448,3)
1080
+ 00065/0595 7 (256,448,3)
1081
+ 00065/0774 7 (256,448,3)
1082
+ 00065/0947 7 (256,448,3)
1083
+ 00065/0985 7 (256,448,3)
1084
+ 00065/0986 7 (256,448,3)
1085
+ 00066/0015 7 (256,448,3)
1086
+ 00066/0043 7 (256,448,3)
1087
+ 00066/0131 7 (256,448,3)
1088
+ 00066/0157 7 (256,448,3)
1089
+ 00066/0169 7 (256,448,3)
1090
+ 00066/0374 7 (256,448,3)
1091
+ 00066/0382 7 (256,448,3)
1092
+ 00066/0481 7 (256,448,3)
1093
+ 00066/0482 7 (256,448,3)
1094
+ 00066/0491 7 (256,448,3)
1095
+ 00066/0493 7 (256,448,3)
1096
+ 00066/0494 7 (256,448,3)
1097
+ 00066/0496 7 (256,448,3)
1098
+ 00066/0680 7 (256,448,3)
1099
+ 00066/0700 7 (256,448,3)
1100
+ 00066/0887 7 (256,448,3)
1101
+ 00066/0910 7 (256,448,3)
1102
+ 00066/0918 7 (256,448,3)
1103
+ 00067/0024 7 (256,448,3)
1104
+ 00067/0059 7 (256,448,3)
1105
+ 00067/0408 7 (256,448,3)
1106
+ 00067/0414 7 (256,448,3)
1107
+ 00067/0417 7 (256,448,3)
1108
+ 00067/0419 7 (256,448,3)
1109
+ 00067/0423 7 (256,448,3)
1110
+ 00067/0441 7 (256,448,3)
1111
+ 00067/0467 7 (256,448,3)
1112
+ 00067/0471 7 (256,448,3)
1113
+ 00067/0487 7 (256,448,3)
1114
+ 00067/0494 7 (256,448,3)
1115
+ 00067/0497 7 (256,448,3)
1116
+ 00067/0513 7 (256,448,3)
1117
+ 00067/0521 7 (256,448,3)
1118
+ 00068/0111 7 (256,448,3)
1119
+ 00068/0123 7 (256,448,3)
1120
+ 00068/0126 7 (256,448,3)
1121
+ 00068/0129 7 (256,448,3)
1122
+ 00068/0270 7 (256,448,3)
1123
+ 00068/0330 7 (256,448,3)
1124
+ 00068/0407 7 (256,448,3)
1125
+ 00068/0428 7 (256,448,3)
1126
+ 00068/0544 7 (256,448,3)
1127
+ 00068/0635 7 (256,448,3)
1128
+ 00068/0637 7 (256,448,3)
1129
+ 00068/0736 7 (256,448,3)
1130
+ 00068/0738 7 (256,448,3)
1131
+ 00068/0747 7 (256,448,3)
1132
+ 00068/0748 7 (256,448,3)
1133
+ 00068/0749 7 (256,448,3)
1134
+ 00068/0762 7 (256,448,3)
1135
+ 00068/0815 7 (256,448,3)
1136
+ 00068/0981 7 (256,448,3)
1137
+ 00068/0982 7 (256,448,3)
1138
+ 00069/0187 7 (256,448,3)
1139
+ 00069/0191 7 (256,448,3)
1140
+ 00070/0001 7 (256,448,3)
1141
+ 00070/0003 7 (256,448,3)
1142
+ 00070/0340 7 (256,448,3)
1143
+ 00070/0341 7 (256,448,3)
1144
+ 00070/0342 7 (256,448,3)
1145
+ 00070/0347 7 (256,448,3)
1146
+ 00070/0372 7 (256,448,3)
1147
+ 00070/0383 7 (256,448,3)
1148
+ 00070/0389 7 (256,448,3)
1149
+ 00070/0728 7 (256,448,3)
1150
+ 00070/0813 7 (256,448,3)
1151
+ 00070/0814 7 (256,448,3)
1152
+ 00070/0823 7 (256,448,3)
1153
+ 00070/0840 7 (256,448,3)
1154
+ 00070/0843 7 (256,448,3)
1155
+ 00070/0861 7 (256,448,3)
1156
+ 00071/0111 7 (256,448,3)
1157
+ 00071/0138 7 (256,448,3)
1158
+ 00071/0143 7 (256,448,3)
1159
+ 00071/0150 7 (256,448,3)
1160
+ 00071/0508 7 (256,448,3)
1161
+ 00071/0514 7 (256,448,3)
1162
+ 00071/0550 7 (256,448,3)
1163
+ 00071/0556 7 (256,448,3)
1164
+ 00071/0600 7 (256,448,3)
1165
+ 00071/0665 7 (256,448,3)
1166
+ 00071/0670 7 (256,448,3)
1167
+ 00071/0672 7 (256,448,3)
1168
+ 00071/0673 7 (256,448,3)
1169
+ 00071/0705 7 (256,448,3)
1170
+ 00071/0706 7 (256,448,3)
1171
+ 00071/0707 7 (256,448,3)
1172
+ 00071/0774 7 (256,448,3)
1173
+ 00071/0799 7 (256,448,3)
1174
+ 00071/0814 7 (256,448,3)
1175
+ 00071/0816 7 (256,448,3)
1176
+ 00071/0819 7 (256,448,3)
1177
+ 00071/0823 7 (256,448,3)
1178
+ 00071/0828 7 (256,448,3)
1179
+ 00071/0830 7 (256,448,3)
1180
+ 00071/0839 7 (256,448,3)
1181
+ 00071/0841 7 (256,448,3)
1182
+ 00072/0192 7 (256,448,3)
1183
+ 00072/0194 7 (256,448,3)
1184
+ 00072/0197 7 (256,448,3)
1185
+ 00072/0199 7 (256,448,3)
1186
+ 00072/0285 7 (256,448,3)
1187
+ 00072/0586 7 (256,448,3)
1188
+ 00072/0795 7 (256,448,3)
1189
+ 00072/0811 7 (256,448,3)
1190
+ 00072/0812 7 (256,448,3)
1191
+ 00072/0824 7 (256,448,3)
1192
+ 00072/0831 7 (256,448,3)
1193
+ 00072/0835 7 (256,448,3)
1194
+ 00072/0837 7 (256,448,3)
1195
+ 00072/0841 7 (256,448,3)
1196
+ 00072/0962 7 (256,448,3)
1197
+ 00073/0296 7 (256,448,3)
1198
+ 00073/0299 7 (256,448,3)
1199
+ 00073/0300 7 (256,448,3)
1200
+ 00073/0301 7 (256,448,3)
1201
+ 00073/0427 7 (256,448,3)
1202
+ 00073/0428 7 (256,448,3)
1203
+ 00073/0494 7 (256,448,3)
1204
+ 00073/0615 7 (256,448,3)
1205
+ 00073/0620 7 (256,448,3)
1206
+ 00073/0624 7 (256,448,3)
1207
+ 00073/0979 7 (256,448,3)
1208
+ 00074/0226 7 (256,448,3)
1209
+ 00074/0250 7 (256,448,3)
1210
+ 00074/0284 7 (256,448,3)
1211
+ 00074/0503 7 (256,448,3)
1212
+ 00074/0614 7 (256,448,3)
1213
+ 00074/0629 7 (256,448,3)
1214
+ 00074/0762 7 (256,448,3)
1215
+ 00074/0765 7 (256,448,3)
1216
+ 00074/0900 7 (256,448,3)
1217
+ 00074/0908 7 (256,448,3)
1218
+ 00075/0352 7 (256,448,3)
1219
+ 00075/0360 7 (256,448,3)
1220
+ 00075/0361 7 (256,448,3)
1221
+ 00075/0365 7 (256,448,3)
1222
+ 00075/0383 7 (256,448,3)
1223
+ 00075/0384 7 (256,448,3)
1224
+ 00075/0386 7 (256,448,3)
1225
+ 00075/0407 7 (256,448,3)
1226
+ 00075/0410 7 (256,448,3)
1227
+ 00075/0412 7 (256,448,3)
1228
+ 00075/0413 7 (256,448,3)
1229
+ 00075/0459 7 (256,448,3)
1230
+ 00075/0504 7 (256,448,3)
1231
+ 00075/0515 7 (256,448,3)
1232
+ 00075/0518 7 (256,448,3)
1233
+ 00075/0567 7 (256,448,3)
1234
+ 00075/0681 7 (256,448,3)
1235
+ 00075/0693 7 (256,448,3)
1236
+ 00075/0728 7 (256,448,3)
1237
+ 00075/0731 7 (256,448,3)
1238
+ 00075/0804 7 (256,448,3)
1239
+ 00075/0974 7 (256,448,3)
1240
+ 00075/0975 7 (256,448,3)
1241
+ 00075/0983 7 (256,448,3)
1242
+ 00075/0997 7 (256,448,3)
1243
+ 00076/0006 7 (256,448,3)
1244
+ 00076/0007 7 (256,448,3)
1245
+ 00076/0011 7 (256,448,3)
1246
+ 00076/0013 7 (256,448,3)
1247
+ 00076/0014 7 (256,448,3)
1248
+ 00076/0027 7 (256,448,3)
1249
+ 00076/0029 7 (256,448,3)
1250
+ 00076/0037 7 (256,448,3)
1251
+ 00076/0041 7 (256,448,3)
1252
+ 00076/0055 7 (256,448,3)
1253
+ 00076/0071 7 (256,448,3)
1254
+ 00076/0172 7 (256,448,3)
1255
+ 00076/0275 7 (256,448,3)
1256
+ 00076/0286 7 (256,448,3)
1257
+ 00076/0467 7 (256,448,3)
1258
+ 00076/0481 7 (256,448,3)
1259
+ 00076/0527 7 (256,448,3)
1260
+ 00076/0895 7 (256,448,3)
1261
+ 00076/0896 7 (256,448,3)
1262
+ 00076/0906 7 (256,448,3)
1263
+ 00076/0924 7 (256,448,3)
1264
+ 00076/0964 7 (256,448,3)
1265
+ 00076/0984 7 (256,448,3)
1266
+ 00077/0317 7 (256,448,3)
1267
+ 00077/0322 7 (256,448,3)
1268
+ 00077/0333 7 (256,448,3)
1269
+ 00077/0334 7 (256,448,3)
1270
+ 00077/0480 7 (256,448,3)
1271
+ 00077/0488 7 (256,448,3)
1272
+ 00077/0490 7 (256,448,3)
1273
+ 00077/0582 7 (256,448,3)
1274
+ 00077/0586 7 (256,448,3)
1275
+ 00077/0969 7 (256,448,3)
1276
+ 00078/0007 7 (256,448,3)
1277
+ 00078/0011 7 (256,448,3)
1278
+ 00078/0153 7 (256,448,3)
1279
+ 00078/0289 7 (256,448,3)
1280
+ 00078/0312 7 (256,448,3)
1281
+ 00078/0492 7 (256,448,3)
1282
+ 00078/0580 7 (256,448,3)
1283
+ 00078/0595 7 (256,448,3)
1284
+ 00078/0814 7 (256,448,3)
1285
+ 00078/0950 7 (256,448,3)
1286
+ 00078/0955 7 (256,448,3)
1287
+ 00079/0060 7 (256,448,3)
1288
+ 00079/0067 7 (256,448,3)
1289
+ 00080/0216 7 (256,448,3)
1290
+ 00080/0308 7 (256,448,3)
1291
+ 00080/0504 7 (256,448,3)
1292
+ 00080/0552 7 (256,448,3)
1293
+ 00080/0576 7 (256,448,3)
1294
+ 00080/0583 7 (256,448,3)
1295
+ 00080/0837 7 (256,448,3)
1296
+ 00080/0839 7 (256,448,3)
1297
+ 00080/0871 7 (256,448,3)
1298
+ 00080/0877 7 (256,448,3)
1299
+ 00080/0880 7 (256,448,3)
1300
+ 00080/0969 7 (256,448,3)
1301
+ 00080/0973 7 (256,448,3)
1302
+ 00080/0980 7 (256,448,3)
1303
+ 00081/0202 7 (256,448,3)
1304
+ 00081/0203 7 (256,448,3)
1305
+ 00081/0210 7 (256,448,3)
1306
+ 00081/0268 7 (256,448,3)
1307
+ 00081/0281 7 (256,448,3)
1308
+ 00081/0283 7 (256,448,3)
1309
+ 00081/0317 7 (256,448,3)
1310
+ 00081/0327 7 (256,448,3)
1311
+ 00082/0018 7 (256,448,3)
1312
+ 00082/0025 7 (256,448,3)
1313
+ 00082/0089 7 (256,448,3)
1314
+ 00082/0140 7 (256,448,3)
1315
+ 00082/0442 7 (256,448,3)
1316
+ 00082/0465 7 (256,448,3)
1317
+ 00082/0473 7 (256,448,3)
1318
+ 00082/0481 7 (256,448,3)
1319
+ 00082/0492 7 (256,448,3)
1320
+ 00082/0495 7 (256,448,3)
1321
+ 00082/0497 7 (256,448,3)
1322
+ 00082/0502 7 (256,448,3)
1323
+ 00082/0504 7 (256,448,3)
1324
+ 00082/0506 7 (256,448,3)
1325
+ 00082/0507 7 (256,448,3)
1326
+ 00082/0510 7 (256,448,3)
1327
+ 00082/0519 7 (256,448,3)
1328
+ 00082/0523 7 (256,448,3)
1329
+ 00082/0588 7 (256,448,3)
1330
+ 00082/0597 7 (256,448,3)
1331
+ 00082/0632 7 (256,448,3)
1332
+ 00082/0751 7 (256,448,3)
1333
+ 00082/0767 7 (256,448,3)
1334
+ 00082/0771 7 (256,448,3)
1335
+ 00082/0790 7 (256,448,3)
1336
+ 00082/0804 7 (256,448,3)
1337
+ 00082/0823 7 (256,448,3)
1338
+ 00083/0052 7 (256,448,3)
1339
+ 00083/0056 7 (256,448,3)
1340
+ 00083/0113 7 (256,448,3)
1341
+ 00083/0114 7 (256,448,3)
1342
+ 00083/0122 7 (256,448,3)
1343
+ 00083/0137 7 (256,448,3)
1344
+ 00083/0270 7 (256,448,3)
1345
+ 00083/0295 7 (256,448,3)
1346
+ 00083/0303 7 (256,448,3)
1347
+ 00083/0308 7 (256,448,3)
1348
+ 00083/0586 7 (256,448,3)
1349
+ 00083/0592 7 (256,448,3)
1350
+ 00083/0640 7 (256,448,3)
1351
+ 00083/0648 7 (256,448,3)
1352
+ 00083/0654 7 (256,448,3)
1353
+ 00083/0662 7 (256,448,3)
1354
+ 00083/0666 7 (256,448,3)
1355
+ 00083/0668 7 (256,448,3)
1356
+ 00083/0669 7 (256,448,3)
1357
+ 00083/0675 7 (256,448,3)
1358
+ 00083/0679 7 (256,448,3)
1359
+ 00083/0681 7 (256,448,3)
1360
+ 00083/0682 7 (256,448,3)
1361
+ 00083/0694 7 (256,448,3)
1362
+ 00083/0695 7 (256,448,3)
1363
+ 00083/0697 7 (256,448,3)
1364
+ 00083/0704 7 (256,448,3)
1365
+ 00083/0713 7 (256,448,3)
1366
+ 00083/0721 7 (256,448,3)
1367
+ 00083/0855 7 (256,448,3)
1368
+ 00084/0109 7 (256,448,3)
1369
+ 00084/0113 7 (256,448,3)
1370
+ 00084/0306 7 (256,448,3)
1371
+ 00084/0442 7 (256,448,3)
1372
+ 00084/0669 7 (256,448,3)
1373
+ 00084/0679 7 (256,448,3)
1374
+ 00084/0685 7 (256,448,3)
1375
+ 00084/0691 7 (256,448,3)
1376
+ 00084/0768 7 (256,448,3)
1377
+ 00084/0817 7 (256,448,3)
1378
+ 00085/0027 7 (256,448,3)
1379
+ 00085/0035 7 (256,448,3)
1380
+ 00085/0038 7 (256,448,3)
1381
+ 00085/0223 7 (256,448,3)
1382
+ 00085/0233 7 (256,448,3)
1383
+ 00085/0281 7 (256,448,3)
1384
+ 00085/0287 7 (256,448,3)
1385
+ 00085/0313 7 (256,448,3)
1386
+ 00085/0521 7 (256,448,3)
1387
+ 00085/0848 7 (256,448,3)
1388
+ 00085/0855 7 (256,448,3)
1389
+ 00085/0865 7 (256,448,3)
1390
+ 00085/0952 7 (256,448,3)
1391
+ 00085/0964 7 (256,448,3)
1392
+ 00085/0973 7 (256,448,3)
1393
+ 00085/0986 7 (256,448,3)
1394
+ 00085/0993 7 (256,448,3)
1395
+ 00086/0070 7 (256,448,3)
1396
+ 00086/0075 7 (256,448,3)
1397
+ 00086/0094 7 (256,448,3)
1398
+ 00086/0103 7 (256,448,3)
1399
+ 00086/0112 7 (256,448,3)
1400
+ 00086/0288 7 (256,448,3)
1401
+ 00086/0576 7 (256,448,3)
1402
+ 00086/0580 7 (256,448,3)
1403
+ 00086/0584 7 (256,448,3)
1404
+ 00086/0599 7 (256,448,3)
1405
+ 00086/0600 7 (256,448,3)
1406
+ 00086/0602 7 (256,448,3)
1407
+ 00086/0612 7 (256,448,3)
1408
+ 00086/0629 7 (256,448,3)
1409
+ 00086/0655 7 (256,448,3)
1410
+ 00086/0679 7 (256,448,3)
1411
+ 00086/0694 7 (256,448,3)
1412
+ 00086/0695 7 (256,448,3)
1413
+ 00086/0701 7 (256,448,3)
1414
+ 00086/0760 7 (256,448,3)
1415
+ 00086/0786 7 (256,448,3)
1416
+ 00086/0845 7 (256,448,3)
1417
+ 00086/0868 7 (256,448,3)
1418
+ 00086/0889 7 (256,448,3)
1419
+ 00086/0891 7 (256,448,3)
1420
+ 00086/0927 7 (256,448,3)
1421
+ 00086/0938 7 (256,448,3)
1422
+ 00086/0946 7 (256,448,3)
1423
+ 00086/0963 7 (256,448,3)
1424
+ 00086/0969 7 (256,448,3)
1425
+ 00087/0023 7 (256,448,3)
1426
+ 00087/0029 7 (256,448,3)
1427
+ 00087/0144 7 (256,448,3)
1428
+ 00087/0148 7 (256,448,3)
1429
+ 00087/0159 7 (256,448,3)
1430
+ 00087/0174 7 (256,448,3)
1431
+ 00087/0283 7 (256,448,3)
1432
+ 00087/0284 7 (256,448,3)
1433
+ 00087/0294 7 (256,448,3)
1434
+ 00087/0296 7 (256,448,3)
1435
+ 00087/0498 7 (256,448,3)
1436
+ 00087/0502 7 (256,448,3)
1437
+ 00087/0532 7 (256,448,3)
1438
+ 00087/0557 7 (256,448,3)
1439
+ 00087/0559 7 (256,448,3)
1440
+ 00087/0574 7 (256,448,3)
1441
+ 00087/0577 7 (256,448,3)
1442
+ 00088/0006 7 (256,448,3)
1443
+ 00088/0268 7 (256,448,3)
1444
+ 00088/0320 7 (256,448,3)
1445
+ 00088/0412 7 (256,448,3)
1446
+ 00088/0431 7 (256,448,3)
1447
+ 00088/0432 7 (256,448,3)
1448
+ 00088/0465 7 (256,448,3)
1449
+ 00088/0507 7 (256,448,3)
1450
+ 00088/0565 7 (256,448,3)
1451
+ 00088/0629 7 (256,448,3)
1452
+ 00088/0831 7 (256,448,3)
1453
+ 00088/0836 7 (256,448,3)
1454
+ 00088/0972 7 (256,448,3)
1455
+ 00088/0974 7 (256,448,3)
1456
+ 00088/0980 7 (256,448,3)
1457
+ 00089/0067 7 (256,448,3)
1458
+ 00089/0244 7 (256,448,3)
1459
+ 00089/0404 7 (256,448,3)
1460
+ 00089/0416 7 (256,448,3)
1461
+ 00089/0419 7 (256,448,3)
1462
+ 00089/0428 7 (256,448,3)
1463
+ 00089/0712 7 (256,448,3)
1464
+ 00089/0713 7 (256,448,3)
1465
+ 00089/0723 7 (256,448,3)
1466
+ 00089/0727 7 (256,448,3)
1467
+ 00089/0770 7 (256,448,3)
1468
+ 00089/0809 7 (256,448,3)
1469
+ 00089/0811 7 (256,448,3)
1470
+ 00089/0888 7 (256,448,3)
1471
+ 00089/0898 7 (256,448,3)
1472
+ 00089/0903 7 (256,448,3)
1473
+ 00089/0907 7 (256,448,3)
1474
+ 00089/0911 7 (256,448,3)
1475
+ 00089/0915 7 (256,448,3)
1476
+ 00089/0926 7 (256,448,3)
1477
+ 00089/0955 7 (256,448,3)
1478
+ 00090/0027 7 (256,448,3)
1479
+ 00090/0028 7 (256,448,3)
1480
+ 00090/0032 7 (256,448,3)
1481
+ 00090/0038 7 (256,448,3)
1482
+ 00090/0076 7 (256,448,3)
1483
+ 00090/0081 7 (256,448,3)
1484
+ 00090/0086 7 (256,448,3)
1485
+ 00090/0119 7 (256,448,3)
1486
+ 00090/0258 7 (256,448,3)
1487
+ 00090/0261 7 (256,448,3)
1488
+ 00090/0447 7 (256,448,3)
1489
+ 00090/0498 7 (256,448,3)
1490
+ 00090/0514 7 (256,448,3)
1491
+ 00090/0523 7 (256,448,3)
1492
+ 00090/0530 7 (256,448,3)
1493
+ 00090/0540 7 (256,448,3)
1494
+ 00090/0548 7 (256,448,3)
1495
+ 00090/0565 7 (256,448,3)
1496
+ 00090/0578 7 (256,448,3)
1497
+ 00090/0580 7 (256,448,3)
1498
+ 00090/0581 7 (256,448,3)
1499
+ 00090/0780 7 (256,448,3)
1500
+ 00090/0940 7 (256,448,3)
1501
+ 00090/0984 7 (256,448,3)
1502
+ 00091/0023 7 (256,448,3)
1503
+ 00091/0051 7 (256,448,3)
1504
+ 00091/0317 7 (256,448,3)
1505
+ 00091/0320 7 (256,448,3)
1506
+ 00091/0582 7 (256,448,3)
1507
+ 00091/0585 7 (256,448,3)
1508
+ 00091/0588 7 (256,448,3)
1509
+ 00091/0601 7 (256,448,3)
1510
+ 00091/0602 7 (256,448,3)
1511
+ 00091/0603 7 (256,448,3)
1512
+ 00091/0634 7 (256,448,3)
1513
+ 00091/0693 7 (256,448,3)
1514
+ 00091/0741 7 (256,448,3)
1515
+ 00091/0966 7 (256,448,3)
1516
+ 00091/0973 7 (256,448,3)
1517
+ 00091/0985 7 (256,448,3)
1518
+ 00092/0007 7 (256,448,3)
1519
+ 00092/0132 7 (256,448,3)
1520
+ 00092/0270 7 (256,448,3)
1521
+ 00092/0296 7 (256,448,3)
1522
+ 00092/0611 7 (256,448,3)
1523
+ 00092/0625 7 (256,448,3)
1524
+ 00092/0627 7 (256,448,3)
1525
+ 00092/0651 7 (256,448,3)
1526
+ 00092/0652 7 (256,448,3)
1527
+ 00092/0910 7 (256,448,3)
1528
+ 00093/0075 7 (256,448,3)
1529
+ 00093/0078 7 (256,448,3)
1530
+ 00093/0100 7 (256,448,3)
1531
+ 00093/0132 7 (256,448,3)
1532
+ 00093/0133 7 (256,448,3)
1533
+ 00093/0176 7 (256,448,3)
1534
+ 00093/0177 7 (256,448,3)
1535
+ 00093/0178 7 (256,448,3)
1536
+ 00093/0181 7 (256,448,3)
1537
+ 00093/0183 7 (256,448,3)
1538
+ 00093/0184 7 (256,448,3)
1539
+ 00093/0286 7 (256,448,3)
1540
+ 00093/0304 7 (256,448,3)
1541
+ 00093/0305 7 (256,448,3)
1542
+ 00093/0319 7 (256,448,3)
1543
+ 00093/0324 7 (256,448,3)
1544
+ 00093/0325 7 (256,448,3)
1545
+ 00093/0327 7 (256,448,3)
1546
+ 00093/0331 7 (256,448,3)
1547
+ 00093/0444 7 (256,448,3)
1548
+ 00093/0450 7 (256,448,3)
1549
+ 00093/0593 7 (256,448,3)
1550
+ 00094/0032 7 (256,448,3)
1551
+ 00094/0057 7 (256,448,3)
1552
+ 00094/0139 7 (256,448,3)
1553
+ 00094/0206 7 (256,448,3)
1554
+ 00094/0211 7 (256,448,3)
1555
+ 00094/0215 7 (256,448,3)
1556
+ 00094/0218 7 (256,448,3)
1557
+ 00094/0257 7 (256,448,3)
1558
+ 00094/0329 7 (256,448,3)
1559
+ 00094/0331 7 (256,448,3)
1560
+ 00094/0332 7 (256,448,3)
1561
+ 00094/0369 7 (256,448,3)
1562
+ 00094/0370 7 (256,448,3)
1563
+ 00094/0383 7 (256,448,3)
1564
+ 00094/0385 7 (256,448,3)
1565
+ 00094/0387 7 (256,448,3)
1566
+ 00094/0399 7 (256,448,3)
1567
+ 00094/0605 7 (256,448,3)
1568
+ 00094/0648 7 (256,448,3)
1569
+ 00094/0649 7 (256,448,3)
1570
+ 00094/0759 7 (256,448,3)
1571
+ 00094/0800 7 (256,448,3)
1572
+ 00094/0894 7 (256,448,3)
1573
+ 00094/0896 7 (256,448,3)
1574
+ 00095/0089 7 (256,448,3)
1575
+ 00095/0108 7 (256,448,3)
1576
+ 00095/0109 7 (256,448,3)
1577
+ 00095/0114 7 (256,448,3)
1578
+ 00095/0128 7 (256,448,3)
1579
+ 00095/0133 7 (256,448,3)
1580
+ 00095/0150 7 (256,448,3)
1581
+ 00095/0153 7 (256,448,3)
1582
+ 00095/0154 7 (256,448,3)
1583
+ 00095/0196 7 (256,448,3)
1584
+ 00095/0209 7 (256,448,3)
1585
+ 00095/0228 7 (256,448,3)
1586
+ 00095/0230 7 (256,448,3)
1587
+ 00095/0231 7 (256,448,3)
1588
+ 00095/0242 7 (256,448,3)
1589
+ 00095/0243 7 (256,448,3)
1590
+ 00095/0253 7 (256,448,3)
1591
+ 00095/0280 7 (256,448,3)
1592
+ 00095/0281 7 (256,448,3)
1593
+ 00095/0283 7 (256,448,3)
1594
+ 00095/0314 7 (256,448,3)
1595
+ 00095/0868 7 (256,448,3)
1596
+ 00095/0894 7 (256,448,3)
1597
+ 00096/0062 7 (256,448,3)
1598
+ 00096/0347 7 (256,448,3)
1599
+ 00096/0348 7 (256,448,3)
1600
+ 00096/0359 7 (256,448,3)
1601
+ 00096/0363 7 (256,448,3)
1602
+ 00096/0373 7 (256,448,3)
1603
+ 00096/0378 7 (256,448,3)
1604
+ 00096/0387 7 (256,448,3)
1605
+ 00096/0395 7 (256,448,3)
1606
+ 00096/0396 7 (256,448,3)
1607
+ 00096/0404 7 (256,448,3)
1608
+ 00096/0653 7 (256,448,3)
1609
+ 00096/0668 7 (256,448,3)
1610
+ 00096/0679 7 (256,448,3)
1611
+ 00096/0729 7 (256,448,3)
1612
+ 00096/0736 7 (256,448,3)
1613
+ 00096/0823 7 (256,448,3)
basicsr/data/meta_info/meta_info_Vimeo90K_train_GT.txt ADDED
The diff for this file is too large to render. See raw diff
 
basicsr/data/paired_image_dataset.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch.utils import data as data
2
+ from torchvision.transforms.functional import normalize
3
+
4
+ from basicsr.data.data_util import paired_paths_from_folder, paired_paths_from_lmdb, paired_paths_from_meta_info_file
5
+ from basicsr.data.transforms import augment, paired_random_crop
6
+ from basicsr.utils import FileClient, bgr2ycbcr, imfrombytes, img2tensor
7
+ from basicsr.utils.registry import DATASET_REGISTRY
8
+
9
+
10
+ @DATASET_REGISTRY.register()
11
+ class PairedImageDataset(data.Dataset):
12
+ """Paired image dataset for image restoration.
13
+
14
+ Read LQ (Low Quality, e.g. LR (Low Resolution), blurry, noisy, etc) and GT image pairs.
15
+
16
+ There are three modes:
17
+
18
+ 1. **lmdb**: Use lmdb files. If opt['io_backend'] == lmdb.
19
+ 2. **meta_info_file**: Use meta information file to generate paths. \
20
+ If opt['io_backend'] != lmdb and opt['meta_info_file'] is not None.
21
+ 3. **folder**: Scan folders to generate paths. The rest.
22
+
23
+ Args:
24
+ opt (dict): Config for train datasets. It contains the following keys:
25
+ dataroot_gt (str): Data root path for gt.
26
+ dataroot_lq (str): Data root path for lq.
27
+ meta_info_file (str): Path for meta information file.
28
+ io_backend (dict): IO backend type and other kwarg.
29
+ filename_tmpl (str): Template for each filename. Note that the template excludes the file extension.
30
+ Default: '{}'.
31
+ gt_size (int): Cropped patched size for gt patches.
32
+ use_hflip (bool): Use horizontal flips.
33
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
34
+ scale (bool): Scale, which will be added automatically.
35
+ phase (str): 'train' or 'val'.
36
+ """
37
+
38
+ def __init__(self, opt):
39
+ super(PairedImageDataset, self).__init__()
40
+ self.opt = opt
41
+ # file client (io backend)
42
+ self.file_client = None
43
+ self.io_backend_opt = opt['io_backend']
44
+ self.mean = opt['mean'] if 'mean' in opt else None
45
+ self.std = opt['std'] if 'std' in opt else None
46
+
47
+ self.gt_folder, self.lq_folder = opt['dataroot_gt'], opt['dataroot_lq']
48
+ if 'filename_tmpl' in opt:
49
+ self.filename_tmpl = opt['filename_tmpl']
50
+ else:
51
+ self.filename_tmpl = '{}'
52
+
53
+ if self.io_backend_opt['type'] == 'lmdb':
54
+ self.io_backend_opt['db_paths'] = [self.lq_folder, self.gt_folder]
55
+ self.io_backend_opt['client_keys'] = ['lq', 'gt']
56
+ self.paths = paired_paths_from_lmdb([self.lq_folder, self.gt_folder], ['lq', 'gt'])
57
+ elif 'meta_info_file' in self.opt and self.opt['meta_info_file'] is not None:
58
+ self.paths = paired_paths_from_meta_info_file([self.lq_folder, self.gt_folder], ['lq', 'gt'],
59
+ self.opt['meta_info_file'], self.filename_tmpl)
60
+ else:
61
+ self.paths = paired_paths_from_folder([self.lq_folder, self.gt_folder], ['lq', 'gt'], self.filename_tmpl)
62
+
63
+ def __getitem__(self, index):
64
+ if self.file_client is None:
65
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
66
+
67
+ scale = self.opt['scale']
68
+
69
+ # Load gt and lq images. Dimension order: HWC; channel order: BGR;
70
+ # image range: [0, 1], float32.
71
+ gt_path = self.paths[index]['gt_path']
72
+ img_bytes = self.file_client.get(gt_path, 'gt')
73
+ img_gt = imfrombytes(img_bytes, float32=True)
74
+ lq_path = self.paths[index]['lq_path']
75
+ img_bytes = self.file_client.get(lq_path, 'lq')
76
+ img_lq = imfrombytes(img_bytes, float32=True)
77
+
78
+ # augmentation for training
79
+ if self.opt['phase'] == 'train':
80
+ gt_size = self.opt['gt_size']
81
+ # random crop
82
+ img_gt, img_lq = paired_random_crop(img_gt, img_lq, gt_size, scale, gt_path)
83
+ # flip, rotation
84
+ img_gt, img_lq = augment([img_gt, img_lq], self.opt['use_hflip'], self.opt['use_rot'])
85
+
86
+ # color space transform
87
+ if 'color' in self.opt and self.opt['color'] == 'y':
88
+ img_gt = bgr2ycbcr(img_gt, y_only=True)[..., None]
89
+ img_lq = bgr2ycbcr(img_lq, y_only=True)[..., None]
90
+
91
+ # crop the unmatched GT images during validation or testing, especially for SR benchmark datasets
92
+ # TODO: It is better to update the datasets, rather than force to crop
93
+ if self.opt['phase'] != 'train':
94
+ img_gt = img_gt[0:img_lq.shape[0] * scale, 0:img_lq.shape[1] * scale, :]
95
+
96
+ # BGR to RGB, HWC to CHW, numpy to tensor
97
+ img_gt, img_lq = img2tensor([img_gt, img_lq], bgr2rgb=True, float32=True)
98
+ # normalize
99
+ if self.mean is not None or self.std is not None:
100
+ normalize(img_lq, self.mean, self.std, inplace=True)
101
+ normalize(img_gt, self.mean, self.std, inplace=True)
102
+
103
+ return {'lq': img_lq, 'gt': img_gt, 'lq_path': lq_path, 'gt_path': gt_path}
104
+
105
+ def __len__(self):
106
+ return len(self.paths)
basicsr/data/prefetch_dataloader.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import queue as Queue
2
+ import threading
3
+ import torch
4
+ from torch.utils.data import DataLoader
5
+
6
+
7
+ class PrefetchGenerator(threading.Thread):
8
+ """A general prefetch generator.
9
+
10
+ Reference: https://stackoverflow.com/questions/7323664/python-generator-pre-fetch
11
+
12
+ Args:
13
+ generator: Python generator.
14
+ num_prefetch_queue (int): Number of prefetch queue.
15
+ """
16
+
17
+ def __init__(self, generator, num_prefetch_queue):
18
+ threading.Thread.__init__(self)
19
+ self.queue = Queue.Queue(num_prefetch_queue)
20
+ self.generator = generator
21
+ self.daemon = True
22
+ self.start()
23
+
24
+ def run(self):
25
+ for item in self.generator:
26
+ self.queue.put(item)
27
+ self.queue.put(None)
28
+
29
+ def __next__(self):
30
+ next_item = self.queue.get()
31
+ if next_item is None:
32
+ raise StopIteration
33
+ return next_item
34
+
35
+ def __iter__(self):
36
+ return self
37
+
38
+
39
+ class PrefetchDataLoader(DataLoader):
40
+ """Prefetch version of dataloader.
41
+
42
+ Reference: https://github.com/IgorSusmelj/pytorch-styleguide/issues/5#
43
+
44
+ TODO:
45
+ Need to test on single gpu and ddp (multi-gpu). There is a known issue in
46
+ ddp.
47
+
48
+ Args:
49
+ num_prefetch_queue (int): Number of prefetch queue.
50
+ kwargs (dict): Other arguments for dataloader.
51
+ """
52
+
53
+ def __init__(self, num_prefetch_queue, **kwargs):
54
+ self.num_prefetch_queue = num_prefetch_queue
55
+ super(PrefetchDataLoader, self).__init__(**kwargs)
56
+
57
+ def __iter__(self):
58
+ return PrefetchGenerator(super().__iter__(), self.num_prefetch_queue)
59
+
60
+
61
+ class CPUPrefetcher():
62
+ """CPU prefetcher.
63
+
64
+ Args:
65
+ loader: Dataloader.
66
+ """
67
+
68
+ def __init__(self, loader):
69
+ self.ori_loader = loader
70
+ self.loader = iter(loader)
71
+
72
+ def next(self):
73
+ try:
74
+ return next(self.loader)
75
+ except StopIteration:
76
+ return None
77
+
78
+ def reset(self):
79
+ self.loader = iter(self.ori_loader)
80
+
81
+
82
+ class CUDAPrefetcher():
83
+ """CUDA prefetcher.
84
+
85
+ Reference: https://github.com/NVIDIA/apex/issues/304#
86
+
87
+ It may consume more GPU memory.
88
+
89
+ Args:
90
+ loader: Dataloader.
91
+ opt (dict): Options.
92
+ """
93
+
94
+ def __init__(self, loader, opt):
95
+ self.ori_loader = loader
96
+ self.loader = iter(loader)
97
+ self.opt = opt
98
+ self.stream = torch.cuda.Stream()
99
+ self.device = torch.device('cuda' if opt['num_gpu'] != 0 else 'cpu')
100
+ self.preload()
101
+
102
+ def preload(self):
103
+ try:
104
+ self.batch = next(self.loader) # self.batch is a dict
105
+ except StopIteration:
106
+ self.batch = None
107
+ return None
108
+ # put tensors to gpu
109
+ with torch.cuda.stream(self.stream):
110
+ for k, v in self.batch.items():
111
+ if torch.is_tensor(v):
112
+ self.batch[k] = self.batch[k].to(device=self.device, non_blocking=True)
113
+
114
+ def next(self):
115
+ torch.cuda.current_stream().wait_stream(self.stream)
116
+ batch = self.batch
117
+ self.preload()
118
+ return batch
119
+
120
+ def reset(self):
121
+ self.loader = iter(self.ori_loader)
122
+ self.preload()
basicsr/data/realesrgan_dataset.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import math
3
+ import numpy as np
4
+ import os
5
+ import os.path as osp
6
+ import random
7
+ import time
8
+ import torch
9
+ from torch.utils import data as data
10
+
11
+ from basicsr.data.degradations import circular_lowpass_kernel, random_mixed_kernels
12
+ from basicsr.data.transforms import augment
13
+ from basicsr.utils import FileClient, get_root_logger, imfrombytes, img2tensor
14
+ from basicsr.utils.registry import DATASET_REGISTRY
15
+
16
+
17
+ @DATASET_REGISTRY.register(suffix='basicsr')
18
+ class RealESRGANDataset(data.Dataset):
19
+ """Dataset used for Real-ESRGAN model:
20
+ Real-ESRGAN: Training Real-World Blind Super-Resolution with Pure Synthetic Data.
21
+
22
+ It loads gt (Ground-Truth) images, and augments them.
23
+ It also generates blur kernels and sinc kernels for generating low-quality images.
24
+ Note that the low-quality images are processed in tensors on GPUS for faster processing.
25
+
26
+ Args:
27
+ opt (dict): Config for train datasets. It contains the following keys:
28
+ dataroot_gt (str): Data root path for gt.
29
+ meta_info (str): Path for meta information file.
30
+ io_backend (dict): IO backend type and other kwarg.
31
+ use_hflip (bool): Use horizontal flips.
32
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
33
+ Please see more options in the codes.
34
+ """
35
+
36
+ def __init__(self, opt):
37
+ super(RealESRGANDataset, self).__init__()
38
+ self.opt = opt
39
+ self.file_client = None
40
+ self.io_backend_opt = opt['io_backend']
41
+ self.gt_folder = opt['dataroot_gt']
42
+
43
+ # file client (lmdb io backend)
44
+ if self.io_backend_opt['type'] == 'lmdb':
45
+ self.io_backend_opt['db_paths'] = [self.gt_folder]
46
+ self.io_backend_opt['client_keys'] = ['gt']
47
+ if not self.gt_folder.endswith('.lmdb'):
48
+ raise ValueError(f"'dataroot_gt' should end with '.lmdb', but received {self.gt_folder}")
49
+ with open(osp.join(self.gt_folder, 'meta_info.txt')) as fin:
50
+ self.paths = [line.split('.')[0] for line in fin]
51
+ else:
52
+ # disk backend with meta_info
53
+ # Each line in the meta_info describes the relative path to an image
54
+ with open(self.opt['meta_info']) as fin:
55
+ paths = [line.strip().split(' ')[0] for line in fin]
56
+ self.paths = [os.path.join(self.gt_folder, v) for v in paths]
57
+
58
+ # blur settings for the first degradation
59
+ self.blur_kernel_size = opt['blur_kernel_size']
60
+ self.kernel_list = opt['kernel_list']
61
+ self.kernel_prob = opt['kernel_prob'] # a list for each kernel probability
62
+ self.blur_sigma = opt['blur_sigma']
63
+ self.betag_range = opt['betag_range'] # betag used in generalized Gaussian blur kernels
64
+ self.betap_range = opt['betap_range'] # betap used in plateau blur kernels
65
+ self.sinc_prob = opt['sinc_prob'] # the probability for sinc filters
66
+
67
+ # blur settings for the second degradation
68
+ self.blur_kernel_size2 = opt['blur_kernel_size2']
69
+ self.kernel_list2 = opt['kernel_list2']
70
+ self.kernel_prob2 = opt['kernel_prob2']
71
+ self.blur_sigma2 = opt['blur_sigma2']
72
+ self.betag_range2 = opt['betag_range2']
73
+ self.betap_range2 = opt['betap_range2']
74
+ self.sinc_prob2 = opt['sinc_prob2']
75
+
76
+ # a final sinc filter
77
+ self.final_sinc_prob = opt['final_sinc_prob']
78
+
79
+ self.kernel_range = [2 * v + 1 for v in range(3, 11)] # kernel size ranges from 7 to 21
80
+ # TODO: kernel range is now hard-coded, should be in the configure file
81
+ self.pulse_tensor = torch.zeros(21, 21).float() # convolving with pulse tensor brings no blurry effect
82
+ self.pulse_tensor[10, 10] = 1
83
+
84
+ def __getitem__(self, index):
85
+ if self.file_client is None:
86
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
87
+
88
+ # -------------------------------- Load gt images -------------------------------- #
89
+ # Shape: (h, w, c); channel order: BGR; image range: [0, 1], float32.
90
+ gt_path = self.paths[index]
91
+ # avoid errors caused by high latency in reading files
92
+ retry = 3
93
+ while retry > 0:
94
+ try:
95
+ img_bytes = self.file_client.get(gt_path, 'gt')
96
+ except (IOError, OSError) as e:
97
+ logger = get_root_logger()
98
+ logger.warn(f'File client error: {e}, remaining retry times: {retry - 1}')
99
+ # change another file to read
100
+ index = random.randint(0, self.__len__())
101
+ gt_path = self.paths[index]
102
+ time.sleep(1) # sleep 1s for occasional server congestion
103
+ else:
104
+ break
105
+ finally:
106
+ retry -= 1
107
+ img_gt = imfrombytes(img_bytes, float32=True)
108
+
109
+ # -------------------- Do augmentation for training: flip, rotation -------------------- #
110
+ img_gt = augment(img_gt, self.opt['use_hflip'], self.opt['use_rot'])
111
+
112
+ # crop or pad to 400
113
+ # TODO: 400 is hard-coded. You may change it accordingly
114
+ h, w = img_gt.shape[0:2]
115
+ crop_pad_size = 400
116
+ # pad
117
+ if h < crop_pad_size or w < crop_pad_size:
118
+ pad_h = max(0, crop_pad_size - h)
119
+ pad_w = max(0, crop_pad_size - w)
120
+ img_gt = cv2.copyMakeBorder(img_gt, 0, pad_h, 0, pad_w, cv2.BORDER_REFLECT_101)
121
+ # crop
122
+ if img_gt.shape[0] > crop_pad_size or img_gt.shape[1] > crop_pad_size:
123
+ h, w = img_gt.shape[0:2]
124
+ # randomly choose top and left coordinates
125
+ top = random.randint(0, h - crop_pad_size)
126
+ left = random.randint(0, w - crop_pad_size)
127
+ img_gt = img_gt[top:top + crop_pad_size, left:left + crop_pad_size, ...]
128
+
129
+ # ------------------------ Generate kernels (used in the first degradation) ------------------------ #
130
+ kernel_size = random.choice(self.kernel_range)
131
+ if np.random.uniform() < self.opt['sinc_prob']:
132
+ # this sinc filter setting is for kernels ranging from [7, 21]
133
+ if kernel_size < 13:
134
+ omega_c = np.random.uniform(np.pi / 3, np.pi)
135
+ else:
136
+ omega_c = np.random.uniform(np.pi / 5, np.pi)
137
+ kernel = circular_lowpass_kernel(omega_c, kernel_size, pad_to=False)
138
+ else:
139
+ kernel = random_mixed_kernels(
140
+ self.kernel_list,
141
+ self.kernel_prob,
142
+ kernel_size,
143
+ self.blur_sigma,
144
+ self.blur_sigma, [-math.pi, math.pi],
145
+ self.betag_range,
146
+ self.betap_range,
147
+ noise_range=None)
148
+ # pad kernel
149
+ pad_size = (21 - kernel_size) // 2
150
+ kernel = np.pad(kernel, ((pad_size, pad_size), (pad_size, pad_size)))
151
+
152
+ # ------------------------ Generate kernels (used in the second degradation) ------------------------ #
153
+ kernel_size = random.choice(self.kernel_range)
154
+ if np.random.uniform() < self.opt['sinc_prob2']:
155
+ if kernel_size < 13:
156
+ omega_c = np.random.uniform(np.pi / 3, np.pi)
157
+ else:
158
+ omega_c = np.random.uniform(np.pi / 5, np.pi)
159
+ kernel2 = circular_lowpass_kernel(omega_c, kernel_size, pad_to=False)
160
+ else:
161
+ kernel2 = random_mixed_kernels(
162
+ self.kernel_list2,
163
+ self.kernel_prob2,
164
+ kernel_size,
165
+ self.blur_sigma2,
166
+ self.blur_sigma2, [-math.pi, math.pi],
167
+ self.betag_range2,
168
+ self.betap_range2,
169
+ noise_range=None)
170
+
171
+ # pad kernel
172
+ pad_size = (21 - kernel_size) // 2
173
+ kernel2 = np.pad(kernel2, ((pad_size, pad_size), (pad_size, pad_size)))
174
+
175
+ # ------------------------------------- the final sinc kernel ------------------------------------- #
176
+ if np.random.uniform() < self.opt['final_sinc_prob']:
177
+ kernel_size = random.choice(self.kernel_range)
178
+ omega_c = np.random.uniform(np.pi / 3, np.pi)
179
+ sinc_kernel = circular_lowpass_kernel(omega_c, kernel_size, pad_to=21)
180
+ sinc_kernel = torch.FloatTensor(sinc_kernel)
181
+ else:
182
+ sinc_kernel = self.pulse_tensor
183
+
184
+ # BGR to RGB, HWC to CHW, numpy to tensor
185
+ img_gt = img2tensor([img_gt], bgr2rgb=True, float32=True)[0]
186
+ kernel = torch.FloatTensor(kernel)
187
+ kernel2 = torch.FloatTensor(kernel2)
188
+
189
+ return_d = {'gt': img_gt, 'kernel1': kernel, 'kernel2': kernel2, 'sinc_kernel': sinc_kernel, 'gt_path': gt_path}
190
+ return return_d
191
+
192
+ def __len__(self):
193
+ return len(self.paths)
basicsr/data/realesrgan_paired_dataset.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from torch.utils import data as data
3
+ from torchvision.transforms.functional import normalize
4
+
5
+ from basicsr.data.data_util import paired_paths_from_folder, paired_paths_from_lmdb
6
+ from basicsr.data.transforms import augment, paired_random_crop
7
+ from basicsr.utils import FileClient, imfrombytes, img2tensor
8
+ from basicsr.utils.registry import DATASET_REGISTRY
9
+
10
+
11
+ @DATASET_REGISTRY.register(suffix='basicsr')
12
+ class RealESRGANPairedDataset(data.Dataset):
13
+ """Paired image dataset for image restoration.
14
+
15
+ Read LQ (Low Quality, e.g. LR (Low Resolution), blurry, noisy, etc) and GT image pairs.
16
+
17
+ There are three modes:
18
+
19
+ 1. **lmdb**: Use lmdb files. If opt['io_backend'] == lmdb.
20
+ 2. **meta_info_file**: Use meta information file to generate paths. \
21
+ If opt['io_backend'] != lmdb and opt['meta_info_file'] is not None.
22
+ 3. **folder**: Scan folders to generate paths. The rest.
23
+
24
+ Args:
25
+ opt (dict): Config for train datasets. It contains the following keys:
26
+ dataroot_gt (str): Data root path for gt.
27
+ dataroot_lq (str): Data root path for lq.
28
+ meta_info (str): Path for meta information file.
29
+ io_backend (dict): IO backend type and other kwarg.
30
+ filename_tmpl (str): Template for each filename. Note that the template excludes the file extension.
31
+ Default: '{}'.
32
+ gt_size (int): Cropped patched size for gt patches.
33
+ use_hflip (bool): Use horizontal flips.
34
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
35
+ scale (bool): Scale, which will be added automatically.
36
+ phase (str): 'train' or 'val'.
37
+ """
38
+
39
+ def __init__(self, opt):
40
+ super(RealESRGANPairedDataset, self).__init__()
41
+ self.opt = opt
42
+ self.file_client = None
43
+ self.io_backend_opt = opt['io_backend']
44
+ # mean and std for normalizing the input images
45
+ self.mean = opt['mean'] if 'mean' in opt else None
46
+ self.std = opt['std'] if 'std' in opt else None
47
+
48
+ self.gt_folder, self.lq_folder = opt['dataroot_gt'], opt['dataroot_lq']
49
+ self.filename_tmpl = opt['filename_tmpl'] if 'filename_tmpl' in opt else '{}'
50
+
51
+ # file client (lmdb io backend)
52
+ if self.io_backend_opt['type'] == 'lmdb':
53
+ self.io_backend_opt['db_paths'] = [self.lq_folder, self.gt_folder]
54
+ self.io_backend_opt['client_keys'] = ['lq', 'gt']
55
+ self.paths = paired_paths_from_lmdb([self.lq_folder, self.gt_folder], ['lq', 'gt'])
56
+ elif 'meta_info' in self.opt and self.opt['meta_info'] is not None:
57
+ # disk backend with meta_info
58
+ # Each line in the meta_info describes the relative path to an image
59
+ with open(self.opt['meta_info']) as fin:
60
+ paths = [line.strip() for line in fin]
61
+ self.paths = []
62
+ for path in paths:
63
+ gt_path, lq_path = path.split(', ')
64
+ gt_path = os.path.join(self.gt_folder, gt_path)
65
+ lq_path = os.path.join(self.lq_folder, lq_path)
66
+ self.paths.append(dict([('gt_path', gt_path), ('lq_path', lq_path)]))
67
+ else:
68
+ # disk backend
69
+ # it will scan the whole folder to get meta info
70
+ # it will be time-consuming for folders with too many files. It is recommended using an extra meta txt file
71
+ self.paths = paired_paths_from_folder([self.lq_folder, self.gt_folder], ['lq', 'gt'], self.filename_tmpl)
72
+
73
+ def __getitem__(self, index):
74
+ if self.file_client is None:
75
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
76
+
77
+ scale = self.opt['scale']
78
+
79
+ # Load gt and lq images. Dimension order: HWC; channel order: BGR;
80
+ # image range: [0, 1], float32.
81
+ gt_path = self.paths[index]['gt_path']
82
+ img_bytes = self.file_client.get(gt_path, 'gt')
83
+ img_gt = imfrombytes(img_bytes, float32=True)
84
+ lq_path = self.paths[index]['lq_path']
85
+ img_bytes = self.file_client.get(lq_path, 'lq')
86
+ img_lq = imfrombytes(img_bytes, float32=True)
87
+
88
+ # augmentation for training
89
+ if self.opt['phase'] == 'train':
90
+ gt_size = self.opt['gt_size']
91
+ # random crop
92
+ img_gt, img_lq = paired_random_crop(img_gt, img_lq, gt_size, scale, gt_path)
93
+ # flip, rotation
94
+ img_gt, img_lq = augment([img_gt, img_lq], self.opt['use_hflip'], self.opt['use_rot'])
95
+
96
+ # BGR to RGB, HWC to CHW, numpy to tensor
97
+ img_gt, img_lq = img2tensor([img_gt, img_lq], bgr2rgb=True, float32=True)
98
+ # normalize
99
+ if self.mean is not None or self.std is not None:
100
+ normalize(img_lq, self.mean, self.std, inplace=True)
101
+ normalize(img_gt, self.mean, self.std, inplace=True)
102
+
103
+ return {'lq': img_lq, 'gt': img_gt, 'lq_path': lq_path, 'gt_path': gt_path}
104
+
105
+ def __len__(self):
106
+ return len(self.paths)
basicsr/data/reds_dataset.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import random
3
+ import torch
4
+ from pathlib import Path
5
+ from torch.utils import data as data
6
+
7
+ from basicsr.data.transforms import augment, paired_random_crop
8
+ from basicsr.utils import FileClient, get_root_logger, imfrombytes, img2tensor
9
+ from basicsr.utils.flow_util import dequantize_flow
10
+ from basicsr.utils.registry import DATASET_REGISTRY
11
+
12
+
13
+ @DATASET_REGISTRY.register()
14
+ class REDSDataset(data.Dataset):
15
+ """REDS dataset for training.
16
+
17
+ The keys are generated from a meta info txt file.
18
+ basicsr/data/meta_info/meta_info_REDS_GT.txt
19
+
20
+ Each line contains:
21
+ 1. subfolder (clip) name; 2. frame number; 3. image shape, separated by
22
+ a white space.
23
+ Examples:
24
+ 000 100 (720,1280,3)
25
+ 001 100 (720,1280,3)
26
+ ...
27
+
28
+ Key examples: "000/00000000"
29
+ GT (gt): Ground-Truth;
30
+ LQ (lq): Low-Quality, e.g., low-resolution/blurry/noisy/compressed frames.
31
+
32
+ Args:
33
+ opt (dict): Config for train dataset. It contains the following keys:
34
+ dataroot_gt (str): Data root path for gt.
35
+ dataroot_lq (str): Data root path for lq.
36
+ dataroot_flow (str, optional): Data root path for flow.
37
+ meta_info_file (str): Path for meta information file.
38
+ val_partition (str): Validation partition types. 'REDS4' or 'official'.
39
+ io_backend (dict): IO backend type and other kwarg.
40
+ num_frame (int): Window size for input frames.
41
+ gt_size (int): Cropped patched size for gt patches.
42
+ interval_list (list): Interval list for temporal augmentation.
43
+ random_reverse (bool): Random reverse input frames.
44
+ use_hflip (bool): Use horizontal flips.
45
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
46
+ scale (bool): Scale, which will be added automatically.
47
+ """
48
+
49
+ def __init__(self, opt):
50
+ super(REDSDataset, self).__init__()
51
+ self.opt = opt
52
+ self.gt_root, self.lq_root = Path(opt['dataroot_gt']), Path(opt['dataroot_lq'])
53
+ self.flow_root = Path(opt['dataroot_flow']) if opt['dataroot_flow'] is not None else None
54
+ assert opt['num_frame'] % 2 == 1, (f'num_frame should be odd number, but got {opt["num_frame"]}')
55
+ self.num_frame = opt['num_frame']
56
+ self.num_half_frames = opt['num_frame'] // 2
57
+
58
+ self.keys = []
59
+ with open(opt['meta_info_file'], 'r') as fin:
60
+ for line in fin:
61
+ folder, frame_num, _ = line.split(' ')
62
+ self.keys.extend([f'{folder}/{i:08d}' for i in range(int(frame_num))])
63
+
64
+ # remove the video clips used in validation
65
+ if opt['val_partition'] == 'REDS4':
66
+ val_partition = ['000', '011', '015', '020']
67
+ elif opt['val_partition'] == 'official':
68
+ val_partition = [f'{v:03d}' for v in range(240, 270)]
69
+ else:
70
+ raise ValueError(f'Wrong validation partition {opt["val_partition"]}.'
71
+ f"Supported ones are ['official', 'REDS4'].")
72
+ self.keys = [v for v in self.keys if v.split('/')[0] not in val_partition]
73
+
74
+ # file client (io backend)
75
+ self.file_client = None
76
+ self.io_backend_opt = opt['io_backend']
77
+ self.is_lmdb = False
78
+ if self.io_backend_opt['type'] == 'lmdb':
79
+ self.is_lmdb = True
80
+ if self.flow_root is not None:
81
+ self.io_backend_opt['db_paths'] = [self.lq_root, self.gt_root, self.flow_root]
82
+ self.io_backend_opt['client_keys'] = ['lq', 'gt', 'flow']
83
+ else:
84
+ self.io_backend_opt['db_paths'] = [self.lq_root, self.gt_root]
85
+ self.io_backend_opt['client_keys'] = ['lq', 'gt']
86
+
87
+ # temporal augmentation configs
88
+ self.interval_list = opt['interval_list']
89
+ self.random_reverse = opt['random_reverse']
90
+ interval_str = ','.join(str(x) for x in opt['interval_list'])
91
+ logger = get_root_logger()
92
+ logger.info(f'Temporal augmentation interval list: [{interval_str}]; '
93
+ f'random reverse is {self.random_reverse}.')
94
+
95
+ def __getitem__(self, index):
96
+ if self.file_client is None:
97
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
98
+
99
+ scale = self.opt['scale']
100
+ gt_size = self.opt['gt_size']
101
+ key = self.keys[index]
102
+ clip_name, frame_name = key.split('/') # key example: 000/00000000
103
+ center_frame_idx = int(frame_name)
104
+
105
+ # determine the neighboring frames
106
+ interval = random.choice(self.interval_list)
107
+
108
+ # ensure not exceeding the borders
109
+ start_frame_idx = center_frame_idx - self.num_half_frames * interval
110
+ end_frame_idx = center_frame_idx + self.num_half_frames * interval
111
+ # each clip has 100 frames starting from 0 to 99
112
+ while (start_frame_idx < 0) or (end_frame_idx > 99):
113
+ center_frame_idx = random.randint(0, 99)
114
+ start_frame_idx = (center_frame_idx - self.num_half_frames * interval)
115
+ end_frame_idx = center_frame_idx + self.num_half_frames * interval
116
+ frame_name = f'{center_frame_idx:08d}'
117
+ neighbor_list = list(range(start_frame_idx, end_frame_idx + 1, interval))
118
+ # random reverse
119
+ if self.random_reverse and random.random() < 0.5:
120
+ neighbor_list.reverse()
121
+
122
+ assert len(neighbor_list) == self.num_frame, (f'Wrong length of neighbor list: {len(neighbor_list)}')
123
+
124
+ # get the GT frame (as the center frame)
125
+ if self.is_lmdb:
126
+ img_gt_path = f'{clip_name}/{frame_name}'
127
+ else:
128
+ img_gt_path = self.gt_root / clip_name / f'{frame_name}.png'
129
+ img_bytes = self.file_client.get(img_gt_path, 'gt')
130
+ img_gt = imfrombytes(img_bytes, float32=True)
131
+
132
+ # get the neighboring LQ frames
133
+ img_lqs = []
134
+ for neighbor in neighbor_list:
135
+ if self.is_lmdb:
136
+ img_lq_path = f'{clip_name}/{neighbor:08d}'
137
+ else:
138
+ img_lq_path = self.lq_root / clip_name / f'{neighbor:08d}.png'
139
+ img_bytes = self.file_client.get(img_lq_path, 'lq')
140
+ img_lq = imfrombytes(img_bytes, float32=True)
141
+ img_lqs.append(img_lq)
142
+
143
+ # get flows
144
+ if self.flow_root is not None:
145
+ img_flows = []
146
+ # read previous flows
147
+ for i in range(self.num_half_frames, 0, -1):
148
+ if self.is_lmdb:
149
+ flow_path = f'{clip_name}/{frame_name}_p{i}'
150
+ else:
151
+ flow_path = (self.flow_root / clip_name / f'{frame_name}_p{i}.png')
152
+ img_bytes = self.file_client.get(flow_path, 'flow')
153
+ cat_flow = imfrombytes(img_bytes, flag='grayscale', float32=False) # uint8, [0, 255]
154
+ dx, dy = np.split(cat_flow, 2, axis=0)
155
+ flow = dequantize_flow(dx, dy, max_val=20, denorm=False) # we use max_val 20 here.
156
+ img_flows.append(flow)
157
+ # read next flows
158
+ for i in range(1, self.num_half_frames + 1):
159
+ if self.is_lmdb:
160
+ flow_path = f'{clip_name}/{frame_name}_n{i}'
161
+ else:
162
+ flow_path = (self.flow_root / clip_name / f'{frame_name}_n{i}.png')
163
+ img_bytes = self.file_client.get(flow_path, 'flow')
164
+ cat_flow = imfrombytes(img_bytes, flag='grayscale', float32=False) # uint8, [0, 255]
165
+ dx, dy = np.split(cat_flow, 2, axis=0)
166
+ flow = dequantize_flow(dx, dy, max_val=20, denorm=False) # we use max_val 20 here.
167
+ img_flows.append(flow)
168
+
169
+ # for random crop, here, img_flows and img_lqs have the same
170
+ # spatial size
171
+ img_lqs.extend(img_flows)
172
+
173
+ # randomly crop
174
+ img_gt, img_lqs = paired_random_crop(img_gt, img_lqs, gt_size, scale, img_gt_path)
175
+ if self.flow_root is not None:
176
+ img_lqs, img_flows = img_lqs[:self.num_frame], img_lqs[self.num_frame:]
177
+
178
+ # augmentation - flip, rotate
179
+ img_lqs.append(img_gt)
180
+ if self.flow_root is not None:
181
+ img_results, img_flows = augment(img_lqs, self.opt['use_hflip'], self.opt['use_rot'], img_flows)
182
+ else:
183
+ img_results = augment(img_lqs, self.opt['use_hflip'], self.opt['use_rot'])
184
+
185
+ img_results = img2tensor(img_results)
186
+ img_lqs = torch.stack(img_results[0:-1], dim=0)
187
+ img_gt = img_results[-1]
188
+
189
+ if self.flow_root is not None:
190
+ img_flows = img2tensor(img_flows)
191
+ # add the zero center flow
192
+ img_flows.insert(self.num_half_frames, torch.zeros_like(img_flows[0]))
193
+ img_flows = torch.stack(img_flows, dim=0)
194
+
195
+ # img_lqs: (t, c, h, w)
196
+ # img_flows: (t, 2, h, w)
197
+ # img_gt: (c, h, w)
198
+ # key: str
199
+ if self.flow_root is not None:
200
+ return {'lq': img_lqs, 'flow': img_flows, 'gt': img_gt, 'key': key}
201
+ else:
202
+ return {'lq': img_lqs, 'gt': img_gt, 'key': key}
203
+
204
+ def __len__(self):
205
+ return len(self.keys)
206
+
207
+
208
+ @DATASET_REGISTRY.register()
209
+ class REDSRecurrentDataset(data.Dataset):
210
+ """REDS dataset for training recurrent networks.
211
+
212
+ The keys are generated from a meta info txt file.
213
+ basicsr/data/meta_info/meta_info_REDS_GT.txt
214
+
215
+ Each line contains:
216
+ 1. subfolder (clip) name; 2. frame number; 3. image shape, separated by
217
+ a white space.
218
+ Examples:
219
+ 000 100 (720,1280,3)
220
+ 001 100 (720,1280,3)
221
+ ...
222
+
223
+ Key examples: "000/00000000"
224
+ GT (gt): Ground-Truth;
225
+ LQ (lq): Low-Quality, e.g., low-resolution/blurry/noisy/compressed frames.
226
+
227
+ Args:
228
+ opt (dict): Config for train dataset. It contains the following keys:
229
+ dataroot_gt (str): Data root path for gt.
230
+ dataroot_lq (str): Data root path for lq.
231
+ dataroot_flow (str, optional): Data root path for flow.
232
+ meta_info_file (str): Path for meta information file.
233
+ val_partition (str): Validation partition types. 'REDS4' or 'official'.
234
+ io_backend (dict): IO backend type and other kwarg.
235
+ num_frame (int): Window size for input frames.
236
+ gt_size (int): Cropped patched size for gt patches.
237
+ interval_list (list): Interval list for temporal augmentation.
238
+ random_reverse (bool): Random reverse input frames.
239
+ use_hflip (bool): Use horizontal flips.
240
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
241
+ scale (bool): Scale, which will be added automatically.
242
+ """
243
+
244
+ def __init__(self, opt):
245
+ super(REDSRecurrentDataset, self).__init__()
246
+ self.opt = opt
247
+ self.gt_root, self.lq_root = Path(opt['dataroot_gt']), Path(opt['dataroot_lq'])
248
+ self.num_frame = opt['num_frame']
249
+
250
+ self.keys = []
251
+ with open(opt['meta_info_file'], 'r') as fin:
252
+ for line in fin:
253
+ folder, frame_num, _ = line.split(' ')
254
+ self.keys.extend([f'{folder}/{i:08d}' for i in range(int(frame_num))])
255
+
256
+ # remove the video clips used in validation
257
+ if opt['val_partition'] == 'REDS4':
258
+ val_partition = ['000', '011', '015', '020']
259
+ elif opt['val_partition'] == 'official':
260
+ val_partition = [f'{v:03d}' for v in range(240, 270)]
261
+ else:
262
+ raise ValueError(f'Wrong validation partition {opt["val_partition"]}.'
263
+ f"Supported ones are ['official', 'REDS4'].")
264
+ if opt['test_mode']:
265
+ self.keys = [v for v in self.keys if v.split('/')[0] in val_partition]
266
+ else:
267
+ self.keys = [v for v in self.keys if v.split('/')[0] not in val_partition]
268
+
269
+ # file client (io backend)
270
+ self.file_client = None
271
+ self.io_backend_opt = opt['io_backend']
272
+ self.is_lmdb = False
273
+ if self.io_backend_opt['type'] == 'lmdb':
274
+ self.is_lmdb = True
275
+ if hasattr(self, 'flow_root') and self.flow_root is not None:
276
+ self.io_backend_opt['db_paths'] = [self.lq_root, self.gt_root, self.flow_root]
277
+ self.io_backend_opt['client_keys'] = ['lq', 'gt', 'flow']
278
+ else:
279
+ self.io_backend_opt['db_paths'] = [self.lq_root, self.gt_root]
280
+ self.io_backend_opt['client_keys'] = ['lq', 'gt']
281
+
282
+ # temporal augmentation configs
283
+ self.interval_list = opt.get('interval_list', [1])
284
+ self.random_reverse = opt.get('random_reverse', False)
285
+ interval_str = ','.join(str(x) for x in self.interval_list)
286
+ logger = get_root_logger()
287
+ logger.info(f'Temporal augmentation interval list: [{interval_str}]; '
288
+ f'random reverse is {self.random_reverse}.')
289
+
290
+ def __getitem__(self, index):
291
+ if self.file_client is None:
292
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
293
+
294
+ scale = self.opt['scale']
295
+ gt_size = self.opt['gt_size']
296
+ key = self.keys[index]
297
+ clip_name, frame_name = key.split('/') # key example: 000/00000000
298
+
299
+ # determine the neighboring frames
300
+ interval = random.choice(self.interval_list)
301
+
302
+ # ensure not exceeding the borders
303
+ start_frame_idx = int(frame_name)
304
+ if start_frame_idx > 100 - self.num_frame * interval:
305
+ start_frame_idx = random.randint(0, 100 - self.num_frame * interval)
306
+ end_frame_idx = start_frame_idx + self.num_frame * interval
307
+
308
+ neighbor_list = list(range(start_frame_idx, end_frame_idx, interval))
309
+
310
+ # random reverse
311
+ if self.random_reverse and random.random() < 0.5:
312
+ neighbor_list.reverse()
313
+
314
+ # get the neighboring LQ and GT frames
315
+ img_lqs = []
316
+ img_gts = []
317
+ for neighbor in neighbor_list:
318
+ if self.is_lmdb:
319
+ img_lq_path = f'{clip_name}/{neighbor:08d}'
320
+ img_gt_path = f'{clip_name}/{neighbor:08d}'
321
+ else:
322
+ img_lq_path = self.lq_root / clip_name / f'{neighbor:08d}.png'
323
+ img_gt_path = self.gt_root / clip_name / f'{neighbor:08d}.png'
324
+
325
+ # get LQ
326
+ img_bytes = self.file_client.get(img_lq_path, 'lq')
327
+ img_lq = imfrombytes(img_bytes, float32=True)
328
+ img_lqs.append(img_lq)
329
+
330
+ # get GT
331
+ img_bytes = self.file_client.get(img_gt_path, 'gt')
332
+ img_gt = imfrombytes(img_bytes, float32=True)
333
+ img_gts.append(img_gt)
334
+
335
+ # randomly crop
336
+ img_gts, img_lqs = paired_random_crop(img_gts, img_lqs, gt_size, scale, img_gt_path)
337
+
338
+ # augmentation - flip, rotate
339
+ img_lqs.extend(img_gts)
340
+ img_results = augment(img_lqs, self.opt['use_hflip'], self.opt['use_rot'])
341
+
342
+ img_results = img2tensor(img_results)
343
+ img_gts = torch.stack(img_results[len(img_lqs) // 2:], dim=0)
344
+ img_lqs = torch.stack(img_results[:len(img_lqs) // 2], dim=0)
345
+
346
+ # img_lqs: (t, c, h, w)
347
+ # img_gts: (t, c, h, w)
348
+ # key: str
349
+ return {'lq': img_lqs, 'gt': img_gts, 'key': key}
350
+
351
+ def __len__(self):
352
+ return len(self.keys)
basicsr/data/single_image_dataset.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from os import path as osp
2
+ from torch.utils import data as data
3
+ from torchvision.transforms.functional import normalize
4
+
5
+ from basicsr.data.data_util import paths_from_lmdb
6
+ from basicsr.utils import FileClient, imfrombytes, img2tensor, rgb2ycbcr, scandir
7
+ from basicsr.utils.registry import DATASET_REGISTRY
8
+
9
+
10
+ @DATASET_REGISTRY.register()
11
+ class SingleImageDataset(data.Dataset):
12
+ """Read only lq images in the test phase.
13
+
14
+ Read LQ (Low Quality, e.g. LR (Low Resolution), blurry, noisy, etc).
15
+
16
+ There are two modes:
17
+ 1. 'meta_info_file': Use meta information file to generate paths.
18
+ 2. 'folder': Scan folders to generate paths.
19
+
20
+ Args:
21
+ opt (dict): Config for train datasets. It contains the following keys:
22
+ dataroot_lq (str): Data root path for lq.
23
+ meta_info_file (str): Path for meta information file.
24
+ io_backend (dict): IO backend type and other kwarg.
25
+ """
26
+
27
+ def __init__(self, opt):
28
+ super(SingleImageDataset, self).__init__()
29
+ self.opt = opt
30
+ # file client (io backend)
31
+ self.file_client = None
32
+ self.io_backend_opt = opt['io_backend']
33
+ self.mean = opt['mean'] if 'mean' in opt else None
34
+ self.std = opt['std'] if 'std' in opt else None
35
+ self.lq_folder = opt['dataroot_lq']
36
+
37
+ if self.io_backend_opt['type'] == 'lmdb':
38
+ self.io_backend_opt['db_paths'] = [self.lq_folder]
39
+ self.io_backend_opt['client_keys'] = ['lq']
40
+ self.paths = paths_from_lmdb(self.lq_folder)
41
+ elif 'meta_info_file' in self.opt:
42
+ with open(self.opt['meta_info_file'], 'r') as fin:
43
+ self.paths = [osp.join(self.lq_folder, line.rstrip().split(' ')[0]) for line in fin]
44
+ else:
45
+ self.paths = sorted(list(scandir(self.lq_folder, full_path=True)))
46
+
47
+ def __getitem__(self, index):
48
+ if self.file_client is None:
49
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
50
+
51
+ # load lq image
52
+ lq_path = self.paths[index]
53
+ img_bytes = self.file_client.get(lq_path, 'lq')
54
+ img_lq = imfrombytes(img_bytes, float32=True)
55
+
56
+ # color space transform
57
+ if 'color' in self.opt and self.opt['color'] == 'y':
58
+ img_lq = rgb2ycbcr(img_lq, y_only=True)[..., None]
59
+
60
+ # BGR to RGB, HWC to CHW, numpy to tensor
61
+ img_lq = img2tensor(img_lq, bgr2rgb=True, float32=True)
62
+ # normalize
63
+ if self.mean is not None or self.std is not None:
64
+ normalize(img_lq, self.mean, self.std, inplace=True)
65
+ return {'lq': img_lq, 'lq_path': lq_path}
66
+
67
+ def __len__(self):
68
+ return len(self.paths)
basicsr/data/transforms.py ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import random
3
+ import torch
4
+
5
+
6
+ def mod_crop(img, scale):
7
+ """Mod crop images, used during testing.
8
+
9
+ Args:
10
+ img (ndarray): Input image.
11
+ scale (int): Scale factor.
12
+
13
+ Returns:
14
+ ndarray: Result image.
15
+ """
16
+ img = img.copy()
17
+ if img.ndim in (2, 3):
18
+ h, w = img.shape[0], img.shape[1]
19
+ h_remainder, w_remainder = h % scale, w % scale
20
+ img = img[:h - h_remainder, :w - w_remainder, ...]
21
+ else:
22
+ raise ValueError(f'Wrong img ndim: {img.ndim}.')
23
+ return img
24
+
25
+
26
+ def paired_random_crop(img_gts, img_lqs, gt_patch_size, scale, gt_path=None):
27
+ """Paired random crop. Support Numpy array and Tensor inputs.
28
+
29
+ It crops lists of lq and gt images with corresponding locations.
30
+
31
+ Args:
32
+ img_gts (list[ndarray] | ndarray | list[Tensor] | Tensor): GT images. Note that all images
33
+ should have the same shape. If the input is an ndarray, it will
34
+ be transformed to a list containing itself.
35
+ img_lqs (list[ndarray] | ndarray): LQ images. Note that all images
36
+ should have the same shape. If the input is an ndarray, it will
37
+ be transformed to a list containing itself.
38
+ gt_patch_size (int): GT patch size.
39
+ scale (int): Scale factor.
40
+ gt_path (str): Path to ground-truth. Default: None.
41
+
42
+ Returns:
43
+ list[ndarray] | ndarray: GT images and LQ images. If returned results
44
+ only have one element, just return ndarray.
45
+ """
46
+
47
+ if not isinstance(img_gts, list):
48
+ img_gts = [img_gts]
49
+ if not isinstance(img_lqs, list):
50
+ img_lqs = [img_lqs]
51
+
52
+ # determine input type: Numpy array or Tensor
53
+ input_type = 'Tensor' if torch.is_tensor(img_gts[0]) else 'Numpy'
54
+
55
+ if input_type == 'Tensor':
56
+ h_lq, w_lq = img_lqs[0].size()[-2:]
57
+ h_gt, w_gt = img_gts[0].size()[-2:]
58
+ else:
59
+ h_lq, w_lq = img_lqs[0].shape[0:2]
60
+ h_gt, w_gt = img_gts[0].shape[0:2]
61
+ lq_patch_size = gt_patch_size // scale
62
+
63
+ if h_gt != h_lq * scale or w_gt != w_lq * scale:
64
+ raise ValueError(f'Scale mismatches. GT ({h_gt}, {w_gt}) is not {scale}x ',
65
+ f'multiplication of LQ ({h_lq}, {w_lq}).')
66
+ if h_lq < lq_patch_size or w_lq < lq_patch_size:
67
+ raise ValueError(f'LQ ({h_lq}, {w_lq}) is smaller than patch size '
68
+ f'({lq_patch_size}, {lq_patch_size}). '
69
+ f'Please remove {gt_path}.')
70
+
71
+ # randomly choose top and left coordinates for lq patch
72
+ top = random.randint(0, h_lq - lq_patch_size)
73
+ left = random.randint(0, w_lq - lq_patch_size)
74
+
75
+ # crop lq patch
76
+ if input_type == 'Tensor':
77
+ img_lqs = [v[:, :, top:top + lq_patch_size, left:left + lq_patch_size] for v in img_lqs]
78
+ else:
79
+ img_lqs = [v[top:top + lq_patch_size, left:left + lq_patch_size, ...] for v in img_lqs]
80
+
81
+ # crop corresponding gt patch
82
+ top_gt, left_gt = int(top * scale), int(left * scale)
83
+ if input_type == 'Tensor':
84
+ img_gts = [v[:, :, top_gt:top_gt + gt_patch_size, left_gt:left_gt + gt_patch_size] for v in img_gts]
85
+ else:
86
+ img_gts = [v[top_gt:top_gt + gt_patch_size, left_gt:left_gt + gt_patch_size, ...] for v in img_gts]
87
+ if len(img_gts) == 1:
88
+ img_gts = img_gts[0]
89
+ if len(img_lqs) == 1:
90
+ img_lqs = img_lqs[0]
91
+ return img_gts, img_lqs
92
+
93
+
94
+ def augment(imgs, hflip=True, rotation=True, flows=None, return_status=False):
95
+ """Augment: horizontal flips OR rotate (0, 90, 180, 270 degrees).
96
+
97
+ We use vertical flip and transpose for rotation implementation.
98
+ All the images in the list use the same augmentation.
99
+
100
+ Args:
101
+ imgs (list[ndarray] | ndarray): Images to be augmented. If the input
102
+ is an ndarray, it will be transformed to a list.
103
+ hflip (bool): Horizontal flip. Default: True.
104
+ rotation (bool): Ratotation. Default: True.
105
+ flows (list[ndarray]: Flows to be augmented. If the input is an
106
+ ndarray, it will be transformed to a list.
107
+ Dimension is (h, w, 2). Default: None.
108
+ return_status (bool): Return the status of flip and rotation.
109
+ Default: False.
110
+
111
+ Returns:
112
+ list[ndarray] | ndarray: Augmented images and flows. If returned
113
+ results only have one element, just return ndarray.
114
+
115
+ """
116
+ hflip = hflip and random.random() < 0.5
117
+ vflip = rotation and random.random() < 0.5
118
+ rot90 = rotation and random.random() < 0.5
119
+
120
+ def _augment(img):
121
+ if hflip: # horizontal
122
+ cv2.flip(img, 1, img)
123
+ if vflip: # vertical
124
+ cv2.flip(img, 0, img)
125
+ if rot90:
126
+ img = img.transpose(1, 0, 2)
127
+ return img
128
+
129
+ def _augment_flow(flow):
130
+ if hflip: # horizontal
131
+ cv2.flip(flow, 1, flow)
132
+ flow[:, :, 0] *= -1
133
+ if vflip: # vertical
134
+ cv2.flip(flow, 0, flow)
135
+ flow[:, :, 1] *= -1
136
+ if rot90:
137
+ flow = flow.transpose(1, 0, 2)
138
+ flow = flow[:, :, [1, 0]]
139
+ return flow
140
+
141
+ if not isinstance(imgs, list):
142
+ imgs = [imgs]
143
+ imgs = [_augment(img) for img in imgs]
144
+ if len(imgs) == 1:
145
+ imgs = imgs[0]
146
+
147
+ if flows is not None:
148
+ if not isinstance(flows, list):
149
+ flows = [flows]
150
+ flows = [_augment_flow(flow) for flow in flows]
151
+ if len(flows) == 1:
152
+ flows = flows[0]
153
+ return imgs, flows
154
+ else:
155
+ if return_status:
156
+ return imgs, (hflip, vflip, rot90)
157
+ else:
158
+ return imgs
159
+
160
+
161
+ def img_rotate(img, angle, center=None, scale=1.0):
162
+ """Rotate image.
163
+
164
+ Args:
165
+ img (ndarray): Image to be rotated.
166
+ angle (float): Rotation angle in degrees. Positive values mean
167
+ counter-clockwise rotation.
168
+ center (tuple[int]): Rotation center. If the center is None,
169
+ initialize it as the center of the image. Default: None.
170
+ scale (float): Isotropic scale factor. Default: 1.0.
171
+ """
172
+ (h, w) = img.shape[:2]
173
+
174
+ if center is None:
175
+ center = (w // 2, h // 2)
176
+
177
+ matrix = cv2.getRotationMatrix2D(center, angle, scale)
178
+ rotated_img = cv2.warpAffine(img, matrix, (w, h))
179
+ return rotated_img
basicsr/data/video_test_dataset.py ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import glob
2
+ import torch
3
+ from os import path as osp
4
+ from torch.utils import data as data
5
+
6
+ from basicsr.data.data_util import duf_downsample, generate_frame_indices, read_img_seq
7
+ from basicsr.utils import get_root_logger, scandir
8
+ from basicsr.utils.registry import DATASET_REGISTRY
9
+
10
+
11
+ @DATASET_REGISTRY.register()
12
+ class VideoTestDataset(data.Dataset):
13
+ """Video test dataset.
14
+
15
+ Supported datasets: Vid4, REDS4, REDSofficial.
16
+ More generally, it supports testing dataset with following structures:
17
+
18
+ ::
19
+
20
+ dataroot
21
+ β”œβ”€β”€ subfolder1
22
+ β”œβ”€β”€ frame000
23
+ β”œβ”€β”€ frame001
24
+ β”œβ”€β”€ ...
25
+ β”œβ”€β”€ subfolder2
26
+ β”œβ”€β”€ frame000
27
+ β”œβ”€β”€ frame001
28
+ β”œβ”€β”€ ...
29
+ β”œβ”€β”€ ...
30
+
31
+ For testing datasets, there is no need to prepare LMDB files.
32
+
33
+ Args:
34
+ opt (dict): Config for train dataset. It contains the following keys:
35
+ dataroot_gt (str): Data root path for gt.
36
+ dataroot_lq (str): Data root path for lq.
37
+ io_backend (dict): IO backend type and other kwarg.
38
+ cache_data (bool): Whether to cache testing datasets.
39
+ name (str): Dataset name.
40
+ meta_info_file (str): The path to the file storing the list of test folders. If not provided, all the folders
41
+ in the dataroot will be used.
42
+ num_frame (int): Window size for input frames.
43
+ padding (str): Padding mode.
44
+ """
45
+
46
+ def __init__(self, opt):
47
+ super(VideoTestDataset, self).__init__()
48
+ self.opt = opt
49
+ self.cache_data = opt['cache_data']
50
+ self.gt_root, self.lq_root = opt['dataroot_gt'], opt['dataroot_lq']
51
+ self.data_info = {'lq_path': [], 'gt_path': [], 'folder': [], 'idx': [], 'border': []}
52
+ # file client (io backend)
53
+ self.file_client = None
54
+ self.io_backend_opt = opt['io_backend']
55
+ assert self.io_backend_opt['type'] != 'lmdb', 'No need to use lmdb during validation/test.'
56
+
57
+ logger = get_root_logger()
58
+ logger.info(f'Generate data info for VideoTestDataset - {opt["name"]}')
59
+ self.imgs_lq, self.imgs_gt = {}, {}
60
+ if 'meta_info_file' in opt:
61
+ with open(opt['meta_info_file'], 'r') as fin:
62
+ subfolders = [line.split(' ')[0] for line in fin]
63
+ subfolders_lq = [osp.join(self.lq_root, key) for key in subfolders]
64
+ subfolders_gt = [osp.join(self.gt_root, key) for key in subfolders]
65
+ else:
66
+ subfolders_lq = sorted(glob.glob(osp.join(self.lq_root, '*')))
67
+ subfolders_gt = sorted(glob.glob(osp.join(self.gt_root, '*')))
68
+
69
+ if opt['name'].lower() in ['vid4', 'reds4', 'redsofficial']:
70
+ for subfolder_lq, subfolder_gt in zip(subfolders_lq, subfolders_gt):
71
+ # get frame list for lq and gt
72
+ subfolder_name = osp.basename(subfolder_lq)
73
+ img_paths_lq = sorted(list(scandir(subfolder_lq, full_path=True)))
74
+ img_paths_gt = sorted(list(scandir(subfolder_gt, full_path=True)))
75
+
76
+ max_idx = len(img_paths_lq)
77
+ assert max_idx == len(img_paths_gt), (f'Different number of images in lq ({max_idx})'
78
+ f' and gt folders ({len(img_paths_gt)})')
79
+
80
+ self.data_info['lq_path'].extend(img_paths_lq)
81
+ self.data_info['gt_path'].extend(img_paths_gt)
82
+ self.data_info['folder'].extend([subfolder_name] * max_idx)
83
+ for i in range(max_idx):
84
+ self.data_info['idx'].append(f'{i}/{max_idx}')
85
+ border_l = [0] * max_idx
86
+ for i in range(self.opt['num_frame'] // 2):
87
+ border_l[i] = 1
88
+ border_l[max_idx - i - 1] = 1
89
+ self.data_info['border'].extend(border_l)
90
+
91
+ # cache data or save the frame list
92
+ if self.cache_data:
93
+ logger.info(f'Cache {subfolder_name} for VideoTestDataset...')
94
+ self.imgs_lq[subfolder_name] = read_img_seq(img_paths_lq)
95
+ self.imgs_gt[subfolder_name] = read_img_seq(img_paths_gt)
96
+ else:
97
+ self.imgs_lq[subfolder_name] = img_paths_lq
98
+ self.imgs_gt[subfolder_name] = img_paths_gt
99
+ else:
100
+ raise ValueError(f'Non-supported video test dataset: {type(opt["name"])}')
101
+
102
+ def __getitem__(self, index):
103
+ folder = self.data_info['folder'][index]
104
+ idx, max_idx = self.data_info['idx'][index].split('/')
105
+ idx, max_idx = int(idx), int(max_idx)
106
+ border = self.data_info['border'][index]
107
+ lq_path = self.data_info['lq_path'][index]
108
+
109
+ select_idx = generate_frame_indices(idx, max_idx, self.opt['num_frame'], padding=self.opt['padding'])
110
+
111
+ if self.cache_data:
112
+ imgs_lq = self.imgs_lq[folder].index_select(0, torch.LongTensor(select_idx))
113
+ img_gt = self.imgs_gt[folder][idx]
114
+ else:
115
+ img_paths_lq = [self.imgs_lq[folder][i] for i in select_idx]
116
+ imgs_lq = read_img_seq(img_paths_lq)
117
+ img_gt = read_img_seq([self.imgs_gt[folder][idx]])
118
+ img_gt.squeeze_(0)
119
+
120
+ return {
121
+ 'lq': imgs_lq, # (t, c, h, w)
122
+ 'gt': img_gt, # (c, h, w)
123
+ 'folder': folder, # folder name
124
+ 'idx': self.data_info['idx'][index], # e.g., 0/99
125
+ 'border': border, # 1 for border, 0 for non-border
126
+ 'lq_path': lq_path # center frame
127
+ }
128
+
129
+ def __len__(self):
130
+ return len(self.data_info['gt_path'])
131
+
132
+
133
+ @DATASET_REGISTRY.register()
134
+ class VideoTestVimeo90KDataset(data.Dataset):
135
+ """Video test dataset for Vimeo90k-Test dataset.
136
+
137
+ It only keeps the center frame for testing.
138
+ For testing datasets, there is no need to prepare LMDB files.
139
+
140
+ Args:
141
+ opt (dict): Config for train dataset. It contains the following keys:
142
+ dataroot_gt (str): Data root path for gt.
143
+ dataroot_lq (str): Data root path for lq.
144
+ io_backend (dict): IO backend type and other kwarg.
145
+ cache_data (bool): Whether to cache testing datasets.
146
+ name (str): Dataset name.
147
+ meta_info_file (str): The path to the file storing the list of test folders. If not provided, all the folders
148
+ in the dataroot will be used.
149
+ num_frame (int): Window size for input frames.
150
+ padding (str): Padding mode.
151
+ """
152
+
153
+ def __init__(self, opt):
154
+ super(VideoTestVimeo90KDataset, self).__init__()
155
+ self.opt = opt
156
+ self.cache_data = opt['cache_data']
157
+ if self.cache_data:
158
+ raise NotImplementedError('cache_data in Vimeo90K-Test dataset is not implemented.')
159
+ self.gt_root, self.lq_root = opt['dataroot_gt'], opt['dataroot_lq']
160
+ self.data_info = {'lq_path': [], 'gt_path': [], 'folder': [], 'idx': [], 'border': []}
161
+ neighbor_list = [i + (9 - opt['num_frame']) // 2 for i in range(opt['num_frame'])]
162
+
163
+ # file client (io backend)
164
+ self.file_client = None
165
+ self.io_backend_opt = opt['io_backend']
166
+ assert self.io_backend_opt['type'] != 'lmdb', 'No need to use lmdb during validation/test.'
167
+
168
+ logger = get_root_logger()
169
+ logger.info(f'Generate data info for VideoTestDataset - {opt["name"]}')
170
+ with open(opt['meta_info_file'], 'r') as fin:
171
+ subfolders = [line.split(' ')[0] for line in fin]
172
+ for idx, subfolder in enumerate(subfolders):
173
+ gt_path = osp.join(self.gt_root, subfolder, 'im4.png')
174
+ self.data_info['gt_path'].append(gt_path)
175
+ lq_paths = [osp.join(self.lq_root, subfolder, f'im{i}.png') for i in neighbor_list]
176
+ self.data_info['lq_path'].append(lq_paths)
177
+ self.data_info['folder'].append('vimeo90k')
178
+ self.data_info['idx'].append(f'{idx}/{len(subfolders)}')
179
+ self.data_info['border'].append(0)
180
+
181
+ def __getitem__(self, index):
182
+ lq_path = self.data_info['lq_path'][index]
183
+ gt_path = self.data_info['gt_path'][index]
184
+ imgs_lq = read_img_seq(lq_path)
185
+ img_gt = read_img_seq([gt_path])
186
+ img_gt.squeeze_(0)
187
+
188
+ return {
189
+ 'lq': imgs_lq, # (t, c, h, w)
190
+ 'gt': img_gt, # (c, h, w)
191
+ 'folder': self.data_info['folder'][index], # folder name
192
+ 'idx': self.data_info['idx'][index], # e.g., 0/843
193
+ 'border': self.data_info['border'][index], # 0 for non-border
194
+ 'lq_path': lq_path[self.opt['num_frame'] // 2] # center frame
195
+ }
196
+
197
+ def __len__(self):
198
+ return len(self.data_info['gt_path'])
199
+
200
+
201
+ @DATASET_REGISTRY.register()
202
+ class VideoTestDUFDataset(VideoTestDataset):
203
+ """ Video test dataset for DUF dataset.
204
+
205
+ Args:
206
+ opt (dict): Config for train dataset. Most of keys are the same as VideoTestDataset.
207
+ It has the following extra keys:
208
+ use_duf_downsampling (bool): Whether to use duf downsampling to generate low-resolution frames.
209
+ scale (bool): Scale, which will be added automatically.
210
+ """
211
+
212
+ def __getitem__(self, index):
213
+ folder = self.data_info['folder'][index]
214
+ idx, max_idx = self.data_info['idx'][index].split('/')
215
+ idx, max_idx = int(idx), int(max_idx)
216
+ border = self.data_info['border'][index]
217
+ lq_path = self.data_info['lq_path'][index]
218
+
219
+ select_idx = generate_frame_indices(idx, max_idx, self.opt['num_frame'], padding=self.opt['padding'])
220
+
221
+ if self.cache_data:
222
+ if self.opt['use_duf_downsampling']:
223
+ # read imgs_gt to generate low-resolution frames
224
+ imgs_lq = self.imgs_gt[folder].index_select(0, torch.LongTensor(select_idx))
225
+ imgs_lq = duf_downsample(imgs_lq, kernel_size=13, scale=self.opt['scale'])
226
+ else:
227
+ imgs_lq = self.imgs_lq[folder].index_select(0, torch.LongTensor(select_idx))
228
+ img_gt = self.imgs_gt[folder][idx]
229
+ else:
230
+ if self.opt['use_duf_downsampling']:
231
+ img_paths_lq = [self.imgs_gt[folder][i] for i in select_idx]
232
+ # read imgs_gt to generate low-resolution frames
233
+ imgs_lq = read_img_seq(img_paths_lq, require_mod_crop=True, scale=self.opt['scale'])
234
+ imgs_lq = duf_downsample(imgs_lq, kernel_size=13, scale=self.opt['scale'])
235
+ else:
236
+ img_paths_lq = [self.imgs_lq[folder][i] for i in select_idx]
237
+ imgs_lq = read_img_seq(img_paths_lq)
238
+ img_gt = read_img_seq([self.imgs_gt[folder][idx]], require_mod_crop=True, scale=self.opt['scale'])
239
+ img_gt.squeeze_(0)
240
+
241
+ return {
242
+ 'lq': imgs_lq, # (t, c, h, w)
243
+ 'gt': img_gt, # (c, h, w)
244
+ 'folder': folder, # folder name
245
+ 'idx': self.data_info['idx'][index], # e.g., 0/99
246
+ 'border': border, # 1 for border, 0 for non-border
247
+ 'lq_path': lq_path # center frame
248
+ }
249
+
250
+
251
+ @DATASET_REGISTRY.register()
252
+ class VideoRecurrentTestDataset(VideoTestDataset):
253
+ """Video test dataset for recurrent architectures, which takes LR video
254
+ frames as input and output corresponding HR video frames.
255
+
256
+ Args:
257
+ opt (dict): Same as VideoTestDataset. Unused opt:
258
+ padding (str): Padding mode.
259
+
260
+ """
261
+
262
+ def __init__(self, opt):
263
+ super(VideoRecurrentTestDataset, self).__init__(opt)
264
+ # Find unique folder strings
265
+ self.folders = sorted(list(set(self.data_info['folder'])))
266
+
267
+ def __getitem__(self, index):
268
+ folder = self.folders[index]
269
+
270
+ if self.cache_data:
271
+ imgs_lq = self.imgs_lq[folder]
272
+ imgs_gt = self.imgs_gt[folder]
273
+ else:
274
+ raise NotImplementedError('Without cache_data is not implemented.')
275
+
276
+ return {
277
+ 'lq': imgs_lq,
278
+ 'gt': imgs_gt,
279
+ 'folder': folder,
280
+ }
281
+
282
+ def __len__(self):
283
+ return len(self.folders)
basicsr/data/vimeo90k_dataset.py ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import torch
3
+ from pathlib import Path
4
+ from torch.utils import data as data
5
+
6
+ from basicsr.data.transforms import augment, paired_random_crop
7
+ from basicsr.utils import FileClient, get_root_logger, imfrombytes, img2tensor
8
+ from basicsr.utils.registry import DATASET_REGISTRY
9
+
10
+
11
+ @DATASET_REGISTRY.register()
12
+ class Vimeo90KDataset(data.Dataset):
13
+ """Vimeo90K dataset for training.
14
+
15
+ The keys are generated from a meta info txt file.
16
+ basicsr/data/meta_info/meta_info_Vimeo90K_train_GT.txt
17
+
18
+ Each line contains the following items, separated by a white space.
19
+
20
+ 1. clip name;
21
+ 2. frame number;
22
+ 3. image shape
23
+
24
+ Examples:
25
+
26
+ ::
27
+
28
+ 00001/0001 7 (256,448,3)
29
+ 00001/0002 7 (256,448,3)
30
+
31
+ - Key examples: "00001/0001"
32
+ - GT (gt): Ground-Truth;
33
+ - LQ (lq): Low-Quality, e.g., low-resolution/blurry/noisy/compressed frames.
34
+
35
+ The neighboring frame list for different num_frame:
36
+
37
+ ::
38
+
39
+ num_frame | frame list
40
+ 1 | 4
41
+ 3 | 3,4,5
42
+ 5 | 2,3,4,5,6
43
+ 7 | 1,2,3,4,5,6,7
44
+
45
+ Args:
46
+ opt (dict): Config for train dataset. It contains the following keys:
47
+ dataroot_gt (str): Data root path for gt.
48
+ dataroot_lq (str): Data root path for lq.
49
+ meta_info_file (str): Path for meta information file.
50
+ io_backend (dict): IO backend type and other kwarg.
51
+ num_frame (int): Window size for input frames.
52
+ gt_size (int): Cropped patched size for gt patches.
53
+ random_reverse (bool): Random reverse input frames.
54
+ use_hflip (bool): Use horizontal flips.
55
+ use_rot (bool): Use rotation (use vertical flip and transposing h and w for implementation).
56
+ scale (bool): Scale, which will be added automatically.
57
+ """
58
+
59
+ def __init__(self, opt):
60
+ super(Vimeo90KDataset, self).__init__()
61
+ self.opt = opt
62
+ self.gt_root, self.lq_root = Path(opt['dataroot_gt']), Path(opt['dataroot_lq'])
63
+
64
+ with open(opt['meta_info_file'], 'r') as fin:
65
+ self.keys = [line.split(' ')[0] for line in fin]
66
+
67
+ # file client (io backend)
68
+ self.file_client = None
69
+ self.io_backend_opt = opt['io_backend']
70
+ self.is_lmdb = False
71
+ if self.io_backend_opt['type'] == 'lmdb':
72
+ self.is_lmdb = True
73
+ self.io_backend_opt['db_paths'] = [self.lq_root, self.gt_root]
74
+ self.io_backend_opt['client_keys'] = ['lq', 'gt']
75
+
76
+ # indices of input images
77
+ self.neighbor_list = [i + (9 - opt['num_frame']) // 2 for i in range(opt['num_frame'])]
78
+
79
+ # temporal augmentation configs
80
+ self.random_reverse = opt['random_reverse']
81
+ logger = get_root_logger()
82
+ logger.info(f'Random reverse is {self.random_reverse}.')
83
+
84
+ def __getitem__(self, index):
85
+ if self.file_client is None:
86
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
87
+
88
+ # random reverse
89
+ if self.random_reverse and random.random() < 0.5:
90
+ self.neighbor_list.reverse()
91
+
92
+ scale = self.opt['scale']
93
+ gt_size = self.opt['gt_size']
94
+ key = self.keys[index]
95
+ clip, seq = key.split('/') # key example: 00001/0001
96
+
97
+ # get the GT frame (im4.png)
98
+ if self.is_lmdb:
99
+ img_gt_path = f'{key}/im4'
100
+ else:
101
+ img_gt_path = self.gt_root / clip / seq / 'im4.png'
102
+ img_bytes = self.file_client.get(img_gt_path, 'gt')
103
+ img_gt = imfrombytes(img_bytes, float32=True)
104
+
105
+ # get the neighboring LQ frames
106
+ img_lqs = []
107
+ for neighbor in self.neighbor_list:
108
+ if self.is_lmdb:
109
+ img_lq_path = f'{clip}/{seq}/im{neighbor}'
110
+ else:
111
+ img_lq_path = self.lq_root / clip / seq / f'im{neighbor}.png'
112
+ img_bytes = self.file_client.get(img_lq_path, 'lq')
113
+ img_lq = imfrombytes(img_bytes, float32=True)
114
+ img_lqs.append(img_lq)
115
+
116
+ # randomly crop
117
+ img_gt, img_lqs = paired_random_crop(img_gt, img_lqs, gt_size, scale, img_gt_path)
118
+
119
+ # augmentation - flip, rotate
120
+ img_lqs.append(img_gt)
121
+ img_results = augment(img_lqs, self.opt['use_hflip'], self.opt['use_rot'])
122
+
123
+ img_results = img2tensor(img_results)
124
+ img_lqs = torch.stack(img_results[0:-1], dim=0)
125
+ img_gt = img_results[-1]
126
+
127
+ # img_lqs: (t, c, h, w)
128
+ # img_gt: (c, h, w)
129
+ # key: str
130
+ return {'lq': img_lqs, 'gt': img_gt, 'key': key}
131
+
132
+ def __len__(self):
133
+ return len(self.keys)
134
+
135
+
136
+ @DATASET_REGISTRY.register()
137
+ class Vimeo90KRecurrentDataset(Vimeo90KDataset):
138
+
139
+ def __init__(self, opt):
140
+ super(Vimeo90KRecurrentDataset, self).__init__(opt)
141
+
142
+ self.flip_sequence = opt['flip_sequence']
143
+ self.neighbor_list = [1, 2, 3, 4, 5, 6, 7]
144
+
145
+ def __getitem__(self, index):
146
+ if self.file_client is None:
147
+ self.file_client = FileClient(self.io_backend_opt.pop('type'), **self.io_backend_opt)
148
+
149
+ # random reverse
150
+ if self.random_reverse and random.random() < 0.5:
151
+ self.neighbor_list.reverse()
152
+
153
+ scale = self.opt['scale']
154
+ gt_size = self.opt['gt_size']
155
+ key = self.keys[index]
156
+ clip, seq = key.split('/') # key example: 00001/0001
157
+
158
+ # get the neighboring LQ and GT frames
159
+ img_lqs = []
160
+ img_gts = []
161
+ for neighbor in self.neighbor_list:
162
+ if self.is_lmdb:
163
+ img_lq_path = f'{clip}/{seq}/im{neighbor}'
164
+ img_gt_path = f'{clip}/{seq}/im{neighbor}'
165
+ else:
166
+ img_lq_path = self.lq_root / clip / seq / f'im{neighbor}.png'
167
+ img_gt_path = self.gt_root / clip / seq / f'im{neighbor}.png'
168
+ # LQ
169
+ img_bytes = self.file_client.get(img_lq_path, 'lq')
170
+ img_lq = imfrombytes(img_bytes, float32=True)
171
+ # GT
172
+ img_bytes = self.file_client.get(img_gt_path, 'gt')
173
+ img_gt = imfrombytes(img_bytes, float32=True)
174
+
175
+ img_lqs.append(img_lq)
176
+ img_gts.append(img_gt)
177
+
178
+ # randomly crop
179
+ img_gts, img_lqs = paired_random_crop(img_gts, img_lqs, gt_size, scale, img_gt_path)
180
+
181
+ # augmentation - flip, rotate
182
+ img_lqs.extend(img_gts)
183
+ img_results = augment(img_lqs, self.opt['use_hflip'], self.opt['use_rot'])
184
+
185
+ img_results = img2tensor(img_results)
186
+ img_lqs = torch.stack(img_results[:7], dim=0)
187
+ img_gts = torch.stack(img_results[7:], dim=0)
188
+
189
+ if self.flip_sequence: # flip the sequence: 7 frames to 14 frames
190
+ img_lqs = torch.cat([img_lqs, img_lqs.flip(0)], dim=0)
191
+ img_gts = torch.cat([img_gts, img_gts.flip(0)], dim=0)
192
+
193
+ # img_lqs: (t, c, h, w)
194
+ # img_gt: (c, h, w)
195
+ # key: str
196
+ return {'lq': img_lqs, 'gt': img_gts, 'key': key}
197
+
198
+ def __len__(self):
199
+ return len(self.keys)