当前位置: 首页 > article >正文

深度学习——激活函数

一、人工神经元

1.1 构建人工神经元

人工神经元接受多个输入信息,对它们进行加权求和,再经过激活函数处理,最后将这个结果输出。

 

1.2 组成部分

  • 输入(Inputs): 代表输入数据,通常用向量表示,每个输入值对应一个权重。
  • 权重(Weights): 每个输入数据都有一个权重,表示该输入对最终结果的重要性。
  • 偏置(Bias): 一个额外的可调参数,作用类似于线性方程中的截距,帮助调整模型的输出。
  • 加权求和: 神经元将输入乘以对应的权重后求和,再加上偏置。
  • 激活函数(Activation Function): 用于将加权求和后的结果转换为输出结果,引入非线性特性,使神经网络能够处理复杂的任务。常见的激活函数有Sigmoid、ReLU(Rectified Linear Unit)、Tanh等。

1.3 数学表示 

如果有 n 个输入 x1,x2,x3,....,xn,权重分别为w1,w2,w3,.....,w4,偏置为b,则神经元的输出y表示为:

 其中是激活函数。

二、深入神经网络 

2.1 基本结构

神经网络有下面三个基础层(Layer)构建而成:

  • 输入层(Input): 神经网络的第一层,负责接收外部数据,不进行计算。
  • 隐藏层(Hidden): 位于输入层和输出层之间,进行特征提取和转换。隐藏层一般有多层,每一层有多个神经元。
  • 输出层(Output): 网络的最后一层,产生最终的预测结果或分类结果

2.2 网络构建

 我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个权重,经典如下:

 

2.3 全连接神经网络

全连接(Fully Connected,FC)神经网络是前馈神经网络的一种,每一层的神经元与上一层的所有神经元全连接,常用于图像分类、文本分类等任务。

2.3.1 特点
  • 全连接层: 层与层之间的每个神经元都与前一层的所有神经元相连。
  • 权重数量: 由于全连接的特点,权重数量较大,容易导致计算量大、模型复杂度高。
  • 学习能力: 能够学习输入数据的全局特征,但对于高维数据却不擅长捕捉局部特征(如图像就需要CNN)。
2.3.2 计算步骤
  1. 数据传递: 输入数据经过每一层的计算,逐层传递到输出层。

  2. 激活函数: 每一层的输出通过激活函数处理。

  3. 损失计算: 在输出层计算预测值与真实值之间的差距,即损失函数值。

  4. 反向传播(Back Propagation): 通过反向传播算法计算损失函数对每个权重的梯度,并更新权重以最小化损失。

三、参数初始化

3.1 固定值初始化

固定值初始化是指在神经网络训练开始时,将所有权重或偏置初始化为一个特定的常数值。这种初始化方法虽然简单,但在实际深度学习应用中通常并不推荐。

3.1.1 全零初始化

将神经网络中的所有权重参数初始化为0。

方法:将所有权重初始化为零。

缺点:导致对称性破坏,每个神经元在每一层中都会执行相同的计算,模型无法学习。

应用场景:通常不用来初始化权重,但可以用来初始化偏置。

# 全0参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.zeros_(linear.weight)

# 结果
# Parameter containing:
# tensor([[0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.],
          [0., 0., 0., 0., 0., 0.]], requires_grad=True)

3.1.2 全1初始化

全1初始化会导致网络中每个神经元接收到相同的输入信号,进而输出相同的值,这就无法进行学习和收敛。所以全1初始化只是一个理论上的初始化方法,但在实际神经网络的训练中并不适用。

# 全1参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.ones_(linear.weight)


# 结果
# Parameter containing:
# tensor([[1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.]], requires_grad=True)

3.1.3 任意常数初始化

将所有参数初始化为某个非零的常数(如 0.1,-1 等)。虽然不同于全0和全1,但这种方法依然不能避免对称性破坏的问题。

# 固定值参数初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.constant_(linear.weight, 0.63)


# 结果
# Parameter containing:
# tensor([[0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300],
          [0.6300, 0.6300, 0.6300, 0.6300, 0.6300, 0.6300]], requires_grad=True)

3.2 随机初始化

方法:将权重初始化为随机的小值,通常从正态分布或均匀分布中采样。

应用场景:这是最基本的初始化方法,通过随机初始化避免对称性破坏。

代码演示:随机分布之均匀初始化

# 均匀分布随机初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.uniform_(linear.weight)


# 结果
# Parameter containing:
# tensor([[0.4080, 0.7444, 0.7616, 0.0565, 0.2589, 0.0562],
          [0.1485, 0.9544, 0.3323, 0.9802, 0.1847, 0.6254],
          [0.6256, 0.2047, 0.5049, 0.3547, 0.9279, 0.8045],
          [0.1994, 0.7670, 0.8306, 0.1364, 0.4395, 0.0412]], requires_grad=True)

代码演示: 正态分布初始化

# 正太分布初始化
linear = nn.Linear(in_features=6, out_features=4)
# 初始化权重参数
nn.init.normal_(linear.weight, mean=0, std=1)

# 结果
# Parameter containing:
# tensor([[ 1.5321,  0.2394,  0.0622,  0.4482,  0.0757, -0.6056],
          [ 1.0632,  1.8069,  1.1189,  0.2448,  0.8095, -0.3486],
          [-0.8975,  1.8253, -0.9931,  0.7488,  0.2736, -1.3892],
          [-0.3752,  0.0500, -0.1723, -0.4370, -1.5334, -0.5393]], requires_grad=True)

3.3 Xavier 初始化

也叫做Glorot初始化。

方法:根据输入和输出神经元的数量来选择权重的初始值。权重从以下分布中采样:

或者  

 

优点:平衡了输入和输出的方差,适合 Sigmoid 和 Tanh 激活函数。

应用场景:常用于浅层网络或使用 Sigmoid 、Tanh 激活函数的网络。

代码演示:

import torch
import torch.nn as nn


def test007():
    # Xavier初始化:正态分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.xavier_normal_(linear.weight)
    print(linear.weight)

    # Xavier初始化:均匀分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.xavier_uniform_(linear.weight)
    print(linear.weight)


if __name__ == "__main__":
    test007()


# 结果
Parameter containing:
tensor([[-0.4838,  0.4121, -0.3171, -0.2214, -0.8666, -0.4340],
        [ 0.1059,  0.6740, -0.1025, -0.1006,  0.5757, -0.1117],
        [ 0.7467, -0.0554, -0.5593, -0.1513, -0.5867, -0.1564],
        [-0.1058,  0.5266,  0.0243, -0.5646, -0.4982, -0.1844]], requires_grad=True)

Parameter containing:
tensor([[-0.5263,  0.3455,  0.6449,  0.2807, -0.3698, -0.6890],
        [ 0.1578, -0.3161, -0.1910, -0.4318, -0.5760,  0.3746],
        [ 0.2017, -0.6320, -0.4060,  0.3903,  0.3103, -0.5881],
        [ 0.6212,  0.3077,  0.0783, -0.6187,  0.3109, -0.6060]], requires_grad=True)

3.4 He初始化

也叫kaiming 初始化。

方法:专门为 ReLU 激活函数设计。权重从以下分布中采样:

优点:适用于 ReLU 和 Leaky ReLU 激活函数。

应用场景:深度网络,尤其是使用 ReLU 激活函数时。

代码演示:

import torch
import torch.nn as nn


def test006():
    # He初始化:正态分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.kaiming_normal_(linear.weight, nonlinearity="relu")
    print(linear.weight)

    # He初始化:均匀分布
    linear = nn.Linear(in_features=6, out_features=4)
    nn.init.kaiming_uniform_(linear.weight, nonlinearity="relu")
    print(linear.weight)


if __name__ == "__main__":
    test006()



# 结果
Parameter containing:
tensor([[ 1.4020,  0.2030,  0.3585, -0.7419,  0.6077,  0.0178],
        [-0.2860, -1.2135,  0.0773, -0.3750, -0.5725,  0.9756],
        [ 0.2938, -0.6159, -1.1721,  0.2093,  0.4212,  0.9079],
        [ 0.2050,  0.3866, -0.3129, -0.3009, -0.6659, -0.2261]], requires_grad=True)

Parameter containing:
tensor([[-0.1924, -0.6155, -0.7438, -0.2796, -0.1671, -0.2979],
        [ 0.7609,  0.9836, -0.0961,  0.7139, -0.8044, -0.3827],
        [ 0.1416,  0.6636,  0.9539,  0.4735, -0.2384, -0.1330],
        [ 0.7254, -0.4056, -0.7621, -0.6139, -0.6093, -0.2577]], requires_grad=True)

四、激活函数

激活函数的作用是在隐藏层引入非线性,使得神经网络能够学习和表示复杂的函数关系,使网络具备非线性能力,增强其表达能力。

4.1 sigmoid

Sigmoid激活函数是一种常见的非线性激活函数,特别是在早期神经网络中应用广泛。它将输入映射到0到1之间的值,因此非常适合处理概率问题。

4.1.1 公式

Sigmoid函数的数学表达式为:

其中,e 是自然常数(约等于2.718),x 是输入。

4.1.2 特征

  1. 将任意实数输入映射到 (0, 1)之间,因此非常适合处理概率场景。
  2. sigmoid函数一般只用于二分类的输出层。
  3. 微分性质: 导数计算比较方便,可以用自身表达式来表示:

4.1.3 缺点

  • 梯度消失:
    • 在输入非常大或非常小时,Sigmoid函数的梯度会变得非常小,接近于0。这导致在反向传播过程中,梯度逐渐衰减。
    • 最终使得早期层的权重更新非常缓慢,进而导致训练速度变慢甚至停滞。
  • 信息丢失:输入100和输入10000经过sigmoid的激活值几乎都是等于 1 的,但是输入的数据却相差 100 倍。
  • 计算成本高: 由于涉及指数运算,Sigmoid的计算比ReLU等函数更复杂,尽管差异并不显著。

 

4.2 tanh 

tanh(双曲正切)是一种常见的非线性激活函数,常用于神经网络的隐藏层。tanh 函数也是一种S形曲线,输出范围为(−1,1)。

4.2.1 公式

tanh数学表达式为:

4.2.2 特征

  1. 输出范围: 将输入映射到(-1, 1)之间,因此输出是零中心的。相比于Sigmoid函数,这种零中心化的输出有助于加速收敛。
  2. 对称性: Tanh函数关于原点对称,因此在输入为0时,输出也为0。这种对称性有助于在训练神经网络时使数据更平衡。
  3. 平滑性: Tanh函数在整个输入范围内都是连续且可微的,这使其非常适合于使用梯度下降法进行优化。

4.2.3 缺点

  1. 梯度消失: 虽然一定程度上改善了梯度消失问题,但在输入值非常大或非常小时导数还是非常小,这在深层网络中仍然是个问题。
  2. 计算成本: 由于涉及指数运算,Tanh的计算成本还是略高,尽管差异不大。

4.3 ReLU

ReLU(Rectified Linear Unit)是深度学习中最常用的激活函数之一,它的全称是修正线性单元。ReLU 激活函数的定义非常简单,但在实践中效果非常好。

4.3.1 公式

ReLU 函数定义如下:

 即ReLU对输入x进行非线性变换:

4.3.2 特征

  1. 计算简单:ReLU 的计算非常简单,只需要对输入进行一次比较运算,这在实际应用中大大加速了神经网络的训练。
  2. ReLU 函数的导数是分段函数:

  3. 缓解梯度消失问题:相比于 Sigmoid 和 Tanh 激活函数,ReLU 在正半区的导数恒为 1,这使得深度神经网络在训练过程中可以更好地传播梯度,不存在饱和问题。
  4. 稀疏激活:ReLU在输入小于等于 0 时输出为 0,这使得 ReLU 可以在神经网络中引入稀疏性(即一些神经元不被激活),这种稀疏性可以提升网络的泛化能力。 

4.3.3 缺点

神经元死亡:由于ReLU在x≤0时输出为0,如果某个神经元输入值是负,那么该神经元将永远不再激活,成为“死亡”神经元。随着训练的进行,网络中可能会出现大量死亡神经元,从而会降低模型的表达能力。

4.4 LeakyReLU

Leaky ReLU是一种对 ReLU 函数的改进,旨在解决 ReLU 的一些缺点,特别是Dying ReLU 问题。Leaky ReLU 通过在输入为负时引入一个小的负斜率来改善这一问题。

4.4.1 公式

Leaky ReLU 函数的定义如下:

其中,\alpha 是一个非常小的常数(如 0.01),它控制负半轴的斜率。这个常数 \alpha是一个超参数,可以在训练过程中可自行进行调整。

 

4.4.2 特征 

  1. 避免神经元死亡:通过在 x<=0 区域引入一个小的负斜率,这样即使输入值小于等于零,Leaky ReLU仍然会有梯度,允许神经元继续更新权重,避免神经元在训练过程中完全“死亡”的问题。
  2. 计算简单:Leaky ReLU 的计算与 ReLU 相似,只需简单的比较和线性运算,计算开销低。

4.4.3 缺点

  1. 参数选择:\alpha 是一个需要调整的超参数,选择合适的\alpha 值可能需要实验和调优。
  2. 出现负激活:如果\alpha 设定得不当,仍然可能导致激活值过低。

4.5 softmax

Softmax激活函数通常用于分类问题的输出层,它能够将网络的输出转换为概率分布,使得输出的各个类别的概率之和为 1。Softmax 特别适合用于多分类问题。

4.5.1 公式

 假设神经网络的输出层有n个节点,每个节点的输出为z_{i},则 Softmax 函数的定义如下:

4.5.2 特征

  1. 将输出转化为概率:通过Softmax,可以将网络的原始输出转化为各个类别的概率,从而可以根据这些概率进行分类决策。

  2. 概率分布:Softmax的输出是一个概率分布,即每个输出值$$\text{Softmax}(z_i)$$都是一个介于0和1之间的数,并且所有输出值的和为 1:

  3. 突出差异:Softmax会放大差异,使得概率最大的类别的输出值更接近1,而其他类别更接近0。

  4. 在实际应用中,Softmax常与交叉熵损失函数Cross-Entropy Loss结合使用,用于多分类问题。在反向传播中,Softmax的导数计算是必需的。

4.5.3 缺点

1、数值不稳定性:在计算过程中,如果z_{i}的数值过大,e^{z_{i}}可能会导致数值溢出。因此在实际应用中,经常会对z_{i}进行调整,如减去最大值以确保数值稳定。

解释:

z_{i}-max(z)是一个非正数,那么e^{z_{i}-max(z)}的值就位于0到1之间,有效避免了数值溢出。

这中调整不会改变Softmax的概率分布结果,因为从数学的角度讲相当于分子、分母都除以了e^{max(z)}。  

2、难以处理大量类别:Softmax在处理类别数非常多的情况下(如大模型中的词汇表)计算开销会较大。

如何选择

隐藏层

  1. 优先选ReLU;
  2. 如果ReLU效果不咋地,那么尝试其他激活,如Leaky ReLU等;
  3. 使用ReLU时注意神经元死亡问题, 避免出现过多神经元死亡;
  4. 不使用sigmoid,尝试使用tanh;

输出层

  1. 二分类问题选择sigmoid激活函数;
  2. 多分类问题选择softmax激活函数;
  3. 回归问题选择identity激活函数;

http://www.kler.cn/a/415830.html

相关文章:

  • 基于snowflake id 的 N 位唯一数字id 生成算法总结
  • 浅谈Java库之‌Guava
  • SQL进阶技巧:如何寻找同一批用户 | 断点分组应用【最新面试题】
  • 【机器学习chp8】统计学习理论
  • 【llamafactory】安装与环境配置
  • 使用 Python 删除视频的某一段并保留其他时间段
  • 技术模板纪要
  • 解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.
  • 如何在谷歌浏览器中使用开发者工具调试网页
  • 004 MATLAB数值微积分
  • [Java]微服务之分布式事务
  • Redis【1】- 如何阅读Redis 源码
  • 3.22决策树,离散值
  • SpringMVC-Day2
  • layui-vue第三方库表格列事件怎么写
  • 人工智能之数学基础:欧式距离及在人工智能领域中的应用
  • 【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(6)
  • 牛客 ZT13 小红的数字删除
  • go每日一题:mock打桩、defer、recovery、panic的调用顺序
  • 【Linux】进程控制-----进程等待wait与waitpid