机器学习之光:神经风格迁移的直观指南!
探索神经风格传输网络的设计选择和技术的直观指南
介绍
神经风格迁移(NST)是一个非常巧妙的想法。 NST的核心理念是:
在CNN中,可以将在计算机视觉任务(例如图像识别任务)中学习到的样式表示和内容表示分离开来。
遵循这一概念,NST采用预训练卷积神经网络(CNN)将样式从给定图像传递到另一个图像。这是通过定义损失函数来完成的,该函数试图最小化内容图像、样式图像和生成的图像之间的差异,这将在后面详细讨论。在本教程结束时,您将能够创建非常酷的艺术作品,如下所示。
本文的目标
本文的目的是提供一个原则性的指南,而不是对算法进行简单的介绍,或者用冗长乏味的代码扼杀读者。特别是到本文结束时,我希望读者能够理解NST背后的概念,并了解为什么某些事情就是这样(例如损失函数)。作为额外的好处,读者可以浏览端到端的代码并查看到实际操作。
代码
请注意,我将仅分享文章中最重要的代码段。该算法是使用TensorFlow实现的。
为何选择NST?
深度神经网络已经超越了物体识别和检测等任务中的人类水平表现。然而,深度网络在产生具有高感知质量的艺术品之类的任务方面还远远落后。使用机器学习技术创造更高质量的艺术品对于达到类似人类的能力是必要的,同时也开辟了一系列新的可能性。随着计算机硬件的进步以及深度学习的激增,深度学习正在被用于创作艺术。例如,人工智能生成的艺术品不会在拍卖中以高达432,500美元的价格出售。
高水平的架构
如前所述,神经样式迁移使用预训练卷积神经网络。然后,为了定义一个无缝融合两个图像以创建视觉上吸引人的艺术的损失函数,NST定义了以下输入:
- 内容图像(c) - 我们要将样式传递到的图像
- 样式图像 - 我们想要传输样式的图像
- 输入(生成)图像(g) - 包含最终结果的图像(唯一可训练的变量)
模型的体系结构以及如何计算损失如下所示。您不需要深入了解下图中的内容,因为您将在接下来的几个部分中详细了解每个组件。其思想是对在样式转换过程中发生的工作流进行高层次的理解。
NST模型的高级架构
下载并加载预先训练的VGG-16
您将从此网页借用VGG-16权重。您需要下载vgg16_weights.npz文件并将其放在项目主目录中名为vgg的文件夹中您只需要卷积和池化层。具体来说,您将加载要用作NST网络的前7个卷积层。您可以使用笔记本中给出的load_weights(...)函数执行此操作。
注意:欢迎您尝试更多图层。但要注意CPU和GPU的内存限制。
定义构建样式传输网络的功能
在这里,您可以定义几个函数,以帮助您稍后在给定输入的情况下完全定义CNN的计算图。
创建TensorFlow变量
在这里,您将加载的numpy数组加载到TensorFlow变量中。我们将创建以下变量:
- 内容图片(tf.placeholder)
- 风格图像(tf.placeholder)
- 生成的图像(tf.Variable和trainable = True)
- 预训练的权重和偏差(tf.Variable and trainable = False)
确保生成的图像可训练,同时保持预训练的权重和偏差不变。下面我们展示两个函数来定义输入和神经网络权重。
计算VGG净输出
在这里,您通过卷积和池化操作计算VGG净输出。请注意,您正在使用tf.nn.avg_pool操作替换tf.nn.max_pool,因为tf.nn.avg_pool在样式传输期间提供了更好的视觉效果[1]。您可以通过更改下面函数中的操作来试验tf.nn.max_pool。
损失函数
在本节中,我们定义了两个损失函数;内容丢失功能和样式丢失功能。内容丢失功能确保内容图像和生成的图像之间的较高层的激活是相似的。样式丢失功能确保样式图像和生成的图像之间所有层中的激活的相关性相似。我们将在下面讨论详细信息。
内容成本函数
内容成本函数确保在生成的图像中捕获内容图像中存在的内容。已经发现CNN捕获关于较高级别内容的信息,其中较低级别更关注于各个像素值[1]。因此,我们使用最顶层的CNN层来定义内容丢失功能。
设A ^ l_ {ij}(I)激活第l层,第i个特征图和使用图像I获得的第j个位置。然后将内容丢失定义为损失,
内容损失
基本上L_ {content}捕获由生成的图像和内容图像产生的激活之间的均方根误差。但是,为什么最小化较高层激活之间的差异可以确保保留内容图像的内容?
内容损失背后的直觉
如果您可视化神经网络学到的内容,则有证据表明在不同对象存在的情况下,更高层中的不同要素图被激活。因此,如果两个图像都具有相同的内容,则它们应该在较高层中具有类似的激活。
我们可以这样定义内容成本。
风格损失函数
定义样式损失函数需要更多工作。为了从VGG网络中提取样式信息,我们使用CNN的所有层。此外,样式信息被测量为给定层中的特征图之间存在的相关量。接下来,将损失定义为由生成的图像计算的特征图与样式图像之间存在的相关性的差异。在数学上,风格损失定义为,
w ^ l(在本教程中选择的均匀)是在损失计算期间给予每个层的权重,并且M ^ l是取决于第l层的大小的超参数。但是在此实现中,您没有使用M ^ l,因为在定义最终损失时,它将被另一个参数定义最终的损失。
风格损失背后的直觉
虽然上面的方程组比较复杂,但这个想法相对简单。目标是为生成的图像和样式图像计算样式矩阵(下面可视化)。然后将样式损失定义为两个样式矩阵之间的均方根差。
下面您可以看到如何计算样式矩阵的示例。样式矩阵本质上是Gram矩阵,其中样式矩阵的第(i,j)个元素通过计算第i和第j个特征图的元素乘法和宽度和高度的求和来计算。在该图中,红叉表示元素乘法,红色加号表示在特征图的两个宽度高度上求和。
您可以按如下方式计算样式损失。
为什么在Gram矩阵中捕获该样式?
很高兴我们知道如何计算风格损失。但是你仍然没有显示“为什么使用Gram矩阵计算样式损失”。 Gram矩阵本质上是捕获给定层中的一组特征映射的“特征分布”。通过尝试最小化两个图像之间的样式损失,您基本上是匹配两个图像之间的特征分布[3,4]。
注意:就个人而言,我认为上述问题的答案并不令人满意。例如[4]解释了风格损失和领域适应之间的相似之处。但这种关系并没有回答上述问题。
因此,让我更直观地解释一下这一点。假设您有以下功能图。为简单起见,我假设只有三个特征映射,其中两个完全不活动。您有一个要素图集,其中第一个要素图看起来像狗,而在第二个要素图集中,第一个要素图看起来像一个颠倒的狗。然后,如果您尝试手动计算内容和样式损失,您将获得这些值。这意味着我们没有丢失两个要素图集之间的样式信息。但是,内容却完全不同。
了解风格损失
最后的损失
最终损失定义为,
其中α和β是用户定义的超参数。这里β吸收了先前定义的M ^ 1归一化因子。通过控制α和β,您可以控制注入生成图像的内容和样式的数量。您还可以在纸张中看到不同α和β值的不同效果的可视化。
定义优化器
接下来,您使用Adam优化器来优化网络的丢失。
定义输入管道
在这里定义完整的输入管道。 tf.data提供了一个非常易于使用且直观的界面来实现输入管道。对于大多数图像处理任务,您可以使用tf.image API,但是tf.image处理动态大小图像的能力非常有限。例如,如果要动态裁剪和调整图像大小,最好以生成器的形式执行,如下所示。
您已定义了两个输入管道;一个用于内容,一个用于样式。内容输入管道查找以单词content开头的jpg图像,通过样式管道查找以style开头的图像。
定义计算图
现在你已准备好摇滚!在本节中,您将定义完整的计算图。
- 定义提供输入的迭代器
- 定义输入和CNN变量
- 定义内容、风格和总损失
- 定义优化操作
跑步风格迁移
是时候运行计算图并生成一些艺术作品了。生成的图稿将保存到data / gen_0,data / gen_1,...,data / gen_5等文件夹中。s
当你运行上面的代码时,你应该得到一些整洁的艺术保存到你的磁盘,如下所示。
结论
在本教程中,您了解了神经样式迁移。神经样式迁移允许将两个图像(一个包含内容和一个包含样式)混合在一起以创建新的艺术。您首先了解了为什么需要神经风格迁移以及方法体系结构的概述。然后,您使用TensorFlow定义了神经样式传输网络的细节。具体来说,您定义了几个函数来定义变量/输入,计算VGG输出,计算损耗并执行优化。接下来你理解了两个让我们实现我们想要的东西的损失;详细的内容损失和风格损失,看他们如何聚集在一起来定义最终的损失。最后,您运行模型并查看由模型生成的图稿。
本教程的代码可在此处获得。(https://github.com/thushv89/exercises_thushv_dot_com/tree/master/neural_style_transfer_light_on_math_ml)