如何将 assemble 标量转换为张量流中的矩阵?

How to assemble scalars into a matrix in tensorflow?

简而言之,我想将 assemble 标量 w_ij 转换为对称矩阵 W,如下所示:

W[i, j] = w_ij
W[j, i] = w_ij

在努力解决这个问题并在互联网和 SE 上查找 material 之后,我找不到从 w_ij 构造矩阵 W 的方法,我不知道如何做到这一点。任何帮助将不胜感激。

阐述和MWE如下。



问题

在我的研究中,我正在尝试训练一个将 source 映射到标量 w_ij 的网络。其中输出 w_ij 旨在表示对称矩阵 W 中的元素 i,j

因此,训练的损失是通过将许多相同网络的输出(具有共享权重但每个看到不同的输入,并驱动矩阵中的不同元素)组装成矩阵形式来构建的,如下所示:

W[i, j] = w_ij
W[j, i] = w_ij

然后在损失形式上训练这些多个网络:

L2_loss(f(W) - f(True_W))

(其中f()是运行s f(Y) = d' Y d二次型的函数---矩阵乘以固定向量从左到右的乘积。)

我需要运行通过这个损失到每个网络的梯度。



我试过的

  1. tensorflow 不支持朴素的张量切片,即

    不支持

    W[i, j] = w_ij

  2. 使用tf.scatter_update()不允许运行渐变通过它。

  3. 最后,虽然我接近解决方案,但我尝试使用 tf.Variable 作为矩阵 W,如下所示:

     W_flat = tf.Variable(initial_value=[0] * (2 * 2), dtype='float32')
    

    然后通过切片W_falt[0].assign(w_ij) 来分配给这个 W_flat,但似乎我对这个变量的分配不起作用(参见 MWE)。


MWE

Bellow 是一个短 MWE,其中 W 是一个 2×2 对称矩阵,对角线为零,所以我只有一个网络必须驱动的独立元素(所以这里我只有一个单个网络),即我想让 W 具有值

W =   [[0, w_ij] [w_ij, 0]]

所以我尝试更新:

W_flat[1].assign(w_ij)
W_flat[2].assign(w_ij)

并将其转回矩阵:

W = tf.reshape(W_flat, (2, 2))

最终此更新没有通过,print 的输出显示 W 仍然全为零。

代码

import tensorflow as tf

def train():

    with tf.Graph().as_default():
        with tf.device('/cpu'):
            source = tf.placeholder(tf.float32, shape=(2, 3))
            is_training = tf.placeholder(tf.bool, shape=())

            w_ij = tf.reduce_sum(source)

            W_flat = tf.Variable(initial_value=[0] * (2 * 2), dtype='float32')

            W_flat[1].assign(w_ij)
            W_flat[2].assign(w_ij)
            tf.assign(W_flat[1], w_ij)
            tf.assign(W_flat[2], w_ij)

            W = tf.reshape(W_flat, (2, 2))

        sess = tf.Session()
        init = tf.global_variables_initializer()
        sess.run(init, {is_training: True})

        ops = {'W_flat': W_flat,
               'source' : source,
               'w_ij' : w_ij,
               'W' : W}

        for epoch in range(2):
            feed_dict = {ops['source']: [[1,1,1], [7,7,7]]}
            res_W_flat, res_wij, res_W = sess.run([ops['W_flat'], ops['w_ij'], ops['W']], feed_dict=feed_dict)
            print("epoch:" ,  epoch)
            print("W_flat:", res_W_flat)
            print("wij:", res_wij)
            print("W:", res_W)

if __name__ == "__main__" :
    train()

print() 输出

epoch: 0
W_flat: [0. 0. 0. 0.]
wij: 24.0
W: [[0. 0.]
 [0. 0.]]
epoch: 1
W_flat: [0. 0. 0. 0.]
wij: 24.0
W: [[0. 0.]
 [0. 0.]]

所以 WW_flat 不会被 w_ij 的值更新,w_ij 的值为 24 但 WW_flat 保持为零.

我经过更多努力找到的解决方案是使用tf.scatter_nd()更新矩阵W,不像tf.scatter_update()tf.scatter_nd()产生支持梯度传播的张量从输入到输出。

所以而不是写作

        W_flat = tf.Variable(initial_value=[0] * (2 * 2), dtype='float32')

        W_flat[1].assign(w_ij)
        W_flat[2].assign(w_ij)

        W = tf.reshape(W_flat, (2, 2))

使用工作:

        W_flat = tf.Variable(initial_value=[0] * (2 * 2), dtype='float32')
        indices = tf.constant([[1], [2]])
        shape = tf.constant([4])
        W_flat = tf.scatter_nd(indices, w_ij, shape)

        W = tf.reshape(W_flat, (2, 2))