Я пытаюсь использовать функциональность TensorFlow @tf.custom_gradient
, чтобы назначить пользовательский градиент для функции с несколькими входами. Я могу собрать рабочую настройку только для одного входа, но не для двух или более.
Мой код основан на документации custom_gradient TensorFlow , которая прекрасно работает для одного ввода, как в этом примере:
import tensorflow as tf
import os
# Suppress Tensorflow startup info
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
# Custom gradient decorator on a function,
# as described in documentation
@tf.custom_gradient
def my_identity(x):
# The custom gradient
def grad(dy):
return dy
# Return the result AND the gradient
return tf.identity(x), grad
# Make a variable, run it through the custom op
x = tf.get_variable('x', initializer=1.)
y = my_identity(x)
# Calculate loss, make an optimizer, train the variable
loss = tf.abs(y)
opt = tf.train.GradientDescentOptimizer(learning_rate=0.001)
train = opt.minimize(loss)
# Start a TensorFlow session, initialize variables, train
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(train)
Этот пример работает без вывода сообщений, затем закрывается. Нет проблем, нет ошибок. Переменная оптимизируется, как и ожидалось. Однако в моем приложении мне нужно сделать такой расчет с несколькими входами, поэтому что-то из этого вида:
@tf.custom_gradient
def my_identity(x, z):
def grad(dy):
return dy
return tf.identity(x*z), grad
Выполнение этого вместо примера (и добавление другой переменной input к вызову my_identify
) приводит к следующему выводу ошибки. Насколько я могу судить, последние части ошибки связаны с динамическим генерированием операции - формат информации соответствует форматированию C ++, требуемому при создании операции (хотя это все, что я знаю об этом).
Traceback (most recent call last):
File "testing.py", line 27, in <module>
train = opt.minimize(loss)
File "/usr/lib/python3/dist-packages/tensorflow/python/training/optimizer.py", line 400, in minimize
grad_loss=grad_loss)
File "/usr/lib/python3/dist-packages/tensorflow/python/training/optimizer.py", line 519, in compute_gradients
colocate_gradients_with_ops=colocate_gradients_with_ops)
File "/usr/lib/python3/dist-packages/tensorflow/python/ops/gradients_impl.py", line 630, in gradients
gate_gradients, aggregation_method, stop_gradients)
File "/usr/lib/python3/dist-packages/tensorflow/python/ops/gradients_impl.py", line 821, in _GradientsHelper
_VerifyGeneratedGradients(in_grads, op)
File "/usr/lib/python3/dist-packages/tensorflow/python/ops/gradients_impl.py", line 323, in _VerifyGeneratedGradients
"inputs %d" % (len(grads), op.node_def, len(op.inputs)))
ValueError: Num gradients 2 generated for op name: "IdentityN"
op: "IdentityN"
input: "Identity"
input: "x/read"
input: "y/read"
attr {
key: "T"
value {
list {
type: DT_FLOAT
type: DT_FLOAT
type: DT_FLOAT
}
}
}
attr {
key: "_gradient_op_type"
value {
s: "CustomGradient-9"
}
}
do not match num inputs 3
Основываясь на других пользовательских параметрах градиента, я предположил, что проблема заключалась в отсутствии предоставленного градиента для второго входного аргумента. Итак, я изменил свою функцию следующим образом:
@tf.custom_gradient
def my_identity(x, z):
def grad(dy):
return dy
return tf.identity(x*z), grad, grad
Это приводит к следующей более знакомой ошибке:
Traceback (most recent call last):
File "testing.py", line 22, in <module>
y = my_identity(x, z)
File "/usr/lib/python3/dist-packages/tensorflow/python/ops/custom_gradient.py", line 111, in decorated
return _graph_mode_decorator(f, *args, **kwargs)
File "/usr/lib/python3/dist-packages/tensorflow/python/ops/custom_gradient.py", line 132, in _graph_mode_decorator
result, grad_fn = f(*args)
ValueError: too many values to unpack (expected 2)
Декоратор @custom_gradient
идентифицирует только последний возвращенный элемент как градиент. Итак, я попытался поместить два градиента в кортеж как (grad, grad)
так, чтобы для функции было только «два» выхода. TensorFlow также отклонил это, на этот раз, потому что он не может вызвать кортеж, как если бы это был Tensor - вполне разумно, оглядываясь назад.
Я возился с примером еще немного, но безрезультатно. Независимо от того, что я пытаюсь, я не могу получить пользовательский градиент для работы с несколькими входами. Я надеюсь, что кто-то с большим знанием, чем я, относительно пользовательских операций и градиентов, получит лучшее представление об этом - заранее спасибо за помощь!