对比学习triple loss

对比学习与多分类学习密切相关,包括对比学习损失和softmax分类损失的相关,最大的差别也就是距离的约束条件不同,也可以说是损失函数的不同。因为我目前做的是二分类,所以先简单的看一下二分类的损失。

1、使用交叉熵函数用于分类的损失的原理是:对比学习triple loss_第1张图片

对某一个样本正确的标签也就是1乘某样本预测正确的概率 ,得到每个样本的损失,然后所有样本的损失求平均,得到模型的损失。不同的模型就算最后得到预测正确的结果是一样的,但是概率的差距可能不同,因此交叉熵损失能够衡量模型的性能差异。损失越小表示性能越好

sigmoid(softmax)+cross-entropy loss 擅长于学习类间的信息,因为它采用了类间竞争机制,它只关心对于正确标签预测概率的准确性,忽略了其他非正确标签的差异,导致学习到的特征比较散。基于这个问题的优化有很多,比如对softmax进行改进,如L-Softmax、SM-Softmax、AM-Softmax等。

softmax损失是衡量

均匀性有助于对比学习学习可分离的特征,但过分追求均匀性会使对比损失对语义相似的样本无法容忍,这可能会破坏潜在的语义结构,不利于形成对下游任务有用的特征。容忍性是指

2、对比学习triple loss

2.1原理

其中a表示anchor,d(a,p)表示锚点与正样本之间的距离,d(a,n)表示锚点与负样本之间的距离。triple loss的目的是想要正样本与锚点的距离近,负样本与锚点之间的距离远。如果满足的话,那么逗号前面的就是负数,最后去最大值0,表示这个确实是符合我们的期望。

为什么要加margin呢,因为如果不加的话,只要正样本与负样本与anchor之间的距离相等就可以,还是难以区分某些正负样本。所以加一个常数margin,使模型能够更好的区分正负样本,但是太大的话模型损失会比较大,造成不收敛的情况。因此这个超参数也需要好好调试。

2.2代码分析

class TripletLoss(nn.Module):

    def __init__(self, margin=0.3, batch_size=32, view_num=3):
        super(TripletLoss, self).__init__()
        self.margin = margin
        self.ranking_loss = nn.MarginRankingLoss(margin=margin)   #排序函数,实现d(a,p),d(a,n),margin之间的大小比较

    def forward(self, inputs,targets = None):
        """
        Args:
            inputs (torch.Tensor): feature matrix with shape (batch_size, feat_dim).
            targets (torch.LongTensor): ground truth labels with shape (num_classes).
            input(batchsize32,2)softmax之后的结果 一定要是两维的,因为dist要弄成一维的才能进行expand
            targets(32)也就是标签
        """
        if targets == None:
            targets = self.targets
        n = inputs.size(0)

        # Compute pairwise distance, replace by the official when merged
        #意思其实就是给了32个点,将每个点转换成一个数来表示,也就是将二维转换成一维表示
        dist = torch.pow(inputs, 2).sum(dim=1, keepdim=True).expand(n, n)
        dist = dist + dist.t()
        dist.addmm_(1, -2, inputs, inputs.t())
        dist = dist.clamp(min=1e-12).sqrt()  # for numerical stability
        # For each anchor, find the hardest positive and negative
        #对lable进行mask的转换,大家可以举一个例子试一下,最终得到的mask是一个32*32的,对于第i个元素来说第i维中是1的就是positive,是0的就是negitave,
        mask = targets.expand(n, n).eq(targets.expand(n, n).t())
        dist_ap, dist_an = [], []
        #dist_ap中存的是对于每一个anchor来说最远的正样本的距离,dist_an存的是对于每一个anchor来说最近的负样本的距离
        for i in range(n):
            dist_ap.append(dist[i][mask[i]].max().unsqueeze(0))
            dist_an.append(dist[i][mask[i] == 0].min().unsqueeze(0))
        dist_ap = torch.cat(dist_ap)
        dist_an = torch.cat(dist_an)

        # Compute ranking hinge loss
        #计算排序损失也就说对于每一个样本来说,是不是满足那个原理
        y = torch.ones_like(dist_an)
        x=self.ranking_loss(dist_an, dist_ap, y)
        return self.ranking_loss(dist_an, dist_ap, y)

选了最大的正样本距离和最小的负样本距离就是寻找难样本。欧式距离就是m维空间中两个点之间的距离,我比较怀疑这将点转换成一个点进行距离度量可行性多少,还需在看文章,看完了更新。

我还是太菜了,继续努力!

你可能感兴趣的:(学习,人工智能)