深度学习 --- 激活函数
深度学习中的激活函数 本文系统介绍了神经网络中激活函数的作用和常见类型。激活函数通过引入非线性特性,使神经网络能够学习和表达复杂的函数关系,增强其非线性建模能力。 文章首先分析了不使用激活函数时,多层神经网络等价于单层线性模型的局限性。随后重点介绍了两种经典激活函数: Sigmoid函数:将输入映射到(0,1)区间,适合概率输出,但存在梯度消失和计算成本高的问题 Tanh函数:输出范围(-1,1)
深度学习 — 激活函数
文章目录
一,基础概念
激活函数的作用是在隐藏层引入非线性,使得神经网络能够学习和表示复杂的函数关系,使网络具备非线性能力,增强其表达能力。
1.1 线性
- 核心观点:如果神经网络的隐藏层不使用激活函数,整个网络将表现为一个线性模型,无法捕捉数据中的非线性关系。
- 数学推导:
- 单层网络:输出为线性变换,即
对于单层网络(输入层到输出层),如果没有激活函数,输出 a ( 1 ) \mathbf{a}^{(1)} a(1) 可以表示为:
a ( 1 ) = W ( 1 ) x + b ( 1 ) \mathbf{a}^{(1)} = \mathbf{W}^{(1)} \mathbf{x} + \mathbf{b}^{(1)} a(1)=W(1)x+b(1)
- 多层网络:
如果有L层,每层都没有激活函数,则第l层的输出为: a ( l ) = W ( l ) a ( l − 1 ) + b ( l ) \mathbf{a}^{(l)} = \mathbf{W}^{(l)} \mathbf{a}^{(l-1)} + \mathbf{b}^{(l)} a(l)=W(l)a(l−1)+b(l) - 结论:
- 激活函数是引入非线性特性、使神经网络能够处理复杂问题的关键。
- 没有激活函数的多层神经网络等价于一个单层线性模型。
1.2 非线性可视化
- 工具:使用 TensorFlow Playground 进行可视化。
- 可视化目的:通过可视化的方式理解非线性拟合能力。
- 可视化工具的特点:
- 可以选择不同的数据集、调整训练与测试数据的比例。
- 可以选择输入特征、调整权重和偏置。
- 可以观察神经网络的输出,通过颜色显示数据点和预测值。
- 提供了对网络结构(如隐藏层数量、激活函数等)的调整功能。
- 可视化结果:
- 激活函数的使用使得神经网络能够捕捉数据中的非线性关系。
- 不同的激活函数和网络结构对拟合能力有显著影响。

1.3总结
- 线性与非线性的重要性:
- 没有激活函数的神经网络只能处理线性问题,而现实世界中的许多问题是非线性的。
- 激活函数是神经网络能够处理复杂非线性问题的关键。
- 可视化工具的作用:
- TensorFlow Playground 提供了一个直观的方式来理解神经网络的非线性拟合能力。
- 通过调整网络结构和激活函数,可以观察到不同的拟合效果,从而更好地理解神经网络的工作原理。
二,常见的激活函数
激活函数通过引入非线性来增强神经网络的表达能力,对于解决线性模型的局限性至关重要。由于反向传播算法(BP)用于更新网络参数,因此激活函数必须是可微的,也就是说能够求导的。
2.1 sigmoid
Sigmoid激活函数是一种常见的非线性激活函数,特别是在早期神经网络中应用广泛。它将输入映射到0到1之间的值,因此非常适合处理概率问题。
| 方面 | 内容 |
|---|---|
| 公式 | f ( x ) = σ ( x ) = 1 1 + e − x f(x) = \sigma(x) = \frac{1}{1 + e^{-x}} f(x)=σ(x)=1+e−x1 |
| 特征 | 1. 将任意实数输入映射到 (0, 1) 之间,适合处理概率场景。 2. 一般用于二分类输出层。 3. 导数计算方便,可以用自身表达式表示: σ ′ ( x ) = σ ( x ) ⋅ ( 1 − σ ( x ) ) \sigma'(x) = \sigma(x) \cdot (1 - \sigma(x)) σ′(x)=σ(x)⋅(1−σ(x)) |
| 优点 | 1. 输出范围在 (0, 1) 之间,适合处理概率问题。 2. 导数计算简单,便于反向传播。 |
| 缺点 | 1. 梯度消失:输入非常大或非常小时,梯度接近于0,导致早期层权重更新缓慢,训练速度变慢甚至停滞。 2. 信息丢失:输入值相差很大时,激活值几乎相同(如输入100和10000的激活值都接近1)。 3. 计算成本高:涉及指数运算,计算复杂度比ReLU等函数高。 |
import torch
import matplotlib.pyplot as plt
# plt支持中文
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
def test001():
# 一行两列绘制图像
_, ax = plt.subplots(1, 2)
# 绘制函数图像
x = torch.linspace(-10, 10, 100)
y = torch.sigmoid(x)
# 网格
ax[0].grid(True)
ax[0].set_title("sigmoid 函数曲线图")
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
# 在第一行第一列绘制sigmoid函数曲线图
ax[0].plot(x, y)
# 绘制sigmoid导数曲线图
x = torch.linspace(-10, 10, 100, requires_grad=True)
# y = torch.sigmoid(x) * (1 - torch.sigmoid(x))
# 自动求导
torch.sigmoid(x).sum().backward()
ax[1].grid(True)
ax[1].set_title("sigmoid 函数导数曲线图", color="red")
ax[1].set_xlabel("x")
ax[1].set_ylabel("y")
# ax[1].plot(x.detach().numpy(), y.detach())
# 用自动求导的结果绘制曲线图
ax[1].plot(x.detach().numpy(), x.grad.detach().numpy())
# 设置曲线颜色
ax[1].lines[0].set_color("red")
plt.show()
if __name__ == "__main__":
test001()

2.2 tanh
tanh(双曲正切)是一种常见的非线性激活函数,常用于神经网络的隐藏层。tanh 函数也是一种S形曲线,输出范围为 ( − 1 , 1 ) (−1,1) (−1,1)
| 方面 | 内容 |
|---|---|
| 公式 | tanh ( x ) = e x − e − x e x + e − x \text{tanh}(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} tanh(x)=ex+e−xex−e−x |
| 特征 | 1. 输出范围在 ( − 1 , 1 ) (-1, 1) (−1,1) 之间,零中心化输出有助于加速收敛。 2. 是关于原点对称的奇函数,输入为0时输出也为0,有助于数据平衡。 3. 全局连续可微,导数公式为: d d x tanh ( x ) = 1 − tanh 2 ( x ) \frac{d}{dx} \text{tanh}(x) = 1 - \text{tanh}^2(x) dxdtanh(x)=1−tanh2(x)。 |
| 优点 | 1. 输出零中心化,加速收敛。 2. 对称性有助于数据平衡。 3. 全局可微,适合梯度下降优化。 |
| 缺点 | 1. 梯度消失:输入值非常大或非常小时,导数接近于0,深层网络中仍会导致训练缓慢甚至无法收敛。 2. 计算成本:涉及指数运算,计算复杂度较高,尽管与 Sigmoid 相比差异不大。 |
import torch
import matplotlib.pyplot as plt
# plt支持中文
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
def test001():
# 一行两列绘制图像
_, ax = plt.subplots(1, 2)
# 绘制函数图像
x = torch.linspace(-10, 10, 100)
y = torch.tanh(x)
# 网格
ax[0].grid(True)
ax[0].set_title("tanh 函数曲线图")
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
# 在第一行第一列绘制tanh函数曲线图
ax[0].plot(x, y)
# 绘制tanh导数曲线图
x = torch.linspace(-10, 10, 100, requires_grad=True)
# y = torch.tanh(x) * (1 - torch.tanh(x))
# 自动求导:需要标量才能反向传播
torch.tanh(x).sum().backward()
ax[1].grid(True)
ax[1].set_title("tanh 函数导数曲线图", color="red")
ax[1].set_xlabel("x")
ax[1].set_ylabel("x.grad")
# ax[1].plot(x.detach().numpy(), y.detach())
# 用自动求导的结果绘制曲线图
ax[1].plot(x.detach().numpy(), x.grad.detach().numpy())
# 设置曲线颜色
ax[1].lines[0].set_color("red")
plt.show()
if __name__ == "__main__":
test001()

2.3 Relu
ReLU(Rectified Linear Unit)是深度学习中最常用的激活函数之一,它的全称是修正线性单元。ReLU 激活函数的定义非常简单,但在实践中效果非常好。
| 方面 | 内容 |
|---|---|
| 定义 | ReLU ( x ) = max ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x) |
| 特征 | 1. 当 x > 0 x > 0 x>0 时,ReLU(x) = x 2. 当 x ≤ 0 x \leq 0 x≤0 时,ReLU(x) = 0 3. 导数是分段函数: ReLU ′ ( x ) = { 1 , if x > 0 0 , if x ≤ 0 \text{ReLU}'(x) = \begin{cases} 1, & \text{if } x > 0 \\ 0, & \text{if } x \leq 0 \end{cases} ReLU′(x)={1,0,if x>0if x≤0 4. 计算简单,只需要一次比较运算。 |
| 优点 | 1. 计算简单:加速神经网络的训练。 2. 缓解梯度消失问题:在正半区导数恒为1,不存在饱和问题,有利于深层网络的梯度传播。 3. 稀疏激活:引入稀疏性,减少冗余信息,提高效率和泛化能力。 |
| 缺点 | 1. 神经元死亡问题:当输入小于等于0时,神经元输出为0,且导数为0,可能导致神经元永远不再激活,降低模型的表达能力。 |
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 中文问题
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
def test006():
# 输入数据x
x = torch.linspace(-20, 20, 1000)
y = F.relu(x)
# 绘制一行2列
_, ax = plt.subplots(1, 2)
ax[0].plot(x.numpy(), y.numpy())
# 显示坐标格子
ax[0].grid()
ax[0].set_title("relu 激活函数")
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
# 绘制导数函数
x = torch.linspace(-20, 20, 1000, requires_grad=True)
F.relu(x).sum().backward()
ax[1].plot(x.detach().numpy(), x.grad.numpy())
ax[1].grid()
ax[1].set_title("relu 激活函数导数", color="red")
# 设置绘制线色颜色
ax[1].lines[0].set_color("red")
ax[1].set_xlabel("x")
ax[1].set_ylabel("x.grad")
plt.show()
if __name__ == "__main__":
test006()

2.4 LeakyRelu
Leaky ReLU是一种对 ReLU 函数的改进,旨在解决 ReLU 的一些缺点,特别是Dying ReLU 问题。Leaky ReLU 通过在输入为负时引入一个小的负斜率来改善这一问题。
| 方面 | 内容 |
|---|---|
| 定义 | Leaky ReLU ( x ) = { x , if x > 0 α x , if x ≤ 0 \text{Leaky ReLU}(x) = \begin{cases} x, & \text{if } x > 0 \\ \alpha x, & \text{if } x \leq 0 \end{cases} Leaky ReLU(x)={x,αx,if x>0if x≤0 其中, α \alpha α 是一个非常小的常数(如 0.01),控制负半轴的斜率。 |
| 特征 | 1. 当 x > 0 x > 0 x>0 时,Leaky ReLU(x) = x。 2. 当 x ≤ 0 x \leq 0 x≤0 时,Leaky ReLU(x) = α x \alpha x αx,其中 α \alpha α 是一个小的负斜率。 3. 计算简单,与 ReLU 类似,只需简单的比较和线性运算。 |
| 优点 | 1. 避免神经元死亡:通过在 x ≤ 0 x \leq 0 x≤0 区域引入一个小的负斜率,即使输入值小于等于零,Leaky ReLU 仍然会有梯度,允许神经元继续更新权重,避免神经元在训练过程中完全“死亡”的问题。 2. 计算简单:与 ReLU 类似,计算开销低。 |
| 缺点 | 1. 参数选择: α \alpha α 是一个需要调整的超参数,选择合适的 α \alpha α 值可能需要实验和调优。 2. 可能出现负激活:如果 α \alpha α 设定得不当,仍然可能导致激活值过低,影响网络的性能。 |
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 中文设置
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
def test006():
x = torch.linspace(-5, 5, 200)
# 设置leaky_relu的负斜率超参数
slope = 0.03
y = F.leaky_relu(x, slope)
# 一行两列
_, ax = plt.subplots(1, 2)
# 开始绘制函数曲线图
ax[0].plot(x, y)
ax[0].set_title("Leaky ReLU 函数曲线图")
ax[0].set_xlabel("x")
ax[0].set_ylabel("y")
ax[0].grid(True)
# 绘制leaky_relu的梯度曲线图
x = torch.linspace(-5, 5, 200, requires_grad=True)
F.leaky_relu(x, slope).sum().backward()
ax[1].plot(x.detach().numpy(), x.grad)
ax[1].set_title("Leaky ReLU 梯度曲线图", color="red")
ax[1].set_xlabel("x")
ax[1].set_ylabel("x.grad")
ax[1].grid(True)
# 设置线的颜色
ax[1].lines[0].set_color("red")
plt.show()
if __name__ == "__main__":
test006()

2.5 softmax
Softmax激活函数通常用于分类问题的输出层,它能够将网络的输出转换为概率分布,使得输出的各个类别的概率之和为 1。Softmax 特别适合用于多分类问题。
| 方面 | 内容 |
|---|---|
| 定义 | S o f t m a x ( z i ) = e z i ∑ j = 1 n e z j \mathrm{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^n e^{z_j}} Softmax(zi)=∑j=1nezjezi |
| 特征 | 1. 将输出转化为概率分布,每个输出值在 (0, 1) 之间,且所有输出值之和为 1。 2. 突出差异,使得概率最大的类别的输出值更接近 1,其他类别更接近 0。 3. 常与交叉熵损失函数结合使用,用于多分类问题。 4. 导数计算:当 i = j i = j i=j 时, ∂ p i ∂ z i = p i ( 1 − p i ) \frac{\partial p_i}{\partial z_i} = p_i(1 - p_i) ∂zi∂pi=pi(1−pi);当 i ≠ j i \neq j i=j 时, ∂ p i ∂ z j = − p i p j \frac{\partial p_i}{\partial z_j} = -p_i p_j ∂zj∂pi=−pipj。 |
| 优点 | 1. 概率化输出:将网络输出转化为概率分布,便于分类决策。 2. 突出差异:放大差异,使得最大概率值更接近 1,其他值更接近 0。 3. 数学性质良好:导数计算简单,适合多分类问题。 |
| 缺点 | 1. 数值不稳定性:当 z i z_i zi 的数值过大时, e z i e^{z_i} ezi 可能导致数值溢出。可以通过减去最大值 max ( z ) \max(z) max(z) 来解决: S o f t m a x ( z i ) = e z i − max ( z ) ∑ j = 1 n e z j − max ( z ) \mathrm{Softmax}(z_i) = \frac{e^{z_i - \max(z)}}{\sum_{j=1}^n e^{z_j - \max(z)}} Softmax(zi)=∑j=1nezj−max(z)ezi−max(z)。 2. 计算开销大:在处理大量类别时(如大词汇表),计算开销较大。 |
import torch
import torch.nn as nn
# 表示4分类,每个样本全连接后得到4个得分,下面示例模拟的是两个样本的得分
input_tensor = torch.tensor([[-1.0, 2.0, -3.0, 4.0], [-2, 3, -3, 9]])
softmax = nn.Softmax()
output_tensor = softmax(input_tensor)
# 关闭科学计数法
torch.set_printoptions(sci_mode=False)
print("输入张量:", input_tensor)
print("输出张量:", output_tensor)
更多推荐
所有评论(0)