如何在张量流中显式广播张量以匹配另一个张量?
How to explicitly broadcast a tensor to match another's shape in tensorflow?
我有三个张量,tensorflow中的A, B and C
,A
和B
都是形状(m, n, r)
,C
是形状的二元张量(m, n, 1)
.
我想根据 C
的值 select 来自 A 或 B 的元素。显而易见的工具是 tf.select
,但是它没有广播语义,所以我需要首先明确地将 C
广播到与 A 和 B 相同的形状。
这将是我第一次尝试如何做到这一点,但它不喜欢我将张量 (tf.shape(A)[2]
) 混合到形状列表中。
import tensorflow as tf
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = tf.greater_equal(C, tf.zeros_like(C))
C = tf.tile(C, [1,1,tf.shape(A)[2]])
D = tf.select(C, A, B)
此处正确的做法是什么?
编辑: 在自 0.12rc0 以来的所有 TensorFlow 版本中,问题中的代码直接工作。 TensorFlow 会自动将张量和 Python 数字堆叠到张量参数中。以下使用 tf.pack()
的解决方案仅在 0.12rc0 之前的版本中需要。请注意,tf.pack()
在 TensorFlow 1.0 中已重命名为 tf.stack()
。
您的解决方案即将生效。您应该替换行:
C = tf.tile(C, [1,1,tf.shape(C)[2]])
...具有以下内容:
C = tf.tile(C, tf.pack([1, 1, tf.shape(A)[2]]))
(问题的原因是 TensorFlow 不会将张量列表和 Python 文字隐式转换为张量。tf.pack()
采用张量列表,因此它将每个转换将其输入中的元素(1
、1
和 tf.shape(C)[2]
)转换为张量。由于每个元素都是标量,因此结果将是一个向量。)
这是一个肮脏的技巧:
import tensorflow as tf
def broadcast(tensor, shape):
return tensor + tf.zeros(shape, dtype=tensor.dtype)
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = broadcast(C, A.shape)
D = tf.select(C, A, B)
import tensorflow as tf
def broadcast(tensor, shape):
"""Broadcasts ``x`` to have shape ``shape``.
|
Uses ``tf.Assert`` statements to ensure that the broadcast is
valid.
First calculates the number of missing dimensions in
``tf.shape(x)`` and left-pads the shape of ``x`` with that many
ones. Then identifies the dimensions of ``x`` that require
tiling and tiles those dimensions appropriately.
Args:
x (tf.Tensor): The tensor to broadcast.
shape (Union[tf.TensorShape, tf.Tensor, Sequence[int]]):
The shape to broadcast to.
Returns:
tf.Tensor: ``x``, reshaped and tiled to have shape ``shape``.
"""
with tf.name_scope('broadcast') as scope:
shape_x = tf.shape(x)
rank_x = tf.shape(shape0)[0]
shape_t = tf.convert_to_tensor(shape, preferred_dtype=tf.int32)
rank_t = tf.shape(shape1)[0]
with tf.control_dependencies([tf.Assert(
rank_t >= rank_x,
['len(shape) must be >= tf.rank(x)', shape_x, shape_t],
summarize=255
)]):
missing_dims = tf.ones(tf.stack([rank_t - rank_x], 0), tf.int32)
shape_x_ = tf.concat([missing_dims, shape_x], 0)
should_tile = tf.equal(shape_x_, 1)
with tf.control_dependencies([tf.Assert(
tf.reduce_all(tf.logical_or(tf.equal(shape_x_, shape_t), should_tile),
['cannot broadcast shapes', shape_x, shape_t],
summarize=255
)]):
multiples = tf.where(should_tile, shape_t, tf.ones_like(shape_t))
out = tf.tile(tf.reshape(x, shape_x_), multiples, name=scope)
try:
out.set_shape(shape)
except:
pass
return out
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = broadcast(C, A.shape)
D = tf.select(C, A, B)
在最新的tensorflow版本(2.0)中,您可以使用tf.broadcast_to
如下:
import tensorflow as tf
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = tf.greater_equal(C, tf.zeros_like(C))
C = tf.broadcast_to(C, A.shape)
D = tf.where(C,A,B)
我有三个张量,tensorflow中的A, B and C
,A
和B
都是形状(m, n, r)
,C
是形状的二元张量(m, n, 1)
.
我想根据 C
的值 select 来自 A 或 B 的元素。显而易见的工具是 tf.select
,但是它没有广播语义,所以我需要首先明确地将 C
广播到与 A 和 B 相同的形状。
这将是我第一次尝试如何做到这一点,但它不喜欢我将张量 (tf.shape(A)[2]
) 混合到形状列表中。
import tensorflow as tf
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = tf.greater_equal(C, tf.zeros_like(C))
C = tf.tile(C, [1,1,tf.shape(A)[2]])
D = tf.select(C, A, B)
此处正确的做法是什么?
编辑: 在自 0.12rc0 以来的所有 TensorFlow 版本中,问题中的代码直接工作。 TensorFlow 会自动将张量和 Python 数字堆叠到张量参数中。以下使用 tf.pack()
的解决方案仅在 0.12rc0 之前的版本中需要。请注意,tf.pack()
在 TensorFlow 1.0 中已重命名为 tf.stack()
。
您的解决方案即将生效。您应该替换行:
C = tf.tile(C, [1,1,tf.shape(C)[2]])
...具有以下内容:
C = tf.tile(C, tf.pack([1, 1, tf.shape(A)[2]]))
(问题的原因是 TensorFlow 不会将张量列表和 Python 文字隐式转换为张量。tf.pack()
采用张量列表,因此它将每个转换将其输入中的元素(1
、1
和 tf.shape(C)[2]
)转换为张量。由于每个元素都是标量,因此结果将是一个向量。)
这是一个肮脏的技巧:
import tensorflow as tf
def broadcast(tensor, shape):
return tensor + tf.zeros(shape, dtype=tensor.dtype)
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = broadcast(C, A.shape)
D = tf.select(C, A, B)
import tensorflow as tf
def broadcast(tensor, shape):
"""Broadcasts ``x`` to have shape ``shape``.
|
Uses ``tf.Assert`` statements to ensure that the broadcast is
valid.
First calculates the number of missing dimensions in
``tf.shape(x)`` and left-pads the shape of ``x`` with that many
ones. Then identifies the dimensions of ``x`` that require
tiling and tiles those dimensions appropriately.
Args:
x (tf.Tensor): The tensor to broadcast.
shape (Union[tf.TensorShape, tf.Tensor, Sequence[int]]):
The shape to broadcast to.
Returns:
tf.Tensor: ``x``, reshaped and tiled to have shape ``shape``.
"""
with tf.name_scope('broadcast') as scope:
shape_x = tf.shape(x)
rank_x = tf.shape(shape0)[0]
shape_t = tf.convert_to_tensor(shape, preferred_dtype=tf.int32)
rank_t = tf.shape(shape1)[0]
with tf.control_dependencies([tf.Assert(
rank_t >= rank_x,
['len(shape) must be >= tf.rank(x)', shape_x, shape_t],
summarize=255
)]):
missing_dims = tf.ones(tf.stack([rank_t - rank_x], 0), tf.int32)
shape_x_ = tf.concat([missing_dims, shape_x], 0)
should_tile = tf.equal(shape_x_, 1)
with tf.control_dependencies([tf.Assert(
tf.reduce_all(tf.logical_or(tf.equal(shape_x_, shape_t), should_tile),
['cannot broadcast shapes', shape_x, shape_t],
summarize=255
)]):
multiples = tf.where(should_tile, shape_t, tf.ones_like(shape_t))
out = tf.tile(tf.reshape(x, shape_x_), multiples, name=scope)
try:
out.set_shape(shape)
except:
pass
return out
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = broadcast(C, A.shape)
D = tf.select(C, A, B)
在最新的tensorflow版本(2.0)中,您可以使用tf.broadcast_to
如下:
import tensorflow as tf
A = tf.random_normal([20, 100, 10])
B = tf.random_normal([20, 100, 10])
C = tf.random_normal([20, 100, 1])
C = tf.greater_equal(C, tf.zeros_like(C))
C = tf.broadcast_to(C, A.shape)
D = tf.where(C,A,B)