当一个语言模型预测下一个词时,它输出的是整个词表上的概率分布。比如在"今天天气很"这个上下文后,模型可能给出"好"的概率是0.7,“差"的概率是0.2,“热"的概率是0.08,其他词的概率更低。如果真实的下一个词确实是"好”,我们如何量化模型预测的质量?更进一步,如何设计一个可微分的损失函数,让模型能够通过梯度下降不断优化这个预测能力?

交叉熵损失函数提供了这个问题的答案。它不仅统治了现代深度学习中的分类任务,更是理解整个概率机器学习框架的核心概念。从1948年香农创立信息论,到今天千亿参数的大语言模型训练,交叉熵始终是连接信息论、概率统计和优化算法的关键桥梁。

graph TD
    A[信息论基础] --> B[自信息 I x = -log p x]
    B --> C[熵 H P = E I x]
    C --> D[交叉熵 H P,Q]
    D --> E[KL散度 D_KL = H P,Q - H P]
    
    F[机器学习] --> G[最大似然估计]
    G --> H[负对数似然]
    H --> D
    
    I[深度学习] --> J[分类任务]
    J --> K[Softmax输出概率]
    K --> L[交叉熵损失]
    L --> D
    
    style D fill:#f9f,stroke:#333
    style L fill:#bbf,stroke:#333

从自信息到熵:理解"惊讶"的度量

要理解交叉熵,必须先回到信息论最基础的概念:如何量化一个事件的"信息量"或"惊讶程度”。

自信息:稀有事件更令人惊讶

1948年,克劳德·香农在《通信的数学理论》中提出了一个深刻的问题:如何度量一个随机事件所携带的信息量?他的答案是:事件越不可能发生,发生时带来的"惊讶"就越大,信息量也越大。

对于概率为 $p$ 的事件,自信息定义为:

$$I(x) = -\log_2 p(x)$$

使用以2为底的对数,信息量的单位是"比特"。这个定义有几个直观的合理性:

确定事件不带来新信息。如果 $p = 1$,则 $I(x) = -\log_2(1) = 0$。这完全符合直觉——如果你百分百确定某事会发生,那么当它发生时你并不感到惊讶,也没有获得任何新信息。

不可能事件带来无穷信息。当 $p \to 0$ 时,$I(x) \to \infty$。一个几乎不可能发生的事件竟然发生了,这带来的震惊是巨大的。

概率的对数关系保证了可加性。假设两个独立事件同时发生,联合概率是各自概率的乘积 $p(x)p(y)$,而自信息则是各自自信息的和:

$$I(x,y) = -\log_2[p(x)p(y)] = -\log_2 p(x) - \log_2 p(y) = I(x) + I(y)$$

这符合直觉:两个独立事件同时发生的惊讶程度,等于各自惊讶程度的叠加。

举个具体的例子。抛一枚公平硬币得到正面,概率是 $1/2$,自信息是 $-\log_2(0.5) = 1$ 比特。掷一个公平骰子得到6,概率是 $1/6$,自信息是 $-\log_2(1/6) \approx 2.58$ 比特。后者更令人惊讶,因为它更稀有。

熵:平均惊讶程度的度量

自信息度量的是单个事件的惊讶程度,但很多时候我们关心的是整个概率分布的"不确定性"或"混乱程度"。这就引出了熵的概念。

熵是自信息的期望值,对于一个离散概率分布 $P$,其熵定义为:

$$H(P) = -\sum_{x} p(x) \log_2 p(x)$$

熵度量的是:如果我们从这个分布中随机抽取样本,平均会获得多少信息量。熵越高,分布越不确定;熵越低,分布越确定。

graph LR
    subgraph "低熵分布 - 确定性高"
    A1[事件A: p=0.9] --> A2[事件B: p=0.1]
    end
    
    subgraph "高熵分布 - 不确定性高"
    B1[事件A: p=0.5] --> B2[事件B: p=0.5]
    end
    
    C[确定性分布] -->|熵=0| D[完全可预测]
    E[均匀分布] -->|熵=max| F[最难预测]
    
    style A1 fill:#afa,stroke:#333
    style B1 fill:#ffa,stroke:#333
    style B2 fill:#ffa,stroke:#333

确定性分布的熵为零。如果分布只取一个值(概率为1),熵是0。比如一个永远输出"是"的随机变量,没有任何不确定性。

均匀分布的熵最大。对于有 $n$ 个可能取值的随机变量,均匀分布 $p(x) = 1/n$ 的熵是:

$$H_{\max} = -\sum_{i=1}^{n} \frac{1}{n} \log_2 \frac{1}{n} = \log_2 n$$

这符合直觉:当所有结果都同等可能时,不确定性最大。

以一个50000词的词表为例。如果模型对下一个词完全无知,给出均匀分布,熵是 $\log_2(50000) \approx 15.6$ 比特。这意味着平均需要15.6比特来编码每个词。但如果模型能够准确预测,只给正确词分配概率1,熵降为0——不需要任何比特来传输,因为接收方已经知道答案。

交叉熵:衡量预测与真相的距离

理解了熵,交叉熵就水到渠成了。

从编码视角理解交叉熵

假设你要设计一套编码方案来传输消息。你知道消息的真实分布是 $P$,但你误以为分布是 $Q$,因此基于 $Q$ 设计了编码方案。

在这种"错误假设"下,传输一个消息所需的平均比特数是多少?答案就是交叉熵:

$$H(P, Q) = -\sum_{x} p(x) \log_2 q(x)$$

这里,$p(x)$ 是真实分布中事件 $x$ 出现的概率,而 $-\log_2 q(x)$ 是基于错误假设设计的编码方案对 $x$ 分配的比特数。

交叉熵告诉我们要为"错误认识"付出的代价:如果你假设的分布 $Q$ 与真实分布 $P$ 差别很大,交叉熵就会很高;如果 $Q$ 很接近 $P$,交叉熵就会很低。

一个关键性质:交叉熵永远不小于熵本身。即:

$$H(P, Q) \geq H(P)$$

这很合理:用错误的假设来编码,永远不可能比用正确的假设编码更高效。当且仅当 $P = Q$ 时等号成立。

KL散度:纯粹的距离度量

交叉熵与熵的差值,被称为KL散度(Kullback-Leibler散度):

$$D_{KL}(P \| Q) = H(P, Q) - H(P) = \sum_{x} p(x) \log_2 \frac{p(x)}{q(x)}$$

KL散度度量的是:因为假设了错误的分布 $Q$ 而不是真实分布 $P$,我们"额外"浪费了多少比特。它是一个纯粹的距离度量——如果 $P = Q$,KL散度为0。

在机器学习中,这个分解至关重要:

$$H(P, Q) = H(P) + D_{KL}(P \| Q)$$

当我们训练模型时,真实分布 $P$ 是固定的(由训练数据决定),所以 $H(P)$ 是常数。最小化交叉熵 $H(P, Q)$,完全等价于最小化KL散度 $D_{KL}(P \| Q)$——让模型的预测分布尽可能接近真实分布。

graph TD
    A[交叉熵 H P,Q] --> B[熵 H P]
    A --> C[KL散度 D_KL P Q]
    
    B --> D[真实分布的不确定性<br/>与模型参数无关]
    C --> E[预测与真相的距离<br/>优化目标]
    
    F[训练模型] --> G[最小化交叉熵]
    G --> H[等价于最小化KL散度]
    
    style A fill:#fbb,stroke:#333
    style B fill:#bfb,stroke:#333
    style C fill:#fbf,stroke:#333
    style E fill:#ff9,stroke:#333

为什么深度学习选择交叉熵而不是MSE?

很多初学者会有疑问:既然我们要让预测分布接近真实分布,为什么不直接用均方误差(MSE)?

数学直觉:交叉熵惩罚更"锐利"

考虑一个三分类问题,真实类别是第1类(one-hot编码为 $[1, 0, 0]$)。

场景A:模型预测概率是 $[0.7, 0.2, 0.1]$

  • 交叉熵损失:$-\log(0.7) \approx 0.357$
  • MSE损失:$(1-0.7)^2 + (0-0.2)^2 + (0-0.1)^2 = 0.14$

场景B:模型预测概率是 $[0.4, 0.4, 0.2]$

  • 交叉熵损失:$-\log(0.4) \approx 0.916$
  • MSE损失:$(1-0.4)^2 + (0-0.4)^2 + (0-0.2)^2 = 0.56$

从场景A到场景B,预测变差了。交叉熵损失从0.357增加到0.916,增长了约157%。MSE损失从0.14增加到0.56,增长了约300%。

看起来MSE对错误更敏感?但问题在于梯度特性

梯度分析:交叉熵与Softmax的完美配合

这是交叉熵在分类任务中占据统治地位的真正原因。

当输出层使用Softmax激活函数时,Softmax将原始输出(logits)转换为概率分布:

$$s_i = \frac{e^{z_i}}{\sum_{j} e^{z_j}}$$

其中 $z$ 是网络的原始输出,$s$ 是概率分布。

现在计算交叉熵损失对logits $z_k$ 的梯度。交叉熵损失是:

$$\mathcal{L} = -\sum_{i} y_i \log s_i$$

其中 $y$ 是one-hot编码的真实标签。

经过推导,梯度有一个令人惊讶的简洁形式:

$$\frac{\partial \mathcal{L}}{\partial z_k} = s_k - y_k$$

这个结果优雅得令人窒息:梯度就是预测概率与真实标签的差值!

如果真实类别是 $c$($y_c = 1$,其他为0),那么:

  • 对于正确类别:$\frac{\partial \mathcal{L}}{\partial z_c} = s_c - 1$(负值,会增加 $z_c$)
  • 对于错误类别:$\frac{\partial \mathcal{L}}{\partial z_k} = s_k$(正值,会减少 $z_k$)

这个梯度有一个关键特性:无论预测概率多小,梯度都不会消失。即使模型对正确类别给出 $s_c = 0.001$ 的极低概率,梯度仍然是 $0.001 - 1 = -0.999$,足够大,能够驱动模型学习。

graph LR
    subgraph "Softmax + 交叉熵"
    A1[Logits z] --> B1[Softmax]
    B1 --> C1[概率 s]
    C1 --> D1[交叉熵 L]
    D1 --> E1[梯度: s - y]
    E1 -->|简洁优雅| F1[无梯度消失]
    end
    
    subgraph "Sigmoid + MSE"
    A2[Logits z] --> B2[Sigmoid]
    B2 --> C2[概率 σ z]
    C2 --> D2[MSE]
    D2 --> E2[复杂梯度]
    E2 -->|饱和区| F2[梯度消失]
    end
    
    style F1 fill:#afa,stroke:#333
    style F2 fill:#faa,stroke:#333

MSE的梯度困境

对比之下,如果使用MSE损失:

$$\mathcal{L}_{MSE} = \sum_{i} (y_i - s_i)^2$$

梯度计算会涉及Softmax的雅可比矩阵,形式复杂得多。更糟糕的是,当模型使用Sigmoid激活(输出在0到1之间)时,MSE损失在饱和区会出现梯度消失问题。

假设二分类问题,真实标签 $y=1$,模型输出 $\hat{y}$。MSE损失是 $(1-\hat{y})^2$,梯度是 $-2(1-\hat{y}) \cdot \hat{y}(1-\hat{y})$(考虑Sigmoid导数)。

当 $\hat{y} \approx 0$(模型严重错误)时,梯度是 $-2(1-0) \cdot 0 \cdot 1 = 0$。模型错得离谱,梯度反而消失了。

而交叉熵损失 $-\log(\hat{y})$ 在 $\hat{y} \approx 0$ 时梯度是 $-1/\hat{y}$,趋近于无穷大——错误越严重,修正越强烈。这正是我们希望的行为。

与最大似然估计的深刻等价性

交叉熵在机器学习中的统治地位,还有一个更深层的理论支撑:它与最大似然估计完全等价。

从最大似然到交叉熵

假设我们有一个参数化模型 $q_\theta$,要拟合真实数据分布 $p$。最大似然估计的目标是找到参数 $\theta$,使得观测数据出现的概率最大:

$$\theta_{MLE} = \arg\max_\theta \prod_{i=1}^{n} q_\theta(x_i)$$

取对数(不改变最优解):

$$\theta_{MLE} = \arg\max_\theta \sum_{i=1}^{n} \log q_\theta(x_i)$$

取负号,变成最小化问题:

$$\theta_{MLE} = \arg\min_\theta -\sum_{i=1}^{n} \log q_\theta(x_i)$$

这正是交叉熵损失的形式!对于分类问题,如果 $x_i$ 是第 $c$ 类,则 $q_\theta(x_i) = q_\theta(y_c)$ 是模型对该类别的预测概率。

因此,最小化交叉熵损失完全等价于最大似然估计。这不是巧合,而是深刻的理论统一:选择交叉熵作为损失函数,等价于我们相信最大似然是一个好的统计推断原则。

数值稳定性:工程实现的隐形艺术

理论上完美的公式,在实际计算中可能遭遇灾难。交叉熵与Softmax的组合就是一个经典案例。

溢出的陷阱

Softmax的定义是:

$$s_i = \frac{e^{z_i}}{\sum_{j} e^{z_j}}$$

当 $z_i$ 很大时,比如 $z_i = 1000$,则 $e^{1000}$ 会超出float64的表示范围,变成无穷大。于是我们得到 $\infty/\infty = \text{NaN}$。

Log-Sum-Exp技巧

解决方案是利用一个简单的数学恒等式。对于任意常数 $c$:

$$\frac{e^{z_i}}{\sum_j e^{z_j}} = \frac{e^{z_i + c}}{\sum_j e^{z_j + c}} = \frac{e^{z_i - \max(z)}}{\sum_j e^{z_j - \max(z)}}$$

关键洞察:减去最大值后,所有指数的输入都变成非正数,最大值是0(对应原来最大的那个元素)。因此 $e^{z_i - \max(z)}$ 永远在 $[0, 1]$ 范围内,不会溢出。

flowchart TD
    A[原始Softmax] --> B["问题: e^1000 溢出"]
    
    C[Log-Sum-Exp技巧] --> D["减去最大值: z - max z"]
    D --> E["e^ z_i - max z ∈ 0,1"]
    E --> F["分子分母同时放大/缩小"]
    F --> G["结果不变,但数值稳定"]
    
    H[LogSoftmax实现] --> I["log s_i = z_i - max z - log Σexp"]
    I --> J["避免计算exp和log分开"]
    J --> K["一次计算,无精度损失"]
    
    style B fill:#faa,stroke:#333
    style G fill:#afa,stroke:#333
    style K fill:#afa,stroke:#333

更进一步,计算 $\log(\text{softmax}(z_i))$ 可以直接得到:

$$\log(s_i) = z_i - \max(z) - \log\left(\sum_j e^{z_j - \max(z)}\right)$$

这被称为Log-Sum-Exp技巧。现代深度学习框架都采用这个实现。

PyTorch的实现智慧

PyTorch的CrossEntropyLoss实际上结合了LogSoftmaxNLLLoss(负对数似然损失):

import torch
import torch.nn as nn

# 方式1:分开计算
log_softmax = nn.LogSoftmax(dim=1)
nll_loss = nn.NLLLoss()
loss = nll_loss(log_softmax(logits), targets)

# 方式2:合并计算(推荐)
cross_entropy = nn.CrossEntropyLoss()
loss = cross_entropy(logits, targets)

两种方式数学上等价,但第二种更高效且数值更稳定,因为框架可以在内部融合操作,避免中间结果的精度损失。

在语言模型中的核心地位

交叉熵损失是大语言模型训练的基石。理解它在语言模型中的具体应用,能让我们更深刻地把握其本质。

下一个词预测:序列上的交叉熵

语言模型的训练目标是预测序列中的下一个词。对于序列 $x_1, x_2, ..., x_T$,模型在每个位置 $t$ 输出一个概率分布,表示对下一个词的预测。

训练时,交叉熵损失定义为:

$$\mathcal{L} = -\frac{1}{T} \sum_{t=1}^{T} \log p(x_t | x_{这里,$p(x_t | x_{

这个公式有一个直观解释:我们希望模型对序列中每个真实出现的词都分配尽可能高的概率。模型的"困惑"程度越低,损失越小。

sequenceDiagram
    participant 输入序列
    participant 模型
    participant Softmax
    participant 交叉熵
    
    输入序列->>模型: x_1
    模型->>Softmax: logits_1
    Softmax->>交叉熵: P x_2 x_1
    交叉熵->>交叉熵: -log P x_2 x_1
    
    输入序列->>模型: x_1, x_2
    模型->>Softmax: logits_2
    Softmax->>交叉熵: P x_3 x_1,x_2
    交叉熵->>交叉熵: -log P x_3 x_1,x_2
    
    Note over 交叉熵: 平均: -1/T Σ log P x_t x_<t

困惑度:交叉熵的另一种表达

困惑度是语言模型评估中最常用的指标之一,它直接源于交叉熵:

$$\text{PPL} = \exp\left(-\frac{1}{T}\sum_{t=1}^{T} \log p(x_t | x_{困惑度可以理解为"有效词表大小"。如果模型的困惑度是100,意味着模型的不确定性等同于在100个等概率选项中随机选择。

困惑度为词表大小时,模型等价于随机猜测。比如词表有50000词,困惑度50000意味着模型毫无预测能力。困惑度为1意味着模型对每个词都完全确定,这通常意味着过拟合。

一个训练良好的英语语言模型,在标准测试集上的困惑度可能在15-30之间,表示模型在每个位置平均在15-30个候选词中选择。

Bits Per Character:消除分词器的影响

不同模型使用不同的分词器,直接比较困惑度可能不公平。Bits Per Character (BPC) 通过按字符归一化来解决这个问题:

$$\text{BPC} = \frac{H(P, Q) \times \text{token数}}{\text{字符数}} \times \log_2 e$$

BPC表示平均每个字符需要多少比特来编码。这是信息论与数据压缩理论的直接联系:一个好的语言模型本质上是一个好的文本压缩器。

现代大模型在英文文本上可以达到约0.7-0.9 BPC,接近人类估计的英语熵(约0.6-1.0 BPC)。

变体与扩展:从二分类到多标签

交叉熵损失有几个重要变体,适用于不同的任务场景。

二分类交叉熵

对于二分类问题,我们只需要预测一个类别的概率 $\hat{y}$(另一个类别的概率自动是 $1-\hat{y}$)。二分类交叉熵定义为:

$$\mathcal{L}_{BCE} = -[y \log \hat{y} + (1-y) \log(1-\hat{y})]$$

这可以看作是多分类交叉熵在类别数为2时的简化形式。

多标签分类的交叉熵

多标签分类中,一个样本可以同时属于多个类别。比如一张图片可能同时包含"猫"、“户外”、“白天"等多个标签。

处理多标签分类的标准方法是将问题分解为多个独立的二分类问题:对每个类别,用Sigmoid函数预测该类别是否存在,然后用二分类交叉熵计算损失:

$$\mathcal{L} = -\sum_{c=1}^{C} [y_c \log \sigma(z_c) + (1-y_c) \log(1-\sigma(z_c))]$$

这里 $\sigma$ 是Sigmoid函数,$y_c \in \{0, 1\}$ 表示样本是否属于类别 $c$。

标签平滑:防止过度自信

标准的交叉熵使用hard label(正确类别概率为1,其他为0)。这可能导致模型过度自信,泛化能力下降。

标签平滑(Label Smoothing)将hard label转换为soft label:

$$y'_c = \begin{cases} 1 - \epsilon + \frac{\epsilon}{C} & \text{如果 } c \text{ 是正确类别} \\ \frac{\epsilon}{C} & \text{其他情况} \end{cases}$$

其中 $\epsilon$ 是平滑系数(通常取0.1),$C$ 是类别数。

这相当于告诉模型:正确类别的概率不是100%,错误类别也有小概率出现。标签平滑鼓励模型产生更平滑的概率分布,提高泛化能力。

在Transformer论文《Attention Is All You Need》和Inception-v2论文中,标签平滑都被证明能提升模型性能。

Focal Loss:处理类别不平衡

当正负样本严重不平衡时(如目标检测中的背景vs物体),标准交叉熵的效果往往不佳。Focal Loss对交叉熵进行了修改:

$$\mathcal{L}_{FL} = -(1-p_t)^\gamma \log(p_t)$$

其中 $p_t$ 是模型对正确类别的预测概率,$\gamma$ 是聚焦参数(通常取2)。

关键思想:当 $p_t$ 接近1时(模型预测正确且自信),$(1-p_t)^\gamma$ 趋近于0,损失被抑制。这减少了简单样本的主导地位,让模型更专注于难分类的样本。

graph TD
    A[交叉熵损失变体] --> B[二分类 BCE]
    A --> C[多分类 CCE]
    A --> D[多标签 BCE]
    
    B --> B1[Sigmoid激活]
    C --> C1[Softmax激活]
    D --> D1[多个Sigmoid]
    
    E[正则化技术] --> F[标签平滑]
    E --> G[Focal Loss]
    
    F --> F1[防止过度自信]
    G --> G1[处理类别不平衡]
    
    H[任务类型选择] --> I{单标签 vs 多标签}
    I -->|单标签| J{类别数}
    J -->|2类| B
    J -->|>2类| C
    I -->|多标签| D
    
    style A fill:#bbf,stroke:#333
    style E fill:#bfb,stroke:#333
    style H fill:#fbf,stroke:#333

实践中的选择指南

交叉熵损失的变体众多,如何选择?

单标签多分类:使用CrossEntropyLoss(结合Softmax)。这是图像分类、文本分类等任务的默认选择。

二分类:可以使用BCEWithLogitsLoss(结合Sigmoid的二分类交叉熵),或者将其视为2类分类使用CrossEntropyLoss。两者在数学上等价,但前者计算更高效。

多标签分类:使用BCEWithLogitsLoss,每个类别独立预测。

语言模型训练:使用CrossEntropyLoss,但通常不会对整个词表计算,而是使用采样策略(如Sampled Softmax)来加速。

类别不平衡:考虑使用加权交叉熵或Focal Loss。加权交叉熵给少数类更高的权重;Focal Loss自动降低简单样本的影响。

从公式到洞察

交叉熵损失函数之所以统治深度学习的概率预测任务,是因为它同时满足了多个层面的要求:

信息论角度,它度量了用错误分布编码真实分布所需的额外比特数,是一个自然的"距离"度量。

统计学角度,最小化交叉熵等价于最大似然估计,有坚实的理论基础。

优化角度,它与Softmax的组合产生简洁优雅的梯度公式,不会出现梯度消失问题。

工程角度,它有成熟的数值稳定实现,是现代深度学习框架的标准组件。

理解交叉熵,就是理解了概率机器学习的核心。从香农的信息论,到最大似然估计,再到现代大语言模型的训练,交叉熵始终是那条贯穿始终的主线。当你下次看到模型输出一个概率分布,想想那个负对数——它不只是一个损失函数,更是信息论、概率论和优化理论的完美交汇。


参考文献

  1. Shannon, C. E. (1948). A mathematical theory of communication. Bell System Technical Journal, 27(3), 379-423.

  2. Kullback, S., & Leibler, R. A. (1951). On information and sufficiency. Annals of Mathematical Statistics, 22(1), 79-86.

  3. Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep Learning. MIT Press.

  4. Vaswani, A., et al. (2017). Attention is all you need. NeurIPS.

  5. Szegedy, C., et al. (2016). Rethinking the inception architecture for computer vision. CVPR.

  6. Lin, T. Y., et al. (2017). Focal loss for dense object detection. ICCV.

  7. Bengio, Y., & Senécal, J. S. (2008). Adaptive importance sampling to accelerate training of a neural probabilistic language model. IEEE Transactions on Neural Networks, 19(4), 713-722.

  8. Jozefowicz, R., et al. (2016). Exploring the limits of language modeling. arXiv preprint arXiv:1602.02410.

  9. Kaplan, J., et al. (2020). Scaling laws for neural language models. arXiv preprint arXiv:2001.08361.

  10. Brown, T. B., et al. (2020). Language models are few-shot learners. NeurIPS.

  11. Press, O., & Wolf, L. (2017). Using the output embedding to improve language models. EACL.

  12. Muller, R., Kornblith, S., & Hinton, G. (2019). When does label smoothing help? NeurIPS.