神经网络的激活函数

05-13 1890阅读

神经网络的激活函数

目录

神经网络 

激活函数 

sigmoid 激活函数

tanh 激活函数

backward方法 

relu 激活函数 

softmax 激活函数


神经网络 

人工神经网络( Artificial Neural Network, 简写为ANN)也简称为神经网络(NN),是一种模仿生物神经网络结构和功能的 计算模型。人脑可以看做是一个生物神经网络,由众多的神经元连接而成。各个神经元传递复杂的电信号,树突接收到输入信号,然后对信号进行处理,通过轴突输出信号。

神经网络的激活函数

人工神经网络

神经网络的激活函数

每一个神经元都是=g(w1x1 + w2x2 + w3x3...) ,即先对输入求和,再对其激活

💎这个流程就像,来源不同树突(树突都会有不同的权重)的信息, 进行的加权计算, 输入到细胞中做加和,再通过激活函数输出细胞值。我们使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个强度 w,机器学习的目的就是求这些 w 值。

神经网络的激活函数

  • 输入层: 即输入 x 的那一层
  • 输出层: 即输出 y 的那一层
  • 隐藏层: 输入层和输出层之间都是隐藏层

    激活函数 

    💎激活函数用于对每层的输出数据进行变换, 进而为整个网络结构结构注入了非线性因素。此时, 神经网络就可以拟合各种曲线。如果不使用激活函数,整个网络虽然看起来复杂,其本质还相当于一种线性模型。

    假设有一个单层的神经网络,其输入为𝑥x,权重为𝑤w,偏置为𝑏b,那么该层的输出𝑦y可以表示为:𝑦=𝑤⋅𝑥+𝑏y=w⋅x+b

    对于多层的神经网络,如果每一层都不使用激活函数,那么无论网络有多少层,最终的输出都可以表示为输入𝑥x的一个线性组合 y=wn​⋅(wn−1​⋅(…(w2​⋅(w1​⋅x+b1​)+b2​)…)+bn−1​)+bn​

    通过给网络输出增加激活函数, 实现引入非线性因素, 使得网络模型可以逼近任意函数。

    激活函数能够向神经网络引入非线性因素,使得网络可以拟合各种曲线。没有激活函数时,无论神经网络有多少层,其输出都是输入的线性组合,这样的网络称为感知机,它只能解决线性可分问题,无法处理非线性问题。 

    增加激活函数之后, 对于线性不可分的场景,神经网络的拟合能力更强:

    神经网络的激活函数

    🔎我们可以发现如果只使用线性函数Lnear,则模型永远不会区分两种小球(不管多少次Epochs)

    神经网络的激活函数

    🔎但当我们引入非线性激活函数后,仅仅100次就可以完美区分两种小球。

    激活函数主要用来向神经网络中加入非线性因素,以解决线性模型表达能力不足的问题,它对神经网络有着极其重要的作用。我们的网络参数在更新时,使用的反向传播算法(BP),这就要求我们的激活函数必须可微。

    sigmoid 激活函数

    f(x) = 1 / (1 + e^(-x))。

    神经网络的激活函数

    Sigmoid函数,也称为逻辑斯蒂激活函数,是早期神经网络中最常用的激活函数之一。它的特点是能够将任何实数值映射到介于0和1之间的值,这使得它在二分类问题中尤其有用,可以将输出解释为概率或者激活程度。

    这个函数的图形呈现出一个S形曲线,它在中心点(x=0)增长缓慢,而在两端则增长迅速接近水平。这种特性使得Sigmoid函数在早期的神经网络中非常受欢迎,因为它可以帮助网络学习非线性关系。然而,它也存在梯度消失的问题,这意味着在训练过程中,当输入值非常大或非常小的时候,梯度几乎为零,这会导致权重更新变得非常缓慢,从而影响网络的学习效率。 

    一般来说, sigmoid 网络在 5 层之内就会产生梯度消失现象。而且,该激活函数并不是以 0 为中心的,所以在实践中这种激活函数使用的很少。sigmoid函数一般只用于二分类的输出层。

     📀绘制Sigmoid函数图像

    import torch
    import matplotlib.pyplot as plt
    import torch.nn.functional as F
    def test():
        _, axes = plt.subplots(1, 2)
        
        x = torch.linspace(-20, 20, 1000)
        y = F.tanh(x)
        axes[0].plot(x, y)
        axes[0].grid()
        axes[0].set_title('Sigmoid 函数图像')
        
        x = torch.linspace(-20, 20, 1000, requires_grad=True)
        torch.sigmoid(x).sum().backward()
        axes[1].plot(x.detach(), x.grad)
        axes[1].grid()
        axes[1].set_title('Sigmoid 导数图像')
        plt.show()
    if __name__ == '__main__':
        test()

    📀在神经网络中,一个神经元的输出可以通过Sigmoid函数来表示其被激活的概率,接近1的值表示高度激活,而接近0的值则表示低激活。这种特性使得Sigmoid函数特别适合用于二分类问题的输出层,因为它可以表示两个类别的概率分布。

    tanh 激活函数

    神经网络的激活函数

    Tanh 的函数图像、导数图像 :

    神经网络的激活函数

    Tanh 函数将输入映射到 (-1, 1) 之间,图像以 0 为中心,在 0 点对称,当输入 大概3 时将被映射为 -1 或者 1。与 Sigmoid 相比,它是以 0 为中心的,使得其收敛速度要比 Sigmoid 快,减少迭代次数。然而,从图中可以看出,Tanh 两侧的导数也为 0,同样会造成梯度消失。 

    • 💡由于tanh函数的输出均值是0,这与许多样本数据的分布均值相近,因此在训练过程中,权重和偏差的更新可以更快地接近最优值。
    • 💡tanh函数的导数在0到1之间变化,而Sigmoid函数的导数最大值仅为0.25,这意味着在反向传播过程中,tanh函数能够提供相对较大的梯度,从而减缓梯度消失的问题,有助于网络更快地收敛。 
    • 💡由于tanh函数的对称性和输出范围,它在正向传播时能够更好地处理正负输入值,这有助于在反向传播时进行更有效的权重更新,减少迭代次数。
      import torch
      import matplotlib.pyplot as plt
      import torch.nn.functional as F
      def test():
          _, axes = plt.subplots(1, 2)
          # 函数图像
          x = torch.linspace(-20, 20, 1000)
          y = F.tanh(x)
          axes[0].plot(x, y)
          axes[0].grid()
          axes[0].set_title('Tanh 函数图像')
          # 导数图像
          x = torch.linspace(-20, 20, 1000, requires_grad=True)
          F.tanh(x).sum().backward()
          axes[1].plot(x.detach(), x.grad)
          axes[1].grid()
          axes[1].set_title('Tanh 导数图像')
          plt.show()

      🔎F.tanh(x)计算了输入张量x的tanh值,然后.sum()将这些tanh值相加得到一个标量值。接下来,.backward()方法会计算这个标量值关于输入张量x的梯度,即tanh函数的导数。这样,我们就可以得到tanh函数在每个输入点上的导数值,从而绘制出tanh导数图像。

      backward方法 

      • 通用性:backward()方法不限于计算损失函数的梯度,它可以用于任何需要进行梯度计算的张量。例如,如果你在进行一些非神经网络的任务,比如简单的数学运算,你也可以使用backward()来计算梯度。
      • 要使用backward()计算梯度,必须满足几个条件。首先,需要计算梯度的张量必须是叶子节点,即它们不是任何其他张量的计算结果。其次,这些张量必须设置requires_grad=True以表明需要跟踪它们的梯度。最后,所有依赖于这些叶子节点的张量也必须设置requires_grad=True,以确保梯度可以传播到整个计算图中。

        relu 激活函数 

        ReLU激活函数的公式是 ReLU(x)=max(0, x)。

        ReLU激活函数(Rectified Linear Unit)在神经网络中用于引入非线性特性,其特点是计算简单且能够加速训练过程。对于正值,它直接输出输入值(即 𝑓(𝑥)=𝑥f(x)=x),对于负值,输出为零(即 𝑓(𝑥)=0f(x)=0)。这种简单的阈值操作避免了复杂的指数或乘法运算,从而显著减少了计算量。

        由于ReLU在正值区间内具有不变的梯度(即梯度为1),它有助于维持信号的传播,使得基于梯度的优化算法(如SGD、Adam等)能够更有效地更新网络权重。 

        函数图像如下: 

        神经网络的激活函数

        ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新。 

        与sigmoid相比,RELU的优势是:

        采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。 sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。 Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

        在神经网络的前向传播过程中,每个隐藏层的神经元都会对其输入执行线性变换(通过权重和偏差),然后应用激活函数。例如,一个神经元的输出y可以通过以下方式计算 y=ReLU(W^Tx+b),其中W是权重矩阵,x是输入向量,b是偏置项。 

        在前向传播后,如果输出与实际值存在差距,则使用反向传播算法根据误差来更新网络中的权重和偏差。这个过程中,ReLU函数的梯度(导数)也会被计算出来,用于调整连接权重。

        softmax 激活函数

        神经网络的激活函数

        这里,( K ) 是类别的总数,( e ) 是自然对数的底数(约等于2.71828)。 

        softmax用于多分类过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。 SoftMax 函数将每个输入元素 ( z_i ) 映射到 (0,1) 区间内,并且所有输出值的总和为1,这使它成为一个有效的概率分布。

        Softmax 直白来说就是将网络输出的 logits 通过 softmax 函数,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)节点,作为我们的预测目标类别。 

        import torch
        scores = torch.tensor([0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75])
        probabilities = torch.softmax(scores, dim=0)
        print(probabilities)
        # 结果:tensor([0.0212, 0.0177, 0.0202, 0.0202, 0.0638, 0.0287, 0.0185, 0.0522, 0.0183,
                0.7392])

        神经网络的激活函数

        🍳对于隐藏层:

        1. 优先选择RELU激活函数

        2. 如果ReLu效果不好,那么尝试其他激活,如Leaky ReLu等。

        3. 如果你使用了Relu, 需要注意一下Dead Relu问题, 避免出现大的梯度从而导致过多的神经元死亡。

        4. 不要使用sigmoid激活函数,可以尝试使用tanh激活函数

        🍳对于输出层:

        1. 二分类问题选择sigmoid激活函数

        2. 多分类问题选择softmax激活函数

        3. 回归问题选择identity激活函数

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]