当谈论到信息论中的损失函数时,InfoNCE(Noise Contrastive Estimation)和交叉熵损失都是两个关键的概念。它们不仅在衡量概率分布之间的差异方面发挥着重要作用,而且在深度学习的自监督学习领域扮演着重要角色。虽然它们的形式和应用环境有所不同,但是我们可以发现它们之间存在着微妙的联系。
交叉熵损失作为衡量两个概率分布之间距离的指标,在分类任务和神经网络训练中广泛使用。而InfoNCE Loss,则是针对自监督学习任务中特征学习的一种损失函数。它通过比较正样本和负样本的相似性来学习模型参数,从而提高特征的区分度。
在这篇博客中,我们将深入探讨交叉熵损失和InfoNCE之间的联系,探究它们在信息论和深度学习中的联系与异同。我们将分析两者的数学形式、应用领域以及它们之间可能的内在关系,以期对这两个重要概念有更深入的理解。
InfoNCE Loss(Noise Contrastive Estimation Loss)是一种用于自监督学习的损失函数,通常用于学习特征表示或者表征学习。它基于信息论的思想,通过对比正样本和负样本的相似性来学习模型参数。
InfoNCE Loss的公式如下:
InfoNCE Loss = − 1 N ∑ i = 1 N log ( exp ( q i ⋅ k i + τ ) ∑ j = 1 N exp ( q i ⋅ k j − τ ) ) \text{InfoNCE Loss} = -\frac{1}{N} \sum_{i=1}^{N} \log \left( \frac{\exp \left( \frac{q_i \cdot k_{i^+}}{\tau} \right)}{\sum_{j=1}^{N} \exp \left( \frac{q_i \cdot k_{j^-}}{\tau} \right)} \right) InfoNCE Loss=−N1i=1∑Nlog ∑j=1Nexp(τqi⋅kj−)exp(τqi⋅ki+)
其中:
从INfoNCE的公式中我们可以发现,分子只包含一对正样本,分母则包含一个batch下的 N N N个所有样本,即1个与 q i q_i qi对应的正样本和 ( N − 1 ) (N-1) (N−1)个负样本,那么上述公式我们也可以简化为下述形式:
InfoNCE Loss = − 1 N ∑ i = 1 N log A + A + + B − \text{InfoNCE Loss} = -\frac{1}{N} \sum_{i=1}^{N} \log\frac{A_+}{A_++B_-} InfoNCE Loss=−N1i=1∑NlogA++B−A+
首先,分式部分一定是介于(0,1)之间的,而log在(0,1)之间是单增的且函数值小于0
在损失优化过程中,我们希望达成的结果是 A + A_+ A+尽可能大,也就是正样本之间的距离尽可能尽,其实也隐含着与负样本之间的相似度尽可能低,距离尽可能远。从公式上来看,我们在最小化loss的过程中,需要让公式接近0,也就是让log内部的分式接近1,要达到这个效果,应该使 A > > B A>>B A>>B,可以发现跟我们的训练思路是吻合的,这就达到了对于查询向量而言,推近它和正样本之间的距离,拉远它和负样本的距离
写到这里,基本上把InfoNCE的公式以及公式背后的主要思想讲清楚了,下面就要说Cross Entropy Loss跟它的关系了,其实主要还是InfoNCELoss代码是基于交叉熵损失实现的,看不明白交叉熵损失的代码逻辑也看不懂InfoNCELoss了
交叉熵损失是衡量两个概率分布之间差异的一种指标。在分类问题中,我们通常有一个真实的概率分布 P P P(通常是一个独热编码向量,代表了样本的真实标签分布),和一个模型预测的概率分布 Q Q Q。交叉熵损失用于衡量这两个概率分布之间的差异。
其数学公式为:
CrossEntropy ( P , Q ) = − ∑ i P ( i ) ⋅ log ( Q ( i ) ) \text{CrossEntropy}(P, Q) = - \sum_i P(i) \cdot \log(Q(i)) CrossEntropy(P,Q)=−i∑P(i)⋅log(Q(i))
交叉熵损失的含义和主要思想是在真实分布和模型预测分布之间衡量误差。当模型的预测与真实情况相符时,交叉熵损失会趋近于0。换句话说,交叉熵损失函数的优化目标是使得模型的预测概率分布尽可能地接近真实标签的概率分布,以最小化误差。
在深度学习中,交叉熵损失通常用作分类任务中的损失函数,在训练过程中用来衡量模型预测与真实标签之间的差异,并通过反向传播来优化模型参数。
结合上述解释,下面来看一下交叉熵损失的代码
'''
创建原始数据样例
x:3row x 4col的张量,表示数据中包含三条数据,每条数据预测四个类别
y:3d张量,与三条数据对应;每个元素属于0-3,与四个类别对应
'''
# 1.创建原始数据
x=torch.rand((3,4))
y=torch.tensor([3,0,2])
# 2.计算x_sfm=softmax(x),求出归一化后的每个类别概率值
softmax_func=nn.Softmax()
x_sfm=softmax_func(x)
# 3.计算log(x_sfm),由于原来的概率值位于0-1,取对数后一定是负值
# 概率值越大,取对数后的绝对值越小,符合我们的损失目标
x_log=torch.log(x_sfm)
# ls = nn.LogSoftmax(dim=1)# 也可以使用nn.LogSoftmax()进行测试,二者结果一致
# print(ls(x))
# 4.最后使用nn.NLLLoss求损失
# 思路,按照交叉熵的计算过程,将真值与经过LogSoftmax后的预测值求和取平均
index=range(len(x))
loss=x_log[index,y]
print(abs(sum(loss)/len(x)))
从代码中可以很好理解交叉熵如何发挥作用,并且也能理解交叉熵的真值标签为啥只是一维张量
import torch
import torch.nn.functional as F
def approx_infoNCE_loss(q, k):
# 计算query和key的相似度得分
similarity_scores = torch.matmul(q, k.t()) # 矩阵乘法计算相似度得分
# 计算相似度得分的温度参数
temperature = 0.07
# 计算logits
logits = similarity_scores / temperature
# 构建labels(假设有N个样本)
N = q.size(0)
labels = torch.arange(N).to(logits.device)
# 计算交叉熵损失
loss = F.cross_entropy(logits, labels)
return loss