sheng的学习笔记-AI基础-激活函数

ai目录:sheng的学习笔记-AI目录-优快云博客

目录

Sigmoid

Tanh 函数

ReLU(Rectified Linear Unit)函数 

Leaky ReLU

ELU(Exponential Linear Unit)

SEIU

Swish

激活函数的选择

激活函数和初始化关联

初始化

keras常见的初始化方法

原理:

Glorot

LeCun

公式内容

glorot_normal(正态化的Glorot)

glorot_uniform(标准化的Glorot初始化)

he_uniform(标准化化的he)

lecun_normal(正态化的lecun)

lecun_uniform(标准化的lecun)

截断正态分布 -- truncated_normal

标准正态分布——random_normal

random_uniform(随机均匀分布):

用initializers初始化参数

自定义方式初始化参数


激活函数(Activation Function) 是神经网络中的一个关键组件,负责将输入的线性组合转化为非线性输出。它赋予神经网络模型以复杂的表达能力,使其能够处理非线性问题,比如分类、图像识别和自然语言处理等任务。

Sigmoid

Sigmoid 函数是深度学习中最早广泛使用的激活函数之一,它将输入值映射到 ( 0 , 1 )  的区间,输出为一个概率值。其公式为:

特点:输出值在 0到1之间,因此常用于二分类问题。
缺点:梯度消失问题,在输入值较大或较小时,Sigmoid 函数的梯度(导数)接近零,这会导致反向传播过程中梯度逐渐减小(消失),影响权重的更新,特别是在深层网络中。
图示

Tanh 函数

Tanh(双曲正切函数)是 Sigmoid 的扩展版本,输出范围为 ( − 1 , 1 ) ,可以解决 Sigmoid 在输出上的偏移问题。其公式为

特点:输出范围为 (-1, 1),相比 Sigmoid 更加居中,能够减少偏移(mean shift)问题。
缺点:同样存在梯度消失问题,在输入值非常大或非常小时,Tanh 的梯度依然会变得很小。
图示:

ReLU(Rectified Linear Unit)函数 

ReLU 是目前使用最为广泛的激活函数之一。ReLU 函数的输出在正数区域保持线性,在负数区域则为 0。其公式为:

特点:当输入大于 0 时,ReLU 直接输出输入值;当输入小于 0 时,输出为 0。
优点
解决梯度消失问题:ReLU 的梯度为 1(当 x > 0 x > 0x>0 时),不会像 Sigmoid 和 Tanh 那样使梯度变小,从而有效缓解梯度消失问题。
计算效率高:ReLU 计算非常简单,只需要一个最大值操作,非常适合在深层网络中使用。
缺点:死亡 ReLU 问题,当输入的值小于 0 时,ReLU 的输出一直为 0,这意味着神经元可能会永远不再激活,这在某些情况下会导致网络性能下降。

Leaky ReLU

Leaky ReLU 是对 ReLU 的一种改进,解决了 ReLU 在负数区域输出为 0 时神经元“死亡”的问题。Leaky ReLU 在负数区域给予一个很小的正数斜率 α (通常为 0.01)而不是完全为 0,其公式为:

优点:在负数区域仍然保持一个小的斜率,使得神经元不完全失活。减少了 ReLU 函数中的死亡 ReLU 问题,确保神经元即使在负值输入时也能有一定的梯度更新。

ELU(Exponential Linear Unit)

ELU 是另一种改进的 ReLU 激活函数,在负数区域使用指数函数进行平滑。其公式为:

其中 α 是一个超参数,通常取值为 1。

  • 特点:在正数区域与 ReLU 类似,但在负数区域使用指数函数进行平滑,避免了死亡 ReLU 问题。
  • 优点:与 Leaky ReLU 相比,ELU 在负数区域提供的平滑曲线可以在一定程度上减少偏差。
  • 缺点:计算量比 ReLU 稍大,因为负数区域的计算涉及指数运算。

SEIU

是ELU激活函数的可扩展变体,如果你构建一个仅由密集层堆叠组成的神经网络,并且如果所有隐藏层都使用SELU激活函数,则该网络是自归一化的:每层的输出倾向于在训练过程中保留平均值0和标准差1,从而解决了梯度消失/梯度爆炸的问题。

SELU激活函数通常大大优于这些神经网络(尤其是深层神经网络)的其他激活函数。但是,有一些产生自归一化的条件

  • ·输入特征必须是标准化的(平均值为0,标准差为1)​。
  • ·每个隐藏层的权重必须使用LeCun正态初始化。在Keras中,这意味着设置kernel_initializer="lecun_normal"。·
  • 网络的架构必须是顺序的。不幸的是,如果你尝试在非顺序架构(例如循环网络)中使用SELU(见第15章)或具有跳过连接的网络(即在Wide&Deep网络中跳过层的连接)​,将无法保证自归一化,因此SELU不一定会胜过其他激活函数。

Swish

Swish 是一种新的激活函数,由 Google 提出,它结合了 ReLU 和 Sigmoid 的优势。其公式为

特点:Swish 在小于 0 的输入值时逐渐趋近于 0,而在大于 0 时逐渐增大,因此它在负值区域不会像 ReLU 那样硬性截断。
优点:Swish 的非线性变化更加平滑,能够捕获更多的复杂模式,特别适合用于深度神经网络中。
缺点:计算量比 ReLU 更大,因为它涉及 Sigmoid 的计算。

激活函数的选择

神经网络中的激活函数选择取决于具体任务和网络结构。以下是一些常见的经验法则:

  • ReLU 是目前最常用的激活函数,特别是在卷积神经网络(CNN)和全连接网络(FCN)中表现优异。对于大多数深度网络,ReLU 是一个很好的起点,因为它能有效避免梯度消失问题。
  • Leaky ReLU 和 ELU 是 ReLU 的改进版本,适合于有负输入的场景或避免神经元失活的场景。
  • Sigmoid 和 Tanh 适用于一些特殊情况,特别是在需要输出概率或对称输出的情况下(例如,输出为 [-1, 1])。不过它们通常会导致梯度消失,因此不推荐用于深层网络。
  • Swish 是一种更平滑的激活函数,在某些复杂任务(如超深网络)上可能表现优异。

通常SELU>ELU>leaky ReLU(及其变体)>ReLU>tanh>logistic

  • 如果网络的架构不能自归一化,那么ELU的性能可能会优于SELU(因为SELU在z=0时不平滑)​。
  • 如果你非常关心运行时延迟,那么你可能更喜欢leaky ReLU。
  • 如果你不想调整其他超参数,则可以使用Keras使用的默认α值(例如,leaky ReLU为0.3)​。

如果你有空闲时间和计算能力,则可以使用交叉验证来评估其他激活函数,例如,如果网络过拟合,则为RReLU;如果你的训练集很大,则为PReLU。也就是说,由于ReLU是迄今为止最常用的激活函数,因此许多库和硬件加速器都提供了ReLU特定的优化。因此,如果你将速度放在首位,那么ReLU可能仍然是最佳选择。

激活函数和初始化关联

初始化

keras常见的初始化方法

初始化方法参数
正态化的Glorot初始化 glorot_normal
标准化的Glorot初始化glorot_uniform
正态化的he初始化 he_normal
标准化的he初始化he_uniform
正态化的lecun初始化lecun_normal
标准化的lecun初始化 lecun_uniform
截断正态分布truncated_normal
标准正态分布random_normal
均匀分布random_uniform

原理:

能显著缓解不稳定梯度问题的方法:

需要信号在两个方向上正确流动:进行预测时,信号为正向;在反向传播梯度时,信号为反向。既不希望信号消失,也不希望它爆炸并饱和

必须按照公式11-1中所述的随机初始化每层的连接权重,其中

其中in和out代表该层的输入和神经元(这些数字称为该层的扇入和扇出)​, 

Glorot

LeCun

公式11-1中,用fan in替换fan avg,就是LeCun,当fanin=fanout时,LeCun初始化等效于Glorot初始化

公式内容

首先编写一个简单模型,并初始化其参数,然后 get_weights 并 plot 查看初始化参数的分布,这里接受 initial 参数并传给参数初始化,可以把上述常见初始化方法直接传入函数即可。这里 Dense 层 kernel 参数共有 50000 x 100 = 5000000 个:

    def getDenseWeights(initial):
        inputs = layers.Input(shape=(100,), name='input')
        d1 = layers.Dense(50000, activation='sigmoid', name='dense1',kernel_initializer=initial)(inputs)
        output = layers.Dense(7, activation='sigmoid', name='output')(d1)
        model = keras.Model(inputs=inputs, outputs=output)
        # 100 x 500
        w_dense1 = np.array(model.get_layer('dense1').get_weights()[0]).reshape(-1) # 获取dense1层的参数
        n, bins, patches = plt.hist(w_dense1,bins=1000)
        plt.title(initial)
        plt.xlabel('data range')
        plt.ylabel('probability')
        plt.show()

直接输入上述初始化方法名称即可: 

    getDenseWeights("glorot_normal")

glorot_normal(正态化的Glorot)

keras.initializers.glorot_normal(seed=None)

Glorot 正态分布初始化器,也称为 Xavier 正态分布初始化器。

它从以 0 为中心,标准差为 stddev = sqrt(2 / (fan_in + fan_out)) 的截断正态分布中抽取样本, 其中 fan_in 是权值张量中的输入单位的数量, fan_out 是权值张量中的输出单位的数量。

glorot_uniform(标准化的Glorot初始化)

keras.initializers.glorot_uniform(seed=None)

Glorot 均匀分布初始化器,也称为 Xavier 均匀分布初始化器。

它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit 是 sqrt(6 / (fan_in + fan_out)), fan_in 是权值张量中的输入单位的数量, fan_out 是权值张量中的输出单位的数量。

he_normal(正态化的he

  • 这种初始化方法由 He 等人在 2015 年提出,主要用于ReLU激活函数的网络中。
  • 权重被初始化为均值为0,标准差为sqrt(2 / fan_in) 的正态分布,其中 fan_in 是权重矩阵的输入维度。
  • 这种初始化方法有助于在ReLU激活下保持输入和输出的方差一致,从而减少梯度消失或爆炸的问题。

keras.initializers.he_normal(seed=None)

He 正态分布初始化器。它从以 0 为中心,标准差为 stddev = sqrt(2 / fan_in) 的截断正态分布中抽取样本, 其中 fan_in 是权值张量中的输入单位的数量。

 

he_uniform(标准化化的he)

keras.initializers.he_uniform(seed=None)

He 均匀方差缩放初始化器。

它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit 是 sqrt(6 / fan_in), 其中 fan_in 是权值张量中的输入单位的数量。

lecun_normal(正态化的lecun)

keras.initializers.lecun_normal(seed=None)

LeCun 正态分布初始化器。

它从以 0 为中心,标准差为 stddev = sqrt(1 / fan_in) 的截断正态分布中抽取样本, 其中 fan_in 是权值张量中的输入单位的数量。

lecun_uniform(标准化的lecun)

keras.initializers.lecun_uniform(seed=None)

LeCun 均匀初始化器。

它从 [-limit,limit] 中的均匀分布中抽取样本, 其中 limit 是 sqrt(3 / fan_in), fan_in 是权值张量中的输入单位的数量。

截断正态分布 -- truncated_normal

keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)

这个初始化方法是 tensorflow 的默认初始化方法,按照截尾正态分布生成随机张量的初始化器。

生成的随机值与 RandomNormal 生成的类似,但是在距离平均值两个标准差之外的随机值将被丢弃并重新生成。这是用来生成神经网络权重和滤波器的推荐初始化器。

参数

  • mean: 一个 Python 标量或者一个标量张量。要生成的随机值的平均数。
  • stddev: 一个 Python 标量或者一个标量张量。要生成的随机值的标准差。
  • seed: 一个 Python 整数。用于设置随机数种子。

标准正态分布——random_normal

keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)

标准正太分布

参数

  • mean: 一个 Python 标量或者一个标量张量。要生成的随机值的平均数。
  • stddev: 一个 Python 标量或者一个标量张量。要生成的随机值的标准差。
  • seed: 一个 Python 整数。用于设置随机数种子。

random_uniform(随机均匀分布)

  • 这种初始化方法将权重初始化为在 [-0.05, 0.05] 区间内均匀分布的随机值。
  • 均匀分布的初始化方法简单直观,但可能不如正态分布那样有助于保持网络各层的激活值方差一致。

keras.initializers.RandomUniform(minval=-0.05, maxval=0.05, seed=None)

  • minval: 一个 Python 标量或者一个标量张量。要生成的随机值的范围下限。
  • maxval: 一个 Python 标量或者一个标量张量。要生成的随机值的范围下限。默认为浮点类型的 1。
  • seed: 一个 Python 整数。用于设置随机数种子。

用initializers初始化参数

上面展示的初始化方法都使用了默认的函数名传入,无法控制 mean, std, limit 等参数,如果想要输入非默认的参数,可以采用如下形式,以 mean = 5 ,std = 3 的标准正态分布为例:

init = keras.initializers.RandomNormal(mean=5, stddev=3, seed=None)
 
def getDenseWeights(init):
    inputs = layers.Input(shape=(100,), name='input')
    d1 = layers.Dense(50000, activation='sigmoid', name='dense1',kernel_initializer=init)(inputs)
    output = layers.Dense(7, activation='sigmoid', name='output')(d1)
    model = keras.Model(inputs=inputs, outputs=output)

参数换成对应的 initializers 

自定义方式初始化参数

除了使用Api给出的方法外,也可以调用其他方法,自定义参数。自定义参数需要遵循如下条件,如果传递一个自定义的可调用函数,那么它必须使用参数 shape(需要初始化的变量的尺寸)和 dtype(数据类型):

    def api_init(shape, dtype=None):
        return K.random_normal(shape, dtype=dtype)

把 api_init 传给 getDenseWeights 即可。

参考文章

【AI知识点】激活函数(Activation Function)-优快云博客

机器学习实战:基于Scikit-Learn、Keras和TensorFlow  书,封皮是个蜥蜴

深度学习 - 3.TF x Keras 常见参数初始化方法_深度学习 参数怎么生成的-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值