Tensorflow-具有批处理数据的输入矩阵的矩阵
python
tensorflow
5
0

我有一些由input_x表示的数据。它是一个未知大小的张量(应分批输入),每个项目的大小均为ninput_x经历tf.nn.embedding_lookup ,因此embed现在具有尺寸[?, n, m] ,其中m是嵌入尺寸, ?是嵌入尺寸?指未知的批次大小。

此处描述:

input_x = tf.placeholder(tf.int32, [None, n], name="input_x") 
embed = tf.nn.embedding_lookup(W, input_x)

我现在正在尝试将输入数据中的每个样本(现在通过嵌入维进行扩展)乘以矩阵变量U ,但我似乎不知道该怎么做。

我首先尝试使用tf.matmul但由于形状不匹配而导致错误。然后,我通过扩展U的维并应用batch_matmul尝试以下batch_matmul (我也尝试了来自tf.nn.math_ops.的函数,结果相同):

U = tf.Variable( ... )    
U1 = tf.expand_dims(U,0)
h=tf.batch_matmul(embed, U1)

这通过了初始编译,但是当应用实际数据时,出现以下错误:

In[0].dim(0) and In[1].dim(0) must be the same: [64,58,128] vs [1,128,128]

我也知道为什么会这样-我复制了U的尺寸,现在是1 ,但是minibatch的大小64不合适。

我如何在张量矩阵输入上正确进行矩阵乘法(对于未知的批量大小)?

参考资料:
Stack Overflow
收藏
评论
共 4 个回答
高赞 时间 活跃

先前的答案已过时。目前, tf.matmul()支持等级大于2的张量:

输入必须是矩阵(或秩大于2的张量,表示矩阵的批次),并且可能在转置后具有匹配的内部尺寸。

同样, tf.batch_matmul()也被删除,而tf.matmul()是进行批处理乘法的正确方法。可以从以下代码中了解主要思想:

import tensorflow as tf
batch_size, n, m, k = 10, 3, 5, 2
A = tf.Variable(tf.random_normal(shape=(batch_size, n, m)))
B = tf.Variable(tf.random_normal(shape=(batch_size, m, k)))
tf.matmul(A, B)

现在您将收到形状为(batch_size, n, k)的张量。这是这里发生的事情。假设你拥有batch_size矩阵nxmbatch_size的矩阵mxk 。现在,为每对它们计算nxm X mxk ,这将为您提供一个nxk矩阵。您将拥有它们的batch_size

请注意,类似这样的内容也是有效的:

A = tf.Variable(tf.random_normal(shape=(a, b, n, m)))
B = tf.Variable(tf.random_normal(shape=(a, b, m, k)))
tf.matmul(A, B)

会给你一个形状(a, b, n, k)

收藏
评论

matmul操作仅适用于矩阵(二维张量)。这是执行此操作的两种主要方法,都假设U是2D张量。

  1. embed到2D张量和乘法每个区域具有U单独。像这样使用tf.scan()可能最容易做到这一点:

     h = tf.scan(lambda a, x: tf.matmul(x, U), embed) 
  2. 另一方面,如果效率很重要,则最好将embed重塑为2D张量,以便可以用单个matmul如下所示:

     embed = tf.reshape(embed, [-1, m]) h = tf.matmul(embed, U) h = tf.reshape(h, [-1, n, c]) 

    其中cU的列数。最后一次重塑将确保h是3D张量,其中第0维对应于该批处理,就像原始x_inputembed

收藏
评论

我想将一批矩阵与一批相同长度的矩阵成对相乘

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最终依赖于tranposematmul进行计算。

因此,即使einsum是编写矩阵乘法的一种非常方便的方法,但它einsum了下面操作的复杂性-例如,猜测einsum表达式将转置数据多少次einsum ,因此该操作将花费多少。同样,它可能掩盖了一个事实,即同一操作可能有多种选择(请参阅案例3.2),而不一定选择更好的选择。

因此,我个人将使用上述明确的公式来更好地传达它们各自的复杂性。尽管如果您知道自己在做什么,并且喜欢einsum语法的简单性,那么einsum

收藏
评论

正如@Stryke回答的那样,有两种方法可以实现此目的:1.扫描和2.重塑

  1. tf.scan需要lambda函数,通常用于递归操作。相同的一些示例在这里: https : //rdipietro.github.io/tensorflow-scan-examples/

  2. 我个人更喜欢重塑,因为它更直观。如果您尝试将3D张量中的每个矩阵乘以2D张量的矩阵,例如Cijl = Aijk * Bkl,则可以通过简单的整形来实现。

     A' = tf.reshape(Aijk,[i*j,k]) C' = tf.matmul(A',Bkl) C = tf.reshape(C',[i,j,l]) 
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号