查看: 1432|回复: 0

如何在Tensorflow中仅使用Python自定义激活函数?

[复制链接]

27

主题

37

帖子

116

积分

论坛管理

Rank: 4

积分
116
发表于 2018-10-13 16:37:41 | 显示全部楼层 |阅读模式
本帖最后由 fantomas 于 2018-10-13 16:37 编辑

https://stackoverflow.com/questi ... ython-in-tensorflow

想要使用的激活函数为例:
构建一个函数
  1. def spiky(x):
  2.     r = x % 1
  3.     if r <= 0.5:
  4.         return r
  5.     else:
  6.         return 0
复制代码
向量化
  1. import numpy as np
  2. np_spiky = np.vectorize(spiky)
复制代码
激活的梯度:在我们的例子中它很简单,如果x mod 1 <0.5则为1,否则为0。所以:
  1. def d_spiky(x):
  2.     r = x % 1
  3.     if r <= 0.5:
  4.         return 1
  5.     else:
  6.         return 0
  7. np_d_spiky = np.vectorize(d_spiky)
复制代码
使一个numpy fct成为tensorflow fct:我们首先将np_d_spiky变成tensorflow函数。 tensorflow中有一个函数tf.py_func(func,inp,Tout,stateful = stateful,name = name)将任何numpy函数转换为tensorflow函数,因此我们可以使用它:
  1. import tensorflow as tf
  2. from tensorflow.python.framework import ops

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


  4. def tf_d_spiky(x,name=None):
  5.     with tf.name_scope(name, "d_spiky", [x]) as name:
  6.         y = tf.py_func(np_d_spiky_32,
  7.                         [x],
  8.                         [tf.float32],
  9.                         name=name,
  10.                         stateful=False)
  11.         return y[0]
复制代码
  1. def py_func(func, inp, Tout, stateful=True, name=None, grad=None):

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

  4.     tf.RegisterGradient(rnd_name)(grad)  # see _MySquareGrad for grad example
  5.     g = tf.get_default_graph()
  6.     with g.gradient_override_map({"PyFunc": rnd_name}):
  7.         return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
复制代码

现在我们差不多完成了,唯一的事情是我们需要传递给上面的py_func函数的grad函数需要采用一种特殊的形式。它需要在操作之前接受操作和先前的梯度,并在操作之后向后传播梯度。
  1. def spikygrad(op, grad):
  2.     x = op.inputs[0]

  3.     n_gr = tf_d_spiky(x)
  4.     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。或者我们可以使用tensorflow函数编写导数:
  1. def spikygrad2(op, grad):
  2.     x = op.inputs[0]
  3.     r = tf.mod(x,1)
  4.     n_gr = tf.to_float(tf.less_equal(r, 0.5))
  5.     return grad * n_gr  
复制代码
将它们结合在一起:
  1. np_spiky_32 = lambda x: np_spiky(x).astype(np.float32)

  2. def tf_spiky(x, name=None):

  3.     with tf.name_scope(name, "spiky", [x]) as name:
  4.         y = py_func(np_spiky_32,
  5.                         [x],
  6.                         [tf.float32],
  7.                         name=name,
  8.                         grad=spikygrad)  # <-- here's the call to the gradient
  9.         return y[0]
复制代码
Test:
  1. with tf.Session() as sess:

  2.     x = tf.constant([0.2,0.7,1.2,1.7])
  3.     y = tf_spiky(x)
  4.     tf.initialize_all_variables().run()

  5.     print(x.eval(), y.eval(), tf.gradients(y, [x])[0].eval())
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表