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

标签 python tensorflow machine-learning keras gradient

我有一个梯度爆炸问题,尝试了几天后我无法解决。我在 TensorFlow 中实现了一个自定义消息传递图神经网络,用于从图数据预测连续值。每个图形都与一个目标值相关联。图的每个节点由一个节点属性向量表示,节点之间的边由一个边属性向量表示。
在消息传递层内,节点属性以某种方式更新(例如,通过聚合其他节点/边属性),并返回这些更新的节点属性。
现在,我设法找出我的代码中出现梯度问题的位置。我有下面的片段。

to_concat = [neighbors_mean, e]
z = K.concatenate(to_concat, axis=-1)
output = self.Net(z)
在这里,neighbors_mean是两个节点属性之间的元素均值vi , vj形成具有边缘属性 e 的边缘. Net是单层前馈网络。有了这个,训练损失在大约 30 轮后突然跳到 NaN,批次大小为 32。如果批次大小为 128,在大约 200 轮后梯度仍然爆炸。
我发现,在这种情况下,梯度爆炸是因为边缘属性 e .如果我没有连接 neighbors_meane并且只使用下面的代码,不会有梯度爆炸。
output = self.Net(neighbors_mean)
我也可以通过发送 e 来避免梯度爆炸通过如下的 sigmoid 函数。但这会降低性能(最终 MAE),因为 e 中的值非线性映射到 0-1 范围。请注意 Rectified Linear Unit (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 .
我有一个自定义的损失函数来训练这个模型,但是我发现这不是损失的问题(其他损失也导致了同样的问题)。下面是我的自定义损失函数。请注意,虽然这是一个单输出回归网络,但我的神经网络的最后一层有两个神经元,与预测的均值和对数(西格玛)相关。
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)
我基本上尝试了网上建议的所有内容以避免梯度爆炸。
  • 应用渐变剪裁 - 使用 Adam(lr, clipnorm=1, clipvalue=5)还有 tf.clip_by_global_norm(gradients, 1.0)
  • 我的目标变量总是按比例缩放
  • 权重用 glorot_uniform 初始化分销
  • 对权重应用正则化
  • 尝试了更大的批量(直到 256,尽管在某些时候会发生延迟梯度爆炸)
  • 尝试降低学习率

  • 我在这里缺少什么?我当然知道它与连接 e 有关。 .但是鉴于 0.5e对我很重要。我还能做些什么来避免模型中的数值溢出?

    最佳答案

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

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


    初始化
    激活函数



    ReLU 和变体

    乐村
    塞卢

    格洛洛特
    Softmax、Logistic、无、Tanh

  • 重新设计你的神经网络:在神经网络中使用更少的层和/或使用更小的批量
  • 选择非饱和激活函数:选择正确的激活函数并降低学习率
  • ReLU
  • 泄漏 ReLU
  • 随机泄漏 ReLU (RReLU)
  • 参数泄漏 ReLU (PReLU)
  • 指数线性单元 (ELU)

  • 批量归一化:理想情况下,根据最适合您的数据集的方式,在每层之前/之后使用批量归一化。
  • 每层后Paper reference
    model = keras.models.Sequential([
                         keras.layers.Flatten(input_shape=[28, 28]),
                         keras.layers.BatchNormalization(),
                         keras.layers.Dense(300, activation="elu", 
                         kernel_initializer="he_normal"),
                         keras.layers.BatchNormalization(),
                         keras.layers.Dense(100, activation="elu", 
                         kernel_initializer="he_normal"),
                         keras.layers.BatchNormalization(),
                         keras.layers.Dense(10, activation="softmax")
             ])
    
  • 在每一层之前
     model = keras.models.Sequential([
                         keras.layers.Flatten(input_shape=[28, 28]),
                         keras.layers.BatchNormalization(),
                         keras.layers.Dense(300, kernel_initializer="he_normal", use_bias=False),
                         keras.layers.BatchNormalization(),
                         keras.layers.Activation("elu"),
                         keras.layers.Dense(100, kernel_initializer="he_normal", use_bias=False),
                         keras.layers.Activation("elu"),
                         keras.layers.BatchNormalization(),
                         keras.layers.Dense(10, activation="softmax")
             ])
    

  • Gradient Clipping :好的默认值是 clipnorm=1.0 和 clipvalue=0.5
  • 确保使用正确的优化器:由于您使用了 Adam 优化器,请检查其他优化器是否最适合您的情况。引用 this documentation有关可用优化器的信息 [SGD、RMSprop、Adam、Adadelta、Adagrad、Adamax、Nadam、Ftrl]
  • 通过时间截断反向传播:通常适用于 RNNS 引用此 documentation
  • 使用 LSTM(RNN 的解决方案)
  • 在层上使用权重正则化器:设置 kernel_regularizer到 L1 或 L2。 Weight regularizer document reference

  • 有关更多信息,请参阅 Aurélien 的 Hands on Machine learning with scikit-learn、keras 和 tensorflow 一书中的第 11 章

    关于python - 图神经网络中的梯度爆炸问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69427103/

    相关文章:

    python - 从 MainWindow 内的 QWidget 内的按钮更改 MainWindow 小部件

    python - Matlab 到 Python numpy 索引和乘法问题

    tensorflow - 如何微调现有的 Tensorflow 对象检测模型以识别其他类?

    python-3.x - 属性错误 : 'Conv2D' object has no attribute 'shape'

    javascript - 尝试将 TensorFlow 保存的模型转换为 TensorFlow.js 模型时出错

    python - kNN - 如何根据计算的距离在训练矩阵中定位最近的邻居

    machine-learning - 在这个暹罗实现中,如何获得最后一层的输出(A 和 B 张量的值)?

    python - 使用python在html文档中查找输入字段的值

    python - Numpy 二维数组 : change all values to the right of NaNs

    python - ConvNN Tensorflow 中奇怪的精度结果