如何在Tensorflow中进行切片分配

ddhy6vgd  于 2022-12-23  发布在  其他
关注(0)|答案(5)|浏览(193)

我发现Tensorflow提供了scatter_update()来为0维Tensor的切片赋值。例如,如果TensorT是三维的,我可以为T[i, :, :]赋值v[1, :, :]

a = tf.Variable(tf.zeros([10,36,36]))   
value = np.ones([1,36,36])   
d = tf.scatter_update(a,[0],value)

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    print a.eval()
    sess.run(d)
    print a.eval()

但是如何将v[1,1,:]赋值给T[i,j,:]呢?

a = tf.Variable(tf.zeros([10,36,36]))   
value1 = np.random.randn(1,1,36)    
e = tf.scatter_update(a,[0],value1) #Error

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    print a.eval()
    sess.rum(e)
    print a.eval()

TF还提供了其他的功能吗?或者有什么简单的方法可以做到这一点吗?

vsaztqbk

vsaztqbk1#

目前,您可以在TensorFlow中对变量进行切片赋值,没有具体的命名函数,但您可以选择一个切片并在其上调用assign

my_var = my_var[4:8].assign(tf.zeros(4))

首先,请注意(在阅读了文档之后),assign的返回值似乎总是对应用更新后的 whole 变量的引用,即使应用于切片也是如此。
编辑:下面的信息要么过时,要么不精确,要么总是错误的。事实上,assign的返回值是一个Tensor,可以很容易地使用,并且已经将依赖关系合并到赋值中,所以简单地计算它或在进一步的操作中使用它将确保它在不需要显式tf.control_dependencies块的情况下执行。
还要注意,这只会将赋值操作添加到图中,但不会运行它,除非它被显式执行或被设置为某个其他操作的依赖项。一个好的实践是在tf.control_dependencies上下文中使用它:

with tf.control_dependencies([my_var[4:8].assign(tf.zeros(4))]):
    my_var = tf.identity(my_var)

您可以在TensorFlow第#4638期中了解更多信息。

xlpyo6sf

xlpyo6sf2#

我相信您需要的是在ticket #206中讨论的assign_slice_update,不过它还没有上市。

assign_slice_update(或scatter_nd())可用之前,您可以构建一个所需行的块,其中包含您不想修改的值以及要更新的值,如下所示:

import tensorflow as tf

a = tf.Variable(tf.ones([10,36,36]))

i = 3
j = 5

# Gather values inside the a[i,...] block that are not on column j
idx_before = tf.concat(1, [tf.reshape(tf.tile(tf.Variable([i]), [j]), [-1, 1]), tf.reshape(tf.range(j), [-1, 1])])
values_before = tf.gather_nd(a, idx_before)
idx_after = tf.concat(1, [tf.reshape(tf.tile(tf.Variable([i]), [36-j-1]), [-1, 1]), tf.reshape(tf.range(j+1, 36), [-1, 1])])
values_after = tf.gather_nd(a, idx_after)

# Build a subset of tensor `a` with the values that should not be touched and the values to update
block = tf.concat(0, [values_before, 5*tf.ones([1, 36]), values_after])

d = tf.scatter_update(a, i, block)

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    sess.run(d)
    print(a.eval()[3,4:7,:]) # Print a subset of the tensor to verify

这个例子生成一个1的Tensor并执行a[i,j,:] = 5。大部分的复杂性在于得到我们不想修改的值a[i,~j,:](否则scatter_update()将替换那些值)。
如果您希望按照要求执行T[i,k,:] = a[1,1,:],则需要将前面示例中的5*tf.ones([1, 36])替换为tf.gather_nd(a, [[1, 1]])
另一种方法是创建一个掩码,从tf.select()中删除所需的元素,并将其赋值回变量,如下所示:

import tensorflow as tf

a = tf.Variable(tf.zeros([10,36,36]))

i = tf.Variable([3])
j = tf.Variable([5])

# Build a mask using indices to perform [i,j,:]
atleast_2d = lambda x: tf.reshape(x, [-1, 1])
indices = tf.concat(1, [atleast_2d(tf.tile(i, [36])), atleast_2d(tf.tile(j, [36])), atleast_2d(tf.range(36))])
mask = tf.cast(tf.sparse_to_dense(indices, [10, 36, 36], 1), tf.bool)

to_update = 5*tf.ones_like(a)
out = a.assign( tf.select(mask, to_update, a) ) 

with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    sess.run(out)
    print(a.eval()[2:5,5,:])

它可能在内存方面效率较低,因为它需要两倍的内存来处理类似ato_update变量,但您可以轻松地修改最后一个示例,以从tf.select(...)节点获得梯度保持操作。您可能还对查看另一个StackOverflow问题感兴趣:Conditional assignment of tensor values in TensorFlow.
当TensorFlow函数可用时,应将这些不优雅的扭曲替换为对适当TensorFlow函数的调用。

wlsrxk51

wlsrxk513#

tf.scatter_update可以修改第一维度的Tensor。如文档所述,
indices:Tensor。必须是以下类型之一:int32,int64。进入ref的第一维的索引的Tensor。
你可以使用scatter_nd_update函数来做你想做的事情。如下所示,我已经测试过了。

a = tf.Variable(tf.zeros([10,36,36])) 
value1 = np.random.randn(1,36)
e = tf.scatter_nd_update(a,[[0,1]],value1)
init= tf.global_variables_initializer()
sess.run(init)
print(a.eval())
sess.run(e)
tuwxkamq

tuwxkamq4#

TF2的答案:

遗憾的是,在Tensorflow 2(TF2)中仍然没有优雅的方法来执行此操作。
我发现最好的方法是将assign解栈,然后重新堆栈:

x = tf.random.uniform(shape=(5,))
new_val = 7
y = tf.unstack(x)
y[2] = new_val
x_updated = tf.stack(y)
xtfmy6hx

xtfmy6hx5#

你可以用tf.tensor_scatter_nd_update来实现它,下面是一个例子,说明从一个二维数组中给一个切片赋值的具体情况。

def tf_assign_slice_2d(heatmap: TensorHeatmap, left: int, top: int, right: int, bottom: int, value: float):
    bw = right - left
    bh = bottom - top
    ixs = tf.range(bw * bh)
    i_ixs = ixs // bw + top
    j_ixs = ixs % bw + left
    ij_ixs = tf.stack([i_ixs, j_ixs], axis=1)
    return tf.tensor_scatter_nd_update(heatmap, ij_ixs, value+tf.zeros(bh*bw, dtype=heatmap.dtype))

通过测试:

def test_assign_slice_2d():
    mat = tf.constant([
        [2, 5, 1, 6],
        [8, 4, 2, 4],
        [7, 2, 0, 2],
    ])
    result = tf_assign_slice_2d(mat, 1, 0, 3, 2, value=-1)
    assert np.array_equal(result.numpy(),[
        [2, -1, -1, 6],
        [8, -1, -1, 4],
        [7, 2, 0, 2],
    ])

相关问题