【毕业论文】| 基于生成对抗网络的图像风格动漫化迁移
📢写在前面
【简要介绍】新人第一篇分享!!本人是2024届(今年)毕业的江苏某中下211本科计算机科学与技术专业的一名女生,今年2024年9月打算前往香港城市大学留学,攻读数据科学硕士学位。
【分享目的】在今年的毕业论文环节,自己的毕业论文最终获得了校优秀论文,并且这篇论文也是自己很用心选题,完全自己独立完成。借此机会,想同csdn的大家一同分享下我的论文同时也相当于是对我毕业论文的一次复盘总结。
如果你也对图像风格动漫迁移,深度学习,生成对抗网络,制作一款图像/视频动漫化迁移系统感兴趣,那么就继续看下去吧~
摘 要
本文首先调研了近些年最为流行的基于生成对抗网络的图像风格迁移模型,选择了目前最合适的AnimeGANv2模型作为基线模型,在多种风格、内容数据集下进行了重新训练,深度研究了其网络架构。但生成的图像仍不是很理想,图像颜色损失较严重。因此,本文在AnimeGANv2模型的基线网络上进行了改良,在生成器网络中引入了CBAM注意力机制,同时在判别器网络里引入了自注意力机制。另外,本文还在生成器的总损失函数中加入了循环一致性损失函数以及新增了两种动漫风格数据集。在重新训练数据集后,得到了比原模型更好的风格迁移效果,图像的颜色效果得到了改善,图像的核心部分也得到重点关注。为了更好的可视化展示,本文还设计了一款图像动漫化迁移系统,界面基于PyQt5框架设计,界面美观,方便了用户操作,还另外加入了视频动漫化风格迁移功能。
关键词:图像风格迁移;生成对抗网络;AnimeGANv2;注意力机制;PyQt5
基线模型:基于 AnimeGANv2 图像动漫化风格迁移模型
【主要参考】:AnimeGANv2
AnimeGAN是由武汉大学和湖北工业大学的研究团队一起研究的图像风格迁移模型,旨在将现实生活中的图像转换为动漫风格的艺术作品,结合了神经风格转换和生成对抗网络(GAN)来完成该项任务。该网络新提出了几种,使生成的动漫化图像拥有更好的质量,分别是灰度风格损失函数、对抗损失函数和颜色重建损失函数,AnimeGAN训练过程中的网络相比于其他的生成对抗网络拥有更低的内存占用情况。而在训练数据集的选取方面,与其他的生成对抗网络不同,这里采用的是没有映射关系的未配对数据集。最终实验分析显示,AnimeGAN通过其特殊的网络设置,能够很好地从图像中捕获其深层特征,而深层特征中捕获的图像中隐藏的难以探寻的复杂信息帮助该网络最后在测试集上生成的图像取得了很好的风格外在特征和保存了原始的内在内容特征。
尽管AnimeGAN已经取得了很好的效果,但对比其生成的图像效果,从色彩和原图的还原度方面来看,效果还远远不够,进而在此模型基础上又改进并提出了一种新型网络,AnimeGANv2。AnimeGANv2在网络上做出了相关改进,在判别器网络中的归一化层由层归一化转换为了实例归一化。此外,还进一步缩小了生成器网络的参数规模,以实现更高效的动画风格转换。AnimeGANv2同大部分的生成对抗网络结构相似,主要由两个网络组成,即生成器网络G和判别器网络D,生成器网络接受真实图像输入经由网络提取其主要内在特征生成一张虚拟的生成图像,判别器网络接受动漫图像和灰度动漫图像作为输入,不断与生成图像进行分析比较更换相应损失函数的数值。具体的网络处理流程见下图。
网络架构
AnimeGANv2主要由三个卷积神经网络组成,这三个主要部分包括VGG19特征提取网络、生成器网络、判别器网络。VGG19特征提取网络主要用途是作为感知网络提取输入图像的主要高级语义特征。生成器网络主要用途是根据真实的场景、人像图片生成一个图片。判别器网络主要用途是判别生成器生成的图片是否与目标动漫场景、人像图相一致。
1 生成器网络
该生成器网络类似于一个图像翻译任务中的U-Net架构,该架构主要的流程类似一个编码和解码系统,首先对输入图像进行特征提取类似一个编码器,将图像看作一个个编码,按照一定顺序对提取的特征进行编排,随后将提取的特征映射到原始图像空间,类似一个解码器,对编码好的特征重新还原,总体类似构成一个编码-解码系统,能够实现端到端的图像生成。总体生成器网络主要由Conv2D二维卷积层、自定义卷积层、深度可分离卷积层、上采样模块、倒残差块、下采样模块、反卷积层等模块构成。
def __init__(self, inputs):
with tf.variable_scope('G_MODEL'):
with tf.variable_scope('A'):
inputs = Conv2DNormLReLU(inputs, 32, 7)
inputs = Conv2DNormLReLU(inputs, 64, strides=2)
inputs = Conv2DNormLReLU(inputs, 64)
with tf.variable_scope('B'):
inputs = Conv2DNormLReLU(inputs, 128, strides=2)
inputs = Conv2DNormLReLU(inputs, 128)
with tf.variable_scope('C'):
inputs = Conv2DNormLReLU(inputs, 128)
inputs = self.InvertedRes_block(inputs, 2, 256, 1, 'r1')
inputs = self.InvertedRes_block(inputs, 2, 256, 1, 'r2')
inputs = self.InvertedRes_block(inputs, 2, 256, 1, 'r3')
inputs = self.InvertedRes_block(inputs