在这之前,我已经通过speaker Model训练获取得到声纹编码。这时,我希望这个声纹编码可以反映speaker之间的分布,如果去做?需要使用损失函数去比较prediction 和ground Truth
本次主要任务:将声纹编码经过一个分类层,得到该声音属于某一类的概率,通过训练,让概率变得更准
损失函数
1.1什么是损失函数
Prediction vs Ground Truth
每个样本经过模型之后得到一个预测值,预测值和真实值之间的差值就是损失,而计算预测值和真实值差距的一类函数就称为损失函数
1.2损失函数在声纹识别的作用
实际上是一个分类任务损失
1.3 如何将声纹编码与分类损失关联?
使用classifier 或者 classification layer
本次研究的损失函数有以下几种:
1.4 几种损失函数
1.4.1 softmax with cross-entropy
主要理解它就可以 后面的几个都是基于其作的改善和优化,基本上就是三角函数的变换
参考链接:
-
- blog.csdn.net/u014380165/…
感官上来说:把不是0-1的数,转为0-1的概率值输出
N = 192 (声纹编码维度)
T = 5994 (Mumber of speaker & class)–T代表类别数,此处表示有5994类,最后的全联接层是5994 相当于是5994选1
Ground Truth:[T * 1] (one hot)
- blog.csdn.net/u014380165/…
其中Z是 W * x的值(两个向量相乘)
softmax的输出向量就是该样本属于各个类的概率。
softmax的问题
分类完成之后有可能出现 同一类型的差距反而比不同类型的差距大,所以我希望,改进成相同类型的差距变小,不同类型的差距变大,由此,使用一个更好的损失函数
1.4.2 Triple Loss (2015年的model)-缺点-效率低
参考链接:zhuanlan.zhihu.com/p/462539667
1.4.3 L-Softmax
其实就是将softmax 公式中的cos函数改成了ψ函数
参考链接:blog.csdn.net/s000da/arti…
主要目的就是为了让目标类型的角度变小
最终使用函数为:
就是将原本softmax的过程中,将原本正确的分类概率中计算公式的cos(θ)改成了cos(mθ)
1.4.4 SphereFace — A-softmax
参考链接:blog.csdn.net/s000da/arti…
1.4.5 Center Loss
用softmax + 数据到该类中心的距离
1.5 Feature Normalization(特征归一化)
1.5.1 作用
前提结论:若A向量和B向量都做了归一化,则L2 dis = cos dis
公式转换之后,决定一个数据在每一类的概率只取决于cos(θ)(角度),从而使系统聚焦于角度
1.5.2 为什么要乘以一个系数
这个系数一般很大 取30 50之类的数字
- 1。若不乘系数,则因为所有向量的模都是1,则所有的feature分布在一个以半径为1的球面中(不确定)无法分的很清楚,半径扩大,则表示更清晰
- 2.feature normal之后有问题 -cos(θ)《=1,但是softmax中需要取指数,乘系数后分的更清楚
1.6AMSoftmax & Cosface
这两个文章做的是同一件事情
1.7 AAM Softmax
代码步骤简述:
... #调用之前需要先自定义损失函数类,此处使用的是AAMsoftmax
#实例化自己的损失函数
self.speaker_loss = AAMsoftmax(n_class = n_class, m = m, s = s).cuda()
...
#获取到声纹编码之后
speaker_embedding = self.speaker_encoder.forward(data.cuda(), aug = True)#获取speaker_embedding
#将speaker_embedding 和 labels放入loss函数中 nloss-》loss的值 prec:训练后 预测的准确度
nloss, prec = self.speaker_loss.forward(speaker_embedding, labels)
nloss, prec = self.speaker_loss.forward(speaker_embedding, labels)
nloss.backward()#将loss回传给整个的network
self.optim.step()#更新network -本次训练已完成
#下面是打印准确度等
index += len(labels)
top1 += prec #循环完成后所有的准确度 --Acc = 所有准确度/训练总数据
loss += nloss.detach().cpu().numpy()#Loss = 所有的loss/mimibatch总数
sys.stderr.write(time.strftime("%m-%d %H:%M:%S") +
" [%2d] Lr: %5f, Training: %.2f%%, " %(epoch, lr, 100 * (num / loader.__len__())) +
" Loss: %.5f, ACC: %2.2f%% r" %(loss/(num), top1/index*len(labels)))
其中损失函数类AASoftmax如下
import torch, math
import torch.nn as nn
import torch.nn.functional as F
from tools import *
class AAMsoftmax(nn.Module): #基本就是按照公式进行三角函数的变换
def __init__(self, n_class, m, s):# n_class 多少类的label,m:cosa+m中m的值,s:scalfaster
super(AAMsoftmax, self).__init__()
self.m = m
self.s = s
self.weight = torch.nn.Parameter(torch.FloatTensor(n_class, 192), requires_grad=True)
self.ce = nn.CrossEntropyLoss()
nn.init.xavier_normal_(self.weight, gain=1)
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, x, label=None):
# 将speaker embedding 和 weight 都normalize之后相乘获取的就是cos的值
cosine = F.linear(F.normalize(x), F.normalize(self.weight))
sine = torch.sqrt((1.0 - torch.mul(cosine, cosine)).clamp(0, 1))#sin
#以下就是三角函数的变换
phi = cosine * self.cos_m - sine * self.sin_m
phi = torch.where((cosine - self.th) > 0, phi, cosine - self.mm)
one_hot = torch.zeros_like(cosine)
one_hot.scatter_(1, label.view(-1, 1), 1)
output = (one_hot * phi) + ((1.0 - one_hot) * cosine)
output = output * self.s
loss = self.ce(output, label)#获得损失(output 预测 )
prec1 = accuracy(output.detach(), label.detach(), topk=(1,))[0]
return loss, prec1