《Enhanced Deep Residual Networks for Single Image Super-Resolution》是首尔国立大学Bee Lim 等人于2017年发表于CVPR的一篇文章,该文章在SRResnet的基础上改进了网络冗余,提出了一种增强型深度超分辨率网络(EDSR),其性能超过当前最先进的SR方法。
EDSR网络主要创新点:
1、提出了一种新的多尺度模型,利用每个尺度学习特征的相互关系,有效地重建不同尺度的高分辨率图像;
2、提出了一种合适的训练方法,该方法对于单尺度和多尺度模型均可使用多尺度训练;
3、使用L1损失作为损失函数训练网络以提高模型性能。
网络模型:
1、Resnet模块
在SRResnet的基础上移除了批处理归一化层,提高网络性能(保留像素间的相对差异)的同时降低了GPU内存使用率,同时去掉ReLU激活层。
2、单尺度模型(EDSR)
研究表明增加网络的信道数量能够在提高性能的同时最大化模型容量,但特征图增加到一定数量会使训练过程的数值不稳定。因此采用系数为0.1的残差缩放来解决这个问题,在每个残差块中最后卷积层之后放置恒定缩放层。其中Baseline模型如下图所示,设置网络层数B=16,特征通道数量F=64,无残差缩放模块;最终的EDSR模型包含残差缩放模块,设置网络层数B=32,特征通道数量F=256,比例因子=0.1。使用×2scale作为预训练模型以加速收敛。
3、多尺度模型(MDSR)
在多尺度架构中,引入了特定尺度的处理模块来处理多尺度的超分辨率。首先,预处理模块位于网络的前端,以减少来自不同尺度输入图像的差异。每个预处理模块由两个卷积核大小为5×5的残差块组成。在预处理模块采用较大的内核可以使尺度特定的部分保持浅层状态,在网络的早期覆盖较大的感受野。在多尺度模型的末尾并行放置特定尺度的上采样模块,以处理多尺度重建。上采样模块的架构与单尺度模型架构相似。其中Baseline模型如下图所示,设置B=16;最终的MDSR模型设置B=80,F=64。
训练过程:
数据集:DIV2K(包含800个训练图像、100个验证图像和100个测试图像),同时比较了四个标准基准数据集的性能(Set5、Set14、B100和Urban100)。
数据预处理:裁剪LR与HR输入对的patches=48×48,随机使用水平翻转和90°旋转来增加训练数据,最后通过减去DIV2K数据集的平均RGB值来预处理所有图像。
训练参数:
基于Pytorch的复现过程:
EDSR网络实现:
class MeanShift(nn.Conv2d):
def __init__(self, rgb_range=255, rgb_mean=(0.4488, 0.4371, 0.4040), rgb_std=(1.0, 1.0, 1.0),sign=-1):
super(MeanShift, self).__init__(3, 3, kernel_size=1)
std = torch.Tensor(rgb_std)
self.weight.data = torch.eye(3).view(3, 3, 1, 1) / std.view(3, 1, 1, 1)
self.bias.data = sign * rgb_range * torch.Tensor(rgb_mean) / std
for p in self.parameters():
p.requires_grad = False
class ResBlock(nn.Module):
def __init__(self, in_channel=256, out_channel=256, kernel_size=3, stride=1, padding=1,bias=True):
super(ResBlock, self).__init__()
layers = [nn.Conv2d(in_channel, out_channel, kernel_size=kernel_size, stride=stride,padding=padding, bias=bias),
nn.ReLU(inplace=True),
nn.Conv2d(in_channel, out_channel, kernel_size=kernel_size, stride=stride,padding=padding, bias=bias)]
self.body = nn.Sequential(*layers)
self.res_scale = 0.1
def forward(self, x):
res = self.body(x).mul(self.res_scale)
res += x
return res
class Upsampler(nn.Sequential):
def __init__(self, scale):
layers = []
if scale == 2 or scale == 4:
layers.append(nn.Conv2d(256, 256 * 4, kernel_size=3, stride=1, padding=1, bias=True))
layers.append(nn.PixelShuffle(2))
if scale == 4:
layers.append(nn.Conv2d(256, 256 * 4, kernel_size=3, stride=1, padding=1,
bias=True))
layers.append(nn.PixelShuffle(2))
elif scale == 3:
layers.append(nn.Conv2d(256, 256 * 9, kernel_size=3, stride=1, padding=1, bias=True))
layers.append(nn.PixelShuffle(3))
else:
raise NotImplementedError
super(Upsampler, self).__init__(*layers)
class EDSR(nn.Module):
def __init__(self, scale):
super(EDSR, self).__init__()
head_layers = [nn.Conv2d(3, 256, kernel_size=3, stride=1, padding=1, bias=True)]
body_layers = []
for _ in range(32):
body_layers.append(ResBlock())
body_layers.append(nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1, bias=True))
tail_layers = [Upsampler(scale=scale),
nn.Conv2d(256, 3, kernel_size=3, stride=1, padding=1, bias=True)]
self.sub_mean = MeanShift(sign=-1)
self.add_mean = MeanShift(sign=1)
self.head = nn.Sequential(*head_layers)
self.body = nn.Sequential(*body_layers)
self.tail = nn.Sequential(*tail_layers)
def forward(self, x):
x = self.sub_mean(x)
x = self.head(x)
res = self.body(x)
res += x
x = self.tail(res)
x = self.add_mean(x)
return x
实验结果:(×4scale下与其他模型的定性比较)