Обрезка градиента в TensorFlow
Обрезка градиента уменьшает
слишком длинный суммарный вектор
производных, сохраняя направление.
Функция clip_by_global_norm
принимает список тензоров градиента
и предел нормы, возвращает
список обрезанных градиентов
и исходную норму.
Сравним короткий и длинный
градиент при пределе 1.0
и 5.0:
import tensorflow as tf
short = tf.constant([3.0, 4.0])
long = tf.constant([30.0, 40.0])
clipped_short, _ = tf.clip_by_global_norm(
[short], clip_norm=1.0
)
clipped_long, norm = tf.clip_by_global_norm(
[long], clip_norm=5.0
)
print(clipped_short[0])
# выведет tf.Tensor([0.6 0.8], shape=(2,), dtype=float32)
print(clipped_long[0], norm)
# выведет tf.Tensor([2.9999998 3.9999998], shape=(2,), dtype=float32) tf.Tensor(50.0, shape=(), dtype=float32)
В своём цикле обрезку ставят
между методом gradient
и методом apply_gradients.
Возьмём большие начальные веса
и предел нормы 1.0:
import tensorflow as tf
tf.keras.utils.set_random_seed(0)
w = tf.Variable([[100.0]])
b = tf.Variable([100.0])
loss_fn = tf.keras.losses.MeanSquaredError()
optimizer = tf.keras.optimizers.SGD(
learning_rate=0.1
)
x = tf.constant([[1.0]])
y = tf.constant([[2.0]])
with tf.GradientTape() as tape:
pred = x @ w + b
loss = loss_fn(y, pred)
grads = tape.gradient(loss, [w, b])
clipped, gnorm = tf.clip_by_global_norm(
grads, clip_norm=1.0
)
optimizer.apply_gradients(zip(clipped, [w, b]))
print(gnorm)
# выведет tf.Tensor(560.028564453125, shape=(), dtype=float32)
Задайте градиент [6.0, 8.0]
и обрежьте его с пределом
нормы 2.0. Выведите
получившийся вектор.
Создайте переменные веса
и смещения с большими
начальными значениями,
считайте один шаг по одной
паре признак-ответ с пределом
нормы 0.5 и выведите
исходную норму до обрезки.
В цикле из двух эпох
обрежьте градиенты модели
с одним выходом перед
каждым шагом спуска.
Обучите на точках (1, 2)
и (2, 4) и выведите
веса после второй эпохи.