softmax溢出问题

目录

  • 上溢及下溢
  • softmax交叉熵损失

softmax函数是深度学习常用的输出函数,它的表达式如下:
y j ^ = e x j ∑ i = 1 n e x i \hat{y_j} = \frac{e^{x_j}}{\sum_{i=1}^{n} e^{x_i}} yj^=i=1nexiexj

上溢及下溢

但是如果 x j x_j xj 是一个很大的数,那么 e x j e^{x_j} exj 可能会大于数据类型容许的最大数字,造成上溢,这将使分母或分子变为 i n f inf inf, 最后得到的是0、 i n f inf inf n a n nan nan y j ^ \hat{y_j} yj^

解决这个问题的一个方法是,在计算softmax之前,先让所有的 x i x_i xi 都先减去 x ∗ = max ( x i ) x^* = \text{max}(x_i) x=max(xi),容易证明这个更改不会改变softmax的返回值:
y j ^ = e x j − x ∗ e x ∗ ∑ i = 1 n e x i − x ∗ e x ∗ = e x j − x ∗ ∑ i = 1 n e x i − x ∗ \begin{aligned} \hat{y_j} &= \frac{e^{x_j - x^*} e^{x^*}}{\sum_{i=1}^{n} e^{x_i - x^*} e^{x^*}}\\ & = \frac{e^{x_j - x^*}}{\sum_{i=1}^{n} e^{x_i - x^*}} \end{aligned} yj^=i=1nexixexexjxex=i=1nexixexjx

这样解决了上溢的问题,但是依然可能存在一些具有较大负值的 x j − x ∗ x_j - x^* xjx,使得 y j ^ \hat{y_j} yj^ 趋于零,造成下溢,这会使得 log ( y j ^ ) \text{log} (\hat{y_j}) log(yj^) 的值为 − i n f -inf inf。而反向传播几步之后,依然会面临 n a n nan nan 的问题。

softmax交叉熵损失

由于softmax一般用于分类问题,而最终需要计算交叉熵损失:
L o s s = ∑ y j log ( y j ^ ) Loss = \sum y_j \text{log} (\hat{y_j}) Loss=yjlog(yj^)

其中 y j y_j yj 取0或1,因此只需要计算 log ( y j ^ ) \text{log} (\hat{y_j}) log(yj^)
log ( y j ^ ) = log ( e x j − x ∗ ∑ i = 1 n e x i − x ∗ ) = ( x j − x ∗ ) − log ( ∑ i = 1 n e x i − x ∗ ) \begin{aligned} \text{log}(\hat{y_j}) &= \text{log}(\frac{e^{x_j - x^*}}{\sum_{i=1}^{n} e^{x_i - x^*}})\\ &= (x_j - x^*) - \text{log}(\sum_{i=1}^{n} e^{x_i - x^*}) \end{aligned} log(yj^)=log(i=1nexixexjx)=(xjx)log(i=1nexix)

这样就避免计算 e x j − x ∗ e^{x_j - x^*} exjx,而仅仅是 x j − x ∗ x_j - x^* xjx 难以超越数据类型容许的范围;而后面的 log ( ∑ i = 1 n e x i − x ∗ ) \text{log}(\sum_{i=1}^{n} e^{x_i - x^*}) log(i=1nexix) 实际是 logsumexp 函数形式,它满足:
0 ≤ log ( ∑ i = 1 n e x i − x ∗ ) ≤ log ( n ) 0 \leq \text{log}(\sum_{i=1}^{n} e^{x_i - x^*}) \leq \text{log}(n) 0log(i=1nexix)log(n)

这样就解决了softmax的溢出问题。

你可能感兴趣的:(机器学习,机器学习)