【问题标题】:How do you write a custom activation function in python for Keras?如何在 python 中为 Keras 编写自定义激活函数?
【发布时间】:2019-12-19 13:17:03
【问题描述】:

我正在尝试编写用于 Keras 的自定义激活函数。我不能用 tensorflow 原语编写它,因为它确实可以正确计算导数。我关注了How to make a custom activation function with only Python in Tensorflow?,它在创建张量流函数时非常有效。但是,当我尝试将其作为经典 MNIST 演示的激活函数放入 Keras 时。我有错误。我还尝试了上述参考中的tf_spiky 函数。

这里是示例代码

tf.keras.models.Sequential([
                      tf.keras.layers.Flatten(input_shape=(28, 28)),
                      tf.keras.layers.Dense(512, activation=tf_spiky),
                      tf.keras.layers.Dropout(0.2),
                      tf.keras.layers.Dense(10, activation=tf.nn.softmax)])

这是我的全部错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-48-73a57f81db19> in <module>
      3                       tf.keras.layers.Dense(512, activation=tf_spiky),
      4                       tf.keras.layers.Dropout(0.2),
----> 5                       tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
      6 x=tf.keras.layers.Activation(tf_spiky)
      7 y=tf.keras.layers.Flatten(input_shape=(28, 28))

/opt/conda/lib/python3.6/site-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
    472     self._setattr_tracking = False  # pylint: disable=protected-access
    473     try:
--> 474       method(self, *args, **kwargs)
    475     finally:
    476       self._setattr_tracking = previous_value  # pylint: disable=protected-access

/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/sequential.py in __init__(self, layers, name)
    106     if layers:
    107       for layer in layers:
--> 108         self.add(layer)
    109 
    110   @property

/opt/conda/lib/python3.6/site-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
    472     self._setattr_tracking = False  # pylint: disable=protected-access
    473     try:
--> 474       method(self, *args, **kwargs)
    475     finally:
    476       self._setattr_tracking = previous_value  # pylint: disable=protected-access

/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/sequential.py in add(self, layer)
    173       # If the model is being built continuously on top of an input layer:
    174       # refresh its output.
--> 175       output_tensor = layer(self.outputs[0])
    176       if isinstance(output_tensor, list):
    177         raise TypeError('All layers in a Sequential model '

/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
    728 
    729         # Check input assumptions set before layer building, e.g. input rank.
--> 730         self._assert_input_compatibility(inputs)
    731         if input_list and self._dtype is None:
    732           try:

/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in _assert_input_compatibility(self, inputs)
   1463         if x.shape.ndims is None:
   1464           raise ValueError('Input ' + str(input_index) + ' of layer ' +
-> 1465                            self.name + ' is incompatible with the layer: '
   1466                            'its rank is undefined, but the layer requires a '
   1467                            'defined rank.')

ValueError: Input 0 of layer dense_1 is incompatible with the layer: its rank is undefined, but the layer requires a defined rank.

据此,我收集到最后一个Dense 层无法在激活函数或类似的东西之后获得输出的尺寸。我确实在 tensorflow 代码中看到许多激活函数注册了一个形状。但要么我没有正确地做到这一点,要么我走错了方向。但我猜测需要对 tensorflow 函数做一些事情,使其成为 Keras 可以使用的激活函数。

如果您能提供任何帮助,我将不胜感激。

这里要求的是tf_spiky 的示例代码,它的工作原理如上述参考中所述。但是,一旦放入 Keras,我就会得到显示的错误。这与 *How to make a custom activation function with only Python in Tensorflow?" stackoverflow 文章中显示的差不多。

def spiky(x):
    print(x)
    r = x % 1
    if r <= 0.5:
        return r
    else:
        return 0
def d_spiky(x):
    r = x % 1
    if r <= 0.5:
        return 1
    else:
        return 0
np_spiky = np.vectorize(spiky)
np_d_spiky = np.vectorize(d_spiky)

np_d_spiky_32 = lambda x: np_d_spiky(x).astype(np.float32)
import tensorflow as tf
from tensorflow.python.framework import ops

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]

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)

def spikygrad(op, grad):
    x = op.inputs[0]

    n_gr = tf_d_spiky(x)
    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]

【问题讨论】:

标签: tensorflow keras neural-network deep-learning activation-function


【解决方案1】:

解决方法在这篇帖子Output from TensorFlow `py_func` has unknown rank/shape

最简单的解决方法是在tf_spiky 的定义中的return 语句之前添加y[0].set_shape(x.get_shape())

也许有人知道如何正确使用 tensorflow 形状函数。挖掘了一下,我在tensorflow.python.framework.common_shapes 中发现了一个unchanged_shape 形状函数,在这里很合适,但我不知道如何将它附加到tf_spiky 函数上。似乎这里有一个 python 装饰器。向其他人解释使用形状函数自定义张量流函数可能是一项服务。

【讨论】:

    猜你喜欢
    • 2017-12-21
    • 2019-01-16
    • 2020-05-29
    • 2017-10-10
    • 2018-08-30
    • 2019-11-28
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多