第一课:什么是人脸识别
卷积神经网络的重要应用:将从人脸识别开始,之后讲神经风格迁移
百度林元庆人脸识别系统。人脸识别和活体检测。后者表明你是一个活人,事实上,活体检测可以使用监督学习来实现。
那么如何构建这个系统中的人脸识别这一部分呢?
首先,术语:人脸验证和人脸识别
人脸验证:
输入一张图片,或者某人的name/ID
这个系统要做的是:验证输入图片是否是这个人,有时候也被称作是1对1问题,只需要弄明白这个人是否和他声称的身份相符。
人脸识别:比验证问题复杂很多
因为在人脸验证是1 : 1的犯错比例,但是在人脸识别上是1:k,为了保证在人脸识别上有1%的犯错比例,对应人脸验证就需要99.9%的犯错比例。
构造一个人脸识别,作为基本模块,你可以把一个犯错率非常小的人脸验证系统应用于人脸识别。
如何构造人脸验证系统,构造人脸验证系统的难点之一就是:
要解决“一次学习”问题。
第二课:One-Shot 学习
人脸识别要面临的一个挑战就是你要解决一次学习问题。这意味着在绝大多数人脸识别应用中,你需要通过单单一张图片,或者一个人脸样例就能识别这个人。
在历史上,当深度学习只有一个训练样例的时候,它的变现并不好。
所以在一次学习问题中,只能通过一个样本来进行学习,以能够认出同一个人,大多数人脸识别系统都需要解决这个问题。因为在你的数据库中,每个雇员或者组员可能都只有一张照片。
有一种办法是:将人的照片,放到卷积神经网络中,使用softmax单元,来输出4种或者说五种标签,分别对应这4个人。但实际上这样的效果并不好,因为训练集太少,不足以训练一个稳健的神经网络。而且如果有新人进入你的团队,这时候你将有五个组员需要识别,输出就变成了六种,这时你又要重新训练你的神经网络么?
所以要让人脸识别能够做到一次学习,为了能有更好的效果。你现在要做的应该是学习Similarity函数:
详细的说,你想要神经网络学习这样一个用d表示的函数,它以两张照片作为输入,然后输出这两张图片的差异值。如果你放进同一个人的两种照片,你希望输出一个非常小的值,如果你放进两个长相差别很大的人的照片,它就输出一个非常大的值。所以在识别的过程中,如果这两张图片的差异值小于某个阈值τ(超参数),那么这时就可以预测这两张图片是同一个人。如果差异值大于τ,就能预测是不同的两个人,这就是解决人脸验证问题的可行办法。
要将它应用于识别任务,你要做的就是拿这张新图片,然后用d函数去比较这两张图片,这样可能会输出一个非常大的数字,如果某个人不在你的数据库,你通过函数d,将图片进行两两比较,最后我们希望d会对所有的比较都输出一个很大的值,就证明这个人不在你的团队里。
要注意在这个问题中,你是如何解决一次学习问题的?
只要你能学习这个函数d,通过输入一对图片,它就能告诉你这两张图片是否属于同一个人,如果之后有新人加入了你的团队,你只需将他的图片放入数据库,系统依然能照常工作。
如何训练你的神经网络学会这个函数d?
第三课: Siamese 网络
函数d的作用就是:输入两张人脸,然后告诉你它们的相似度,实现这个功能的一个方式就是用 Siamese 网络。
我们不使用常规的卷积神经网络的卷积和池化,以及softmax 分类。
我们的关注的重点是最后一个卷积向量,加入它有128个数,它是由网络深层的全连接层计算出来的,我们命名这128个数字的向量为:f(x^1)。
你可以把f(x^1)看作是输入图像x1的编码。
建立一个人脸识别系统的方法就是:
如果你要比较两个图片的话,你要做的就是把第二个图片喂给有同样参数的神经网络,然后得到一个不同的128维向量。这个向量代表或者编码第二个图片,将第二张图片的编码叫做f(x^2)。
最后如果你相信这些代码,可以输入任意一张图片,认为输出向量很好地代表了这两张图片,你要做的就是定义d(x1,x2)定义为两幅图片编码之差的范数。
对于两个不同的输入,运行相同的卷积神经网络,然后比较它们,这一般叫做siamese网络架构。
底下这篇论文的研究成果源自一个开发系统DeepFace。
怎么训练这个siamese神经网络呢?
更准确的说,神经网络的参数定义了一个编码f(x^i),如果给定输入图像xi,这个网络会输出xi的一个128维的编码。
你要做的就是学习参数,使得两张图片xi和xj是同一个人,那么你得到的两个编码的距离就小,而且训练集里任意一对xi和xj都可以。
相反如果xi和xj是不同的人,那么你会想让它们之间的编码距离大一点。
如果你改变这个网络所有层的参数,你会得到不同的编码结果。你要做的就是利用反向传播来改变这些所有的参数,以确保满足这些条件。
你已经了解了siamese的网络结构,并且知道你想要的网络输出是什么,即什么是好的编码,但是如何定义实际的目标函数,能够让你的神经网络学习并做到我们所说的呢?
三元组损失函数!
第四课:Triplet 损失
要想通过学习神经网络的参数来得到优质的人脸识别编码,方法之一就是定义:三元组损失函数然后应用梯度下降。
为了应用三元组损失函数,你需要比较成对的图像。
用三元组损失的术语来说:
positive意味着是同一个人的距离很接近
negtive意味着是不同的人距离更远一点
这就是为什么叫做三元组损失,它代表你通常会同时看三张图片,Anchor,positive和negtive。如果把这些写成公式,你想要的网络的参数或者编码能够满足以下特性:
你可以把d(istance)看作是距离函数。
但是当所有的输出都是0的时候,满足这个公式,所以为了对于所有的编码,不会总是输出0,即都设为互相相等的,为了阻止这种情侣的发生,我们需要修改这个目标,在0后面加一个超参数负值α,这样就可以阻止网络输出无用的结果。这里的α也叫做间隔,间隔参数α可以人为的将图片对比的值得到提升,即它拉大了anchor对positive和negtive图片对之间的差距。
更公式化的定义三元损失函数:
三元组损失函数的定义基于三张图片,接下来我们定义损失函数,它的定义基于三元图片组,然后通过max()函数,确保计算值小于0,所以我们定义的损失函数达到的效果就是确保计算值小于等于0,而不会关心它负值多大。
以上就是一个三元损失函数,整个网络的代价函数,应该是训练集中这些单个三元组损失的总和。
假如你有10000张图片的训练集,里面是1000个不同人的照片,你要做的就是取这10000张图片,然后生成这样的三元组,然后训练你的学习算法,对这种代价函数应用梯度下降。
注意:为了定义三元组的数据集,你需要成对的A和P,即同一个人的成对的图片,为了训练你的系统,你确实需要一个数据集,里面是不同人的多个图片,即1000个人平均每人10张图片构成了你整个数据集。如果每人一张图片,那么就没办法训练这个识别系统。
当然,训练完这个系统之后,你可以应用到你的一次学习问题上,对于你想要应用于识别的系统,你可能只有一张图片,但是对于训练集,要确保有同一个人的多个图片,从而组成成对的positive和negtive。
现在,你如何选择这些三元组来形成训练集呢?
一个问题是如果你从训练集中随机的选择A和P,遵守A和P是同一个人,而A和N是不同的人这一原则,有个问题就是如何随机的选择它们?
其实很容易得到,因为随机选择的图片,A和N比A和P的差距很大的概率很大。
但是如果A和N是随机选择的不同人,那么等式成立的可能性会变得很大,这样网络并不能从中学习到什么。所以为了构建数据集,你要做的就是尽可能选择难训练的三元组A、P和N。具体而言,你想要的所有三元组,都满足这个条件。
难训练的三元组就是你的A、P和N的选择使得d(A,P)很接近d(A,N),这样你的学习算法会竭尽全力满足上述公式要求。这样可以增强你的学习算法的计算效率。但是如果随机选取这些三元组,那么由于太多会很简单,梯度算法不会有什么效果,因为网络总是很轻松就可以获得正确的结果。
只有选择较难的三元组,梯度下降法才能发挥作用。论文里的FaceNet系统有对细节更详细的描述,即如何 通过选择最有用的三元组训练来加速算法的细节。
深度学习系统的命名规则:如果你研究某个特定的领域,通常会将系统命名为“某某”网络或者深度“某某”。
总结一下:
训练这个三元组损失,你需要取你的训练集,然后把它做成很多三元组。定义了这些包括A、P和N的图片数据集以后,你还需要做的是用梯度下降最小化我们之前定义的代价函数J,这样做的效果就是反向传播到网络中的所有参数来学习到一种编码,使得如果这两个图片是同一个人,那么它们的d就会很小,如果不是同一个人,d就会很大。
以上就是三元组损失并且如何用它来训练网络,输出一个好的编码用于人脸识别,现在的人脸识别系统,尤其是大规模的商业人脸识别系统,都是在很大的数据集上训练,超过百万图片的数据集并不罕见,一些公司用千万级的图片甚至上亿级的图片来训练这些系统。
幸运的是,已经有些公司训练了这些大型的网络,并上传了模型参数,所以相比于从头训练这些网络,在这一领域,由于这些训练集太大,这个领域的一个实用操作就是下载别人的预训练模型,而不是一切都要从头开始。但是即使你下载了别人的预训练模型,我认为了解怎么训练这些算法也是有用的。以防针对一些应用,你需要从头实现这些想法,这就是三元损失。
siamese的一些其它变体?
第五课:面部验证和二分类
三元组损失是一个学习人脸识别卷积网络参数的好方法,还有其它学习参数的方法,怎么把人脸识别看成是二分类问题?
另一个训练神经网络的方法是选取一对神经网络,选取siamese网络,使其同时计算这些嵌入,比如说128维嵌入,然后将其输入到逻辑回归单元,然后进行预测,如果是相同的人,那么输出是1,若是不同的人,输出是0。
这就变成了一个二分类问题,如果巡礼的好,可以替换三元组损失的方法。
最后的逻辑回归单元是怎么处理的?
把这128个元素当作特征,然后把它们放入逻辑回归中,最后的逻辑回归可以增加参数wi和b,就像普通的逻辑回归一样。你将在这128个单元上训练合适的权重, 用来预测两张图片是否是同一个人, 这是一个合理的方法来学习预测0或1。
还有一些其他的方式来计算,即替换公式,将绝对值距离换位其他的距离计算公式x平方公式。
值得注意的一点是:两个卷积神经网络的参数应该是相同的,两套系统的参数是绑定的,这样的系统效果最好。
之前提到的计算结果可以帮助你显著提高部署效果:
对于在数据库中的图片,不需要每次都计算其特征,你可以提前计算好,如果输入是一张新图片,当员工走进门时,可以将这个新图片的输入计算编码和提起计算好的编码进行比较,然后输出预测值y,因为不需要存储原始图像,如果你有一个很大的数据库,你不需要为员工每次都计算编码。
这个预先计算的思想可以节省大量的计算,而这个预训练的工作,可以用在siamese网络结构中进行人脸识别,当做一个二分类问题,也可以用在学习三元损失函数上。
总结一下:
把人脸验证当做是一个监督学习,创建一个只有成对图片的训练集,不是三个一组,而是成对的图片,目标标签是1,表示一对图片是一个人,利用不同对的图片,使用反向传播算法,去训练siamese网络。
所以这个你看到的版本处理人脸验证问题,将人脸识别问题扩展为二分类问题,这样的效果也很好,我希望你知道在一次学习问题上,你需要什么来训练人脸验证或人脸识别问题。
第六课:什么是神经风格转换?
最近,卷积神经网络最有趣的应用是神经风格迁移。
什么是神经风格迁移?
为了实现神经风格迁移,你需要知道卷积网络提取的特征,在不同的神经网络中,深层的浅层的。
所以卷积网络不同层之间的具体运算是什么呢?
第七课:深度卷积网络在学什么?
卷积网络中深度较大的层真正在做什么?这将有助于理解如何实现神经风格迁移。
例子:
假如你训练了一个卷积伸进网络,是一个Alex网络,轻量级网络,你希望看到不同层之间隐藏单元的计算结果。
你可以这么做:
从第一层的隐藏单元开始,假设你遍历了训练集,然后发现一些图片或者图片块,最大化的激活了那个运算单元,换句话说,经过神经网络,然后弄明白哪一张图片最大限度地激活特定的单元?
你可以这么理解(可视化神经卷积网络的计算内容):
第一层的隐藏单元,通常会找一些简单的特征,比如说边缘或者颜色阴影。
在第一层的九个隐藏单元重复几遍得到一部分特征单元以后,如何在更深层的隐藏单元中进行这样的计算呢?在更深层次的隐藏单元,它可以看到一张图片更大的部分,在极端情况下,可以假设每一个像素都会影响到神经网络更深层的输出,靠后的隐藏单元可以看到更大的图片块。
如果我们在深层卷积神经网络重复这一过程,并且放大后观察:
第一层:角度边缘
第二层:更复杂的形状和模式
第三层:更复杂的模式
第四层:更加复杂了
第五层:更加多样性
第一层的边缘——第二层的质地——到深层到复杂物体...
希望你可以从中了解卷积网络的浅层和深层是如何计算的?
接下来,神经风格迁移!
第八课:代价函数
要创建一个神经风格迁移系统,我们需要为生成的图像定义一个代价函数,通过最小化代价函数,你可以生成你想要的任何图像。
为了十点神经风格迁移,你要做的就是:
定义一个关于G的代价函数J,用来评判某个生成图像的好坏,我们将使用梯度下降法去最小化J(G),以便于生成图像,怎么判断生成图像的好坏呢?
我们把代价函数定义为两部分:
第一部分称为内容代价,是一个关于内容图片和生成图片的函数,它是用来度量生成图片的内容与内容图片C的内容有多相似,然后我们会把结果加上一个风格代价函数。
这个风格代价函数是关于S和G的,即图片G和图片S风格的相似度。
最后添加两个超参数α和β来确定内容代价和风格代价两者之间的权重,用两个超参数来确定两个代价的权重似乎是多余的,我觉得一个超参数就够了。可以提出神经风格的原作者,使用了两个不同的超参数,所以要保持一致。
算法的运行是这样的:
对于代价函数J(G),为了生成一个新图像,你接下来要做的是:
1.随机初始化图像G
2.使用梯度下降法将代价函数最小化,在这一步骤中,你实际更新的是图像G的像素值。
以上就是神经风格迁移算法的概要,定义一个生成图片G的代价函数,并将其最小化,接下来我们需要了解怎么去定义内容代价函数和风格代价函数?
第九课:内容代价函数
风格迁移网络的代价函数有一个内容代价组分,还有一个风格代价组分,我们先定义内容代价组分:
假如说你用隐藏层l来计算内容代价,那么这个代价函数会使你的生成图片像素上非常接近你的内容图片,然而如果你使用很深的层,那么就会问图片里是否有狗,所以在实际中,这个层l在网络中既不会选的太浅,也不会选的太深,通常l会选在网络的中间层,既不太浅,也不太深。
然后用一个预训练的卷积模型,可以使VGG网络,或者其他网络,现在你需要衡量假如有一个内容图片和一个生成图片,它们在内容上的相似度,我们令这个a[l]加上上标[c]代表图片在l层上的激活函数值。
如果这两个激活值相似那么就意味着两个图片的内容相似。
即两个激活值间的差值平方和,这就是两个图片之间的l层激活值的差值平方和,后面如果对J(G)做梯度下降,来找G的值时,整个代价函数会鼓励这个算法找到图像G,使得隐藏层的激活值和你内容图像相似。
第十课:风格代价函数
什么是图片的风格?
假如你取卷积神经网络的某一层,然后去为图片的风格定义一个深度测量。
将图像的风格定义为l层中各通道之间激活项的相关系数。
首先看前面两个通道,如何计算这两个通道之间的激活项目的相关系数呢?
我们在每个通道上都得到一些数字对,当我们取得了nh和nw的所有数字对后,怎么计算相关系数呢?它是如何决定图片风格的呢?
我们可以在卷积网络的神经元中找到对应通道,什么时候两个通道拥有高度相关性呢?
相关系数描述的是当图片某处出现这种垂直纹理时,该处又同时是橙色的可能性,相关系数为你提供了一种去测量这些不同特征的方法,或是其他的特征。通过测量它们在图片中的位置,同时出现或不同时出现的频率,如果我们使用相关系数来描述通道的风格,你能做的就是测量你的生成图像中,第一个通道是否与第二个通道相关,通过测量,你就能得知在生成的图像中,垂直纹理和橙色同时出现或者不同时出现的频率,这样你就能测量生成图像的风格与输入图像的相似程度。
你需要计算一个风格矩阵:
严格来说,它是一种非标准的互相关函数,因为我们没有减去平均数,而是将它们直接相乘。
所以你要做的就是计算出这张图像的风格矩阵,以便能够测量出刚才说的相关系数。
所以上面的式子就是把图中各个高度和宽度的激活项都遍历一遍,并将k和k‘通道对应位置的激活项都进行相乘,这就是Gkk'的定义。
通过对k和k’通道中所有数值进行计算,就得到了G矩阵,也就是风格矩阵。
它其实是一种非标准的互协方差,因为没有减去均值,而是把元素直接相乘,以上就是计算图像风格的方法,要同时对S和G都运行相同的运算。
最后代入到风格代价函数中去计算,从而得到两个矩阵之间的误差。
实际上,如果你对各层都使用风格代价函数,会让结果变得更好。
为了把这些封装起来,你现在可以定义一个全体代价函数,等于α乘以C与G内容代价函数。之后用梯度下降法或者更复杂的优化算法,来找到一个合适的图像G,并计算J(G)的最小值。
如何对1D或3D的数据进行卷积?
第十一课:一维到三维推广
即使我们大多数情况下讨论的都是2D图像,许多你掌握的思想甚至可以延伸到1D乃至3D数据。
一维数据,一维过滤器卷积,加上通道可以得到一个二位数据。
对3D数据如何呢?
对于CT扫描:
你的数据具备一定的高度、长度和宽度,如果你想要在3D扫描或CT扫描中建立特征识别,使用3D过滤器。