Softmax & Entorpy
本文最后更新于 2025年4月18日 晚上
问题来源
经常在保研经验帖中看到问softmax以及让手写softmax。我只知道有个softmax函数,以及是用在多分类任务里的,知之甚少,所以系统学习一番。
写完后发现有点简单,所以加个cross-entropy凑凑篇幅。
数学原理
Softmax函数定义:(来源于Grok3的回答,暂未在《机器学习》中找到相关描述)
Softmax函数将一个 \(K\) 维实数向量 \(\boldsymbol{z}=[z_1,z_2,...,z_K]\) 转化为概率分布: \[ \sigma(z)_i=\frac{\exp(z_i)}{\sum_{j=1}^K\exp(z_j)},\ i=1,2,...,K \]
比如,\([1.0, 2.0, 3.0]\)会转换为\([0.09, 0.24, 0.67]\),看起来,就是把一个类似权重的向量归一化成一串概率
性质:
- 输出值在(0, 1)区间
- 所有输出值的和为1
- 指数函数放大输入差异,使较大值更接近1,较小值接近0
Softmax的输出可解释为类别 \(i\) 的条件概率: \[ P(y=i|x)=\frac{\exp(w_i^Tx+b_i)}{\sum_{j=1}^K\exp(w_j^Tx+b_j)} \] 其中 \(w_i\) 和 \(b_i\) 是类别 \(i\) 的权重和偏置
Softmax通常与交叉熵损失(cross-entropy)结合使用,用于优化模型参数。假设真实标签为 \(y\) ,预测概率为 \(\hat{y}=\sigma(z)\),交叉熵损失为: \[ L=-\sum_{i=1}^{K} y_i\log(\hat{y_i}) \] 对于单样本,若正确类别为 \(k\) 则 \(y_k=1\) ,其他 \(y_i=0\) ,损失简化为: \[ L=-\log(\hat{y_k})=-\log(\frac{\exp(z_k)}{\sum_{j=1}^K \exp(z_j)}) \]
计算Softmax和数值稳定性
在Python中计算给定向量上的softmax函数的简单实现是: 1
2
3def softmax(x):
exps = np.exp(x)
return exps / np.sum(exps)
对于之前的示例 [1,2,3]
,输出
[ 0.09003057, 0.24472847, 0.66524096]
,但是如果数字更大,就会输出nan
(not
a
number),因为Numpy使用的浮点数数值范围有限,所以可以将输入转换一下,避免大指数计算,由数学推导(见参考中的第一条)可得,在exp内部加减常数对结果没有影响,一般采用以下形式:
\[
\sigma(z)_i=\frac{\exp(z_i-\max(z))}{\sum_{j=1}^K \exp(z_j-\max(z))}
\] 实现:
1 |
|
axis=-1
:确保对每个样本的 logits 向量(最后一维)计算最大值,而不是对整个数组。这对于多维输入(例如批量数据)至关重要。没有的话,对于多维数据,就会取全局最大,比如[[1000, 2000, 3000], [4000, 5000, 6000]]
会输出[[0., 0., 0.], [0., 0., 1.]]
keepdims=True
:保持输出维度,不加的话,对于多维向量,可能把各行最大值的列向量给变成行向量,后面减法会出错。
但现在:
1 |
|
虽然softmax不会输出0,但是差异太大,所以过于接近0.
some Entropy
信息熵(香农熵)
信息量的大小跟随机事件的概率有关,越小概率的事情发生了,产生的信息量越大
比如高中学过的 \(3\sigma\) 原则,当正态分布在 \(3\sigma\) 外的事件发生,就可以认为出现异常
而确定性时间没有信息量,所以概率越小,信息越大,给概率取个倒什么的就可以变成一种权重,于是有了 \(\frac{1}{P(x)}\) ,但是香农的定义还套了一层 \(\log_2\) ,套个对数的好处在于,如果多个独立事件都发生,可以化乘为加,更多具体原因见信息熵为什么要定义成-Σp*log(p)。所以,信息熵的定义是: \[ \begin{aligned} \text{Entropy} & =\sum_iP(i)\log_2\frac{1}{P(i)} \\ & =-\sum_iP(i)\log_2P(i) \end{aligned} \] 在连续变量上: \[ \text{Entropy}=-\int P(x)\log_2P(x)\,\mathrm{d}x \]
相对熵(KL散度)
用来衡量两个概率分布的差异性: \[ D_{KL}(p||q)=\sum_{i=1}^Np(x_i)\log(\frac{p(x_i)}{q(x_i)}) \] 由上式可见,相对熵没有对称性,也就是说 \(D_{KL}(p||q) \ne D_{KL}(q||p)\)
交叉熵
单个样本,预测分布p,真实分布q的交叉熵: \[ H(p,q)=\sum_{i=1}^np(x_i)\log\frac{1}{q(x_i)}=-\sum_{i=1}^np(x_i)\log q(x_i)=D_{KL}(p||q) + H(p) \] \(H(p,q)\) 指分布p和分布q的交叉熵,\(H(p)\) 指分布p的信息熵。
同样,交叉熵也没有对称性。
求平均交叉熵损失的简单实现: 1
2
3
4
5
6
7
8def cross_entropy(predictions, targets, epsilon=1e-12):
# 取(epsilon, 1-epsilon)内的,防对数数值问题
predictions = np.clip(predictions, epsilon, 1.-epsilon)
# 样本数量
N = predictions.shape[0]
# target就是p,predict就是q,见上面定义式
ce = - np.sum(targets*np.log(predictions)) / N
return ce
区别联系和理解方法
熵在以2为对数底时表示对事件中的随机变量编码所需的最小字节数
KL散度指使用B的编码来编A,所需要的额外所需的编码长度
交叉熵指使用B作为密码来表示A时所需要的 “平均的编码长度”
由 \(H(p,q)=D_{KL}(p||q) + H(p)\) 可知,当p是个常数时,优化KL跟优化交叉熵是一样的。
当不是常数时,就有区别了,但这要根据具体使用场景看,我经验少,举不出例子,只知道一般都用交叉熵,KL在VAG、GAN中用到
参考
The Softmax function and its derivative - Eli Bendersky's website
一篇文章讲清楚交叉熵和KL散度 - 康斯坦丁的文章 - 知乎
KL散度(Kullback-Leibler Divergence)介绍及详细公式推导 | HsinJhao's Blogs