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值出现跳动,一直不收敛时,除了设小学习率之外,梯度裁剪也是一个好方法。

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

  • 相关阅读:
    Java中printf
    error C3688: invalid literal suffix '__FSTREXP'; literal operator or literal operator template 'operator ""__FSTREXP' not found
    C# IIS 访问网络映射磁盘 读取文件列表
    datatables 参数详解
    Telnet协议详解
    WCF中的ServiceHost初始化两种方式
    C# FTP 上传、下载、获取文件列表
    Oracle存储过程编译卡死的解决方法
    oracle 查询表结构
    Oracle大数据常见优化查询
  • 原文地址:https://www.cnblogs.com/zongfa/p/9737698.html
Copyright © 2011-2022 走看看