8.2 DeepDream
DeepDream是一种艺术性的图像修改技术,它用到了卷积神经网络学到的表示。DeepDream由 Google于 2015年夏天首次发布,使用 Caffe深度学习库编写实现(当时比 TensorFlow的首次公开发布要早几个月)。它很快在网上引起了轰动,这要归功于它所生成的迷幻图像(比如图 8-3),图像中充满了算法生成的错觉式伪影、鸟羽毛和狗眼睛。这是 DeepDream卷积神经网络在 ImageNet上训练的副作用,因为 ImageNet中狗和鸟的样本特别多。
图 8-3 DeepDream输出图像示例
DeepDream算法与第 5章介绍的卷积神经网络过滤器可视化技术几乎相同,都是反向运行一个卷积神经网络:对卷积神经网络的输入做梯度上升,以便将卷积神经网络靠顶部的某一层的某个过滤器激活最大化。DeepDream使用了相同的想法,但有以下这几个简单的区别。
- 使用 DeepDream,我们尝试将所有层的激活最大化,而不是将某一层的激活最大化,因此需要同时将大量特征的可视化混合在一起。
- 不是从空白的、略微带有噪声的输入开始,而是从现有的图像开始,因此所产生的效果能够抓住已经存在的视觉模式,并以某种艺术性的方式将图像元素扭曲。
- 输入图像是在不同的尺度上[叫作八度(octave)]进行处理的,这可以提高可视化的质量。我们来生成一些 DeepDream图像。
8.2.1 用 Keras实现 DeepDream
我们将从一个在 ImageNet上预训练的卷积神经网络开始。 Keras中有许多这样的卷积神经网络:VGG16、VGG19、Xception、ResNet50等。我们可以用其中任何一个来实现 DeepDream,但我们选择的卷积神经网络会影响可视化的效果,因为不同的卷积神经网络架构会学到不同的特征。最初发布的 DeepDream中使用的卷积神经网络是一个 Inception模型,在实践中,人们已经知道 Inception能够生成漂亮的 DeepDream图像,所以我们将使用 Keras内置的 Inception V3模型。
代码清单 8-8 加载预训练的 Inception V3模型
接下来,我们要计算损失(loss),即在梯度上升过程中需要最大化的量。在第 5章的过滤器可视化中,我们试图将某一层的某个过滤器的值最大化。这里,我们要将多个层的所有过滤器的激活同时最大化。具体来说,就是对一组靠近顶部的层激活的 L2范数进行加权求和,然后将其最大化。选择哪些层(以及它们对最终损失的贡献)对生成的可视化结果具有很大影响,所以我们希望让这些参数变得易于配置。更靠近底部的层生成的是几何图案,而更靠近顶部的层生成的则是从中能够看出某些 ImageNet类别(比如鸟或狗)的图案。我们将随意选择 4层的配置,但你以后一定要探索多个不同的配置。
代码清单 8-9 设置 DeepDream配置
接下来,我们来定义一个包含损失的张量,损失就是代码清单 8-9中层激活的 L2范数的加权求和。
代码清单 8-10 定义需要最大化的损失
下面来设置梯度上升过程。
代码清单 8-11 梯度上升过程
最后就是实际的 DeepDream算法。首先,我们来定义一个列表,里面包含的是处理图像的尺度(也叫八度)。每个连续的尺度都是前一个的 1.4倍(放大 40%),即首先处理小图像,然后逐渐增大图像尺寸(见图 8-4)。
图 8-4 DeepDream过程:空间处理尺度的连续放大(八度)与放大时重新注入细节
对于每个连续的尺度,从最小到最大,我们都需要在当前尺度运行梯度上升,以便将之前定义的损失最大化。每次运行完梯度上升之后,将得到的图像放大 40%。
在每次连续的放大之后(图像会变得模糊或像素化),为避免丢失大量图像细节,我们可以使用一个简单的技巧:每次放大之后,将丢失的细节重新注入到图像中。这种方法是可行的,因为我们知道原始图像放大到这个尺寸应该是什么样子。给定一个较小的图像尺寸 S和一个较大的图像尺寸 L,你可以计算将原始图像大小调整为 L与将原始图像大小调整为 S之间的区别,这个区别可以定量描述从 S到 L的细节损失。
代码清单 8-12 在多个连续尺度上运行梯度上升
注意,上述代码使用了下面这些简单的 Numpy辅助函数,其功能从名称中就可以看出来。它们都需要安装 SciPy。
代码清单 8-13 辅助函数
注意
因为原始 Inception V3网络训练识别尺寸为 299×299的图像中的概念,而上述过程中将图像尺寸减小很多,所以 DeepDream实现在尺寸介于 300×300和 400×400之间的图像上能够得到更好的结果。但不管怎样,你都可以在任何尺寸和任何比例的图像上运行同样的代码。
最开始的照片是在旧金山湾和 Google校园之间的小山上拍摄的,我们从这张照片得到的DeepDream图像如图 8-5所示。
图 8-5 在示例图像上运行 DeepDream代码
我们强烈建议你调节在损失中使用的层,从而探索能够得到什么样的结果。网络中更靠近底部的层包含更局部、不太抽象的表示,得到的梦境图案看起来更像是几何形状。更靠近顶部的层能够得到更容易识别的视觉图案,这些图案都是基于 ImageNet中最常见的对象,比如狗眼睛、鸟羽毛等。你可以随机生成 layer_contributions字典中的参数,从而快速探索多种不同的层组合。对于一张自制美味糕点的图像,图 8-6给出了利用不同的层配置所得到的一系列结果。
图 8-6 在一张示例图像上尝试一系列 DeepDream配置
8.2.2 小结
- DeepDream的过程是反向运行一个卷积神经网络,基于网络学到的表示来生成输入。
- 得到的结果是很有趣的,有些类似于通过迷幻剂扰乱视觉皮层而诱发的视觉伪影。
- 注意,这个过程并不局限于图像模型,甚至并不局限于卷积神经网络。它可以应用于语音、音乐等更多内容。