从NumPy版本构建Tensorflow中的Softmax衍生版

时间:2017-03-21 17:17:28

标签: python numpy tensorflow

我对在Tensorflow中构建Softmax的衍生产品感兴趣,并且作为新用户我感到困惑。

我能找到的最接近的代码是NumPy版本Softmax derivative in NumPy approaches 0 (implementation)。代码如下。我能够轻松地将softmax部分转换为张量流,但我仍然坚持如何将导数部分应用于张量流 - 在"以及"如果衍生"给我带来麻烦。您将如何构建衍生部分的三条线?

谢谢。

衍生部分

if derivative:
    J = - signal[..., None] * signal[:, None, :] # off-diagonal Jacobian
    iy, ix = np.diag_indices_from(J[0])
    J[:, iy, ix] = signal * (1. - signal) # diagonal
    return J.sum(axis=1)

以下是上述链接的完整代码。

def softmax_function( signal, derivative=False ):
    # Calculate activation signal
    e_x = np.exp( signal )
    signal = e_x / np.sum( e_x, axis = 1, keepdims = True )
    if derivative:
        J = - signal[..., None] * signal[:, None, :] # off-diagonal Jacobian
        iy, ix = np.diag_indices_from(J[0])
        J[:, iy, ix] = signal * (1. - signal) # diagonal
        return J.sum(axis=1)
    else:
        # Return the activation signal
        return signal

3 个答案:

答案 0 :(得分:1)

我最近处于这种情况并且找不到多少帮助,特别是在提取对角线元素以更新i = j场景时。

一个可能的原因可能是缺乏像tensorflow中的多功能性那样的numpy。

看看下面两个替代方案是否适合您,

  1. 在numpy中实现派生部分,并在feed_dict内的会话中动态调用该函数,
  2. 在图表中定义占位符

    derivative = tf.placeholder(tf.float32,[None,num_features])

    考虑到你的softmax概率存储在一个名为'output'的变量中

    然后在你的会话中你可以这样做,

    session.run(train,feed_dict {derivative:softmax(output.eval(),deriv = True)})

    注意:此方法的计算成本可能很高。

    1. 了解特定衍生物背后的数学
    2. 损失函数,

            L= -1/N  ∑ yk.log⁡(pk)
      

      根据连锁规则,

            ∂L/∂W2 = ∂L/dpi .∂pi/∂a2 .∂a2/dW2
      

      其中L是损失函数        p是概率输出

      通过计算两个案例的链规则中的前两个项,k = i和k!= i,将其简化为下面的术语,

         ∂L/dpi . ∂pi/∂a2 = pi-yi  --- > delta value for the output layer.
      

      所以你可以简单地通过从前传播的softmax输出中减去你的目标而不是复杂的雅可比矩阵方法来计算你的l2_delta。

      查看这些链接,了解有关此背后数学的更多信息,

      为什么softmax衍生物不像任何其他激活那样简单的优秀解释 - > Derivative of a softmax function

      PDF解释答案PDF

      中描述的简化步骤

答案 1 :(得分:1)

我的代码有几个注释:

  • Tensorflow基于计算图,因此无需手动计算梯度。在纯粹的numpy中做这件事是完全没问题的,只是为了让你知道。

  • 您的softmax正向计算是正确的,但可能在数值上不稳定。简而言之,划分非常大的值会导致精度损失,因此在计算指数之前最好减去signal的最大值:

    stable_signal = signal - np.max(signal)
    e_x = np.exp(stable_signal)
    signal = e_x / np.sum(e_x, axis=1, keepdims=True)
    

    有关详细信息,请参阅this post中的“实际问题:数字稳定性”部分。

  • Softmax衍生物本身有点毛茸茸。计算来自softmax层的后向信号更有效(也更容易),即信号的交叉熵损失的导数。为此,您需要将正确的标签y传递给softmax_function。然后计算如下:

    sums_per_row = np.sum(exponents, axis=1, keepdims=True)  # can also reuse with the forward pass
    all_softmax_matrix = (e_x.T / sums_per_row).T
    grad_coeff = np.zeros_like(signal)
    grad_coeff[np.arange(num_train), y] = -1
    grad_coeff += all_softmax_matrix
    return grad_coeff
    

    如果您不确定为何如此容易,请查看these brilliant notes

答案 2 :(得分:0)

您可以直接在 tensorflow 中编写您的导数部分,如下所示:

#Assuming signal is a tensor created in tensorflow.
if derivative:
   J = - signal[..., None] * signal[:, None, :] # off-diagonal Jacobian
   J = tf.linalg.set_diag(J, signal * (1. - signal))# diagonal
   return tf.reduce_sum(J,1)