Arcface 总结

目录

公式理解:

 L2归一化后欧拉距离的平方和cosine相似度等价

L1距离 L2距离:

ArcFace简介

对于torch中一些函数的理解

ArcMarginmodel:


公式理解:

通俗易懂-arcface - 知乎

 L2归一化后欧拉距离的平方和cosine相似度等价

深度学习|L2归一化后欧拉距离的平方和cosine相似度等价 - 知乎

L1距离 L2距离:

举例:其中I1和I2是p维向量,例如I1=[0, 1],I2=[1, 2]。则p=2,d1(I1,I2) = 2, d2(I1, I2) = √2.

如果I1=[0, 1],I2=[1, 0]。则p=2,d1(I1,I2) = 2, d2(I1, I2) = √2,说明距离有偏差的。

解释一下为什么L1距离图像为什么为正方形,而L2距离图像为圆
我们以二维空间为例:对于L1,他计算的是第一维差的绝对值加上第二维差的绝对值,可以想象成直角三角形的两条直角边的长度和。对于L2,他计算的是第一维差的平方加上第二维差的平方再求和,然和开根。由勾股,可以想象成直角三角形的斜边长。
当距离一定时,若以I1为原点,则I2所有可能的点即为上述图像。

原文链接:https://blog.csdn.net/u011851421/article/details/102728783

ArcFace简介

转自:ArcFace简介 - 知乎

详细介绍:人脸识别合集 | 10 ArcFace解析 - 知乎

LFW上99.83%,YTF上98.02%。用了580万数据训练

cfp-fp  agedb-30 lfw 
0.8986    0.9347 99.18

88.80 91.2 99.03

https://github.com/foamliu/MobileFaceNet-PyTorch

Accuracy    LFW    MegaFace    Download
paper    99.55%    92.59%    
ours    99.48%    82.55%    Link

https://github.com/xuexingyu24/MobileFaceNet_Tutorial_Pytorch

model zoo中有对齐的数据集

Download training and evaluation data from Model Zoo. All training data has been cropped, aligned and resized as 112 x 112. Put images and annotation files into "data_set" folder. The structure should be arranged as follows:

插播:这也是数据集:

Eval TypeScoreLFWAgeDB-30CFP-FP
FlipL299.5296.3092.93
FlipCos99.5096.1892.84
UnFlipL299.4595.6393.10
UnFlipCos99.4595.6593.10

精度比较高

https://github.com/ZhaoJ9014/face.evoLVe.PyTorch#Data-Zoo

有权重 ir50,166m backbone_ir50_asia

没有准确率,但是有人脸数据集

https://github.com/isLouisHsu/MobileFaceNet_ArcFace_Darknet

简单来说,

1.feature转换为512维特征,

2.再用矩阵乘法转换为分类数。

https://github.com/TreB1eN/InsightFace_Pytorch

先把InsightFace中ArcFace代码贴出来: 

class Arcface(Module):
    # implementation of additive margin softmax loss in https://arxiv.org/abs/1801.05599    
    def __init__(self, embedding_size=512, classnum=51332,  s=64., m = 0.5):
        super(Arcface, self).__init__()
        self.classnum = classnum
        self.kernel = Parameter(torch.Tensor(embedding_size, classnum))
        # initial kernel
        self.kernel.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5) #uniform_(-1, 1)服从均匀分布,mul_对应点相乘
        self.m = m # the margin value, default is 0.5
        self.s = s # scalar value default is 64, see normface https://arxiv.org/abs/1704.06369
        self.cos_m = math.cos(m)
        self.sin_m = math.sin(m)
        self.mm = self.sin_m * m  # issue 1
        self.threshold = math.cos(math.pi - m)
    def forward(self, embbedings, label):
        # weights norm
        nB = len(embbedings)
        kernel_norm = l2_norm(self.kernel, axis=0)
        # cos(theta+m)
        cos_theta = torch.mm(embbedings, kernel_norm)#进行矩阵乘法
#         output = torch.mm(embbedings,kernel_norm)
        cos_theta = cos_theta.clamp(-1,1) # for numerical stability
        cos_theta_2 = torch.pow(cos_theta, 2)
        sin_theta_2 = 1 - cos_theta_2
        sin_theta = torch.sqrt(sin_theta_2)
        cos_theta_m = (cos_theta * self.cos_m - sin_theta * self.sin_m)
        # this condition controls the theta+m should in range [0, pi]
        #      0<=theta+m<=pi
        #     -m<=theta<=pi-m
        cond_v = cos_theta - self.threshold
        cond_mask = cond_v <= 0
        keep_val = (cos_theta - self.mm) # when theta not in [0,pi], use cosface instead
        cos_theta_m[cond_mask] = keep_val[cond_mask]
        output = cos_theta * 1.0 # a little bit hacky way to prevent in_place operation on cos_theta
        idx_ = torch.arange(0, nB, dtype=torch.long)
        output[idx_, label] = cos_theta_m[idx_, label]
        output *= self.s # scale up in order to make softmax work, first introduced in normface
        return output


对于torch中一些函数的理解

1)对于self.kernel = Parameter(torch.Tensor(embedding_size, classnum))中,Parameter的作用:

首先可以把Parameter理解为类型转换函数,将一个不可训练的类型Tensor转换成可以训练的类型parameter并将这个parameter绑定到这个module里面(net.parameter()中就有这个绑定的parameter,所以在参数优化的时候可以进行优化的),所以经过类型转换这个self.kernel变成了模型的一部分,成为了模型中根据训练可以改动的参数了。使用这个函数的目的也是想让某些变量在学习的过程中不断的修改其值以达到最优化。(摘自:原文链接:https://blog.csdn.net/qq_36955294/article/details/88117170)

看了torch官网的解释:
"Variable的一种,常被用于模块参数(module parameter)。

Parameters 是 Variable 的子类。Paramenters和Modules一起使用的时候会有一些特殊的属性,即:当Paramenters赋值给Module的属性的时候,他会自动的被加到 Module的 参数列表中(即:会出现在 parameters() 迭代器中)。将Varibale赋值给Module属性则不会有这样的影响。 这样做的原因是:我们有时候会需要缓存一些临时的状态(state)"

这句话中,embedding_size = 512,classnum是人脸识别的ID数,先使用orch.Tensor,生成一个512×classnum的张量,然后通过Parameter将这个张量转化为可以训练的模型;

2)对于self.kernel.data.uniform_(-1, 1).renorm_(2, 1, 1e-5).mul_(1e5)  的理解:

#uniform_(from=-1, to=1) → Tensor    将tensor用从均匀分布中抽样得到的值填充。

# renorm_返回一个张量,包含规范化后的各个子张量,使得沿着2维划分的各子张量的1范数小于1e-5

# mul_用标量值1e5乘以输入input的每个元素,并返回一个新的结果张量;

以上是对pytorch中一些函数的理解;

对于arcface公式的代码实现

对于arcFace的实现实际应该是包括两部分,第一部分是cosin函数部分;第二部分就是常规的softmax部分;

在pytorch代码中,第二部分直接有函数实现,是可以直接使用的;所以重点是cosin函数部分的实现;

下面就重点讲解记录一下怎样一步步的实现第一部分代码:

1)对Feature进行了l2 norm,对参数也进行了l2 norm.所以权值参数×feature = cos theta

2)将cos theta夹逼到【-1, 1】之间,因为cos theta的定义域在【0,pi】值域实在【-1,1】之间;

3)计算cos(theta + m)使用到余弦定理;

4)计算完成后,要判断theta是否超出范围,进行数据调整,这一块的判读原理在下图:

(不知道这样理解是否有错?望大佬赐教)

判断后得出一个值为0或1的mask,通过使用cos_theta_m[cond_mask] = keep_val[cond_mask],将超出范围的值使用keep_val表示,加入[cond_mask],是将mask为1(True)位置的元素取出,进行修改;

https://github.com/foamliu/InsightFace-v2

https://github.com/foamliu/InsightFace-PyTorch

ArcMarginmodel:

这个使用线性回归来替代矩阵相乘,区别就是看看好不好收敛吧

class ArcMarginModel(nn.Module):
    def __init__(self, args):
        super(ArcMarginModel, self).__init__()

        self.weight = Parameter(torch.FloatTensor(num_classes, args.emb_size))
        nn.init.xavier_uniform_(self.weight)

        self.easy_margin = args.easy_margin
        self.m = args.margin_m
        self.s = args.margin_s

        self.cos_m = math.cos(self.m)
        self.sin_m = math.sin(self.m)
        self.th = math.cos(math.pi - self.m)
        self.mm = math.sin(math.pi - self.m) * self.m

    def forward(self, input, label):
        x = F.normalize(input)
        W = F.normalize(self.weight)
        cosine = F.linear(x, W)
        sine = torch.sqrt(1.0 - torch.pow(cosine, 2))
        phi = cosine * self.cos_m - sine * self.sin_m  # cos(theta + m)
        if self.easy_margin:
            phi = torch.where(cosine > 0, phi, cosine)
        else:
            phi = torch.where(cosine > self.th, phi, cosine - self.mm)
        one_hot = torch.zeros(cosine.size(), device=device)
        one_hot.scatter_(1, label.view(-1, 1).long(), 1)
        output = (one_hot * phi) + ((1.0 - one_hot) * cosine)
        output *= self.s

        return output


 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值