I have provided three different ways of defining custom gradients in Tensorflow in this repo.
custom_gradient_with_py_func
In this approach we define a tf op using tf.py_func and assign a custom gradient function to it.
with g.gradient_override_map({"PyFunc": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
custom_gradient_with_python:
In this approach we use a workaround to define a custom gradient for a composition of Tensorflow ops. We override the gradient of the identity op.
def python_func(x_in, name=None):
with ops.name_scope(name):
backward_func = tf.identity(x_in) # We'll later override the gradient of identity to deflect our desired gradient function.
forward_func = tf.subtract(2 * tf.exp(x_in), x_in)
return backward_func + tf.stop_gradient(forward_func - backward_func)
def my_op(func, inp, grad, name=None, victim_op='Identity'):
# Need to generate a unique name to avoid duplicates.
rnd_name = 'my_gradient' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad)
g = tf.get_default_graph()
with g.gradient_override_map({victim_op: rnd_name}):
return func(inp, name=name)
custom_gradient_with_eager:
This approach uses tensorflow.contrib.eager available as of Tensorflow 1.5 to define custom gradients for a composition of tensorflow ops.
@tfe.custom_gradient
def python_func(x_in):
def grad_func(grad):
return grad * ((2 * tf.exp(x_in)) - 1)
forward_func = tf.subtract(2 * tf.exp(x_in), x_in)
return forward_func, grad_func