文章目录
前言
本文首先回回顾了求导四则运算法则和常见基本初等函数的导数,目的是为了对下文激活函数公式的推导做铺垫。接着介绍了sigmoid函数,并提出了sigmoid函数存在的期望不为0且梯度消失问题。因此,基于sigmoid函数的缺陷提出了tanh(x)激活函数。虽然tanh函数在一定程度上缓解了sigmoid函数带来的“均值不为0”的问题,但是仍然存在“梯度饱和”的现象。为了避免梯度饱和现象的发生,修正线性单元(Rectified Linear Unit, ReLU)被提出。但是ReLU存在“死区”现象。为了缓解死区现象,研究者们提出了一些ReLU的变种,如Leaky ReLU、Parametric ReLU(PReLU)、Exponential Linear Unit(ELU)等。另外,本文详细地推导了softmax函数的导数公式和探讨了softmax溢出问题,并给出了解决方案。最后,提及了一些常用激活函数的应用场景。
求导四则运算法则
若函数
u
(
x
)
{u(x)}
u(x),
v
(
x
)
{v(x)}
v(x) 都可导,则
(
u
(
x
)
±
v
(
x
)
)
′
=
u
′
(
x
)
±
v
′
(
x
)
(
u
(
x
)
∙
v
(
x
)
)
′
=
u
′
(
x
)
∙
v
(
x
)
+
u
(
x
)
∙
v
′
(
x
)
(
u
(
x
)
v
(
x
)
)
′
=
u
′
(
x
)
v
(
x
)
−
v
′
(
x
)
u
(
x
)
v
2
(
x
)
\begin{gathered}\left(u\left(x\right)\pm v\left(x\right)\right)^{^{\prime}}=u^{^{\prime}}\left(x\right)\pm v^{^{\prime}}\left(x\right)\\\left(u\left(x\right)\bullet v\left(x\right)\right)^{^{\prime}}=u^{^{\prime}}\left(x\right)\bullet v\left(x\right)+u\left(x\right)\bullet v^{^{\prime}}\left(x\right)\\\left(\frac{u\left(x\right)}{v\left(x\right)}\right)^{^{\prime}}=\frac{u^{^{\prime}}\left(x\right)v\left(x\right)-v^{^{\prime}}\left(x\right)u\left(x\right)}{v^{2}\left(x\right)}\end{gathered}
(u(x)±v(x))′=u′(x)±v′(x)(u(x)∙v(x))′=u′(x)∙v(x)+u(x)∙v′(x)(v(x)u(x))′=v2(x)u′(x)v(x)−v′(x)u(x)
基本初等函数的导数
sigmoid函数
sigmoid函数也叫Logistic函数,对于一个定义域在
R
{R}
R中的输入,sigmoid函数将输入变换为区间(0,1)上的输出。因此,sigmoid通常称为挤压函数(squashingfunction):它将范围(‐inf,inf)中的任意输入压缩到区间(0,1)中的某个值:
s
i
g
m
o
i
d
(
x
)
=
1
1
+
exp
(
−
x
)
sigmoid(x)=\frac{1}{1+\exp (-x)}
sigmoid(x)=1+exp(−x)1
sigmoid函数适用场景
当我们想要将输出视作二元分类问题的概率时,sigmoid仍然被广泛用作输出单元上的激活函数(sigmoid可以视为softmax的特例)。然而,sigmoid在隐藏层中已经较少使用,它在大部分时候被更简单、更容易训练的ReLU所取代。
sigmoid函数图像
下面,我们绘制sigmoid函数。注意,当输入接近0时,sigmoid函数接近线性变换。
从上图可以看出,sigmoid函数的性质如下:
- 关于 ( 0 , 0.5 ) (0,0.5) (0,0.5)中心对称,其值全部大于0
- sigmoid可以将实数域的值映射到 ( 0 , 1 ) (0,1) (0,1)之间,赋予了概率的意义
- 在sigmoid函数值 x > 5 x>5 x>5或者 x < − 5 x<-5 x<−5的区域,出现了饱和区域,函数值几乎平稳不变
sigmoid函数的导数公式
d d x sigmoid ( x ) = ( 1 1 + exp ( − x ) ) ′ = exp ( − x ) ( 1 + exp ( − x ) ) 2 = 1 1 + exp ( − x ) ⋅ exp ( − x ) 1 + exp ( − x ) = 1 1 + exp ( − x ) ⋅ ( 1 − 1 1 + exp ( − x ) ) = sigmoid ( x ) ( 1 − sigmoid ( x ) ) \begin{aligned} \frac{d}{d x} \operatorname{sigmoid}(x) & =\left(\frac{1}{1+\exp (-x)}\right)^{\prime} \\ & =\frac{\exp (-x)}{(1+\exp (-x))^{2}} \\ & =\frac{1}{1+\exp (-x)} \cdot \frac{\exp (-x)}{1+\exp (-x)} \\ & =\frac{1}{1+\exp (-x)} \cdot\left(1-\frac{1}{1+\exp (-x)}\right) \\ & =\operatorname{sigmoid}(x)(1-\operatorname{sigmoid}(x)) \end{aligned} dxdsigmoid(x)=(1+exp(−x)1)′=(1+exp(−x))2exp(−x)=1+exp(−x)1⋅1+exp(−x)exp(−x)=1+exp(−x)1⋅(1−1+exp(−x)1)=sigmoid(x)(1−sigmoid(x))
sigmoid函数的导数图像
sigmoid函数的导数图像如下所示。注意,当输入为0时,sigmoid函数的导数达到最大值0.25;而输入在任一方向上越远离0点时,导数越接近0。
sigmoid函数的缺点
sigmoid函数的输出存在均值不为0的情况,并且在其定义域的两端(即输入值非常大或非常小的时候)存在梯度消失的问题,这意味着在这些区域的输入变化对输出的影响非常小,这会导致在反向传播过程中导数处于该区域的误差很难甚至无法被传递到前层,从而导致网络在学习过程中难以对这些区域的输入进行有效的调整。
解决办法
1、在深层网络中使用其他激活函数替代。如ReLU(x)、Leaky ReLU(x)等。
2、在分类问题中,sigmoid做激活函数时,使用交叉熵损失函数替代均方误差损失函数。
3、采用正确的权重初始化方法。
4、加入BN层。
批归一化(Batch Normalization,BN)层可以标准化每层的输入,使它们的均值接近0,方差接近1。这样做不仅可以加快训练速度,还可以在一定程度上减轻梯度消失问题,因为它减少了激活函数输入值的动态范围。
5、分层训练权重。
分层训练是指先训练浅层网络,然后再逐步增加网络深度继续训练。这种方法可以确保在训练深层网络时,浅层网络的权重已经相对稳定,从而降低了梯度消失的风险。
tanh函数
基于sigmoid函数的缺陷提出了tanh(x)激活函数。
tanh(x)型函数可以解决sigmoid型函数的期望(均值)不为0的情况,但tanh(x)型函数依然存在梯度消失的问题。
tanh(双曲正切)函数也能将其输入压缩转换到区间(‐1,1)上。tanh函数的公式如下:
tanh
(
x
)
=
1
−
exp
(
−
2
x
)
1
+
exp
(
−
2
x
)
\tanh(x) = \frac{1-\exp(-2x)}{1+\exp(-2x)}
tanh(x)=1+exp(−2x)1−exp(−2x)
tanh函数公式推导过程
tanh ( x ) = sinh ( x ) cosh ( x ) = exp ( x ) − exp ( − x ) exp ( x ) + exp ( − x ) = exp ( x ) exp ( x ) − exp ( − x ) exp ( x ) exp ( x ) exp ( x ) + exp ( − x ) exp ( x ) = exp ( 2 x ) − 1 exp ( 2 x ) + 1 = exp ( − 2 x ) ( exp ( 2 x ) − 1 ) exp ( − 2 x ) ( exp ( 2 x ) + 1 ) = 1 − exp ( − 2 x ) 1 + exp ( − 2 x ) \begin{align*} \tanh(x) &= \frac{\sinh(x)}{\cosh(x)} \\ &= \frac{\exp(x)-\exp(-x)}{\exp(x)+\exp(-x)} \\ &= \frac{\exp(x)\exp(x)-\exp(-x)\exp(x)}{\exp(x)\exp(x)+\exp(-x)\exp(x)} \\ &= \frac{\exp(2x)-1}{\exp(2x)+1} \\ &= \frac{\exp(-2x)(\exp(2x)-1)}{\exp(-2x)(\exp(2x)+1)} \\ &= \frac{1-\exp(-2x)}{1+\exp(-2x)} \end{align*} tanh(x)=cosh(x)sinh(x)=exp(x)+exp(−x)exp(x)−exp(−x)=exp(x)exp(x)+exp(−x)exp(x)exp(x)exp(x)−exp(−x)exp(x)=exp(2x)+1exp(2x)−1=exp(−2x)(exp(2x)+1)exp(−2x)(exp(2x)−1)=1+exp(−2x)1−exp(−2x)
tanh函数图像
下面我们绘制tanh函数。注意,当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数,
不同的是tanh函数关于坐标系原点中心对称。
tanh函数的导数公式
d d x tanh ( x ) = 1 − tanh 2 ( x ) \frac{d}{dx} \tanh(x) = 1 - \tanh^2(x) dxdtanh(x)=1−tanh2(x)
tanh函数的导数图像
t a n h ( x ) + 1 = 2 s i g m o i d ( 2 x ) tanh(x) + 1 = 2sigmoid(2x) tanh(x)+1=2sigmoid(2x)
tanh ( x ) + 1 = e x − e − x e x + e − x + e x + e − x e x + e − x = 2 e x e x + e − x = e x ⋅ 2 e x e x ⋅ ( e x + e − x ) = 2 e 2 x e 2 x + 1 \begin{align*} \tanh\left(x\right)+1&=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}+\frac{e^{x}+e^{-x}}{e^{x}+e^{-x}} \\ &=\frac{2e^{x}}{e^{x}+e^{-x}} \\ &=\frac{e^{x}\cdot2e^{x}}{e^{x}\cdot(e^{x}+e^{-x})} \\ &=\frac{2e^{2x}}{e^{2x}+1} \\ \end{align*} tanh(x)+1=ex+e−xex−e−x+ex+e−xex+e−x=ex+e−x2ex=ex⋅(ex+e−x)ex⋅2ex=e2x+12e2x 2 s i g m o i d ( 2 x ) = 2 1 + e − 2 x = e 2 x ⋅ 2 e 2 x ⋅ ( 1 + e − 2 x ) = 2 e 2 x e 2 x + 1 \begin{align*} 2sigmoid(2x)&=\frac{2}{1+e^{-2x}} \\ &=\frac{e^{2x}\cdot2}{e^{2x}\cdot(1+e^{-2x})} \\ &=\frac{2e^{2x}}{e^{2x}+1} \end{align*} 2sigmoid(2x)=1+e−2x2=e2x⋅(1+e−2x)e2x⋅2=e2x+12e2x
sigmoid和tanh函数图像对比
ReLU函数
为了避免梯度饱和现象的发生,修正线性单元(Rectified Linear Unit, ReLU)被提出。ReLU提供了一种非常简单的非线性变换。给定元素x,ReLU函数被定义为该元素与0的最大值: R e L u ( x ) = m a x ( x , 0 ) {ReLu(x)=max(x,0)} ReLu(x)=max(x,0)通俗地说,ReLU函数通过将相应的活性值设为0,仅保留正元素并丢弃所有负元素。这里的活性值指那些作为ReLU函数输入的值。换句话说,ReLU函数将所有负的活性值设置为0,只保留正的活性值。
ReLU函数图像
为了直观感受一下,我们可以画出ReLu函数的曲线图。
ReLU在零点处不可导
注意,当输入值精确等于0时,ReLU函数不可导。在此时,我们默认使用左侧的导数,即当输入为0时导数为0。我们可以忽略这种情况,因为输入可能永远都不会是0(ReLU在零点处不可导,人为将梯度规定为0)。下面我们绘制ReLU函数的导数。
可以看到,当
x
≥
0
x≥0
x≥0时,梯度为1。这部分解决了sigmoid函数和tanh函数梯度饱和的问题,除此之外,ReLU的计算比较简单,加速了训练过程。
当
x
<
0
x<0
x<0时,梯度为0。这会导致ReLU出现"Dead ReLU"问题(死区现象)。这种死区现象会导致网络的部分神经元失去活性,不再对任何输入产生响应,从而减少了网络的表达能力。
ReLU函数负半区间也是非线性激活函数的理解
1、单侧抑制
2、稀疏激活性
ReLU函数从图像上看,是一个分段函数,把所有的负值都变为0,而正值不变,这样就成为单侧抑制。
由于单侧抑制,使得神经网络中的神经元也具有了稀疏激活性。
稀疏激活性:从信号方面,神经元同时只对输入信号的少部分选择响应,大量信号被刻意屏蔽,这样可以提高学习精度,更好更快地提取稀疏特征。当 x < 0 x<0 x<0时,ReLU硬饱和,而当 x > 0 x>0 x>0时,则不存在饱和问题。ReLU能够在 x > 0 x>0 x>0时保持梯度不衰减,从而缓解梯度消失问题。
使用ReLU的原因
使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。
ReLU6
ReLU的正值输出为
[
0
,
+
∞
)
[0,+∞)
[0,+∞),而计算机内存有限,并不能够存储无穷大的数,所以将ReLU应用到实际中需要限定输出的最大值,最大输出限定为6,就是ReLU6,如下图所示。
Leaky ReLU函数
为了缓解“死区”现象,Leaky ReLU尝试将ReLU的
x
<
0
x<0
x<0部分调整成一个斜率很小的值,其公式如下:
Leaky ReLU(x)
=
{
x
,
x
≥
0
α
⋅
x
,
x
<
0
\left.\text{Leaky ReLU(x)}=\left\{\begin{matrix}x,&\quad x\geq0\\\alpha\cdot x,&\quad x<0\end{matrix}\right.\right.
Leaky ReLU(x)={x,α⋅x,x≥0x<0其中,α是一个非常小的正值,通常是0.01,表示在负值区域的一个小斜率。
Leaky ReLU函数优缺点
优点
- 缓解了“死区”现象,即使在负值输入时也能进行有效的反向传播。
- 保持了ReLU在正值区域的线性特性,有助于加速神经网络的训练过程。
缺点
- 由于在负值区域引入了额外的超参数α,这个超参数比较敏感不好设置。
参数化ReLU(P-ReLU)
参数化ReLU为了解决超参数α合适的值不好设定的问题,直接将该参数也融入模型整体训练过程中。使用误差反向传播和随机梯度下降的方法更新参数。
随机化ReLU(R-ReLU)
即超参数α随机化,让不同层自己学习不同的超参数,但随机化的超参数的分布符合均值分布或高斯分布。
指数化线性单元(ELU)
指数化线性单元(Exponential Linear Unit, ELU)也是为了解决ReLU中的“死区”现象,其公式如下:
E
L
U
(
x
)
=
{
x
,
x
≥
0
λ
⋅
(
e
x
−
1
)
,
x
<
0
\left.ELU(x)=\left\{\begin{matrix}x,&x\geq0\\\lambda\cdot(e^x-1),&x<0\end{matrix}\right.\right.
ELU(x)={x,λ⋅(ex−1),x≥0x<0
软饱和性和无饱和性
软饱和性:软饱和性指的是激活函数在其输入值达到一定范围后,输出值的增加速率逐渐减缓的特性。换句话说,当输入值较大时,激活函数的导数会减小,但不会完全变为零。这种特性使得神经网络在面对较大的输入值时,仍然能够保持一定的学习能力,但学习速度会变慢。
无饱和性:无饱和性是指激活函数在其整个输入范围内,输出值的增加速率保持一致,不会因为输入值的增大而减缓。这种特性使得神经网络在面对各种大小的输入值时,都能够以相同的速度进行学习。
ELU指数线性单元特点
- 融合了sigmoid和ReLU,左侧具有软饱和性,右侧无饱和性。
- 右侧线性部分使得ELU能够缓解梯度消失,而左侧软饱和性能够让ELU对输入变化或噪声更鲁棒。
- ELU的输出均值接近于0,所以收敛速度更快。
缺点
- 由于在负值区域使用了指数运算,导致计算量大。
Swish函数
Swish激活函数具备无上界有下界、平滑、非单调的特性,Swish在深层模型上效果优于ReLU。其公式如下:
s
w
i
s
h
(
x
)
=
x
⋅
s
i
g
m
o
i
d
(
β
x
)
swish(x)=x\cdot sigmoid(\beta x)
swish(x)=x⋅sigmoid(βx)
其中,β是个常数或者可训练的参数。
SiLU
当β=1时,我们也称作SiLU激活函数。
采用以下代码来绘制图像。
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def swish(x, beta):
return x * sigmoid(beta * x)
x = np.linspace(-5, 5, 100)
betas = [0.1, 1.0, 10.0]
plt.figure()
for beta in betas:
plt.plot(x, swish(x, beta), label=f'Swish (β={beta})', zorder=2)
plt.title('Swish Activation Function')
plt.xlabel('Input')
plt.ylabel('Output')
plt.legend()
# Add horizontal and vertical lines
plt.axhline(0, color='lightgrey', linestyle='-', zorder=1)
plt.axvline(0, color='lightgrey', linestyle='-', zorder=1)
# Set x-axis limits
# Set y-axis limits
plt.xlim(-5, 3)
plt.ylim(-2, 3)
plt.show()
Mish函数
Mish函数同样具备无上界有下界、平滑、非单调的特性,且允许负值有一定的梯度流入。其公式如下:
M
i
s
h
=
x
⋅
t
a
n
h
(
l
o
g
(
1
+
e
x
)
)
Mish=x\cdot tanh(log(1+e^x))
Mish=x⋅tanh(log(1+ex))
其中
l
o
g
(
1
+
e
x
)
log(1+e^x)
log(1+ex)为
s
o
f
t
p
l
u
s
(
x
)
softplus(x)
softplus(x)激活函数(
s
o
f
t
p
l
u
s
softplus
softplus函数可以看作是ReLU函数的平滑)。
采用以下代码来绘制图像。
import numpy as np
import matplotlib.pyplot as plt
def softplus(x):
return np.log(1 + np.exp(x))
def mish(x):
return x * np.tanh(np.log(1 + np.exp(x)))
x = np.linspace(-5, 5, 100)
plt.figure()
plt.plot(x, softplus(x), label='Softplus')
plt.plot(x, mish(x), label='Mish')
plt.title('Softplus and Mish Activation Functions')
plt.xlabel('Input')
plt.ylabel('Output')
plt.legend()
plt.show()
Mish激活函数已经在图像分类和目标检测等任务上展现出了比ReLU和Swish等激活函数更优越的性能。特别是在处理那些需要精细梯度调控的任务时,Mish激活函数能够提供更优的选择。
Maxout函数
与常规的激活函数不同,Maxout函数可以看做是在神经网络中激活函数的地方加入一个激活函数层。Maxout函数是一种可学习的激活函数,其特点是具有参数,并且这些参数能够通过神经网络的反向传播机制进行优化。其公式如下:
M
a
x
o
u
t
(
x
)
=
max
i
∈
[
1
,
k
]
(
W
i
⋅
x
+
b
i
)
Maxout(x)=\max_{i\in[1,k]}(W_i\cdot x+b_i)
Maxout(x)=i∈[1,k]max(Wi⋅x+bi)
Maxout函数的优势在于其强大的拟合能力,理论上它可以拟合任意的凸函数,缺点是需要的参数较多,导致模型的参数量显著增加。
softmax函数
在二分类任务时,经常使用sigmoid激活函数。而在处理多分类问题的时候,需要使用softmax函数。
softmax函数公式
softmax函数的公式如下:
y
i
=
s
o
f
t
m
a
x
(
x
i
)
=
e
x
i
∑
k
=
1
N
e
x
k
{y_i}=softmax(x_i) = \frac{e^{x_{i}}}{\sum_{k=1}^{N}e^{x_{k}}}
yi=softmax(xi)=∑k=1Nexkexi
其中
x
i
{x_i}
xi是输入向量的第 i 个元素。softmax函数的作用是将输入向量中的每个元素转换为其作为概率值的形式。
softmax函数的导数公式
即求
y
i
=
e
x
i
∑
k
=
1
N
e
x
k
y_{i}=\frac{e^{x_{i}}}{\sum_{k=1}^{N}e^{x_{k}}}
yi=∑k=1Nexkexi 的导数。
观察可知,
y
i
{y_i}
yi 是形如
y
i
=
g
(
x
)
f
(
x
)
{y_i}=\frac{g(x)}{f(x)}
yi=f(x)g(x) 的函数。
求导公式: ∂ y i ∂ x = g ′ ( x ) h ( x ) − g ( x ) h ′ ( x ) [ h ( x ) ] 2 \frac{\partial y_i}{\partial x}=\frac{g^{\prime}(x)h(x)-g(x)h^{\prime}(x)}{[h(x)]^2} ∂x∂yi=[h(x)]2g′(x)h(x)−g(x)h′(x)
类比可知,
e
x
i
e^{x_i}
exi相当于
g
(
x
)
{g(x)}
g(x);
∑
k
=
1
N
e
x
k
{\sum_{k=1}^{N}e^{x_{k}}}
∑k=1Nexk相当于
h
(
x
)
h(x)
h(x)。
所以,要想得到softmax函数的导数,只需要分别求出
e
x
i
e^{x_i}
exi 和
∑
k
=
1
N
e
x
k
{\sum_{k=1}^{N}e^{x_{k}}}
∑k=1Nexk 的导数即可。
对于第
i
i
i个元素
x
i
{x_i}
xi,
(
∑
k
=
1
N
e
x
k
)
′
({\sum_{k=1}^{N}e^{x_{k}}})^{\prime}
(∑k=1Nexk)′
=
(
e
x
1
+
e
x
2
+
⋅
⋅
⋅
+
e
x
i
+
⋅
⋅
⋅
+
e
x
N
)
′
=({e^{x_1}}+{e^{x_2}}+···+{e^{x_i}}+···+{e^{x_N}})^{\prime}
=(ex1+ex2+⋅⋅⋅+exi+⋅⋅⋅+exN)′
=
e
x
i
={e^{x_i}}
=exi。
由于 k {k} k是从 1 1 1开始直到 N N N的,所以肯定能找到一个 k k k值与 i {i} i相等,使得 ( e x k ) ′ ({e^{x_k}})^{\prime} (exk)′ = ( e x i ) ′ ({e^{x_i}})^{\prime} (exi)′ = e x i {e^{x_i}} exi;
而对于其他不等于 i i i的 k k k值, e x k {e^{x_k}} exk相对于 x i {x_i} xi都是常数,求导变为0。
我们分两种情况来讨论softmax函数的求导。
设
i
i
i 表示输入向量的第
i
i
i个元素,
j
j
j 表示输入向量的第
j
j
j个元素。
当 i ≠ j i ≠ j i=j 时
我们关心的是第
i
i
i个输入变量
x
i
{x_i}
xi如何受到其他变量
x
j
{x_j}
xj的影响,计算的是
y
i
{y_i}
yi对第
j
j
j个元素的偏导数。
此时,
(
e
x
i
)
′
=
0
({e^{x_i}})^{\prime}=0
(exi)′=0,
(
e
x
j
)
′
=
x
j
({e^{x_j}})^{\prime}={x_j}
(exj)′=xj
∂
y
i
∂
x
j
=
∂
e
x
i
∑
k
=
1
N
e
x
k
∂
x
j
=
0
−
e
x
i
e
x
j
∑
2
=
−
e
x
i
∑
e
x
j
∑
=
−
y
i
y
j
\frac{\partial y_{i}}{\partial x_{j}}=\frac{\partial\frac{e^{x_{i}}}{\sum_{k=1}^{N}e^{x_{k}}}}{\partial x_{j}}=\frac{0-e^{x_{i}}e^{x_{j}}}{\sum^{2}}=-\frac{e^{x_{i}}}{\sum}\frac{e^{x_{j}}}{\sum}=-y_{i}y_{j}
∂xj∂yi=∂xj∂∑k=1Nexkexi=∑20−exiexj=−∑exi∑exj=−yiyj
这个结果表明,第
i
i
i个输出变量
y
i
{y_i}
yi对第
j
{j}
j个输入变量
x
j
{x_j}
xj的偏导数是负的,表示它们是相互抑制的关系。因此,在这种情况下,当其中一个变量的得分增加时,其他变量的相对概率就会减少,这就是所谓的“竞争效应”。
当 i = j i = j i=j 时
我们关心的是第
i
i
i个输入变量
x
i
{x_i}
xi如何受到自身变化的影响,计算的是
y
i
{y_i}
yi对第
i
(
或
j
)
i(或j)
i(或j) 个元素的偏导数。
此时,
(
e
x
i
)
′
=
(
e
x
j
)
′
=
x
i
=
x
j
({e^{x_i}})^{\prime}=({e^{x_j}})^{\prime}={x_i}={x_j}
(exi)′=(exj)′=xi=xj
∂
y
i
∂
x
j
=
∂
e
x
i
∑
k
=
1
N
e
x
k
∂
x
j
=
e
x
i
∑
−
e
x
i
e
x
j
∑
2
=
e
x
i
∑
∑
−
e
x
j
∑
=
y
i
(
1
−
y
j
)
\frac{\partial y_{i}}{\partial x_{j}}=\frac{\partial\frac{e^{x_{i}}}{\sum_{k=1}^{N}e^{x_{k}}}}{\partial x_{j}}=\frac{e^{x_{i}}\sum-e^{x_{i}}e^{x_{j}}}{\sum^{2}}=\frac{e^{x_{i}}}{\sum}\frac{\sum-e^{x_{j}}}{\sum}=y_{i}(1-y_{j})
∂xj∂yi=∂xj∂∑k=1Nexkexi=∑2exi∑−exiexj=∑exi∑∑−exj=yi(1−yj)
这个结果表明,第 i i i个输出变量 y i {y_i} yi对第 i {i} i个输入变量 x i {x_i} xi的偏导数是正的,表示它们是相互促进的关系。因此,在这种情况下,当 x i {x_i} xi的得分增加时,他的输出概率 y i {y_i} yi也会相应的增加,但同时其他变量的输出概率会减少,以保证所有输出概率的总和为1。
softmax溢出问题
参考文章
上溢出(overflow)和下溢出(underflow)
在使用softmax函数时,可能会出现两种数值问题:上溢出(overflow)和下溢出(underflow)。
上溢出发生在softmax函数的输入值非常大时。具体来说,当softmax函数的某个输入值非常大,以至于经过指数运算后得到的值大于数据类型容许的最大数字或者超出了计算机能够表示的范围时,就会出现上溢出(overflow)。这时,softmax函数的输出值会被表示为无穷大(inf),这在数值计算中可能导致一些问题,因为无穷大的值会导致后续的除法运算失败。
下溢出则发生在softmax函数的输入值非常小,接近于零时。由于计算机使用浮点数表示实数,当数值小到一定程度时,可能会被四舍五入为0。在softmax函数中,如果分母接近于0,那么在计算概率时可能会导致除以零的错误,进而引发数值不稳定或程序崩溃。
解决方法
令 M = m a x ( x i ) , i = 1 , 2 , 3 , . . . , N M = max({x_i}),i=1,2,3,...,N M=max(xi),i=1,2,3,...,N,即 M M M为所有 x i {x_i} xi中最大的值,那么只需要把计算 s o f t m a x ( x i ) softmax(x_i) softmax(xi)的值,改为计算 s o f t m a x ( x i − M ) softmax(x_i-M) softmax(xi−M)的值,就可以解决上溢出、下溢出的问题,并且计算结果理论上仍然和 s o f t m a x ( x i ) softmax(x_i) softmax(xi)保持一致。
举个例子
设
x
1
=
3
,
x
2
=
1
,
x
3
=
−
3
x_1=3,x_2=1,x_3=-3
x1=3,x2=1,x3=−3,我们常用“常规”的方法来计算
y
2
y_2
y2,即
e
x
2
e
x
1
+
e
x
2
+
e
x
3
=
e
1
e
3
+
e
1
+
e
−
3
=
2.7
20
+
2.7
+
0.05
≈
0.12
\begin{aligned}\frac{e^{x_2}}{e^{x_1}+e^{x_2}+e^{x_3}}&=\frac{e^1}{e^3+e^1+e^{-3}}=\frac{2.7}{20+2.7+0.05}\approx0.12\end{aligned}
ex1+ex2+ex3ex2=e3+e1+e−3e1=20+2.7+0.052.7≈0.12
现在我们改成:
e
x
2
−
M
e
x
1
−
M
+
e
x
2
−
M
+
e
x
3
−
M
=
e
1
−
3
e
3
−
3
+
e
1
−
3
+
e
−
3
−
3
≈
0.12
\begin{aligned}\frac{e^{x_2-M}}{e^{x_1-M}+e^{x_2-M}+e^{x_3-M}}&=\frac{e^{1-3}}{e^{3-3}+e^{1-3}+e^{-3-3}}\approx0.12\end{aligned}
ex1−M+ex2−M+ex3−Mex2−M=e3−3+e1−3+e−3−3e1−3≈0.12
其中,
M
=
3
M=3
M=3是
x
1
,
x
2
,
x
3
x_1,x_2,x_3
x1,x2,x3中的最大值。
可见计算结果并未改变。这是怎么做到的呢?通过简单的代数运算就可以参透其中的“秘密”:
e
x
2
e
x
1
+
e
x
2
+
e
x
3
=
e
x
2
e
M
e
x
1
+
e
x
2
+
e
x
3
e
M
=
e
x
2
e
M
e
x
1
e
M
+
e
x
2
e
M
+
e
x
3
e
M
=
e
(
x
2
−
M
)
e
(
x
1
−
M
)
+
e
(
x
2
−
M
)
+
e
(
x
3
−
M
)
\frac{e^{x_2}}{e^{x_1}+e^{x_2}+e^{x_3}}=\frac{\frac{e^{x_2}}{e^M}}{\frac{e^{x_1}+e^{x_2}+e^{x_3}}{e^M}}=\frac{\frac{e^{x_2}}{e^M}}{\frac{e^{x_1}}{e^M}+\frac{e^{x_2}}{e^M}+\frac{e^{x_3}}{e^M}}=\frac{e^{(x_2-M)}}{e^{\left(x_1-M\right)}+e^{\left(x_2-M\right)}+e^{\left(x_3-M\right)}}
ex1+ex2+ex3ex2=eMex1+ex2+ex3eMex2=eMex1+eMex2+eMex3eMex2=e(x1−M)+e(x2−M)+e(x3−M)e(x2−M)
通过这样的变换,对任何一个 xi,减去M之后,e 的指数的最大值为0,所以不会发生上溢出;同时,分母中也至少会包含一个值为1的项,所以分母也不会下溢出(四舍五入为0)。
延伸问题
如果softmax函数中的分子发生下溢出,也就是 x i {x_i} xi为负数,且 ∣ x i ∣ {|x_i|} ∣xi∣很大,此时分母是一个极小的正数,有可能四舍五入为0的情况。此时,如果我们把softmax函数的计算结果再拿去计算 log,即 log softmax,其实就相当于计算 log(0) ,所以会得到 −∞ ,但这实际上是错误的,因为它是由舍入误差造成的计算错误。
解决方法
log
[
y
i
]
=
log
(
e
x
i
e
x
1
+
e
x
2
+
⋯
e
x
n
)
=
log
(
e
x
i
e
M
e
x
1
e
M
+
e
x
2
e
M
+
⋯
e
x
n
e
M
)
=
log
(
e
(
x
i
−
M
)
∑
j
n
e
(
x
j
−
M
)
)
=
log
(
e
(
x
i
−
M
)
)
−
log
(
∑
j
n
e
(
x
j
−
M
)
)
=
(
x
i
−
M
)
−
log
(
∑
j
n
e
(
x
j
−
M
)
)
\begin{aligned} \log[y_i]&=\log\left(\frac{e^{x_i}}{e^{x_1}+e^{x_2}+\cdots e^{x_n}}\right)\\ &=\log\left(\frac{\frac{e^{x_i}}{e^M}}{\frac{e^{x_1}}{e^M}+\frac{e^{x_2}}{e^M}+\cdots\frac{e^{x_n}}{e^M}}\right)\\ &=\log\left(\frac{e^{(x_i-M)}}{\sum_j^ne^{(x_j-M)}}\right)\\ &=\log\Bigl(e^{(x_i-M)}\Bigr)-\log\left(\sum_j^ne^{(x_j-M)}\right)\\ &=(x_i-M)-\log\left(\sum_j^ne^{(x_j-M)}\right) \end{aligned}
log[yi]=log(ex1+ex2+⋯exnexi)=log(eMex1+eMex2+⋯eMexneMexi)=log(∑jne(xj−M)e(xi−M))=log(e(xi−M))−log(j∑ne(xj−M))=(xi−M)−log(j∑ne(xj−M))
可以看到,在最后的表达式中,避免计算了
e
(
x
i
−
M
)
{e^{(x_i-M)}}
e(xi−M),而仅仅是
x
i
−
M
x_i-M
xi−M难以超越数据类型容许的范围;后面的
log
(
∑
j
n
e
(
x
j
−
M
)
)
\log\left(\sum_j^ne^{(x_j-M)}\right)
log(∑jne(xj−M))实际上是一种类似"LogSumExp技巧"的聪明方式,他满足:
0
≤
log
(
∑
i
=
1
n
e
x
i
−
M
)
≤
log
(
n
)
\mathrm{0\leq\log(\sum_{i=1}^ne^{x_i-M})\leq\log(n)}
0≤log(i=1∑nexi−M)≤log(n)这样就解决了softmax的溢出问题。
softmax函数在多分类问题中的应用
softmax在多分类过程中,它将多个神经元的输出(比如
o
1
,
o
2
,
o
3
o_1,o_2,o_3
o1,o2,o3)映射到(0,1)区间内,转换为一组概率值(比如
y
1
,
y
2
,
y
3
y_1,y_2,y_3
y1,y2,y3),这些概率值的总和为1,每个概率值可以看作是每个类别的预测概率,我们选取概率值最大(也就是神经元输出值最大的)结点,作为预测目标。
激活函数的应用场景
- sigmoid
二分类问题。由于其输出值在0到1之间,因此非常适合表示概率。 - tanh
回归问题和循环神经网络(RNN)。在RNN中,Tanh函数通常用于隐藏层,因为它可以使得输出值在-1到1之间,这有助于控制梯度的流动。 - ReLU
深度学习中广泛应用。由于其计算速度快且能够解决梯度消失问题,ReLU函数在大多数情况下都能取得较好的效果。 - Leaky ReLU
当担心ReLU函数可能导致神经元死亡时,可以考虑使用Leaky ReLU函数。 - ELU
在某些情况下,ELU函数可能会比ReLU函数表现得更好,尤其是在处理噪声数据时。
选择哪种激活函数取决于具体的任务和数据。在实际应用中,需要根据具体情况进行尝试和调整,以找到最适合的激活函数。