Sympy Tensor产品错误结果

时间:2019-02-24 01:41:47

标签: python numpy sympy

我有一个大小为[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'

1 个答案:

答案 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]]])

我们可以对另一个einsumnp.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])