1、One-Shot学习(One-shot learning)
人脸识别所面临的一个挑战就是需要解决一次学习问题(one-shot learning problem),这意味着在大多数人脸识别应用中,你需要通过单单一张图片或者单单一个人脸样例就能去识别这个人。而历史上,当深度学习只有一个训练样例时,它的表现并不好。
要让人脸识别能够做到一次学习,为了能有更好的效果,现在要做的应该是学习Similarity函数。Similarity函数的核心作用是计算两个输入(如向量、集合、概率分布等)之间的相似度,不同的相似度函数适用于不同的场景。常见的相似度函数包括余弦相似度、欧氏距离、Jaccard相似度等。
上述公式以两张图片作为输入,然后输出这两张图片的差异值。如果输入同一个人的两张照片,你希望输出一个很小的值;如果输入两个长相差别很大的人的照片,则希望输出一个很大的值。在识别过程中,一般设置阈值,它是一个超参数。如果d大于阈值,则预测是两个不同的人。这是解决人脸验证的一个可行方法。
我们已经知道函数d是如何工作的,通过输入两张照片,它将让你能够解决一次学习问题。那么,下一节中将会学习如何训练神经网络学会这个函数d。
2、Siamese 网络(Siamese network)
上节中函数d的作用就是输入两张人脸图片,然后输出相似度。实现这个功能的一个方式就是用Siamese网络。
上图是常见的卷积网络,输入图片x^(1),然后经过卷积层、池化层和全连接层,最终得到特征向量。假如它有128个数,它是由网络深层的全连接层计算出来的,给这128个数命个名字,f(x^(1)),可以看成是图像x^(1)的编码。建立一个人脸识别系统的方法就是:如果要比较两个图片的话,把第二张图片x^(2)喂给有同样参数的神经网络,然后得到一个不同的128维向量。这里x^(1)和x^(2)仅代表两个输入图片,是任意两个图片。
接下来定义d,将x^(1)和x^(2)的距离定义为这两种图片编码之差的范数:
对于两个不同的输入,运行相同的卷积神经网络,然后比较它们,这一般叫做Siamese网络架构(Siamese neural network architecture)。下面展示怎么训练这个Siamese神经网络。
由于两个网络有相同的参数,因此就是训练一个网络。你要做的就是学习参数,如果两张图片是同一个人,那两个编码的距离就很小;如果是不同的人,编码距离就大一些。如果你改变这个网络所有层的参数,你会得到不同的编码结果,你要做的就是用反向传播(back propagation)来改变这些所有的参数,以确保满足这些条件。
训练Siamese网络时,最常用的损失函数是对比损失(Contrastive Loss)或三元组损失(Triplet Loss),下面我们将来学习三元组损失函数。
4、Triplet 损失(Triplet loss)
要想通过学习神经网络的参数来得到优质的人脸图片编码,方法之一就是定义三元组损失函数(triplet loss function),然后应用梯度下降。
为了应用三元组损失函数,你需要比较成对的图像。用三元组损失的术语来说,你要做的通常是看一个 Anchor 图片,你想让Anchor图片和Positive图片(Positive意味着是同一个人)的距离很接近。然而,当Anchor图片与Negative图片(Negative意味着是非同一个人)对比时,你会想让他们的距离离得更远一点。这就是为什么叫做三元组损失,它代表你通常会同时看三张图片(Anchor图片、Postive图片和Negative图片),通常把它们简写成A、P、N。
下面来看改如何选择这些三元组来形成训练集。
一个问题是如果你从训练集中,随机地选择A、P和N,遵守A和P是同一个人,而A和N是不同的人这一原则。随机选择的话约束条件很容易满足,因为A和N比A和P差别很大的概率很大,这样网络并不能从中学到什么。所以要尽可能的选择难(hard)训练的A、P和N,使得d(A,P)和d(A,N)很接近,即:
这样你的学习算法会竭尽全力使右边这个式子变大,或者使左边这个式子变小,这样左右两边至少有一个间隔(margin),并且选择这样的三元组还可以增加你的学习算法的计算效率。因此,只有选择难的三元组梯度下降法才能发挥作用,使得这两边离得尽可能远。
5、什么是神经风格迁移?
神经风格迁移(Neural Style Transfer, NST)是一种利用深度学习将两幅图像的内容和风格融合在一起的技术。具体来说,它能够将一幅图像的内容与另一幅图像的风格进行结合,生成一幅既保留原图内容特征、又具有目标图风格的图像。
为了描述如何实现神经网络迁移,使用C来表示内容(content)图像,S表示风格(style)图像,G表示生成的图像(generated image)。为了实现神经风格迁移,我们需要知道卷积网络提取的特征,在不同的神经网络,深层的、浅层的。
6、深度卷积网络学习什么?
深度卷积网络到底在学什么?下面将展示一些可视化的例子,可以帮助我们理解卷积网络中深度较大的层真正在做什么,这样有助于理解如何实现神经风格迁移。
图中展示了如何可视化卷积神经网络(CNN)内部的工作方式,尤其是它的隐藏层如何从输入图像中学习到特征。这是基于AlexNet网络的一个例子,研究人员通过查看神经网络的某些神经元(或称为“单元”)在处理图像时的激活情况,帮助我们理解每个神经元到底在学习什么样的特征,通过上图可看出到这个神经元主要对什么样的图像特征特别敏感,例如可能对某个方向的边缘、纹理、颜色特别“感兴趣”。
从上图来看,检测已经有了一些进展,从检测简单的事物,比如说,第一层的边缘,第二层的质地,到深层的复杂物体。
7、代价/成本函数(cost function)
要构建一个神经风格迁移系统,需要为生成的图像定义一个成本函数(cost function),通过最小化成本函数,可以生成你想要的任何图像。
重新描述一下问题:给定一个内容图像C和一个风格图片S,目标是生成一个新图片G。为了实现神经风格迁移,定义一个关于G的成本函数J(G)来评判生成图像的好坏,然后使用梯度下降法最小化J(G)来生成新的图像G。定义成本函数的公式如下:
第一部分被称作内容代价(content cost),这是一个关于内容图片和生成图片的函数,它是用来度量生成图片G的内容与内容图片C的内容有多相似。第二部分是风格代价函数(style cost),是关于S和G的函数,用来度量图片G的风格和S的风格的相似度。
如上图,为了生成一个新图像,要做的是(1)随机初始化生成图像G,它可能是100×100×3,可能是500×500×3,又或者是任何你想要的尺寸。(2)使用梯度下降法使成本函数J(G)最小化,更新公式:,在这个步骤中,实际上更新的是图像G的像素值,也就是100×100×3。
看上图的这个例子。假设你从这张内容图片(编号1)和风格(编号2)图片(毕加索画作)开始,当你随机初始化G,随机初始化的生成图像可能就是这张随机选取像素的白噪声图(编号3)。接下来运行梯度下降算法,最小化代价函数J(G),逐步处理像素,这样慢慢得到一个生成图片(编号4、5、6),越来越像用风格图片的风格画出来的内容图片。
8、内容代价函数(Content cost function)
我们先定义内容代价函数(content cost function)。
如上图,(1)用隐含层l来计算内容代价函数,如果l是个很小的数,比如用隐含层1,这个代价函数就会使生成图片像素上非常接近内容图片。然而如果你用很深的层,那么你就会问,内容图片里是否有狗,然后它就会确保生成图片里有一个狗。所以在实际中,这个层l在网络中既不会选的太浅也不会选的太深。具体例子里通常会选择在网络的中间层,既不太浅也不很深,(2)然后用一个预训练的卷积模型,可以是VGG网络或者其他的网络也可以。接下来你需要衡量假如有一个内容图片和一个生成图片他们在内容上的相似度,(3)我们令这个a^[l][C]和a^[l][G],分别代表这两个图片C和G的l层的激活函数值。(4)如果这两个激活值相似,那么就意味着两个图片的内容相似。
衡量两个激活值不同或相似的程度用如下公式:
取l层的隐含单元的激活值,按元素相减,然后取平方,前面可以加上归一化或者不加,比如1/2。这里用的符号都是展成向量形式(vectors)的,因此对应元素相减变成了L2范数的平方。然后用梯度下降法来找到图像G,使得隐含层的激活值和你内容图像的相似。
9、风格代价函数(Style cost function)
学习了内容代价函数之后,我们来了解风格代价函数(style cost function)。
这是一张彩色图片,现在我们选择了某一层l(蓝色框部分)去为图片的风格定义一个深度测量(deep measure),接下来将图片的风格定义为l层中各个通道之间激活项的相关系数(correlation)。
如上图,假设有5个通道(channels),这里用五种颜色表示。一般而言,神经网络中会有许多通道。在第一个通道中含有某个激活项,第二个通道也含有某个激活项,于是它们组成了一对数字。同理,可以得到很多数字对(pairs)。
在这里,这个红色的通道对应的第2个神经元,它能找出图片中的特定位置是否含有这些垂直的纹理,而第二个通道(黄色的通道),对应第4个神经元,它可以粗略地找出橙色的区域。
如果我们使用相关系数来描述通道的风格,你能做的就是测量你的生成图像中第一个通道(红色)是否与第二个通道(黄色)相关,通过测量,你能得知在生成的图像中垂直纹理和橙色同时出现或者不同时出现的频率,这样你将能够测量生成的图像的风格与输入的风格图像的相似程度。接下来具体讲解。
如上图,对于这两个图像(风格图像S和生成图像G),需要计算一个风格矩阵(style matrix),说得更具体一点就是用l层来测量风格。其中a^[l]_i,j,k表示隐藏层l中(i,j,k)位置的激活值,i,j,k分别表示该位置的高度、宽度以及对应的通道数。计算关于l层和风格图像的一个矩阵,即G^[l][S],这是一个n_c*n_c的矩阵,高度和宽度都是l层的通道数。矩阵中的k和k'被用来描述k通道和k'通道之间的相关系数。输入的风格图像S构成的风格矩阵具体表现为:
备注:用符号i,j表示下届,对i,j,k位置的激活值乘以同样位置的激活值,然后i和j分别加到l层的高度和宽度。严格来说,它是一种非标准的互相关函数(unnormalized cross-covariance),因为没有减去平均数,而是直接相乘。这是输入的风格图像构成的风格矩阵,然后对生成图像G做同样的操作。
风格矩阵就是把图中各个高度和宽度的激活项都遍历一遍,并将k和k'通道中对应位置的激活项都进行相乘。现在分别从风格图像S和生成图像G得到两个矩阵。过程见下图:
最后,上图所示,将S和G代入到风格代价函数中去计算,得到这两个矩阵的误差,这里用的Frobenius范数,实际上是计算两个矩阵对应元素相减的平方的和。把这个式子展开,从k和k'开始作差,然后把所有的结果加起来,作者使用了一个归一化常数(renormalization constant),再在外面加一个平方,一般我们只要将它乘以一个超参数beta就行。
如上图,最后,这是对l层定义的风格代价函数J^[l],实际上,如果各层都使用风格代价函数,结果会更好,你可把各个层的结果(各层的风格代价函数)都加起来,对每个层定义权重,即额外的(extra)超参数,用lambda^[l]表示。这样将在神经网络中使用不同的层,包括之前的一些可以测量类似边缘这样的低级特征的层,以及之后的一些能测量高级特征的层,使得我们的神经网络在计算风格时能够同时考虑到这些低级和高级特征的相关系数。这样,在基础的训练中你在定义超参数时,可以尽可能的得到更合理的选择。
把这些东西封装起来,就定义了一个全体代价函数:
接着用梯度下降法或者其他优化算法来寻找合适的图像G,并计算J(G)的最小值,这样将能够得到非常好看的结果。