超分辨率第四章-VDSR&EDSR

超分辨率第四章-VDSR&EDSR

VDSR是2016年提出的模型

EDSR是是SRResNet的增强版本,2017年提出

一.VDSR

1.模型介绍

  • SRCNN的不足
    • 在增加深度之后训练效果较差。
    • 模型只适用于单个放大因子,若需使用其他放大因子的尺度,需另外训练一个模型。
  • 改进措施
    • 基于VGG网络的方法,增强感受野,模型深度达到20层。
    • 使用残差网络训练模型,避免退化问题。
    • 使用高学习率(0.1开始)加快收敛速度,并使用一个可调的梯度裁剪,以最大限度地提高速度,同时抑制爆炸梯度。
    • SRCNN是针对单一尺度进行训练的,如果需要处理不同尺度的图像,则需要训练多个模型。而VDSR通过训练一个单一的网络来处理多尺度的超分辨率问题,显著降低了参数量并提高了实用性
  • 模型架构:作者使用20个网络层,除第一层和最后一层外,其余层具有相同的类型:64个大小为3x3x64的滤波器,也就是每一层滤波器的输入通道数为64,输出通道数也为64。其中一个滤波器在3*3的空间区域上操作。第一个网络层对输入图像进行操作,最后一个网络层用于图像重建。

pAQCOc4.png

2.数据集

  • 训练集-91张图片(进行数据增强后得到训练集)
  • 测试集-set5

3.模型结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#设置中间层结构
class Conv_ReLU_Block(nn.Module):
def __init__(self):
super(Conv_ReLU_Block, self).__init__()
self.conv = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
self.relu = nn.ReLU(inplace=True)

def forward(self, x):
return self.relu(self.conv(x))

# 主要网络结构
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.residual_layer = self.make_layer(Conv_ReLU_Block, 18) #18个3*3*64的中间层结构
self.input = nn.Conv2d(in_channels=1, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False) #输入层
self.output = nn.Conv2d(in_channels=64, out_channels=1, kernel_size=3, stride=1, padding=1, bias=False) #输出层
self.relu = nn.ReLU(inplace=True)

# 初始化Conv2d层中的权重,使用高斯分布,标准差根据输入特征数量动态计算
for m in self.modules():
if isinstance(m, nn.Conv2d):
n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
m.weight.data.normal_(0, sqrt(2. / n))

def make_layer(self, block, num_of_layer): #创建中间层
layers = []
for _ in range(num_of_layer):
layers.append(block())
return nn.Sequential(*layers)

def forward(self, x):
residual = x #原始输入作为残差
out = self.relu(self.input(x)) #依次通过输入层、中间层、输出层
out = self.residual_layer(out)
out = self.output(out)
out = torch.add(out, residual) #输出与残差相加,实现残差连接
return out

if __name__ == '__main__':
modeltest = Net()
print(modeltest)

4.模型训练

参数设置:

1
2
Namespace(batchSize=128, nEpochs=50, lr=0.1, step=10, cuda=True, resume='', start_epoch=1, clip=0.4, threads=1, momentum=0.9, weight_decay=0.0001, pretrained='none', gpus='0')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
train_set = DatasetFromHdf5("data/train.h5")  
training_data_loader = DataLoader(dataset=train_set, batch_size=opt.batchSize, shuffle=True)
model = Net()
criterion = nn.MSELoss(reduction='sum')
optimizer = optim.SGD(model.parameters(), lr=opt.lr, momentum=opt.momentum, weight_decay=opt.weight_decay) # 设置优化器

for epoch in range(opt.start_epoch, opt.nEpochs + 1):
train(training_data_loader, optimizer, model, criterion, epoch) # 调用训练函数
save_checkpoint(model, epoch) # 保存每轮训练后的权重

def train(training_data_loader, optimizer, model, criterion, epoch):
#每轮调整学习率
lr = adjust_learning_rate(optimizer, epoch-1)
#遍历优化器的参数组,将每个组的学习率设置为新的学习率
for param_group in optimizer.param_groups:
param_group["lr"] = lr
# 打印当前epoch和对应的学习率
print("Epoch = {}, lr = {}".format(epoch, optimizer.param_groups[0]["lr"]))

# 设置模型为训练模式
model.train()
for iteration, batch in enumerate(training_data_loader, 1):
input, target = Variable(batch[0]), Variable(batch[1], requires_grad=False)
if opt.cuda:
input = input.cuda()
target = target.cuda()

loss = criterion(model(input), target)
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), opt.clip) #梯度裁剪是一种技术,用于控制梯度的更新量,以避免在训练过程中出现梯度爆炸的问题,从而有助于模型训练的稳定性,当调用 nn.utils.clip_grad_norm_(model.parameters(), opt.clip) 时,PyTorch 会计算模型所有参数的梯度的L2范数。如果这个范数大于 opt.clip 指定的值,那么每个参数的梯度将会按比例缩放,使得最终的L2范数等于 opt.clip。
optimizer.step()

二. EDSR

  • 在SRResnet的基础上去除了BN层

pAQm0Gn.png

结构如下:

  • pAQmDx0.png
-------------本文结束-------------