【问题标题】:what activation function should I use to enforce rounding like behaviour我应该使用什么激活函数来强制执行舍入行为
【发布时间】:2019-01-14 22:18:14
【问题描述】:

我需要一个对我的张量进行四舍五入的激活函数。

函数 round() 的导数(梯度)为 0(或在 tensorflow 中为 None),这使得它无法用作激活函数。

我正在寻找一个强制类似舍入行为的函数,以便我的模型的结果不只是近似一个数字。 (因为我的标签是整数)

我知道公式:tanh ○ sigmoid 用于强制 {-1, 0, 1} 数字仅流经模型,所以是否有一些可导出的函数组合来模拟舍入行为?

【问题讨论】:

  • @PMende 舍入本质上是 non-differntiable。完全不同意 OP 可以以某种方式编写一个有意义的函数来做到这一点。他/她最好的机会是对结果进行四舍五入,然后使用某种MSE/Huber Loss 函数
  • 舍入函数不可微分。可微函数尤其是连续的,如果绘制舍入函数,您会发现它是不连续的。
  • @PMende 嗯? ReLU 指定 0 处的导数(它只是不可微分的点)为0。这不是数学 - 这是习惯。 round 没有这种方法可以做到这一点(处处为零是你能做的最好的),如果你考虑一下/知道介绍性微积分,那就很清楚了。
  • @modesitt 如果您考虑一下,并理解高级微积分和分布的概念,那么很明显存在导数。将分布用作函数在简单的应用程序中不起作用,但如果这确实是所需的行为,则可以创建近似值。
  • @modesitt round 的导数是 Dirac 梳,频率为 1,相位为 0.5。每个狄拉克三角函数都可以看作是高斯变得无限薄和无限高的极限。如果您想要舍入行为以及此类函数的梯度,您可以为您的归一化高斯选择一些适当的方差。请注意,我并不是说这会在计算上高效,但如果它真的是某人想要的,它是可行的。

标签: python tensorflow neural-network derivative activation-function


【解决方案1】:

如果您想在实线上进行近似圆形,您可以执行以下操作:

def approx_round(x, steepness=1):
    floor_part = tf.floor(x)
    remainder = tf.mod(x, 1)
    return floor_part + tf.sigmoid(steepness*(remainder - 0.5))

事实上,有一些方法可以在 Tensorflow 中注册您自己的渐变(例如,参见 this question)。但是,我对实现这部分不太熟悉,因为我不经常使用 Keras/TensorFlow。

就一个函数而言,它会给你这个近似值的梯度,它将是以下内容:

def approx_round_grad(x, steepness=1):
    remainder = tf.mod(x, 1)
    sig = tf.sigmoid(steepness*(remainder - 0.5))
    return sig*(1 - sig)

为了清楚起见,这个近似值假设您使用的是“足够陡峭”steepness 参数,因为 sigmoid 函数不会精确到 0 或 1,除非在大参数的限制。

要进行半正弦近似,您可以使用以下方法:

def approx_round_sin(x, width=0.1):
    if width > 1 or width <= 0:
        raise ValueError('Width must be between zero (exclusive) and one (inclusive)')
    floor_part = tf.floor(x)
    remainder = tf.mod(x, 1)
    return (floor_part + clipped_sin(remainder, width))

def clipped_sin(x, width):
    half_width = width/2
    sin_part = (1 + tf.sin(np.pi*((x-0.5)/width)))/2
    whole = sin_part*tf.cast(tf.abs(x - 0.5) < half_width, tf.float32)
    whole += tf.cast(x > 0.5 + half_width, tf.float32)
    return whole

def approx_round_grad_sin(x, width=0.1):
    if width > 1 or width <= 0:
        raise ValueError('Width must be between zero (exclusive) and one (inclusive)')
    remainder = tf.mod(x, 1)
    return clipped_cos(remainder, width)

def clipped_cos(x, width):
    half_width = width/2
    cos_part = np.pi*tf.cos(np.pi*((x-0.5)/width))/(2*width)
    return cos_part*tf.cast(tf.abs(x - 0.5) < half_width, dtype=tf.float32)

【讨论】:

  • 由于我对 Keras/Tensorflow API 不是很熟悉,因此我很难提供有关封装此功能的建议。原则上,您可能希望以某种方式定义函数,这样您就不必确保将steepness 超参数始终传递给基函数及其梯度。例如,您可以通过定义一个返回基函数及其梯度作为元组的第三个函数来实现这一点。
  • 小心。您的函数也不能在整数值处微分。
  • @Tissuebox 它的工作原理近似于圆形函数,是的,但从数学上讲它是不可微的。请阅读可微的正式定义。
  • @Tissuebox 太酷了!很高兴听到它对你来说是成功的。事实上,在训练数据的支持之外不进行泛化是中性网络中的一个常见问题。听到您的架构在您的训练数据范围之外工作很有趣!尽管考虑到激活函数的性质及其“导数”,但它对我来说还是有点直观的感觉。如果您发表论文,请随时在致谢中提及我。 :P
  • 我应该明确地说,如果您使用有界激活函数,神经网络通常很难在训练数据范围之外进行泛化。
【解决方案2】:

也许使用 softmax 函数 tf.nn.softmax_cross_entropy_with_logits_v2 的交叉熵损失是您正在寻找的,请参阅

https://www.tensorflow.org/api_docs/python/tf/nn/softmax_cross_entropy_with_logits_v2

也可以看看

https://deepnotes.io/softmax-crossentropy

【讨论】:

  • 除非我误解了 deepnotes 链接中所说的内容,否则此损失函数对于开放域整数(这是我的标签的一部分)并不是最好的
  • 开域整数是什么意思?如果您的意思是您可以将任何整数作为标签,那么我认为您不会找到任何合适的损失函数。当您将模型拟合到数据集时,您应该已经拥有所有可用的标签。否则配件部分首先没有意义
  • 好吧,我不是在寻找损失函数,而是在寻找激活函数
猜你喜欢
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 2011-01-03
  • 1970-01-01
  • 2013-07-21
  • 2023-03-13
相关资源
最近更新 更多