loss函数之TripletMarginLoss与TripletMarginWithDistanceLoss

不同于交叉熵损失仅仅考虑样本与类别标签之间误差,triplet loss关注样本与其他样本之间距离。来自论文Learning local feature descriptors with triplets and shallow convolutional neural networks

对于包含 N N N个样本的batch数据 D ( a , p , n ) D(a, p,n) D(a,p,n)。 第 i i i个样本对应的 l o s s loss loss,如下:
l i = max ⁡ { d ( a i , p i ) − d ( a i , n i ) + margin ⁡ , 0 } l_{i}=\max \left\{d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\operatorname{margin}, 0\right\} li=max{d(ai,pi)d(ai,ni)+margin,0}
其中, a a a p p p n n n,分别代表锚点,正例(与锚点同类)和负例(与锚点不同类)。距离函数 d d d, 用于度量锚点与正例负例之间的距离。 m a r g i n margin margin是人为设置的常数。最小化损失函数,使得锚点与正例的距离越小,与负例的距离越大。

由以上公式可知,

(1) 当 d ( a i , p i ) − d ( a i , n i ) + margin ⁡ < 0 d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\operatorname{margin}<0 d(ai,pi)d(ai,ni)+margin<0,即 d ( a i , n i ) > d ( a i , p i ) + margin ⁡ d\left(a_{i}, n_{i}\right) > d\left(a_{i}, p_{i}\right)+\operatorname{margin} d(ai,ni)>d(ai,pi)+margin, 该样本对应的 l o s s loss loss为0。

此时,锚点和负例的距离大于锚点和正例的距离,并且差值大于 m a r g i n margin margin。 对于这样的锚点被认为是易分类样本,直接忽略其带来的误差,从而加速计算。

(2) 当 d ( a i , p i ) − d ( a i , n i ) + margin ⁡ > 0 d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\operatorname{margin}>0 d(ai,pi)d(ai,ni)+margin>0, 该样本对应的 l o s s loss loss d ( a i , p i ) − d ( a i , n i ) + margin ⁡ d\left(a_{i}, p_{i}\right)-d\left(a_{i}, n_{i}\right)+\operatorname{margin} d(ai,pi)d(ai,ni)+margin, 分为两种情况:

  • d ( a i , p i ) + margin ⁡ > d ( a i , n i ) > d ( a i , p i ) d\left(a_{i}, p_{i}\right)+\operatorname{margin}>d\left(a_{i}, n_{i}\right)>d\left(a_{i}, p_{i}\right) d(ai,pi)+margin>d(ai,ni)>d(ai,pi) , 对应难分类样本。

  • d ( a i , p i ) + margin ⁡ > d ( a i , p i ) > d ( a i , n i ) d\left(a_{i}, p_{i}\right)+\operatorname{margin}>d\left(a_{i}, p_{i}\right)>d\left(a_{i}, n_{i}\right) d(ai,pi)+margin>d(ai,pi)>d(ai,ni) ,对应非常难分类样本,容易误分类

TripletMarginLoss
class TripletMarginLoss(_Loss):
    __constants__ = ['margin', 'p', 'eps', 'swap', 'reduction']
    def __init__(self, margin=1.0, p=2., eps=1e-6, swap=False, size_average=None,
                 reduce=None, reduction='mean'):
        super(TripletMarginLoss, self).__init__(size_average, reduce, reduction)
        self.margin = margin
        self.p = p
        self.eps = eps
        self.swap = swap
    def forward(self, anchor, positive, negative):
        return F.triplet_margin_loss(anchor, positive, negative, margin=self.margin, p=self.p,
                                     eps=self.eps, swap=self.swap, reduction=self.reduction)

pytorch中通过torch.nn.TripletMarginLoss类实现,也可以直接调用F.triplet_margin_loss 函数。size_averagereduce已经弃用。reduction有三种取值mean, sum, none,对应不同的返回 ℓ ( a , p , n ) \ell(a, p, n) (a,p,n) 。 默认为mean,对应于一般情况下整体 l o s s loss loss的计算。

L = { l 1 , … , l N } L=\left\{l_{1}, \ldots, l_{N}\right\} L={l1,,lN}

ℓ ( a , p , n ) = { L ,  if reduction  =  ’none’  1 N ∑ i = 1 N l i ,  if reduction  =  ’mean’  ∑ i = 1 N l i ,  if reduction  =  ’sum’  \ell(a, p, n)=\left\{\begin{array}{ll} L, & \text { if reduction }=\text { 'none' } \\ \frac{1}{N} \sum_{i=1}^{N} l_{i}, & \text { if reduction }=\text { 'mean' } \\ \sum_{i=1}^{N} l_{i}, & \text { if reduction }=\text { 'sum' }\end{array}\right. (a,p,n)=L,N1i=1Nli,i=1Nli, if reduction = ’none’  if reduction = ’mean’  if reduction = ’sum’ 

该类默认使用如下距离函数, p p p默认为2,对应欧式距离。

d ( x i , y i ) = ∥ x i − y i ∥ p d\left(x_{i}, y_{i}\right)=\left\|\mathbf{x}_{i}-\mathbf{y}_{i}\right\|_{p} d(xi,yi)=xiyip

pytorch也有计算该距离的函数torch.nn.PairwiseDistance

例子:

import torch
import torch.nn as nn
torch.manual_seed(20)
triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
output = triplet_loss(anchor, positive, negative)
print(output.item())
# none
triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2, reduction="none")
output = triplet_loss(anchor, positive, negative)
print(output.size())

结果:

1.1951137781143188
torch.Size([100])
TripletMarginWithDistanceLoss

该loss函数与 TripletMarginLoss功能基本一致,只不过可以定制化的传入不同的距离函数。当传入的距离函数是torch.nn.PairwiseDistance时,两者完全一致

例子:

import torch
import torch.nn as nn
torch.manual_seed(20)
triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
triplet_loss = nn.TripletMarginWithDistanceLoss(reduction="mean", distance_function=nn.PairwiseDistance())
output = triplet_loss(anchor, positive, negative)
print(output.item())

triplet_loss = nn.TripletMarginWithDistanceLoss(reduction="none", distance_function=nn.PairwiseDistance())
output = triplet_loss(anchor, positive, negative)
print(output.size())

结果和TripletMarginLoss一致:

1.1951137781143188
torch.Size([100])

使用自定义的距离函数:

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

torch.manual_seed(20)
triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)


# Custom Distance Function
def l_infinity(x1, x2):
    return torch.max(torch.abs(x1 - x2), dim=1).values
triplet_loss = nn.TripletMarginWithDistanceLoss(distance_function=l_infinity, margin=1.5)
output = triplet_loss(anchor, positive, negative)
print(output.item())

# Custom Distance Function (Lambda)
triplet_loss = nn.TripletMarginWithDistanceLoss(
    distance_function=lambda x, y: 1.0 - F.cosine_similarity(x, y))
output = triplet_loss(anchor, positive, negative)
print(output.item())

结果:

1.529929518699646
1.0007251501083374
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
TripletMarginLossTripletMarginWithDistanceLoss是用于学习嵌入表示(embedding representation)的损失函数loss function),常用于人脸识别、图像检索等任务中。 在这两个损失函数中,输入是一组三元组(anchor,positive,negative),其中anchor是一个样本,positive是与anchor相似的样本,negative是与anchor不相似的样本。这些三元组被用来训练神经网络,使得网络能够将相似的样本嵌入到相近的空间区域中,而将不相似的样本嵌入到空间中较远的区域。 TripletMarginLoss是最简单的损失函数之一,它的目标是将相似样本之间的距离最小化,并将不相似样本之间的距离最大化。具体地,对于每个三元组(anchor,positive,negative),TripletMarginLoss定义了以下损失函数loss = max(dist(anchor, positive) - dist(anchor, negative) + margin, 0) 其中,dist表示两个样本之间的距离,margin是一个预定义的常数值,用于控制相似样本和不相似样本之间的距离差异。 TripletMarginWithDistanceLossTripletMarginLoss的扩展版本,它在计算损失时考虑了样本之间的距离。具体地,对于每个三元组(anchor,positive,negative),TripletMarginWithDistanceLoss定义了以下损失函数loss = max(dist(anchor, positive) - dist(anchor, negative) + margin, 0) + alpha * (dist(anchor, positive) + dist(anchor, negative)) 其中,alpha是一个预定义的常数值,用于平衡相似样本和不相似样本之间的距离差异和嵌入空间的紧密度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

旺旺棒棒冰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值