tensorflow使用python_如何在Tensorflow中仅使用Python制作自定义激...

就在这里!

信用:

很难找到信息并使其正常工作,但这里有一个例子,复制了here和here中找到的原则和代码.

要求:

在我们开始之前,有两个要求才能成功.首先,您需要能够将激活编写为numpy数组上的函数.其次,您必须能够将该函数的派生函数作为Tensorflow中的函数(更简单)或最坏情况下编写为numpy数组上的函数.

写入激活功能:

那么让我们以我们想要使用激活函数的函数为例:

def spiky(x):

r = x % 1

if r <= 0.5:

return r

else:

return 0

其外观如下:

第一步是将它变成一个numpy函数,这很容易:

import numpy as np

np_spiky = np.vectorize(spiky)

现在我们应该写出它的衍生物.

激活梯度:

在我们的例子中它很容易,如果x mod 1 <1则为1.否则为0.5和0.所以:

def d_spiky(x):

r = x % 1

if r <= 0.5:

return 1

else:

return 0

np_d_spiky = np.vectorize(d_spiky)

现在为了制作TensorFlow功能的困难部分.

为一个张量流fct制作一个numpy fct:

我们将首先将np_d_spiky转换为tensorflow函数. tensorflow中有一个函数tf.py_func(func,inp,Tout,stateful = stateful,name = name)[doc]将任何numpy函数转换为tensorflow函数,因此我们可以使用它:

import tensorflow as tf

from tensorflow.python.framework import ops

np_d_spiky_32 = lambda x: np_d_spiky(x).astype(np.float32)

def tf_d_spiky(x,name=None):

with tf.name_scope(name, "d_spiky", [x]) as name:

y = tf.py_func(np_d_spiky_32,

[x],

[tf.float32],

name=name,

stateful=False)

return y[0]

tf.py_func作用于张量列表(并返回张量列表),这就是为什么我们有[x](并返回y [0]).有状态选项是告诉tensorflow函数是否总是为同一输入提供相同的输出(stateful = False),在这种情况下,tensorflow可以简单地是张量流图,这是我们的情况,在大多数情况下可能就是这种情况.此时要注意的一件事是numpy使用float64但是tensorflow使用float32所以你需要将你的函数转换为使用float32,然后才能将它转换为tensorflow函数,否则tensorflow会抱怨.这就是我们需要先制作np_d_spiky_32的原因.

渐变怎么样?仅执行上述操作的问题在于,即使我们现在有tf_d_spiky是np_d_spiky的张量流版本,但是如果我们想要的话,我们也不能将它用作激活函数,因为tensorflow不知道如何计算它的渐变功能.

Hack获取渐变:正如上面提到的来源中所解释的那样,使用tf.RegisterGradient [doc]和tf.Graph.gradient_override_map [doc]定义函数的渐变有一个hack.从harpone复制代码我们可以将tf.py_func函数修改为让它同时定义渐变:

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)

现在我们差不多完成了,唯一的事情就是我们需要传递给上面的py_func函数的grad函数需要采用一种特殊的形式.它需要在操作之前进行操作和先前的渐变,并在操作之后向后传播渐变.

渐变功能:因此对于我们的尖刺激活功能,我们将如何做到:

def spikygrad(op, grad):

x = op.inputs[0]

n_gr = tf_d_spiky(x)

return grad * n_gr

激活函数只有一个输入,这就是x = op.inputs [0]的原因.如果操作有很多输入,我们需要返回一个元组,每个输入一个渐变.例如,如果操作是a-b相对于a的梯度是1并且相对于b是-1,那么我们将返回1 * grad,-1 * grad.请注意,我们需要返回输入的tensorflow函数,这就是为什么需要tf_d_spiky,np_d_spiky不起作用,因为它不能对张量流张量起作用.或者我们可以使用tensorflow函数编写导数:

def spikygrad2(op, grad):

x = op.inputs[0]

r = tf.mod(x,1)

n_gr = tf.to_float(tf.less_equal(r, 0.5))

return grad * n_gr

将它们结合在一起:既然我们拥有所有的部分,我们可以将它们组合在一起:

np_spiky_32 = lambda x: np_spiky(x).astype(np.float32)

def tf_spiky(x, name=None):

with tf.name_scope(name, "spiky", [x]) as name:

y = py_func(np_spiky_32,

[x],

[tf.float32],

name=name,

grad=spikygrad) #

return y[0]

现在我们完成了.我们可以测试一下.

测试:

with tf.Session() as sess:

x = tf.constant([0.2,0.7,1.2,1.7])

y = tf_spiky(x)

tf.initialize_all_variables().run()

print(x.eval(), y.eval(), tf.gradients(y, [x])[0].eval())

[ 0.2 0.69999999 1.20000005 1.70000005] [ 0.2 0. 0.20000005 0.] [ 1. 0. 1. 0.]

成功!

你可能感兴趣的:(tensorflow使用python_如何在Tensorflow中仅使用Python制作自定义激...)