须知:本文作者建议各位读者结合Coursera上Andrew NG(吴恩达)教授的DeeLearning.ai课程一同学习,理解效果更佳。本文为《Convolutional Neural Networks》第四周 特殊应用:人脸识别和神经风格迁移的学习笔记。
文章目录
什么是神经风格迁移(What is neural style transfer?)
神经风格迁移是卷积神经网络最有趣的应用之一,简单来说就是通过一种人工神经系统,实现了图像内容与风格的分离,从而允许以任何其他图像的风格重铸一个图像的内容。
我们来看几个例子。

先来看上图左半部分照片,Content(简记为C)是在斯坦福大学拍摄的,你想利用右边照片的风格来重新创造原本的照片,右边的Style(简记为S)是梵高的星空,利用神经风格迁移生成下方这幅梵高风格的Generated image(简记为G)。
再看上图右半部分照片,Content(简记为C)是在旧金山的金门大桥,右边的Style(简记为S)是毕加索的风格,利用神经风格迁移生成下方这幅张毕加索风格的的金门大桥 Generated image(简记为G)。
深度卷积网络学习什么?(What are deep ConvNets learning?)
为了实现神经风格迁移,你需要知道卷积网络在不同的神经网络(深层的、浅层的)是如何提取特征的。我们先来看一下深度卷积网络到底在学什么?
以AlexNet为例,你希望将看到不同层之间隐藏单元的计算结果。
可以这样做:

-
从第一层的隐藏单元开始,将训练集经过神经网络,然找出哪一张图像最大限度地激活特定的单元。注意:在第一层的隐藏单元只能看到小部分卷积网络。
- 比如你选择隐藏单元1,发现有9个图片最大化了单元激活,你可能找到编号1所示的9个图片,说明隐藏单元1寻找到了编号2这样的边缘或线。
- 然后可以选一个第一层的另一个隐藏单元(记为隐藏单元2)重复刚才的步骤,找到了编号3所示的9个图片,说明隐藏单元2寻找的是编号4这样的边缘或线。
- 接着对其它隐藏单元也进行同样处理。第一层的隐藏单元通常会找一些简单的特征,比如说边缘或者颜色阴影(shade of color)。后面的层会找到更复杂的形状和模式。在深层部分一个隐藏单元会看到一张图像更大的部分。在极端的情况下,可以假设每一个像素都会影响到神经网络更深层的输出。
-
对其它层重复上述过程。
-
我们将每一层得到的最大程度激活的9个隐藏单元可视化出来,如下图:


将第二层的结果放大,我们发现,第二层似乎检测到更复杂的形状和模式,比如说这个隐藏单元(编号1),它会找到有很多垂线的垂直图案,这个隐藏单元(编号2)似乎在左侧有圆形图案时会被高度激活,这个的特征(编号3)是很细的垂线,以此类推,第二层检测的特征变得更加复杂。

第五层检测到更加复杂的事物,注意到这(编号1)也有一个神经元,似乎是一个狗检测器,但是可以检测到的狗似乎更加多样性。这个(编号2)可以检测到键盘,或者是键盘质地的物体,可能是有很多点的物体。我认为这个神经元(编号3)可能检测到文本,但是很难确定,这个(编号 4)检测到花。
感兴趣的话,更多细节可阅读这篇论文:
Visualizing and Understanding Convolutional Networks
我们发现,从第一层的边缘,到第二层的质地,……,到深层的复杂物体,越往后会越找到复杂的形状和模式。
代价函数(Cost function)
要构建一个神经风格迁移系统,需要为生成的图像定义一个代价函数,通过最小化此代价函数,生成我们想要的图像。
换言之,我们的问题是,给了一个内容图像
C
C
C,给定一个风格图片
S
S
S,而目标是生成一个新图片
G
G
G。为了实现神经风格迁移,你要做的是定义一个关于
G
G
G的代价函数
J
J
J用来评判某个生成图像的好坏,我们将使用梯度下降法去最小化
J
(
G
)
J(G)
J(G),以便于生成这个图像。
代价函数分为两部分:
- J c o n t e n t ( C , G ) J_{content}(C,G) Jcontent(C,G)
第一部分被称作内容代价函数,这是一个关于内容图片和生成图片的函数,它是用来度量生成图片 G G G的内容与内容图片 C C C的内容有多相似。
- J s t y l e ( S , G ) J_{style}(S,G) Jstyle(S,G)
第二部分是风格代价函数,也就是关于 S S S和 G G G的函数,用来度量生成图片 G G G的风格和风格图片 S S S的风格的相似度。
- J ( G ) = α J c o n t e n t ( C , G ) + β J s t y l e ( S , G ) J(G)=\alpha J_{content}(C,G)+\beta J_{style}(S,G) J(G)=αJcontent(C,G)+βJstyle(S,G)
α \alpha α、 β \beta β是两个超参数,用来确定内容代价和风格代价的权重。
有兴趣的可以阅读一下这篇论文:A Neural Algorithm of Artistic Style
算法如何运行?
- 首先随机初始化生成图像 G G G,它可能是100×100×3,可能是500×500×3,又或者是任何你想要的尺寸。
- 用梯度下降法最小化代价函数 J J J,更新 G : = G − ∂ ∂ G J ( G ) G:=G-\frac{\partial}{\partial G}J(G) G:=G−∂G∂J(G)
- 在这个步骤中,你实际上更新的是图像 G G G的像素值,也就是 100×100×3,比如 RGB 通道的图片。
举个例子:

假设你从这张内容图片(编号1)和风格(编号2)图片(毕加索)开始,当你随机初始化 G G G生成的图像就是这张随机选取像素的白噪声图(编号3)。接下来运行梯度下降算法,最小化代价函数 J ( G ) J(G) J(G),逐步处理像素,这样慢慢得到一个生成图片(编号4、5、6),越来越像用风格图片的风格画出来的内容图片。
内容代价函数(Content cost function)

我们已经知道,神经风格迁移网络的代价函数由内容代价函数和风格代价函数两部分组成。
- J ( G ) = α J c o n t e n t ( C , G ) + β J s t y l e ( S , G ) J(G)=\alpha J_{content}(C,G)+\beta J_{style}(S,G) J(G)=αJcontent(C,G)+βJstyle(S,G)
那么什么是内容代价函数呢?
- 用隐含层 l l l来计算内容代价。
如果 l l l是个很小的数,比如用隐含层1,这个代价函数就会使你的生成图片像素上非常接近你的内容图片。然而如果你用很深的层,那么就会问,内容图片里是否有狗,然后它就会确保生成图片里有一个狗。所以在实际中,这个层 l l l在网络中既不会选的太浅也不会选的太深。
- 用一个预训练的卷积模型,可以是VGG或者其他模型。
- 用 a [ l ] ( C ) a^{[l](C)} a[l](C)和 a [ l ] ( G ) a^{[l](G)} a[l](G)来代表 C C C、 G G G两个图片在 l l l层的激活值。
- J c o n t e n t ( C , G ) = 1 2 ∣ ∣ a [ l ] ( C ) − a [ l ] ( G ) ∣ ∣ 2 J_{content}(C,G)=\frac{1}{2}||a^{[l](C)}-a^{[l](G)}||^2 Jcontent(C,G)=21∣∣a[l](C)−a[l](G)∣∣2为两个激活值不同或者相似的程度。
- 取 l l l层的隐含单元的激活值,求L2范数。
- 1/2 类似于归一化,也可取其他值,也可以不取,因为代价函数前有权重系数。
- 注意这里都为向量形式。
- 如果这两个激活值相似,那么就意味着两个图片的内容相似。
风格代价函数(Style cost function)
What is Style?

对于一个卷积神经网络,我们选择某一层 l l l(如图中编号1),用这一层去为图片做一个深度测量,而图片的风格定义为 l l l层中各个通道之间激活项的相关系数。

将 l l l 层的激活项取出,是一个 n H ∗ n W ∗ n C n_H*n_W*n_C nH∗nW∗nC的三维数据块。如何知道这些不同通道之间激活项的相关系数呢?
- 假设有5个通道,先将不同通道渲染成不同颜色。
- 红色的通道(编号1)对应的神经元能找出图片中的特定位置是否含有这些垂直的纹理(编号 3),而第二个通道也就是黄色的通道(编号2),对应这个的神经元(编号4),它可以粗略地找出橙色的区域。
什么时候两个通道拥有高度相关性呢?
-
如果它们有高度相关性,那么这幅图片中出现垂直纹理的地方(编号 2),那么这块地方(编号 4)很大概率是橙色的。
-
如果说它们是不相关的,这意味着图片中有垂直纹理的地方很大概率不是橙色的。
-
相关系数描述的就是当图片某处出现这种垂直纹理时,该处又同时是橙色的可能性。
-
我们将相关系数应用到风格图片S和生成图片G的对应通道上,就可以度量风格图片和生成图片的相似度。
风格矩阵(Style Matrix)
- 设 a i , j , k [ l ] a_{i,j,k}^{[l]} ai,j,k[l] 表示在隐藏层 l l l中( i , j , k i,j,k i,j,k)位置的激活项,其中 i , j , k i,j,k i,j,k代表该位置的高度、宽度以及对应的通道数。
-
G
[
l
]
G^{[l]}
G[l] 表示关于
l
l
l层的风格矩阵,大小为
(
n
c
∗
n
c
)
(n_c*n_c)
(nc∗nc)
-
G k , k ′ [ l ] ( S ) = ∑ i = 1 n H [ l ] ∑ j = 1 n W [ l ] a i , j , k [ l ] ( S ) a i , j , k ′ [ l ] ( S ) G_{k,k'}^{[l](S)}=\sum_{i=1}^{n_H^{[l]}}\sum_{j=1}^{n_W^{[l]}}a_{i,j,k}^{[l](S)}a_{i,j,k'}^{[l](S)} Gk,k′[l](S)=i=1∑nH[l]j=1∑nW[l]ai,j,k[l](S)ai,j,k′[l](S)
-
G k , k ′ [ l ] ( G ) = ∑ i = 1 n H [ l ] ∑ j = 1 n W [ l ] a i , j , k [ l ] ( G ) a i , j , k ′ [ l ] ( G ) G_{k,k'}^{[l](G)}=\sum_{i=1}^{n_H^{[l]}}\sum_{j=1}^{n_W^{[l]}}a_{i,j,k}^{[l](G)}a_{i,j,k'}^{[l](G)} Gk,k′[l](G)=i=1∑nH[l]j=1∑nW[l]ai,j,k[l](G)ai,j,k′[l](G)
-
- G G G是一个矩阵,高度和宽度都是 l l l层的通道数
- i , j i,j i,j是激活块中对应位置的坐标,也就是该激活项所在的高和宽, i i i会从1加到 n H [ l ] n_H^{[l]} nH[l], j j j会从1加到 n W [ l ] n_W^{[l]} nW[l]
- 用 G k , k ′ [ l ] G_{k,k'}^{[l]} Gk,k′[l]来描述 k k k通道和 k ′ k' k′通道激活项之间的相关系数, k k k和 k ′ k' k′会在1到 n c n_c nc之间取值, n c n_c nc就是 l l l层通道的总数
- 将 k k k通道和 k ′ k' k′通道上对应位置的激活项相乘
- 上标( S S S)和( G G G)分别表示风格图像 S S S和生成图像 G G G
- 是一种非标准的互协方差,因为我们并没有减去均值而只是把这些元素直接相乘,这就是计算图像风格的方法。
风格代价函数
- J s t y l e [ l ] ( S , G ) = 1 2 n H [ l ] n W [ l ] n C [ l ] ∣ ∣ G [ l ] ( S ) − G [ l ] ( G ) ∣ ∣ F 2 = 1 2 n H [ l ] n W [ l ] n C [ l ] ∑ k ∑ k ′ ( G k , k ′ [ l ] ( S ) − G k , k ′ [ l ] ( G ) ) 2 J_{style}^{[l]}(S,G)=\frac{1}{2n_H^{[l]}n_W^{[l]}n_C^{[l]}}||G^{[l](S)}-G^{[l](G)}||_F^2=\frac{1}{2n_H^{[l]}n_W^{[l]}n_C^{[l]}}\sum_k\sum_{k'}(G_{k,k'}^{[l](S)}-G_{k,k'}^{[l](G)})^2 Jstyle[l](S,G)=2nH[l]nW[l]nC[l]1∣∣G[l](S)−G[l](G)∣∣F2=2nH[l]nW[l]nC[l]1k∑k′∑(Gk,k′[l](S)−Gk,k′[l](G))2
同内容代价函数一样,前面的归一化常数可以去掉,因为代价函数前有权重系数。
- 如果对每一层都使用风格代价函数,那就需定义总的代价函数,把各个层的结果(各层的风格代价函数)都加起来:
J s t y l e ( S , G ) = ∑ λ λ [ l ] J s t y l e [ l ] ( S , G ) J_{style}(S,G)=\sum_\lambda \lambda^{[l]}J_{style}^{[l]}(S,G) Jstyle(S,G)=λ∑λ[l]Jstyle[l](S,G)
一维到三维推广(1D and 3D generalizations of models)
我们大部分讨论的图像数据,某种意义上而言都是2D数据。许多你所掌握的思想不仅局限于2D图像,也可以延伸至1D,乃至3D数据。

- 2D卷积:
- Input: 14 ∗ 14 ∗ 3 14*14*3 14∗14∗3
- filter: 5 ∗ 5 ∗ 3 5*5*3 5∗5∗3, n c n_c nc:16
- Output: 10 ∗ 10 ∗ 16 10*10*16 10∗10∗16
- 1D卷积:(1D数据应用:如医学诊断使用EKG信号/心电图)
- Input: 14 ∗ 1 14*1 14∗1
- filter: 5 ∗ 1 5*1 5∗1, n c n_c nc:16
- Output1: 10 ∗ 16 10*16 10∗16
- filter: 5 ∗ 16 5*16 5∗16, n c n_c nc:32
- Output2: 6 ∗ 32 6*32 6∗32

- 3D卷积:(3D数据应用:如医学CT扫描输出身体3D模型,将电影中随时间变化的不同视频切片)
- Input: 14 ∗ 14 ∗ 14 ∗ 1 14*14*14*1 14∗14∗14∗1 【注】:不一定为正方体,长、宽、高可以不相等,此处以141414为例。
- filter: 5 ∗ 5 ∗ 5 ∗ 1 5*5*5*1 5∗5∗5∗1, n c n_c nc:16
- Output1: 10 ∗ 10 ∗ 10 ∗ 16 10*10*10*16 10∗10∗10∗16
- filter: 5 ∗ 5 ∗ 5 ∗ 16 5*5*5*16 5∗5∗5∗16, n c n_c nc:32
- Output2: 6 ∗ 6 ∗ 6 ∗ 32 6*6*6*32 6∗6∗6∗32