整理:TripletMarginLoss、nn.MarginRankingLoss

在pytorch中,提供了两个损失函数,都与triplet loss相关。但是使用的方式不一样。

 

一、TripletMarginLoss

这个就是最正宗的Triplet Loss的实现。它的输入是anchor, positive, negative三个B*N的张量(表示Batchsize个N为的特征向量),输出triplet loss的值。

定义为:

criterion = torch.nn.TripletMarginLoss(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction='mean')

参数:

margin (float) – 默认为1
p (int) – norm degree,默认为2
reduction (string) – 指定返回各损失值(none),批损失均值(mean),批损失和(sum),默认返回批损失均值(mean)
 

使用:

loss = criterion(anchor, positive, negative)

输入三个二维张量,每个向量的尺寸:(B,N),B为批量大小,N为张量维度

 

计算方法为:

整理:TripletMarginLoss、nn.MarginRankingLoss_第1张图片

最后对这B个loss,求平均或者求和(根据reduction的设置不同而定)

 

举例:

import torch

criterion = torch.nn.TripletMarginLoss(margin=0.3, p=2, reduction='mean')

anchor = torch.Tensor([[1, 0, 1], [1,1,1]])  #2*3的向量,表示batchsize=2,3维向量。
positive = torch.Tensor([[4, 1, 5], [2,2,2]])
negative = torch.Tensor([[3, 1, 2], [1,1,2]])

loss = criterion(anchor, positive, negative)
print(loss)

结果为:

验证:

具体怎么算出来的呢?

对于第一组向量:a = [1,0,1], p=[4,1,5], n =[3,1,2]

dap = math.sqrt((1-4)^2 + (0-1)^2 + (1-5)^2 ) = math.sqrt(9 +1 + 16) = 5.099

dan = math.sqrt((1-3)^2 + (0-1)^2 + (1-2)^2 ) = math.sqrt(4 + 1 +1) = 2.4495

max (dap - dan + 0.3 , 0 ) = 2.9495

 

对于第二组向量:a = [1,1,1], p=[2,2,2], n =[1,1,2]

dap = math.sqrt((1-2)^2 + (1-2)^2 + (1-2)^2) = math.sqrt(3) = 1.732

dan = math.sqrt((1-1)^2 + (1-1)^2 + (1-2)^2) = 1

max(dap - dan + 0.3, 0) = 1.032

 

最后求平均:(2.9495 + 1.032)/2 = 1.9908

 

 

 

二、nn.MarginRankingLoss

 

定义为:

torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

 

使用:

loss = criterion(x1, x2, y)

x1、x2、y都是一个长度为B的一维向量。

 

计算方法:

举例:

import torch

criterion = torch.nn.MarginRankingLoss(margin=0.3, reduction='mean')

x1 = torch.Tensor([3, 2])
x2 = torch.Tensor([1, 4])

y = torch.Tensor([1, 2])

loss = criterion(x1, x2, y)

print(loss)

输出:

 

验证:

对于第1个点,x1=3, x2 = 1, y=1。 max(-y*(x1-x2), 0) = max(-1*(3-1)+0.3, 0) = max(-1.7, 0) = 0

对于第2个点,x1=2, x2 = 4, y=2。 max(-y*(x1-x2), 0) = max(-2*(2-4), 0) = max(4.3, 0) = 4.3

求平均:2.15

 

 

三、nn.MarginRankingLoss与TripletMarginLoss的关系

nn.marginRankingLoss不是专门用来计算triplet loss的,但是也可以用来计算triplet loss。

当用来计算triplet loss时, 与TripletMarginLoss的不同是,它的输入是不再是三个原始的向量anchor, positive, negative,而是计算好dap和dan的值,再输入进去。

 

在nn.marginRankingLoss的公式中:

如果让,y=全1向量, x1 = dan, x2 = dap ,那么:

loss = max(0, -(dan - dap) + margin) = max(dap - dan + margin, 0) 

就刚好是triplet loss的公式。

 

举例:

import torch
'''
anchor = torch.Tensor([[1, 0, 1], [1,1,1]])  #2*3的向量,表示batchsize=2,3维向量。
positive = torch.Tensor([[4, 1, 5], [2,2,2]])
negative = torch.Tensor([[3, 1, 2], [1,1,2]])


'''

criterion = torch.nn.MarginRankingLoss(margin=0.3, reduction='mean')

dap = torch.Tensor([5.099, 1.732])   #dap是一个B维的向量。如[a1,a2,a3],a1表示anchor1与positive1的距离,a2表示anchor2与positive2的距离,...
dan = torch.Tensor([2.4495, 1])      #dan是一个B维的向量。如[b1,b2,b3],b1表示anchor1与negative1的距离,b2表示anchor2与negative2的距离,...

y = torch.Tensor([1, 1])

loss = criterion(dan, dap, y)   #注意dan在前,dap在后

print(loss)   #1.99

结果:

与TripletMarginLoss中的例子的结果相同。

 

 

注意: 在计算triHard loss的时候,我们就用到了nn.marginRankingLoss来求,因为我们求困难样本的时候已经知道了距离矩阵,所以可以直接用nn.marginRankingLoss求更方便,二如果调用TripletMarginLoss的话会再求一遍距离。见实现:triHard loss的原理与实现

 

 

 

你可能感兴趣的:(11,Python/DL/ML)