我有两个向量v
和w
,我想从中创建一个矩阵m
,以便:
m[i, j] = v[i] * w[j]
换句话说,我想计算它们的外部产品。我可以使用theano.tensor.outer
或向v
和v
添加新索引并使用dot
产品来完成此操作。
m = T.dot(v[:,numpy.newaxis], w[numpy.newaxis,:])
现在,我尝试解决一个更普遍的问题。而不是两个向量v
和w
我有两个矩阵(我再次称它们为v
和w
)我想从矩阵计算每一行的外积v
与矩阵w
的对应行(第一个矩阵中的第i行应该与第二个矩阵的第i行相乘)。所以,我想做那样的事情:
m1 = T.tensordot(v[:,:, numpy.newaxis], w[:,:,numpy.newaxis], axes = [[2],[2]])
m[i, j, k] = m1[i, k, j, k]
换句话说,m[:,:,k]
是与矩阵k_th
的矩阵v
和k_th
行的w
行的外积相对应的矩阵。
我发现上述"解决方案"有两个问题。首先,它不是一个真正的解决方案,因为代码的第二行不是正确的theano代码。所以,我的第一个问题是如何做到这一点"高级切片"通过强制某些索引相等。例如m[i, k] = a[i, k, i, i, k]
。其次,我不喜欢这样的事实:我首先从两个2D张量创建一个4D tesnor(m1
),然后我将其缩减回3D张量。它可能非常耗费内存。我想可以避免它。
答案 0 :(得分:4)
我们需要使用dimshuffle
将可广播的维度引入到两个输入矩阵中,然后让broadcasting
处理元素乘法,从而产生相应行之间的外积。
因此,将V
和W
作为theano矩阵,只需执行 -
V.dimshuffle(0, 1, 'x')*W.dimshuffle(0, 'x', 1)
在NumPy
中,我们有np.newaxis
来扩展维度,np.transpose()
用于置换维度。使用theno
,dimshuffle
可以使用列表维度ID和x
混合执行这两项任务,以引入新的可广播轴。< / p>
示例运行
1)输入:
# Numpy arrays
In [121]: v = np.random.randint(11,99,(3,4))
...: w = np.random.randint(11,99,(3,5))
...:
# Perform outer product on corresponding rows in inputs
In [122]: for i in range(v.shape[0]):
...: print(np.outer(v[i],w[i]))
...:
[[2726 1972 1740 2117 1972]
[8178 5916 5220 6351 5916]
[7520 5440 4800 5840 5440]
[8648 6256 5520 6716 6256]]
[[8554 3458 8918 4186 4277]
[1786 722 1862 874 893]
[8084 3268 8428 3956 4042]
[2444 988 2548 1196 1222]]
[[2945 2232 1209 372 682]
[2565 1944 1053 324 594]
[7125 5400 2925 900 1650]
[6840 5184 2808 864 1584]]
2)Theano部分:
# Get to theano : Get the theano matrix versions
In [123]: V = T.matrix('v')
...: W = T.matrix('w')
...:
# Use proposed code
In [124]: OUT = V.dimshuffle(0, 1, 'x')*W.dimshuffle(0, 'x', 1)
# Create a function out of it and then use on input NumPy arrays
In [125]: f = function([V,W], OUT)
3)验证结果:
In [126]: f(v,w) # Verify results against the earlier loopy results
Out[126]:
array([[[ 2726., 1972., 1740., 2117., 1972.],
[ 8178., 5916., 5220., 6351., 5916.],
[ 7520., 5440., 4800., 5840., 5440.],
[ 8648., 6256., 5520., 6716., 6256.]],
[[ 8554., 3458., 8918., 4186., 4277.],
[ 1786., 722., 1862., 874., 893.],
[ 8084., 3268., 8428., 3956., 4042.],
[ 2444., 988., 2548., 1196., 1222.]],
[[ 2945., 2232., 1209., 372., 682.],
[ 2565., 1944., 1053., 324., 594.],
[ 7125., 5400., 2925., 900., 1650.],
[ 6840., 5184., 2808., 864., 1584.]]])
答案 1 :(得分:1)
>>> a = b = np.arange(8).reshape([2,4])
>>> a[:,None,:]*b[:,:,None]
array([[[ 0, 0, 0, 0],
[ 0, 1, 2, 3],
[ 0, 2, 4, 6],
[ 0, 3, 6, 9]],
[[16, 20, 24, 28],
[20, 25, 30, 35],
[24, 30, 36, 42],
[28, 35, 42, 49]]])
答案 2 :(得分:1)
我无法相信没有人试图使用np.einsum
。
w
array([[1, 8, 9, 2],
[1, 2, 9, 0],
[5, 8, 7, 3],
[2, 9, 8, 2]])
v
array([[1, 4, 5, 9],
[9, 1, 3, 7],
[9, 6, 1, 5],
[4, 9, 7, 0]])
for i in range(w.shape[0]):
print(np.outer(w[i], v[i]))
[[ 1 4 5 9]
[ 8 32 40 72]
[ 9 36 45 81]
[ 2 8 10 18]]
[[ 9 1 3 7]
[18 2 6 14]
[81 9 27 63]
[ 0 0 0 0]]
[[45 30 5 25]
[72 48 8 40]
[63 42 7 35]
[27 18 3 15]]
[[ 8 18 14 0]
[36 81 63 0]
[32 72 56 0]
[ 8 18 14 0]]
np.einsum('ij,ik->ijk', w, v)
array([[[ 1, 4, 5, 9],
[ 8, 32, 40, 72],
[ 9, 36, 45, 81],
[ 2, 8, 10, 18]],
[[ 9, 1, 3, 7],
[18, 2, 6, 14],
[81, 9, 27, 63],
[ 0, 0, 0, 0]],
[[45, 30, 5, 25],
[72, 48, 8, 40],
[63, 42, 7, 35],
[27, 18, 3, 15]],
[[ 8, 18, 14, 0],
[36, 81, 63, 0],
[32, 72, 56, 0],
[ 8, 18, 14, 0]]])
看起来等效的Theano函数是theano.tensor.batched_dot
(它应该比einsum
更快),但我对Theano没有经验。