【问题标题】:How to avoid that Theano computing gradient going toward NaN如何避免 Theano 计算梯度朝向 NaN
【发布时间】:2017-03-17 06:20:11
【问题描述】:

我正在尝试使用 5 个卷积层 - 2 个隐藏层 - 1 个 Softmax 的 CNN。

架构是:

cv0->relu->cv1->relu-cv2->relu->cv3->relu->cv4->relu->cv5->hid1->relu->hid2->relu->logistic softmax

通过使用图像中的 66 个补丁标记应用随机梯度。训练仅应用于具有 20 个 epoch 的单个图像以进行测试。

从网络中识别出的错误在每次迭代中都在爆炸,因此梯度在第 4 个 epoch 的第 3 个之后计算 nan。

  • epoch 1 学习成本:4.702012
  • epoch 2 学习成本:45338036.000000
  • epoch 3 学习成本:74726722389225987403008805175296.000000
  • epoch 4 学习成本:nan

正如您所见,在错误被分解为非常高的值后,梯度产生的 nan 传播到了所有网络中。

查看来自不同层权重值的单个节点以了解发生了什么:

layer8 (softmax):

  • 初始值[ 0.05436778 0.02379715]
  • 纪元 1 [ 0.28402206 -0.20585714]
  • 第二纪元[ -5.27361184e-02 9.52038541e-02]
  • 第三纪元[-7330.04199219 7330.12011719]
  • 第四纪元[ nan nan]

layer6 (hid1):

  • 初始值[-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309]
  • 纪元 1 [-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309]
  • 第二纪元[-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309
  • 第三纪元[ -2.54468974e-02 1.79247314e+16 ..., -5.87915350e-03 2.61985492e-02 -2.06307964e+19]
  • 第四纪元[ nan nan ..., nan nan nan]

layer0 (cv0):

关于初始化是

[[-0.01704694 -0.01683052 -0.0894756 ]
 [ 0.12275343 -0.05518051 -0.09202443]
 [-0.11599202 -0.04718829 -0.04359322]]

而在第三个纪元是

[[-24165.15234375 -26490.89257812 -24820.1484375 ]
 [-27381.8203125  -26653.3359375  -24762.28710938]
 [-23120.56835938 -21189.44921875 -24513.65039062]]

很明显,权重值正在爆炸式增长。

学习率为 0.01 所以为了解决这个问题,我将学习率改为 0.001,Nan 有时会消失,网络会收敛,有时不会收敛,网络会被 NaN 饱和。再次尝试使用 0.0001 的较小学习率,但我还没有看到 NaN。我从每次重新运行代码时得到的结果中看到的结果确实不同,我认为这首先与权重初始化有关。

所以我尝试了不同的权重初始化:

对于带有relu的Conv层

W_bound_6 = numpy.sqrt(6. / (fan_in + fan_out))
W_bound_2 = numpy.sqrt(2. / (fan_in + fan_out))
W_values = numpy.asarray(
                numpy.random.randn(filter_shape[0], filter_shape[1], filter_shape[2], filter_shape[3]) * W_bound_2,
                dtype=theano.config.floatX)

对于隐藏层和softamx层

W_bound_2 = numpy.sqrt(2. / (filter_shape[0] + filter_shape[1]))
W_values = numpy.asarray(
                numpy.random.randn(filter_shape[0], filter_shape[1]) * W_bound_2,
                dtype=theano.config.floatX
            )

并将 b 全部初始化为零。

差异并不大,我仍然看不出结果有什么不同。

我将我的问题发布到:

  • disccuess 如果我正在做的权重初始化是 正确编码
  • 看看我们是否可以避免让学习率变得非常小,并至少在前几次迭代中保持较高,因为在我的例子中,它是在第 4 次迭代中传播 Nan。
  • 我想知道是 L1,L2 正则化,因为我正在使用 Theano,我应该在哪里实现成本函数中的代码,或者我应该更改更新函数。

成本函数

-T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y])

更新功能

updates = [
        (param_i, param_i - learning_rate * grad_i)
        for param_i, grad_i in zip(classifier.params, grads)
    ]
  • 在我的结构中每一层之后的 relu 实现是否正确,但在 softmax 中不正确?

【问题讨论】:

  • 我对 CNN 了解不多,但您尝试过剪裁渐变吗?在某些时候,您可能拥有grads = T.grad(cost, classifier.params)。尝试使用grads_clipped = [T.clip(g, -2, 2] for g in grads) 添加一个新行并将更新中的grads 替换为grads_clipped,即zip(classifier.params, grads_clipped)
  • 我在 google group 上看到了这项工作,以避免梯度爆炸。我不记得到底在讨论什么是好技术还是不好。
  • 值得一试。关于 L1、L2 正则化,您只需将其粘贴在损失函数的末尾即可cost = -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y] + L1 + L2)

标签: python machine-learning deep-learning theano convolution


【解决方案1】:

我正在寻找不同的方法来避免这个问题,但是寻找其他人提出的正式解决方案并阅读一些理论解决方案,我会在这里写下我的答案,以帮助其他有同样问题的人。

这个问题背后的原因是使用了 softmax 和交叉熵。因此,当您计算梯度并按零或 inf 潜水时,您会得到 nan ,它正在传播 backword 抛出所有网络参数。

很少有人建议避免这个问题

  • 如果错误开始增加,然后出现 NaN:由于发散 学习率太高
  • 如果 NaN 突然出现:饱和单元产生不可微分 由于 log(0) 导致的梯度 NaN 计算
  • NaN 由于浮点问题(对高权重)或激活 输出 0/0、inf/inf、inf*weight...

解决方案:

  1. 降低学习率
  2. 更改权重初始化
  3. 使用 L2 规范
  4. 安全的 softmax(对 log(x) 添加小值)
  5. 渐变剪裁

在我的例子中,学习率解决了这个问题,但我仍在努力优化它

【讨论】:

    【解决方案2】:

    我猜这可能是导致数学错误的“dead relu”问题。负对数似然成本函数涉及不期望为零的自然对数计算。 Relu 函数可以输出零,并且零的自然对数欠精细,因此它返回 NaN。在最后一层尝试使用不输出负数和零的函数或尝试其他成本函数。

    【讨论】:

    • 负对数似然将计算它是 softmax 概率分布的梯度,所以我不认为它是一个死的 Relu。问题是相关的高成本错误,它在所有网络中传播 inf 并产生 NaN。
    猜你喜欢
    • 2015-09-16
    • 2016-04-01
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多