Python 如何用广播计算点积?

Python 如何用广播计算点积?,python,numpy,matrix,array-broadcasting,dot-product,Python,Numpy,Matrix,Array Broadcasting,Dot Product,我想计算点积 a=np.arange(18).reshape(2,3,3) b=np.arange(6).reshape(2,3) 在广播方面,我试着 a[0]@b[0] array([ 5, 14, 23]) a[1]@b[1] array([122, 158, 194]) 但是形状不是我想要的 c=a@b[...,None] c array([[[ 5], [ 14], [ 23]], [[122], [158],

我想计算点积

a=np.arange(18).reshape(2,3,3)
b=np.arange(6).reshape(2,3)
在广播方面,我试着

a[0]@b[0]
array([ 5, 14, 23])

a[1]@b[1]
array([122, 158, 194])
但是形状不是我想要的

c=a@b[...,None]
c
array([[[  5],
        [ 14],
        [ 23]],

       [[122],
        [158],
        [194]]])
  • 如何在计算中获得形状
    (2,3)
    ,而不是
    (2,3,1)
    ,而不是改变轴的方式

  • 对于广播,为什么
    [:,None]
    不起作用?这里的
    是什么意思


  • 在本例中,
    b[…,None]
    b[:,:,None]
    ,a(2,3,1)数组相同
    表示“根据需要尽可能多的

    因此,点积和与
    a
    的最后
    3
    b
    的中间
    3
    (倒数第二)

    您可以使用
    挤压
    来去除大小为1的维度

    但是对于(2,3,3)和(2,3),您想要哪个
    dot
    产品?在
    einsum
    符号中,我可以看到

    c.shape
    (2, 3, 1)
    
    dot
    具有2个2d阵列的产品定义良好。但是当一个是3d的时候,会有一些模棱两可的地方

    'ijk,ij->ik'
    'ijk,ik->ij'
    'ijk,mj->imk'
    etc
    
    matmul
    文件中的相关注释如下:

    如果任一参数为N-D,N>2,则将其视为 位于最后两个索引中的矩阵,并相应地广播

    ValueError-如果
    a
    的最后一个维度的大小与
    b
    的倒数第二个维度


    matmul
    中的广播示例如下:

    In [2]: a=np.arange(18).reshape(2,3,3)
       ...: b=np.arange(6).reshape(2,3)
       ...: 
    
    In [3]: np.einsum('ijk,ik->ij',a,b)
    Out[3]: 
    array([[  5,  14,  23],
           [122, 158, 194]])
    
    In [4]: np.dot(a,b)
    ValueError: shapes (2,3,3) and (2,3) not aligned: 3 (dim 2) != 2 (dim 0)
    
    In [6]: np.dot(a,b[:,:,None]).shape  # 'ijk,kml->ijml'
    Out[6]: (2, 3, 2, 1)
    
    In [7]: np.matmul(a,b[:,:,None]).shape   # @ 
    Out[7]: (2, 3, 1)
    In [8]: np.einsum('ijk,ikm->ijm',a,b[...,None])
    Out[8]: 
    array([[[  5],
            [ 14],
            [ 23]],
    
           [[122],
            [158],
            [194]]])
    
    In [12]: np.squeeze(_)   # removing that added dimension
    Out[12]: 
    array([[  5,  14,  23],
           [122, 158, 194]])
    
    更新 我刚刚了解到,
    optimize=True
    现在是
    einsum
    的默认值,而且这并不总是最快的

    In [15]: a@b.T
    Out[15]: 
    array([[[  5,  14],
            [ 14,  50],
            [ 23,  86]],
    
           [[ 32, 122],
            [ 41, 158],
            [ 50, 194]]])
    
    In [16]: _.shape
    Out[16]: (2, 3, 2)
    
    In [17]: a@b.T[None,:,:]
    Out[17]: 
    array([[[  5,  14],
            [ 14,  50],
            [ 23,  86]],
    
           [[ 32, 122],
            [ 41, 158],
            [ 50, 194]]])
    

    在这种情况下,
    b[…,None]
    b[:,:,None]
    ,a(2,3,1)数组相同
    表示“根据需要尽可能多的

    因此,点积和与
    a
    的最后
    3
    b
    的中间
    3
    (倒数第二)

    您可以使用
    挤压
    来去除大小为1的维度

    但是对于(2,3,3)和(2,3),您想要哪个
    dot
    产品?在
    einsum
    符号中,我可以看到

    c.shape
    (2, 3, 1)
    
    dot
    具有2个2d阵列的产品定义良好。但是当一个是3d的时候,会有一些模棱两可的地方

    'ijk,ij->ik'
    'ijk,ik->ij'
    'ijk,mj->imk'
    etc
    
    matmul
    文件中的相关注释如下:

    如果任一参数为N-D,N>2,则将其视为 位于最后两个索引中的矩阵,并相应地广播

    ValueError-如果
    a
    的最后一个维度的大小与
    b
    的倒数第二个维度


    matmul
    中的广播示例如下:

    In [2]: a=np.arange(18).reshape(2,3,3)
       ...: b=np.arange(6).reshape(2,3)
       ...: 
    
    In [3]: np.einsum('ijk,ik->ij',a,b)
    Out[3]: 
    array([[  5,  14,  23],
           [122, 158, 194]])
    
    In [4]: np.dot(a,b)
    ValueError: shapes (2,3,3) and (2,3) not aligned: 3 (dim 2) != 2 (dim 0)
    
    In [6]: np.dot(a,b[:,:,None]).shape  # 'ijk,kml->ijml'
    Out[6]: (2, 3, 2, 1)
    
    In [7]: np.matmul(a,b[:,:,None]).shape   # @ 
    Out[7]: (2, 3, 1)
    In [8]: np.einsum('ijk,ikm->ijm',a,b[...,None])
    Out[8]: 
    array([[[  5],
            [ 14],
            [ 23]],
    
           [[122],
            [158],
            [194]]])
    
    In [12]: np.squeeze(_)   # removing that added dimension
    Out[12]: 
    array([[  5,  14,  23],
           [122, 158, 194]])
    
    更新 我刚刚了解到,
    optimize=True
    现在是
    einsum
    的默认值,而且这并不总是最快的

    In [15]: a@b.T
    Out[15]: 
    array([[[  5,  14],
            [ 14,  50],
            [ 23,  86]],
    
           [[ 32, 122],
            [ 41, 158],
            [ 50, 194]]])
    
    In [16]: _.shape
    Out[16]: (2, 3, 2)
    
    In [17]: a@b.T[None,:,:]
    Out[17]: 
    array([[[  5,  14],
            [ 14,  50],
            [ 23,  86]],
    
           [[ 32, 122],
            [ 41, 158],
            [ 50, 194]]])
    

    Thx,我再次编辑我的问题,我想点积
    a[0]@b[0]
    a[1]@b[1]
    。我仍然可以使用
    @
    操作符来实现形状
    (2,3)
    ?@kindchan,根据
    matmul
    规则,您需要展开
    b
    ,使其为三维。
    a
    的最后一个dim必须与
    b
    的第二个到最后一个匹配。为了得到(2,3),你已经挤出了你添加的维度-after.thx对于所有事情,我认为
    np.einsum
    可能是一个更好的方法。thx,我再次编辑我的问题,我想点积
    a[0]@b[0]
    a[1]@b[1]
    。我仍然可以使用
    @
    操作符来实现形状
    (2,3)
    ?@kindchan,根据
    matmul
    规则,您需要展开
    b
    ,使其为三维。
    a
    的最后一个dim必须与
    b
    的第二个到最后一个匹配。为了得到(2,3),您已经挤出了您添加的维度-after.thx,我认为
    np.einsum
    可能是一个更好的方法。您并不是真正的广播。在产品中使用
    b
    之前,先展开其维度<代码>a@b.T确实使用广播,将
    b.T
    扩展到(1,3,2)到(3,3,2),这
    点产生(2,3,2)。你不是真正的广播。在产品中使用
    b
    之前,先展开其维度<代码>a@b.T
    确实使用广播,将
    b.T
    扩展到(1,3,2)到(3,3,2),从而
    产生(2,3,2)。