关于矩阵的张量流梯度

Tensorflow gradient with respect to matrix

仅供参考,我正在尝试使用 Tensorflow 实现梯度下降算法。

我有一个矩阵X

[ x1 x2 x3 x4 ]
[ x5 x6 x7 x8 ]

我将其乘以一些特征向量 Y 得到 Z

      [ y1 ]
Z = X [ y2 ]  = [ z1 ]
      [ y3 ]    [ z2 ]
      [ y4 ]

然后我把Z通过一个softmax函数,取对数。我将输出矩阵称为 W.

所有这些都是按如下方式实现的(添加了一点样板,因此它可以运行)

sess = tf.Session()
num_features = 4
num_actions = 2

policy_matrix = tf.get_variable("params", (num_actions, num_features))
state_ph = tf.placeholder("float", (num_features, 1))
action_linear = tf.matmul(params, state_ph)
action_probs = tf.nn.softmax(action_linear, axis=0)
action_problogs = tf.log(action_probs)

W(对应action_problogs)看起来像

[ w1 ]
[ w2 ]

我想找到 w1 相对于矩阵 X 的梯度——也就是说,我想计算

          [ d/dx1 w1 ]
d/dX w1 =      .
               .
          [ d/dx8 w1 ]

(最好仍然看起来像一个矩阵,这样我可以将它添加到 X,但我真的不关心那个)

我希望 tf.gradients 能解决问题。我这样计算 "gradient"

problog_gradient = tf.gradients(action_problogs, policy_matrix)

但是,当我检查 problog_gradient 时,这是我得到的结果

[<tf.Tensor 'foo_4/gradients/foo_4/MatMul_grad/MatMul:0' shape=(2, 4) dtype=float32>]

请注意,这与 X 的形状完全相同,但实际上不应该。我希望得到一个包含两个梯度的列表,每个梯度对应 8 个元素。我怀疑我得到的是两个渐变,但每个渐变都与四个元素有关。

我是 tensorflow 的新手,所以我很感激并解释正在发生的事情以及我如何实现我想要的行为。

tf.gradients 实际上对 ys 求和并计算其梯度,这就是出现此问题的原因。

梯度需要一个标量函数,因此默认情况下,它对条目求和。这是默认行为,因为所有梯度下降算法都需要这种类型的功能,而随机梯度下降(或其变体)是 Tensorflow 内部的首选方法。您不会找到任何更高级的算法(如 BFGS 或其他算法),因为它们根本尚未实现(并且它们需要真正的雅可比行列式,但也尚未实现)。就其价值而言,这是我编写的一个有效的 Jacobian 实现:

def map(f, x, dtype=None, parallel_iterations=10):
    '''
    Apply f to each of the elements in x using the specified number of parallel iterations.

    Important points:
    1. By "elements in x", we mean that we will be applying f to x[0],...x[tf.shape(x)[0]-1].
    2. The output size of f(x[i]) can be arbitrary. However, if the dtype of that output
       is different than the dtype of x, then you need to specify that as an additional argument.
    '''
    if dtype is None:
        dtype = x.dtype

    n = tf.shape(x)[0]
    loop_vars = [
        tf.constant(0, n.dtype),
        tf.TensorArray(dtype, size=n),
    ]
    _, fx = tf.while_loop(
        lambda j, _: j < n,
        lambda j, result: (j + 1, result.write(j, f(x[j]))),
        loop_vars,
        parallel_iterations=parallel_iterations
    )
    return fx.stack()

def jacobian(fx, x, parallel_iterations=10):
    '''
    Given a tensor fx, which is a function of x, vectorize fx (via tf.reshape(fx, [-1])),
    and then compute the jacobian of each entry of fx with respect to x.
    Specifically, if x has shape (m,n,...,p), and fx has L entries (tf.size(fx)=L), then
    the output will be (L,m,n,...,p), where output[i] will be (m,n,...,p), with each entry denoting the
    gradient of output[i] wrt the corresponding element of x.
    '''
    return map(lambda fxi: tf.gradients(fxi, x)[0],
               tf.reshape(fx, [-1]),
               dtype=x.dtype,
               parallel_iterations=parallel_iterations)

虽然此实现有效,但当您尝试嵌套它时它不起作用。 例如,如果您尝试使用 jacobian( jacobian( ... )) 计算 Hessian,则会出现一些奇怪的错误。这被跟踪为 Issue 675. I am still awaiting a response 为什么会抛出错误。我相信 while 循环实现或渐变实现中存在 deep-seated 错误,但我真的不知道。

无论如何,如果你只需要一个 jacobian,试试上面的代码。