:大模型不是因为“猜错”才挨罚:Cross Entropy 到底在惩罚什么?)
上一课讲完 Logits、Softmax 和 Sampling 以后有一个地方特别容易让人产生错觉。我们看到“法国的首都是”模型经过 Transformer得到一堆 Logits。Softmax 再把这些 Logits 变成 Probability Distribution。比如TokenProbability巴黎51%伦敦30%北京10%罗马6%香蕉3%最后如果使用 Argmax模型会选择巴黎。看起来没什么问题。但现在我把另一个模型放在旁边TokenProbability巴黎99%伦敦0.4%北京0.3%罗马0.2%香蕉0.1%它最后选择的同样是巴黎。于是一个很有意思的问题出现了。第一个模型答对了。第二个模型也答对了。如果只看最终答案两者都是 100% 正确。那训练系统是不是应该认为这两个模型表现完全一样显然不是。一个模型只是勉强觉得“巴黎最有可能”。另一个模型几乎已经确定答案就是巴黎。它们对这个世界的判断质量明显不在一个水平上。事情再反过来看会更明显。假设第三个模型给P(巴黎)49%而P(伦敦)50%它最后选错了。第四个模型则给P(巴黎)0.000001几乎把所有概率都压在伦敦上。它也选错了。如果只看“对 / 错”两者都是错。但它们真的错得一样严重吗当然不是。第三个模型只是差一点判断错。第四个模型则是在极度自信地否定真实答案。这就是这一课真正的起点。语言模型训练不能只知道你最后猜对了没有。它必须知道真实答案出现的时候你到底给它留下了多少概率。一旦这句话想通Cross Entropy 后面几乎所有公式都会突然变得顺理成章。先看完整逻辑真实 Token 已知→模型给它概率 p→−log p→Cross Entropy / NLL→Loss先把“生成”放到一边训练阶段有一个巨大不同上一课讨论 Sampling 时我们站在推理阶段。模型面对的是未来。比如“今天下班以后我准备去……”后面到底是吃饭健身看电影还是回家没有 Ground Truth 在旁边告诉模型答案。所以模型只能根据 Probability Distribution 去选择一个 Token。这就是 Decoding。但是训练阶段完全不是这样。训练数据已经在那里了。例如训练文本就是“法国的首都是巴黎。”当模型看到“法国的首都是”训练系统早就知道下一个真实 Token 是巴黎。所以训练阶段根本不需要先 Sampling 一个 Token再看看猜没猜中。真正的问题只有一个Pθ(巴黎|法国的首都是)到底是多少假设模型给0.9很好。如果给0.5还不够好。如果只给0.000001那问题就非常严重。所以第三课讲的 Probability Distribution在训练阶段终于有了真正的用途。第三课问的是模型怎样形成一个 Probability Distribution这一课问的是既然正确答案已经知道了怎么根据这个 Distribution 判断模型到底错了多少这就是 Loss 要解决的问题。如果让你自己设计 Loss你会先提出什么要求先不要看任何机器学习公式。我们自己来设计。假设正确 Token 是巴黎。模型给巴黎的概率记作p一个合理的 Loss至少应该有下面这种性格。如果p1模型已经把全部概率都给了正确答案。那最好Loss0如果p0.8有一点不确定。Loss 应该有但不能太大。如果p0.1正确答案只有 10% 概率。Loss 应该明显变大。如果p→0模型几乎确信真实答案“不可能发生”。这时候惩罚应该非常重。所以我们真正想要的是一个函数L(p)满足正确答案概率越高Loss 越低。正确答案概率越低Loss 越高。而当模型极度自信地否定正确答案时惩罚应该继续增大。看到这里很多人会自然想到一个东西那直接用L1−p不就行了吗如果p1Loss 是 0。如果p0Loss 是 1。看起来很合理。但先别急。这个想法恰好可以帮我们理解为什么最后大语言模型没有停在这么简单的 Loss 上。真正的训练目标比“错多少”还要更早出现我们先换一个角度。现在有三个模型。模型 APA(巴黎)0.1模型 BPB(巴黎)0.6模型 CPC(巴黎)0.95训练数据已经告诉我们真实答案就是巴黎。哪一个模型更好显然CBA为什么因为真实世界已经发生的事情就是“巴黎”。一个更好的模型应该在事情发生之前就给这个真实结果更高的概率。所以我们甚至还没讨论 Loss就已经得到一个非常自然的训练目标max θ Pθ(y|x)这里(x) 是 Context。(y) 是真实 Token。(θ) 是模型参数。翻译成人话就是不断调整模型参数让训练数据中真正发生的事情在模型看来越来越可能。这其实就是 Maximum Likelihood。最大似然估计。名字听起来很统计学但思想一点都不复杂。真实数据已经发生了。我们现在要找的就是哪一组模型参数最愿意相信这些真实数据Probability 和 Likelihood其实只是观察方向变了Likelihood 中文通常翻译成“似然”。很多人第一次看到这个词就开始紧张。其实它和 Probability 用的甚至可能是同一个数学表达式Pθ(y|x)区别主要在你把谁看成变量。假设模型已经固定。你问“在这个模型看来看到‘法国的首都是’以后巴黎出现的概率是多少”这是 Probability 的视角。但训练的时候数据已经固定。我们已经知道答案就是巴黎。现在变化的是θ也就是模型参数。我们想问参数方案 A、B、C谁能让“巴黎”这个真实结果获得更高概率这就是 Likelihood 的视角。所以不用把它想得太神秘。一句话就够Probability 是模型固定看数据有多可能。Likelihood 是数据固定看哪一个模型更能解释它。训练语言模型做的事情自然就是max θ Pθ(y|x)但语言模型显然不可能只训练一个 Token如果训练任务只有“法国的首都是” → “巴黎”事情到这里就结束了。问题是大模型吃进去的是海量文本。比如一句非常简单的话“我 喜欢 机器 学习”为了方便我们暂时把它看成四个 Tokenx1我x2喜欢x3机器x4学习这句话天然可以拆出多个 Next Token Prediction。看到“我”预测“喜欢”。也就是P(x2|x1)看到“我 喜欢”预测“机器”。也就是P(x3|x1,x2)看到“我 喜欢 机器”预测“学习”。也就是P(x4|x1,x2,x3)第二课讲过的P(xt|xt)到这里终于不再只是一个抽象公式。它就是训练过程中一个位置一个位置真正被优化的东西。对于每一个位置我们都希望Pθ(xt|xt)尽可能大。一个个 Token 的概率怎么变成整段文本的概率现在开始出现一个非常漂亮的连接。根据 Probability Chain RuleP(x1,x2,…,xT) ∏t P(xt|xt)意思是一整段 Sequence 的概率可以拆成很多个 Next Token Probability 的乘积。举个简单例子。假设三个位置模型给真实 Token 的概率分别是0.8, 0.6, 0.7那么这几个条件概率乘起来0.8×0.6×0.70.336从 Maximum Likelihood 的角度我们当然希望真实 Sequence 的整体概率尽可能高。于是训练目标自然变成max θ ∏t Pθ(xt|xt)这一步非常关键。因为到这里你会发现语言模型看起来是在做无数道“猜下一个词”的小题。但从概率建模的角度看它们不是互不相关的小题。所有这些条件概率一起组成了模型对整段语言数据的概率判断。所以 Next Token Prediction 并不是“做很多猜词游戏。”它实际上是在逼模型学习什么样的 Token Sequence在真实语言世界里更可能出现。接下来遇到第一个麻烦概率乘积小得太快假设模型每一步给正确 Token 的概率都不错0.5只有 10 个 Token 时0.510≈0.0009766100 个 Token0.5100≈7.9×10−31如果是 1000 个 Token 呢10000 个呢大量小于 1 的概率不断相乘结果会飞快向 0 靠近。这不仅让数值处理很麻烦还有另一个问题所有 Token 的贡献都纠缠在一个巨大乘积里。原本是P1P2P3P4… PT如果我们希望知道每一个 Token Position 分别贡献了多少训练信号这种形式非常不好用。于是一个极其普通的数学工具登场了log因为log (ab)log alog b所以log ( ∏tPt )可以变成∑tlog Pt原本P1P2P3P4…现在变成log P1log P2log P3log P4…这一变换对语言模型训练非常重要。因为一整条 Sequence 的目标从一个巨大的概率乘积变成了很多 Token-level 项的求和。每个位置都可以独立计算。最后再加起来或者取平均。这就非常适合现代深度学习训练。取了 Log会不会偷偷改变谁是最优模型不会。因为 Log 是严格单调递增函数。如果0.90.50.1那么log 0.9log 0.5log 0.1虽然这些 Log Probability 通常都是负数但它不会改变大小顺序。所以max P和max log P寻找的是同一个最优解。我们没有改变训练目标。只是换了一种更容易处理的表达方式。于是max θ ∏t Pθ(xt|xt)就可以写成max θ ∑t log Pθ(xt|xt)这叫Maximum Log-Likelihood。到这里距离我们每天在训练日志里看到的 Loss其实只差一步。为什么还要突然加一个负号现在我们的目标是max θ ∑tlog Pθ(xt|xt)也就是Log-Likelihood 越大越好。但机器学习里通常习惯把优化问题统一写成min θ LLoss 越小越好。怎么办不用发明任何新东西。乘一个负号就行。最大化log P等价于最小化−log P于是对于一个 TokenL−log Pθ(y|x)它有一个非常直白的名字Negative Log-Likelihood。简称NLL。现在再看这个公式感觉应该和第一次见它完全不一样了。它不是教材突然丢给我们的“标准损失函数”。而是一步一步被逼出来的。真实数据应该获得更高概率。所以最大化 Likelihood。一整条 Sequence 的概率是条件概率连乘。乘积不好处理所以取 Log。训练通常写成最小化所以加负号。最后自然得到L−log P(y|x)这就是为什么语言模型的 Loss 会长成今天这个样子。为什么不是更简单的 (1-p)现在可以回头看开头那个问题了。如果正确 Token 的概率是 (p)为什么不用L1−p而要搞一个L−log p先看数字。正确 Token 概率 p1-p-ln p0.90.10.1050.50.50.6930.10.92.3030.010.994.6050.0000010.99999913.816真正有意思的是后面几行。当模型给正确答案10%1%0.0001%的时候(1-p) 已经几乎贴着 1 不动了。也就是说“错得很严重”和“极度自信地错得离谱”在这个尺度上差得并没有那么明显。而−log p完全不是这种性格。正确答案概率越逼近 0Loss 会持续增大。p→0时−log p→∞这意味着你可以不确定但不要在真实答案面前自信到几乎不给它任何可能性。这恰恰是概率模型很需要的一种惩罚结构。需要说明的是仅凭这一张表并不能简单证明“(1-p) 在数学上绝对不能用”。真正决定性的地方是前面的 Maximum Likelihood 推导。一旦我们的目标是最大化真实数据的 Likelihood那么−log p不是拍脑袋选出来的。它是这个概率建模目标自然导出的结果。Cross Entropy 到底在哪里前面讲的不是 NLL 吗很多人学到这里会卡一下。前面我们明明一路推出来的是−log P(y)这叫 NLL。为什么机器学习框架和大模型论文里又到处都写Cross Entropy Loss这两个到底是不是一回事要回答这个问题必须重新回到第三课。第三课告诉我们模型输出的不是一个答案。而是整个 Vocabulary 上的 Probability Distribution。比如q [0.70,0.15,0.08,0.05,0.02]对应巴黎、伦敦、北京、罗马、香蕉。这里的 (q) 就是模型预测出来的 Distribution。但真实答案巴黎同样可以写成一个 Distributionp [1,0,0,0,0]它表达的意思非常简单巴黎是正确答案概率质量全部放在巴黎上。其他 Token 都是 0。这叫 One-hot Target Distribution。Cross Entropy 的定义是H(p,q) −∑i pilog qi不要急着背。直接把刚才的数据塞进去。因为p[1,0,0,0,0]所以H(p,q) −( 1log 0.70 0log 0.15 0log 0.08 0log 0.05 0log 0.02 )后面全部消失。只剩H(p,q) −log 0.70也就是H(p,q) −log P(正确 Token)到这里Cross Entropy 和 NLL 终于汇合了。在标准的 One-hot Next Token Prediction 中Cross Entropy Negative Log Likelihood不是两个公式碰巧长得一样。而是两个不同视角最后走到了同一个地方。NLL 问的是真实发生的数据在模型看来有多可能Cross Entropy 问的是模型预测出来的分布 (q)和目标分布 (p) 有多不匹配当目标是 One-hot 时这两个问题最终都会落到−log P(正确 Token)到这里才能真正理解Cross Entropy 到底在训练什么假设真实 Token 是巴黎。训练初期模型可能是q [0.30,0.25,0.20,0.15,0.10]巴黎只有 30%。训练一段时间后q [0.60,0.18,0.10,0.07,0.05]继续训练q [0.90,0.04,0.03,0.02,0.01]这三个 Distribution 的变化其实比任何公式都更能说明问题。模型在做什么它正在不断把 Probability Mass 从错误候选那里重新分配。让真实 Token 获得越来越多的概率。于是P(巴黎)↑对应−log P(巴黎)↓最后如果P(巴黎)→1那么Loss→0所以 Cross Entropy 并不是一个神秘的数学仪式。在最标准的 Next Token Prediction 里它干的事情极其具体真实 Token 已经发生了那你就应该把越来越多的概率放到它身上。这里有个很刁钻的问题那其他错误 Token 呢看两个模型。模型 AqA[0.6,0.4,0,0,0]模型 BqB[0.6,0.1,0.1,0.1,0.1]假设第一个 Token 才是正确答案。那么两个模型的 Cross Entropy 都是−log 0.6完全一样。这时很多人会产生一个非常自然的疑问既然 Loss 最后只看正确 Token 的概率那其他错误 Token 怎么分训练系统是不是根本不在乎如果只看这个样本最后得到的Loss 数值确实只剩下−log P(y)但如果因此得出“其他 Token 不参与训练”就错了。真正的原因藏在上一课的 Softmax 里。Softmax 从一开始就没允许任何 Token 独立行动对于第 (i) 个 Tokenqi ezi ∑j ezj所有 Token 的概率满足∑iqi1整个 Vocabulary 一共只有 100% 的 Probability Mass。如果正确 Token 从0.6上升到0.8那剩下所有 Token 加起来就必须从0.4下降到0.2概率不是互相独立的。因为所有 Token 都被同一个 Softmax 分母绑在一起∑j ezj所以Cross Entropy 虽然最后可以写成只看正确 Token−log qy但这个 (qᵧ) 本身就是和整个 Vocabulary 竞争之后得到的。更精彩的是Softmax 和 Cross Entropy 放在一起以后会得到深度学习里一个特别漂亮的结果∂ L∂ zi qi−yi这一课先不推。第五课会专门把它拆开。但现在可以先看它在说什么。假设q [0.70,0.15,0.08,0.05,0.02]Target 是y [1,0,0,0,0]那么q−y [−0.30,0.15,0.08,0.05,0.02]你会发现一个非常关键的事实不是只有正确 Token 收到了训练信号。每一个 Logit 都有。正确 Token 的方向和错误 Token 不一样。而某个错误 Token 当前概率越高它对应的误差信号也会越明显。所以 Cross Entropy 的真正价值不只是“给这次预测打了一个分。”它做了一件更关键的事情把一个概率分布上的错误变成了后面可以继续传播的 Error Signal。从这里开始Loss 才真正有机会改变神经网络。现在你应该重新理解train_loss 2.31以后你训练模型日志里看到train_loss 2.31千万不要在脑子里翻译成“模型这道题错了 2.31 分。”完全不是这个意思。一条 Sequence 里面会有很多预测位置。每一个位置都会产生Lt −log Pθ(xt|xt)比如三个位置正确 Token 概率 pToken Loss -ln p0.800.2230.600.5110.700.357如果简单取 MeanL 0.2230.5110.3573得到L≈0.364真正的大模型训练当然会有大量Batch、Sequence、Token Position。所以训练日志里的 Loss更准确的理解应该是当前参与统计的大量 Token Position各自计算出 Cross Entropy / NLL再按照训练实现进行聚合后的结果。这也是为什么 Loss 是一个非常浓缩的数字。它背后其实汇总了海量 Next Token Prediction。一条普通文本为什么可以自动产生这么多训练信号到这里顺便可以真正理解 Self-Supervised Learning。假设训练语料只有一句“今天 天气 很 好”它天然就能产生看到“今天”预测“天气”。看到“今天天气”预测“很”。看到“今天天气很”预测“好”。根本不需要人工把互联网改造成问题一今天后面是什么答案天气。问题二今天天气后面是什么答案很。原始文本自己就已经同时提供了Context和Target。前面的 Token 是输入。后面的真实 Token 是监督信号。于是海量原始文本可以自动转化为海量(xt,xt)训练对。每一个位置再产生−log Pθ(xt|xt)这就是为什么一个看起来极其简单的 Objective可以扩展到几万亿 Token 的训练规模。Perplexity 到底是什么别再把它理解成“模型在几个词里犹豫”讲 Cross Entropy经常会顺带看到另一个指标Perplexity。简称PPL。假设平均 Token-level NLL 是L如果使用自然对数那么PPLeL例如Lln 2那么PPL2如果Lln 10那么PPL10很多文章会解释“PPL 10可以理解成模型平均在 10 个 Token 之间犹豫。”这个比喻可以帮你建立一点直觉。但千万别把它当定义。PPL 10 并不意味着模型真的只考虑 10 个 Token。Vocabulary 可能有十几万个 Token。概率分布也几乎不可能是均匀的。如果想更扎实地理解 Perplexity可以把公式展开。因为L −1T ∑tlog Pt所以PPL exp ( −1T ∑tlog Pt )利用 Log 和指数的关系可以看成PPL ( ∏t1Pt )1/T这其实是真实 Token 逆概率的几何平均。于是 Perplexity 的意义会清楚很多。如果模型长期给真实 Token 很高的概率PPL 就低。如果模型经常对真实 Token 很没把握PPL 就高。所以更准确地说Perplexity 是平均 Token-level Negative Log-Likelihood 的指数形式用来描述模型在当前数据上的预测不确定程度。但一定要加一个限定在当前 Dataset 和当前 Objective 下。Loss 更低PPL 更低不等于数学一定更强代码一定更强工具调用一定更强聊天一定更好。它首先反映的是语言模型在对应数据分布上的概率建模表现。到这里前四课其实已经完全连起来了第一课我们提出了整个训练闭环Data → Model → Prediction → Loss → Gradient → Parameter Update当时每一个词都知道却没有真正打开。第二课解决的是Prediction 到底在预测什么答案是Pθ(xt|xt)语言模型通过 Next Token Prediction 学习整个语言数据的条件概率结构。第三课继续往模型内部走。Context 进入 Transformer。得到 Hidden State。经过 LM Head 得到 Logits。Logits 再经过 Softmax。最后形成整个 Vocabulary 上的Probability Distribution。到了第四课我们终于把下一段补上Probability Distribution加上训练数据里已经存在的 Ground Truth Token得到Cross Entropy。Cross Entropy 再压缩成Loss。于是现在完整链条已经走到了Text → Token → Context → Transformer → Logits → Softmax → Probability Distribution → Ground Truth → Cross Entropy → Loss到这里大模型已经知道这一次到底错得有多严重。但真正神奇的问题才刚刚开始。最后想明白一个问题这一课就真的学会了假设某一步训练正确 Token 的概率只有0.01于是L−log 0.01≈4.605现在模型终于知道这次预测很差。问题来了。4.605 只是一个数字。但模型里面可能有几十亿几百亿甚至上万亿个参数。那这一个 Loss 到底怎么告诉网络哪一个参数应该增大哪一个参数应该减小LM Head 应该改多少最后一层 Transformer 应该承担多少责任Attention 里的某一个权重怎么办MLP 怎么办更前面的 Embedding 又怎么知道“这次预测错误跟我也有关系”真正需要计算的其实已经不是L而是∂ L∂ w1, ∂ L∂ w2, …, ∂ L∂ wn也就是∇θ L到这里第四课真正完成了自己的任务。第三课解决模型怎样把 Context 变成一个 Probability Distribution第四课解决这个 Probability Distribution 怎样变成一个可以评价错误程度的 Loss第五课则要解决一个位于网络最末端的 Loss究竟怎样把“责任”一层一层传回几十亿个参数那就是 Backpropagation。如果这一课最后只能记住一句话我希望不是“Cross Entropy 的公式是 (−log p)。”而是语言模型训练惩罚的从来不是“你最后选错了哪个 Token”而是当真实 Token 已经发生时你到底给它留下了多少概率。只要这一句话真的想通了Maximum Likelihood、Negative Log-Likelihood、Cross Entropy甚至后面要学的很多训练方法都会开始变得没有那么神秘。