Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Tensorflow:如何在python中使用渐变编写op?_Python_Tensorflow_Neural Network_Gradient Descent - Fatal编程技术网

Tensorflow:如何在python中使用渐变编写op?

Tensorflow:如何在python中使用渐变编写op?,python,tensorflow,neural-network,gradient-descent,Python,Tensorflow,Neural Network,Gradient Descent,我想用python编写一个TensorFlow op,但我希望它是可微的(能够计算梯度) 这个问题询问如何用python编写op,答案建议使用py_func(没有渐变): > TF文档描述了如何仅从C++代码中添加OP: 在我的例子中,我正在进行原型设计,所以我不关心它是否在GPU上运行,也不关心它是否可以从TF python API以外的任何地方使用。下面是一个向特定的py_func 这是一个问题是的,正如@Yaroslav的回答中提到的,这是可能的,关键是他引用的链接:和。我想通过一个具

我想用python编写一个TensorFlow op,但我希望它是可微的(能够计算梯度)

这个问题询问如何用python编写op,答案建议使用py_func(没有渐变):

<> > TF文档描述了如何仅从C++代码中添加OP:


在我的例子中,我正在进行原型设计,所以我不关心它是否在GPU上运行,也不关心它是否可以从TF python API以外的任何地方使用。

下面是一个向特定的
py_func


这是一个问题

是的,正如@Yaroslav的回答中提到的,这是可能的,关键是他引用的链接:和。我想通过一个具体的例子来详细说明这个答案

模运算:让我们在tensorflow中实现元素级模运算(它已经存在,但它的梯度尚未定义,但在本例中,我们将从头开始实现)

Numpy函数:第一步是定义我们想要的Numpy阵列操作。元素方式的模运算已经在numpy中实现,因此很容易:

import numpy as np
def np_mod(x,y):
    return (x % y).astype(np.float32)
之所以使用
.astype(np.float32)
,是因为默认情况下tensorflow采用float32类型,如果您给它float64(numpy默认值),它会抱怨

梯度函数:接下来,我们需要为操作的每个输入定义梯度函数作为tensorflow函数。函数需要采用非常具体的形式。它需要获取opOperation
op
的tensorflow表示和输出
grad
的梯度,并说明如何传播梯度。在我们的例子中,
mod
运算的梯度很容易,相对于第一个参数和 关于第二个(几乎到处都是,在有限数量的点上是无限的,但我们忽略这一点,请参阅了解详细信息)。所以我们有

def modgrad(op, grad):
    x = op.inputs[0] # the first argument (normally you need those to calculate the gradient, like the gradient of x^2 is 2x. )
    y = op.inputs[1] # the second argument

    return grad * 1, grad * tf.neg(tf.floordiv(x, y)) #the propagated gradient with respect to the first and second argument respectively
grad函数需要返回一个n元组,其中n是操作的参数数。注意,我们需要返回输入的tensorflow函数

使用梯度创建TF函数:如上文提到的源代码所述,有一种使用
TF.registerGradent
TF.Graph.grade\u override\u map
定义函数梯度的方法

从中复制代码,我们可以修改
tf.py_func
函数,使其同时定义渐变:

import tensorflow as tf

def py_func(func, inp, Tout, stateful=True, name=None, grad=None):

    # Need to generate a unique name to avoid duplicates:
    rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))

    tf.RegisterGradient(rnd_name)(grad)  # see _MySquareGrad for grad example
    g = tf.get_default_graph()
    with g.gradient_override_map({"PyFunc": rnd_name}):
        return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
stateful
选项是告诉tensorflow函数是否总是为相同的输入提供相同的输出(stateful=False),在这种情况下tensorflow可以简单地绘制tensorflow图,这是我们的情况,在大多数情况下可能都是这样

将其组合在一起:现在我们有了所有的片段,我们可以将它们组合在一起:

from tensorflow.python.framework import ops

def tf_mod(x,y, name=None):

    with ops.op_scope([x,y], name, "mod") as name:
        z = py_func(np_mod,
                        [x,y],
                        [tf.float32],
                        name=name,
                        grad=modgrad)  # <-- here's the call to the gradient
        return z[0]
[0.3000001 0.69999999 1.2000005 1.70000005][0.20.51.2.90000001][0.10000001 0.19999999 0.2000005 1.70000005][1.1.1.][-1.-1.-1.-1.0.]


成功

谢谢,这个要点确实回答了问题。主要是调用tf.RegisterGradient(),然后调用gradient\u override\u map()。正如他们在这个问题上提到的那样,这是一种非常骇人的方法,因为它依赖于给函数命名,但这似乎是目前唯一的方法。再次感谢!非常感谢这篇文章!你有没有办法告诉Tensorflow
z
的形状
x
具有形状(4),
y
具有形状(4),但Tensorflow不知道
z
具有形状(4)。只有在运行时,它才会解析形状为4。您确定渐变正确吗?谢谢回答得很好。正如一个旁注,如果你计划将图表序列化(例如,以后以C++运行),则不能使用代码> Tf.PyFunc < /Cord>。在这种情况下,您仍然可以定义一个OP梯度,但它更复杂,因为您必须在C++中完成。“这里有更多的信息,@patapouúai谢谢你的回答。”。我还需要grad函数中输入的numpy版本,因此我在
modgrad
中调用
op.inputs[0].eval()
。所以我的问题是,是否也可以在grad函数中实现numpy中的所有内容?啊,好的,我应该将grad函数包装到
tf.py_func
中。
with tf.Session() as sess:

    x = tf.constant([0.3,0.7,1.2,1.7])
    y = tf.constant([0.2,0.5,1.0,2.9])
    z = tf_mod(x,y)
    gr = tf.gradients(z, [x,y])
    tf.initialize_all_variables().run()

    print(x.eval(), y.eval(),z.eval(), gr[0].eval(), gr[1].eval())