张量流:如何交错两个张量的列(例如,使用tf.scatter_nd)?

时间:2018-09-29 20:24:35

标签: python tensorflow

我已经读过tf.scatter_nd documentation并为1D和3D张量运行示例代码...现在我正在尝试为2D张量进行此操作。我想“交织”两个张量的列。对于一维张量,可以通过

'''
We want to interleave elements of 1D tensors arr1 and arr2, where
arr1 = [10, 11, 12]
arr2 = [1, 2, 3, 4, 5, 6]
such that
desired result = [1, 2, 10, 3, 4, 11, 5, 6, 12]
'''

import tensorflow as tf

with tf.Session() as sess:

    updates1 = tf.constant([1,2,3,4,5,6])
    indices1 = tf.constant([[0], [1], [3], [4], [6], [7]])
    shape = tf.constant([9])
    scatter1 = tf.scatter_nd(indices1, updates1, shape)

    updates2 = tf.constant([10,11,12])
    indices2 = tf.constant([[2], [5], [8]])
    scatter2 = tf.scatter_nd(indices2, updates2, shape)

    result = scatter1 + scatter2

    print(sess.run(result))

(除了:有没有一种更好的方法来做到这一点?我都很高兴。)

这给出了输出

[ 1 2 10 3 4 11 5 6 12]

是的!起作用了!

现在让我们尝试将其扩展到2D。

    '''
    We want to interleave the *columns* (not rows; rows would be easy!) of

    arr1 = [[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]]
    arr2 = [[10 11 12], [10 11 12], [10 11 12]]
    such that
    desired result = [[1,2,10,3,4,11,5,6,12],[1,2,10,3,4,11,5,6,12],[1,2,10,3,4,11,5,6,12]]
    '''

    updates1 = tf.constant([[1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]])
    indices1 = tf.constant([[0], [1], [3], [4], [6], [7]])
    shape = tf.constant([3, 9])
    scatter1 = tf.scatter_nd(indices1, updates1, shape)

这给出了错误 ValueError: The outer 1 dimensions of indices.shape=[6,1] must match the outer 1 dimensions of updates.shape=[3,6]: Dimension 0 in both shapes must be equal, but are 6 and 3. Shapes are [6] and [3]. for 'ScatterNd_2' (op: 'ScatterNd') with input shapes: [6,1], [3,6], [2].

好像我的indices是在指定行索引而不是列索引,并给出以numpy和tensorflow(即行优先顺序)“连接”数组的方式,这是否意味着 我需要为updates1中的每个元素明确地指定每对索引吗? 还是我可以为行使用某种“通配符”规范? (注意indices1 = tf.constant([[:,0], [:,1], [:,3], [:,4], [:,6], [:,7]])可能会出现语法错误。)

只进行转置,对行进行交织然后再转回会更容易吗? 因为我尝试过...

scatter1 = tf.scatter_nd(indices1, tf.transpose(updates1), tf.transpose(shape))
print(sess.run(tf.transpose(scatter1)))

...并且收到了很多更长的错误消息,除非有人要求,否则我不希望发布。

PS-我进行了搜索,以确保这不是重复的内容-我很难想象别人之前没有问过这个问题-但没有发现任何问题。

2 个答案:

答案 0 :(得分:1)

这是纯粹的切片,但我不知道像{b, ...c}:这样的语法是否有效。似乎可以,但是不确定是否更好。

这可能是您正在寻找的通配符切片机制。

arr1[0:,:][:,:2]

输出为

arr1 = tf.constant([[1,2,3,4,5,6],[1,2,3,4,5,7],[1,2,3,4,5,8]])
arr2 = tf.constant([[10, 11, 12], [10, 11, 12], [10, 11, 12]])

with tf.Session() as sess :
    sess.run( tf.global_variables_initializer() )
    print(sess.run(tf.concat([arr1[0:,:][:,:2], arr2[0:,:] [:,:1],
                              arr1[0:,:][:,2:4],arr2[0:, :][:, 1:2],
                              arr1[0:,:][:,4:6],arr2[0:, :][:, 2:3]],axis=1)))

例如,

[[ 1 2 10 3 4 11 5 6 12] [ 1 2 10 3 4 11 5 7 12] [ 1 2 10 3 4 11 5 8 12]] 返回

arr1[0:,:]

[[1 2 3 4 5 6] [1 2 3 4 5 7] [1 2 3 4 5 8]] 返回前两列

arr1[0:,:][:,:2]

轴为1。

答案 1 :(得分:1)

一些主持人可能将我的问题视为this one的重复,不是因为问题相同,而是因为答案包含可以用来回答此问题的部分-即通过指定每个索引组合手。

完全不同的方法是乘以the last answer to this question中所示的置换矩阵。由于我最初的问题是关于scatter_nd的,所以我将发布此解决方案,但请等一下其他答案……(或者,我或某人可以编辑该问题以重新排序不特定于scatter_nd < strong>-编辑:我刚刚编辑了问题标题以体现这一点)。

在这里,我们将两个不同的数组/张量连接起来...

import numpy as np
import tensorflow as tf

sess = tf.Session()

# the ultimate application is for merging variables which should be in groups,
#   e.g. in this example, [1,2,10] is a group of 3, and there are 3 groups of 3
n_groups = 3
vars_per_group = 3    # once the single value from arr2 (below) is included

arr1 = 10+tf.range(n_groups, dtype=float)
arr1 = tf.stack((arr1,arr1,arr1),0)
arr2 = 1+tf.range(n_groups * (vars_per_group-1), dtype=float)
arr2 = tf.stack((arr2,arr2,arr2),0)

catted = tf.concat((arr1,arr2),1)        # concatenate the two arrays together
print("arr1 = \n",sess.run(arr1))
print("arr2 = \n",sess.run(arr2))
print("catted = \n",sess.run(catted))

哪个提供输出

arr1 = 
 [[10. 11. 12.]
 [10. 11. 12.]
 [10. 11. 12.]]
arr2 = 
 [[1. 2. 3. 4. 5. 6.]
 [1. 2. 3. 4. 5. 6.]
 [1. 2. 3. 4. 5. 6.]]
catted = 
 [[10. 11. 12.  1.  2.  3.  4.  5.  6.]
 [10. 11. 12.  1.  2.  3.  4.  5.  6.]
 [10. 11. 12.  1.  2.  3.  4.  5.  6.]]

现在我们建立置换矩阵并乘以...

start_index = 2               # location of where the interleaving begins

# cml = "column map list" is the list of where each column will get mapped to
cml = [start_index + x*(vars_per_group) for x in range(n_groups)]  # first array  
for i in range(n_groups):                                       # second array 
    cml += [x + i*(vars_per_group) for x in range(start_index)] # vars before start_index
    cml += [1 + x + i*(vars_per_group) + start_index \
        for x in range(vars_per_group-start_index-1)]           # vars after start_index
print("\n cml = ",cml,"\n")

# Create a permutation matrix using p
np_perm_mat = np.zeros((len(cml), len(cml)))
for idx, i in enumerate(cml):
    np_perm_mat[idx, i] = 1
perm_mat = tf.constant(np_perm_mat,dtype=float)

result = tf.matmul(catted, perm_mat)
print("result = \n",sess.run(result))

哪个提供输出

cml =  [2, 5, 8, 0, 1, 3, 4, 6, 7] 

result = 
 [[ 1.  2. 10.  3.  4. 11.  5.  6. 12.]
 [ 1.  2. 10.  3.  4. 11.  5.  6. 12.]
 [ 1.  2. 10.  3.  4. 11.  5.  6. 12.]]

即使这并不像最初的问题那样使用scatter_nd,但我喜欢的一件事是,您可以通过某种perm_mat方法分配__init__()一次,然后继续使用它,在最初的开销之后,它只是矩阵-矩阵乘以一个稀疏,恒定的矩阵,应该很快。 (?)

仍然很高兴等待,看看还有什么其他答案。