使用 ESPCN 模型进行超分辨率图像处理

前言

使用 ESPCN (Efficient Sub-Pixel CNN) 模型对低分辨率的图像,进行超分辨率处理。

效果展示

lowres 表示低分辨率图像,highres 表示高分辨率图像,prediction 表示模型预测的高分辨率图像,可以看出模型在生成高分辨率图像过程中确实发挥了作用。

image.png

image.png

image.png

PSNR of low resolution image and high resolution image is 25.4162
PSNR of predict and high resolution is 26.8309

image.png

image.png

image.png

PSNR of low resolution image and high resolution image is 24.5984
PSNR of predict and high resolution is 26.2234

模型原理

SRCNNDRCN 中,低分辨率图像都是先通过上采样插值得到与高分辨率图像同样的大小再作为网络输入,这意味着卷积操作在较高的分辨率上进行,相比于在低分辨率的图像上计算卷积会降低效率ESPCN 提出一种在低分辨率图像上直接计算卷积得到高分辨率图像的高效率方法。

image.png

ESPCN 的核心概念是亚像素卷积层(sub-pixel convolutional layer)。如上图所示,网络的输入是原始低分辨率图像,通过若干卷积层以后,得到的特征图像大小与输入图像一样,但是特征通道为 r^2 。将每个像素的 r^2 个通道重新排列成一个 r x r 的区域,对应于高分辨率图像中的一个 r x r 大小的子块,从而大小为r^2 x H x W 的特征图像被重新排列成 1 x rH x rW 大小的高分辨率图像。这个变换虽然被称作 sub-pixel convolution , 但实际上并没有卷积操作。总之亚像素卷积层包含两个过程,分别是普通的卷积层和后面的排列像素的步骤。

通过使用 sub-pixel convolution , 图像从低分辨率到高分辨率放大的过程,插值函数被隐含地包含在前面的卷积层中,可以自动学习到。只在最后一层对图像大小做变换,前面的卷积运算由于在低分辨率图像上进行,因此效率会较高。

数据处理

  • 我自己生成了一批数据,我这里是放在了 D:\pythonProject\HKYModel\data2 目录之下。
  • 因为数据集中已经分好了训练集测试集,所以直接使用函数进行本地数据的读取即可得到 train_dsvalid_ds
  • train_dsvalid_ds 中的图片都做归一化操作
root_dir = "D:\pythonProject\HKYModel\BSR\BSDS500\data"
crop_size = 300
upscale_factor = 3
input_size = crop_size // upscale_factor
batch_size = 8
train_ds = image_dataset_from_directory(root_dir, batch_size=batch_size, image_size=(crop_size, crop_size), validation_split=0.2,  subset="training", seed=1337,  label_mode=None)
valid_ds = image_dataset_from_directory(root_dir, batch_size=batch_size,  image_size=(crop_size, crop_size),  validation_split=0.2, subset="validation",  seed=1337, label_mode=None)
def scaling(input_image):input_image = input_image / 255.return input_image
train_ds = train_ds.map(scaling)
valid_ds = valid_ds.map(scaling)
  • process_input 函数接受输入图像和输入大小作为参数,并且将输入图像转换为 YUV 颜色空间。YUV 颜色空间包含了亮度(Y)和色度(U、V)信息。tf.image.rgb_to_yuv 函数用于将 RGB 彩色图像转换为 YUV 颜色空间。接着确定最后一个维度的索引。这个索引被用来沿着颜色通道轴(通常是最后一个维度)拆分输入张量,得到 Y、U、V 三个通道的张量。我们从拆分后的张量中只提取亮度通道 Y,并使用 tf.image.resize 函数将其调整为指定的输入大小,调整大小的方法是 "area"
  • process_target 函数也是类似的,它也将输入图像转换为 YUV 颜色空间,并提取出亮度通道 Y。但不同的是,它并没有调整图像的大小,只是返回了亮度通道 Y。
dataset = os.path.join(root_dir, "images")
test_path = os.path.join(dataset, "test")
test_img_paths = sorted([os.path.join(test_path, fname) for fname in os.listdir(test_path) if fname.endswith(".jpg")])
def process_input(input, input_size):input = tf.image.rgb_to_yuv(input)last_dimension_axis = len(input.shape) - 1y, u, v = tf.split(input, 3, axis=last_dimension_axis)return tf.image.resize(y, [input_size, input_size], method="area")
def process_target(input):input = tf.image.rgb_to_yuv(input)last_dimension_axis = len(input.shape) - 1y, u, v = tf.split(input, 3, axis=last_dimension_axis)return y
train_ds = train_ds.map(lambda x: (process_input(x, input_size), process_target(x))).prefetch(buffer_size=32)
valid_ds = valid_ds.map(lambda x: (process_input(x, input_size), process_target(x))).prefetch(buffer_size=32)

模型

  • DepthToSpace 类继承自 layers.Layer,表示一个深度转换空间的层,用于实现深度转换空间操作。 get_config 方法用于获取层的配置信息。这个方法被调用以保存层的配置,以便在需要序列化模型时可以重新创建相同的层实例。call 方法实现了层的前向传播逻辑,在这个方法中,它接受一个输入张量 input,然后执行深度转换空间操作。具体地,它首先获取输入张量的形状信息,然后按照 block_size 分块重排张量,并最终返回转换后的张量。

  • get_model 函数用于创建一个 Keras 模型。在这个函数中,它接受两个参数:upscale_factorchannelsupscale_factor 表示上采样因子,channels 表示输入图像的通道数。在模型中,它使用了一系列的卷积层构建了一个深度卷积神经网络。然后,通过 DepthToSpace 层来实现深度转换空间操作,以实现图像的上采样。最后,通过 keras.Model 类构建了一个 Keras 模型,指定了输入和输出,返回了这个模型。

class DepthToSpace(layers.Layer):def __init__(self, block_size):super().__init__()self.block_size = block_sizedef get_config(self):config = super().get_config()config.update({"block_size": self.block_size})return configdef call(self, input):batch, height, width, depth = ops.shape(input)depth = depth // (self.block_size**2)x = ops.reshape(input, [batch, height, width, self.block_size, self.block_size, depth])x = ops.transpose(x, [0, 1, 3, 2, 4, 5])x = ops.reshape(x, [batch, height * self.block_size, width * self.block_size, depth])return x
def get_model(upscale_factor=3, channels=1):conv_args = {"activation": "relu",  "kernel_initializer": "orthogonal", "padding": "same"}inputs = keras.Input(shape=(None, None, channels))x = layers.Conv2D(512, 5, **conv_args)(inputs)x = layers.Conv2D(256, 3, **conv_args)(x)x = layers.Conv2D(64, 3, **conv_args)(x)x = layers.Conv2D(channels * (upscale_factor**2), 3, **conv_args)(x)outputs = DepthToSpace(upscale_factor)(x)return keras.Model(inputs, outputs)

训练

  • 自定义回调函数类 ESPCNCallback ,在每个 epoch 开始时调用 on_epoch_begin 方法,它初始化了一个列表 self.psnr,用于存储每个 epoch 的峰值信噪比(PSNR)。在每个 epoch 结束时调用 on_epoch_end 方法。它计算了当前 epoch 的平均 PSNR ,并打印输出。每隔 20 个 epoch 就利用模型生成了一个预测图像,并通过 plot_results 函数绘制了这个预测图像,用于观察模型的生成效果。在每个测试集的 batch 结束时调用on_test_batch_end 方法,它计算了当前 batch 的 PSNR ,并将其添加到 self.psnr 列表中。
  • 另外创建了两个额外的 Keras 回调函数:early_stopping_callback 用于在训练过程中实施 early stopping 策略,如果在连续 5 个 epoch 中损失没有降低,则停止训练;model_checkpoint_callback 用于在训练过程中保存模型的最佳参数。
  • 使用 Adam 优化器和均方误差作为损失函数。
  • 使用 model.fit 函数进行模型的训练。指定了训练数据集 train_ds,并设置了训练的 epochs 数目为 200,并且设置了之前定义的回调函数作为回调参数。
class ESPCNCallback(keras.callbacks.Callback):def __init__(self):super().__init__()self.test_img = get_lowres_image(load_img(test_img_paths[0]), upscale_factor)def on_epoch_begin(self, epoch, logs=None):self.psnr = []def on_epoch_end(self, epoch, logs=None):print("Mean PSNR for epoch: %.2f" % (np.mean(self.psnr)))if epoch % 20 == 0:prediction = upscale_image(self.model, self.test_img)plot_results(prediction, "epoch-" + str(epoch), "prediction")def on_test_batch_end(self, batch, logs=None):self.psnr.append(10 * math.log10(1 / logs["loss"]))early_stopping_callback = keras.callbacks.EarlyStopping(monitor="loss", patience=5)
model_checkpoint_callback = keras.callbacks.ModelCheckpoint(filepath="ESPCN/checkpoint.keras", save_weights_only=False, monitor="loss",  mode="min", save_best_only=True, )
model = get_model(upscale_factor=upscale_factor, channels=1)
model.summary()
callbacks = [ESPCNCallback(), early_stopping_callback, model_checkpoint_callback]
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss=keras.losses.MeanSquaredError())
model.fit(train_ds, epochs=200, callbacks=callbacks, validation_data=valid_ds, verbose=2)

日志打印:

Epoch 1/200
2024-03-06 16:14:17.804215: I tensorflow/stream_executor/cuda/cuda_dnn.cc:384] Loaded cuDNN version 8100
Mean PSNR for epoch: 22.44
50/50 - 5s - loss: 0.0226 - val_loss: 0.0058 - 5s/epoch - 105ms/step
Epoch 2/200
Mean PSNR for epoch: 23.57
50/50 - 1s - loss: 0.0064 - val_loss: 0.0043 - 1s/epoch - 21ms/step
...
Epoch 29/200
Mean PSNR for epoch: 26.75
50/50 - 1s - loss: 0.0025 - val_loss: 0.0022 - 996ms/epoch - 20ms/step
Epoch 30/200
Mean PSNR for epoch: 26.53
50/50 - 1s - loss: 0.0025 - val_loss: 0.0023 - 992ms/epoch - 20ms/step
Epoch 31/200
Mean PSNR for epoch: 26.18
50/50 - 1s - loss: 0.0025 - val_loss: 0.0023 - 987ms/epoch - 20ms/step

那么,我们该如何学习大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

一、大模型全套的学习路线

学习大型人工智能模型,如GPT-3、BERT或任何其他先进的神经网络模型,需要系统的方法和持续的努力。既然要系统的学习大模型,那么学习路线是必不可少的,下面的这份路线能帮助你快速梳理知识,形成自己的体系。

L1级别:AI大模型时代的华丽登场

L2级别:AI大模型API应用开发工程

L3级别:大模型应用架构进阶实践

L4级别:大模型微调与私有化部署

一般掌握到第四个级别,市场上大多数岗位都是可以胜任,但要还不是天花板,天花板级别要求更加严格,对于算法和实战是非常苛刻的。建议普通人掌握到L4级别即可。

以上的AI大模型学习路线,不知道为什么发出来就有点糊,高清版可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LDR6020一拖二快充线:高效充电的新选择

LDR6020一拖二快充线:高效充电的新选择 随着移动设备的普及和功能的日益增强,电池续航成为了用户关注的重点之一。为了满足用户对于快速充电的需求,各大厂商纷纷推出了各种快充技术和产品。在这个背景下,LDR6020一拖二快充线凭借…

【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控

【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控 大家好 我是寸铁👊 总结了一篇【Golang】探索进程资源监控的精妙细节:利用Gopsutil/Process实现高级进程性能和资源信息监控的文章✨ 喜欢的小伙伴…

3-1RT-Thread时钟管理

这里写自定义目录标题 时钟节拍是RT thread操作系统的最小时间单位。 第一个功能,rt tick值自动加1,在RT thread当中通过RT_USING_SMP定义了多核和单核的场景。第二个功能,检查当前线程的时间片,首先获取当前线程,将当…

Flowable项目启动报错#java.time.LocalDateTime cannot be cast to java.lang.String

Flowable 项目启动后报错 flow项目第一次启动创建表成功,但是第二次启动时报错信息如下: 1、Error creating bean with name ‘appRepositoryServiceBean’ defined in class 2、Error creating bean with name ‘flowableAppEngine’: FactoryBean t…

React实战(一)初始化项目、配置router、redux、axios

(一)初始化项目 1.安装项目 npx create-react-app 项目名 编译报错: 解决办法:安装最新的babel-preset-react-app npm install babel-preset-react-applatest 2.配置项目 (1)配置文件目录 (2)使用craco配置webpack.config npm install craco/crac…

传统工科硕士想转嵌入式,时间够吗?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!! 零基础开始学&#xff0…

每天五分钟深度学习pytorch:pytorch中的广播机制是什么?

本文重点 在pytorch中经常有张量和张量之间的运算,那么有一点需要注意,那就是维度要匹配,如果维度不匹配就有可能出现问题。如果维度不一致,此时也可以同时进行操作,此时就需要使用pytorch中的广播机制,本节课程就讲解pytorch中的广播机制。 广播机制示意图 如上就是py…

Prism 入门06,发布订阅(入门完结)

本章节介绍使用 Prism 框架的消息聚合器 IEventAggregator ,实现如何进行消息发布,订阅,取消订阅的功能 继续使用上一章节使用的 Prism WPF 空模板项目 BlankApp1 1.首先,在使用 Prism 框架当中,进行事件消息的发布和订阅之前,需要定义发布事件的事件消息模型。如下所示:…

[图解]建模相关的基础知识-05

1 00:00:01,510 --> 00:00:03,900 练习,我们就出这一道就行了 2 00:00:04,230 --> 00:00:07,210 这些都是像数理逻辑 3 00:00:08,140 --> 00:00:10,570 包括信息专业的 4 00:00:11,350 --> 00:00:12,900 包括文科的 5 00:00:12,910 --> 00:00:14…

反激肖特基整流二级管及输出滤波电容的设计

反激肖特基整流二级管的设计 1 耐压:Vdr > Vor*1.2(1.2为裕量) 其中Vor (Vo Vf)*(Np/Ns) 2 电流计算: Id > 4Io,Id为峰值电流 肖特基上面的吸收电路的计算 直接调试更加快捷,首先确定吸收电容的容量&…

linux内存缓存占用过高分析和优化

1、什么是buffer/cache ? buffer/cache其实是作为服务器系统的文件数据缓存使用的,尤其是针对进程对文件存在read/write操作的时候,所以当你的服务进程在对文件进行读写的时候,Linux内核为了提高服务的读写速度,则将会…

【前端基础】CSS介绍|CSS选择器|常用CSS

目录 一、CSS介绍 1.1 什么是CSS 1.2 基本语法规范 1.3 引⼊⽅式 1.4 规范 💡二、CSS选择器 1. 标签选择器 2. class选择器 3. id选择器 4. 复合选择器 5. 通配符选择器 三、常用CSS 3.1 color 3.2 font-size 3.3 border 3.4 width/height 3.5 padd…

单片机原理及技术(三)—— AT89S51单片机(二)(C51编程)

一、AT89S51单片机的并行I/O端口 1.1 P0口 AT89S51的P0口是一个通用的I/O口,可以用于输入和输出。每个引脚都可以通过软件控制为输入或输出模式。 1.1.1 P0口的工作原理 P0口的工作原理是通过对P0寄存器的读写操作来控制P0口的引脚。 输出模式:当P0口…

【进程调度的基本过程】初步认识进程和线程的区别与联系:计算机是如何工作的

​ 🔥个人主页: 中草药 🔥专栏:【Java】登神长阶 史诗般的Java成神之路 🐺一.冯诺依曼体系结构 认识计算机的祖师爷 -- 冯诺依曼 冯诺依曼(John von Neumann,1903年12⽉28⽇-1957年2⽉8⽇&…

docker实战命令大全

文章目录 1 环境准备1.1 移除旧版本Docker1.2安装工具包1.3配置docker yum源 2 安装最新docker2.1 设置开机自启docker2.2配置加速器 3 实操-镜像3.1搜索镜像3.2下载镜像3.3查看镜像3.4 删除镜像 4 实操-容器4.1运行nginx容器4.2 查看容器4.3启动容器4.5关闭容器4.6查看容器日志…

软件测试--Linux快速入门

文章目录 软件测试-需要掌握的Linux指令Linux命令操作技巧Linx命令的基本组成常用命令 软件测试-需要掌握的Linux指令 Linux命令操作技巧 使用Tab键自动补全上下键进行翻找之前输入的命令命令执行后无法停止使用CtrC,结束屏幕输出 Linx命令的基本组成 命令 [-选项] [参数] …

nginx c++模块编译

不论是c还是c,nginx的第三方模块编写没什么太区别,但是提供给nginx调用的,必须是纯c的接口。 先说下为什么不能使用c编译nginx,nginx是纯c写的,而且c是兼容c的,但是用c(g)编译nginx的框架,就会出…

深度网络学习笔记(二)——Transformer架构详解(包括多头自注意力机制)

Transformer架构详解 前言Transformer的整体架构多头注意力机制(Multi-Head Attention)具体步骤1. 步骤12. 步骤23. 步骤34. 步骤4 Self-Attention应用与比较Self-Attention用于图像处理Self-Attention vs. CNNSelf-Attention vs. RNN Transformer架构详…

【嵌入式】智能系统优化:【C++】驱动的【机器学习】与【数据挖掘】技术

目录 一、嵌入式系统简介 二、C在嵌入式系统中的优势 三、机器学习在嵌入式系统中的挑战 四、C实现机器学习模型的基本步骤 五、实例分析:使用C在嵌入式系统中实现手写数字识别 1. 数据准备 2. 模型训练与压缩 3. 模型部署 六、优化与分析 1. 模型优化 模…

生成式人工智能如何运作?

一、简述 生成式人工智能是一种可用于创建内容(包括对话、故事、图像、视频和音乐)的人工智能。人工智能技术试图在图像识别、自然语言处理(NLP)和翻译等非传统计算任务中模仿人类智能。生成式人工智能是人工智能的发展方向。您可…