关于相关理论知识,可以去看看下面这篇论文,
王微. 融合全局和局部信息的度量学习方法研究[D].合肥:中国科学技术大学,2014
关于Maximally Collapsing Metric Learning(简称MCML),我一开始没找的那种实现好的代码,然后我就自己看理论写了一个,当然了我这个实现是一个很low的版本了,希望后期有大佬可以重新写吧,我这个代码应该没啥大问题,如果有问题的话,欢迎大家提出解决办法,一起成长。
关于其中的M矩阵,我并没有具体实现,我写一个简单的公式,我想就可以明白了,y = F(x),
利用模型训练巧妙的避开了其中的M参数,但结果还是蛮好的。
我是在最后一层计算MCML的,其实可以考虑在特征提取过后就进行MCML,然后更新,可能效果会更好一点。
我的3060直接放弃了,有能力的小伙伴可以继续尝试。
#版本3,矩阵优化
class MCML_Loss(nn.Module):
#第二种实现,F(x) 维度 (bs,512)
def __init__(self):
super(MCML_Loss, self).__init__()
self.KL = nn.KLDivLoss(reduction="batchmean") #KL散度
def forward(self, x, labels):
# one = time.time()
label = labels.cpu()
bs = x.shape[0]
P = torch.ones([bs, bs]).cuda() #根据真实标签计算条件概率
D = torch.cdist(x, x, p=2)
Q_E = (-D).exp()
Q_E = Q_E - torch.diag_embed(torch.diag(Q_E)) #设置i=j的元素都为0,不用担心log0的存在 KL散度y(logy-logy') 其中y=y'=0
fm_sum = torch.sum(Q_E,dim=1) #构建条件概率分母 每一行运算出的结果 张量形状(bs)
fm_sum = torch.reshape(fm_sum,(-1,1))
Q = torch.div(Q_E, fm_sum)
number = 0
for i in label:
indexs = np.argwhere(label==i)
for j in indexs:
P[number][j] = 0
number +=1
# input should be a distribution in the log space
q = F.log_softmax(Q)
# Sample a batch of distributions. Usually this would come from the dataset
p = F.softmax(P)
loss = self.KL(q, p)
return loss