当前位置: 首页 > 面试题库 >

为什么numpy.zeros和numpy.zeros_like之间的性能差异?

毛镜
2023-03-14
问题内容

我终于在代码中发现了性能瓶颈,但是对于原因是很困惑的。为了解决这个问题,我将所有对的调用都numpy.zeros_like改为使用numpy.zeros。但是为什么zeros_like太慢了?

例如(注意e-05zeros电话):

>>> timeit.timeit('np.zeros((12488, 7588, 3), np.uint8)', 'import numpy as np', number = 10)
5.2928924560546875e-05
>>> timeit.timeit('np.zeros_like(x)', 'import numpy as np; x = np.zeros((12488, 7588, 3), np.uint8)', number = 10)
1.4402990341186523

但是奇怪的是,写入使用创建的数组zeros要慢于使用创建的数组zeros_like

>>> timeit.timeit('x[100:-100, 100:-100] = 1', 'import numpy as np; x = np.zeros((12488, 7588, 3), np.uint8)', number = 10)
0.4310588836669922
>>> timeit.timeit('x[100:-100, 100:-100] = 1', 'import numpy as np; x = np.zeros_like(np.zeros((12488, 7588, 3), np.uint8))', number = 10)
0.33325695991516113

我的猜测是zeros使用一些CPU技巧,而不是实际写入内存来分配它。写入时可以即时完成。但这仍不能解释数组创建时间的巨大差异。

我正在使用当前的numpy版本运行Mac OS X Yosemite:

>>> numpy.__version__
'1.9.1'

问题答案:

我在Ipython中的计时是(使用更简单的timeit接口):

In [57]: timeit np.zeros_like(x)
1 loops, best of 3: 420 ms per loop

In [58]: timeit np.zeros((12488, 7588, 3), np.uint8)
100000 loops, best of 3: 15.1 µs per loop

当我使用IPython(np.zeros_like??)查看代码时,我看到:

res = empty_like(a, dtype=dtype, order=order, subok=subok)
multiarray.copyto(res, 0, casting='unsafe')

np.zeros黑匣子-纯编译代码。

的时间empty是:

In [63]: timeit np.empty_like(x)
100000 loops, best of 3: 13.6 µs per loop

In [64]: timeit np.empty((12488, 7588, 3), np.uint8)
100000 loops, best of 3: 14.9 µs per loop

因此,额外的时间zeros_like就在其中copy

在我的测试中,分配时间(x[]=1)的差异可以忽略不计。

我的猜测是zerosonesempty都是早期编译作品。 empty_like为方便起见添加了此功能,只是从输入中绘制形状和类型信息。
zeros_like撰写本书时,empty_like比起速度,更多的是着眼于轻松进行编程维护(重用)。

np.onesnp.full使用该np.empty ... copyto序列,并显示相似的时间。

https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/array_assign_scalar.c
似乎是将标量(例如0)复制到数组的文件。我看不到使用memset

https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/alloc.c调用了malloccalloc

https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/ctors.c-zeros和的来源empty。两者都通话PyArray_NewFromDescr_int,但是一个最终使用npy_alloc_cache_zero另一个npy_alloc_cache

npy_alloc_cachealloc.c通话中alloc
npy_alloc_cache_zero呼叫npy_alloc_cache后跟一个memset。输入的代码alloc.c进一步与THREAD选项混淆。

关于callocvmalloc+memset差异的更多信息: 为什么malloc +
memset比calloc慢?

但是对于缓存和垃圾回收,我想知道这种calloc/memset区别是否适用。

这与简单的测试memory_profile包支持声称zerosempty分配“上即时”内存,而zeros_like分配一切前面:

N = (1000, 1000) 
M = (slice(None, 500, None), slice(500, None, None))

Line #    Mem usage    Increment   Line Contents
================================================
     2   17.699 MiB    0.000 MiB   @profile
     3                             def test1(N, M):
     4   17.699 MiB    0.000 MiB       print(N, M)
     5   17.699 MiB    0.000 MiB       x = np.zeros(N)   # no memory jump
     6   17.699 MiB    0.000 MiB       y = np.empty(N)
     7   25.230 MiB    7.531 MiB       z = np.zeros_like(x) # initial jump
     8   29.098 MiB    3.867 MiB       x[M] = 1     # jump on usage
     9   32.965 MiB    3.867 MiB       y[M] = 1
    10   32.965 MiB    0.000 MiB       z[M] = 1
    11   32.965 MiB    0.000 MiB       return x,y,z


 类似资料:
  • 问题内容: 我正在计算稀疏自动编码器的算法。我已经使用和在python中实现了它。代码几乎相同,但是性能却大不相同。matlab完成任务所需的时间为0.252454秒,而numpy为0.973672151566,几乎是原来的四倍。在最小化问题中,我将在以后多次调用此代码,因此这种差异会导致实现之间的延迟几分钟。这是正常行为吗?如何提高numpy的性能? numpy实现: Sparse.rho是调整

  • 是的,这是一个老话题,但我还是有些困惑。 在爪哇,人们说: LinkedList的插入速度比ArrayList快。这里插入是什么意思?如果这意味着向后移动一些元素,然后将元素放在中间的空点,那么ArrayList应该比LinkedList慢。如果插入只意味着添加(对象)操作,这怎么会慢呢?

  • 问题内容: 我想知道为什么numpy.zeros占用这么小的空间? 这不会占用任何内存, 占用约1.5GB。numpy.zeros是否创建一个空指针数组?如果是这样,是否可以在cython中更改指针后将其设置为空?如果我使用: 内存使用率上升。有没有办法更改一个值,然后将其更改回numpy.zeros的格式,最初是在python或cython中使用的? 问题答案: 您在使用Linux吗?Linux

  • 是的,这是一个老话题,但我仍然有一些困惑。 在Java,人们说: > 如果我随机访问它的元素,ArrayList比LinkedList快。我认为随机存取意味着“给我第n个元素”。为什么ArrayList更快? LinkedList的删除速度比ArrayList快。我理解这一点。ArrayList速度较慢,因为需要重新分配内部备份阵列。代码说明: LinkedList的插入速度比ArrayList快

  • 我想知道使用子句和之间的性能差异。我从他们两个那里得到了不同的时间。假设我有10个组,我想让一个用户可以访问5个组,同时排除5个组。因此,我有两种使用查询的方式: 我可以在布尔查询中使用子句,并执行。我可以再次在布尔查询中使用子句,并执行。 我在这里没有提供很多细节,因为我只是想更多地了解使用这两个术语的性能差异。我在ES文档中读到了Boolean查询,它说在子句中忽略评分,尽管我还不明白在Luc

  • 使用AtomicLong.IncrementAndGet方法测试JDK7和JDK8的性能差异,测试数据表明JDK7的性能优于JDK8。为什么JDK7的性能比JDK8好?是什么导致JDK8中的性能差? 系统环境: CPU:Intel(R)至强(R)CPU E5620@2.40 GHz 2.40 GHz(双处理器) 内存:8.00 GB set jvm_opt=-xms1024m-xmx1024m-x