В чем разница между `GradientTape`,` implicit_gradients`? - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь переключиться в режим ожидания TensorFlow, и я нахожу документацию с разницей между контекстом GradientTape() и функциями implicit_gradients() и implicit_value_and_gradients() немного запутанной. В чем разница между ними и когда лучше использовать тот или иной? Вступительная точка в документации вообще не упоминает неявные * функции, но почти все примеры в репозитории tf, похоже, используют этот метод для вычисления градиентов.

1 Ответ

0 голосов
/ 12 мая 2018

Существует 4 способа автоматического вычисления градиентов при активном выполнении (на самом деле, они также работают в графическом режиме):

  • tf.GradientTape контекст записывает вычисления, так что вы можете вызвать tfe.gradient(), чтобы получить градиенты любого тензора, вычисленные при записи в отношении любой обучаемой переменной.
  • tfe.gradients_function() принимает функцию (скажем, f()) и возвращает функцию градиента (скажем, fg()), которая может вычислять градиенты выходных данных f() в отношении параметров f() (или их подмножество).
  • tfe.implicit_gradients() очень похож, но fg() вычисляет градиенты выходных данных f() относительно всех обучаемых переменных, от которых зависят эти выходные данные.
  • tfe.implicit_value_and_gradients() почти идентичен, но fg() также возвращает вывод функции f().

Обычно в машинном обучении вам нужно вычислять градиенты потерь в зависимости от параметров модели (т. Е. Переменных), и вас, как правило, также интересует значение самой потери. Для этого варианта использования наиболее простыми и эффективными являются tf.GradientTape и tfe.implicit_value_and_gradients() (два других варианта не дают значения самой потери, поэтому, если она вам понадобится, для нее потребуются дополнительные вычисления). Я лично предпочитаю tfe.implicit_value_and_gradients() при написании рабочего кода и tf.GradientTape при экспериментах с ноутбуком Jupyter.

Редактировать : В TF 2.0 кажется, что остается только tf.GradientTape. Возможно, другие функции будут добавлены обратно, но я бы на это не рассчитывал.

Подробный пример

Давайте создадим небольшую функцию для выделения различий:

import tensorflow as tf
import tensorflow.contrib.eager as tfe
tf.enable_eager_execution()

w1 = tfe.Variable(2.0)
w2 = tfe.Variable(3.0)
​
def weighted_sum(x1, x2):
    return w1 * x1 + w2 * x2

s = weighted_sum(5., 7.)
print(s.numpy()) # 31

Использование tf.GradientTape

В контексте GradientTape все операции записываются, после чего вы можете вычислить градиенты любого тензора, вычисленного в контексте, в отношении любой обучаемой переменной. Например, этот код вычисляет s в контексте GradientTape, а затем вычисляет градиент s относительно w1. Начиная с s = w1 * x1 + w2 * x2, градиент s относительно w1 составляет x1:

with tf.GradientTape() as tape:
    s = weighted_sum(5., 7.)
​
[w1_grad] = tape.gradient(s, [w1])
print(w1_grad.numpy()) # 5.0 = gradient of s with regards to w1 = x1

Использование tfe.gradients_function()

Эта функция возвращает другую функцию, которая может вычислять градиенты возвращаемого значения функции относительно ее параметров. Например, мы можем использовать его для определения функции, которая будет вычислять градиенты s относительно x1 и x2:

grad_fn = tfe.gradients_function(weighted_sum)
x1_grad, x2_grad = grad_fn(5., 7.)
print(x1_grad.numpy()) # 2.0 = gradient of s with regards to x1 = w1

В контексте оптимизации было бы более разумно вычислять градиенты в зависимости от переменных, которые мы можем настроить. Для этого мы можем изменить функцию weighted_sum() так, чтобы она принимала в качестве параметров w1 и w2, и указать tfe.gradients_function(), чтобы она учитывала только параметры с именами "w1" и "w2":

def weighted_sum_with_weights(w1, x1, w2, x2):
    return w1 * x1 + w2 * x2

grad_fn = tfe.gradients_function(weighted_sum_with_weights, params=["w1", "w2"])
[w1_grad, w2_grad] = grad_fn(w1, 5., w2, 7.)
print(w2_grad.numpy()) # 7.0 = gradient of s with regards to w2 = x2

Использование tfe.implicit_gradients()

Эта функция возвращает другую функцию, которая может вычислять градиенты возвращаемого значения функции относительно всех обучаемых переменных, от которых она зависит. Возвращаясь к первой версии weighted_sum(), мы можем использовать ее для вычисления градиентов s по w1 и w2 без явной передачи этих переменных. Обратите внимание, что функция градиента возвращает список пар градиент / переменная:

grad_fn = tfe.implicit_gradients(weighted_sum)
[(w1_grad, w1_var), (w2_grad, w2_var)] = grad_fn(5., 7.)
print(w1_grad.numpy()) # 5.0 = gradient of s with regards to w1 = x1

assert w1_var is w1
assert w2_var is w2

Эта функция кажется самой простой и наиболее полезной опцией, поскольку, как правило, мы заинтересованы в вычислении градиентов потерь с учетом параметров модели (т. Е. Переменных). Примечание: попробуйте сделать w1 неотслеживаемым (w1 = tfe.Variable(2., trainable=False)) и переопределить weighted_sum(), и вы увидите, что grad_fn возвращает только градиент s относительно w2.

Использование tfe.implicit_value_and_gradients()

Эта функция почти идентична implicit_gradients(), за исключением того, что созданная ею функция также возвращает результат дифференцируемой функции (в данном случае weighted_sum()):

grad_fn = tfe.implicit_value_and_gradients(weighted_sum)
s, [(w1_grad, w1_var), (w2_grad, w2_var)] = grad_fn(5., 7.)
print(s.numpy()) # 31.0 = s = w1 * x1 + w2 * x2

Когда вам нужен как вывод функции, так и ее градиенты, эта функция может дать вам хороший прирост производительности, так как вы получаете выход функции бесплатно при вычислении градиентов с использованием автодифференцирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...