facenet

一:人脸识别常用数据集及其发展

在这里插入图片描述
在这里插入图片描述

一:人脸识别常用方法

1、主流路线

1:比较的方法(相同离得近,不同离得远)
2:朴素的分类网络(逐渐发展为改变softmax)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、Triplet loss的缺点

在这里插入图片描述

三:Facenet

1、什么是Facenet

   谷歌人脸识别算法,发表于 CVPR 2015,利用人脸在不同角度等姿态的照片下有高内聚性,不同人脸	有低耦合性,提出使用 cnn + triplet mining 方法,在LFW数据集上准确度达到 99.63%。

通过 CNN 将人脸映射到欧式空间的特征向量上,实质上:不同图片人脸特征的距离较大;通过相同个体的人脸的距离,总是小于不同个体的人脸这一先验知识训练网络。

测试时只需要计算人脸特征EMBEDDING,然后计算距离使用阈值即可判定两张人脸照片是否属于相同的个体。

在这里插入图片描述

2、主干网络介绍

facenet的主干网络起到提取特征的作用,原版的facenet以Inception-ResNetV1为主干特征提取网络。

本文一共提供了两个网络作为主干特征提取网络,分别是mobilenetv1和Inception-ResNetV1(当时更为先进的网络还没有出来),二者都起到特征提取的作用,为了方便理解,本博文中会使用mobilenetv1作为主干特征提取网络。

MobilenetV1模型是Google针对手机等嵌入式设备提出的一种轻量级的深层神经网络,其使用的核心思想便是depthwise separable convolution(深度可分离卷积块),其结构如下所示。

在这里插入图片描述
深度可分离卷积块由两个部分组成,分别是深度可分离卷积和1x1普通卷积,深度可分离卷积的卷积核大小一般是3x3的,我们可以把它当作是特征提取,1x1的普通卷积可以完成通道数的调整。

在这里插入图片描述
MobileNet的结构如下,其中Conv dw就是分层卷积,在其之后都会接一个1x1的卷积进行通道处理。

在这里插入图片描述

3、构建分类器(用于辅助Triplet Loss的收敛)

仅仅只是用Triplet Loss会使得整个网络难以收敛,本文结合Cross-Entropy Loss和Triplet Loss作为总体loss。

Triplet Loss用于进行不同人的人脸特征向量欧几里得距离的扩张,同一个人的不同状态的人脸特征向量欧几里得距离的缩小。
Cross-Entropy Loss用于人脸分类,具体作用是辅助Triplet Loss收敛。

想要利用Cross-Entropy Loss进行训练需要构建分类器,因此我们在原网络的最后增加一个全连接层用于分类。

在进行网络的训练的时候,可使用分类器辅助训练,在预测的时候,分类器是不需要的,其结构如下。

class Facenet(nn.Module):
    def __init__(self, backbone="mobilenet", dropout_keep_prob=0.5, embedding_size=128, num_classes=None, mode="train"):
        super(Facenet, self).__init__()
        if backbone == "mobilenet":
            self.backbone = mobilenet()
            flat_shape = 1024
        elif backbone == "inception_resnetv1":
            self.backbone = inception_resnet()
            flat_shape = 1792
        else:
            raise ValueError('Unsupported backbone - `{}`, Use mobilenet, inception_resnetv1.'.format(backbone))
        self.avg = nn.AdaptiveAvgPool2d((1,1))
        self.Dropout = nn.Dropout(1 - dropout_keep_prob)
        self.Bottleneck = nn.Linear(flat_shape, embedding_size,bias=False)
        self.last_bn = nn.BatchNorm1d(embedding_size, eps=0.001, momentum=0.1, affine=True)
        if mode == "train":
            self.classifier = nn.Linear(embedding_size, num_classes)

    def forward(self, x):
        x = self.backbone(x)
        x = self.avg(x)
        x = x.view(x.size(0), -1)
        x = self.Dropout(x)
        x = self.Bottleneck(x)
        x = self.last_bn(x)
        x = F.normalize(x, p=2, dim=1)
        return x

    def forward_feature(self, x):
        x = self.backbone(x)
        x = self.avg(x)
        x = x.view(x.size(0), -1)
        x = self.Dropout(x)
        x = self.Bottleneck(x)
        before_normalize = self.last_bn(x)
        x = F.normalize(before_normalize, p=2, dim=1)
        return before_normalize, x

    def forward_classifier(self, x):
        x = self.classifier(x)
        return x

3、Triplet Loss在这里插入图片描述

Triplet Loss的输入是一个三元组

a:anchor,基准图片获得的128维人脸特征向量
p:positive,与基准图片属于同一张人脸的图片获得的128维人脸特征向量
n:negative,与基准图片不属于同一张人脸的图片获得的128维人脸特征向量
我们可以将anchor和positive求欧几里得距离,并使其尽量小。
我们可以将negative和positive求欧几里得距离,并使其尽量大。

我们所使用的公式为。
Loss=max(d(a,p)−d(a,n)+margin,0)
d(a,p)就是anchor和positive的欧几里得距离。我们希望,同一个人的不同状态的人脸特征向量欧几里得距离小。
d(a,n)就是negative和positive的欧几里得距离。我们希望不同人的人脸特征向量欧几里得距离大
margin是一个常数。

#####triplet_loss代码如下################

def triplet_loss(alpha = 0.2):
    def _triplet_loss(y_pred,Batch_size):
        anchor, positive, negative = y_pred[:int(Batch_size)], y_pred[int(Batch_size):int(2*Batch_size)], y_pred[int(2*Batch_size):]

        pos_dist = torch.sqrt(torch.sum(torch.pow(anchor - positive,2), axis=-1))
        neg_dist = torch.sqrt(torch.sum(torch.pow(anchor - negative,2), axis=-1))
        #neg_dist - pos_dist < alpha,不同图片差距过大没有意义(太容易识别),故设置alpha值
        keep_all = (neg_dist - pos_dist < alpha).cpu().numpy().flatten()
        hard_triplets = np.where(keep_all == 1)

        pos_dist = pos_dist[hard_triplets].cuda()
        neg_dist = neg_dist[hard_triplets].cuda()

        basic_loss = pos_dist - neg_dist + alpha
        #该批次中满足neg_dist - pos_dist < alpha的平均损失
        loss = torch.sum(basic_loss)/torch.max(torch.tensor(1),torch.tensor(len(hard_triplets[0])))
        return loss
    return _triplet_loss

本文参考:https://blog.csdn.net/weixin_44791964/article/details/108220265,在此特别感谢该博主的无私贡献

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值