简介:个人学习分享,如有错误,欢迎批评指正。
一. 激活函数的定义
激活函数(Activation Function)是人工神经网络中对每个神经元的输入进行非线性变换的函数。神经网络中的每个神经元都会接受来自上一层的输入,加权求和后通过激活函数进行处理,决定输出信号。激活函数的引入使得神经网络可以逼近任意复杂的函数,而不仅仅是线性的组合
。
一个简单的神经元计算过程可以表达为:
y = f ( w T x + b ) y = f(w^T x + b) y=f(wTx+b)
其中, x x x 是输入, w w w 是权重, b b b 是偏置, f f f 是激活函数, y y y 是输出。
二. 激活函数的目的
激活函数的主要目的是引入非线性,从而使神经网络能够解决线性模型无法解决的复杂问题。没有激活函数的网络是一个线性性模型,无法学习复杂的模式,而引入激活函数后,网络就能够学习到更为复杂的特征和数据分布
。
具体来说,激活函数的作用包括:
-
引入非线性: 神经网络中的线性组合(即 w T x + b w^T x + b wTx+b)本身是线性的,因此无论网络如何堆叠线性层,最终仍是线性函数。激活函数通过引入非线性,使得网络能够
逼近任何复杂的非线性映射
,从而具备更大的表达能力。 -
特征选择: 激活函数可以
帮助神经网络筛选和选择重要的特征
。例如,ReLU 函数会将负数设为 0,而保留正数,这可以视为一种特征筛选过程。 -
控制输出范围: 某些激活函数将
输出限制在特定范围内
,这对输出层尤为重要。例如,Sigmoid 函数将输出限制在 (0, 1) 之间,这在二分类问题中可以解释为概率;Softmax 函数则会将输出值转变为概率分布,适用于多分类问题。 -
提高梯度传播的效率: 不同激活函数的梯度不同,直接影响反向传播中梯度的传播速度和稳定性。一些函数如 ReLU 能有效避免梯度消失问题,使得梯度在反向传播中不会过快消失,从而加速收敛。
三. 激活函数的作用
激活函数在神经网络中的作用非常关键,决定了网络的表现和训练效果。其作用可以从以下几个方面来分析:
3.1 提供非线性能力
最重要的作用是引入非线性能力
。如果没有非线性激活函数,神经网络无论层数多深,其最终表达的仍然是线性组合。引入非线性激活函数后,神经网络就能够处理更复杂的数据,并逼近复杂的函数。
例如,给定一个深度为 3 的神经网络,如果没有激活函数,网络的表示是以下形式:
y = W 3 ( W 2 ( W 1 x ) ) = ( W 3 W 2 W 1 ) x y = W_3 (W_2 (W_1 x)) = (W_3 W_2 W_1) x y=W3(W2(W1x))=(W3W2W1)x
这是一个线性变换,而无论如何堆叠都无法学习复杂的非线性关系。通过在层与层之间加入激活函数,网络能够学习和逼近复杂的非线性函数
。
3.2 梯度的有效传递
激活函数影响着神经网络的梯度传播。通过反向传播算法,神经网络会根据误差对每一层的权重进行调整,而激活函数的选择直接影响反向传播中梯度的大小和变化
。
某些激活函数(如 Sigmoid 和 Tanh)在输入值大或小的情况下,梯度会趋于 0,导致梯度消失问题。这意味着模型参数更新无法有效更新,导致学习能力下降。而一些改进的激活函数(如 ReLU 和 Leaky ReLU)能够缓解这个问题,保证梯度的有效传递。
3.3 控制网络输出
激活函数的另一个作用是控制网络的输出范围
。例如,在分类任务中,输出层的激活函数通常选择 Softmax 或 Sigmoid,它们会将输出值限定在 (0, 1) 范围内,并将其解释为概率。这种设计使得模型的输出更具有直观的解释性,便于应用于实际任务。
3.4 提高网络的收敛速度
一些激活函数(如 ReLU 和 Leaky ReLU)在实际应用中比传统的 Sigmoid 和 Tanh 更快。ReLU 的计算非常简单,当输入为正时,输出等于输入;当输入为负时,输出为 0。这种简单的计算方式加快了网络的收敛速度,并减少了计算资源的消耗。
四、常见激活函数
1.Sigmoid 函数
1. 定义
Sigmoid 函数(也称为逻辑函数)是一种常用的激活函数,广泛应用于神经网络,尤其是在二分类问题的输出层
。其数学表达式为:
σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1
2. 图形表示
Sigmoid 函数的图形呈 S 形,具有平滑的曲线特性:
3. 特点
- 输出范围:
σ
(
x
)
\sigma(x)
σ(x) 的输出值在
(0, 1) 之间
。 - 平滑性: Sigmoid 函数在整个定义域内都是
平滑且可微的
,这对于优化算法(如梯度下降)非常有利。 - 单调性: 函数是
单调递增的
。 - 中心对称性: 虽然 Sigmoid 函数本身不是中心对称的,但它的输出可以通过平移和缩放进行调整,使其对称。
4. 优点
- 概率解释: 由于输出范围在 (0, 1) 之间,Sigmoid 函数的
输出可以被解释为概率
,特别适用于二分类问题的输出层。 - 平滑和连续: 函数的平滑性有助于梯度下降算法在优化过程中稳定收敛。
- 历史悠久: 作为早期的激活函数,Sigmoid 函数在许多经典神经网络架构中得到了广泛应用。
5. 缺点
- 梯度消失问题: 当输入值绝对值较大时,Sigmoid 函数的梯度趋近于 0,这会导致反向传播时
梯度消失
,影响深层网络的训练。 - 输出非零中心化: Sigmoid 函数的输出范围为 (0, 1),其
均值不为 0
。这可能导致梯度更新时的振荡,降低收敛速度。 - 计算成本: 相比于一些更简单的激活函数(如 ReLU),Sigmoid 函数的计算需要
指数运算
,计算成本较高。
6. 导数与梯度性质
Sigmoid 函数的导数在反向传播中起着关键作用。其导数公式为:
σ ′ ( x ) = σ ( x ) ⋅ ( 1 − σ ( x ) ) \sigma'(x) = \sigma(x) \cdot (1 - \sigma(x)) σ′(x)=σ(x)⋅(1−σ(x))
性质分析:
- 梯度范围:
σ
′
(
x
)
\sigma'(x)
σ′(x) 的值在
(0, 0.25) 之间
,最大值为 0.25。当 x = 0 x = 0 x=0 时, σ ′ ( 0 ) = 0.25 \sigma'(0) = 0.25 σ′(0)=0.25。 - 梯度消失: 对于 x x x 远离 0 的区域, σ ( x ) \sigma(x) σ(x) 接近 0 或 1,此时导数 σ ′ ( x ) \sigma'(x) σ′(x) 接近 0,导致梯度消失问题,特别是在深层神经网络中。
7. 应用场景
-
输出层激活: 在二分类问题中,Sigmoid 函数常用于
输出层
,将网络的输出映射到 (0, 1) 之间,表示为预测为正类的概率
。 -
隐藏层激活: 虽然在现代深度学习中较少使用,但在一些
浅层网络
中,Sigmoid 函数仍可作为隐藏层的激活函数
。
8.代码示例
以下是使用 Sigmoid 函数的简单 Python 代码示例,利用 NumPy 实现 Sigmoid 函数及其导数:
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
s = sigmoid(x)
return s * (1 - s)
# 示例
x = np.array([-2, -1, 0, 1, 2])
y = sigmoid(x)
dy = sigmoid_derivative(x)
print("Sigmoid 输出:", y)
print("Sigmoid 导数:", dy)
2. Tanh 函数
1. 定义
双曲正切函数(Tanh 函数)是一种常用的激活函数,广泛应用于神经网络的隐藏层。其数学表达式为:
t a n h ( x ) = e x − e − x e x + e − x tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} tanh(x)=ex+e−xex−e−x
2. 图形表示
Tanh 函数的图形同样呈 S 形,但其输出范围为 (-1, 1),相比 Sigmoid 函数更加对称。
3. 特点
- 输出范围:
t
a
n
h
(
x
)
tanh(x)
tanh(x) 的
输出值在 (-1, 1) 之间
。 - 平滑性: 函数在整个定义域内都是
平滑且可微的
,有利于优化算法(如梯度下降)的应用。 - 单调性: 函数是
单调递增
的。 - 中心对称性: Tanh 函数是
中心对称的
,其输出均值为 0
,这有助于数据的归一化和平衡。
4. 优点
- 零中心化: Tanh 函数的输出范围为 (-1, 1),均值为 0。这有助于
减轻梯度下降过程中偏移问题
,使得后续层的输入更接近于零,有助于加快收敛速度。 - 更强的梯度: 相比 Sigmoid 函数,Tanh 在大多数区域内具有
更大的梯度
,这在一定程度上缓解了梯度消失问题。 - 平滑和连续: 函数的平滑性有助于梯度下降算法在优化过程中稳定收敛。
5. 缺点
- 梯度消失问题: 尽管 Tanh 比 Sigmoid 有更大的梯度,但在输入值绝对值较大时,其梯度仍然趋近于 0,导致深层网络中的
梯度消失
问题。 - 计算成本: 与一些更简单的激活函数(如 ReLU)相比,Tanh 函数需要计算
指数运算
,计算成本较高。 - 非稀疏激活: Tanh 函数的输出较宽,可能导致大量神经元在某一时刻都处于激活状态,
降低网络的稀疏性
。
6. 导数与梯度性质
Tanh 函数的导数在反向传播中起着关键作用。其导数公式为:
t a n h ′ ( x ) = 1 − t a n h 2 ( x ) tanh'(x) = 1 - tanh^2(x) tanh′(x)=1−tanh2(x)
性质分析:
- 梯度范围:
t
a
n
h
′
(
x
)
tanh'(x)
tanh′(x) 的值在
(0, 1) 之间
,最大值为 1,当 x = 0 x = 0 x=0 时, t a n h ′ ( 0 ) = 1 tanh'(0) = 1 tanh′(0)=1。 - 梯度消失: 对于 x x x 远离 0 的区域, t a n h ( x ) tanh(x) tanh(x) 接近 -1 或 1,此时导数 t a n h ′ ( x ) tanh'(x) tanh′(x) 接近 0,导致梯度消失问题,尤其在深层神经网络中。
7. 应用场景
- 隐藏层激活: Tanh 函数常用于神经网络的隐藏层,因为其零中心化特性有助于加快训练过程。
- 递归神经网络 (RNN): 在一些 RNN 结构中,Tanh 被用于激活函数,以
处理时间序列数据
。 - 自编码器: Tanh 函数在自编码器的隐藏层中有时被用来增强模型的表达能力。
8. 代码示例
以下是使用 Tanh 函数的简单 Python 代码示例,利用 NumPy 实现 Tanh 函数及其导数:
import numpy as np
def tanh(x):
return np.tanh(x)
def tanh_derivative(x):
return 1.0 - np.tanh(x)**2
# 示例
x = np.array([-2, -1, 0, 1, 2])
y = tanh(x)
dy = tanh_derivative(x)
print("Tanh 输出:", y)
print("Tanh 导数:", dy)
3. ReLU (Rectified Linear Unit)
1. 定义
ReLU(Rectified Linear Unit,修正线性单元)是当前最广泛使用的激活函数之一,特别是在深度神经网络中。其数学表达式为:
R e L U ( x ) = max ( 0 , x ) ReLU(x) = \max(0, x) ReLU(x)=max(0,x)
2. 图形表示
ReLU 函数的图形呈现出一个简单的线性部分和一个非线性部分的结合:
3. 特点
- 输出范围: ReLU 的输出范围为 [ 0 , + ∞ ) [0, +\infty) [0,+∞)。
- 非线性: 尽管 ReLU 看起来像是分段线性函数,但它引入了非线性,使得神经网络能够学习复杂的模式。
- 计算效率高: ReLU 的计算非常简单,仅涉及比较和取最大值,适合大规模神经网络的高效计算。
- 稀疏激活: ReLU 只在输入为正时激活输出,负值部分输出为零,导致网络的
激活稀疏化,有助于减少过拟合
。
4. 优点
- 减轻梯度消失问题: 在正区间,ReLU 的
梯度恒为 1
,不会像 Sigmoid 和 Tanh 那样在某些区域内导致梯度消失,有助于深层网络的训练。 - 计算简单高效: ReLU 的计算仅涉及简单的阈值操作,极大提高了训练和推理的速度。
- 促进稀疏激活: ReLU 的负区间输出为 0,使得网络中只有一部分神经元在激活,有助于模型的稀疏性和泛化能力。
- 缓解梯度消失: 由于 ReLU 在正区间具有恒定梯度,有助于反向传播中的梯度流动,促进更深层次的网络训练。
5. 缺点
- “死亡神经元”问题: 在训练过程中,
某些神经元
可能会因为权重更新而永久输出 0
,导致这些神经元“死亡”,无法对模型的输出产生贡献。 - 非零中心化: ReLU 的输出范围为
[
0
,
+
∞
)
[0, +\infty)
[0,+∞),
均值不为 0
,可能导致后续层的输入分布偏移,影响训练效率。 - 梯度爆炸: 虽然 ReLU 通常缓解了梯度消失问题,但在某些情况下,特别是在
网络层数过多时
,仍可能面临梯度爆炸问题
。
6. 导数与梯度性质
ReLU 函数的导数在反向传播中起着关键作用。其导数公式为:
R e L U ′ ( x ) = { 1 if x > 0 0 if x ≤ 0 ReLU'(x) = \begin{cases} 1 & \text{if } x > 0 \\ 0 & \text{if } x \leq 0 \end{cases} ReLU′(x)={10if x>0if x≤0
性质分析:
- 梯度范围: ReLU 的导数要么是
1
,要么是0
。这使得在正区间内,梯度恒定,有利于深层网络的训练。 - 不可导点: 在 x = 0 x = 0 x=0 处,ReLU 函数不可导,但在实际应用中,通常采用次梯度方法处理。
- 梯度稀疏性: 负区间的梯度为 0,导致部分神经元在训练过程中不更新权重。
7. 应用场景
-
隐藏层激活: ReLU 是神经网络中隐藏层最常用的激活函数,适用于各种任务,如图像分类、自然语言处理等。
-
卷积神经网络 (CNN): 在 CNN 的各层之间,ReLU 被广泛应用于
激活卷积层的输出
。 -
深层网络: 由于其减轻梯度消失问题的特性,ReLU 特别适合用于深层神经网络的训练。
-
生成对抗网络 (GAN): 在 GAN 的生成器和判别器中,ReLU 常用于
隐藏层的激活
。
8. 代码示例
以下是使用 ReLU 函数的简单 Python 代码示例,利用 NumPy 实现 ReLU 函数及其导数:
import numpy as np
def relu(x):
return np.maximum(0, x)
def relu_derivative(x):
return np.where(x > 0, 1, 0)
# 示例
x = np.array([-2, -1, 0, 1, 2])
y = relu(x)
dy = relu_derivative(x)
print("ReLU 输出:", y)
print("ReLU 导数:", dy)
4. Leaky ReLU
1. 定义
Leaky ReLU(带泄漏的修正线性单元)是 ReLU 函数的一种改进版本,旨在解决 ReLU 的“死亡神经元”问题。其数学表达式为:
L e a k y R e L U ( x ) = { x if x > 0 α x if x ≤ 0 Leaky \, ReLU(x) = \begin{cases} x & \text{if } x > 0 \\ \alpha x & \text{if } x \leq 0 \end{cases} LeakyReLU(x)={xαxif x>0if x≤0
其中,
α
\alpha
α 是一个很小的正数
,通常取值为
0.01
0.01
0.01 或其他小于
1
1
1 的常数。
2. 图形表示
Leaky ReLU 函数的图形与 ReLU 类似,但在负区间有一个小的斜率,而不是完全为零:
3. 特点
- 输出范围: Leaky ReLU 的输出范围为 ( − ∞ , + ∞ ) (-\infty, +\infty) (−∞,+∞),但在负区间的输出受到 α \alpha α 的限制。
- 非线性: 与 ReLU 一样,Leaky ReLU 引入了非线性,使得神经网络能够学习复杂的模式。
- 计算效率高: Leaky ReLU 的计算仍然非常简单,仅涉及线性变换,适合大规模神经网络的高效计算。
- 减轻“死亡神经元”问题: 通过在负区间引入小斜率,Leaky ReLU 允许神经元在负区间有非零梯度,
减少了“死亡神经元”的现象
。
4. 优点
- 缓解“死亡神经元”问题: 相比于 ReLU 完全将负值设为零,Leaky ReLU 在负区间引入了小斜率,允许神经元在负输入时仍能传递梯度,减少了神经元永久不激活的风险。
- 保持稀疏激活: 尽管在负区间有小的激活,Leaky ReLU 仍然保持了
稀疏激活
的特性,有助于减少过拟合。 - 计算简单高效: Leaky ReLU 的计算仅涉及简单的线性变换,保持了与 ReLU 相似的高计算效率。
- 有助于梯度流动: 在
负区间保留小梯度,有助于反向传播过程中梯度的有效流动
,促进更深层网络的训练。
5. 缺点
- 参数选择依赖: Leaky ReLU 中的 α \alpha α 是一个超参数,需要根据具体任务进行选择和调整,不同的 α \alpha α 值可能影响模型性能。
- 非零中心化: 与 ReLU 类似,Leaky ReLU 的输出范围
不对称
,可能导致后续层的输入分布偏移
,影响训练效率。 - 可能引入噪声: 在负区间的小斜率可能引入噪声,尤其是在 α \alpha α 选择不当时,可能影响模型的稳定性。
- 梯度爆炸风险: 尽管 Leaky ReLU 改善了梯度消失问题,但在某些情况下,尤其是
深层网络
中,仍可能面临梯度爆炸的问题
。
6. 导数与梯度性质
Leaky ReLU 函数的导数在反向传播中起着关键作用。其导数公式为:
L e a k y R e L U ′ ( x ) = { 1 if x > 0 α if x ≤ 0 Leaky \, ReLU'(x) = \begin{cases} 1 & \text{if } x > 0 \\ \alpha & \text{if } x \leq 0 \end{cases} LeakyReLU′(x)={1αif x>0if x≤0
性质分析:
- 梯度范围: Leaky ReLU 的导数在正区间为 1 1 1,在负区间为 α \alpha α。这保证了在任何输入下都有非零梯度,促进了梯度的有效传播。
- 可导性: 虽然在
x
=
0
x = 0
x=0 处存在不可导点,但在实际应用中,通常采用
次梯度方法
处理。 - 梯度稳定性: 由于在负区间保留了小的梯度,Leaky ReLU 有助于防止梯度完全消失,促进更深层网络的训练。
7. 应用场景
- 隐藏层激活: Leaky ReLU 常用于神经网络的隐藏层,尤其是在深层网络中,帮助缓解“死亡神经元”问题。
- 卷积神经网络 (CNN): 在 CNN 的各层之间,Leaky ReLU 被广泛应用于激活
卷积层
的输出,提升模型的表达能力。 - 生成对抗网络 (GAN): 在 GAN 的生成器和判别器中,Leaky ReLU 常用于
隐藏层
的激活,以促进模型的稳定训练。 - 递归神经网络 (RNN): 在某些 RNN 结构中,Leaky ReLU 被用作激活函数,以
处理时间序列数据
,提升模型的性能。
8. 代码示例
以下是使用 Leaky ReLU 函数的简单 Python 代码示例,利用 NumPy 实现 Leaky ReLU 函数及其导数:
import numpy as np
def leaky_relu(x, alpha=0.01):
return np.where(x > 0, x, alpha * x)
def leaky_relu_derivative(x, alpha=0.01):
return np.where(x > 0, 1, alpha)
# 示例
x = np.array([-2, -1, 0, 1, 2])
y = leaky_relu(x)
dy = leaky_relu_derivative(x)
print("Leaky ReLU 输出:", y)
print("Leaky ReLU 导数:", dy)
5. Parametric ReLU (PReLU)
1. 定义
Parametric ReLU (PReLU, 参数化修正线性单元) 是 Leaky ReLU 的一种扩展,旨在通过让负区间的斜率参数 α \alpha α 可学习,从而进一步提升激活函数的灵活性和模型性能。其数学表达式为:
P R e L U ( x ) = { x if x > 0 α x if x ≤ 0 PReLU(x) = \begin{cases} x & \text{if } x > 0 \\ \alpha x & \text{if } x \leq 0 \end{cases} PReLU(x)={xαxif x>0if x≤0
其中,
α
\alpha
α 是一个可以在训练过程中通过反向传播学习到的参数,而非固定的常数
。
2. 图形表示
PReLU 函数的图形与 Leaky ReLU 类似,但在负区间的斜率 α \alpha α 可以根据数据自动调整:
3. 特点
- 输出范围: PReLU 的输出范围为 ( − ∞ , + ∞ ) (-\infty, +\infty) (−∞,+∞),与 Leaky ReLU 类似,但负区间的斜率由参数 α \alpha α 控制。
- 非线性: 引入了非线性特性,使得神经网络能够学习更复杂的模式。
- 参数化: 负区间的斜率 α \alpha α 是可训练的参数,增加了模型的灵活性和表达能力。
- 计算效率高: PReLU 的计算仍然非常简单,仅涉及线性变换和可学习参数,适合大规模神经网络的高效计算。
4. 优点
- 自适应负斜率: 通过让负区间的斜率
α
\alpha
α 可学习,PReLU 能够
根据数据自适应地调整激活函数的形状
,提升模型的表现。 - 缓解“死亡神经元”问题: 与 Leaky ReLU 一样,PReLU 通过在负区间引入小斜率,减少了神经元永久不激活的风险。
- 增强模型的表达能力: 可学习的参数 α \alpha α 使得激活函数能够更好地适应不同层和不同任务的需求,提升整体模型的表现。
- 稀疏激活: 尽管负区间有小斜率,PReLU 仍保持了
稀疏激活
的特性,有助于减少过拟合。 - 简单的实现: PReLU 的实现与 ReLU 和 Leaky ReLU 类似,易于集成到现有的神经网络框架中。
5. 缺点
- 增加模型参数: 每个 PReLU 激活单元需要学习一个额外的参数 α \alpha α,这在大规模网络中可能显著增加模型的参数数量,进而增加计算和存储成本。
- 过拟合风险: 可学习的
α
\alpha
α 参数增加了模型的复杂性,可能
在小数据集或简单任务上导致过拟合
。 - 训练稳定性: 在某些情况下,学习到的 α \alpha α 参数可能会导致激活函数的梯度不稳定,影响模型的训练过程。
- 初始化敏感性: α \alpha α 参数的初始值选择可能会影响模型的收敛速度和最终性能,需采用合理的初始化策略。
6. 导数与梯度性质
PReLU 函数的导数在反向传播中起着关键作用。其导数公式为:
P R e L U ′ ( x ) = { 1 if x > 0 α if x ≤ 0 PReLU'(x) = \begin{cases} 1 & \text{if } x > 0 \\ \alpha & \text{if } x \leq 0 \end{cases} PReLU′(x)={1αif x>0if x≤0
性质分析:
- 梯度范围: 在正区间,
导数为 1
;在负区间,导数为 α \alpha α。由于 α \alpha α 是可学习的参数,模型可以根据数据动态调整梯度。 - 可导性: 虽然在
x
=
0
x = 0
x=0 处存在不可导点,但在实际应用中,通常采用
次梯度方法
处理。 - 梯度稳定性: 通过学习 α \alpha α,PReLU 能够保持负区间的小梯度,促进梯度的有效传播,特别是在深层网络中。
7. 应用场景
- 隐藏层激活: PReLU 常用于神经网络的隐藏层,尤其是在需要高灵活性和表达能力的深层网络中。
- 卷积神经网络 (CNN): 在 CNN 的各层之间,PReLU 被广泛应用于激活
卷积层
的输出,提升模型的表现。 - 生成对抗网络 (GAN): 在 GAN 的生成器和判别器中,PReLU 常用于
隐藏层
的激活,以促进模型的稳定训练和生成能力。 - 递归神经网络 (RNN): 在某些 RNN 结构中,PReLU 被用作激活函数,以
处理时间序列数据
,提升模型的性能。 - 迁移学习: 在预训练模型中,PReLU 可用于
微调阶段
,进一步优化模型在特定任务上的表现。
8. 代码示例
以下是使用 PReLU 函数的简单 Python 代码示例,利用 NumPy 实现 PReLU 函数及其导数:
import numpy as np
class PReLU:
def __init__(self, alpha_init=0.25):
self.alpha = alpha_init # 初始化斜率参数
def forward(self, x):
self.x = x
return np.where(x > 0, x, self.alpha * x)
def backward(self, grad_output):
grad_input = np.where(self.x > 0, 1, self.alpha)
# 更新 alpha 的梯度
grad_alpha = np.sum(grad_output * self.x * (self.x <= 0))
return grad_input, grad_alpha
# 示例
x = np.array([-2, -1, 0, 1, 2], dtype=float)
prelu = PReLU(alpha_init=0.01)
y = prelu.forward(x)
dy, d_alpha = prelu.backward(np.ones_like(x)) # 假设上层梯度为1
print("PReLU 输出:", y)
print("PReLU 导数:", dy)
print("PReLU Alpha 梯度:", d_alpha)
6. Softmax 函数
1. 定义
Softmax 函数是一种常用于多分类问题输出层的激活函数,其主要作用是将一个实数向量转换为一个概率分布
。Softmax 函数的数学表达式为:
S o f t m a x ( x i ) = e x i ∑ j e x j Softmax(x_i) = \frac{e^{x_i}}{\sum_j e^{x_j}} Softmax(xi)=∑jexjexi
其中, x i x_i xi 是输入向量中的第 i i i 个元素, ∑ j e x j \sum_j e^{x_j} ∑jexj 是所有输入元素的指数和。
2. 图形表示
Softmax 函数的图形通常在三维情况下展示,每个输入对应一个输出概率。由于 Softmax 处理的是向量而非单个标量,其图形较为复杂,但可以通过多个输入点的概率分布来理解其行为:
3. 特点
- 输出范围: Softmax 的
输出值
位于(0, 1)
之间。 - 概率分布:
输出向量的所有元素之和为 1
,可以被解释为概率分布。 - 归一化: Softmax 对输入向量进行归一化处理,
强调较大的输入值,同时抑制较小的输入值
。 - 可微性: Softmax 函数是
可微的
,适合在反向传播中使用。
4. 优点
- 概率解释: Softmax 的输出可以
直接解释为各类别的预测概率
,便于模型结果的理解和应用。 - 归一化特性: 确保输出向量的和为 1 1 1,适用于多分类任务的输出需求。
- 区分度高: 通过指数函数,Softmax
增强了不同类别之间的区分度
,使得预测结果更加明确。 - 与交叉熵损失结合良好:
Softmax
通常与交叉熵损失函数
一起使用,能够有效地训练多分类模型
。
5. 缺点
- 对异常值敏感: Softmax 对输入向量中的
极端值非常敏感
,可能导致数值稳定性问题。 - 计算复杂度: 对于大规模分类问题,计算 Softmax 可能会增加计算负担。
- 梯度消失问题: 在某些情况下,Softmax 可能
导致梯度消失
,尤其是在输入值较大或较小时。 - 不适用于回归任务: Softmax 主要用于分类任务,
不适用于
需要连续输出的回归任务
。
6. 导数与梯度性质
Softmax 函数在反向传播中的导数较为复杂,因为每个输出元素不仅依赖于自身的输入,还依赖于其他输入元素。其导数公式为:
∂ S o f t m a x ( x i ) ∂ x j = S o f t m a x ( x i ) ⋅ ( δ i j − S o f t m a x ( x j ) ) \frac{\partial Softmax(x_i)}{\partial x_j} = Softmax(x_i) \cdot (\delta_{ij} - Softmax(x_j)) ∂xj∂Softmax(xi)=Softmax(xi)⋅(δij−Softmax(xj))
其中,
δ
i
j
\delta_{ij}
δij 是 Kronecker delta,当 i = j时为 1,否则为 0
。
性质分析:
- 雅可比矩阵: Softmax 的导数形成一个
雅可比矩阵
,其中对角线元素为 S o f t m a x ( x i ) ( 1 − S o f t m a x ( x i ) Softmax(x_i)(1 - Softmax(x_i) Softmax(xi)(1−Softmax(xi),非对角元素为 S o f t m a x ( x i ) S o f t m a x ( x j ) Softmax(x_i)Softmax(x_j) Softmax(xi)Softmax(xj)。 - 梯度流动: Softmax 与交叉熵损失结合时,
梯度缩化为预测概率与真实标签之间的差异
,有助于有效的梯度流动。 - 数值稳定性: 在实际计算中,通常通过减去输入向量的最大值来提高 Softmax 的数值稳定性,防止指数运算导致的溢出。
7. 应用场景
- 多分类问题: Softmax 函数主要用于
多分类问题
的输出层,如图像分类、文本分类等。 - 神经网络输出层: 在深度学习模型中,Softmax 常用于
神经网络的最后一层
,将模型的输出转换为概率分布
。 - 注意力机制: 在序列到序列模型(如 Transformer)中的
注意力机制
里,Softmax 用于计算注意力权重
。 - 概率生成模型: 如
变分自编码器
(VAE) 中的分类任务,Softmax 用于生成类别概率分布。
8. 代码示例
以下是使用 Softmax 函数的简单 Python 代码示例,利用 NumPy 实现 Softmax 函数及其导数:
import numpy as np
def softmax(x):
"""计算稳定的 Softmax 函数"""
shiftx = x - np.max(x, axis=1, keepdims=True) # 减去每行的最大值,提高数值稳定性
exps = np.exp(shiftx)
return exps / np.sum(exps, axis=1, keepdims=True)
def softmax_derivative(softmax_output):
"""计算 Softmax 的导数(雅可比矩阵)"""
s = softmax_output.reshape(-1,1)
return np.diagflat(s) - np.dot(s, s.T)
# 示例
x = np.array([[2.0, 1.0, 0.1],
[1.0, 3.0, 0.2]])
y = softmax(x)
dy = softmax_derivative(y[0]) # 计算第一行的导数
print("Softmax 输出:\n", y)
print("\nSoftmax 导数(第一行):\n", dy)
7. Swish 函数
1. 定义
Swish 函数是一种由 Google 研究人员在 2017 年提出的激活函数,旨在提升神经网络的性能和训练效率。Swish 函数的数学表达式为:
S w i s h ( x ) = x ⋅ σ ( x ) = x 1 + e − x Swish(x) = x \cdot \sigma(x) = \frac{x}{1 + e^{-x}} Swish(x)=x⋅σ(x)=1+e−xx
其中, σ ( x ) \sigma(x) σ(x) 是 Sigmoid 函数。
2. 图形表示
Swish 函数的图形呈现出一个平滑的 S 形曲线,结合了线性和 Sigmoid 函数的特性:
3. 特点
- 输出范围: Swish 的
输出范围
为 ( − ∞ , + ∞ ) (-\infty, +\infty) (−∞,+∞),与 ReLU 类似,但具有更平滑的非线性。 - 非单调性: Swish 函数在某些区间内是
非单调的
,这有助于模型捕捉更复杂的模式。 - 平滑性: Swish 函数是
连续且可微的
,提供了平滑
的梯度,有利于优化过程。 - 自门控特性: Swish 函数通过 Sigmoid 函数自动调节输入的激活程度,实现
自门控机制
。
4. 优点
- 性能提升: 在多个基准测试中,Swish 函数表现出比 ReLU 和其他传统激活函数更好的性能,尤其是在深层神经网络中。
- 平滑梯度: Swish 的平滑性有助于梯度的稳定传播,减少训练过程中的震荡,加速了收敛速度。
- 非单调性: 非单调特性使得 Swish 能够更好地拟合复杂的非线性关系,提升了模型的表达能力。
- 自门控机制: Swish 函数
通过 Sigmoid 函数自适应地调整激活程度
,增强了神经元的动态调节能力。
5. 缺点
- 计算复杂度: 相比于 ReLU 的简单阈值操作,Swish 需要计算 Sigmoid 函数,增加了计算成本,尤其在大规模网络中。
- 非零中心化: Swish 的输出范围不对称,可能导致后续层输入的
均值偏移
,影响训练效率。 - 收敛不稳定性: 在某些情况下,Swish 可能导致训练过程的收敛不稳定,尤其是在高学习率下。
- 实现复杂性: 相较于 ReLU 等简单激活函数,Swish 的实现和优化需要更多的计算资源和技巧。
6. 导数与梯度性质
Swish 函数在反向传播中的导数较为复杂,其导数公式为:
S w i s h ′ ( x ) = σ ( x ) + x ⋅ σ ′ ( x ) = σ ( x ) ⋅ ( 1 + x ⋅ ( 1 − σ ( x ) ) ) Swish'(x) = \sigma(x) + x \cdot \sigma'(x) = \sigma(x) \cdot (1 + x \cdot (1 - \sigma(x))) Swish′(x)=σ(x)+x⋅σ′(x)=σ(x)⋅(1+x⋅(1−σ(x)))
性质分析:
- 梯度范围: Swish 的导数在不同区间内具有不同的梯度值,
正区间梯度接近 1
,负区间梯度较小但非零
。 - 平滑梯度: 由于 Swish 的导数包含 Sigmoid 函数,梯度变化更加平滑,有助于稳定梯度流动。
- 自适应梯度: Swish 的导数依赖于输入值,使得梯度在不同区域具有自适应性,有助于优化过程。
7. 应用场景
- 深层神经网络: Swish 函数在深层神经网络中表现出色,尤其是在需要复杂非线性特征学习的任务中。
- 卷积神经网络(CNN): Swish 被广泛应用于 CNN 的
隐藏层
激活,提升图像分类和目标检测的性能。 - 生成对抗网络(GAN): 在
GAN 的生成器和判别器
中,Swish 有助于稳定训练过程,提升生成质量。 - 自然语言处理(NLP): 在
Transformer
等模型中,Swish 用于隐藏层激活
,提升语言理解和生成能力。 - 迁移学习: 在预训练模型中,Swish 可用于
微调阶段
,进一步优化模型在特定任务上的表现。
8. 代码示例
以下是使用 Swish 函数的简单 Python 代码示例,利用 NumPy 实现 Swish 函数及其导数:
import numpy as np
def sigmoid(x):
"""计算 Sigmoid 函数"""
return 1 / (1 + np.exp(-x))
def swish(x):
"""计算 Swish 函数"""
return x * sigmoid(x)
def swish_derivative(x):
"""计算 Swish 函数的导数"""
s = sigmoid(x)
return s + x * s * (1 - s)
# 示例
x = np.array([-2.0, -1.0, 0.0, 1.0, 2.0])
y = swish(x)
dy = swish_derivative(x)
print("Swish 输出:", y)
print("Swish 导数:", dy)
8. GELU (Gaussian Error Linear Unit)
1. 定义
GELU(Gaussian Error Linear Unit,高斯误差线性单元)是一种现代激活函数,广泛应用于深度学习模型,特别是在 Transformer 架构中。GELU 函数结合了线性和非线性特性
,通过引入概率性激活
,提升了模型的表达能力和训练效率。其
GELU函数的完整数学表达式有两种常见形式:
1.1 基于标准正态分布累积分布函数(CDF)的表达式:
G
E
L
U
(
x
)
=
x
⋅
Φ
(
x
)
GELU(x) = x \cdot \Phi(x)
GELU(x)=x⋅Φ(x)
其中,
Φ
(
x
)
\Phi(x)
Φ(x) 是标准正态分布的累积分布函数,定义为:
Φ
(
x
)
=
1
2
π
∫
−
∞
x
e
−
t
2
2
d
t
\Phi(x) = \frac{1}{\sqrt{2\pi}} \int_{-\infty}^{x} e^{-\frac{t^2}{2}} dt
Φ(x)=2π1∫−∞xe−2t2dt
1.2. 基于双曲正切函数(tanh)的近似表达式:
由于直接计算累积分布函数在实际应用中可能计算复杂度较高,GELU函数常用以下的近似形式来简化计算:
G
E
L
U
(
x
)
=
1
2
x
[
1
+
tanh
(
2
π
(
x
+
0.044715
x
3
)
)
]
GELU(x) = \frac{1}{2}x \left[ 1 + \tanh\left( \sqrt{\frac{2}{\pi}} \left(x + 0.044715x^3\right)\right) \right]
GELU(x)=21x[1+tanh(π2(x+0.044715x3))]
这个近似公式在保留GELU函数原有性质的同时,减少了计算的复杂度,因而在实际应用中更为常用。
2. 图形表示
GELU 函数的图形呈现出平滑的非线性曲线,与 ReLU 和 Swish 类似,但更加平滑且具有概率性激活特性。
3. 特点
- 输出范围: GELU 的
输出范围
为 ( − ∞ , + ∞ ) (-\infty, +\infty) (−∞,+∞),类似于 ReLU 和 Swish。 - 平滑非线性: GELU 提供了比 ReLU 更平滑的非线性变换,结合了
线性和概率性激活
的优点。 - 自门控特性: 通过标准正态分布的累积分布函数,GELU 实现了
自门控机制
,根据输入值动态调整激活程度。 - 可微性: GELU 函数在整个定义域内都是
连续且可微的
,适合梯度下降优化算法。
4. 优点
- 性能提升: GELU 在多个任务和模型中展示出比 ReLU 和其他传统激活函数更优的性能,尤其在深层神经网络和 Transformer 架构中。
- 平滑梯度: GELU 的
平滑性
有助于稳定梯度传播,减少训练过程中的震荡,加速收敛速度。 - 概率性激活: 通过引入标准正态分布的累积分布函数,GELU 使得激活具有
概率性
,有助于模型学习复杂复杂的模式。 - 非零中心化: GELU 的输出分布更
接近于零中心化
,有助于加快训练过程和提高模型性能。 - 与 Transformer 兼容性强:
GELU 是 Transformer 等现代架构的默认激活函数
,证明了其在复杂模型中的有效性。
5. 缺点
- 计算复杂度高: 相比于 ReLU 和 Leaky ReLU,GELU 需要计算误差函数 erf ( x ) \text{erf}(x) erf(x),增加了计算成本,尤其在大规模网络中。
- 实现复杂性: GELU 的实现比 ReLU 更为复杂,可能需要额外的计算资源和优化技巧。
- 数值稳定性: 在算极端输入值时,可能面临数值稳定性问题,需要采取适当的数值处理措施。
- 不适用于所有任务: 尽管在许多任务中表现优异,但在某些特定任务或模型中,GELU 可能并不是最佳选择。
6. 导数与梯度性质
GELU 函数在反向传播中的导数相对复杂,其导数公式为:
G E L U ′ ( x ) = Φ ( x ) + x ⋅ ϕ ( x ) GELU'(x) = \Phi(x) + x \cdot \phi(x) GELU′(x)=Φ(x)+x⋅ϕ(x)
其中, ϕ ( x ) \phi(x) ϕ(x) 是标准正态分布的概率密度函数(PDF),即:
ϕ ( x ) = 1 2 π e − x 2 2 \phi(x) = \frac{1}{\sqrt{2\pi}} e^{-\frac{x^2}{2}} ϕ(x)=2π1e−2x2
性质分析:
- 梯度范围: GELU 的导数在整个输入域内变化平滑,既包含了
线性区域的梯度(接近 1
),也包含了非线性区域的渐变梯度(小于 1)
。 - 平滑梯度: 由于 GELU 的导数结合了 Φ ( x ) \Phi(x) Φ(x) 和 ϕ ( x ) \phi(x) ϕ(x),梯度变化更加平滑,有助于优化过程的稳定性。
- 数值稳定性: 在计算导数时,需确保误差函数和概率函数的计算稳定,尤其在处理极端输入值时。
7. 应用场景
- Transformer 模型: GELU 是 Transformer 架构中默认的激活函数,广泛应用于
自然语言处理
(NLP)任务中。 - 深层神经网络: 在需要复杂非线性特征学习的深层网络中,GELU 提供了更强的表达能力和稳定的梯度传播。
- 卷积神经网络(CNN): 在 CNN 的
隐藏层
中,GELU 用于提升图像分类、目标检测等任务的性能。 - 生成对抗网络(GAN): GELU 在 GAN 的生成器和判别器中有助于稳定训练过程,提升生成质量。
- 迁移学习: 在预训练模型中,GELU 可用于
微调阶段
,进一步优化模型在特定任务上的表现。 - 强化学习: 在
强化学习
模型中,GELU 有助于稳定策略网络和价值网络的训练。
8. 代码示例
以下是使用 GELU 函数的简单 Python 代码示例,利用 NumPy 实现 GELU 函数及其导数:
import numpy as np
from scipy.special import erf
def gelu(x):
"""计算 GELU 函数"""
return x * 0.5 * (1 + erf(x / np.sqrt(2)))
def gelu_derivative(x):
"""计算 GELU 函数的导数"""
return 0.5 * (1 + erf(x / np.sqrt(2))) + (x / np.sqrt(2 * np.pi)) * np.exp(-0.5 * x ** 2)
# 示例
x = np.array([-2.0, -1.0, 0.0, 1.0, 2.0])
y = gelu(x)
dy = gelu_derivative(x)
print("GELU 输出:", y)
print("GELU 导数:", dy)
五. 激活函数的对比总结
激活函数 | 定义 | 输出范围 | 可微性 | 主要优点 | 主要缺点 | 典型应用场景 |
---|---|---|---|---|---|---|
Sigmoid | σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1 | (0, 1) | 可微 | 概率解释,平滑连续 | 梯度消失,非零中心化,计算成本高 | 二分类输出层,浅层网络隐层激活 |
Tanh | tanh ( x ) = e x − e − x e x + e − x \tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} tanh(x)=ex+e−xex−e−x | (-1, 1) | 可微 | 零中心化,较大的梯度 | 梯度消失,计算成本高 | 隐藏层,递归神经网络(RNN),自编码器 |
ReLU | ReLU ( x ) = max ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x) | [0, +∞) | 可微( x ≠ 0 x \neq 0 x=0) | 减轻梯度消失,计算简单,稀疏激活 | “死亡神经元”问题,非零中心化 | 隐藏层,卷积神经网络(CNN),深层网络 |
Leaky ReLU | Leaky ReLU ( x ) = { x x > 0 α x x ≤ 0 \text{Leaky ReLU}(x) = \begin{cases} x & x > 0 \\ \alpha x & x \leq 0 \end{cases} Leaky ReLU(x)={xαxx>0x≤0 | (-∞, +∞) | 可微( x ≠ 0 x \neq 0 x=0) | 缓解“死亡神经元”问题,保持梯度流动 | 参数选择依赖,非零中心化,可能引入噪声 | 隐藏层,深层网络,卷积神经网络(CNN),生成对抗网络(GAN) |
PReLU | PReLU ( x ) = { x x > 0 α x x ≤ 0 \text{PReLU}(x) = \begin{cases} x & x > 0 \\ \alpha x & x \leq 0 \end{cases} PReLU(x)={xαxx>0x≤0 | (-∞, +∞) | 可微( x ≠ 0 x \neq 0 x=0) | 自适应负斜率,增强表达能力,缓解“死亡神经元”问题 | 增加模型参数,过拟合风险,训练稳定性问题受影响 | 隐藏层,深层网络,CNN,GAN,递归神经网络(RNN) |
Softmax | Softmax ( x i ) = e x i ∑ j e x j \text{Softmax}(x_i) = \frac{e^{x_i}}{\sum_j e^{x_j}} Softmax(xi)=∑jexjexi | (0, 1) 且总和为1 | 可微 | 概率解释,归一化特性,与交叉熵损失结合良好 | 对异常值敏感,计算复杂度高,梯度消失问题 | 多分类输出层,注意力机制,概率生成模型 |
Swish | Swish ( x ) = x ⋅ σ ( x ) = x 1 + e − x \text{Swish}(x) = x \cdot \sigma(x) = \frac{x}{1 + e^{-x}} Swish(x)=x⋅σ(x)=1+e−xx | (-∞, +∞) | 可微 | 性能提升,平滑梯度,非单调性,自门控机制 | 计算复杂度高,非零中心化,收敛不稳定 | 隐藏层,深层网络,CNN,GAN,自然语言处理(NLP) |
GELU | GELU ( x ) = x ⋅ Φ ( x ) = x ⋅ 1 2 [ 1 + erf ( x 2 ) ] \text{GELU}(x) = x \cdot \Phi(x) = x \cdot \frac{1}{2}\left[ 1 + \text{erf}\left(\frac{x}{\sqrt{2}}\right)\right] GELU(x)=x⋅Φ(x)=x⋅21[1+erf(2x)] | (-∞, +∞) | 可微 | 性能提升,平滑梯度,概率性激活,非零中心化 | 计算复杂度高,数值稳定性问题 | Transformer,深层网络,CNN,GAN,自然语言处理(NLP) |
不同的激活函数在不同的任务和模型架构中具有各自的优势和适用性。以下是一些选择激活函数的建议:
- 二分类任务: 在输出层使用 Sigmoid 激活函数,隐藏层可选择 ReLU、Tanh 或 GELU。
- 多分类任务: 在输出层使用 Softmax 激活函数,隐藏层可选择 ReLU、Swish、GELU 或 Tanh。
- 深层网络: 推荐使用 ReLU、Leaky ReLU、PReLU、Swish 或 GELU,以缓解梯度消失问题并提高训练效率。
- 生成模型(如 GAN): 在隐藏层中使用 Leaky ReLU 或 PReLU,以稳定训练过程和提升生成质量。
- 自然语言处理(NLP)和 Transformer: 推荐使用 GELU 作为默认激活函数,因其在这些架构中表现出色。
- 计算资源限制的环境: 优先考虑计算简单的激活函数,如 ReLU、Leaky ReLU,避免使用计算复杂度较高的 Swish、GELU。
- 需要高表达能力和灵活性的任务: 可以选择 Swish 或 GELU,特别是在深层网络和复杂特征学习中表现优异。
在实际应用中,激活函数的选择要结合具体任务需求、模型架构和计算资源因素综合考虑。通过实验和验证,可以找到最适合特定应用场景的激活函数,以提升模型的性能和训练效率。
结~~~