当前位置: 首页 > 知识库问答 >
问题:

图形神经网络中的梯度爆炸问题

红经亘
2023-03-14

我有一个梯度爆炸的问题,试了好几天都没能解决。我在TensorFlow中实现了一个自定义消息传递图神经网络,用于从图数据中预测一个连续值。每个图与一个目标值相关联。图的每个节点由一个节点属性向量表示,节点之间的边由一个边属性向量表示。

在消息传递层中,节点属性以某种方式更新(例如,通过聚合其他节点/边缘属性),并返回这些更新的节点属性。

现在,我设法弄清楚了代码中出现梯度问题的位置。我有下面的片段。

to_concat = [neighbors_mean, e]
z = K.concatenate(to_concat, axis=-1)
output = self.Net(z)

这里,neighbors_mean是两个节点属性vivjNet是一个单层前馈网络。这样,训练损失在大约30个周期(批次大小为32)后突然跳至NaN。如果批次大小为128,则梯度在大约200个周期后仍会爆炸。

我发现,在这种情况下,渐变会爆炸,因为边属性e。如果我不将neighbors_meane连接起来,只使用下面的代码,就不会有渐变爆炸。

output = self.Net(neighbors_mean)

我也可以通过sigmoid函数发送< code>e来避免梯度爆炸,如下所示。但是这降低了性能(最终MAE),因为< code>e中的值被非线性地映射到0-1范围。请注意,整流线性单位(ReLU)而不是sigmoid不起作用。

to_concat = [neighbors_mean, tf.math.sigmoid(e)]
z = K.concatenate(to_concat, axis=-1)
output = self.Net(z)

仅需提及,e携带与两个相应节点之间的距离相关的单个值,该距离始终在0.5-4范围内。e中没有大值或NaN。

我有一个自定义损失函数来训练这个模型,但我发现这不是损失的问题(其他损失也导致了同样的问题)。以下是我的自定义损失函数。请注意,尽管这是一个单输出回归网络,但我的NN的最后一层有两个神经元,与预测的平均值和对数(sigma)有关。

def robust_loss(y_true, y_pred):
  """
  Computes the robust loss between labels and predictions.
  """
  mean, sigma = tf.split(y_pred, 2, axis=-1)
  # tried limiting 'sigma' with  sigma = tf.clip_by_value(sigma,-4,1.0) but the gradients still explode
  loss =  np.sqrt(2.0) * K.abs(mean - y_true) * K.exp(-sigma)  + sigma
  return K.mean(loss)

为了避免梯度爆炸,我基本上尝试了所有网上建议的方法。

  1. 应用梯度裁剪-使用Adam(lr, clipNorm=1, clipvalue=5),也使用tf.clip_by_global_norm(gradients,1.0)
  2. 我的目标变量总是缩放
  3. 权重用glorot_uniform分布
  4. 初始化
  5. 将正则化应用于权重
  6. 尝试更大的批量(直到256,尽管延迟梯度爆炸会在某个时候发生)
  7. 尝试学习率降低

我错过了什么?我当然知道这与连接< code>e有关。但是考虑到0.5

共有2个答案

长孙德惠
2023-03-14

由于这个很酷的调试工具tf.debuging.check_numerics,我解决了这个问题。

我最初发现连接< code>e是个问题,然后意识到传递给< code>e的值比用< code>e连接的< code>neighbors_mean中的值大得多。一旦它们被连接起来并通过神经网络(在我的代码中是< code>Net())发送,我观察到一些输出是数百个,随着训练的进行慢慢达到数千个。

这是有问题的,因为我在消息传递层中有一个softmax操作。请注意,softmax计算指数(exi/∑exj)。任何高于e709的值都会导致Python中的数字溢出。这会产生inf值,最终所有变成nan的东西都是我代码中的问题。所以,从技术上讲,这不是一个梯度爆炸问题,这就是为什么不能用梯度裁剪来解决这个问题。

我是如何跟踪问题的?

我将< code > TF . debugging . check _ numerics()片段放在我认为会产生nan值的几个层/张量下。大概是这样的:

tf.debugging.check_numerics(layerN, "LayerN is producing nans!")

这会在训练期间层输出变为infnan时立即生成InvalidArgumentError

Traceback (most recent call last):
  File "trainer.py", line 506, in <module>
    worker.train_model()
  File "trainer.py", line 211, in train_model
    l, tmae = train_step(*batch)
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/def_function.py", line 828, in __call__
    result = self._call(*args, **kwds)
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/def_function.py", line 855, in _call
    return self._stateless_fn(*args, **kwds)  # pylint: disable=not-callable
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/function.py", line 2943, in __call__
    filtered_flat_args, captured_inputs=graph_function.captured_inputs)  # pylint: disable=protected-access
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/function.py", line 1919, in _call_flat
    ctx, args, cancellation_manager=cancellation_manager))
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/function.py", line 560, in call
    ctx=ctx)
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/execute.py", line 60, in quick_execute
    inputs, attrs, num_outputs)
tensorflow.python.framework.errors_impl.InvalidArgumentError:  LayerN is producing nans! : Tensor had NaN values

现在我们知道问题出在哪里了。

如何解决问题

我将内核约束应用于神经网络权重,其输出传递给softmax函数

layers.Dense(x, name="layer1", kernel_regularizer=regularizers.l2(1e-6), kernel_constraint=min_max_norm(min_value=1e-30, max_value=1.0))

这应该确保所有权重都小于1,并且该层不会产生较大的输出。这在不降低性能的情况下解决了问题。

或者,可以使用 softmax 函数的数值稳定实现。

栾烨华
2023-03-14

看起来很棒,因为您已经遵循了大多数解决方案来解决梯度爆炸问题。以下是您可以尝试的所有解决方案的列表

避免梯度爆炸问题的解决方案

>

  • 适当的权重初始化:根据所使用的激活函数使用适当的权重初始化。

  •  类似资料:
    • 本文向大家介绍梯度消失,梯度爆炸的问题,相关面试题,主要包含被问及梯度消失,梯度爆炸的问题,时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 激活函数的原因,由于梯度求导的过程中梯度非常小,无法有效反向传播误差,造成梯度消失的问题。

    • 本文向大家介绍梯度消失梯度爆炸怎么解决相关面试题,主要包含被问及梯度消失梯度爆炸怎么解决时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 1)、使用 ReLU、LReLU、ELU、maxout 等激活函数 sigmoid函数的梯度随着x的增大或减小和消失,而ReLU不会。 2)、使用批规范化 通过规范化操作将输出信号x规范化到均值为0,方差为1保证网络的稳定性。从上述分析分可以看到,反向传播

    • 本文向大家介绍如何解决梯度消失和梯度爆炸?相关面试题,主要包含被问及如何解决梯度消失和梯度爆炸?时的应答技巧和注意事项,需要的朋友参考一下 (1)梯度消失: 根据链式法则,如果每一层神经元对上一层的输出的偏导乘上权重结果都小于1的话,那么即使这个结果是0.99,在经过足够多层传播之后,误差对输入层的偏导会趋于0 可以采用ReLU激活函数有效的解决梯度消失的情况,也可以用Batch Normaliz

    • 本文向大家介绍梯度爆炸会引发什么?相关面试题,主要包含被问及梯度爆炸会引发什么?时的应答技巧和注意事项,需要的朋友参考一下 在深度多层感知机网络中,梯度爆炸会引起网络不稳定,最好的结果是无法从训练数据中学习,而最坏的结果是出现无法再更新的 NaN 权重值。 梯度爆炸导致学习过程不稳定。—《深度学习》,2016. 在循环神经网络中,梯度爆炸会导致网络不稳定,无法利用训练数据学习,最好的结果是网络无法

    • 本文向大家介绍如何解决RNN梯度爆炸和弥散的问题?相关面试题,主要包含被问及如何解决RNN梯度爆炸和弥散的问题?时的应答技巧和注意事项,需要的朋友参考一下 答:梯度爆炸:为解决梯度爆炸问题,Thomas Mikolov首先提出了一个简单的启发性的解决方案,就是当梯度大于一定阀值的时候,将它截断为一个较为小的数。 解决梯度弥散问题的两种方法: 第一种:将随机初始化W改为一个有关联的矩阵初始化。 第二

    • LeNet 5 LeNet-5是第一个成功的卷积神经网络,共有7层,不包含输入,每层都包含可训练参数(连接权重)。 AlexNet tf AlexNet可以认为是增强版的LeNet5,共8层,其中前5层convolutional,后面3层是full-connected。 GooLeNet (Inception v2) GoogLeNet用了很多相同的层,共22层,并将全连接层变为稀疏链接层。 In