我想将一批矩阵与一批相同长度的矩阵成对相乘
M = tf.random_normal((batch_size, n, m))
N = tf.random_normal((batch_size, m, p))
# python >= 3.5
MN = M @ N
# or the old way,
MN = tf.matmul(M, N)
# MN has shape (batch_size, n, p)
2.我想将一批矩阵与一批长度相同的向量成对相乘
通过向v
添加和删除维,我们回到情况1。
M = tf.random_normal((batch_size, n, m))
v = tf.random_normal((batch_size, m))
Mv = (M @ v[..., None])[..., 0]
# Mv has shape (batch_size, n)
3.我想将单个矩阵与一批矩阵相乘
在这种情况下,我们不能简单地将批处理维度1
添加到单个矩阵,因为tf.matmul
不会以批处理维度进行广播。
3.1。单个矩阵在右侧
在这种情况下,我们可以使用简单的整形将矩阵批处理视为单个大矩阵。
M = tf.random_normal((batch_size, n, m))
N = tf.random_normal((m, p))
MN = tf.reshape(tf.reshape(M, [-1, m]) @ N, [-1, n, p])
# MN has shape (batch_size, n, p)
3.2。单个矩阵在左侧
这种情况更复杂。通过转置矩阵,我们可以回到情况3.1。
MT = tf.matrix_transpose(M)
NT = tf.matrix_transpose(N)
NTMT = tf.reshape(tf.reshape(NT, [-1, m]) @ MT, [-1, p, n])
MN = tf.matrix_transpose(NTMT)
但是,换位可能是一项昂贵的操作,并且在此过程中,对整批矩阵都进行了两次。最好简单地复制M
来匹配批次尺寸:
MN = tf.tile(M[None], [batch_size, 1, 1]) @ N
分析将告诉您哪个选项对给定的问题/硬件组合更有效。
4.我想将一个矩阵与一批向量相乘
这看起来与情况3.2类似,因为单个矩阵位于左侧,但实际上更简单,因为转置向量本质上是无操作的。我们最终
M = tf.random_normal((n, m))
v = tf.random_normal((batch_size, m))
MT = tf.matrix_transpose(M)
Mv = v @ MT
einsum
呢?
以前的所有乘法都可以用tf.einsum
瑞士军刀书写。例如,第一个3.2的解决方案可以简单地写成
MN = tf.einsum('nm,bmp->bnp', M, N)
但是,请注意einsum
最终依赖于tranpose
和matmul
进行计算。
因此,即使einsum
是编写矩阵乘法的一种非常方便的方法,但它einsum
了下面操作的复杂性-例如,猜测einsum
表达式将转置数据多少次einsum
,因此该操作将花费多少。同样,它可能掩盖了一个事实,即同一操作可能有多种选择(请参阅案例3.2),而不一定选择更好的选择。
因此,我个人将使用上述明确的公式来更好地传达它们各自的复杂性。尽管如果您知道自己在做什么,并且喜欢einsum
语法的简单性,那么einsum
。
0
我有一些由
input_x
表示的数据。它是一个未知大小的张量(应分批输入),每个项目的大小均为n
。input_x
经历tf.nn.embedding_lookup
,因此embed
现在具有尺寸[?, n, m]
,其中m
是嵌入尺寸,?
是嵌入尺寸?
指未知的批次大小。此处描述:
我现在正在尝试将输入数据中的每个样本(现在通过嵌入维进行扩展)乘以矩阵变量
U
,但我似乎不知道该怎么做。我首先尝试使用
tf.matmul
但由于形状不匹配而导致错误。然后,我通过扩展U
的维并应用batch_matmul
尝试以下batch_matmul
(我也尝试了来自tf.nn.math_ops.
的函数,结果相同):这通过了初始编译,但是当应用实际数据时,出现以下错误:
In[0].dim(0) and In[1].dim(0) must be the same: [64,58,128] vs [1,128,128]
我也知道为什么会这样-我复制了
U
的尺寸,现在是1
,但是minibatch的大小64
不合适。我如何在张量矩阵输入上正确进行矩阵乘法(对于未知的批量大小)?