AI绘画第二弹——图像风格迁移

简介:

简介

所谓图像风格迁移,是指将一幅内容图 A 的内容,和一幅风格图 B 的风格融合在一起,从而生成一张具有 A 图风格和 B 图内容的图片 C 的技术。目前这个技术已经得到了比较广泛的应用,这里安利一个 app——"大画家",这个软件可以将用户的照片自动变换为具有艺术家的风格的图片。

准备

其实刚开始写这篇文章的时候我是准备详细介绍下原理的,但是后来发现公式实在是太多了,就算写了估计也没什么人看,而且这篇文章本来定位的用户就是只需要实现功能的新人。此外,有关风格迁移的原理解析的博客实在是太多了,所以这里我就把重点放在如何使用 TensorFlow 实现一个快速风格迁移的应用上,原理的解析就一带而过了。如果只想实现这个效果的可以跳到"运行"一节。

第一步我们需要提前安装好 TensorFlow,如果有 GPU 的小伙伴可以参考我的这篇文章搭建一个 GPU 环境:《AI 绘画第一弹——用 GPU 为你的训练过程加速》,如果打算直接用 CPU 运行的话,执行下面一行话就可以了

pip install numpy tensorflow scipy

原理

本篇文章是基于A Neural Algorithm of Artistic Style一文提出的方法实现的,如果嫌看英文论文太麻烦的也可以查看我对这篇文章的翻译【译】一种有关艺术风格迁移的神经网络算法

为了将风格图的风格和内容图的内容进行融合,所生成的图片,在内容上应当尽可能接近内容图,在风格上应当尽可能接近风格图,因此需要定义内容损失函数风格损失函数,经过加权后作为总的损失函数。

预训练模型

CNN 具有抽象和理解图像的能力,因此可以考虑将各个卷积层的输出作为图像的内容,这里我们采用了利用 VGG19 训练好的模型来进行迁移学习,一般认为,卷积神经网络的训练是对数据集特征的一步步抽取的过程,从简单的特征,到复杂的特征。训练好的模型学习到的是对图像特征的抽取方法,而该模型就是在 imagenet 数据集上预训练的模型,所以理论上来说,也可以直接用于抽取其他图像的特征,虽然效果可能没有在原有数据集上训练出的模型好,但是能够节省大量的训练时间,在特定情况下非常有用。

加载预训练模型

def vggnet(self):
    # 读取预训练的vgg模型
    vgg = scipy.io.loadmat(settings.VGG_MODEL_PATH)
    vgg_layers = vgg['layers'][0]
    net = {}
    # 使用预训练的模型参数构建vgg网络的卷积层和池化层
    # 全连接层不需要
    # 注意,除了input之外,这里参数都为constant,即常量
    # 和平时不同,我们并不训练vgg的参数,它们保持不变
    # 需要进行训练的是input,它即是我们最终生成的图像
    net['input'] = tf.Variable(np.zeros([1, settings.IMAGE_HEIGHT, settings.IMAGE_WIDTH, 3]), dtype=tf.float32)
    # 参数对应的层数可以参考vgg模型图
    net['conv1_1'] = self.conv_relu(net['input'], self.get_wb(vgg_layers, 0))
    net['conv1_2'] = self.conv_relu(net['conv1_1'], self.get_wb(vgg_layers, 2))
    net['pool1'] = self.pool(net['conv1_2'])
    net['conv2_1'] = self.conv_relu(net['pool1'], self.get_wb(vgg_layers, 5))
    net['conv2_2'] = self.conv_relu(net['conv2_1'], self.get_wb(vgg_layers, 7))
    net['pool2'] = self.pool(net['conv2_2'])
    net['conv3_1'] = self.conv_relu(net['pool2'], self.get_wb(vgg_layers, 10))
    net['conv3_2'] = self.conv_relu(net['conv3_1'], self.get_wb(vgg_layers, 12))
    net['conv3_3'] = self.conv_relu(net['conv3_2'], self.get_wb(vgg_layers, 14))
    net['conv3_4'] = self.conv_relu(net['conv3_3'], self.get_wb(vgg_layers, 16))
    net['pool3'] = self.pool(net['conv3_4'])
    net['conv4_1'] = self.conv_relu(net['pool3'], self.get_wb(vgg_layers, 19))
    net['conv4_2'] = self.conv_relu(net['conv4_1'], self.get_wb(vgg_layers, 21))
    net['conv4_3'] = self.conv_relu(net['conv4_2'], self.get_wb(vgg_layers, 23))
    net['conv4_4'] = self.conv_relu(net['conv4_3'], self.get_wb(vgg_layers, 25))
    net['pool4'] = self.pool(net['conv4_4'])
    net['conv5_1'] = self.conv_relu(net['pool4'], self.get_wb(vgg_layers, 28))
    net['conv5_2'] = self.conv_relu(net['conv5_1'], self.get_wb(vgg_layers, 30))
    net['conv5_3'] = self.conv_relu(net['conv5_2'], self.get_wb(vgg_layers, 32))
    net['conv5_4'] = self.conv_relu(net['conv5_3'], self.get_wb(vgg_layers, 34))
    net['pool5'] = self.pool(net['conv5_4'])
    return net

训练思路

我们使用 VGG 中的一些层的输出来表示图片的内容特征和风格特征。比如,我使用[‘conv4_2’,’conv5_2’]表示内容特征,使用[‘conv1_1’,’conv2_1’,’conv3_1’,’conv4_1’]表示风格特征。在settings.py中进行配置。

# 定义计算内容损失的vgg层名称及对应权重的列表
CONTENT_LOSS_LAYERS = [('conv4_2', 0.5),('conv5_2',0.5)]
# 定义计算风格损失的vgg层名称及对应权重的列表
STYLE_LOSS_LAYERS = [('conv1_1', 0.2), ('conv2_1', 0.2), ('conv3_1', 0.2), ('conv4_1', 0.2), ('conv5_1', 0.2)]

内容损失函数

image-20190429151634583

其中,X 是噪声图片的特征矩阵,P 是内容图片的特征矩阵。M 是 P 的长*宽,N 是信道数。最终的内容损失为,每一层的内容损失加权和,再对层数取平均。

我知道很多人一看到数学公式就会头疼,简单理解就是这个公式可以让模型在训练过程中不断的抽取图片的内容。

风格损失函数

计算风格损失。我们使用风格图像在指定层上的特征矩阵的 GRAM 矩阵来衡量其风格,风格损失可以定义为风格图像和噪音图像特征矩阵的格莱姆矩阵的差值的 L2 范数。

对于每一层的风格损失函数,我们有:

其中 M 是特征矩阵的长*宽,N 是特征矩阵的信道数。G 为噪音图像特征的 Gram 矩阵,A 为风格图片特征的 GRAM 矩阵。最终的风格损失为,每一层的风格损失加权和,再对层数取平均。

同样的,看不懂公式没关系,你就把它理解为这个公式可以在训练过程中获取图片的风格。

计算总损失函数并训练模型

最后我们只需要将内容损失函数和风格损失函数带入刚开始的公式中即可,要做的就是控制一些风格的权重和内容的权重:

# 内容损失权重
ALPHA = 1
# 风格损失权重
BETA = 500

ALPHA 越大,则最后生成的图片内容信息越大;同理,BETA 越大,则最后生成的图片风格化更严重。

当训练开始时,我们根据内容图片和噪声,生成一张噪声图片。并将噪声图片喂给网络,计算 loss,再根据 loss 调整噪声图片。将调整后的图片喂给网络,重新计算 loss,再调整,再计算…直到达到指定迭代次数,此时,噪声图片已兼具内容图片的内容和风格图片的风格,进行保存即可。

运行

如果对上述原理不感兴趣的,想直接运行代码的可以去微信公众号「01 二进制」后台回复「图像风格迁移」获得源码。接下来我们来说说如何使用这个代码跑出自己的绘画。

首先看下项目结构:

images 下有两张图片,分别是内容图和风格图,output 下是训练过程中产生的文件,.mat 文件就是预训练模型,models.py 是我们实现的用于读取预训练模型的文件,settings.py 是配置文件,train.py 是最终的训练文件。

想要运行该项目,我们只需要执行python train.py即可,想更改风格和内容的的话只要在 images 文件中更换原先的图片即可。当然你也可以在settings.py中修改路径:

# 内容图片路径
CONTENT_IMAGE = 'images/content.jpg'
# 风格图片路径
STYLE_IMAGE = 'images/style.jpg'
# 输出图片路径
OUTPUT_IMAGE = 'output/output'
# 预训练的vgg模型路径
VGG_MODEL_PATH = 'imagenet-vgg-verydeep-19.mat'

我们来看看训练后的图片:

最后

虽然通过上述代码我们可以实现图像的风格迁移,但是他有一个最大的缺点,就是无法保存训练好的模型,每次转换风格都要重新跑一遍,如果使用 CPU 跑 1000 轮的话大约是在 30 分钟左右,因此推荐大家使用 GPU 进行训练。

但是即使使用上了 GPU,训练时间也无法满足商业使用的,那有没有什么办法可以保存训练好的风格模型,然后直接快速生成目标图片呢?当然是有的,斯坦福的李飞飞发表过一篇《Perceptual Losses for Real-Time Style Transfer and Super-Resolution》,通过使用 perceptual loss 来替代 per-pixels loss 使用 pre-trained 的 vgg model 来简化原先的 loss 计算,增加一个 transform Network,直接生成 Content image 的 style。这里就不再多说了,感兴趣的可以参考我下面给出的两个链接:

  1. 《深度有趣 | 30 快速图像风格迁移》
  2. 《风格迁移背后原理及 tensorflow 实现》

以上就是本篇文章的全部内容,个人做下来感觉还是挺有意思的,因个人能力有限,文中如有纰漏错误之处,还请各位大佬指正,万分感谢!

参考

  1. A Neural Algorithm of Artistic Style
  2. 深度学习实战(一)快速理解实现风格迁移
  3. 深度有趣 | 04 图像风格迁移
  4. 学习笔记:图像风格迁移
相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
30天前
|
机器学习/深度学习 人工智能 并行计算
"震撼!CLIP模型:OpenAI的跨模态奇迹,让图像与文字共舞,解锁AI理解新纪元!"
【10月更文挑战第14天】CLIP是由OpenAI在2021年推出的一种图像和文本联合表示学习模型,通过对比学习方法预训练,能有效理解图像与文本的关系。该模型由图像编码器和文本编码器组成,分别处理图像和文本数据,通过共享向量空间实现信息融合。CLIP利用大规模图像-文本对数据集进行训练,能够实现zero-shot图像分类、文本-图像检索等多种任务,展现出强大的跨模态理解能力。
81 2
|
1月前
|
人工智能 开发者
MidJourney 替代品:为什么 FLUX.1 是终极 AI 图像生成工具
MidJourney 是目前流行的 AI 驱动图像生成工具,以其艺术风格和易用性闻名。然而,随着技术进步,其他模型如 FLUX.1、DALL·E 3 和 Stable Diffusion 3 也崭露头角,提供了更多定制选项和高质量输出。其中,FLUX.1 以其开源性质、卓越图像质量和开发者友好性脱颖而出,成为 MidJourney 的有力替代品。选择合适的工具应基于具体需求,FLUX.1 在灵活性和高性能方面表现优异。
|
1月前
|
人工智能 Serverless
AI助理精准匹配------助力快速搭建Stable Difussion图像生成应用
【10月更文挑战第7天】过去在阿里云社区搭建Stable Diffusion图像生成应用需查阅在线实验室或官方文档,耗时且不便。现阿里云AI助理提供精准匹配服务,直接在首页询问AI助理即可获取详细部署步骤,简化了操作流程,提高了效率。用户可按AI助理提供的步骤快速完成应用创建、参数设置、应用部署及资源释放等操作,轻松体验Stable Diffusion图像生成功能。
|
17天前
|
人工智能 小程序
【一步步开发AI运动小程序】五、帧图像人体识别
随着AI技术的发展,阿里体育等公司推出的AI运动APP,如“乐动力”和“天天跳绳”,使云上运动会、线上健身等概念广受欢迎。本文将引导您从零开始开发一个AI运动小程序,使用“云智AI运动识别小程序插件”。文章分为四部分:初始化人体识别功能、调用人体识别功能、人体识别结果处理以及识别结果旋转矫正。下篇将继续介绍人体骨骼图绘制。
|
1月前
|
人工智能 Serverless
AI助理精准匹配,为您推荐方案——如何添加一个Stable Difussion图像生成应用
介绍了一种利用AI助手快速获取并搭建Stable Diffusion图像生成应用的方法。用户只需在阿里云官网向AI助手提出需求,即可获得详细的实施方案。随后,按照AI助手提供的方案,通过函数计算部署应用,并进行测试。此过程显著提升了开发效率。
797 2
AI助理精准匹配,为您推荐方案——如何添加一个Stable Difussion图像生成应用
|
30天前
|
人工智能
添加一个Stable Difussion图像生成应用,通过向AI助手简单的提问,即可快速搭建Stable Diffusion应用至自己的网站中,大幅提升开发效率。
添加一个Stable Difussion图像生成应用,通过向AI助手简单的提问,即可快速搭建Stable Diffusion应用至自己的网站中,大幅提升开发效率。
|
2月前
|
人工智能 计算机视觉 Python
AI计算机视觉笔记八:基于mediapipe的虚拟绘画
该项目利用MediaPipe手部关键点识别技术,实现了隔空绘画功能。用户可以通过手势控制绘画工具,选择颜色或橡皮擦。环境配置基于`mediapipe_env`,在PyCharm中运行。项目包括两个文件:`AiVirtualPainter.py`负责绘画逻辑,`HandTrackingModule.py`用于手部关键点检测。此项目展示了AI技术在互动应用中的潜力,适合初学者实践与学习。
66 10
|
3月前
|
人工智能 Anolis
|
3月前
|
机器学习/深度学习 人工智能 PyTorch
面向AI Native应用的高效迁移学习策略
【8月更文第1天】随着人工智能技术的发展,越来越多的应用场景需要定制化的AI解决方案。然而,从零开始训练一个深度学习模型往往需要大量的标注数据和计算资源。迁移学习提供了一种有效的方法来解决这个问题,它利用预训练模型的知识,通过少量的数据就能达到很好的性能。本文将深入探讨面向AI Native应用的高效迁移学习策略,并通过实例展示如何针对具体场景进行模型微调。
251 6
面向AI Native应用的高效迁移学习策略
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
利用迁移学习加速AI模型训练
【7月更文第29天】迁移学习是一种强大的技术,允许我们利用已经训练好的模型在新的相关任务上进行快速学习。这种方法不仅可以显著减少训练时间和计算资源的需求,还能提高模型的准确率。本文将详细介绍如何利用迁移学习来加速AI模型的训练,并通过具体的案例研究来展示其在计算机视觉和自然语言处理领域的应用。
120 4

热门文章

最新文章