本文是Deep Learning Specialization系列课程的第4课《Convolutional Neural Networks》中Face recognition & Neural style transfer应用部分的学习笔记。
本文对人脸识别和神经风格转换进行了描述,包含:
- 人脸验证 vs 人脸识别
- One Shot Learning
- Siamese Network
- Triplet Loss
- 神经风格转换的代价函数
1 人脸识别
人脸识别现在在国内的普及比较广泛,比如大楼门禁、机场安检等,一方面是技术上的发展,一方面是国人对这方面隐私的忍受度较高。
1.1 人脸验证 vs 人脸识别
- 人脸验证是1对1的,输入人脸图像和ID,来验证这个人是否是对应ID的人,比如通过FaceID解锁手机。
- 人脸识别是1对多的,有一个包含多人人脸的数据库,然后输入人脸来识别是否为该数据库中的一部分,比如大楼的门禁系统。
人脸识别是在人脸验证上的增强,要难的多,假如人脸验证的准确度为99%,那么人脸识别则是有K次的机会来产生误差。
1.2 One Shot Learning
One Shot Learing是指我们很多时候在人脸识别系统中只有一张示例/训练图像用来学习,并且基于此来完成人脸识别。
一个方案是,我们可以将所有的图像都运用到卷积神经网络中,最后的输出是一个softmax分类。但这种方法存在一个很大的问题,假如输入数据中又增加了一张照片,那么这就意味着我们需要重新对卷积神经网络进行训练。
1.3 相似度函数
相似度函数(Similarity Function)主要是用来计算图像之间差异度,设定一个阈值,若小于该值则表示这两种图像是相同的,否则是不同的。
- 如果 d ( i m g 1 , i m g 2 ) ≤ τ d(img1, img2) \le \tau d(img1,img2)≤τ, 则相同
- 如果 d ( i m g 1 , i m g 2 ) > τ d(img1, img2) > \tau d(img1,img2)>τ, 则不同
1.4 Siamese Network
那么,如何来计算两张图像的差异呢?这里就需要用到Siamese Network了,该方法是Taigman等人2014年在《DeepFace: Closing the Gap to Human-Level Performance in Face Verification》中提出的。
Siamese Network是将输入图像利用相同的参数来进行卷积神经网络处理,利用最后得到的全连接层进行比较。比如输入图像是
x
i
x_i
xi,经过计算得到的全连接层称为为
f
(
x
i
)
f(x_i)
f(xi),
x
i
x_i
xi与
x
j
x_j
xj的比较就可以转化为
f
(
x
i
f(x_i
f(xi与
f
(
x
j
)
f(x_j)
f(xj)之间的比较了。这里通过引入 Norm 来使得归一化计算的结果。
1.5 Triplet Loss
要使得前面神经网络中对脸部图像能有比较好的编码(encoding
x
i
x_i
xi to
f
(
x
i
)
f(x_i)
f(xi)),一种方法是使用Triplet Loss(三元组损失),对其进行梯度递减来学习所需神经网络的参数。
这一方法是Schroff等人2015年在《FaceNet: A Unified Embedding for Face Recognition and Clustering》提出的。
Triplet Loss包含三张图片,Anchor (A)、Positive §和Negative (N)。其原理是使得 d ( A , P ) d(A, P) d(A,P)要小于 d ( A , N ) d(A, N) d(A,N),即 ∥ f ( A ) − f ( P ) ∥ 2 ≤ ∥ f ( A ) − f ( N ) ∥ 2 {\parallel f(A) - f(P)\parallel}^2 \le {\parallel f(A) - f(N) \parallel}^2 ∥f(A)−f(P)∥2≤∥f(A)−f(N)∥2 。
如果所有的图片向量都为0,那么上述等式也成立,但是这对人脸识别没有任何作用,于是在等式中引入一个超参数
α
\alpha
α (margin),拉大Anchor与Positive和Anchor与Negative之间的差距。
Triplet损失函数是要保证
∥
f
(
A
)
−
f
(
P
)
∥
2
−
∥
f
(
A
)
−
f
(
N
)
∥
2
+
α
≤
0
{\parallel f(A) - f(P)\parallel}^2 - {\parallel f(A) - f(N) \parallel}^2 + \alpha \le 0
∥f(A)−f(P)∥2−∥f(A)−f(N)∥2+α≤0,如果其大于0,则进行梯度递减使得损失函数小于0。
其代价函数为:
l
(
A
,
P
,
N
)
=
m
a
x
(
∥
f
(
A
)
−
f
(
P
)
∥
2
−
∥
f
(
A
)
−
f
(
N
)
∥
2
+
α
,
0
)
l(A, P, N) = max({\parallel f(A) - f(P)\parallel}^2 - {\parallel f(A) - f(N) \parallel}^2 + \alpha, 0)
l(A,P,N)=max(∥f(A)−f(P)∥2−∥f(A)−f(N)∥2+α,0)
这里的输入数据X
是包含Anchor、Postive和Negative的三张图像,在训练过程中使得代价函数最小从而得到合适的参数,最后通过相似度函数
d
(
x
i
,
x
j
)
d(x_i, x_j)
d(xi,xj)来完成图像的验证。
在Triplet Loss的训练中,A
, P
, N
都是从训练数据中选取来组成三元组的。在训练中,若只是随机的进行数据的选取,其实很容易就能符合
∥
f
(
A
)
−
f
(
P
)
∥
2
−
∥
f
(
A
)
−
f
(
N
)
∥
2
+
α
≤
0
{\parallel f(A) - f(P)\parallel}^2 - {\parallel f(A) - f(N) \parallel}^2 + \alpha \le 0
∥f(A)−f(P)∥2−∥f(A)−f(N)∥2+α≤0的条件,这不利于我们的人脸识别系统。因此,我们在训练时,需要尽量构建难以训练的数据对,来提高人脸识别算法。
1.6 二元分类
另外一种进行人脸验证的方法是在Siamese Network的基础上,将两张图像的输出转化为二元分类的问题。
这里比较的仍是Siamese Network产生的编码后的值
f
(
x
i
)
f(x_i)
f(xi),通过对要对比的两张图像进行逻辑回归的计算来的到最后的预测结果。
这里的输入数据X
是包含待验证和已有的两张图像,输出y
是1
或0
。其中,对已有数据的Siamese Network产生的编码是可以提前计算并保存下来的,在进行人脸识别时,只需重新计算待验证图像的Siamese Network产生的编码,再做二元分类的计算。
2 神经风格转换
神经风格转换是指将一张原始图像(Content)按照另一张图像(Style)的风格来进行渲染,最后得到风格转换后的图像(Generated)。
2.1 深度神经网络学习
要理解为什么可以进行神经风格转换,我们就需要了解一下深度卷积神经网络是怎么来学习的。
在一个AlexNet神经网络中,隐藏层从浅到深能检测到越来越复杂的特征。比如,第一层隐藏层的不同单元只能看到小部分卷积神经,能识别出一些简单的边缘或者颜色阴影。
这部分的内容详细也可以参考Zeiler等人2013年发表的《Visualizing and understanding Convolutional Networks》
2.2 代价函数
为了构建一个神经风格转换系统,我们需要为生成的图像(G)定义一个代价函数,并最小化该代价函数来生成最终想要的图像。
生成图像是由原图像和风格图像合成的,其代价函数可以表示为:
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)
具体的实现是先通过一个随机值来初始化G,再通过梯度递减法
G
=
G
−
∂
∂
G
J
(
G
)
G = G - {\partial \over \partial G}J(G)
G=G−∂G∂J(G)来求得生成图像的最小代价函数,以此来得到最终的风格转换图像。其过程如下图中的右侧部分。
2.3 内容代价函数
上面我们知道生成图像的代价函数为:
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),那我们接下来要做的就是分别求的
J
c
o
n
t
e
n
t
(
C
,
G
)
J_{content}(C, G)
Jcontent(C,G)和
J
s
t
y
l
e
(
S
,
G
)
J_{style}(S, G)
Jstyle(S,G)。
在求内容图像的代价函数
J
c
o
n
t
e
n
t
(
C
,
G
)
J_{content}(C, G)
Jcontent(C,G)时,我们一般会使用已训练过的卷积神经网络,比如VGG。针对第
l
l
l层的网络,内容图像的激活函数为
a
[
l
]
(
C
)
a^{[l](C)}
a[l](C),生成图像的激活函数为
a
[
l
]
(
G
)
a^{[l](G)}
a[l](G)。
如果两者相似,那么其激活函数应该相近,通过这我们可以来计算内容代价函数,即
J
c
o
n
t
e
n
t
(
C
,
G
)
=
1
/
2
∥
a
[
l
]
(
C
)
−
a
[
l
]
(
C
)
∥
2
J_{content}(C, G) = 1/2 { \parallel a^{[l](C)} - a^{[l](C)} \parallel}^2
Jcontent(C,G)=1/2∥a[l](C)−a[l](C)∥2
2.4 风格代价函数
图像风格
利用卷积神经网络,图片的风格可以定义成第l
层隐藏层不同通道间激活函数的乘积(相关性)。
选取某一隐藏层,将各通道使用不同颜色标注。每个通道识别的特征不同,比如红色通道提取的是图片的垂直纹理特征,黄色通道提取的是图片的橙色背景特征。如果这两个通道的相关性越大,说明原始图片中包含了垂直纹理的区域也包含了橙色背景;如果相关性越小,则原始图片中包含了垂直纹理的区域可能就不包含橙色背景。
通过计算不同通道的相关性,能反映原始图片特征间的相互关系,从某种程度上刻画了图片的「风格」。
接下来定义风格图像的 Style Matrix,也可以称为 Gram 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
i,j
i,j代表当前的高度和宽度,
k
k
k和
k
′
k'
k′为不同的通道。
G
k
,
k
′
[
l
]
G_{k, k'}^{[l]}
Gk,k′[l]是第
l
l
l层隐藏层不同通道对应的所有激活函数输出和,最终得到的 Style Matrix 是一个
n
c
∗
n
c
n_c * n_c
nc∗nc的矩阵,如下图所示:
如果两个通道之间相似度较高,那么
G
k
,
k
′
[
l
]
G_{k, k'}^{[l]}
Gk,k′[l]较大;如果通道间相似度低,那么
G
k
,
k
′
[
l
]
G_{k, k'}^{[l]}
Gk,k′[l]较小。
下面将上面的Style Matrix应用于风格图像和生成图像,并比较将两者进行比较,若两者相似度较高,则
G
k
,
k
′
[
l
]
(
S
)
G_{k, k'}^{[l](S)}
Gk,k′[l](S)与
G
k
,
k
′
[
l
]
(
G
)
G_{k, k'}^{[l](G)}
Gk,k′[l](G)的差值较小。
第
l
l
l层的风格代价函数为
J
s
t
y
l
e
[
l
]
(
C
,
G
)
=
β
∑
∑
(
G
k
,
k
′
[
l
]
(
S
)
−
G
k
,
k
′
[
l
]
(
G
)
)
2
J_{style}^{[l]}(C, G) =\beta \sum \sum(G_{k, k'}^{[l](S)} - G_{k, k'}^{[l](G)})^2
Jstyle[l](C,G)=β∑∑(Gk,k′[l](S)−Gk,k′[l](G))2
最后得到的风格代价函数为:
J
s
t
y
l
e
(
C
,
G
)
=
∑
λ
[
l
]
J
s
t
y
l
e
[
l
]
(
S
,
G
)
J_{style}(C, G) = \sum \lambda ^{[l]}J_{style}^{[l]}(S, G)
Jstyle(C,G)=∑λ[l]Jstyle[l](S,G)
上面所有的内容都引自Gatys等人2015年发表的《A Neural Algorithm of Artistic Style》。
最终, 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),再通过梯度递减法 G = G − ∂ ∂ G J ( G ) G = G - {\partial \over \partial G}J(G) G=G−∂G∂J(G)来求得生成图像的最小代价函数,以此来得到最终的风格转换图像。