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

时间:2016-08-19 23:31:33

标签: python tensorflow neural-network gradient-descent

我想在python中编写TensorFlow操作,但我希望它是可微分的(能够计算渐变)。

这个问题询问如何在python中编写op,答案建议使用py_func(没有渐变):Tensorflow: Writing an Op in Python

TF文档描述了如何仅从C ++代码添加操作:https://www.tensorflow.org/versions/r0.10/how_tos/adding_an_op/index.html

在我的情况下,我正在进行原型设计,所以我不关心它是否在GPU上运行,我不关心它是否可用于TF python API以外的其他任何东西。

2 个答案:

答案 0 :(得分:11)

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

Modulo opperation:让我们在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默认值),它会抱怨。

渐变函数:接下来,我们需要为opperation的每个输入定义我们的opperation的渐变函数作为tensorflow函数。该功能需要采取非常具体的形式。它需要采用opperation op的张量流表示和输出grad的渐变,并说明如何传播渐变。在我们的例子中,mod操作的梯度很容易,相对于第一个参数,导数是1, enter image description here关于第二个(几乎无处不在,在有限数量的点上无限,但让我们忽略它,详见https://math.stackexchange.com/questions/1849280/derivative-of-remainder-function-wrt-denominator)。所以我们有

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.RegisterGradient [doc]和{{1来定义函数的渐变是一种黑客攻击}} [doc]

harpone复制代码,我们可以修改tf.Graph.gradient_override_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) 选项是告诉tensorflow函数是否总是为同一输入提供相同的输出(stateful = False),在这种情况下,tensorflow可以简单地是张量流图,这是我们的情况,可能是大多数情况下的情况。

将它们组合在一起:现在我们已经拥有了所有部分,我们可以将它们组合在一起:

stateful

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] 对张量列表进行操作(并返回张量列表),这就是我们tf.py_func(并返回[x,y])的原因。 现在我们完成了。我们可以测试它。

<强>测试

z[0]
  

[0.30000001 0.69999999 1.20000005 1.70000005] [0.2 0.5 1. 2.9000001] [0.10000001 0.19999999 0.20000005 1.70000005] [1. 1. 1. 1.] [-1。 -1。 -1。 0。]

成功!

答案 1 :(得分:4)

以下是向特定select l1, l2, max(date) from a group by l1, l2 having max(date) < date '9999-12-31'; 添加渐变的示例 https://gist.github.com/harpone/3453185b41d8d985356cbe5e57d67342

问题discussion