首页 > 解决方案 > 在 tensorflow r1.8 中使用 tf.custom_gradient

问题描述

系统信息

描述问题

您好,我正在尝试使用 tf.custom_gradient 的功能进行custom_gradient操作。我根据网上的API解释做了我的测试代码。但是,custom_gradient 函数似乎存在问题。谢谢!

源代码/日志

import tensorflow as tf
import numpy as np

@tf.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.log(1 + e), grad

x = tf.constant(100.)
f = tf.custom_gradient(log1pexp)

y, dy = f(x)

sess = tf.Session()
print (y.eval(session=sess), y.eval(session=sess).shape)

File "/home/local/home/research/DL/unit_tests/tf_test_custom_grad.py", line 14, in <module>
    y, dy = f(x)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/custom_gradient.py", line 111, in decorated
    return _graph_mode_decorator(f, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/custom_gradient.py", line 132, in _graph_mode_decorator
    result, grad_fn = f(*args)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/framework/ops.py", line 439, in __iter__
"Tensor objects are not iterable when eager execution is not "
TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn.

标签: tensorflow

解决方案


如果你只是想测试文档中的代码,这里是方法。

以下代码将给出不稳定的[nan]结果:

import tensorflow as tf

def log1pexp(x):
    return tf.log(1 + tf.exp(x))

x = tf.constant(100.)
y = log1pexp(x)
dy = tf.gradients(y, x)

with tf.Session() as sess:
    print(sess.run(dy))

以下代码将给出正确的结果[1.0]

import tensorflow as tf

@tf.custom_gradient
def log1pexp(x):
    e = tf.exp(x)
    def grad(dy):
        return dy * (1 - 1 / (1 + e))
    return tf.log(1 + e), grad

x = tf.constant(100.)
y = log1pexp(x)
dy = tf.gradients(y, x)

with tf.Session() as sess:
    print(sess.run(dy))

细节:

这里的主要问题是你试图log1pexp在你的代码中装饰两次:一次 with@tf.custom_gradient和一次 with f = tf.custom_gradient(log1pexp)。在python中,@tf.custom_gradient这里相当于log1pexp = tf.custom_gradient(log1pexp). 您应该只执行一次,尤其是在这里,原因如下。

tf.custom_gradient需要调用传递给它的函数以获得函数输出和梯度,即期望两个返回。在装修期间,一切都按预期工作,因为log1pexp退货tf.log(1 + e)grad。装饰后log1pexplog1pexp(由返回tf.custom_gradient)成为一个只返回一个张量的新函数tf.log(1 + e)。当你做f = tf.custom_gradient(log1pexp)装饰后log1pexptf.custom_gradient只能得到一个回报,即单张量tf.log(1 + e)。它将尝试通过迭代这个返回的张量来把这个张量分成两个。但这是错误的,并且不允许,如错误消息所述:

当未启用急切执行时,张量对象不可迭代。

无论如何,你不应该装饰log1pexp两次。但这就是您收到此错误的原因。还要提一件事,即使您删除了@tf.custom_gradient. 删除后@tf.custom_gradient,该行f = tf.custom_gradient(log1pexp)应按预期工作。但是f是一个只返回一个张量的函数。y, dy = f(x)是错误的,将不起作用。


推荐阅读