【图像超分】论文复现:Pytorch实现FSRCNN,包含详细实验流程和与SRCNN的比较

文章目录

  • 前言
  • 1. FSRCNN网络结构
  • 2. 训练FSRCNN
  • 3. FSRCNN模型测试
  • 4. 训练好的FSRCNN模型超分自己的图像


前言

论文地址:Accelerating the Super-Resolution Convolutional Neural Network

论文精读:

请配合上述论文精读文章使用,效果更佳!

代码地址:

不想理解原理,希望直接跑通然后应用到自己的图像数据的同学,请直接下载上面的代码,有训练好的模型,直接用即可。具体使用方式见代码中的README!有问题来本文评论区留言!

深度学习的模型训练一般遵循以下步骤:

  1. 准备数据集,以及数据预处理
  2. 搭建网络模型
  3. 设置参数并训练
  4. 测试训练好的模型
  5. 用训练好的模型测试自己的数据

硬件环境:windows11+RTX 2060(比这个高肯定没问题,我这个配置本机跑500个epoch一点问题没有,一会就跑完。但超分自己的图像时,如果图像很大,可能有内存溢出的错误
运行环境:jupyter notebook/pycharm(前者好处是分代码段运行,测试方法,适合学习用;后者适合跑完整项目用
pytorch环境:torch1.9.1+cuda11.1(其他版本没测试过,应该问题不大)

本文是在SRCNN的基础上进一步实现的,如果没看过前面SRCNN的复现文章,请先阅读那篇文章。

数据预处理与SRCNN完全相同,本文从搭建网络模型开始。

1. FSRCNN网络结构

在这里插入图片描述
简单回顾一下FSRCNN的改进:

  • 取消双三次插值,直接以低分辨率输入
  • 网络最后一层为反卷积层
  • SRCNN的非线性映射层改进为沙漏型的收缩、映射、扩展层
  • 激活函数由ReLU变成了PReLU
  • 与SRCNN相比,卷积核大小变小,但网络结构变深
  • 输入和输出的图大小可以不同

网络的整体结构为:Conv(5, d, 1)−PReLU −Conv(1, s, d)−PReLU −m×Conv(3, s, s)−PReLU − Conv(1, d, s) − PReLU − DeConv(9, 1, d)

我们使用论文中4.4提到的默认网络FSRCNN (56,12,4)来实验。

网络结构的定义如下:

class FSRCNN(nn.Module):
    def __init__(self, scale_factor, num_channels=1, d=56, s=12, m=4):
        super(FSRCNN, self).__init__()
        # 特征提取部分
        self.first_part = nn.Sequential(
            nn.Conv2d(num_channels, d, kernel_size=5, padding=5//2),
            nn.PReLU(d)
        )
        
        # 收缩层
        self.mid_part = [nn.Conv2d(d, s, kernel_size=1), nn.PReLU(s)]
        
        # m个映射层
        for _ in range(m):
            self.mid_part.extend([nn.Conv2d(s, s, kernel_size=3, padding=3//2), nn.PReLU(s)])
            
        # 扩展层
        self.mid_part.extend([nn.Conv2d(s, d, kernel_size=1), nn.PReLU(d)])
        
        # 上面三个层构成中间层
        self.mid_part = nn.Sequential(*self.mid_part)
        
        # 反卷积nn.ConvTranspose2d,输入输出与特征提取层相同,output_padding防止输入输入图像大小不匹配
        self.last_part = nn.ConvTranspose2d(d, num_channels, kernel_size=9, stride=scale_factor, padding=9//2,
                                            output_padding=scale_factor-1)

        self._initialize_weights()
        
    # 初始权重都是均值为0标准差为0.001的高斯分布
    def _initialize_weights(self):
        for m in self.first_part:
            if isinstance(m, nn.Conv2d):
                nn.init.normal_(m.weight.data, mean=0.0, std=math.sqrt(2/(m.out_channels*m.weight.data[0][0].numel())))
                nn.init.zeros_(m.bias.data)
        for m in self.mid_part:
            if isinstance(m, nn.Conv2d):
                nn.init.normal_(m.weight.data, mean=0.0, std=math.sqrt(2/(m.out_channels*m.weight.data[0][0].numel())))
                nn.init.zeros_(m.bias.data)
        nn.init.normal_(self.last_part.weight.data, mean=0.0, std=0.001)
        nn.init.zeros_(self.last_part.bias.data)

    def forward(self, x):
        x = self.first_part(x)
        x = self.mid_part(x)
        x = self.last_part(x)
        return x

2. 训练FSRCNN

根据论文4.1部分训练策略章节:卷积层的学习率是0.001,反卷积层的学习率是0.0001。

参照之前文章中的SRCNN训练,我们实现了FSRCNN的训练:

model = FSRCNN(1).to(device)
criterion = nn.MSELoss()
# optimizer = optim.Adam(model.parameters(), lr=1e-2)
optimizer = optim.Adam(              
    [
        {"params": model.first_part.parameters(), "lr": 0.001},
        {"params": model.mid_part.parameters(), "lr": 0.001},
        {"params": model.last_part.parameters(), "lr": 0.0001},
    ]
)
#scheduler = MultiStepLR(optimizer, milestones=[50, 75, 100], gamma=0.1) # 学习率调度器,在epoch在50,75,100时降低学习率
best_psnr = 0.0
each_psnr = []
for epoch in range(nb_epochs):
    # Train
    epoch_loss = 0
    for iteration, batch in enumerate(trainloader):
        input, target = batch[0].to(device), batch[1].to(device)
        optimizer.zero_grad()
        out = model(input)
        loss = criterion(out, target)
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
    print(f"Epoch {epoch}. Training loss: {epoch_loss / len(trainloader)}")
    # Val
    sum_psnr = 0.0
    sum_ssim = 0.0
    with torch.no_grad():
        for batch in valloader:
            input, target = batch[0].to(device), batch[1].to(device)
            out = model(input)
            loss = criterion(out, target)
            pr = psnr(loss)
            sm = ssim(input, out)
            sum_psnr += pr
            sum_ssim += sm
    print(f"Average PSNR: {sum_psnr / len(valloader)} dB.")
    print(f"Average SSIM: {sum_ssim / len(valloader)} ")
    avg_psnr = sum_psnr / len(valloader)
    each_psnr.append(avg_psnr)
    if avg_psnr >= best_psnr:
        best_psnr = avg_psnr
        torch.save(model, r"best_model_FSRCNN_2.pth")
    #scheduler.step()

数据的相关参数设置与SRCNN相同,放大倍数为2。训练500个epoch,PSNR稳定在28.43,SSIM稳定在0.9268。

在这里插入图片描述
可视化epoch与PSNR的关系:
在这里插入图片描述
有波动和梯度骤降是因为我设置了学习率调度器,取消学习率调度器后为平滑曲线。对于BSD200数据集来说,训练100个epoch的PSNR基本保持稳定,没必要训练500个epoch。

可视化的代码如下,与SRCNN中的画图代码基本一致:

epochs = range(0,nb_epochs)

# plot画图,设置颜色和图例,legend设置图例样式,右下,字体大小
plt.plot(epochs,each_psnr,color='red',label='FSRCNN(trained on BSD200)')  
plt.legend(loc = 'lower right',prop={'family' : 'Times New Roman', 'size'   : 12})

# 横纵轴文字内容以及字体样式
plt.xlabel("epoch",fontproperties='Times New Roman',size = 12)
plt.ylabel("Average test PSNR (dB)",fontproperties='Times New Roman',size=12)

# 横纵轴刻度以及字体样式
plt.xlim(0,nb_epochs)
plt.ylim(20,29)
plt.yticks(fontproperties='Times New Roman', size=12)
plt.xticks(fontproperties='Times New Roman', size=12)

# 网格样式
plt.grid(ls = '--')

plt.show()

3. FSRCNN模型测试

测试代码如下:

BATCH_SIZE = 4
model_path = "best_model_FSRCNN_2.pth"
testset = DatasetFromFolder(r"./data/images/test", zoom_factor)
testloader = DataLoader(dataset=testset, batch_size=BATCH_SIZE,
                        shuffle=False, num_workers=NUM_WORKERS)
sum_psnr = 0.0
sum_ssim = 0.0
model = torch.load(model_path).to(device)
criterion = nn.MSELoss()
with torch.no_grad():
    for batch in testloader:
        input, target = batch[0].to(device), batch[1].to(device)
        out = model(input)
        loss = criterion(out, target)
        pr = psnr(loss)
        sm = ssim(input, out)
        sum_psnr += pr
        sum_ssim += sm
print(f"Test Average PSNR: {sum_psnr / len(testloader)} dB")
print(f"Test Average SSIM: {sum_ssim / len(testloader)} ")

结果为:
在这里插入图片描述
在相同数据集上测试,FSRCNN的PSNR高于SRCNN,但是SSIM更低。

4. 训练好的FSRCNN模型超分自己的图像

代码如下:

# 参数设置
zoom_factor = 1
model = "best_model_FSRCNN_2.pth"
image = "./SEM_image_test/6.jpg"
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# 读取图片
img = Image.open(image).convert('YCbCr') # PIL类型,转成YCbCr
img = img.resize((int(img.size[0] * zoom_factor), int(img.size[1] * zoom_factor)), Image.BICUBIC) # 双三次插值放大
y, cb, cr = img.split() # 划分Y,cb,cr三个通道
img_to_tensor = transforms.ToTensor() # 获得一个ToTensor对象

# view中-1的含义是该维度不明,让其自动计算, input是由torch.Tensor([1,h,w])变成torch.Tensor([1,1,h,w])
# 图像Tensor格式:(batch_size, channel, h, w)
input = img_to_tensor(y).view(1, -1, y.size[1], y.size[0]).to(device) # 将y通道变换成网络输入的tensor格式

# 输出图片
model = torch.load(model).to(device) # 载入模型
out = model(input).cpu() # 模型输出
out_img_y = out[0].detach().numpy() # 返回新的三维张量并转成numpy
out_img_y *= 255.0 
out_img_y = out_img_y.clip(0, 255) # 取0-255内的值
out_img_y = Image.fromarray(np.uint8(out_img_y[0]), mode='L') # numpy转成PIL
out_img = Image.merge('YCbCr', [out_img_y, cb, cr]).convert('RGB') # 合并三个通道变成RGB格式

# 绘图显示,上面的操作都是为了plt显示图像
fig, ax = plt.subplots(1, 2, figsize=(22, 10))
ax[0].imshow(img)
ax[0].set_title("原图")
ax[1].imshow(out_img)
ax[1].set_title("FSRCNN恢复结果")

# 改dpi大小得到保存的图像清晰度,越大图片文件越大,质量越高;有的办法是保存成pdf,pdf放大不失真
plt.savefig(r"./SEM_image_test/6_FSRCNN_x1_result.png",dpi=1000,bbox_inches = 'tight')
plt.show()

在这里插入图片描述
视觉上感觉跟SRCNN差不多。

从指标上来看,用与SRCNN中提到的根据图像上每个像素计算PSNR和SSIM,结果为:
在这里插入图片描述
PSNR基本相同,但是SSIM降低很多。对于超分后的图像,经过FSRCNN的结构变化要比经过SRCNN大。即FSRCNN的性能更显著。

除此之外,通过对模型文件的大小观察,FSRCNN明显更小,但性能更好,也与论文相符。
在这里插入图片描述
后续将用91images数据集和其他数据集来测试模型,重点还是在于入门深度学习流程。

如果本文对你有所帮助,点个赞吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/451008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python接口自动化核心模块 - 数据库操作和日志

一、Python连接数据库常见模块 MysqlDBpython2时代最火的驱动库。基于C开发,对windows平台不友好。现在已经进入python3时代,基本不再使用MysqlClientmysqldb的衍生版本,完全兼容python3.它是重量级Web开发框架Django中ORM功能依赖工具Pymys…

01_lombok review

文章目录 Lombok父子工程ide中的Maven基础配置前置知识储备 Lombok 怎么引入Lombok依赖&#xff1a; step1&#xff1a;引入Lombok依赖 eg&#xff1a; <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok<…

9:00面试,9:06就出来了,问的实在是太变态了

我从一家小公司转投到另一家公司&#xff0c;期待着新的工作环境和机会。然而&#xff0c;新公司的加班文化让我有些始料未及。虽然薪资相对较高&#xff0c;但长时间的工作和缺乏休息使我身心俱疲。 就在我逐渐适应这种高强度的工作节奏时&#xff0c;公司突然宣布了一则令人…

GaussianEditor:根据用户指令编辑三维 GS 场景

Paper: Fang J, Wang J, Zhang X, et al. Gaussianeditor: Editing 3d gaussians delicately with text instructions[J]. arXiv preprint arXiv:2311.16037, 2023. Introduction: https://gaussianeditor.github.io/ Code: Unreleased 本篇的 GaussianEditor 和 NTU 的 Gaussi…

《父母的语言:3000万词汇塑造更强大的学习型大脑》早期家庭语言环境的重要性(二)

目录 简介 经典内容摘录 简介 本书作者是美国芝加哥大学妇科及儿科教授达娜萨斯金德博士。作者发起了“3000万词汇倡议”&#xff0c;“3000万词汇倡议”发现了一个秘密&#xff0c;即低收入家庭的孩子为什么“输在起跑线”上。调查显示&#xff0c;低收入家庭…

【零基础学习03】嵌入式linux驱动中自旋锁功能基本实现

大家好,为了进一步提升大家对实验的认识程度,每个控制实验将加入详细控制思路与流程,欢迎交流学习。 今天给大家分享一下,linux系统里面自旋锁操作的具体实现,操作硬件为I.MX6ULL开发板。 第一:自旋锁基本简介 ①、自旋锁保护的临界区要尽可能的短,可以使用一个变量来表…

119.龙芯2k1000-pmon(18)-全自动安装linux系统

经过两天的测试和完善&#xff0c;现在基本已经正常可用了。 &#xff08;全自动是假&#xff0c;接近全自动吧。&#xff09; 需要使用配测电脑的网络功能&#xff0c;windows即可&#xff0c;脱离linux虚拟机。&#xff08;理论上讲u盘也是可以的&#xff09; 测试平台&…

JDBC底层原理

1、什么是JBDC? JBDC&#xff08;Java Database Connectivity&#xff09;&#xff0c;JDBC只是一套规范接口&#xff0c;真正实现的是各数据库厂商驱动。 2、JBDC的底层的主要接口对象是什么&#xff1f; JBDC的底层主要是三个接口对象,Connection、Statement、ResultSet。Co…

C#实现二分查找算法

C#实现二分查找算法 以下是一个使用 C# 实现的二分查找算法示例&#xff1a; using System;class Program {static int BinarySearch(int[] arr, int target){int low 0;int high arr.Length - 1;while (low < high){int mid (low high) / 2;// 如果目标值等于中间元素…

javaEE6(网站第3章-jsp练习中三个例题动手做一遍;课后题2(1),(2))

两个数求和 用javascript实现。 输入、处理、输出用同一个页面(自己处理自己)。 输入1.jsp&#xff0c;处理和输出2.jsp。 &#xff08;4&#xff09;输入1.jsp&#xff0c;处理2.jsp&#xff0c;处理完转回1.jsp显示结果。 &#xff08;5&#xff09;输入1.jsp&#xff0c;处…

Python: 如何绘制核密度散点图和箱线图?

01 数据样式 这是数据样式&#xff1a; 要求&#xff08;我就懒得再复述一遍了&#xff0c;直接贴图&#xff09;&#xff1a; Note&#xff1a;数据中存在无效值NA&#xff08;包括后续的DEM&#xff09;&#xff0c;需要注意 02 提取DEM 这里我就使用gdal去提取一下DEM列…

Mixamo动画素材导入UE5的最简单方法

一、Mixamo素材 官网&#xff1a;https://www.mixamo.com/ Mixamo是Adobe公司出品的免费动画库&#xff0c;可商用。软件分为characters(角色&#xff09;、Animations&#xff08;动画)两个部分。 二、辅助工具MIXAMO CONVERTER 官网&#xff1a;https://terribilisstudio…

海外媒体发稿:新闻媒体发稿7种方法-华媒舍

新闻报道媒体发稿营销推广是当代企业形象宣传的重要手段之一&#xff0c;合理推广可以提升品牌知名度、吸引住潜在用户。在这篇文章中&#xff0c;我们将要详细介绍七种科学合理的形式&#xff0c;帮助你完全把握新闻报道媒体发稿营销推广。 1.明确目标群体明确目标群体是实现推…

阅读欣赏推荐之(三)——纪录片《地平线系列:大数据时代》

现今的我们正处于一个时代转型中&#xff0c;因为科技的发展与互联网的日益强大&#xff0c;数据将逐步取代旧事物&#xff0c;创造出新事物。当今社会以一种前所未有的方式&#xff0c;通过对海量数据进行分析&#xff0c;获得巨大价值的产品和服务&#xff0c;或深刻的洞见。…

SSM整合项目(显示+添加+修改家居)

文章目录 1.显示全部家居1.需求分析2.思路分析3.编写Service层1.FurnService.java 添加方法2.FurnServiceImpl.java 实现方法3.单元测试 4.编写Controller层1.FurnController.java 添加方法2.postman完成测试 5.前端展示家居1.HomeView.vue 修改el-table使其prop跟Furn的属性名…

PLC远程故障诊断

随着工业自动化水平的不断提升&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;在生产线控制、设备自动化等领域发挥着越来越重要的作用。然而&#xff0c;PLC在运行过程中难免会出现故障&#xff0c;影响生产线的稳定运行。因此&#xff0c;如何迅速、准确地诊断并解…

有c语言基础,如何快速学会C++核心知识?

有c语言基础&#xff0c;如何快速学会C核心知识&#xff1f; 在开始前我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;给了我机会&#xff0c;一年时间从3k薪资涨到18k的&#xff0c; 我师父给了一些 电气工程师学习方法和资料&#xff0c;让我不断提…

Python deepFM推荐系统,推荐算法,deepFM源码实战,deepFM代码模板

1.DeepFM介绍&#xff1a; DeepFM&#xff08;Deep Factorization Machine&#xff09;是一种结合了深度学习和因子分解机的推荐模型。它在CTR&#xff08;点击率&#xff09;预测任务中表现出色&#xff0c;并能够有效地处理稀疏特征。 DeepFM模型由两个部分组成&#xff1a;因…

截断表

oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 截断表 事务处理本身是保护数据完整性的一个手段&#xff0c;但是在使用事务处理的过程之中需要注意一点 在用户更新数据后还未进行事务提交时&#xff0c;如果发生了 DDL…

1688 API接口在数据分析与营销决策中的应用探索

在当今数字化快速发展的时代&#xff0c;数据分析与营销决策已成为企业运营中不可或缺的重要环节。而1688 API接口&#xff0c;作为阿里巴巴旗下的一个强大的数据交互平台&#xff0c;为企业在数据分析与营销决策方面提供了丰富的数据源和灵活的操作方式。本文将深入探讨1688 A…