【深度学习】2、Pytorch自行实现常见的11个激活函数的Fashion Minist项目实践对比(你需要的这里都有了!)(一)

简介: 【深度学习】2、Pytorch自行实现常见的11个激活函数的Fashion Minist项目实践对比(你需要的这里都有了!)(一)

简介


神经网络为什么需要激活函数:首先数据的分布绝大多数是非线性的,而一般神经网络的计算是线性的,引入激活函数,是在神经网络中引入非线性,强化网络的学习能力。所以激活函数的最大特点就是非线性。


   激活函数对神经网络的重要性自不必多言,来自丹麦技术大学的 Casper Hansen 通过公式、图表和代码实验介绍了 Sigmoid、Tanh、ReLU、Softplus、Softmax、ELU 以及更新的 Leaky ReLU、SELU、GELU、Maxout 以及Swish这些激活函数,并比较了它们的优势和短板。


   在计算每一层的激活值时,我们要用到激活函数,之后才能确定这些激活值究竟是多少。根据每一层前面的激活、权重和偏置,我们要为下一层的每个激活计算一个值。但在将该值发送给下一层之前,我们要使用一个激活函数对这个输出进行缩放。本文将介绍不同的激活函数。


1、概述


   激活函数是神经网络中一个至关重要的部分。在这篇长文中,我将全面介绍11种不同的激活函数,并阐述它们各自的优缺点。我会给出激活函数的方程和微分方程,还会给出它们的图示。本文的目标是以简单的术语解释这些方程以及图。


2、Sigmoid 函数


   Sigmoid 函数是一个Logistic函数,意思就是说:不管输入是什么,得到的输出都在0到1之间。也就是说,你输入的每个神经元、节点或激活都会被缩放为一个介于 0到1之间的值。

   sigmoid 这样的函数常被称为非线性函数,因为我们不能用线性的项来描述它。很多激活函数都是非线性或者线性和非线性的组合(有可能函数的一部分是线性的,但这种情况很少见)。


   这基本上没什么问题,但值恰好为 0 或 1 的时候除外(有时候确实会发生这种情况)。为什么这会有问题?


   这个问题与反向传播有关(有关反向传播的介绍请参阅我的前一篇文章)。在反向传播中,我们要计算每个权重的梯度,即针对每个权重的小更新。这样做的目的是优化整个网络中激活值的输出,使其能在输出层得到更好的结果,进而实现对成本函数的优化。


   在反向传播过程中,我们必须计算每个权重影响成本函数(cost function)的比例,具体做法是计算成本函数相对于每个权重的偏导数。假设我们不定义单个的权重,而是将最后一层 L 中的所有权重 w 定义为 w^L,则它们的导数为:

83b586af8f35c4f0ed67b587d66591c3.png

   注意,当求偏导数时,我们要找到 ∂a^L 的方程,然后仅微分 ∂z^L,其余部分保持不变。我们用撇号「'」来表示任意函数的导数。当计算中间项 ∂a^L/∂z^L 的偏导数时,我们有:

08d6998f52f4632710aa78bc8fe42547.png

   则sigmoid 函数的导数就为:

2699db00b728660c01151b39f3f1f907.png

   当我们向这个 sigmoid 函数输入一个很大的x值(正或负)时,我们得到几乎为 0 的y值——也就是说,当我们输入 w×a+b 时,我们可能得到一个接近于 0 的值。


   当 x 是一个很大的值(正或负)时,我们本质上就是用一个几乎为0的值来乘这个偏导数的其余部分。

13666f328a4a0792c511563c7102b5de.png

   如果有太多的权重都有这样很大的值,那么我们根本就没法得到可以调整权重的网络,这可是个大问题。如果我们不调整这些权重,那么网络就只有细微的更新,这样算法就不能随时间给网络带来多少改善。对于针对一个权重的偏导数的每个计算,我们都将其放入一个梯度向量中,而且我们将使用这个梯度向量来更新神经网络。可以想象,如果该梯度向量的所有值都接近 0,那么我们根本就无法真正更新任何东西。

a1648e315ca0df47a3e6ba712b7beb0a.png

   这里描述的就是梯度消失问题。这个问题使得 sigmoid 函数在神经网络中并不实用,我们应该使用后面介绍的其它激活函数。


Sigmoid函数的自定义实现

b90f1c4e90221048a11b74d8ccad563a.png


3、Tanh函数


   tanh为双曲正切函数,其英文读作Hyperbolic Tangent。tanh和 sigmoid 相似,都属于饱和激活函数,区别在于输出值范围由 (0,1) 变为了 (-1,1),可以把 tanh 函数看做是 sigmoid 向下平移和拉伸后的结果。

tanh公式:

c9ca2666053525d0be994c2f69a13c26.png

   从公式中,可以更加清晰看出tanh与sigmoid函数的关系(平移+拉伸)。tanh及其导数曲线:

a18f202cb4fadfc86e29bd14c3593f48.jpg

tanh作为激活函数的特点:

相比Sigmoid函数,

   1、tanh的输出范围时(-1, 1),解决了Sigmoid函数的不是zero-centered输出问题;

   2、幂运算的问题仍然存在;

   3、tanh导数范围在(0, 1)之间,相比sigmoid的(0, 0.25),梯度消失(gradient vanishing)问题会得到缓解,但仍然还会存在。

自定义实现:

b25e6534ce43ed17397424671a907ab7.png


4、梯度问题


4.1、梯度消失问题

更新特定的权重,则更新规则为:

298ad8347485a500e15ae7d2701a441f.png

   但如果偏导数 ∂C/∂w^(L) 很小,如同消失了一般,又该如何呢?这时我们就遇到了梯度消失问题,其中许多权重和偏置只能收到非常小的更新。

   可以看到,如果权重的值为 0.2,则当出现梯度消失问题时,这个值基本不会变化。因为这个权重分别连接了第一层和第二层的首个神经元:

   假设这个权重的值为 0.2,给定一个学习率(具体多少不重要,这里使用了 0.5),则新的权重为:

   这个权重原来的值为 0.2,现在更新为了 0.199999978。很明显,这是有问题的:梯度很小,如同消失了一样,使得神经网络中的权重几乎没有更新。这会导致网络中的节点离其最优值相去甚远。这个问题会严重妨碍神经网络的学习。


人们已经观察到,如果不同层的学习速度不同,那么这个问题还会变得更加严重。层以不同的速度学习,前面几层总是会根据学习率而变得更差。

   在这个示例中,隐藏层 4 的学习速度最快,因为其成本函数仅取决于连接到隐藏层 4 的权重变化。我们看看隐藏层 1;这里的成本函数取决于连接隐藏层 1 与隐藏层 2、3、4 的权重变化。如果你看过了我前一篇文章中关于反向传播的内容,那么你可能知道网络中更前面的层会复用后面层的计算。

同时,如前面介绍的那样,最后一层仅取决于计算偏导时出现的一组变化:

350d227b20222d3730af81546ec857c8.png

   最终,这就是个大问题了,因为现在权重层的学习速度不同。这意味着网络中更后面的层几乎肯定会被网络中更前面的层受到更多优化。而且问题还在于反向传播算法不知道应该向哪个方向传递权重来优化成本函数。


4.2、梯度爆炸问题

   梯度爆炸问题本质上就是梯度消失问题的反面。研究表明,这样的问题是可能出现的,这时权重处于「爆炸」状态,即它们的值快速增长。


我们将遵照以下示例来进行说明:http://neuralnetworksanddeeplearning.com/chap5.html#what's_causing_the_vanishing_gradient_problem_unstable_gradients_in_deep_neural_nets


   注意,这个示例也可用于展示梯度消失问题,而我是从更概念的角度选择了它,以便更轻松地解释。


   本质上讲,当 01 时,我们可能遇到梯度爆炸问题。但是,当一个层遇到这个问题时,必然有更多权重满足梯度消失或爆炸的条件。


   我们从一个简单网络开始。这个网络有少量权重、偏置和激活,而且每一层也只有一个节点。

5a370ee769400b2d51e96468288c13d9.png

   这个网络很简单。权重表示为 w_j,偏置为 b_j,成本函数为 C。节点、神经元或激活表示为圆圈。


   Nielsen 使用了物理学上的常用表示方式 Δ 来描述某个值中的变化(这不同于梯度符号 ∇)。举个例子,Δb_j 描述的是第 j 个偏置的值变化。

4b155ea55e890c678e47cd6ba57daea6.png

通过下式衡量变化率:

2565b6e214ecf884377f6c98ff95f574.png

   下面式子的论据和上面的偏导一样。即我们如何通过偏置的变化率来衡量成本函数的变化率?正如刚才介绍的那样,Nielsen 使用Δ来描述变化,因此我们可以说这个偏导能大致通过Δ来替代:

95a5dbad011b3641623dba2cf161a8db.png

   先从网络的起点开始,计算第一个偏置 b_1 中的变化将如何影响网络。因为我们知道,在上一篇文章中,第一个偏置 b_1 会馈入第一个激活 a_1,我们就从这里开始。我们先回顾一下这个等式:

bfdff85af5a7be2e65f0f18492fbe394.png

   如果 b_1 改变,我们将这个改变量表示为 Δb_1。因此,我们注意到当 b_1改变时,激活a_1也会改变——我们通常将其表示为 ∂a_1/∂b_1。


   因此,我们左边有偏导的表达式,这是 b_1中与 a_1 相关的变化。但我们开始替换左边的项,先用 z_1 的 sigmoid 替换a_1:

   上式表示当 b_1 变化时,激活值 a_1 中存在某个变化。我们将这个变化描述为 Δa_1。

   我们将变化 Δa_1 看作是与激活值 a_1 中的变化加上变化 Δb_1 近似一样。

8572ed4982dcbfa165158b750dbe9569.png

   这里我们跳过了一步,但本质上讲,我们只是计算了偏导数,并用偏导的结果替代了分数部分。a_1 的变化导致 z_2 的变化所描述的变化 Δa_1 现在会导致下一层的输入 z_2 出现变化。

06a577d7cd74a2bca26b8e2877398feb.png

表示方式和前面一样,我们将下一个变化记为 Δz_2。我们又要再次经历前面的过程,只是这次要得到的是 z_2 中的变化:

cfea8302cf5ae6c2ddf01d9c71ecd023.png

可以使用下式替代 Δa_1:

e05e4f778caf7e9f226c72bd1bf854ef.png

   计算这个式子。希望你清楚地明白到这一步的过程——这与计算 Δa_1 的过程一样。


   这个过程会不断重复,直到我们计算完整个网络。通过替换 Δa_j 值,我们得到一个最终函数,其计算的是成本函数中与整个网络(即所有权重、偏置和激活)相关的变化。

7fe6ee9d8cfac6d9571dee05fbf91402.png

基于此,我们再计算 ∂C/∂b_1,得到我们需要的最终式:

79fbdb46a6479a93c5495ca8b23e8382.png


4.3、梯度爆炸的极端案例

   据此,如果所有权重 w_j 都很大,即如果很多权重的值大于 1,我们就会开始乘以较大的值。举个例子,所有权重都有一些非常高的值,比如 100,而我们得到一些在 0 到 0.25 之间、sigmoid 函数导数的随机输出:

5120847c58f56df2b9fc26042ec3d914.png

可以合理地相信这会远大于1,但为了方便示例展示,我们将其设为 1。

f0c29844f19c18ee5b26a051c03ed08f.png

使用这个更新规则,如果我们假设 b_1 之前等于 1.56,而学习率等于 0.5。

5a2dbbf375267e3226142098182a526f.png

尽管这是一个极端案例,但你懂我的意思。权重和偏置的值可能会爆发式地增大,进而导致整个网络爆炸。

c0eb50838f0907ee5558ca7388822425.png

   现在花点时间想想网络的权重和偏置以及激活的其它部分,爆炸式地更新它们的值。这就是我们所说的梯度爆炸问题。很显然,这样的网络学不到什么东西,因此这会完全毁掉你想要解决的任务。


4.4、避免梯度爆炸:梯度裁剪/规范

   解决梯度爆炸问题的基本思路就是为其设定一个规则。这部分我不会深入进行数学解释,但我会给出这个过程的步骤:

   选取一个阈值——如果梯度超过这个值,则使用梯度裁剪或梯度规范;


   定义是否使用梯度裁剪或规范。如果使用梯度裁剪,你就指定一个阈值,比如 0.5。如果这个梯度值超过 0.5 或 -0.5,则要么通过梯度规范化将其缩放到阈值范围内,要么就将其裁剪到阈值范围内。


    但是要注意,这些梯度方法都不能避免梯度消失问题。所以我们还将进一步探索解决这个问题的更多方法。通常而言,如果你在使用循环神经网络架构(比如 LSTM 或 GRU),那么你就需要这些方法,因为这种架构常出现梯度爆炸的情况

相关文章
|
2月前
|
机器学习/深度学习 传感器 数据采集
深度学习在故障检测中的应用:从理论到实践
深度学习在故障检测中的应用:从理论到实践
185 6
|
28天前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch FlexAttention技术实践:基于BlockMask实现因果注意力与变长序列处理
本文介绍了如何使用PyTorch 2.5及以上版本中的FlexAttention和BlockMask功能,实现因果注意力机制与填充输入的处理。通过attention-gym仓库安装相关工具,并详细展示了MultiheadFlexAttention类的实现,包括前向传播函数、因果掩码和填充掩码的生成方法。实验设置部分演示了如何组合这两种掩码并应用于多头注意力模块,最终通过可视化工具验证了实现的正确性。该方法适用于处理变长序列和屏蔽未来信息的任务。
72 17
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
揭秘人工智能:深度学习的奥秘与实践
在本文中,我们将深入浅出地探索深度学习的神秘面纱。从基础概念到实际应用,你将获得一份简明扼要的指南,助你理解并运用这一前沿技术。我们避开复杂的数学公式和冗长的论述,以直观的方式呈现深度学习的核心原理和应用实例。无论你是技术新手还是有经验的开发者,这篇文章都将为你打开一扇通往人工智能新世界的大门。
|
2月前
|
机器学习/深度学习 算法 TensorFlow
深度学习中的自编码器:从理论到实践
在这篇文章中,我们将深入探讨深度学习的一个重要分支——自编码器。自编码器是一种无监督学习算法,它可以学习数据的有效表示。我们将首先介绍自编码器的基本概念和工作原理,然后通过一个简单的Python代码示例来展示如何实现一个基本的自编码器。最后,我们将讨论自编码器的一些变体,如稀疏自编码器和降噪自编码器,以及它们在实际应用中的优势。
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
揭秘AI:深度学习的奥秘与实践
本文将深入浅出地探讨人工智能中的一个重要分支——深度学习。我们将从基础概念出发,逐步揭示深度学习的原理和工作机制。通过生动的比喻和实际代码示例,本文旨在帮助初学者理解并应用深度学习技术,开启AI之旅。
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
深入浅出深度学习:从理论到实践的探索之旅
在人工智能的璀璨星空中,深度学习如同一颗耀眼的新星,以其强大的数据处理能力引领着技术革新的浪潮。本文将带您走进深度学习的核心概念,揭示其背后的数学原理,并通过实际案例展示如何应用深度学习模型解决现实世界的问题。无论您是初学者还是有一定基础的开发者,这篇文章都将为您提供宝贵的知识和启发。
65 5
|
2月前
|
机器学习/深度学习 存储 人工智能
探索深度学习的奥秘:从理论到实践的技术感悟
本文深入探讨了深度学习技术的核心原理、发展历程以及在实际应用中的体验与挑战。不同于常规摘要,本文旨在通过作者个人的技术实践经历,为读者揭示深度学习领域的复杂性与魅力,同时提供一些实用的技术见解和解决策略。
50 0
|
3月前
|
机器学习/深度学习 自然语言处理 算法
深度学习在图像识别中的应用及实践
本文将探讨深度学习在图像识别领域的应用,并分享一个使用Python和Keras库实现的简单代码示例。我们将介绍深度学习的原理、常用模型以及如何在实际应用中解决问题。通过阅读本文,您将了解深度学习在图像识别中的潜力,并学会如何构建一个简单的神经网络模型。
69 0
|
4天前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现传统CTR模型WideDeep网络
本文介绍了如何在昇腾平台上使用PyTorch实现经典的WideDeep网络模型,以处理推荐系统中的点击率(CTR)预测问题。
149 65
|
4月前
|
算法 PyTorch 算法框架/工具
Pytorch学习笔记(九):Pytorch模型的FLOPs、模型参数量等信息输出(torchstat、thop、ptflops、torchsummary)
本文介绍了如何使用torchstat、thop、ptflops和torchsummary等工具来计算Pytorch模型的FLOPs、模型参数量等信息。
557 2

热门文章

最新文章