Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.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 当其中一个是np.array(dtype=np.complex128.real)时,numpy matmul非常慢_Python_Numpy - Fatal编程技术网

Python 当其中一个是np.array(dtype=np.complex128.real)时,numpy matmul非常慢

Python 当其中一个是np.array(dtype=np.complex128.real)时,numpy matmul非常慢,python,numpy,Python,Numpy,我发现,当matmuling两个numpy数组时,如果其中一个是更大的复数数组的实部或虚部,则操作可能比使用原始复数数组慢数十甚至数百倍 考虑以下示例: import numpy as np from time import time class timeit(): def __init__(self, string): self.string = string def __enter__(self): self.t0 = time()

我发现,当
matmul
ing两个
numpy
数组时,如果其中一个是更大的复数数组的实部或虚部,则操作可能比使用原始复数数组慢数十甚至数百倍

考虑以下示例:

import numpy as np
from time import time

class timeit():
    def __init__(self, string):
        self.string = string

    def __enter__(self):
        self.t0 = time()

    def __exit__(self, *args):
        print(f'{self.string} : {time() - self.t0}')


A  = np.random.rand(200, 1000) + 0j
B = np.random.rand(1000, 5000)

with timeit('with complex'):
    out = A @ B

Ar = A.real
with timeit('after .real'):
    out = Ar @ B

Ai = (A * 1j).imag
with timeit('after .imag'):
    out = Ai @ B

with timeit('after .astype(float)'):
    out = A.astype(np.float64()) @ B

with timeit('after .real.astype(float)'):
    out = A.real.astype(np.float64()) @ B
输出是

with complex : 0.09374785423278809
after .real : 1.9792003631591797
after .imag : 1.717487096786499
after .astype(float) : 0.016920804977416992
after .real.astype(float) : 0.017952442169189453
请注意,当两个数组中的一个为
A.real
A.imag
时,操作速度会慢20倍(如果数组较大,则速度会慢数百倍)

使用
A.astype(np.float64)
速度非常快,但每次都会抛出警告,即使虚部为空

唯一快速而安静的解决方案似乎是
A.real.astype(float)
,但是,老实说,它在我看来相当难看

通过检查这些数组的内存地址,我得到以下结果

def aid(x):
    # This function returns the memory
    # block address of an array.
    return x.__array_interface__['data'][0]

print(f'ID(A.real) == ID(A): {aid(A.real) == aid(A)}')
print(f'ID(A.imag) == ID(A): {aid(A.imag) == aid(A)}')
print(f'ID(A.astype) == ID(A): {aid(A.astype(np.float64())) == aid(A)}')
print(f'ID(A.real.astype) == ID(A): {aid(A.real.astype(np.float64())) == aid(A)}')

这是回报

ID(A.real) == ID(A): True
ID(A.imag) == ID(A): False
ID(A.astype) == ID(A): False
ID(A.real.astype) == ID(A): False
这似乎表明
A.real
A
具有相同的内存地址,而
A.astype(np.float64)
没有。这会导致这种行为吗?但是
A
A.imag
有不同的内存地址,但是
matmul
仍然非常慢

这是虫子吗?
我应该使用
A.real.astype(np.float64)
的解决方案吗?

重要的不是内存位置或布局。这是
@
根据输入类型选择的路径
A.real
不是一个“新”数组;它是一种访问复杂数据类型实际值的方法。我没有时间展示我的全部计时结果,但这里有几个快速的结果

In [2]: timeit A@B
436 ms ± 32.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
添加
real
会以这种方式降低速度:

In [3]: timeit A.real@B
3.93 s ± 4.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [4]: %%timeit a = A.real
   ...: a@B
3.92 s ± 3.29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
但制作一个新的浮点数组会加快速度:

In [5]: %%timeit a = A.real.copy()
   ...: a@B 
101 ms ± 496 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
A.real
不进行任何实际计算:

In [6]: timeit A.real    
203 ns ± 9.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
从实际值生成新数组并不是那么慢:

In [7]: timeit A.real.copy()
239 µs ± 3.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
包含内联复制不会影响时间:

In [8]: timeit A.real.copy()@B
102 ms ± 1.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
不受
实数的困扰

In [9]: timeit A.real.dot(B)
106 ms ± 3.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
A.dot(B)
A@B

因此,复杂的计算大约比浮动慢4倍。考虑到
A
的平均值是平均值的两倍,这听起来很合理

dot
正确处理
实数
,无需太多麻烦即可提取实数


@
有某种缺陷,使其运行缓慢。

重要的不是内存位置或布局。这是
@
根据输入类型选择的路径
A.real
不是一个“新”数组;它是一种访问复杂数据类型实际值的方法。我没有时间展示我的全部计时结果,但这里有几个快速的结果

In [2]: timeit A@B
436 ms ± 32.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
添加
real
会以这种方式降低速度:

In [3]: timeit A.real@B
3.93 s ± 4.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [4]: %%timeit a = A.real
   ...: a@B
3.92 s ± 3.29 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
但制作一个新的浮点数组会加快速度:

In [5]: %%timeit a = A.real.copy()
   ...: a@B 
101 ms ± 496 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
A.real
不进行任何实际计算:

In [6]: timeit A.real    
203 ns ± 9.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
从实际值生成新数组并不是那么慢:

In [7]: timeit A.real.copy()
239 µs ± 3.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
包含内联复制不会影响时间:

In [8]: timeit A.real.copy()@B
102 ms ± 1.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
不受
实数的困扰

In [9]: timeit A.real.dot(B)
106 ms ± 3.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
A.dot(B)
A@B

因此,复杂的计算大约比浮动慢4倍。考虑到
A
的平均值是平均值的两倍,这听起来很合理

dot
正确处理
实数
,无需太多麻烦即可提取实数


@
有某种缺陷,发送速度很慢。

或者pickle错误地丢弃了您的大部分数据。无法在我的系统上重现。两者都给了我大约0.2秒的期望值。@mCoding检查编辑。另外
numpy.array.copy()
解决了这个问题。在我看来,这与pickle无关。如果不知道原始数组是如何创建的,我想我们帮不了忙。我想不出一个数组存储或属性会让事情变慢,而且不会通过
pickle
copy
@hpaulj,这基本上是我的问题。哪个属性可能导致此问题,而未通过
pickle
copy
?或我应该在原始数组中检查哪个属性,以允许我复制错误?我将尝试生成一个最小的工作示例,但问题似乎很难重现(即使它在我的代码中系统地发生),或者pickle错误地丢弃了大部分数据。无法在我的系统上重现。两者都给了我大约0.2秒的期望值。@mCoding检查编辑。另外
numpy.array.copy()
解决了这个问题。在我看来,这与pickle无关。如果不知道原始数组是如何创建的,我想我们帮不了忙。我想不出一个数组存储或属性会让事情变慢,而且不会通过
pickle
copy
@hpaulj,这基本上是我的问题。哪个属性可能导致此问题,而未通过
pickle
copy
?或我应该在原始数组中检查哪个属性,以允许我复制错误?我将尝试生成一个最小的工作示例,但是这个问题似乎很难重现(即使它在我的代码中系统地发生),所以您认为这是由于
@
的实现中的错误造成的?在问题的前一个版本中,我注意到
.copy()
解决了这个问题。我的问题是…为什么?
matmul
显然会根据输入的性质选择不同的评估路线。对于浮点数组的直接评估,它将任务直接传递给高度优化的BLAS类型例程。但它是编译的代码,所以更难探索。可能会有一些关于github Repository的讨论。因此,您认为这是由于
@
的实现中的错误造成的?在问题的前一个版本中,我注意到
.copy()
解决了这个问题。