我大概讲一下损失函数的常见概念然后我进入问答阶段,在问题中学习概率与知识。
大模型的训练通常分为两大核心阶段:预训练/指令微调(Pre-training & SFT) 和 人类偏好对齐(Alignment, 如 RLHF/DPO)。
1. 预训练与指令微调阶段:交叉熵损失 (Cross-Entropy Loss)
在这个阶段,无论是让模型阅读海量无标签文本(预训练),还是让它学习特定的问答格式(指令微调),大模型的核心任务都是一致的:Next-token prediction(预测下一个词)。
你可以把预测下一个词看作是一个巨大的多分类问题。假设模型的词表里有 10 万个词(Token),那么模型每生成一个词,就是在做 10 万选 1 的单选题。
工作原理:
对于给定的上下文,模型会输出词表中每个词是下一个词的概率分布。真实的下一个词概率为 1,其他词概率为 0(One-hot 编码)。交叉熵损失的作用就是衡量模型预测的概率分布 与真实的概率分布之间的差距。
数学表达:
对于一个长度为 T的文本序列,大模型的自回归交叉熵损失可以表示为:
-
是真实序列中的第
个词。
-
是这个词前面的所有上下文。
-
是模型预测出正确词
的概率。
模型预测真实词的概率越高,
里面的值就越接近 1,损失
就越小。
2. 人类偏好对齐阶段 (Alignment Stage)
仅仅会"文字接龙"的模型可能会输出有害、带有偏见或不符合人类逻辑的内容。因此需要对齐阶段来规范它的行为。这里最主流的方案是 RLHF(基于人类反馈的强化学习) 和最近非常火的 DPO(直接偏好优化)。
A. RLHF 阶段的损失函数
RLHF 通常需要训练一个"裁判"模型(奖励模型),然后再用这个裁判来指导大模型。
-
奖励模型损失 (Reward Model Loss / Pairwise Ranking Loss):
人类标注员会拿到同一个问题的两个不同回答,并选出哪个更好。奖励模型(RM)的任务就是给好回答打高分,给差回答打低分。它的损失函数基于排序(Ranking):
其中
是被偏好的好回答,
是被拒绝的差回答,
是模型的打分函数,
是 Sigmoid 激活函数。两者分数差距越大,损失越小。
-
PPO 损失 (Proximal Policy Optimization):
在强化学习阶段,大模型(Actor)会根据奖励模型给出的分数来更新自己的参数。PPO 的损失函数非常复杂,主要是为了实现两个目标:最大化奖励 :让生成的回答得分越高越好。KL 散度惩罚 (KL Penalty):限制模型不要为了刷高分而"胡言乱语",确保它的输出分布不要偏离初始的 SFT 模型太远。
B. DPO (直接偏好优化) 损失
由于 RLHF 涉及多个模型的交替训练(Actor, Critic, Reward Model, Reference Model),显存占用大且极不稳定。DPO (Direct Preference Optimization) 提出了一种极其优雅的数学等价替换。
DPO 证明了:不需要专门训练一个奖励模型再做强化学习。我们可以直接把人类的偏好数据(好回答 vs 坏回答)代入到大模型的交叉熵训练中。
DPO 的损失函数:
-
是正在训练的模型,
是冻结的参考模型。
-
它的核心逻辑是:增加模型生成"好回答"的相对概率,同时降低生成"差回答"的相对概率,中间通过
参数控制更新的幅度。
-
优势: 把复杂的强化学习问题,重新变回了类似监督学习(SFT)的分类损失问题。
3.KL散度
KL散度(Kullback-Leibler Divergence) ,有时也被称为相对熵(Relative Entropy),是统计学和信息论中的一个核心概念。
用最白话的方式来说:它就是用来衡量"两个概率分布之间有多大差异"的一把尺子。
假设你有两个概率分布 P 和 Q。P 通常代表"真实数据的分布"或者"我们期望的理想分布",而 Q 代表"模型预测的分布"或者"近似分布"。KL 散度就是用来计算:用 Q 来近似 P 时,我们损失了多少信息。
想象我们要预测明天天气的概率:
-
真实情况(分布 P):晴天 80%,下雨 20%。
-
气象台 A 的预测(分布
):晴天 70%,下雨 30%。
-
气象台 B 的预测(分布
):晴天 10%,下雨 90%。
显然,气象台 A 的预测更接近真实情况,而 B 错得离谱。如果你计算它们与真实情况 P 的 KL 散度:
-
的值会很小(因为两者很接近)。
-
的值会很大(因为两者差异巨大)。
-
如果有个气象台 C 预测也是晴天 80%、下雨 20%,那么
。
数学公式
对于离散的概率分布,KL 散度的公式长这样:
-
是真实分布中事件
发生的概率。
-
是近似分布中事件
发生的概率。
-
如果
和
完全一样,那么
,而
。累加起来 KL 散度就是 0。
回到咱们上一个话题,在 RLHF(基于人类反馈的强化学习)的 PPO 阶段,KL 散度扮演着"狗链子"的作用。
在这个阶段,模型为了拿高分(Reward),可能会开始"投机取巧"。比如,奖励模型可能特别喜欢带有"礼貌用语"的回答,大模型为了刷分,可能会输出:"您好您好您好您好,地球是圆的,谢谢谢谢谢谢。" 这显然不是人类想要的正常交流。
为了防止大模型在追求高分的路上"走火入魔",研究人员引入了 KL 惩罚(KL Penalty):
-
我们把刚刚经过指令微调(SFT)、说话最像正常人的模型当作参考模型(分布 P)。
-
把正在强化学习、拼命刷分的模型当作当前模型(分布 Q)。
-
在模型每更新一步时,我们都会计算
。如果当前模型
的生成风格偏离原始模型
太远,KL 散度就会飙升,系统就会狠狠地扣它的分。
所以,在大模型的对齐训练中,KL 散度的意义就是:允许你为了拿高分去优化回答,但你的说话方式必须被限制在"正常语言模型"的分布范围内,不能胡言乱语。
面试题目
1.什么是KL散度?KL散度公式是什么
2.什么是交叉熵损失,公式写一下
3.多任务学习中不同任务的loss差异过大怎样处理?
4.分类问题为什么都用交叉熵损失函数不用均方误差(MSE)?
5.什么是信息增益?
6.多分类任务的交叉熵损失是什么?
7.如果softmax的e次方超过float的值了怎么办?
解析:
1.参考上文
2.参考上文
3.多任务训练
什么叫多任务训练 (Multi-Task Learning, MTL)?
一句话解释:让同一个 AI 模型同时学习并完成多个不同的、但通常有关联的任务。
打个比方,传统的单任务模型就像是一个"偏科生",一辈子只钻研数学,或者只钻研物理。而多任务模型是一个"全科生",被要求同时学习数学、物理和化学。
在深度学习的结构里,它最经典的形态是 "共享底层 (Shared Bottom) + 独立顶层 (Task-specific Heads)":
-
共享底层: 模型前面的一大半网络结构是所有任务共用的。它的职责是提取通用的基础特征(比如在图像里寻找边缘和轮廓,或者在文本里理解基础的语法和词性)。
-
独立顶层: 模型到了最后几层会分叉,长出几个不同的"脑袋"。每个脑袋专门负责输出一个特定任务的结果(比如一个脑袋负责给文章分类,另一个脑袋负责提取文章里的关键人名)。
在多任务学习中,如果不同任务的损失函数差异过大(例如,Task A 是一个均方误差极大的回归任务,Loss 动辄上千;Task B 是一个交叉熵分类任务,Loss 只有 0.1),那么在反向传播时,Loss 大的任务产生的梯度会彻底"淹没" Loss 小的任务 。 这会导致模型几乎把所有参数都用来拟合 Task A,而对 Task B "视而不见",这种现象被称为梯度支配或任务饥饿。
要解决这个问题,业界通常会从以下四个递进的层次来处理:
1. 静态缩放与对齐
如果你不想引入太复杂的算法,可以先尝试对 Loss 本身进行数学上的暴力拉平。
-
初始损失归一化 (Initial Loss Normalization):
不要让任务之间比拼绝对大小,而是比拼"相对下降进度"。记录下每个任务在第一轮(Epoch 0 或 Step 0)的初始损失
,后续的损失都除以这个初始值。
这样,所有任务的 Loss 在训练开始时都在 1.0 左右,处于同一起跑线。
-
Log 平滑变换:
如果某个任务的 Loss 是指数级波动的,可以在加权前套一层 Log:
,这能极大地压制异常偏大的 Loss 峰值。
2. 基于不确定性的自适应加权
这是目前工程上性价比最高、最常用的方法之一(出自 CVPR 2018 剑桥大学的论文)。它的核心思想是:不要手动调权重,让模型自己去学。
它把每个任务的损失看作带有不确定性(同方差噪声)的观测值。为每个任务引入一个可学习的标量参数 (代表该任务的噪声或难度):
- 工作原理: 如果某个任务的
天生特别大,模型会自动增大对应的
,从而拉低这一项在总 Loss 中的权重;同时,后面的
是正则化项,防止模型无限度地把
放大来作弊。通过这种机制,模型会在训练中自动找到一个平衡点。
3. 关注学习进度的动态调整 (DWA 等)
有些方法不看 Loss 的绝对值,而是看 Loss 的下降速度。
- 动态权重平均 (Dynamic Weight Averaging, DWA): 如果 Task A 的 Loss 在过去几个 Epoch 里下降得非常快,说明它学得很好,系统就会降低 它的权重;如果 Task B 的 Loss 遇到瓶颈停滞不前,系统就会提高它的权重,强迫模型分出精力去啃硬骨头。
4. 梯度级别的硬核干预
既然 Loss 差异大的根本危害是"梯度大小差异大",那不如跳过 Loss,直接去管控底层共享网络(Shared Bottom)传递过来的梯度。
-
GradNorm: 在共享层的最后一层,计算不同任务带来的梯度范数(梯度的绝对大小)。GradNorm 会动态计算出一组 Loss 权重,强迫不同任务在共享层产生的梯度大小保持一致。无论你的 Loss 是 1000 还是 0.1,到了共享层,大家抢夺参数更新的"力气"是一样大的。
-
PCGrad (Projecting Conflicting Gradients): 除了大小差异,多任务梯度还会有方向冲突(Task A 要往左走,Task B 要往右走,夹角大于 90 度)。PCGrad 会将冲突的梯度投影到彼此的法向量上,不仅解决了方向打架的问题,也变相削弱了过于强势的梯度。
4.分类损失
在分类任务中,我们通常期望模型输出的是一个概率分布(也就是经过 Sigmoid 或 Softmax 激活函数处理后的结果,值域在 0 到 1 之间)。如果我们在这个基础上去强行使用均方误差(MSE),会遭遇三个致命的数学灾难。
1. 致命的"梯度消失":错得越离谱,反而学得越慢
这是 MSE 在分类问题中最被诟病的一点。在神经网络中,参数的更新依赖于损失函数的梯度(也就是导数)。我们希望模型"如果错得很离谱,就用很大的步伐去纠正;如果快接近正确答案了,就微调"。
如果使用 MSE + Sigmoid:
假设真实标签 ,模型输出的概率为
。
MSE 的损失函数求导后,其梯度中会包含一个激活函数的导数项 :
-
灾难场景: 如果模型极其自信地给出了一个绝对错误的答案(比如输出
,但真实
),此时
的值会无限接近于 0。
-
结果: 整个梯度变成了 0。模型明明大错特错,但它的参数却卡死不动了,根本无法学习。
如果使用 交叉熵 (Cross-Entropy) + Sigmoid/Softmax:
交叉熵神奇的对数设计恰好可以和 Sigmoid 的导数完美抵消。最终的梯度极度精简:
- 完美场景: 梯度直接等于"预测值与真实值的差"。你错得越远,差值越大,梯度就越大,模型更新就越快。完美符合人类的学习直觉。
2. 损失平面的形状:非凸优化 vs 严格凸优化
想象你在一个连绵起伏的山脉中蒙着眼睛找最低的谷底(这就是梯度下降的过程)。
-
使用 MSE: 当 MSE 与非线性激活函数(如 Sigmoid)结合时,它构成的损失函数是一个非凸函数(Non-convex)。它的表面就像坑坑洼洼的月球表面,充满了无数个"局部最优解"。你的模型极容易掉进一个半山腰的浅坑里出不来,导致训练失败。
-
使用交叉熵: 交叉熵损失函数经过严谨的数学证明,是一个严格的凸函数(Strictly Convex)。它的表面就像一个平滑的、完美的碗。无论你的初始参数落在碗的哪个位置,只要顺着坡度往下走,就一定会且必定会滑落到碗的最底部(全局最优解)。
3. 概率论视角的底层假设:高斯分布 vs 伯努利分布
损失函数不是凭空捏造的,它们本质上都是最大似然估计(MLE)在不同数据分布假设下的推导结果。
-
MSE 的数学本质: MSE 的底层假设是:数据的误差服从高斯分布(正态分布)。这在预测连续数值(回归问题,比如预测房价、温度)时是非常合理的,因为真实世界的误差通常呈钟形曲线。但分类问题的标签是离散的(比如 0 或 1,猫或狗),根本不符合高斯分布。
-
交叉熵的数学本质: 交叉熵的底层假设是:数据服从伯努利分布(二项分布)或多项式分布。这完全契合分类问题(抛硬币,非黑即白,或者多选一)的物理现实。使用交叉熵,就是在数学理论最严密的框架下,最大化模型预测出正确分类的概率。
| 对比维度 | 均方误差 (MSE) | 交叉熵 (Cross-Entropy) |
|---|---|---|
| 适用场景 | 回归问题 (预测连续数值) | 分类问题 (预测离散概率) |
| 底层概率假设 | 误差服从高斯分布 | 结果服从伯努利/多项式分布 |
| 结合 Sigmoid 的梯度 | 存在梯度消失风险,错得越远更新越慢 | 线性梯度 ,错得越远更新越快 |
| 损失函数凸性 | 非凸,容易陷入局部最优 | 严格凸函数,保证能找到全局最优 |
5.信息增益
要真正弄懂"信息增益"(Information Gain),我们需要先理解它的前置概念------信息熵(Entropy) 。信息增益本质上是用来衡量我们在获取了某个特征的信息后,对事物不确定性消除了多少。
这个概念在机器学习中,尤其是决策树算法(如 ID3)中扮演着绝对核心的角色。
1. 前置概念:什么是信息熵 (Entropy)?
在信息论中,熵用来度量一个系统的不确定性或"混乱程度"。
-
高熵(很混乱): 假设一个袋子里有 5 个红球和 5 个黑球,你随便抓一个,很难确定是什么颜色。这时候不确定性最高,熵最大。
-
低熵(很纯粹): 假设袋子里有 9 个红球和 1 个黑球,你随便抓一个,大概率是红球。这时候不确定性较低,熵较小。
-
零熵(完全确定): 袋子里全是红球。你百分百确定会抓到红球,完全没有不确定性,熵为 0。
数学公式: 对于一个包含 种类别的数据集
,其信息熵的计算公式为:
其中, 是第
类样本在数据集中出现的概率。
2. 正式定义:什么是信息增益?
信息增益 = 分类前的不确定性(初始熵) - 分类后的不确定性(条件熵)。
用大白话来说:我们在做一个决定或预测时,如果我们知道了某个特征(比如天气、年龄、收入等),能帮我们排除掉多少"瞎猜的成分"。排除的瞎猜成分越多,信息增益就越大。
数学公式: 假设我们用特征 来对数据集
进行划分,那么特征
带来的信息增益为:
-
是划分前整体数据集的初始信息熵。
-
是知道了特征
之后,数据集剩下的条件熵(通常是按特征
的不同取值划分后的子集熵的加权平均)。
假设你在玩猜人物游戏,你需要在 100 个人里猜出对方心里想的是谁。这时候你面临的"初始熵"(不确定性)是非常高的。
为了缩小范围,你可以问一个问题(也就是选择一个特征进行分类)。你有两个问题可以选择:
-
特征 A(性别): "这个人是男的吗?" 假设 100 个人里 50 男 50 女。对方回答"是",你的候选人立刻缩减到 50 人。不确定性大幅下降。这个特征带来的信息增益很高。
-
特征 B(是否长了两只眼睛): "这个人有两只眼睛吗?" 100 个人里 99 个人都有两只眼睛。对方回答"是",你的候选人只缩减到了 99 人,你还是不知道是谁。不确定性几乎没变。这个特征带来的信息增益极低。
在构建决策树模型时,面对几十甚至上百个特征(比如预测房价时的面积、楼层、朝向、房龄等),模型怎么知道应该先看哪个特征呢?
决策树的贪心策略就是:每次都去计算所有特征的信息增益,谁的信息增益最大(谁最能消除不确定性),就选谁作为当前的分类节点(分裂点)。
-
第一步:计算发现"地段"的信息增益最大,于是树的根节点就是"地段"。
-
第二步:在划分好的子区域里,继续算剩下的特征,发现"面积"增益最大,于是第二层节点就是"面积"。
-
以此类推,直到把数据完全分离开来(熵降为 0)。
一个小缺陷补充: 信息增益有一个天生的缺点:它倾向于选择取值分支非常多的特征 。比如如果有一个特征是"身份证号",因为每个人的身份证号都不一样,如果按它分类,每个子集里都只有一个人(完全纯粹,熵为 0),信息增益达到了最大值。但这在现实预测中是毫无意义的(严重过拟合)。后来 C4.5 算法引入了信息增益率(Gain Ratio),就是专门为了修复这个缺陷。
6.多分类损失函数
在多分类问题中,我们使用的损失函数叫做多分类交叉熵损失(Categorical Cross-Entropy Loss)。
第一步:Softmax 出场(将"原始得分"变成"概率")
假设我们在做一个猫、狗、猪的三分类任务。神经网络的最后一层(全连接层)通常会输出一组未经处理的实数得分,我们称之为 Logits 。比如:[3.0, 1.0, -2.0]。
这些数字有正有负,加起来也不等于 1,没法直接当成概率来用。这时候就需要请出 Softmax 函数:
-
是某个类别的原始得分(Logit)。
-
是总类别数。
Softmax 做了两件非常巧妙的事:
-
引入指数运算 (
): 把所有的负数都变成了正数,并且放大了得分之间的差异 。原本得分只差一点点,经过
放大后,赢家通吃(Soft-max 的名字也是这么来的,它是对 Max 函数的一种平滑近似)。
-
归一化处理: 把每个类别放大后的值,除以所有类别放大后的值之和。这样保证了最终输出的所有概率都在 0 到 1 之间,且加起来绝对等于 1。
经过 Softmax 处理后,刚才的 [3.0, 1.0, -2.0] 可能就变成了完美的概率分布:[0.88, 0.11, 0.01]。
第二步:交叉熵出场(计算"预测概率"与"绝对真理"的差距)
现在模型给出了预测概率:猫 88%,狗 11%,猪 1%。 而真实标签(Ground Truth)通常采用 One-Hot 编码 ,假设这张图真的是猫,标签就是:[1, 0, 0]。
接下来,多分类交叉熵损失(Categorical Cross-Entropy Loss) 就要上场来计算误差了:
-
是真实的标签值(One-Hot 编码,只有正确类别是 1,其他全是 0)。
-
是模型经过 Softmax 输出的该类别的预测概率。
这个公式的精妙之处在于:
因为除了正确类别之外,其他类别的真实标签 都是 0。所以求和符号
里的绝大多数项都被 0 乘没了!整个公式实际上直接坍缩成了:
在我们的例子中,损失就是 。
只要模型给正确类别的预测概率 越接近 1,
就越接近 0,损失就越小。
7.MAX技巧
在常用的单精度浮点数(float32)下,它能表示的最大值大约是 。而指数函数
的增长是极其狂暴的,只要你的输入得分(Logit)超过 89 ,
就已经足以把
float32 撑爆,直接变成 inf(无穷大)。
一旦出现 inf,接下来的加减乘除都会变成 NaN(Not a Number),你的模型参数瞬间就会全部崩溃(也就是常说的"Loss 炸了")。
为了解决这个问题,所有的主流深度学习框架(PyTorch, TensorFlow 等)在底层实现 Softmax 时,都会偷偷使用一个极其简单却极其优雅的数学魔法:Max 技巧 (The Max Trick / Shifted Softmax)。
这个技巧的操作非常粗暴:在算 之前,找出所有得分里的最大值,然后让所有的得分都减去这个最大值。
假设你的模型输出了三个极其离谱的得分:。
直接算 电脑会当场死机。
使用了 Max 技巧后:
-
找到最大值:
。
-
所有得分减去最大值:
。
-
对新得分算 Softmax:
。
你看,最大也就是 1,其他的都是小于 1 的正小数,完美避开了无穷大(Overflow)的问题!
你可能会问:随便改变输入的得分,算出来的概率分布不会变吗?
答案是:绝对不会变。 这是由指数运算的性质决定的。
我们在分子和分母上同时乘以一个常数 (其中
是最大得分),数学推导如下:
你看,减去一个常数 c,在数学上是完全等价的。真实的概率分布连小数点后任意位都不会改变。
下溢出 (Underflow) 怎么办?
既然减去了最大值,那原本就很小的数字,减完之后会变成一个绝对值极大的负数(比如 )。
这时候去算 ,超出了浮点数能表示的最小精度,电脑会把它四舍五入变成 0 。这就是下溢出(Underflow)。
这会导致灾难吗?完全不会。
-
对于分子: 如果它变成了 0,说明这个类别的原始得分实在太低了,它对应的概率本来就无限趋近于 0,直接当成 0 对结果没有任何影响。
-
对于分母: 因为我们减去的是最大值,所以这组数里必定有一个 0 (最大值减最大值等于 0)。因此,分母里必定包含一个
。这就保证了分母绝对不可能为 0,永远不会出现
0 / 0这种除以零的致命报错。