在TensorFlow中实现重载步骤功能

时间:2018-04-12 12:45:56

标签: python tensorflow machine-learning

我想在TensorFlow中创建heavyiside步骤功能。由于Heaviside函数不可微分,我还需要选择导数近似并定义自定义渐变,因此完全实现如下所示:

import tensorflow as tf


@tf.RegisterGradient("HeavisideGrad")
def _heaviside_grad(unused_op: tf.Operation, grad: tf.Tensor):
    x = unused_op.inputs[0]
    # During backpropagation heaviside behaves like sigmoid
    return tf.sigmoid(x) * (1 - tf.sigmoid(x)) * grad


def heaviside(x: tf.Tensor, g: tf.Graph = tf.get_default_graph()):
    custom_grads = {
        "Sign": "HeavisideGrad"
    }
    with g.gradient_override_map(custom_grads):
        # TODO: heaviside(0) currently returns 0. We need heaviside(0) = 1
        sign = tf.sign(x)
        # tf.stop_gradient is needed to exclude tf.maximum from derivative
        step_func = sign + tf.stop_gradient(tf.maximum(0.0, sign) - sign)
        return step_func

我的实现中有一个警告:tf.sign(0)返回零值,因此heaviside(0)也返回零,我希望heaviside(0)返回1.我怎样才能实现这样的行为?

4 个答案:

答案 0 :(得分:1)

一种非常黑客的方法是使用

1 - max(0.0, sign(-x)) 

作为步骤功能而不是

max(0.0, sign(x))

另一种选择是使用greater_equal并将结果转换为所需类型,并使用已有的sigmoid覆盖覆盖其渐变。

答案 1 :(得分:0)

最简单的代码修复方法是在tf.sign()的结果中添加一个小数字并再次取符号。这将导致获得1为0:

sign = tf.sign ( tf.sign( x ) + 0.1 )

答案 2 :(得分:0)

好的,我想我已经明白了。非常感谢etarion指出解决问题的正确方法。

所以基本的想法是使用tf.greater_equal而不是tf.signmaximum的组合。自定义渐变应用于tf.identity操作。

以下是重载功能的更新实现:

import tensorflow as tf

@tf.RegisterGradient("HeavisideGrad")
def _heaviside_grad(unused_op: tf.Operation, grad: tf.Tensor):
    return tf.maximum(0.0, 1.0 - tf.abs(unused_op.inputs[0])) * grad


def heaviside(x: tf.Tensor, g: tf.Graph = tf.get_default_graph()):
    custom_grads = {
        "Identity": "HeavisideGrad"
    }
    with g.gradient_override_map(custom_grads):
        i = tf.identity(x, name="identity_" + str(uuid.uuid1()))
        ge = tf.greater_equal(x, 0, name="ge_" + str(uuid.uuid1()))
        # tf.stop_gradient is needed to exclude tf.to_float from derivative
        step_func = i + tf.stop_gradient(tf.to_float(ge) - i)
        return step_func

答案 3 :(得分:0)

这将使单元步进功能仅使用TensorFlow API,因此结果仍然是张量:

#in Eager mode
def heaviside(v):
  return 1-tf.reduce_max(tf.constant([0,-tf.sign(v).numpy()], tf.float32));