TensorFlow 中 tf.matmul 没有广播

No broadcasting for tf.matmul in TensorFlow

我遇到了一个一直困扰我的问题。跟tf.matmul()和没有广播有关

我知道 https://github.com/tensorflow/tensorflow/issues/216 上有一个类似的问题,但 tf.batch_matmul() 看起来不像我的情况的解决方案。

我需要将输入数据编码为 4D 张量: X = tf.placeholder(tf.float32, shape=(None, None, None, 100)) 第一个维度是批次的大小,第二个维度是批次中的条目数。 您可以将每个条目想象成多个对象的组合(三维)。最后,每个对象都由一个包含 100 个浮点值的向量来描述。

请注意,我对第二个和第三个维度使用了 None,因为每个批次的实际尺寸可能会发生变化。但是,为简单起见,让我们用实际数字塑造张量: X = tf.placeholder(tf.float32, shape=(5, 10, 4, 100))

这些是我的计算步骤:

  1. 计算每个包含 100 个浮点值的向量的函数(例如,线性函数) W = tf.Variable(tf.truncated_normal([100, 50], stddev=0.1)) Y = tf.matmul(X, W) 问题tf.matmul() 没有广播,使用 tf.batch_matmul() 也没有成功 Y 的预期形状:(5, 10, 4, 50)

  2. 为批次的每个条目应用平均池化(在每个条目的对象上): Y_avg = tf.reduce_mean(Y, 2) Y_avg 的预期形状:(5, 10, 50)

我预计 tf.matmul() 会支持广播。然后我发现 tf.batch_matmul(),但它看起来仍然不适用于我的情况(例如,W 至少需要有 3 个维度,不清楚为什么)。

顺便说一句,上面我使用了一个简单的线性函数(其权重存储在W中)。但在我的模型中,我有一个深层网络。所以,我遇到的更普遍的问题是自动为张量的每个切片计算一个函数。这就是为什么我预计 tf.matmul() 会有广播行为(如果是这样,也许甚至不需要 tf.batch_matmul())。

期待向您学习! 阿莱西奥

您可以通过将 X 重塑为 [n, d] 来实现这一点,其中 d 是单个 "instance" 计算的维数(在您的示例中为 100),并且n 是多维对象中这些实例的数量(在您的示例中为 5*10*4=200)。重塑后,您可以使用 tf.matmul 然后重塑回所需的形状。前三个维度可以变化的事实使这有点棘手,但您可以使用 tf.shape 来确定 运行 时间内的实际形状。最后,您可以执行计算的第二步,这应该是对相应维度的简单 tf.reduce_mean。总而言之,它看起来像这样:

X = tf.placeholder(tf.float32, shape=(None, None, None, 100))
W = tf.Variable(tf.truncated_normal([100, 50], stddev=0.1))
X_ = tf.reshape(X, [-1, 100])
Y_ = tf.matmul(X_, W)
X_shape = tf.gather(tf.shape(X), [0,1,2]) # Extract the first three dimensions
target_shape = tf.concat(0, [X_shape, [50]])
Y = tf.reshape(Y_, target_shape)
Y_avg = tf.reduce_mean(Y, 2)

作为GitHub issue you linked suggests, you should use tf.tensordot(). It enables contraction of axes pairs between two tensors, in line with Numpy's tensordot()的更名标题。对于您的情况:

X = tf.placeholder(tf.float32, shape=(5, 10, 4, 100))
W = tf.Variable(tf.truncated_normal([100, 50], stddev=0.1))
Y = tf.tensordot(X, W, [[3], [0]])  # gives shape=[5, 10, 4, 50]