如何在Tensorflow中仅使用Python创建自定义激活函数?
假设您需要创建一个激活函数,而仅使用预定义的tensorflow构建块是不可能的,您可以做什么 因此,在Tensorflow中,可以创建自己的激活函数。但是它相当复杂,你必须用C++编写,重新编译整个TysFooS.<如何在Tensorflow中仅使用Python创建自定义激活函数?,python,tensorflow,neural-network,deep-learning,activation-function,Python,Tensorflow,Neural Network,Deep Learning,Activation Function,假设您需要创建一个激活函数,而仅使用预定义的tensorflow构建块是不可能的,您可以做什么 因此,在Tensorflow中,可以创建自己的激活函数。但是它相当复杂,你必须用C++编写,重新编译整个TysFooS.< 有更简单的方法吗?是的,有 积分: 很难找到信息并使其正常工作,但下面是一个从原理和代码中复制的示例 要求: 在我们开始之前,这需要两个条件才能成功。首先,您需要能够将激活作为函数写入numpy阵列。其次,您必须能够将该函数的导数编写为Tensorflow中的函数(更容易),或者
有更简单的方法吗?是的,有强> 积分: 很难找到信息并使其正常工作,但下面是一个从原理和代码中复制的示例 要求: 在我们开始之前,这需要两个条件才能成功。首先,您需要能够将激活作为函数写入numpy阵列。其次,您必须能够将该函数的导数编写为Tensorflow中的函数(更容易),或者在最坏的情况下编写为numpy数组中的函数 写入激活功能:
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())
让我们以这个函数为例,我们希望使用一个激活函数:
def spiky(x):
r = x % 1
if r <= 0.5:
return r
else:
return 0
现在我们应该写出它的导数
激活梯度:
在我们的例子中很容易,如果x mod 1<0.5,则为1,否则为0。因此:
def d_spiky(x):
r = x % 1
if r <= 0.5:
return 1
else:
return 0
np_d_spiky = np.vectorize(d_spiky)
tf.py\u func
作用于张量列表(并返回张量列表),这就是为什么我们有[x]
(并返回y[0]
)。stateful
选项是告诉tensorflow函数是否总是为相同的输入提供相同的输出(stateful=False),在这种情况下tensorflow可以简单地绘制tensorflow图,这是我们的情况,在大多数情况下可能都是这样。此时需要注意的一点是,numpy使用了float64
,但tensorflow使用了float32
,因此您需要先将函数转换为使用float32
,然后才能将其转换为tensorflow函数,否则tensorflow会抱怨。这就是为什么我们需要首先制作np_d_spiky_32
梯度呢?只做上述操作的问题是,尽管我们现在有了tf_d_spiky
,这是np_d_spiky
的tensorflow版本,但如果我们想要,我们不能将其用作激活函数,因为tensorflow不知道如何计算该函数的梯度
获取梯度的方法:如上所述,可以使用tf.registerGradent
和tf.Graph.grade\u override\u map
定义函数的梯度。从中复制代码,我们可以修改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函数的梯度函数需要采用一种特殊形式。它需要接受一个操作,以及操作之前的渐变,并在操作之后向后传播渐变
梯度函数:因此,对于我们的尖峰激活函数,我们将这样做:
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*梯度,-1*梯度
。请注意,我们需要返回输入的tensorflow函数,这就是为什么needtf_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) # <-- here's the call to the gradient
return y[0]
[0.20.699999 1.2000005 1.70000005][0.20.0.2000005 0.][1.0.1.0.]
成功为什么不简单地使用tensorflow中已有的函数来构建新函数呢 对于中的
spiky
函数,可以如下所示
def spiky(x):
r = tf.floormod(x, tf.constant(1))
cond = tf.less_equal(r, tf.constant(0.5))
return tf.where(cond, r, tf.constant(0))
我会认为这要简单得多(甚至不需要计算任何梯度),除非你想做一些奇异的事情,我几乎无法想象TySoFrof不能为构建高度复杂的激活函数提供构建块。但如果你告诉我们你想创建什么样的激活函数(函数族),也许有人能帮助你。@lahwran这并不是你想在现实生活中使用的激活函数。这只是一个如何实现自定义激活功能的示例,如果你需要的话。是的,它可以工作:)但我没有尝试在实际的学习问题中使用网络it,我需要制作一个比我的目的更复杂的激活功能,但是在这里的帖子里,我只放了一个玩具激活功能,我并没有试着用它来学习。太棒了!注意:对于当前希望使用您的方法的用户,您应该将op.scope替换为tf.name\u scope,因为前者已被弃用。op.scope的参数顺序如下:op.scope(值,名称,“default_name”),而tf.name_scope的参数顺序是tf.name_scope(名称,default_名称,值),因此应该使用tf.name_scope(名称,“spiky”,[x])@patapouf\u TensorFlow在自定义函数上使用GPU加速吗?也就是说,这种激活是否会并行应用于CUDA内核中的许多张量元素?@patapouf_ai对创建自定义张量流函数的最清晰解释,我迄今为止已经看过了-谢谢!是的,的确,spiky可以用tf原语来完成,但是spiky只是一个简单的例子,不会被复杂性搞糊涂
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())
def spiky(x):
r = tf.floormod(x, tf.constant(1))
cond = tf.less_equal(r, tf.constant(0.5))
return tf.where(cond, r, tf.constant(0))