arcface损失函数在mnist数据集上的实现

arcface loss是人脸识别中的损失函数,对于人脸识别还有一个常用的损失函数centerloss,但centerloss存在比较大的缺陷,那就是当类别比较多时,GPU内存要求比较高,比较耗费算力。并且在效果上arcface loss的效果要优于centerloss,因为前者是基于角度,而后者是基于距离,对于分类来说,arcfaceloss的影响更加直接。

说起arcfaceloss就不得不提一下向量相关知识。

1、什么是向量的相关性?两个向量之间有哪几种相关性?

      向量的相关性是指两个向量之间的差异,差异越小,相关性越大;

      两个向量之间有:正相关、负相关、不相关

2、向量相关性的表示方法?

     2.1、欧式距离(L2距离):

     2.2、余弦相似度:

                                值越大即夹角越小,相关度越大,反之,值越小夹角越大,相关度越小、

    2.3、余弦距离:

                                 值域为[0,2],值越大,相关性越小,值越小,相关性越大

3、一般来说,空间中的两个向量,欧式距离越小,余弦相似度越小,相关性越大,但是相关性越大,欧氏距离不一定就小。

      若要使空间两个向量的欧式距离和余弦相似度具有等价性,必须给两个向量做二范数归一化,此时,欧氏距离越小,相关性          越大

下面切入正文,首先提出第一个问题,arcface loss是基于角度的,那这个角度从哪里来?

看一下下面这个公式,是不是感觉挺熟悉,其实就是softmaxloss,它的演变过程其实就是把softmax中的输入改写成wx+b,然后将bias设置为0,然后将两个向量的内积改写一下,就是多看到的这样,这就出现了角度θ。

那arcface loss是如何实现更好的分类效果呢?其实就是在θ上加上一个角度,让两个向量分的更开(在arcface之前还有A-softmaxloss和AM-softmaxloss,前者是增加角度乘积系数方式来增大角度分类,但倍角公式求导不变,后者是减小相似度系数来增加向量之间的距离,但效果不如arcface)

arcface损失函数公式如下:

值得注意的是:上式中,s为超球面的半径,m为margin是弧度,1弧度等于57.3°

arcface的训练没有什么难度,超参数一般设置为1。

效果如下:

代码:

import torch
import torch.nn as nn
import torch.nn.functional as F

class ArcNet(nn.Module):
    def __init__(self):
        super(ArcNet, self).__init__()
        self.W=nn.Parameter(torch.randn(2,10),requires_grad=True)
    def forward(self,feature,m=1):
        x=F.normalize(feature,dim=1)
        w=F.normalize(self.W,dim=0)
        cosa=torch.matmul(x,w)/(torch.sqrt(torch.sum(torch.pow(w,2)))*torch.sqrt(torch.sum(torch.pow(x,2))))#torch.Size([100, 10])
        s=torch.sqrt(torch.sum(torch.pow(x,2)))*torch.sqrt(torch.sum(torch.pow(w,2)))
        a=torch.acos(cosa)
        arcsoftmax=torch.exp(s*torch.cos(a+m))/(torch.sum(torch.exp(s*cosa),dim=1,keepdim=True)-torch.exp(s*cosa)+torch.exp(s*torch.cos(a+m)))
        return arcsoftmax

import torchvision
import torch
import torch.nn as nn
import torch.utils.data as data
import torchvision.transforms as transforms
from My_Net import Net
import os

if __name__ == '__main__':
    if not os.path.exists("./models"):
        os.makedirs("./models")
    save_path="models/net_arcface_pth"
    if not os.path.exists("./images"):
        os.makedirs("./images")
    trans=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.5],[0.5])
    ])
    train_data=torchvision.datasets.MNIST(root="./MNIST",train=True,transform=trans,download=False)
    train_load=data.DataLoader(train_data,batch_size=100,shuffle=True,num_workers=4)
    device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
    net=Net().to(device)
    loss_fn=nn.NLLLoss()
    optimizer=torch.optim.Adam(net.parameters())
    if os.path.exists(save_path):
        net.load_state_dict(torch.load(save_path))
    else:
        print("No Param")
    epoch=0
    while epoch<100:
        feat_loader,label_loader=[],[]
        for i,(X,Y) in enumerate(train_load):
            x=X.to(device)
            y=Y.to(device)
            feature,output=net(x)
            loss=loss_fn(output,y)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            feat_loader.append(feature)
            label_loader.append(y)
            if i%100==0:
                print("epoch:",epoch,"\t","i:",i,"\t","arcsoftmax_loss:{:.3f}".format(loss.item()))
        feat=torch.cat(feat_loader,0)
        labels=torch.cat(label_loader,0)
        net.visualize(feat.data.cpu().numpy(),labels.data.cpu().numpy(),epoch)
        epoch+=1
        torch.save(net.state_dict(),save_path)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值