31

如何发现「将死」的ReLu?可视化工具TensorBoard助你一臂之力

 4 years ago
source link: https://www.jiqizhixin.com/articles/2019-11-14-8
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

深度学习模型训练中会出现各种各样的问题,比如梯度消失、梯度爆炸,以及 Dying ReLU。那么如何及时发现这些问题并找出解决方案呢?本文以 Dying ReLU 问题为例,介绍了如何使用可视化工具TensorBoard发现该问题,并提供了不同解决思路。

F77NJ3J.jpg!web

本文介绍了如何利用可视化工具TensorBoard发现「Dying ReLU 问题」。

什么是 ReLU?

ReLU 即修正线性单元(Rectified Linear Unit),是人工神经网络中的一种激活函数。通常情况下,ReLU 是最常使用的激活函数。其主要原因在于 ReLU 不会遇到梯度消失问题。ReLU 的数学公式为:

y6RfEv6.png!web

另外一种表达式为:

EJzuie6.png!web

其函数图像如下所示:

NZRji2M.png!web

注意,该函数并非线性,其输出是非线性的。

ReLU 的导数是:

FRZRVrJ.png!web

当 x=0 时,ReLU 的导数是未定义的。

什么是 Dying ReLU 问题?

ReLU 的主要优势在于:其输出为 0 和 1,(无需在反向传播过程中乘以非常小的值,)从而解决了梯度消失问题。然而,它也存在缺陷。由于它对每个负值的输出均为 0,ReLU神经元可能陷入负值中,持续输出 0,且无法恢复。这叫做 Dying ReLU 问题。这个问题非常严重,因为一旦神经元死亡,它基本上学不到任何信息,从而导致网络的大部分无法工作。

利用TensorBoard检测 Dying ReLU 问题

使用以下代码创建随机样本:

ZruARzI.png!web

x 表示大小为 200k x 4 的数组,其数值均从 (-1,0) 区间内均匀采样得到。该数组内绝大部分数值为负,是 ReLU 最不喜欢的一类输入。将该数据按照 7:3 的比例分割为训练集和测试集。

使用一个具备 ReLU激活函数的一层简单网络。随机初始化权重,将偏差初始化为 0。

IbQbm2n.jpg!web

现在,初始化TensorBoard变量。每个 epoch 都需要梯度,因此将 write_grads 初始化为 True。

JreemaR.png!web

最后拟合模型,在 callbacks参数中使用TensorBoard变量。

yYFfyeM.png!web

绘制训练损失和验证损失的图像。

rU7nE3m.png!web

FNfiUjR.png!web

所有 epoch 的验证损失(上)和训练损失(下)。

从上图中,我们可以清晰地看到模型损失没有降低,这意味着模型停止了学习。现在使用TensorBoard对密集层的梯度和输出进行可视化。

ZJbMnqe.png!web

密集层输出(左)和密集层梯度(右)。

从上图中我们可以看到,对于所有 epoch,密集层梯度都为 0,输出也均为 0。梯度图显示出,一旦梯度变成 0,模型试图挣脱这种情况,但它已经完全死亡,这从损失图中也能看出,因为损失没有随时间发生变化,说明模型停止学习或者学不到任何信息。

添加层

现在,使用具备同样 ReLU 函数的三层网络,看看上述问题是否解决。本文使用如下网络:

6z6BRzJ.jpg!web

这是一个三层网络,所有层的激活函数均为 ReLU。

现在,通过TensorBoard观察所有层的梯度:

7RZZfeN.png!web

Dense_3 梯度(左)、Dense_2 梯度(中)、Dense_1 梯度(右)。

从上图中可以看到,添加层并没有解决 dying ReLU 问题,所有层的梯度仍然为 0,这些梯度被反向传播至模型其他层,从而影响模型的性能。

解决方案

1. 增加数据规模会有帮助吗?

不会!如果新数据与原有数据属于同一分布,则在训练集中添加这些新数据是无用的。不过,为同样的问题收集一个新数据集可能是一种解决方案。

2. 添加Dropout会有帮助吗?

Dropout与 ReLU 的输出没有任何关系,因此添加或者更改Dropout对 dying ReLU 没有影响。

3. 添加层会有帮助吗?

不会。如上所述,添加层对解决 dying ReLU 问题没有帮助。

4. 增加训练 epoch 会有帮助吗?

不会,虽然每个 epoch 结束后都会更新权重,但是由于神经元死亡,梯度为 0,使得权重无法得到更新。权重一直不变,使用相同的权重计算梯度只能得到 0,因此这对解决 dying ReLU 问题没有帮助。

5. 改变权重初始化会有帮助吗?

我们先来尝试不同的权重初始化器,并绘制其梯度和输出。下图是为使用 ReLU激活函数的密集层梯度绘制的图,这四个网络使用的权重初始化器分别是:he_normal、he_uniform、ecun_normal 和 random_uniform。

3u2i2iU.jpg!web

he_normal(左)和 he_uniform(右)。

zume22y.jpg!web

lecun_uniform(左)和 random_uniform(右)。

从上图中我们可以看到,权重初始化对解决 dying ReLU 问题没有帮助。从 he_normal、he_uniform 和 lecun_normal 的图示中可以看到,在初始化阶段有轻微的改善,但是随着 epoch 数量的增加,导数趋向于 0。

由于输入多为负值,我们使用以下代码将权重初始化为负值:

Mjm6Bb6.png!web

分配给权重的值均从 (-1,0) 区间内随机均匀采样得到,这与输入的分布相同。该网络的梯度和输出如下图所示:

ymAFZrq.jpg!web

dense_1 输出(左)、dense_1 梯度(右)。

从上图中同样可以观察到,随着 epoch 数量的增加,梯度变为 0,输出也集中于 0。因此我们可以认为改变初始权重是解决 dying ReLU 问题的一种办法,但是需要确保模型不要运行太多 epoch,因为这又会导致 dying ReLU 问题。事实上,从这些图中可以看出,改变初始权重对解决 dying ReLU 问题并没有太大帮助。

6. 改变激活函数会有帮助吗?

可能会。那么要用哪种函数替代 ReLU 呢?我们可以使用 tanh 和 Sigmoid 函数。使用 ReLU 的变体 Leaky ReLU 也可以避开该问题。但是,在为该实验创建的示例中,以上所有函数均失败了,因为它们都遭遇了梯度消失问题。当我们需要在梯度消失和 Dying ReLU 中进行权衡时,有动静总比没有好。遇到梯度消失问题后,模型仍在学习,而在 Dying ReLU 中没有学习,学习过程被中断了。

这时候,Leaky ReLU 的加强版 SELU (Scaled Exponential Linear Units) 就派上用场了。SELU激活函数可以自行归一化神经网络,即归一化后网络权重和偏差的均值为 0,方差为 1。SELU 的主要优势是不会遭遇梯度消失和梯度爆炸,同时也不会出现激活函数死亡现象。关于 SELU 的更多信息,参见论文 《Self-Normalizing Neural Networks》

注意:SELU 必须与 lecun_normal 初始化一起使用,且将 AlphaDropout作为 dropout。对于以上数据集,我们可以使用以下网络:

M7ZRJbY.jpg!web

该网络密集层的梯度和输出如下图所示:

6riqUfF.jpg!web

从梯度图中可以看出,梯度有所改善,逐渐远离 0。从输出图中可以看出,具备 SELU激活函数的密集层输出值很小,但也不像之前示例那样输出为 0。因此,即使在最糟糕的情况下,SELU 也比 ReLU 效果好。

结论

训练和使用深度神经网络时,实时监控损失和梯度情况是一种不错的做法,有助于发现深度学习模型训练过程中的大部分问题。如果你不知道如何发现和解决问题,那么写深度网络是没有意义的。本文只涉及了众多问题的冰山一角。每个使用深度学习和人工神经网络的人总会遇到激活函数死亡问题,一着不慎就要浪费数个小时重新训练模型,因为这时只改变模型参数已经没用了。由于 ReLU 是大部分深度学习问题中最常用的激活函数,因此大家一定要谨慎地避免该问题。而有了TensorBoard之后,你可以轻松发现该问题。

原文链接: https://medium.com/@jithinjayan1993/is-relu-dead-27943b50102


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK