zoukankan      html  css  js  c++  java
  • TensorFlow的梯度裁剪

    在较深的网络,如多层CNN或者非常长的RNN,由于求导的链式法则,有可能会出现梯度消失(Gradient Vanishing)或梯度爆炸(Gradient Exploding )的问题。

    原理

    问题:为什么梯度爆炸会造成训练时不稳定而且不收敛?
    梯度爆炸,其实就是偏导数很大的意思。回想我们使用梯度下降方法更新参数:

    损失函数的值沿着梯度的方向呈下降趋势,然而,如果梯度(偏导数)很大话,就会出现函数值跳来跳去,收敛不到最值的情况,如图:

    当然出现这种情况,其中一种解决方法是,将学习率αα设小一点,如0.0001。

    这里介绍梯度裁剪(Gradient Clipping)的方法,对梯度进行裁剪,论文提出对梯度的L2范数进行裁剪,也就是所有参数偏导数的平方和再开方。

    TensorFlow代码

    方法一:

    optimizer = tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.5)
    grads = optimizer.compute_gradients(loss)
    for i, (g, v) in enumerate(grads):
        if g is not None:
            grads[i] = (tf.clip_by_norm(g, 5), v)  # 阈值这里设为5
    train_op = optimizer.apply_gradients(grads)

    其中
    optimizer.compute_gradients()返回的是正常计算的梯度,是一个包含(gradient, variable)的列表。

    tf.clip_by_norm(t, clip_norm)返回裁剪过的梯度,维度跟t一样。

    不过这里需要注意的是,这里范数的计算不是根据全局的梯度,而是一部分的。

    方法二:

    optimizer = tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.5)
    grads, variables = zip(*optimizer.compute_gradients(loss))
    grads, global_norm = tf.clip_by_global_norm(grads, 5)
    train_op = optimizer.apply_gradients(zip(grads, variables))

    这里是计算全局范数,这才是标准的。不过缺点就是会慢一点,因为需要全部梯度计算完之后才能进行裁剪。

    总结

    当你训练模型出现Loss值出现跳动,一直不收敛时,除了设小学习率之外,梯度裁剪也是一个好方法。

    然而这也说明,如果你的模型稳定而且会收敛,但是效果不佳时,那这就跟学习率和梯度爆炸没啥关系了。因此,学习率的设定和梯度裁剪的阈值并不能提高模型的准确率。

  • 相关阅读:
    还在使用golang 的map 做Json编码么?
    Golang 性能测试(2) 性能分析
    golang 性能测试 (1) 基准性能测试
    消息队列 NSQ 源码学习笔记 (五)
    消息队列 NSQ 源码学习笔记 (四)
    消息队列 NSQ 源码学习笔记 (三)
    消息队列 NSQ 源码学习笔记 (二)
    消息队列 NSQ 源码学习笔记 (一)
    你不知道的空格
    Supervisor 使用和进阶4 (Event 的使用)
  • 原文地址:https://www.cnblogs.com/zongfa/p/9737698.html
Copyright © 2011-2022 走看看