想了解 TensorFlow 中梯度裁剪实现过程中
tf.clip_by_value
和 tf.clip_by_global_norm
的作用区别。首选哪一个以及如何确定要剪辑的最大值?
TL;DR:使用
tf.clip_by_global_norm
进行梯度裁剪,以“某个高值”作为最大值。
tf.clip_by_value
剪切一个张量内的每个值,无论张量中的其他值如何。例如,
tf.clip_by_value([-1, 2, 10], 0, 3) -> [0, 2, 3] # Only the values below 0 or above 3 are changed
因此,它可以改变张量的方向,因此如果张量中的值相互去相关(梯度裁剪不是这种情况),则应该使用它,或者避免张量中的零/无限值可能会在其他地方导致 Nan/无限值(例如,通过使用最小值 epsilon=1e-8 和非常大的最大值进行裁剪)。
tf.clip_by_norm
如有必要,会重新调整一个张量,使其 L2 范数不超过某个阈值。通常,避免一个张量上的梯度爆炸很有用,因为您可以保持梯度方向。例如:
tf.clip_by_norm([-2, 3, 6], 5) -> [-2, 3, 6]*5/7 # The original L2 norm is 7, which is >5, so the final one is 5
tf.clip_by_norm([-2, 3, 6], 9) -> [-2, 3, 6] # The original L2 norm is 7, which is <9, so it is left unchanged
但是,
clip_by_norm
仅适用于一个梯度,因此如果您在所有梯度张量上使用它,您将使它们不平衡(一些将被重新缩放,另一些不会,并且并非全部具有相同的缩放比例)。
请注意,前两个仅适用于一个张量,而最后一个则用于张量列表。
tf.clip_by_global_norm
重新缩放张量列表,以便所有其范数的向量的总范数不超过阈值。目标与 clip_by_norm
相同(避免梯度爆炸,保持梯度方向),但它同时作用于所有梯度,而不是单独作用于每个梯度(也就是说,如果需要,所有梯度都会按相同的因子重新缩放) ,或者它们都不被重新调整)。这更好,因为保持了不同梯度之间的平衡。
例如:
tf.clip_by_global_norm([tf.constant([-2, 3, 6]),tf.constant([-4, 6, 12])] , 14.5)
将按因子
14.5/sqrt(49 + 196)
重新缩放两个张量,因为第一个张量的 L2 范数为 7,第二个张量的 L2 范数为 14,而 sqrt(7^2+ 14^2)>14.5
这个 (
tf.clip_by_global_norm
) 是您应该用于渐变剪辑的。例如,请参阅this了解更多信息。
选择最大值是最难的部分。您应该使用最大值,这样就不会出现梯度爆炸(其影响可能是张量中出现的
Nan
或 infinite
值,经过几个训练步骤后会出现恒定的损失/准确性)。 tf.clip_by_global_norm
的值应该比其他值更大,因为由于隐含的张量数量,全局 L2 范数在机械上会比其他范数更大。