ELAI S.r.l.

如果每份文档同等重要,长度为什么会改变训练?

词元平均与文档平均并不等价。通过交叉熵、掩码和梯度的完整例子,理解训练目标究竟在优化什么。

如果每份文档同等重要,长度为什么会改变训练?

两份文档,两种决定其权重的方法

团队准备用领域文档适配AI模型,其中有短文档,也有长文档。如果希望每份文档同等重要,把它们放入同一批次后平均损失就足够吗?未必。对全部受监督位置求平均,会让位置更多的文档权重更大。分母是学习目标的一部分,而不是程序中无关紧要的细节。

我们要问:到底在平均什么,梯度又如何改变?两个合成分组分别包含2和8个有效位置,用只有一个参数的二分类模型完整计算交叉熵,再加入仅用于对齐长度的填充位置。这里不训练语言模型,而是用可控制模型隔离一种同样影响领域模型适配的机制。

单个损失衡量什么

词元是文本表示中的单位;受监督位置是需要做出预测且存在目标的位置。这个例子不需要真实词语或特定分词器。每个位置的标签y为0或1,模型在所有位置都给类别1分配同一概率p。模型刻意简化,因为目的是展示聚合规则,而不是学习语言。

p = sigmoid(theta) = 1 / (1 + exp(-theta)) ell(theta,y) = -y log(p) - (1-y) log(1-p)

Theta是模型可以改变的实数参数,称为logit。theta=0时,p=0.5。使用自然对数,损失单位为nat。y=1时惩罚过小的p,y=0时惩罚过小的1−p。损失并不是答对比例。改变观察权重后,即使损失数值相同,梯度仍可能不同。

全局平均隐式决定了文档权重

令n_i为文档i的有效位置数,L_i为该文档的平均损失。词元平均先对所有损失求和,再除以有效位置总数;文档平均先计算各L_i,再给予各文档相同权重。前者中L_i的系数与n_i成比例,后者系数相同,前提是每份文档至少有一个有效位置。

L_token = sum_i n_i L_i / sum_i n_i L_document = (1/D) sum_i L_i

D是文档数量。n_A=2、n_B=8时,词元目标为0.2 L_A+0.8 L_B,文档目标为0.5 L_A+0.5 L_B。第一个目标中文档B的权重是A的四倍,第二个则相等。这不表示词元平均自动就是错误的;若每个位置同等重要,它是自洽选择。只有意图是每份文档同等重要时,才与意图不符。

梯度让区别显现出来

给文档A的两个位置都赋标签1,给B的八个位置都赋标签0。这些是构造目标,不是语料中的实测频率。要判断theta如何改变,需要对它求导。sigmoid的导数为p(1−p),代入对数导数后化简得到p−y。梯度表示损失局部增加的方向。

d ell / d theta = -y(1-p) + (1-y)p = p-y g_token = p - 2/10 = p - 0.2 g_document = p - 1/2 = p - 0.5

theta=0、p=0.5时,词元梯度为0.3,文档梯度为0。下降步骤从参数中减去正步长乘梯度,因此前者让theta向负方向移动,后者已经处于驻点。两个初始损失却都是log 2,约0.693147 nat。只看损失数值,不会发现两种准则建议不同更新。

还可以求最优点。梯度是p减去标签1的加权比例,因此词元目标在p=0.2时为零,文档目标在p=0.5时为零。二阶导数p(1−p)在0与1之间为正,所以本标量模型有唯一且有限的最优点。这不证明大型语言模型的损失面凸,结论只针对已声明的模型。

填充不是新增的类别零样本

为得到两行长度8的数据,给A增加六个人工位置。它们没有任务目标,只用于组织张量形状。如果把它们标记为0并当真实数据计入损失,就变成16个位置中仅2个正例,最优值为p=2/16=0.125。文档内容没变,却向目标中添加了六个虚构样本。

有效位置的掩码m为1,填充为0;掩码必须同时作用于平均的分子和分母。继续添加掩码为0的位置后,正确损失与梯度应保持不变。程序用0、1、6、20个新增位置及三个theta值检查该性质。它是构造计算中的性质,不是现场模型鲁棒性测量。

L_masked = sum_j m_j ell_j / sum_j m_j sum_j m_j = 10, not 16

第二种错误正确删除了填充损失,却仍除以16。结果是正确损失的10/16。theta=0时,损失从0.693147降到0.433217,预测概率却毫无改善;梯度从0.3降为0.1875。因为整个函数乘了正数常量,标量最优值仍为p=0.2,但更新尺度改变了。曲线数字更低,不代表预测更好。

第三种错误把标签0当作填充的同义词,忽略所有0,包括B中八个合法监督目标。只剩两个标签1,初始梯度变为−0.5,让p趋向1。此时最小值是在theta无限增大时接近的极限,不是有限最优点。必须区分类别数值与位置的人工填充角色;掩码应描述后者。

准则theta=0时损失(nat)theta=0时梯度最优p
词元平均0.6931470.30000.200
文档平均0.6931470.00000.500
包括填充0.6931470.37500.125
分母错误0.4332170.18750.200
忽略类别零0.693147-0.50001(极限)

表格描述不同目标函数,并非五次训练在同一测试集上的比较。词元与文档平均是明确的权重选择,其他行则违反约定的有效数据定义。固定缩放因子可以吸收到优化步长中;若各批次填充比例不同,因子也不同,更新中各贡献的相对权重就会改变。

左图的曲线使用三种不同权重,不能仅比较数值最小值就选择更好的模型。右图在同一theta=0下展示梯度大小变化,以及删除合法0标签后的符号反转。数据与模型均为合成,没有测量LLM准确率。
左图的曲线使用三种不同权重,不能仅比较数值最小值就选择更好的模型。右图在同一theta=0下展示梯度大小变化,以及删除合法0标签后的符号反转。数据与模型均为合成,没有测量LLM准确率。

拆分批次不应悄悄改变目标

假设为节省内存,把A和B作为两个依次处理的微批次。theta=0时,各自平均梯度为−0.5与+0.5。简单平均得到0,相当于文档目标。要恢复全局词元平均,必须按有效位置数量加权:(2 ×−0.5+8 × 0.5)/10=0.3,与未拆分批次一致。

g_global = sum_b n_b g_b / sum_b n_b g_mean_of_means = (1/B) sum_b g_b

这里B表示微批次数。有效数量相同时,两公式相等;某些特殊抵消也可能使其相等。但填充后的张量长度相同并不够。这是在检查累积的代数关系,并非指控某版本Trainer或框架有缺陷。实现必须与其声明目标及实际归约规则对照。

从公式到库,区分不同层次

PyTorch 2.14官方CrossEntropyLoss文档区分类别索引目标与概率分布目标。对类别索引,ignore_index把目标排除在损失和梯度之外;没有类别权重时,平均分母为未忽略目标的数量。例子正是离散标签、无类别权重的情况,不能不加修改地推广到概率目标或其他权重方案。

在因果语言模型中,有效位置还取决于输入与下一词元目标的对齐,以及是否监督提示、回答或两者。文档总长度不一定等于n_i。注意力掩码与损失掩码回答不同问题,即使某实现把两者联系起来。使用计数之前,必须明确哪些预测真正贡献于目标,而不是只统计张量里有多少词元。

如果没有有效位置,平均分母为零,公式没有定义。程序明确报告该情况,而不是返回零,伪装成完美预测。没有目标的文档,其L_i也没有定义;排除它或采取其他处理都需要声明策略。我们不把自有代码的行为归于所有库,其他库可能有不同处理。

不训练LLM也能复现推理

程序只用Python数学库计算损失与解析梯度,采用数值稳定的对数形式,保存五种目标,检查正确屏蔽填充的不变性,并在theta=0.3处与中心有限差分比较。实际检查误差约4.1 × 10⁻¹¹,低于该检查选定的1 × 10⁻⁸容差。这不构成对自动微分系统的正确性验证。

简短代码中,lengths表示贡献位置数,gradients保存每份文档的平均贡献。最后两种平均重建不同目标,不需要GPU、模型权重或外部数据。对位置求和的成本随处理数量线性增加,但这不衡量推理或训练成本。标量运算没有模拟真实模型中昂贵的计算部分。

到底希望按什么单位分配重要性?

当长度改变各贡献在目标函数中的权重时,它就会改变训练。文档同等重要,需要文档平均或等价权重;位置同等重要,需要词元平均。没有哪一种普遍更好。但两种选择都必须区分填充与有效目标,微批次拆分也不应引入未声明的权重。真实模型质量最终需要独立评价,本例不能代替。

来源与可复现材料

PyTorch 2.14 documentation, CrossEntropyLoss: class-index and probability targets, reduction, ignore_index. Relevant technical definitions read 21 October 2026. Documentation consulted; no PyTorch execution claimed..

import math
p=0.5
lengths=[2,8]
labels=[1,0]
gradients=[p-y for y in labels]
token_gradient=sum(n*g for n,g in zip(lengths,gradients))/sum(lengths)
document_gradient=sum(gradients)/len(gradients)
assert abs(token_gradient-0.3)<1e-12
assert document_gradient==0
print(token_gradient,document_gradient)

代码、数据与说明 · JSON. 教学计算使用 Python 3.14.0,图使用 Matplotlib 3.11.2。分析由 AI 辅助,不声称经过同行评审或人工审核。原创 ImageGen 封面仅作示意,不记录 EL-AI 人员、场所或实际安装。来源查阅于 2026 年 10 月 21 日。