Week2

学习时间:2020/06/29 - 2020/07/05

0 主要学习内容

所有相关资料和我写的代码可以在此处下载:Download

  • Coursera深度学习风格迁移编程作业
  • Coursera深度学习人脸识别编程作业

1 Neural Style Transfer(神经网络风格迁移)

神经网络风格迁移就是一次(也可以的一个batch生成多张)利用一张内容图片(content image, notaion:C)和一张风格图片(style image, notation:S)去生成一张内容与C类似,风格与S类似的图片G。

Week2

1.1 风格迁移特点概述

 根据我对神经网络风格迁移的理解以及编程实现中所遇到的一些问题,现总结神经网络风格迁移的特点如下:

  1. 风格迁移需要借助一个pre-trained的网络实现(GitHub代码中借助的是VGG-19
  2. 风格迁移训练时更新的权重是input层中初始时随机生成图片的像元(这里原来所学习的更新网络权重参数的方式有所不同,这也是为什么要用pre-trained网络的原因)
  3. 风格迁移计算内容损失(Content Cost)时,只考虑一个隐含层的输出。而计算风格损失(Style Cost)时则需要考虑多个,甚至是全部隐含层的输出。

1.2 风格迁移构建步骤

  1. 挑选Content Cost所考虑的一层隐含层;挑选Style Cost所考虑的几层隐含层以及其对应的权重λi\lambda_i(tips:Content Cost考虑的隐含层一般选取中间的层,从而提取不浅也不太深的特征即可;Style Cost所考虑的几层权重应满足i=1nλ=1\sum_{i = 1}^{n} \lambda = 1
  2. 随机初始化一张图片,作为待更新图片。(tips:为了加快收敛速度,其实可以用Content Image + Random Noise的方式初始化)
  3. 计算Content Cost
  4. 计算Style Cost
  5. 计算总损失J(G)=αJcontent(C,G)+βJstyle(S,G)J(G) = \alpha J_{content}(C, G) + \beta J_{style}(S, G)
  6. 根据总损失J(G)J(G)更新G中的像素

1.3 风格迁移重点知识

1.3.1 Content Cost

 从Visualizing and understanding convolutional networks这篇发表在ECCV2014的论文中可以了解到,卷积神经网络较浅层次学习的是颜色、边缘等低层特征,而较深层次学习的是纹理、网格特征甚至是一些完整的、具有辨别性的关键特征。
 因此,为了能够度量两张图片的内容相似程度,我们就可以选择网络中间层的输出(目的是提取不是太浅,也不是太深的特征)aCa_CaGa_G来计算两张图片的相似程度。计算公式如下:
Jcontent(C,G)=14×nH×nW×nCim(aC(i)aC(i))2 J_{content}(C,G) = \frac{1}{4 \times n_H \times n_W \times n_C} \sum_i^m(a_C^{(i)} - a_C^{(i)})^2

1.3.2 Style Cost

1.3.2.1 Gram Matrix

 为了更好的理解Style Cost,我们需要先理解一下什么叫做Gram Matrix。
 Gram Matrix被定义为n维欧式空间中任意k个向量α1,α2,α3αk\alpha_1,\alpha_2, \alpha_3 \dots \alpha_k的内积所组成的矩阵。公式如下:
(α1,α2,αk)=[(α1,α1)(α1,α2)(α1,αk)(α2,α1)(α2,α2)(α2,αk)(αk,α1)(αk,α2)(αk,αk)] \triangle(\alpha_1, \alpha_2, \dots \alpha_k)= \left[ \begin{matrix} (\alpha_1, \alpha_1) & (\alpha_1, \alpha_2) & \cdots & (\alpha_1, \alpha_k)\\ (\alpha_2, \alpha_1) & (\alpha_2, \alpha_2) & \cdots & (\alpha_2, \alpha_k)\\ \vdots & \vdots & \ddots & \vdots\\ (\alpha_k, \alpha_1) & (\alpha_k, \alpha_2) & \cdots & (\alpha_k, \alpha_k) \end{matrix} \right]
 其中(α1,α1)(\alpha_1, \alpha_1)表示两个向量的内积。
 由于在向量2范数固定之后(可以想象一下全部都是单位向量),向量的内积大小其实是由两个向量夹角的cos值所决定的。即Gram Matrix实际上的每一个元素都反映着对应两个向量方向的相似程度。所以我们采用Gram Matrix去度量两张图片的风格相似程度。

1.3.2.2 Unrolling trick

Week2
 有了上面Gram Matrix的知识,我们想要用它去代表一张图片的风格,这个时候该怎么办呢?
 首先根据Gram Matrix的定义,我们需要准备k个向量去两两做内积吧。根据这一点,同时考虑到图片本身就是由一个个通道stack起来的,所以图片风格其实是可以由各个通道之间的关联性度量的。因此,为了保持每个通道包含信息完整且用Gram Matrix度量的是每个通道之间的关联性,我们就需要把这个nH×nW×nCn_H \times n_W \times n_C的图片变成nCn_C个向量。即从上图的左边变到右边,以方便我们用矩阵的乘法构建Gram Matrix。
Week2
 至此,如上图所示,我们只需要把aGa_GaSa_S变换一下,就可以用矩阵乘法方便地计算出Gram Matrix。

编程tips:TensorFlow中完成上述操作可以查看一下tf.transpose和tf.reshape的官方API

1.3.2.3 Style Cost的计算

 有了Gram Matrix实际上就很好计算Style Cost了,但这里要注意的是计算Style Cost需要考虑多层隐含层的输出。因此下面给出Style Cost计算的公式:
Jstyle[l](S,G)=14×nC2×(nH×nW)2i=1nCj=1nC(G(gram)i,j[l](S)G(gram)i,j[l](G))2(1)J_{style}^{[l]}(S,G) = \frac{1}{4 \times {n_C}^2 \times (n_H \times n_W)^2} \sum _{i=1}^{n_C}\sum_{j=1}^{n_C}(G^{[l](S)}_{(gram)i,j} - G^{[l](G)}_{(gram)i,j})^2 \tag{1}
Jstyle(S,G)=lλ[l]Jstyle[l](S,G)(2)J_{style}(S,G) = \sum_{l} \lambda^{[l]} J^{[l]}_{style}(S,G) \tag{2}
 其中公式(1)计算的是两图片第l层输出结果的Style Cost,而公式(2)是总体Style Cost(即各个层的加权平均)

1.3.3 总体Cost计算

 有了Content Cost和Style Cost,取两者的加权平均就很容易计算出总体的Cost。公式如下:
J(G)=αJcontent(C,G)+βJstyle(S,G)J(G) = \alpha J_{content}(C, G) + \beta J_{style}(S, G)

1.3.4 迭代更新

 风格迁移的迭代更新与之前所学习的神经网络不太一样的地方就是,风格迁移利用的是一个pre-trained的网络,在迭代更新的时候并不会更新网络的权重参数,而是会更新输入层的输入G。

1.4 风格迁移结果展示

 Python代码有需要请自行在Download处下载。
Content image:
Week2
Style image:
Week2
Generated image:
Week2