numpy.einsum中的out参数不能按预期工作 [英] The `out` arguments in `numpy.einsum` can not work as expected

查看:91
本文介绍了numpy.einsum中的out参数不能按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个邮政编码.第一个是:

I have two piece codes. The first one is:

A = np.arange(3*4*3).reshape(3, 4, 3)
P = np.arange(1, 4)
A[:, 1:, :] = np.einsum('j, ijk->ijk', P, A[:, 1:, :])

,结果A为:

array([[[  0,   1,   2],
        [  6,   8,  10],
        [ 18,  21,  24],
        [ 36,  40,  44]],

       [[ 12,  13,  14],
        [ 30,  32,  34],
        [ 54,  57,  60],
        [ 84,  88,  92]],

       [[ 24,  25,  26],
        [ 54,  56,  58],
        [ 90,  93,  96],
        [132, 136, 140]]])

第二个是:

A = np.arange(3*4*3).reshape(3, 4, 3)
P = np.arange(1, 4)
np.einsum('j, ijk->ijk', P, A[:, 1:, :], out=A[:,1:,:])

,结果A为:

array([[[ 0,  1,  2],
        [ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0]],

       [[12, 13, 14],
        [ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0]],

       [[24, 25, 26],
        [ 0,  0,  0],
        [ 0,  0,  0],
        [ 0,  0,  0]]])

所以结果是不同的.在这里,我想使用out来节省内存.是numpy.einsum中的错误吗?还是我错过了什么?

So the result is different. Here I want to use out to save memory. Is it a bug in numpy.einsum? Or I missed something?

顺便说一句,我的numpy版本是1.13.3.

By the way, my numpy version is 1.13.3.

推荐答案

我以前没有使用过这个新的out参数,但是过去曾使用过einsum,并对它的工作方式有一个大致的了解(或至少以前是这样).

I haven't used this new out parameter before, but have worked with einsum in the past, and have a general idea of how it works (or at least used to).

在我看来,它在迭代开始之前将out数组初始化为零.这将解释A[:,1:,:]块中的所有0.相反,如果我最初是单独的out数组,则会插入所需的值

It looks to me like it initializes the out array to zero before the start of iteration. That would account for all the 0s in the A[:,1:,:] block. If instead I initial separate out array, the desired values are inserted

In [471]: B = np.ones((3,4,3),int)
In [472]: np.einsum('j, ijk->ijk', P, A[:, 1:, :], out=B[:,1:,:])
Out[472]: 
array([[[  3,   4,   5],
        [ 12,  14,  16],
        [ 27,  30,  33]],

       [[ 15,  16,  17],
        [ 36,  38,  40],
        [ 63,  66,  69]],

       [[ 27,  28,  29],
        [ 60,  62,  64],
        [ 99, 102, 105]]])
In [473]: B
Out[473]: 
array([[[  1,   1,   1],
        [  3,   4,   5],
        [ 12,  14,  16],
        [ 27,  30,  33]],

       [[  1,   1,   1],
        [ 15,  16,  17],
        [ 36,  38,  40],
        [ 63,  66,  69]],

       [[  1,   1,   1],
        [ 27,  28,  29],
        [ 60,  62,  64],
        [ 99, 102, 105]]])

einsum的Python部分并没有告诉我太多,除了它决定如何将out数组传递给c部分(作为tmp_operands的列表之一):

The Python portion of einsum doesn't tell me much, except how it decides to pass the out array to the c portion, (as one of the list of tmp_operands):

c_einsum(einsum_str,* tmp_operands,** einsum_kwargs)

c_einsum(einsum_str, *tmp_operands, **einsum_kwargs)

我知道它使用str定义了轴和迭代,设置了np.nditerc-api等效项.

I know that it sets up a c-api equivalent of np.nditer, using the str to define the axes and iterations.

它会在迭代教程中对此部分进行迭代:

It iterates something like this section in the iteration tutorial:

https://docs .scipy.org/doc/numpy-1.13.0/reference/arrays.nditer.html#reduction-iteration

尤其要注意it.reset()步骤.在迭代之前将out缓冲区设置为0.然后,它遍历输入数组和输出数组的元素,将计算值写入输出元素.由于它要进行一定数量的乘积运算(例如out[:] += ...),因此必须从干净的表盘开始.

Notice in particular the it.reset() step. That sets the out buffer to 0 prior to iterating. It then iterates over the elements of input arrays and the output array, writing the calculation values to the output element. Since it is doing a sum of products (e.g. out[:] += ...), it has to start with a clean slate.

我在猜测实际发生的情况,但是对我来说应该将输出缓冲区归零,这似乎是合乎逻辑的.如果该数组与输入之一相同,则最终将使计算混乱.

I'm guessing a bit as to what is actually going on, but it seems logical to me that it should zero out the output buffer to start with. If that array is the same as one of the inputs, that will end up messing with the calculation.

因此,我认为这种方法不会起作用并节省您的内存.它需要一个干净的缓冲区来累积结果.完成后,您也可以将值写回到A中.但是考虑到dot之类产品的性质,您不能将相同的数组用于输入和输出.

So I don't think this approach will work and save you memory. It needs a clean buffer to accumulate the results in. Once that's done it, or you, can write the values back into A. But given the nature of a dot like product, you can't use the same array for input and for output.

In [476]: A[:,1:,:] = np.einsum('j, ijk->ijk', P, A[:, 1:, :])
In [477]: A
Out[477]: 
array([[[  0,   1,   2],
        [  3,   4,   5],
        [ 12,  14,  16],
        [ 27,  30,  33]],
        ....)

这篇关于numpy.einsum中的out参数不能按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆