问题起与这篇知乎:训练到一定epoch之后,突然loss为Nan,其中一种方法说 梯度截断。我觉得我LSTM可能会出现这个问题。
https://www.zhihu.com/question/49346370
梯度消失(vanishing gradient)与梯度爆炸(exploding gradient)
(1)梯度不稳定问题:
什么是梯度不稳定问题:深度神经网络中的梯度不稳定性,前面层中的梯度或会消失,或会爆炸。
原因:前面层上的梯度是来自于后面层上梯度的乘乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景,如梯度消失和梯度爆炸。
(2)梯度消失(vanishing gradient problem):
原因:例如三个隐层、单神经元网络:
则可以得到:
然而,sigmoid方程的导数曲线为:
可以看到,sigmoid导数的最大值为1/4,通常abs(w)<1,则:
前面的层比后面的层梯度变化更小,故变化更慢,从而引起了梯度消失问题。
(3)梯度爆炸(exploding gradient problem):
当权值过大,前面层比后面层梯度变化更快,会引起梯度爆炸问题。
(4)sigmoid时,消失和爆炸哪个更易发生?
量化分析梯度爆炸出现时a的树枝范围:因为sigmoid导数最大为1/4,故只有当abs(w)>4时才可能出现
由此计算出a的数值变化范围很小,仅仅在此窄范围内会出现梯度爆炸问题。而最普遍发生的是梯度消失问题。
(5)如何解决梯度消失和梯度爆炸?
使用ReLU,maxout等替代sigmoid。(具体细节请看博主之前神经网络**函数部分)
区别:(1)sigmoid函数值在[0,1],ReLU函数值在[0,+无穷],所以sigmoid函数可以描述概率,ReLU适合用来描述实数;(2)sigmoid函数的梯度随着x的增大或减小和消失,而ReLU不会。
---------------------
梯度爆炸的解决方法:Gradient Clipping
随着神经网络层数的增多,会出现梯度消失或梯度爆炸问题。原因可以参考之前写过的文章。
针对梯度爆炸问题,解决方案是引入Gradient Clipping(梯度裁剪)。通过Gradient Clipping,将梯度约束在一个范围内,这样不会使得梯度过大。
在tensorflow 文档中,可以看到Gradient Clipping板块有五个函数。这里,我们仅仅介绍其中两个:tf.clip_by_norm(t,clip_norm,name=None)和tf.clip_by_global_norm(t_list,clip_norm,use_norm=None,name=None)
tf.clip_by_norm(t,clip_norm,name=None)
参数说明: t: a tensor ; clip_norm: 阈值,即maximum L2-norm。
如果 tensor的L2-norm大于clip_norm,则 t = t * clip_norm / l2norm(t)
否则t = t
tf.clip_by_global_norm(t_list,clip_norm,use_norm=None,name=None)
参数说明: t_list: multiple tensors; clip_norm: a clipping ratio; use_norm: 如果你已经计算出global_norm,你可以在use_norm进行指定。
t_list[i] = t_list[i] * clip_norm / max(global_norm,clip_norm)
where
global_norm = sqrt(sum(l2norm(t)**2 for t in t_list))
Any of the entries of t_list that are of type None are ignored.
This is the correct way to perform gradient clipping (for example, see R. Pascanu, T. Mikolov, and Y. Bengio, “On the difficulty of training Recurrent Neural Networks”. http://arxiv.org/abs/1211.5063)
通过介绍这两个函数,可以意识到tf.clip_by_global_norm(t_list,clip_norm,use_norm=None,name=None)更慢一些,因为它需要等所有的梯度都求出来才可以进行梯度截断。
---------------------
clip gradients 算法介绍
1.梯度爆炸的影响
在一个只有一个隐藏节点的网络中,损失函数和权值w偏置b构成error surface,其中有一堵墙,如下所示
损失函数每次迭代都是每次一小步,但是当遇到这堵墙时,在墙上的某点计算梯度,梯度会瞬间增大,指向某处不理想的位置。如果我们使用缩放,可以把误导控制在可接受范围内,如虚线箭头所示
2.解决梯度爆炸问题的方法
通常会使用一种叫”clip gradients “的方法. 它能有效地权重控制在一定范围之内.
算法步骤如下。
- 首先设置一个梯度阈值:clip_gradient
- 在后向传播中求出各参数的梯度,这里我们不直接使用梯度进去参数更新,我们求这些梯度的l2范数
- 然后比较梯度的l2范数||g||与clip_gradient的大小
- 如果前者大,求缩放因子clip_gradient/||g||, 由缩放因子可以看出梯度越大,则缩放因子越小,这样便很好地控制了梯度的范围
- 最后将梯度乘上缩放因子便得到最后所需的梯度
3. 有无clip_gradient在GRU模型中的结果比较
- 无clip_gradient
可以很清楚地发现在2000次迭代出发生了梯度爆炸,最终影响了训练的效果。
- 有clip_gradient
可以发现clip_gradient在前期有效了控制了梯度爆炸的影响,使得最终的loss能下降到满意的结果
原文:https://blog.csdn.net/YQMind/article/details/80955838
原文:https://blog.csdn.net/cppjava_/article/details/68941436