Tensorflow 2 - tf.slice 及其 NumPy 切片语法不兼容的行为
Posted
技术标签:
【中文标题】Tensorflow 2 - tf.slice 及其 NumPy 切片语法不兼容的行为【英文标题】:Tensorflow 2 - tf.slice and its NumPy slice syntax incompatible behavior 【发布时间】:2021-07-26 09:40:12 【问题描述】:问题
请确认以下是否符合设计和预期,或者tf. slice的问题,或者tf. slice
的使用错误。如果有错误,请建议如何更正。
背景
Introduction to tensor slicing - Extract tensor slices 表示类似 Numpy 的切片语法是 tf. slice
的替代方案。
使用 tf. 执行类似 NumPy 的张量切片。切片。
t1 = tf.constant([0, 1, 2, 3, 4, 5, 6, 7]) print(tf.slice(t1, begin=[1], size=[3]))
或者,您可以使用更 Pythonic 的语法。请注意,张量切片在开始-停止范围内均匀分布。
print(t1[1:4])
问题
更新深橙色区域。
TYPE = tf.int32
N = 4
D = 5
shape = (N,D)
# Target to update
Y = tf.Variable(
initial_value=tf.reshape(tf.range(N*D,dtype=TYPE), shape=shape),
trainable=True
)
print(f"Target Y: \nY\n")
---
Target Y:
<tf.Variable 'Variable:0' shape=(4, 5) dtype=int32, numpy=
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]], dtype=int32)>
tf. slice
不起作用。
# --------------------------------------------------------------------------------
# Slice region in the target to be updated
# --------------------------------------------------------------------------------
S = tf.slice( # Error "EagerTensor' object has no attribute 'assign'"
Y,
begin=[0,1], # Coordinate (n,d) as the start point
size=[3,2] # Shape (3,2) -> (n+3, n+2) as the end point
)
print(f"Slice to update S: \nS\n")
# Values to set
V = tf.ones(shape=tf.shape(S), dtype=TYPE)
print(f"Values to set V: \nV\n")
# Assing V to S region of T
S.assign(V)
---
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-e5692b1750c8> in <module>
24
25 # Assing V to S region of T
---> 26 S.assign(V)
AttributeError: 'tensorflow.python.framework.ops.EagerTensor' object has no attribute 'assign'
但是,切片语法可以工作。
S = Y[
0:3, # From coordinate (n=0,d), slice rows (0,1,2) or 'size'=3 -> shape (3,?)
1:3 # From coordinate (n=0,d=1), slice columns (1,2) or 'size'=2 -> shape (3,2)
]
print(f"Slice to update S: \nS\n")
# Values to set
V = tf.ones(shape=tf.shape(S), dtype=TYPE)
print(f"Values to set V: \nV\n")
# Assing V to S region of T
S.assign(V)
---
<tf.Variable 'UnreadVariable' shape=(4, 5) dtype=int32, numpy=
array([[ 0, 1, 1, 3, 4],
[ 5, 1, 1, 8, 9],
[10, 1, 1, 13, 14],
[15, 16, 17, 18, 19]], dtype=int32)>
【问题讨论】:
【参考方案1】:据我了解,上述行为是意料之中的或至少不是错误。正如错误所说,在tf. Tensor
(EagerTensor
用于急切执行)没有属性称为assign
,但在tf. Variable
中有。通常,tf. slice
返回 张量 作为其输出,因此它不具有 assign
属性。
AttributeError: 'tensorflow.python.framework.ops.EagerTensor' object has no attribute 'assign'
但是当我们对np
进行切片并使用它来修改原始tf. Variable
时,它可以无缝工作。
可能的解决方案
一种解决方法是使用tf.strided_slice
而不是tf.slice
。如果我们查看它的源代码,我们会看到,它接受了var
参数,这是一个对应于input_
的变量
@tf_export("strided_slice")
@dispatch.add_dispatch_support
def strided_slice(input_,
begin,
end,
..........
var=None,
name=None):
当我们为var
传递一个基本对应于input_
的参数时,它会调用其中定义的assign
function
def assign(val, name=None):
"""Closure that holds all the arguments to create an assignment."""
if var is None:
raise ValueError("Sliced assignment is only supported for variables")
else:
if name is None:
name = parent_name + "_assign"
return var._strided_slice_assign(
begin=begin,
end=end,
strides=strides,
value=val,
name=name,
begin_mask=begin_mask,
end_mask=end_mask,
ellipsis_mask=ellipsis_mask,
new_axis_mask=new_axis_mask,
shrink_axis_mask=shrink_axis_mask)
所以,当我们在tf.strided_slice
中传递var
时,它会返回一个可赋值对象。
代码
这是完整的工作代码供参考。
import tensorflow as tf
print(tf.__version__)
TYPE = tf.int32
N = 4
D = 5
shape = (N,D)
# Target to update
Y = tf.Variable(
initial_value=tf.reshape(tf.range(N*D,dtype=TYPE), shape=shape),
trainable=True
)
Y
2.4.1
<tf.Variable 'Variable:0' shape=(4, 5) dtype=int32, numpy=
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]], dtype=int32)>
现在,我们使用tf.stried_slice
代替tf.slice
。
S = tf.strided_slice(
Y,
begin = [0, 1],
end = [3, 3],
var = Y,
name ='slice_op'
)
S
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[ 1, 2],
[ 6, 7],
[11, 12]], dtype=int32)>
更新变量时不会出现归因错误。
# Values to set
V = tf.ones(shape=tf.shape(S), dtype=TYPE)
print(V)
print()
# Assing V to S region of T
S.assign(V)
tf.Tensor(
[[1 1]
[1 1]
[1 1]], shape=(3, 2), dtype=int32)
<tf.Variable 'UnreadVariable' shape=(4, 5) dtype=int32, numpy=
array([[ 0, 1, 1, 3, 4],
[ 5, 1, 1, 8, 9],
[10, 1, 1, 13, 14],
[15, 16, 17, 18, 19]], dtype=int32)>
像切片一样使用np
。
# slicing
S = Y[
0:3,
1:3
]
S
<tf.Tensor: shape=(3, 2), dtype=int32, numpy=
array([[ 1, 2],
[ 6, 7],
[11, 12]], dtype=int32)>
# Values to set
V = tf.ones(shape=tf.shape(S), dtype=TYPE)
print(V)
# Assing V to S region of T
S.assign(V)
tf.Tensor(
[[1 1]
[1 1]
[1 1]], shape=(3, 2), dtype=int32)
<tf.Variable 'UnreadVariable' shape=(4, 5) dtype=int32, numpy=
array([[ 0, 1, 1, 3, 4],
[ 5, 1, 1, 8, 9],
[10, 1, 1, 13, 14],
[15, 16, 17, 18, 19]], dtype=int32)>
材料
tf.Variable - tf.Tensor。【讨论】:
以上是关于Tensorflow 2 - tf.slice 及其 NumPy 切片语法不兼容的行为的主要内容,如果未能解决你的问题,请参考以下文章
了解 tensorflow 中 tf.slice 的参数以及为啥我不能更改它
像在 numpy 中一样使用 tf.slice 检测越界切片
tensorrt不支持:tf.unpack,tf.slice,tf.tile,tf.expand_dims,tf.fill,tf.cast,tf.floor_div,tf.range