基于欧几里得距离的损失函数:Contrastive loss、Triplet loss、Center Loss+Softmax loss
Softmax loss适用于多分类,只具有可分离性(separable),即将类间分离,而没有判别性(discriminative),即不能类内聚合。而人脸识别需要有可分离性+判别性,可以泛化到对未知人脸的同类与不同类的分类,所以有了以下的损失函数。
在有监督的机器学习领域,通常有固定的类别,这时就可以使用基于softmax的交叉熵损失函数进行训练。但有时,类别是一个变量,此时使用triplet loss就能解决问题,triplet loss的优势在于细节区分,即当两个输入相似时,triplet loss能够更好地对细节进行建模,相当于加入了两个输入差异性差异的度量,学习到输入的更好表示。
siamese network, triplet network的输入都是成对或者triplet的,怎么对一个样本进行分类啊?神经网络的优势在于表示学习,自动的特征提取。所以,成对或者triplet的输入能让神经网络学到输入的更好的表示,后面再接svm, logtistic regression就可以分类了。1 对比损失(Contrastive Loss)
Contrastive loss 最初源于Yann LeCun于2006年发表的 Dimensionality Reduction by Learning an Invariant Mapping,该损失函数原本主要是用于降维中,即本来相似的样本,在经过降维(特征提取)后,两个样本仍旧相似;而原本不相似的样本,在经过降维后,两个样本仍旧不相似。同样,该损失函数也可以很好的表达成对样本的匹配程度。对比损失的定义
- 对比损失,需要用成对样本X1和X2来训练,还需要标注Y标签是否相似。公式如下:
- 有一点点像是Modified Huber Loss(结合了MSE、Hinge Loss)
![2ff41d2854771b61496f71ec6982ad6b.png](https://i-blog.csdnimg.cn/blog_migrate/590293e8554e48578868a9b527e67359.png)
其中Dw(X1,X2)代表两个成对样本特征X1和X2的欧氏距离(二范数),P 表示样本的特征维数,Y为两个样本是否匹配的标签,m为阈值。
- 它可以很好的表达成对样本的匹配程度
- Y=0,两个样本相似或匹配,红线,距离越大损失越大,横轴为欧式距离
- Y=1,样本不相似,蓝线,距离越小损失越大
- 当距离超过阈值margin的,则把其loss看做为0,即不相似的特征离的很远
![8d2f23ec3289b5d8d5cce485ef4492a6.png](https://i-blog.csdnimg.cn/blog_migrate/07d95556811b2719c619ea492ae02388.jpeg)
对比损失的梯度
使用随机梯度下降来更新w,以得到较小loss,更好表达成对样本的匹配程度。计算loss梯度的公式如下:
- Y=0,两个样本相似时,梯度为:
![431631dec963bd6692192f8e2abcb2c1.png](https://i-blog.csdnimg.cn/blog_migrate/bc1e4832c74dbfb682757b37ab3d7545.png)
- Y=1,两个样本不相似时,梯度为:
![a676566adc12eabea0cea8d3187024c0.png](https://i-blog.csdnimg.cn/blog_migrate/aa46225a23ea886e652f09c277a5c01c.png)
用弹簧模型类比
弹簧模型公式为:F=−K*X ,(F表示两点间弹簧的作用力,K是弹簧的劲度系数,X为弹簧拉伸或收缩的长度,弹簧静止状态时X=0)
![e94de5ba8fdfdbb3f7887b5197d214a8.png](https://i-blog.csdnimg.cn/blog_migrate/252dbb6e5da8034cbc309e2fe7378f94.png)
- (a) 相似是吸引力,蓝点与只吸引(attract-only) 弹簧连接到相似的点。
- (b) 与相似对关联的损失函数及梯度
- (c) 不相似是弹射力,蓝点仅与半径为m的圆内的非相似点用m-repulse-only弹簧连接
- (d) 与非相似对关联的损失函数及梯度
- (e) 一个点被不同方向的其他点拉动,形成平衡的情况
![fafd400c753419eb44e93faf4d9acbed.png](https://i-blog.csdnimg.cn/blog_migrate/f6ed9e3b95c14c3571de424394283635.png)
TensorFlow实现contrastive loss
输入图像对及它们的标签(相似或不相似),例如输入28x28x1的图像:
left
参考:参考1 TF实现contrastive loss和triplet loss2 三元组损失(Triplet Loss)
Triplet loss源于google在2015发表的 FaceNet: A Unified Embedding for Face Recognition and Clustering,伴随FaceNet。三元组损失的定义
- 三元组损失:最小化锚点和具有相同的身份的正例之间的距离,并最大化锚点和不同身份的负例之间的距离。
- 目标:
- 相同标签的两个示例使其嵌入在嵌入空间中靠近在一起,不同标签的两个示例的嵌入距离要很远
- 但不希望推动每个标签的训练嵌入到非常小的簇中。 唯一的要求是给出同一类的两个正例和一个负例,负例应该比正例的距离至少远margin。 这与SVM中使用的margin非常相似,这里希望每个类的簇由margin分隔。
![fbf0e3e91943bedaa07676edab34732c.png](https://i-blog.csdnimg.cn/blog_migrate/e89abfab12246386f9fe9c3efb873b90.png)
- 期望的三元组约束:
![8e0f0bc0b32e77fd705e3c9f1be44a1f.png](https://i-blog.csdnimg.cn/blog_migrate/49c1f0fb883085b7eed9b5372d0f7378.png)
- 三元组损失函数:
![37f4181b079978b22d92159d1e4bf088.png](https://i-blog.csdnimg.cn/blog_migrate/a5b5d8f4af93263a4c81f24eb0949388.png)
- 梯度,是对3个样本向量的:
![ee66cfd74f416e7db1802cf91aa0413b.png](https://i-blog.csdnimg.cn/blog_migrate/5b96f1d50134319ce5967d7ec06443a8.jpeg)
- 需要将3个样本在嵌入空间表示成3个向量,图像经过特征提取再降维就是在嵌入空间上。
- 在嵌入上定义三元组损失步骤:
- 锚点(anchor)、与锚类别相同的正例(positive)、类别不同的负例(nagative)
- 对嵌入空间的距离d,一个三元组(a,p,n)上的损失为:
- 最小化该损失就是让锚点与正例的距离d(a,p)趋近0,并使锚点与负例的距离大于d(a,p)+间隔,即d(a,n)>d(a,p)+margin
![dbf8c1f489c254c2ae6e9de18e5b3565.png](https://i-blog.csdnimg.cn/blog_migrate/127e4d499feee78e18ec55094e2a53ec.png)
![35b00f5f625604a7b506f6debe055ad1.png](https://img-blog.csdnimg.cn/img_convert/35b00f5f625604a7b506f6debe055ad1.png)
- 缺点:Triplet loss难于实现,所有的triplet组合太多了,都要训练效率低,所以要挑一些比较好的triplet进行训练
Triplet的选取
- 如何选择triplet,如何用正负例构建triplet,对模型训练的效率有很大影响。easy negative example比较容易识别,没必要训练,否则会严重降低训练效率。若都采用hard negative example,又可能会影响训练效果。
- Facenet论文中采用了随机的semi-hard negative构建triplet进行训练。
- 基于negative example与anchor和positive距离,分为三类三元组:
- 容易三元组(easy triplets):损失为0的三元组,因为d(a,n)>d(a,p)+margin
- 困难三元组(hard triplets) :其中负例比正例更靠近锚点,即d(a,n)<d(a,p)
- 半困难三元组(semi-hard triplets):其中负例不比正例更接近锚点,但仍有大于0的损失,d(a,p)<d(a,n)<d(a,p)+margin
![cd2a18ab7861944dd2a211f1300d8e03.png](https://i-blog.csdnimg.cn/blog_migrate/975ca8f3fa48e55c9673c9eb8b56363a.jpeg)
Batch Hard Sampling
2017的《In Defense of the Triplet Loss for Person Re-Identification》提出batch hard的表现最好。
- Offline triplet mining:离线triplet mining将所有的训练数据喂给神经网络,得到每一个训练样本的编码,根据编码计算得到negative example与anchor和positive example之间的距离,根据这个距离判断semi-hard triplets,hard triplets还是easy triplets。
- 它仅选择了hard 或 semi-hard triplets,但不够高效,因为最初要把所有的训练数据喂给神经网络,而且每过1个或几个epoch,可能还要重新对negative examples进行分类。
- Online triplet mining:Google提出了在线triplet mining的方法,即将B张图片(一个batch)喂给神经网络,得到B张图片的embedding。则triplet的组合一共最多B^3个triplets,其中包含很多没用的triplet(如三个negative examples和三个positive examples)。
- valid triplets:一个triplet(B_i,B_j,B_k),样本i和j有相同的label且不是同一个样本,而样本k具有不同的label。就是一个正例两个负例或者一个负例两个正例。
- 还需要用batch all或batch hard方法挑选出有效的triplet,假设一个batch的数据包含P*K张人脸,P个人,每人K张图片,如下:
- batch all:选择所有的valid triplet,并对hard 和 semi-hard triplets上的loss进行平均。
- 产生PK*(K-1)*(PK-K)个triplet,即PK个anchor,对于每个anchor有k-1个可能的positive example,PK-K个可能的negative examples
- 但不用easy triplets,因为easy triplets的损失为0,平均会把整体损失缩小
- batch hard:对于每一个anchor,选择hardest positive(距离anchor最远的positive example) 和 hardest negative(距离anchor最近的negative example)
- 产生PK个triplet,这些triplet是最难分的
Triplet network
《Deep metric learning using Triplet network》指出Siamese network是双胞胎连体,Triplet network是三胞胎连体,,输入是三个,一个负例+两个正例,训练的目标是找到满足相同类别间的距离尽可能的小,让不同类别间的距离尽可能的大的向量。Triplet在cifar, mnist的数据集上效果都是很不错的。
![a338482c7f2bf43700b6c5dd97ac5964.png](https://i-blog.csdnimg.cn/blog_migrate/f00c0f66df5a14d5da3b8df16c855651.png)
TensorFlow实现triplet loss
输入三张图片 anchor, positive, negative,但不需要标签:
(1)offline triplets实现
anchor_output = ... # shape [None, 128]
positive_output = ... # shape [None, 128]
negative_output = ... # shape [None, 128]
d_pos = tf.reduce_sum(tf.square(anchor_output - positive_output), 1)
d_neg = tf.reduce_sum(tf.square(anchor_output - negative_output), 1)
loss = tf.maximum(0., margin + d_pos - d_neg)
loss = tf.reduce_mean(loss)
(2)batch hard的实现方式
def
参考:
参考1 TF代码 Olivier Moindrot caffe中triplet loss layer的实现 MNIST示例3 中心损失(Center Loss)
Center Loss源于深圳先研院乔宇、Yandong Wen等在ECCV 2016上发表的 A Discriminative Feature Learning Approach for Deep Face Recognition。判别性
- 深度学习的特征需要具有discriminative(判别性)和泛化能力,以便在没有标签预测的情况下识别新的未见类别,如一个人脸即便没有训练过也能判断类别。判别性同时表征了紧凑的类内差异和可分离的类间差异。
- 判别性特征可以通过最近邻(NN)或k近邻(k-NN)算法进行良好分类,其不一定取决于标签预测。
- 而softmax损失仅鼓励特征的可分离性,所得到的特征对于人脸识别不是足够有效的。
- 对比损失和三元组损失分别构成图像对和三元组的损失函数,然而与原样本相比,训练对或三元组的数量急剧增加,导致了网络收敛缓慢。
中心损失的定义
- 中心损失:为每一个类别提供一个类别中心,最小化min-batch中每个样本与该类别中心的距离,即缩小类内距离。
- 有效地表征了深度特征的类内距离,提升深度特征的判别能力,在保持不同类别的特征可分离的同时最小化类内距离是关键。公式如下,c_yi就是第yi个类别的特征中心,xi表示全连接层之前的特征,m表示mini-batch的大小
![1871ede771e71220ad43e50f2ad4b346.png](https://i-blog.csdnimg.cn/blog_migrate/650cf46e4e5b4043c46a61ef1003f3cd.png)
- LC相对于xi的梯度和c_yi的更新方程为:
- 如果条件满足则δ(条件)=1,否则δ(条件)= 0,即只有当yi(表示yi类别)和cj的类别j一样的时候cj才需要更新。
- center可使用"xavier"进行初始化,然后在每个mini-batch迭代后在当前类别中更新一次。;每次迭代过程中,只对对应类别的特征取平均计算,相当于让cj是向x的平均移动。
- 为了避免少样本类别造成的较大干扰,采用一个因子α来控制类别中心的学习率。
![432adcd9356787e7d20ee4870c64b986.png](https://i-blog.csdnimg.cn/blog_migrate/4ceb4067b22c7829f0a4d12059962a18.png)
- 用softmax损失+中心损失的联合监督来训练CNN进行判别性特征学习,可以获得用于鲁棒的人脸识别的高判别性特征。标量λ用于平衡两个损失函数,则总的损失函数为:
- softmax可以让不同类的深度特征分开;center loss可以将同一类的特征吸引到类中心。两者结合不仅可以扩大不同类的特征区别,还可以减小同一类的特征的区别。
![4657f7cf4b5319ce821221d47c1c24e4.png](https://i-blog.csdnimg.cn/blog_migrate/98c5ebfb94d62f414ca39cddfa537a83.png)
- 判别性特征的学习算法步骤:
![4c76b8418bec7050ec62d44445cda8ac.png](https://i-blog.csdnimg.cn/blog_migrate/d81460dafe84d7a7f6f971385e47e856.jpeg)
- λ对于softmax loss与center loss联合监督下深度特征分布的影响:
- λ越大center loss比重越大,类内越聚合,判别能力越大。不同颜色的点表示来自不同类别的深度特征,白色的圆点(c0,c1,...,c9) 分别表示 10 类深度特征的类别中心.
![22cdfbec7f518cda2745ee7348097c8f.png](https://i-blog.csdnimg.cn/blog_migrate/e73cb82512a09fa7676bbcf8557d467e.jpeg)
- 优点:
- 容易实现:梯度方程和更新方程易于推导,得到的CNN模型是可训练的。
- 容易训练:Centers的更新基于可调学习率的mini-batch
- 容易输入:中心损失与softmax loss具有相同的训练数据格式,不需要复杂的样本挖掘和重组,直接在特征输出层中引入它即可。
- 这在对比损失和三元组损失中是不可避免的,由于预先收集所有可能的训练测试标识是不切实际的,因此CNNs中的标签预测并不总是适用。需要对深度学习的特性进行足够的一般化,以便在没有标签预测的情况下识别新的未知类。
- 容易收敛:在联合监督下,DeepIDNet由0.7M人脸图像训练,在14小时内迭代28k收敛。
- 缺点:另一个角度上说,center loss采取的是在训练过程中用空间换取时间的策略
基于Center Loss + Softmax Loss的人脸识别网络
三个local convolution层的权值分别在4×4、2×2和1×1区域进行局部共享。将第4个池化层和第3个local convolution层连接起来作为第1个全连接层的输入。全连通层的输出尺寸为512。
![3fb29229772f786b2bff132c9deddabd.png](https://i-blog.csdnimg.cn/blog_migrate/10a7b73ca523a689f3f06fcf933c8ced.jpeg)
![0bc950adf16ffe43cbca3311ea448643.png](https://i-blog.csdnimg.cn/blog_migrate/200a0c22ce2ec63984e48c250fcec931.png)
本论文在Wild (LFW)和Youtube Face (YTF)上的测试,我们用λ=0.003和α=0.5的模型C,有更少的0.7M的训练数据和更简单的网络架构。模型A仅受softmax损失的监督,模型B受softmax loss + contrastive loss相结合进行监督,模型C的结果准确率更高,这说明在设计的神经网络中,中心损耗比对比损耗更有优势。但仍不如三元组准确率高。
![0824ead17a4b4f0ce9499ffd37720465.png](https://i-blog.csdnimg.cn/blog_migrate/c9e4c245a33f8008ec6de0a085198681.jpeg)
Tensorflow实现Center loss
def center_loss(features, label, alfa, nrof_classes):
nrof_features = features.get_shape()[1]
# 训练过程中,需要保存当前所有类中心的全连接预测特征centers, 每个batch的计算都要先读取已经保存的centers
centers = tf.get_variable('centers', [nrof_classes, nrof_features], dtype=tf.float32, initializer=tf.constant_initializer(0), trainable=False)
label = tf.reshape(label, [-1])
centers_batch = tf.gather(centers, label) # 获取当前batch对应的类中心特征
diff = (1 - alfa) * (centers_batch - features) # 计算当前的类中心与特征的差异,用于Cj的的梯度更新,这里做了一个 1-alfa操作,比较奇怪,和原论文不同
centers = tf.scatter_sub(centers, label, diff) # 更新梯度Cj,对于上图中步骤6,tensorflow会将该变量centers保留下来,用于计算下一个batch的centerloss
loss = tf.reduce_mean(tf.square(features - centers_batch)) # 计算当前的centerloss 对应于Lc
return loss, centers
参考:
作者源码: https://github.com/ydwen/caffe-face
作者课件 参考1 caffe实现
转载请注明: https:// zhuanlan.zhihu.com/Face Rec
还可在我的知乎中查看其他系列专栏《CNN模型合集》《人脸识别合集》《目标检测合集》《CS231n深度视觉笔记》《OpenCV图像处理教程》