Pytorch实现有监督对比学习损失函数

关于对比损失

  无监督对比损失,通常视数据增强后的图像与原图像互为正例。而对于有监督对比损失来说,可以将同一batch中标签相同的视为正例,与它不同标签的视为负例。对比学习能够使得同类更近,不同类更远。有监督对比损失公式如下。

有监督对比损失数学公式

在这里插入图片描述

Pytorch实现有监督对比损失

  话不多说,直接看代码。为了更好的说明有监督对比损失的整个实现过程,以下代码没有经过系统整理,从一个例子,一步一步地计算出损失。若是理解了每一步,那系统整理应该没什么问题。

import torch
import torch.nn.functional as F




T = 0.5  #温度参数T
label = torch.tensor([1,0,1,0,1])
n = label.shape[0]  # batch

#假设我们的输入是5 * 3  5是batch,3是句向量
representations = torch.tensor([[1, 2, 3],[1.2, 2.2, 3.3],
                                [1.3, 2.3, 4.3],[1.5, 2.6, 3.9],
                                [5.1, 2.1, 3.4]])

#这步得到它的相似度矩阵
similarity_matrix = F.cosine_similarity(representations.unsqueeze(1), representations.unsqueeze(0), dim=2)
#这步得到它的label矩阵,相同label的位置为1
mask = torch.ones_like(similarity_matrix) * (label.expand(n, n).eq(label.expand(n, n).t()))

#这步得到它的不同类的矩阵,不同类的位置为1
mask_no_sim = torch.ones_like(mask) - mask

#这步产生一个对角线全为0的,其他位置为1的矩阵
mask_dui_jiao_0 = torch.ones(n ,n) - torch.eye(n, n )

#这步给相似度矩阵求exp,并且除以温度参数T
similarity_matrix = torch.exp(similarity_matrix/T)

#这步将相似度矩阵的对角线上的值全置0,因为对比损失不需要自己与自己的相似度
similarity_matrix = similarity_matrix*mask_dui_jiao_0


#这步产生了相同类别的相似度矩阵,标签相同的位置保存它们的相似度,其他位置都是0,对角线上也为0
sim = mask*similarity_matrix


#用原先的对角线为0的相似度矩阵减去相同类别的相似度矩阵就是不同类别的相似度矩阵
no_sim = similarity_matrix - sim


#把不同类别的相似度矩阵按行求和,得到的是对比损失的分母(还差一个与分子相同的那个相似度,后面会加上)
no_sim_sum = torch.sum(no_sim , dim=1)

'''
将上面的矩阵扩展一下,再转置,加到sim(也就是相同标签的矩阵上),然后再把sim矩阵与sim_num矩阵做除法。
至于为什么这么做,就是因为对比损失的分母存在一个同类别的相似度,就是分子的数据。做了除法之后,就能得到
每个标签相同的相似度与它不同标签的相似度的值,它们在一个矩阵(loss矩阵)中。
'''
no_sim_sum_expend = no_sim_sum.repeat(n, 1).T
sim_sum  = sim + no_sim_sum_expend
loss = torch.div(sim , sim_sum)


'''
由于loss矩阵中,存在0数值,那么在求-log的时候会出错。这时候,我们就将loss矩阵里面为0的地方
全部加上1,然后再去求loss矩阵的值,那么-log1 = 0 ,就是我们想要的。
'''
loss = mask_no_sim + loss + torch.eye(n, n )


#接下来就是算一个批次中的loss了
loss = -torch.log(loss)  #求-log
loss = torch.sum(torch.sum(loss, dim=1) )/(2*n)  #将所有数据都加起来除以2n

print(loss)  #0.9821
#最后一步也可以写为---建议用这个, (len(torch.nonzero(loss)))表示一个批次中样本对个数的一半
loss = torch.sum(torch.sum(loss, dim=1)) / (len(torch.nonzero(loss)))

END

  大致实现过程就是这样,如果有什么问题可以随时提出。或者有什么更好的实现方法,也欢迎共享。若你要使用该损失发文章,请引用:
  “Chen, L., Wang, F., Yang, R. et al. Representation learning from noisy user-tagged data for sentiment classification. Int. J. Mach. Learn. & Cyber. (2022). https://doi.org/10.1007/s13042-022-01622-7

### 对比学习损失函数在聚类中的应用 对于聚类任务而言,对比学习通过构建正样本对和负样本对来优化模型表示能力。具体到聚类场景下,对比学习的目标是在嵌入空间中拉近属于同一簇的数据点(即正样本),而推远来自不同簇的数据点(即负样本)。为了实现这一目标,通常采用的损失函数形式可以概括为: #### InfoNCE Loss 一种广泛使用的对比损失函数是InfoNCE (Noise Contrastive Estimation),其定义如下: \[ \mathcal{L}_{\text {infoNCE }}=\sum_{i=1}^{N}-\log \frac{\exp (\operatorname{sim}\left(\boldsymbol{z}_i, \boldsymbol{z}_j\right) / \tau)}{\sum_{k=1}^{K} I(k \neq j) \exp (\operatorname{sim}\left(\boldsymbol{z}_i, \boldsymbol{z}_k\right) / \tau)} \] 其中 \( z_i \) 和 \( z_j \) 是同一个实例经过不同变换得到的两个视图对应的表征向量;\( sim() \) 表示相似度度量方式,比如余弦相似度;\( τ \) 则是一个温度参数用来调整分布锐利程度[^1]。 然而,在实际操作过程中发现仅依靠上述标准对比损失难以获得理想的聚类效果,因为这需要大量精心挑选的负样本来维持良好的互信息边界。针对这个问题,研究者们提出了多种改进方案,例如引入额外的正则化项以增强特征表达力或减少对抗噪声干扰等。 #### 正则化损失 Lreg 考虑到直接最大化簇间距离可能带来过拟合风险,有工作建议加入一个专门设计的正则化损失 \( L_{\mathrm{reg}} \),旨在扩大不同基底间的高维特征差异的同时保持一定平滑性。该损失基于成对样本之间余弦相似度 s_ij 的计算,并试图最小化跨类别样本间的这种相似度得分,从而促进更清晰可分的集群结构形成[^5]。 ```python import torch from torch.nn.functional import normalize def info_nce_loss(z_i, z_j, temperature=0.5): """Compute the InfoNCE loss.""" batch_size = z_i.shape[0] # Normalize representations to unit vectors z_i_norm = normalize(z_i) z_j_norm = normalize(z_j) # Compute pairwise cosine similarities between all pairs of samples logits_ii = torch.mm(z_i_norm, z_i_norm.t()) / temperature logits_ij = torch.mm(z_i_norm, z_j_norm.t()) / temperature mask = torch.eye(batch_size).to(logits_ii.device) positives = logits_ij.diag() negatives = torch.cat([logits_ii[mask==0], logits_ij[mask==0]], dim=-1) nominator = torch.exp(positives) denominator = nominator + torch.sum(torch.exp(negatives), dim=-1) return -torch.mean(torch.log(nominator/denominator)) ```
评论 112
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值