Qwen2.5-VL 损失函数
flyfish
文章名称 | 链接 |
---|---|
深入理解交叉熵损失 CrossEntropyLoss - 概率基础 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 对数 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 概率分布 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 信息论(交叉熵) | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 损失函数 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - one-hot 编码 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - Softmax | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 归一化 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - nn.LogSoftmax | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 似然 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 乘积符号在似然函数中的应用 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - 最大似然估计 | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - nn.NLLLoss(Negative Log-Likelihood Loss) | 链接 |
深入理解交叉熵损失 CrossEntropyLoss - CrossEntropyLoss | 链接 |
qwen2_5_vl/modular_qwen2_5_vl.py
qwen2_5_vl/modeling_qwen2_5_vl.py
文件的forward方法中使用了CrossEntropyLoss
loss = None
if labels is not None:# Upcast to float if we need to compute the loss to avoid potential precision issueslogits = logits.float()# Shift so that tokens < n predict nshift_logits = logits[..., :-1, :].contiguous()shift_labels = labels[..., 1:].contiguous()# Flatten the tokensloss_fct = CrossEntropyLoss()shift_logits = shift_logits.view(-1, self.config.vocab_size)shift_labels = shift_labels.view(-1)# Enable model parallelismshift_labels = shift_labels.to(shift_logits.device)loss = loss_fct(shift_logits, shift_labels)if not return_dict:output = (logits,) + outputs[1:]return (loss,) + output if loss is not None else output
loss_fct(shift_logits, shift_labels)
1. shift_logits
- 类型:
torch.Tensor
- 含义:它代表模型的原始输出得分,也就是未经Softmax函数处理过的对数概率。在多分类任务里,每个样本的
shift_logits
是一个长度为词汇表大小(self.config.vocab_size
)的向量,此向量的每个元素对应着模型预测该样本属于各个类别的得分。 - 形状:在代码里,
shift_logits
经过view(-1, self.config.vocab_size)
操作后,其形状为(N, C)
,其中N
是所有样本的总数(即批次大小与序列长度的乘积),C
是类别数量(也就是词汇表的大小)。
2. shift_labels
- 类型:
torch.LongTensor
- 含义:它代表样本的真实标签。每个元素是一个整数,这个整数对应着样本的真实类别索引,其取值范围是
[0, C - 1]
,这里的C
是类别数量(即词汇表的大小)。 - 形状:在代码中,
shift_labels
经过view(-1)
操作后,其形状为(N,)
,这里的N
是所有样本的总数(即批次大小与序列长度的乘积),要和shift_logits
的第一个维度保持一致。
示例代码
使用 CrossEntropyLoss
计算
import torch
from torch.nn import CrossEntropyLoss# 假设词汇表大小为10
vocab_size = 10
# 假设总样本数为5
N = 5# 生成随机的logits和labels
shift_logits = torch.randn(N, vocab_size)
shift_labels = torch.randint(0, vocab_size, (N,))# 创建CrossEntropyLoss实例
loss_fct = CrossEntropyLoss()# 计算损失
loss = loss_fct(shift_logits, shift_labels)
print(f"Loss: {loss.item()}")
shift_logits
是模型的原始输出得分,shift_labels
是样本的真实标签,loss_fct(shift_logits, shift_labels)
会计算出这些样本的交叉熵损失。
代码中使用了CrossEntropyLoss类来计算损失,在 PyTorch 中,CrossEntropyLoss结合了LogSoftmax和NLLLoss(负对数似然损失)。LogSoftmax操作会对模型的输出logits应用 Softmax 函数,将其转换为概率分布,然后再取对数;NLLLoss则基于这个对数概率分布和真实标签计算损失。因此,CrossEntropyLoss本质上实现的是 Softmax 交叉熵。
多分类场景的体现:shift_logits被调整为形状(-1, self.config.vocab_size),其中self.config.vocab_size表示词汇表的大小,这意味着模型的输出是一个多分类的概率分布,每个类别对应词汇表中的一个词。
简单的说
1. 基础概念:熵、交叉熵与KL散度
1.1 信息熵(Entropy)
信息熵是随机变量的不确定性度量,对于离散概率分布 P ( x ) P(x) P(x),其公式为 H ( P ) = − ∑ i P ( x i ) log P ( x i ) H(P) = -\sum_{i} P(x_i) \log P(x_i) H(P)=−∑iP(xi)logP(xi)。直观来看,熵越高意味着分布越“均匀”,不确定性越大——例如掷骰子结果的熵高于抛硬币,因为骰子的可能结果更多且分布更均匀,其不确定性更强。
1.2 交叉熵(Cross-Entropy)
交叉熵用于衡量用分布 Q Q Q 表示分布 P P P 的困难程度,公式为 H ( P , Q ) = − ∑ i P ( x i ) log Q ( x i ) H(P, Q) = -\sum_{i} P(x_i) \log Q(x_i) H(P,Q)=−∑iP(xi)logQ(xi)。交叉熵越小,说明 Q Q Q 与 P P P 的差异越小,即 Q Q Q 越接近真实分布 P P P,因此常被用作衡量两个分布相似性的指标。
1.3 KL散度(Kullback-Leibler Divergence)
KL散度是对两个概率分布差异的量化度量,公式为 D K L ( P ∣ ∣ Q ) = ∑ i P ( x i ) log P ( x i ) Q ( x i ) D_{KL}(P||Q) = \sum_{i} P(x_i) \log \frac{P(x_i)}{Q(x_i)} DKL(P∣∣Q)=∑iP(xi)logQ(xi)P(xi),其与交叉熵、信息熵的关系为 H ( P , Q ) = H ( P ) + D K L ( P ∣ ∣ Q ) H(P, Q) = H(P) + D_{KL}(P||Q) H(P,Q)=H(P)+DKL(P∣∣Q),即交叉熵等于信息熵与KL散度之和。当真实分布 P P P 固定时,最小化交叉熵等价于最小化KL散度,目标是让预测分布 Q Q Q 尽可能接近 P P P。
2. 交叉熵损失在分类任务中的应用
2.1 二分类问题
在二分类场景中,模型需要预测样本属于0或1类的概率,通常通过sigmoid函数将输出映射到[0, 1]区间,得到概率 y ^ \hat{y} y^。二元交叉熵(BCE)损失函数为 L = − 1 N ∑ i = 1 N [ y i log ( y ^ i ) + ( 1 − y i ) log ( 1 − y ^ i ) ] L = -\frac{1}{N} \sum_{i=1}^{N} \left[ y_i \log(\hat{y}_i) + (1-y_i) \log(1-\hat{y}_i) \right] L=−N1∑i=1N[yilog(y^i)+(1−yi)log(1−y^i)]:当真实标签 y i = 1 y_i=1 yi=1 时,损失为 − log ( y ^ i ) -\log(\hat{y}_i) −log(y^i),鼓励 y ^ i \hat{y}_i y^i 接近1;当 y i = 0 y_i=0 yi=0 时,损失为 − log ( 1 − y ^ i ) -\log(1-\hat{y}_i) −log(1−y^i),鼓励 y ^ i \hat{y}_i y^i 接近0。
2.2 多分类问题
多分类任务中,样本需被预测为 C C C 个类别之一,模型通过softmax函数将输出转换为概率分布 y ^ 1 , … , y ^ C \hat{y}_1, \dots, \hat{y}_C y^1,…,y^C(满足 ∑ i = 1 C y ^ i = 1 \sum_{i=1}^{C} \hat{y}_i = 1 ∑i=1Cy^i=1),损失函数为多类交叉熵 L = − 1 N ∑ i = 1 N ∑ c = 1 C y i , c log ( y ^ i , c ) L = -\frac{1}{N} \sum_{i=1}^{N} \sum_{c=1}^{C} y_{i,c} \log(\hat{y}_{i,c}) L=−N1∑i=1N∑c=1Cyi,clog(y^i,c),其中 y i , c y_{i,c} yi,c 是one-hot标签(样本 i i i 属于类别 c c c 时为1,否则为0),该公式本质是对每个样本的真实类别对应的预测概率取负对数并求平均。
3. 交叉熵损失与最大似然估计
3.1 从最大似然到交叉熵
假设训练数据 ( x i , y i ) (x_i, y_i) (xi,yi) 独立同分布,模型预测为条件概率 P ( y ∣ x ; θ ) P(y|x; \theta) P(y∣x;θ),对数似然函数为 log L ( θ ) = ∑ i = 1 N log P ( y i ∣ x i ; θ ) \log \mathcal{L}(\theta) = \sum_{i=1}^{N} \log P(y_i|x_i; \theta) logL(θ)=∑i=1NlogP(yi∣xi;θ),最小化负对数似然(NLL)即 L = − 1 N ∑ i = 1 N log P ( y i ∣ x i ; θ ) L = -\frac{1}{N} \sum_{i=1}^{N} \log P(y_i|x_i; \theta) L=−N1∑i=1NlogP(yi∣xi;θ) 等价于最大化似然。对于分类问题,若 P ( y i ∣ x i ; θ ) P(y_i|x_i; \theta) P(yi∣xi;θ) 是softmax分布,则NLL损失恰好对应交叉熵损失。
3.2 为什么用交叉熵而非MSE?
从梯度特性看,交叉熵在预测错误时梯度较大,能加速收敛;而MSE在预测值远离真实值时梯度较小,可能导致训练缓慢。从概率解释角度,交叉熵直接优化似然函数,与概率模型的训练目标一致,而MSE更适用于回归任务,不直接关联概率分布的拟合。
4. 交叉熵损失在语言模型中的应用
4.1 自回归语言模型
自回归语言模型的任务是根据前文 x 1 , … , x t − 1 x_1, \dots, x_{t-1} x1,…,xt−1 预测下一个token x t x_t xt 的概率分布,损失函数为对序列每个位置 t t t 计算交叉熵 L = − 1 T ∑ t = 1 T log P ( x t ∣ x 1 , … , x t − 1 ) L = -\frac{1}{T} \sum_{t=1}^{T} \log P(x_t | x_1, \dots, x_{t-1}) L=−T1∑t=1TlogP(xt∣x1,…,xt−1)。以PyTorch为例,假设模型输出logits为 [batch_size, seq_len, vocab_size],真实标签为 [batch_size, seq_len],可通过 nn.CrossEntropyLoss()
计算损失:loss = loss_fct(logits.view(-1, vocab_size), labels.view(-1))
,其中函数会自动对logits应用softmax并计算交叉熵。
4.2 与分类任务的联系
语言模型中每个token位置的预测可视为独立的分类问题,词汇表大小即类别数,模型需在每个位置预测当前token属于词汇表中某个词的概率。因此,语言模型的训练本质是对序列中每个位置的“分类器”进行联合优化,与多分类任务的核心逻辑一致,只是序列场景下需要考虑上下文依赖关系。
交叉熵损失和交叉熵区别
1. 区别
交叉熵(信息论概念)是衡量两个概率分布差异的指标,数学定义为 H ( P , Q ) = − ∑ i P ( x i ) log Q ( x i ) H(P, Q) = -\sum_{i} P(x_i) \log Q(x_i) H(P,Q)=−∑iP(xi)logQ(xi),其中 P P P是真实分布, Q Q Q是预测分布,核心作用是衡量用分布 Q Q Q表示分布 P P P的“不匹配程度”,不匹配程度越低,交叉熵越小。而交叉熵损失(机器学习损失函数)是交叉熵在模型训练中的具体应用,本质上是对样本的交叉熵求平均,用于量化模型预测与真实标签的差距,作为优化目标,例如在分类任务中,其表达式为 L = − 1 N ∑ i = 1 N ∑ c = 1 C y i , c log y ^ i , c L = -\frac{1}{N} \sum_{i=1}^{N} \sum_{c=1}^{C} y_{i,c} \log \hat{y}_{i,c} L=−N1∑i=1N∑c=1Cyi,clogy^i,c,其中 N N N是样本数, C C C是类别数, y i , c y_{i,c} yi,c是样本 i i i的one-hot标签, y ^ i , c \hat{y}_{i,c} y^i,c是模型预测的概率。
2. 联系:交叉熵损失是交叉熵的“工程化应用”
交叉熵损失的设计直接基于交叉熵的数学定义,在机器学习中,真实标签(如one-hot向量)可视为真实分布 P P P,模型预测的概率分布是 Q Q Q,此时交叉熵即对应单个样本的损失,而交叉熵损失是所有样本交叉熵的平均。例如在二分类问题中,真实标签 y y y(0或1)对应伯努利分布 P P P,模型预测概率 y ^ \hat{y} y^对应分布 Q Q Q,单个样本的交叉熵为 L = − [ y log y ^ + ( 1 − y ) log ( 1 − y ^ ) ] L = -[y \log \hat{y} + (1-y) \log (1-\hat{y})] L=−[ylogy^+(1−y)log(1−y^)],这正是二元交叉熵损失(BCE Loss)的表达式。
交叉熵是通用指标,不依赖于机器学习任务,只要存在两个概率分布,就可用交叉熵衡量它们的差异(如在信息压缩、分布匹配中);而交叉熵损失是任务特定的优化目标,仅在模型训练时使用,目的是通过最小化损失让预测分布 Q Q Q逼近真实分布 P P P,例如在语言模型中,交叉熵损失对应“预测下一个token的概率与真实token的匹配程度”,而交叉熵本身可用来评估语言模型的困惑度(Perplexity)。