5、整流线性单元(ReLU)
整流线性单元是我们解决梯度消失问题的方法,但这是否会导致其它问题呢?请往下看。ReLU 的公式如下:
ReLU 公式表明:如果输入 x 小于 0,则令输出等于 0;如果输入 x 大于 0,则令输出等于输入。
尽管我们没法用大多数工具绘制其图形,但你可以这样用图解释 ReLU。x 值小于零的一切都映射为 0 的 y 值,但 x 值大于零的一切都映射为它本身。也就是说,如果我们输入 x=1,我们得到 y=1。
这很好,但这与梯度消失问题有什么关系?首先,我们必须得到其微分方程:
其意思是:如果输入 x 大于 0,则输出等于 1;如果输入小于或等于 0,则输出变为 0。用下图表示:
现在我们得到了答案:当使用 ReLU 激活函数时,我们不会得到非常小的值(比如前面sigmoid函数的 0.0000000438)。相反,它要么是0(导致某些梯度不返回任何东西),要么是 1。但这又催生出另一个问题:死亡 ReLU 问题。
如果在计算梯度时有太多值都低于0会怎样呢?我们会得到相当多不会更新的权重和偏置,因为其更新的量为 0。要了解这个过程的实际表现,我们反向地看看前面梯度爆炸的示例。
我们在这个等式中将ReLU 记为R,我们只需要将每个 sigmoidσ 替换成 R:
现在,假如说这个微分后的 ReLU 的一个随机输入 z 小于 0——则这个函数会导致偏置「死亡」。假设是 R'(z_3)=0:
反过来,当我们得到 R'(z_3)=0 时,与其它值相乘自然也只能得到 0,这会导致这个偏置死亡。我们知道一个偏置的新值是该偏置减去学习率减去梯度,这意味着我们得到的更新为 0。
ReLU自定义如下:
6、死亡 ReLU:优势和缺点
当我们将 ReLU 函数引入神经网络时,我们也引入了很大的稀疏性。那么稀疏性这个术语究竟是什么意思?
稀疏:数量少,通常分散在很大的区域。在神经网络中,这意味着激活的矩阵含有许多 0。这种稀疏性能让我们得到什么?当某个比例(比如 50%)的激活饱和时,我们就称这个神经网络是稀疏的。这能提升时间和空间复杂度方面的效率——常数值(通常)所需空间更少,计算成本也更低。
Yoshua Bengio 等人发现 ReLU 这种分量实际上能让神经网络表现更好,而且还有前面提到的时间和空间方面的效率。论文地址:https://www.utc.fr/~bordesan/dokuwiki/_media/en/glorot10nipsworkshop.pdf
torch.nn.ReLU(inplace=False)
torch.nn.ReLU6(inplace=False)
优点:相比于 sigmoid,由于稀疏性,时间和空间复杂度更低;不涉及成本更高的指数运算;能避免梯度消失问题。
缺点:引入了死亡 ReLU 问题,即网络的大部分分量都永远不会更新。但这有时候也是一个优势;ReLU 不能避免梯度爆炸问题。
7、Softplus函数
Softplus函数是Logistic-Sigmoid函数原函数。
加了1是为了保证非负性。Softplus可以看作是强制非负校正函数max(0,x)平滑版本。红色的即为ReLU。
softplus可以看作是ReLu的平滑。根据神经科学家的相关研究,softplus和ReLu与脑神经元激活频率函数有神似的地方。也就是说,相比于早期的激活函数,softplus和ReLu更加接近脑神经元的激活模型,而神经网络正是基于脑神经科学发展而来,这两个激活函数的应用促成了神经网络研究的新浪潮。
Softplus自定义实现如下:
8、指数线性单元(ELU)
指数线性单元激活函数解决了 ReLU 的一些问题,同时也保留了一些好的方面。这种激活函数要选取一个 α 值;常见的取值是在 0.1 到 0.3 之间。
如果你数学不好,ELU 的公式看起来会有些难以理解:
如果你输入的 x值大于0,则结果与 ReLU 一样——即 y 值等于 x 值;但如果输入的 x 值小于 0,则我们会得到一个稍微小于 0 的值。
所得到的 y 值取决于输入的 x 值,但还要兼顾参数 α——可以根据需要来调整这个参数。更进一步,我们引入了指数运算 e^x,因此 ELU 的计算成本比 ReLU 高。下面绘出了α值为 0.2 的 ELU 函数的图:
上图很直观,我们应该还能很好地应对梯度消失问题,因为输入值没有映射到非常小的输出值。
但 ELU 的导数又如何呢?这同样也很重要。
看起来很简单。如果输入 x 大于 0,则 y 值输出为 1;如果输入 x 小于或等于 0,则输出是 ELU 函数(未微分)加上 α 值。可绘出图为:
你可能已经注意到,这里成功避开了死亡 ReLU 问题,同时仍保有 ReLU 激活函数的一些计算速度增益——也就是说,网络中仍还有一些死亡的分量。
torch.nn.ELU(alpha=1.0,inplace=False)
ELU自定义实现如下:
优点:能避免死亡 ReLU 问题;能得到负值输出,这能帮助网络向正确的方向推动权重和偏置变化;在计算梯度时能得到激活,而不是让它们等于 0。
缺点:由于包含指数运算,所以计算时间更长;无法避免梯度爆炸问题;神经网络不学习α值。
9、渗漏型整流线性单元激活函数(Leaky ReLU)
渗漏型整流线性单元激活函数也有一个α值,通常取值在 0.1 到 0.3 之间。Leaky ReLU 激活函数很常用,但相比于 ELU 它也有一些缺陷,但也比 ReLU 具有一些优势。
Leaky ReLU 的数学形式如下:
因此,如果输入x大于 0,则输出为x;如果输入x小于或等于 0,则输出为 α 乘以输入。
这意味着能够解决死亡 ReLU 问题,因为梯度的值不再被限定为 0——另外,这个函数也能避免梯度消失问题。尽管梯度爆炸的问题依然存在,但后面的代码部分会介绍如何解决。下面给出了 Leaky ReLU 的图示,其中假设 α 值为 0.2:
和在公式中看到的一样,如果 x 值大于 0,则任意 x 值都映射为同样的 y 值;但如果 x 值小于 0,则会多一个系数 0.2。也就是说,如果输入值 x为 -5,则映射的输出值为 -1。
因为 Leaky ReLU 函数是两个线性部分组合起来的,所以它的导数很简单:
第一部分线性是当 x 大于 0 时,输出为 1;而当输入小于 0 时,输出就为 α 值,这里我们选择的是 0.2。
从上图中也能明显地看出来,输入 x 大于或小于 0,微分的 Leaky ReLU 各为一个常量。
torch.nn.LeakyReLU(negative_slope=0.01,inplace=False)
自定义实现:
优点:类似 ELU,Leaky ReLU 也能避免死亡 ReLU 问题,因为其在计算导数时允许较小的梯度;由于不包含指数运算,所以计算速度比 ELU 快。
缺点:无法避免梯度爆炸问题;神经网络不学习 α 值;在微分时,两部分都是线性的;而 ELU 的一部分是线性的,一部分是非线性的。
10、扩展型指数线性单元激活函数(SELU)
扩展型指数线性单元激活函数比较新,介绍它的论文包含长达90页的附录(包括定理和证明等)。当实际应用这个激活函数时,必须使用 lecun_normal 进行权重初始化。如果希望应用 dropout,则应当使用 AlphaDropout。后面的代码部分会更详细地介绍。
论文作者已经计算出了公式的两个值:α 和 λ;如下所示:
可以看到,它们的小数点后还有很多位,这是为了绝对精度。而且它们是预先确定的,也就是说我们不必担心如何为这个激活函数选取合适的 α 值。
说实话,这个公式看起来和其它公式或多或少有些类似。所有新的激活函数看起来就像是其它已有的激活函数的组合。
SELU 的公式如下:
也就是说,如果输入值 x 大于 0,则输出值为 x 乘以 λ;如果输入值 x 小于 0,则会得到一个奇异函数——它随 x 增大而增大并趋近于 x 为 0 时的值 0.0848。本质上看,当 x 小于 0 时,先用 α 乘以 x 值的指数,再减去 α,然后乘以 λ 值。
自定义实现SELU激活函数: