张量流中的外积
Outer product in tensorflow
在tensorflow中,有很好的entrywise和矩阵乘法函数,但是在查看文档后,我找不到任何内部函数来获取两个张量的外积,即,通过较小张量元素(如 numpy.outer)的所有可能乘积生成更大的张量:
v_{i,j} = x_i*h_j
或
M_{ij,kl} = A_{ij}*B_{kl}
tensorflow有这样的功能吗?
是的,您可以利用 tensorflow 的广播语义来做到这一点。第一个的大小为 1xN,第二个的大小为 Mx1,当你将它们相乘时,所有结果都会广播到 MxN。
(您可以在 numpy 中尝试相同的东西,看看它在更简单的上下文中的表现,顺便说一句:
a = np.array([1, 2, 3, 4, 5]).reshape([5,1])
b = np.array([6, 7, 8, 9, 10]).reshape([1,5])
a*b
你在 tensorflow 中具体如何做取决于你想使用哪个轴以及你想要乘法的语义,但一般的想法是适用的。
以防其他人偶然发现这个问题,根据 tensorflow 文档,您可以使用 tf.einsum()
函数来计算两个张量 a
和 b
的外积:
# Outer product
>>> einsum('i,j->ij', u, v) # output[i,j] = u[i]*v[j]
有点令人惊讶的是,直到最近,在 tensorflow 中还没有简单和“自然”的方法在任意张量(也称为“张量积”)之间进行外积,特别是考虑到库的名称。 .
有了 tensorflow>=1.6
,您现在终于可以通过简单的方式获得您想要的东西:
M = tf.tensordot(A, B, axes=0)
在tensorflow的早期版本中,axes=0
引发了一个ValueError: 'axes' must be at least 1.
。不知何故 tf.tensordot()
过去至少需要一个维度才能实际求和。简单的方法是简单地添加一个带有 tf.expand_dims()
.
的“假”维度
在 tensorflow<=1.5
上,您可以通过执行以下操作获得与上述相同的结果:
M = tf.tensordot(tf.expand_dims(A, 0), tf.expand_dims(B, 0), axes=[[0],[0]])
这会在位置 0 为两个张量添加维度 1 的新索引,然后让 tf.tensordot()
对这些索引求和。
tf.multiply(及其“*”快捷方式)导致外积,无论是否使用批次。特别是,如果两个输入张量具有 [batch, n, 1] 和 [batch, 1, n] 的 3D 形状,则此操作将计算 [n,1]、[1,n] 每个批次中的每个样本。如果没有批次,则两个输入张量是二维的,此操作将计算相同的外积。
另一方面,虽然 tf.tensordot 产生二维矩阵的外积,但在添加批次时它并没有类似地广播。
没有批次:
a_np = np.array([[1, 2, 3]]) # shape: (1,3) [a row vector], 2D Tensor
b_np = np.array([[4], [5], [6]]) # shape: (3,1) [a column vector], 2D Tensor
a = tf.placeholder(dtype='float32', shape=[1, 3])
b = tf.placeholder(dtype='float32', shape=[3, 1])
c = a*b # Result: an outer-product of a,b
d = tf.multiply(a,b) # Result: an outer-product of a,b
e = tf.tensordot(a,b, axes=[0,1]) # Result: an outer-product of a,b
有一批:
a_np = np.array([[[1, 2, 3]], [[4, 5, 6]]]) # shape: (2,1,3) [a batch of two row vectors], 3D Tensor
b_np = np.array([[[7], [8], [9]], [[10], [11], [12]]]) # shape: (2,3,1) [a batch of two column vectors], 3D Tensor
a = tf.placeholder(dtype='float32', shape=[None, 1, 3])
b = tf.placeholder(dtype='float32', shape=[None, 3, 1])
c = a*b # Result: an outer-product per batch
d = tf.multiply(a,b) # Result: an outer-product per batch
e = tf.tensordot(a,b, axes=[1,2]) # Does NOT result with an outer-product per batch
运行 这两个图表中的任何一个:
sess = tf.Session()
result_astrix = sess.run(c, feed_dict={a:a_np, b: b_np})
result_multiply = sess.run(d, feed_dict={a:a_np, b: b_np})
result_tensordot = sess.run(e, feed_dict={a:a_np, b: b_np})
print('a*b:')
print(result_astrix)
print('tf.multiply(a,b):')
print(result_multiply)
print('tf.tensordot(a,b, axes=[1,2]:')
print(result_tensordot)
正如其他答案所指出的,外积可以使用广播来完成:
a = tf.range(10)
b = tf.range(5)
outer = a[..., None] * b[None, ...]
tf.InteractiveSession().run(outer)
# array([[ 0, 0, 0, 0, 0],
# [ 0, 1, 2, 3, 4],
# [ 0, 2, 4, 6, 8],
# [ 0, 3, 6, 9, 12],
# [ 0, 4, 8, 12, 16],
# [ 0, 5, 10, 15, 20],
# [ 0, 6, 12, 18, 24],
# [ 0, 7, 14, 21, 28],
# [ 0, 8, 16, 24, 32],
# [ 0, 9, 18, 27, 36]], dtype=int32)
解释:
a[..., None]
在最后一个轴后插入一个长度为 1 的新维度。
- 类似地,
b[None, ...]
在第一个轴之前插入一个长度为 1 的新维度。
- 元素范围的乘法然后将张量从形状
(10, 1) * (1, 5)
传播到 (10, 5) * (10, 5)
,计算外积。
插入附加维度的位置决定了计算外积的维度。例如,如果两个张量都有批量大小,您可以使用 :
跳过它,它给出 a[:, ..., None] * b[:, None, ...]
。这可以进一步缩写为 a[..., None] * b[:, None]
。要在最后一个维度上执行外积并因此支持任意数量的批量维度,请使用 a[..., None] * b[..., None, :]
.
我本来想对 MasDra 发表评论,但作为新注册用户,我不让。
排列成长度顺序U的多个向量的一般外积可以通过
得到
tf.einsum(','.join(string.ascii_lowercase[0:order])+'->'+string.ascii_lowercase[0:order], *U)
在tensorflow中,有很好的entrywise和矩阵乘法函数,但是在查看文档后,我找不到任何内部函数来获取两个张量的外积,即,通过较小张量元素(如 numpy.outer)的所有可能乘积生成更大的张量:
v_{i,j} = x_i*h_j
或
M_{ij,kl} = A_{ij}*B_{kl}
tensorflow有这样的功能吗?
是的,您可以利用 tensorflow 的广播语义来做到这一点。第一个的大小为 1xN,第二个的大小为 Mx1,当你将它们相乘时,所有结果都会广播到 MxN。
(您可以在 numpy 中尝试相同的东西,看看它在更简单的上下文中的表现,顺便说一句:
a = np.array([1, 2, 3, 4, 5]).reshape([5,1])
b = np.array([6, 7, 8, 9, 10]).reshape([1,5])
a*b
你在 tensorflow 中具体如何做取决于你想使用哪个轴以及你想要乘法的语义,但一般的想法是适用的。
以防其他人偶然发现这个问题,根据 tensorflow 文档,您可以使用 tf.einsum()
函数来计算两个张量 a
和 b
的外积:
# Outer product
>>> einsum('i,j->ij', u, v) # output[i,j] = u[i]*v[j]
有点令人惊讶的是,直到最近,在 tensorflow 中还没有简单和“自然”的方法在任意张量(也称为“张量积”)之间进行外积,特别是考虑到库的名称。 .
有了 tensorflow>=1.6
,您现在终于可以通过简单的方式获得您想要的东西:
M = tf.tensordot(A, B, axes=0)
在tensorflow的早期版本中,axes=0
引发了一个ValueError: 'axes' must be at least 1.
。不知何故 tf.tensordot()
过去至少需要一个维度才能实际求和。简单的方法是简单地添加一个带有 tf.expand_dims()
.
在 tensorflow<=1.5
上,您可以通过执行以下操作获得与上述相同的结果:
M = tf.tensordot(tf.expand_dims(A, 0), tf.expand_dims(B, 0), axes=[[0],[0]])
这会在位置 0 为两个张量添加维度 1 的新索引,然后让 tf.tensordot()
对这些索引求和。
tf.multiply(及其“*”快捷方式)导致外积,无论是否使用批次。特别是,如果两个输入张量具有 [batch, n, 1] 和 [batch, 1, n] 的 3D 形状,则此操作将计算 [n,1]、[1,n] 每个批次中的每个样本。如果没有批次,则两个输入张量是二维的,此操作将计算相同的外积。 另一方面,虽然 tf.tensordot 产生二维矩阵的外积,但在添加批次时它并没有类似地广播。
没有批次:
a_np = np.array([[1, 2, 3]]) # shape: (1,3) [a row vector], 2D Tensor
b_np = np.array([[4], [5], [6]]) # shape: (3,1) [a column vector], 2D Tensor
a = tf.placeholder(dtype='float32', shape=[1, 3])
b = tf.placeholder(dtype='float32', shape=[3, 1])
c = a*b # Result: an outer-product of a,b
d = tf.multiply(a,b) # Result: an outer-product of a,b
e = tf.tensordot(a,b, axes=[0,1]) # Result: an outer-product of a,b
有一批:
a_np = np.array([[[1, 2, 3]], [[4, 5, 6]]]) # shape: (2,1,3) [a batch of two row vectors], 3D Tensor
b_np = np.array([[[7], [8], [9]], [[10], [11], [12]]]) # shape: (2,3,1) [a batch of two column vectors], 3D Tensor
a = tf.placeholder(dtype='float32', shape=[None, 1, 3])
b = tf.placeholder(dtype='float32', shape=[None, 3, 1])
c = a*b # Result: an outer-product per batch
d = tf.multiply(a,b) # Result: an outer-product per batch
e = tf.tensordot(a,b, axes=[1,2]) # Does NOT result with an outer-product per batch
运行 这两个图表中的任何一个:
sess = tf.Session()
result_astrix = sess.run(c, feed_dict={a:a_np, b: b_np})
result_multiply = sess.run(d, feed_dict={a:a_np, b: b_np})
result_tensordot = sess.run(e, feed_dict={a:a_np, b: b_np})
print('a*b:')
print(result_astrix)
print('tf.multiply(a,b):')
print(result_multiply)
print('tf.tensordot(a,b, axes=[1,2]:')
print(result_tensordot)
正如其他答案所指出的,外积可以使用广播来完成:
a = tf.range(10)
b = tf.range(5)
outer = a[..., None] * b[None, ...]
tf.InteractiveSession().run(outer)
# array([[ 0, 0, 0, 0, 0],
# [ 0, 1, 2, 3, 4],
# [ 0, 2, 4, 6, 8],
# [ 0, 3, 6, 9, 12],
# [ 0, 4, 8, 12, 16],
# [ 0, 5, 10, 15, 20],
# [ 0, 6, 12, 18, 24],
# [ 0, 7, 14, 21, 28],
# [ 0, 8, 16, 24, 32],
# [ 0, 9, 18, 27, 36]], dtype=int32)
解释:
a[..., None]
在最后一个轴后插入一个长度为 1 的新维度。- 类似地,
b[None, ...]
在第一个轴之前插入一个长度为 1 的新维度。 - 元素范围的乘法然后将张量从形状
(10, 1) * (1, 5)
传播到(10, 5) * (10, 5)
,计算外积。
插入附加维度的位置决定了计算外积的维度。例如,如果两个张量都有批量大小,您可以使用 :
跳过它,它给出 a[:, ..., None] * b[:, None, ...]
。这可以进一步缩写为 a[..., None] * b[:, None]
。要在最后一个维度上执行外积并因此支持任意数量的批量维度,请使用 a[..., None] * b[..., None, :]
.
我本来想对 MasDra 发表评论,但作为新注册用户,我不让。
排列成长度顺序U的多个向量的一般外积可以通过
得到tf.einsum(','.join(string.ascii_lowercase[0:order])+'->'+string.ascii_lowercase[0:order], *U)