我有一个大小为[3x2]的张量W和一个大小为[2x12]的张量Tr。我会
A = Array(Matrix([
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1]
])).reshape(3,3,4)
b = Array(Matrix([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
])).reshape(3,4,1)
MatMul(A,b)
我相信这是通过matmul完成的吗?但是,当我尝试使用SymPy Matmul进行操作时,出现错误:
AttributeError: 'ImmutableDenseNDimArray' object has no attribute 'as_base_exp'
答案 0 :(得分:2)
让我们在matmul
中阐明numpy
的动作:
In [8]: A = np.arange(24).reshape(2,3,4); B = np.arange(8).reshape(2,4,1)
In [9]: A@B
Out[9]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
In [10]: _.shape
Out[10]: (2, 3, 1)
这是在最后两个轴上进行dot
或2d矩阵乘积。在第一个轴上生效的批处理:
In [11]: A[0].dot(B[0])
Out[11]:
array([[14],
[38],
[62]])
我更喜欢einsum
的清晰度,尽管i
轴承载着,k
轴是乘积之和。
In [12]: np.einsum('ijk,ikl->ijl',A,B)
Out[12]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
我认为这里的问题是sympy/tensor
模块是否可以做到这一点。
In [13]: from sympy import Array, tensorproduct, tensorcontraction
In [14]: As = Array(A[0])
In [15]: As
Out[15]: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
In [16]: Bs = Array(B[0])
In [17]: Bs
Out[17]: [[0], [1], [2], [3]]
In [18]: tensorproduct(As,Bs)
Out[18]: [[[[0], [0], [0], [0]], [[0], [1], [2], [3]], [[0], [2], [4], [6]], [[0], [3], [6], [9]]], [[[0], [4], [8], [12]], [[0], [5], [10], [15]], [[0], [6], [12], [18]], [[0], [7], [14], [21]]], [[[0], [8], [16], [24]], [[0], [9], [18], [27]], [[0], [10], [20], [30]], [[0], [11], [22], [33]]]]
In [19]: tensorcontraction(_, (1,2))
Out[19]: [[14], [38], [62]]
因此Out[19]
与Out[11]
相匹配。我们可以为A[1]
等重复此操作。
并且使用sympy/Matrix
类:
In [20]: from sympy import Matrix
In [21]: Matrix(A[0])*Matrix(B[0])
Out[21]:
Matrix([
[14],
[38],
[62]])
制作3d sympy Array
:
In [22]: AS = Array(A)
In [23]: AS
Out[23]: [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]
In [24]: AS.shape
Out[24]: (2, 3, 4)
In [25]: BS = Array(B)
In [26]: BS.shape
Out[26]: (2, 4, 1)
tensorproduct
产生6d数组:
In [28]: CS = tensorproduct(AS, BS)
In [29]: CS.shape
Out[29]: (2, 3, 4, 2, 4, 1)
删除中间的2
:
In [30]: CS[:,:,:,0,:,:].shape
Out[30]: (2, 3, 4, 4, 1)
并像以前一样进行收缩:
In [31]: tensorcontraction(CS[:,:,:,0,:,:],(2,3)).shape
Out[31]: (2, 3, 1)
In [32]: tensorcontraction(CS[:,:,:,0,:,:],(2,3))
Out[32]: [[[14], [38], [62]], [[86], [110], [134]]]
上半部匹配Out[9]
,但其余部分不匹配。
matmul
被添加到numpy
的大部分原因是很难用np.dot
(和/或np.tensordot
)实现所需的“批处理”操作。 np.einsum
是唯一可行的选择。
此einsum
收缩为k
,同时包含Out[9]
和Out[32]
值:
In [80]: np.einsum('ijk,lkn',A,B)
Out[80]:
array([[[[ 14],
[ 38]],
[[ 38],
[126]],
[[ 62],
[214]]],
[[[ 86],
[302]],
[[110],
[390]],
[[134],
[478]]]])
问题是,如何选择正确的子集。没有索引的tensorcontraction
也会产生这些。 CS[:,:,:,0,:,:]
不是删除重复项的正确方法。
In [81]: tensorcontraction(CS, (2,4))
Out[81]: [[[[14], [38]], [[38], [126]], [[62], [214]]], [[[86], [302]], [[110], [390]], [[134], [478]]]]
Out[81]: [[[[14], [38]],
[[38], [126]],
[[62], [214]]],
[[[86], [302]],
[[110], [390]],
[[134], [478]]]
]
使用einsum
,我可以对角线:
In [96]: np.einsum('ijk,lkn',A,B)[[0,1],:,[0,1],:]
Out[96]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
我们可以对另一个einsum
,np.einsum('ijim->ijm', np.einsum('ijk,lkn',A,B))
进行合并,合并为In[12]
表达式'ijk,ikl-> ijl'。
我可以对Out[81]
对象执行相同的操作。 sympy.Array
显然没有实现与numpy
相同类型的高级索引:
In [108]: np.array(Out[81].tolist())[[0,1],:,[0,1],:]
Out[108]:
array([[[14],
[38],
[62]],
[[302],
[390],
[478]]], dtype=object)
我应该记得,在其他情况下,当我尝试使用matmul
实现np.dot
样式的批处理产品时,我必须采用这样的对角线。实际上,dot
在非合并维度上采用外部乘积,我们必须舍弃大多数值。
另一种查看方式是我们需要np.dot(A[0], B[0])
和np.dot(A[1], B[1])
。但是tesorproduct
(外部产品)也给了我们np.dot(A[0], B[1])
和np.dot(A[1], B[0])
。