Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python numpy.tensordot函数是如何逐步工作的?_Python_Numpy - Fatal编程技术网

Python numpy.tensordot函数是如何逐步工作的?

Python numpy.tensordot函数是如何逐步工作的?,python,numpy,Python,Numpy,我是numpy新手,因此在可视化numpy.tensordot()函数的工作时遇到一些问题。根据tensordot的文档,轴在参数中传递,其中轴=0或1表示正规矩阵乘法,而轴=2表示收缩 有人能解释一下乘法是如何进行的吗 示例1:a=[1,1]b=[2,2]对于轴=0,1为什么它会对轴=2抛出错误? 示例2:a=[[1,1],[1,1]]b=[[2,2],[2,2]]对于轴=0,1,2 编辑:这个答案最初的焦点是轴是一个元组,为每个参数指定一个或多个轴。这种使用允许我们在传统的点上执行变化,特别

我是numpy新手,因此在可视化
numpy.tensordot()
函数的工作时遇到一些问题。根据
tensordot
的文档,轴在参数中传递,其中轴=0或1表示正规矩阵乘法,而轴=2表示收缩

有人能解释一下乘法是如何进行的吗

示例1:
a=[1,1]b=[2,2]对于轴=0,1
为什么它会对轴=2抛出错误?
示例2:
a=[[1,1],[1,1]]b=[[2,2],[2,2]]对于轴=0,1,2


编辑:这个答案最初的焦点是
是一个元组,为每个参数指定一个或多个轴。这种使用允许我们在传统的
点上执行变化,特别是对于大于2d的阵列(我在链接问题中的回答也是,)。轴作为标量是一种特殊情况,可以转换为元组版本。因此,它的核心仍然是一个
dot
产品

作为元组的轴
a
b
是列表
tensordot
将它们转换为数组

In [236]: np.tensordot(a,b,(0,0))
Out[236]: array(4)
因为它们都是一维数组,所以我们将轴值指定为0

如果我们尝试指定1:

In [237]: np.tensordot(a,b,(0,1))
---------------------------------------------------------------------------
   1282     else:
   1283         for k in range(na):
-> 1284             if as_[axes_a[k]] != bs[axes_b[k]]:
   1285                 equal = False
   1286                 break

IndexError: tuple index out of range
它正在检查
a
的轴0的大小是否与
b
的轴1的大小匹配。但是因为
b
是1d,所以它不能检查它

In [239]: np.array(a).shape[0]
Out[239]: 2
In [240]: np.array(b).shape[1]
IndexError: tuple index out of range
第二个示例是二维阵列:

In [242]: a=np.array([[1,1],[1,1]]); b=np.array([[2,2],[2,2]])
指定
a
的最后一个轴和
b
的第一个轴(倒数第二个轴),生成常规矩阵(点)积:

更好的诊断价值:

In [250]: a=np.array([[1,2],[3,4]]); b=np.array([[2,3],[2,1]])
In [251]: np.tensordot(a,b,(1,0))
Out[251]: 
array([[ 6,  5],
       [14, 13]])
In [252]: np.dot(a,b)
Out[252]: 
array([[ 6,  5],
       [14, 13]])

In [253]: np.tensordot(a,b,(0,1))
Out[253]: 
array([[11,  5],
       [16,  8]])
In [254]: np.dot(b,a)      # same numbers, different layout
Out[254]: 
array([[11, 16],
       [ 5,  8]])
In [255]: np.dot(b,a).T
Out[255]: 
array([[11,  5],
       [16,  8]])
另一对:

In [256]: np.tensordot(a,b,(0,0))
In [257]: np.dot(a.T,b)
轴的(0,1,2)明显错误。axis参数应该是2个数字或2个元组,对应于2个参数

tensordot
中的基本处理是对输入进行转置和整形,以便将结果传递给常规(a的最后一个,b的第二个到最后一个)矩阵积的
np.dot

轴作为标量 如果我对
tensordot
代码的读取正确,则
参数将转换为两个列表,其中包含:

def foo(axes):
    try:
        iter(axes)
    except Exception:
        axes_a = list(range(-axes, 0))
        axes_b = list(range(0, axes))
    else:
        axes_a, axes_b = axes
    try:
        na = len(axes_a)
        axes_a = list(axes_a)
    except TypeError:
        axes_a = [axes_a]
        na = 1
    try:
        nb = len(axes_b)
        axes_b = list(axes_b)
    except TypeError:
        axes_b = [axes_b]
        nb = 1

    return axes_a, axes_b
对于标量值0,1,2,结果为:

In [281]: foo(0)
Out[281]: ([], [])
In [282]: foo(1)
Out[282]: ([-1], [0])
In [283]: foo(2)
Out[283]: ([-2, -1], [0, 1])
axes=1
与在元组中指定相同:

In [284]: foo((-1,0))
Out[284]: ([-1], [0])
至于第二项:

In [285]: foo(((-2,-1),(0,1)))
Out[285]: ([-2, -1], [0, 1])
在我的最新示例中,
axes=2
与在2个阵列的所有轴上指定一个
dot
相同:

In [287]: np.tensordot(a,b,axes=2)
Out[287]: array(18)
In [288]: np.tensordot(a,b,axes=((0,1),(0,1)))
Out[288]: array(18)
In [292]: foo(((),()))
Out[292]: ([], [])
这与在阵列的展平1d视图上执行点操作相同:

In [289]: np.dot(a.ravel(), b.ravel())
Out[289]: 18
我已经演示了这些阵列的传统点积,
axes=1
情况

轴=0
轴=((),())
相同,两个数组没有求和轴:

In [287]: np.tensordot(a,b,axes=2)
Out[287]: array(18)
In [288]: np.tensordot(a,b,axes=((0,1),(0,1)))
Out[288]: array(18)
In [292]: foo(((),()))
Out[292]: ([], [])
np.tensordot(a,b,((),())
np.tensordot(a,b,axes=0)相同

当输入数组为1d时,是
foo(2)
翻译中的
-2
给您带来了问题
axes=1
是1d数组的“收缩”。换句话说,不要将文档中的单词描述过于字面化。他们只是试图描述代码的行为;它们不是正式的规范

einsum等价物 我认为
einsum
的轴规格更清晰、更强大。以下是0,1,2的等效值

In [295]: np.einsum('ij,kl',a,b)
Out[295]: 
array([[[[ 2,  3],
         [ 2,  1]],

        [[ 4,  6],
         [ 4,  2]]],


       [[[ 6,  9],
         [ 6,  3]],

        [[ 8, 12],
         [ 8,  4]]]])
In [296]: np.einsum('ij,jk',a,b)
Out[296]: 
array([[ 6,  5],
       [14, 13]])
In [297]: np.einsum('ij,ij',a,b)
Out[297]: 18
轴=0的情况相当于:

np.dot(a[:,:,None],b[:,None,:])
它添加了一个新的最后一个轴和新的第二个到最后一个轴,并对这些轴进行传统的点积求和。但我们通常用广播做这种“外部”乘法:

a[:,:,None,None]*b[None,None,:,:]
虽然对轴使用0,1,2很有趣,但它实际上并没有增加新的计算能力。轴的元组形式更强大、更有用

代码摘要(大步骤) 1-将
转换为
轴a
轴b
,如上述
foo
功能中所摘录

2-将
a
b
制成数组,并获得形状和ndim

3-检查要求和的轴上的匹配尺寸(收缩)

4-构建一个
新图形a
新图形a
;与
b
相同(复杂步骤)

5-
at=a.转置(新轴a).重塑(新形状a)
;对于
b

6-
res=dot(at,bt)

7-将
res
重塑为所需的返回形状

5和6是计算核心。4是概念上最复杂的步骤。对于所有
值,计算是相同的,
产品,但设置不同

超过0,1,2 虽然文档只提到标量轴的0,1,2,但代码并不限于这些值

In [331]: foo(3)
Out[331]: ([-3, -2, -1], [0, 1, 2])
如果输入为3,轴=3应工作:

In [330]: np.tensordot(np.ones((2,2,2)), np.ones((2,2,2)), axes=3)
Out[330]: array(8.)
或者更一般地说:

In [325]: np.tensordot(np.ones((2,2,2)), np.ones((2,2,2)), axes=0).shape
Out[325]: (2, 2, 2, 2, 2, 2)
In [326]: np.tensordot(np.ones((2,2,2)), np.ones((2,2,2)), axes=1).shape
Out[326]: (2, 2, 2, 2)
In [327]: np.tensordot(np.ones((2,2,2)), np.ones((2,2,2)), axes=2).shape
Out[327]: (2, 2)
In [328]: np.tensordot(np.ones((2,2,2)), np.ones((2,2,2)), axes=3).shape
Out[328]: ()
如果输入为0d,轴=0工作(轴=1不工作):

你能解释一下吗

In [363]: np.tensordot(np.ones((4,2,3)),np.ones((2,3,4)),axes=2).shape
Out[363]: (4, 4)
我已经使用了3d阵列的其他标量轴值。虽然可以产生成对的形状来工作,但更显式的元组轴值更容易使用。
0,1,2
选项是仅适用于特殊情况的捷径。元组方法更易于使用-尽管我仍然喜欢
einsum
表示法。

示例1-0:
np.tensordot([1,1],[2,2],axes=0)
在这种情况下,ab都有一个轴,并且具有形状
(2,)

axes=0
参数可以转换为(a的最后一个0轴)、(b的第一个0轴),或者在本例中是
((),())
。这些是将要收缩的轴

所有其他轴不会收缩。由于ab中的每一个都有第0个轴,而没有其他轴,因此这些轴是
((0,),(0,)

然后,tensordot操作如下(大致):

请注意,由于
In [363]: np.tensordot(np.ones((4,2,3)),np.ones((2,3,4)),axes=2).shape
Out[363]: (4, 4)
[
    [x*y for y in b]  # all the non-contraction axes in b
    for x in a        # all the non-contraction axes in a
]
sum(  # summing over contraction axis
    [x*y for x,y in zip(a, b)]  # contracted axes must line up
)
[
    [
        sum(  # summing the contracted indices
            [x*y for x,y in zip(v,w)]  # axis 1 of a and axis 0 of b must line up for the summation
        )
        for w in b.T  # iterating over axis 1 of b (i.e. the columns)
    ]
    for v in a  # iterating over axis 0 of a (i.e. the rows)
]