如何将 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
二次型的函数---矩阵乘以固定向量从左到右的乘积。)
我需要运行通过这个损失到每个网络的梯度。
我试过的
tensorflow
不支持朴素的张量切片,即
不支持W[i, j] = w_ij
。
使用tf.scatter_update()
不允许运行渐变通过它。
最后,虽然我接近解决方案,但我尝试使用 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.]]
所以 W
和 W_flat
不会被 w_ij
的值更新,w_ij
的值为 24 但 W
和 W_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))
简而言之,我想将 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
二次型的函数---矩阵乘以固定向量从左到右的乘积。)
我需要运行通过这个损失到每个网络的梯度。
我试过的
不支持tensorflow
不支持朴素的张量切片,即W[i, j] = w_ij
。使用
tf.scatter_update()
不允许运行渐变通过它。最后,虽然我接近解决方案,但我尝试使用
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.]]
所以 W
和 W_flat
不会被 w_ij
的值更新,w_ij
的值为 24 但 W
和 W_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))