基于Python+tensorflow深度学习VGG-19图像风格迁移+自动去噪(MNIST数据集)机器学习+人工智能+神经网络——含全部Python工程源码

news2024/12/23 8:54:19

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
    • TensorFlow 环境
  • 模块实现
    • 1. 图片处理
    • 2. 模型构造
  • 系统测试
  • 工程源代码下载
  • 其它资料下载

在这里插入图片描述

前言

本项目基于 MNIST 数据集,使用 VGG-19 网络模型,将图像进行风格迁移,实现去噪功能。

VGG-19是一种深度卷积神经网络模型,具有较强的图像特征提取能力。在本项目中,我们利用VGG-19模型的卷积层,提取输入图像的特征表示。

图像风格迁移是一种通过将图像的内容与另一个图像的风格相结合,生成新图像的技术。通过将待处理的图像输入VGG-19模型,我们可以获得图像的内容特征和风格特征。然后,利用风格迁移算法,将图像的内容特征与一个风格图像的风格特征进行融合。这样,我们可以生成一张具有原始图像内容但具有去除噪声的新图像。

这项技术可以应用于图像处理领域,提高图像质量,去除噪声干扰,从而改善图像的视觉效果和可用性。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 和 TensorFlow 运行环境。

Python 环境

需要 Python 3.6 及以上配置,在 Windows 环境下推荐下载 Anaconda 完成 Python 所需的配置,下载地址:https://www.anaconda.com/。也可以下载虚拟机在 Linux 环境下运行代码。

TensorFlow 环境

打开 Anaconda Prompt,输入清华仓库镜像。

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config –set show_channel_urls yes

创建 Python 3.5 环境,名称为 TensorFlow:

conda create -n tensorflow python=3.5

有需要确认的地方,都输入 y。

在 Anaconda Prompt 中激活 TensorFlow 环境:

activate tensorflow

安装 CPU 版本的 TensorFlow:

pip install –upgrade --ignore-installed tensorflow

模块实现

本项目包括3 个模块:图片处理、模型构造、迭代更新,下面分别给出各模块的功能介绍及相关代码。

1. 图片处理

图片风格迁移会涉及到图片处理,主要为图片的大小裁剪、导入和保存。由于图片尺寸参差不齐,在风格迁移之前,将图片大小调为一致以降低难度。图像风格迁移过程中会迭代更新很多张图片,这些图片放一起做成动图。

def get_resized_image(img_path, width, height, save=True):
    #改变图片大小
    image = Image.open(img_path)
    image = ImageOps.fit(image, (width, height), Image.ANTIALIAS)
    if save:
        image_dirs = img_path.split('/')
        image_dirs[-1] = 'resized_' + image_dirs[-1]
        out_path = '/'.join(image_dirs)
        if not os.path.exists(out_path):
            image.save(out_path)
    image = np.asarray(image, np.float32)
    return np.expand_dims(image, 0)
def generate_noise_image(content_image, width, height, noise_ratio=0.6):
    #给图片加噪声
    noise_image = np.random.uniform(-20, 20, (1, height, width, 3)).astype(np.float32)
    return noise_image * noise_ratio + content_image * (1 - noise_ratio)
def save_image(path, image):
    #保存图片
    image = image[0]
    image = np.clip(image, 0, 255).astype('uint8')
    scipy.misc.imsave(path, image)
def safe_mkdir(path):
    #生成路径
    try:
        os.mkdir(path)
    except OSError:
        pass
def create_gif(root_dir, duration=0.3):
    #创建GIF动图
    img_list = os.listdir(root_dir)
    img_list.sort(key=lambda x: int(x[6:-4]))
    frames = list()
    gif_name = GIF_PATH + '/' + root_dir.split('/')[-1] + '.gif'
    for i in img_list:
        i = root_dir + '/' + i
        frames.append(imageio.imread(i))
    imageio.mimsave(gif_name, frames, 'GIF', duration=duration)
    return gif_name

2. 模型构造

本部分包括定义模型结构和优化损失函数。

1)定义模型结构

项目用到的网络模型为预训练好的 VGG-19,使用过程中抛弃最后三个全连接层,取出前面各层的参数,构建网络结构。

def download(download_link, file_name, expected_bytes):
    #下载VGG-19
    print(file_name)
    if os.path.exists(file_name):
        print("VGG-19 pre-trained model is ready")
        return
    print("Downloading the VGG pre-trained model. This might take a while ...")
    file_name, _ = urllib.request.urlretrieve(download_link, file_name)
    file_stat = os.stat(file_name)
    if file_stat.st_size == expected_bytes:
      print('Successfully downloaded VGG-19 pre-trained model', file_name)
    else:
        raise Exception('File ' + file_name +
       ' might be corrupted.You should try downloading it with a browser.')
class VGG(object):
    def __init__(self, input_img):
        #下载文件
        utils.download(VGG_DOWNLOAD_LINK, VGG_FILENAME, EXPECTED_BYTES)
        #加载文件
        self.vgg_layers = scipy.io.loadmat(VGG_FILENAME)["layers"]
        self.input_img = input_img
      #VGG在处理图像时将图片进行mean-center,所以要计算RGB三个通道上的mean值
      #为训练集每个通道求和的均值,统一减去,使得均值为0,模型收敛更快
   		self.mean_pixels=np.array([123.68,116.779,103.939]).reshape((1,1,1, 3))
    def _weights(self, layer_idx, expected_layer_name):
        #参数特定存储位置
        W = self.vgg_layers[0][layer_idx][0][0][2][0][0]
        b = self.vgg_layers[0][layer_idx][0][0][2][0][1]
        #当前层的名称
        layer_name = self.vgg_layers[0][layer_idx][0][0][0][0]
        assert layer_name==expected_layer_name, print("Layer name error!")
        return W, b.reshape(b.size)
    def conv2d_relu(self, prev_layer, layer_idx, layer_name):
        with tf.variable_scope(layer_name):
            #获取当前权重(numpy格式)
            W, b = self._weights(layer_idx, layer_name)
            #将权重转化为tensor(由于不需要重新训练VGG的权重,初始化为常数)
            W = tf.constant(W, name="weights")
            b = tf.constant(b, name="bias")
            #卷积操作
            conv2d = tf.nn.conv2d(input=prev_layer,
                                  filter=W,
                                  strides=[1, 1, 1, 1],
                                  padding="SAME")
            #激活
            out = tf.nn.relu(conv2d + b)
        setattr(self, layer_name, out)
    def avgpool(self, prev_layer, layer_name):
        with tf.variable_scope(layer_name):
            out = tf.nn.avg_pool(value=prev_layer,
                                 ksize=[1, 2, 2, 1],
                                 strides=[1, 2, 2, 1],
                                 padding="SAME")
        setattr(self, layer_name, out)
    def load(self):
        self.conv2d_relu(self.input_img, 0, "conv1_1")
        self.conv2d_relu(self.conv1_1, 2, "conv1_2")
        self.avgpool(self.conv1_2, "avgpool1")
        self.conv2d_relu(self.avgpool1, 5, "conv2_1")
        self.conv2d_relu(self.conv2_1, 7, "conv2_2")
        self.avgpool(self.conv2_2, "avgpool2")
        self.conv2d_relu(self.avgpool2, 10, "conv3_1")
        self.conv2d_relu(self.conv3_1, 12, "conv3_2")
        self.conv2d_relu(self.conv3_2, 14, "conv3_3")
        self.conv2d_relu(self.conv3_3, 16, "conv3_4")
        self.avgpool(self.conv3_4, "avgpool3")
        self.conv2d_relu(self.avgpool3, 19, "conv4_1")
        self.conv2d_relu(self.conv4_1, 21, "conv4_2")
        self.conv2d_relu(self.conv4_2, 23, "conv4_3")
        self.conv2d_relu(self.conv4_3, 25, "conv4_4")
        self.avgpool(self.conv4_4, "avgpool4")
        self.conv2d_relu(self.avgpool4, 28, "conv5_1")
        self.conv2d_relu(self.conv5_1, 30, "conv5_2")
        self.conv2d_relu(self.conv5_2, 32, "conv5_3")
        self.conv2d_relu(self.conv5_3, 34, "conv5_4")
        self.avgpool(self.conv5_4, "avgpool5")

2)优化损失函数

搭建好网络模型,需要定义损失函数,由内容损失、风格损失构成。内容损失采用 L2范数损失,风格损失用 Gram 矩阵计算各通道的相关性,以便更好的捕捉笔触、纹理等细节信息,利用 adam 梯度下降算法进行优化。

     def create_input(self):
       #初始化图片tensor
       with tf.variable_scope("input"):
           self.input_img = tf.get_variable("in_img", 
                              shape=([1, self.img_height, self.img_width, 3]),
                                            dtype=tf.float32,
                                            initializer=tf.zeros_initializer())
    def load_vgg(self):
        #加载VGG模型并对图片进行预处理
        self.vgg = load_vgg.VGG(self.input_img)
        self.vgg.load()
        #mean-center
        self.content_img -= self.vgg.mean_pixels
        self.style_img -= self.vgg.mean_pixels
    def _content_loss(self, P, F):
        #计算内容损失
        self.content_loss = tf.reduce_sum(tf.square(F - P))/(4.0 * P.size)
        def _gram_matrix(self, F, N, M):
        F = tf.reshape(F, (M, N))
        return tf.matmul(tf.transpose(F), F)
    def _single_style_loss(self, a, g):
        N = a.shape[3]
        M = a.shape[1] * a.shape[2]
        #生成特征图的gram_matrix
        A = self._gram_matrix(a, N, M)
        G = self._gram_matrix(g, N, M)
        return tf.reduce_sum(tf.square(G - A)) / ((2 * N * M) ** 2)
    def _style_loss(self, A):
        #层数(用conv1_1, conv2_1, conv3_1, conv4_1, conv5_1)
        n_layers = len(A)
        #计算损失
    E=[self.single_style_loss(A[i],getattr(self.vgg,self.style_layers[i]))
             for i in range(n_layers)]
        #加权求和
        self.style_loss = sum(self.style_layer_w[i] * E[i] for i in range(n_layers))
    def losses(self):
        #模型总体损失
        with tf.variable_scope("losses"):
            #内容损失
            with tf.Session() as sess:
                sess.run(self.input_img.assign(self.content_img))
                gen_img_content = getattr(self.vgg, self.content_layer)
                content_img_content = sess.run(gen_img_content)
            self._content_loss(content_img_content, gen_img_content)
            #风格损失
            with tf.Session() as sess:
                sess.run(self.input_img.assign(self.style_img))
                style_layers = sess.run([getattr(self.vgg, layer) for layer in self.style_layers])                              
            self._style_loss(style_layers)
            #加权求得最终的损失
            self.total_loss = self.content_w * self.content_loss + self.style_w * self.style_loss
    def optimize(self):
        self.optimizer = tf.train.AdamOptimizer(self.lr).minimize(self.total_loss, global_step=self.gstep)

3)迭代更新

训练过程中,每 10 个 epoch 生成一张图片。当 epoch > 20 时,每 20 个 epoch 生成一张图片,以免生成过多。

    def train(self, epoches=20):
        skip_step = 1
        with tf.Session() as sess:
            sess.run(tf.global_variables_initializer())
            sess.run(self.input_img.assign(self.initial_img))
            initial_step = self.gstep.eval()
            for epoch in range(initial_step, epoches):
                #前面几轮每隔10个epoch生成一张图片
                if 5 <= epoch < 20:
                    skip_step = 10
                #后面每隔20个epoch生成一张图片
                elif epoch >= 20:
                    skip_step = 20
                sess.run(self.optimizer)
                if epoch == epoches - 1 or (epoch + 1) % skip_step == 0:
                    gen_image, total_loss = sess.run([self.input_img, self.total_loss])
                    #对生成的图片逆向mean-center,即在每个通道加上mean
                    gen_image = gen_image + self.vgg.mean_pixels
                    print("Step {}\n   Sum: {:5.1f}".format(epoch + 1, np.sum(gen_image)))
                    print("   Loss: {:5.1f}".format(total_loss))
                    filename = OUTPUT_PATH + "/%s_%s/epoch_%d.png" % (self.content_name, self.style_name, epoch + 1)
                    utils.save_image(filename, gen_image)
                    self.mix_img = filename.replace(sys.path[0], '')
                    self.prog = (epoch + 1) / epoches * 100   

系统测试

对于分类问题,数据都有很明确的标签,可以用准确率、召回率来评判模型优劣程度。但对于图像风格迁移这种模糊算法,并没有客观的评判标准。损失函数可以反映出一部分情况,更多的是人为观察运行结果。内容如图 1 所示,风格如图 2 所示。

在这里插入图片描述

图1 内容图

在这里插入图片描述

图2 风格图

进行 100 次迭代更新,第一次迭代的损失值如下图所示。

在这里插入图片描述

经过 40 次迭代,损失值和效果如图 3 和图 4 所示。

在这里插入图片描述

图 3 损失图(40 次迭代)

在这里插入图片描述

图 4 合成图(40 次迭代)

40 次和 100 次迭代的效果并未明显增强,且 40 次迭代风格迁移已很明显,可根据自身需求,合理调节迭代次数。100 次迭代的损失和效果如图 5 和图 6 所示。

在这里插入图片描述

图 5 损失图(100 次迭代)

在这里插入图片描述

图 6 合成图(100 次迭代)

工程源代码下载

详见本人博客资源下载页

其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字信号处理课程设计——调制与解调

文字目录 数字信号处理课程设计 摘要&#xff1a; 1绪论 1.1通信信号的调制与解调 1.2设计题目 2卷积定理和希尔伯特公式理论推导 2.1卷积定理 ​2.2希尔伯特公式 3信号DSB调制与希尔伯特解调 3.1过程框图 3.2相关理论推导 3.2.1卷积定理在调制中的应用 3.2.2希尔…

某马 qiankun 公开课 学习记录

端午早晨阳光正好&#xff0c;起来学习一小下 客观评价一哈&#xff1a;此视频适合不了解 qiankun 的朋友入门观看&#xff0c;更详细的使用方法还是推荐 qiankun 官网哦&#xff0c;老师讲的生动活泼&#xff0c;值得萌新一听 某马 qiankun 公开课 - bilibili ovo很多公司的…

高通Camera Log Debug 知识点

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、Camx UMD Log Debug二、Camx KMD log Debug三、常用缩写解释四、参考文献 一、Camx UMD Log Debug 1.1 两种方式设置camx UMD Log /vendor/etc/cam…

GPT-3.5眼中的编程语言之最:Python的卓越之处

当谈论编程语言的选择时&#xff0c;每个开发者都有自己的偏好和理由。作为GPT-3.5&#xff0c;以我的分析和学习能力&#xff0c;我也有自己心目中的编程语言之最。在众多编程语言中&#xff0c;Python在我的眼中独树一帜&#xff0c;是最令人着迷和受欢迎的编程语言之一。 首…

面试经典150题(1)

文章目录 前言除自身以外数组的乘积要求思路代码 跳跃游戏|要求题解代码 跳跃游戏||要求题解代码 前言 今天开始我将陆续为大家更新面试经典150题中较难理解的题目。今天我为大家分享的是&#xff0c;除自身以外数组的乘积、跳跃游戏| 和 跳跃游戏||。 除自身以外数组的乘积 …

【unity之UiI专题】GUI(IMGUI)详解

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

AI 绘画工具 Stable Diffusion 本地安装使用

最近要用到 AI 绘画&#xff0c;所以研究了下目前市面上的 AI 绘画工具&#xff0c;真可谓是琳琅满目&#xff0c;但主流的还是 Stable diffusion 和 Midjourney 两大阵营。 Midjourney 不多说&#xff0c;开箱即用&#xff0c;对新手非常友好&#xff0c;但不免费&#xff0c…

Linux基础(二)—— 怎么在VMware/WSL中安装Ubuntu系统

文章目录 01 | VMware安装Ubuntu02 | WSL2安装Ubuntu 虚拟机安装Linux的方式分为两种&#xff1a;APP安装、WSL安装 APP安装就是常见的VMware VirtualBox安装的方式&#xff0c;而WSL是Windows系统自带的一个虚拟机应用&#xff0c;可以更好的与Windows进行信息交互&#xff08…

判断是否为美丽数组

判断是否为美丽数组c思路和实现 这段代码的功能是对于给定的多个序列&#xff0c;判断每个序列是否是一个 beautiful 序列。没次读取当前的序列判断之后再加入下一个数字进序列。 首先&#xff0c;输入一个整数 t&#xff0c;表示测试数据组数。 对于每组测试数据&#xff0c;…

【初识C语言】字符串+转义字符+注释

文章目录 1. 字符串2. 转义字符转义字符表常见转义字符 3. 注释 1. 字符串 “hello world.\n” 上面这种由双引号引起的一串字符就被称为字符串&#xff1b; 字符串的存储 C 语言当中没有字符串类型&#xff0c;如果想要将字符串存储起来的话就需要用到字符串数组。 #include…

Excel VBA 编程入门

Visual Basic for Applications&#xff08;VBA&#xff09;是一种用于 Microsoft Office 套件中的编程语言&#xff0c;它可以帮助您自动化重复性任务、定制应用程序以及增强工作效率。本文将向您介绍 Excel VBA 编程的基础知识&#xff0c;并通过示例帮助您入门。 1、启用“开…

融云WICC2023:成为「卷王」的路上,如何更好借力 AIGC

近期&#xff0c;“融云 WICC2023 泛娱乐出海嘉年华”在广州成功举办&#xff0c;行业多方力量与数百位开发者汇聚一堂&#xff0c;共同探讨出海人布局全球的突围之道。关注【融云全球互联网通信云】了解更多 在嘉年华的圆桌会议环节&#xff0c;白鲸出海创始人&#xff06;CE…

Axure教程—计数器

本文将教大家如何用AXURE制作计数器&#xff08;商品购件数的交互设计&#xff09; 一、效果 预览地址&#xff1a;https://uf9ie1.axshare.com 二、功能 1、用户点击“”号时数值加1 2、用户点击“-”号时数值减1 三、制作 数值 拖入一个矩形组件&#xff0c;其大小设置为164…

个人一年工作情况总结报告

个人一年工作情况总结报告篇1 转眼间又到了年终岁尾&#xff0c;这一年就要在很充实忙碌的工作中过去了。在这一年里&#xff0c;我收获了很多也积累了不少的工作经验。同时在两位领导和各位主管的帮助与支持下&#xff0c;我很好的完成了本职工作。作为一名办公室文员&#xf…

云计算成本大揭秘:硬件、研发、电力等各项成本都在这里!

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 云计算作为一种技术和商业模式&#xff0c;已经深深地影响了全球的IT行业和各种商业运营。云服务商的主要模式以订阅为基础&#xff0c;一旦应用程序和工作负载移动到云上&#xff0c;它们通常会停留在那里&#xff0c;订阅…

js blob 文件上传

js blob 文件上传 js中的文件处理和文件上传掌握得更扎实&#xff0c;有更深入的理解&#xff0c;底层原理 ps.项目中使用插件上传 filereadermime类型筛选单文件的2种处理方案多文件&文件上传进度管控 Ajax文件上传时&#xff1a;Formdata、File、Blob的关系-腾讯云开发者…

基于Java端游账号销售管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

C语言 --- 文件操作(万字详解)

文章目录 前言&#x1f31f;一、为什么使用文件&#x1f31f;二、什么是文件&#x1f30f;2.1程序文件&#xff1a;&#x1f30f;2.2数据文件&#xff1a;&#x1f30f;2.3文件名&#xff1a; &#x1f31f;三、文件的打开和关闭&#x1f30f;3.1文件指针&#xff1a;&#x1f…

TDEngine 调优 - 高速查询及插入

TDEngine 调优 - 高速查询及插入 一、基本参数二、TDEngine大数据核心2.1 vnode分片2.1.1 表分布不均匀2.1.2 vnode分布不均匀2.2 时间段分区 三、数据库性能优化3.1 数据文件3.1.1 maxrows 和 minrows3.1.2 数据的保留策略duration\days 3.2 磁盘IO - vgroups3.3 性能优化实战…

「网络编程」第二讲:网络编程socket套接字(一)

「前言」文章是关于网络编程的socket套接字方面的&#xff0c;下面开始讲解&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 春风得意马蹄疾&#xff0c;一日看尽长安花。 ——孟郊《登科后》 目录 一…