我有一个梯度爆炸问题,尝试了几天后我无法解决。我在 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_mean
与 e
并且只使用下面的代码,不会有梯度爆炸。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
初始化分销我在这里缺少什么?我当然知道它与连接
e
有关。 .但是鉴于 0.5最佳答案
看起来很棒,因为您已经按照大多数解决方案来解决梯度爆炸问题。以下是您可以尝试的所有解决方案的列表
避免梯度爆炸问题的解决方案
初始化
激活函数
他
ReLU 和变体
乐村
塞卢
格洛洛特
Softmax、Logistic、无、Tanh
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")
])
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/