【问题标题】:Why does copying a >= 16 GB Numpy array set all its elements to 0?为什么复制 >= 16 GB Numpy 数组会将其所有元素设置为 0?
【发布时间】:2017-02-05 07:08:35
【问题描述】:

在我的 Anaconda Python 发行版中,复制正好为 16 GB 或更大的 Numpy 数组(不考虑 dtype)会将副本的所有元素设置为 0:

>>> np.arange(2 ** 31 - 1).copy()  # works fine
array([         0,          1,          2, ..., 2147483644, 2147483645,
       2147483646])
>>> np.arange(2 ** 31).copy()  # wait, what?!
array([0, 0, 0, ..., 0, 0, 0])
>>> np.arange(2 ** 32 - 1, dtype=np.float32).copy()
array([  0.00000000e+00,   1.00000000e+00,   2.00000000e+00, ...,
         4.29496730e+09,   4.29496730e+09,   4.29496730e+09], dtype=float32)
>>> np.arange(2 ** 32, dtype=np.float32).copy()
array([ 0.,  0.,  0., ...,  0.,  0.,  0.], dtype=float32)

这里是 np.__config__.show() 用于此分发:

blas_opt_info:
    library_dirs = ['/users/username/.anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/users/username/.anaconda3/include']
    libraries = ['mkl_rt', 'pthread']
lapack_opt_info:
    library_dirs = ['/users/username/.anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/users/username/.anaconda3/include']
    libraries = ['mkl_rt', 'pthread']
mkl_info:
    library_dirs = ['/users/username/.anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/users/username/.anaconda3/include']
    libraries = ['mkl_rt', 'pthread']
openblas_lapack_info:
  NOT AVAILABLE
lapack_mkl_info:
    library_dirs = ['/users/username/.anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/users/username/.anaconda3/include']
    libraries = ['mkl_rt', 'pthread']
blas_mkl_info:
    library_dirs = ['/users/username/.anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/users/username/.anaconda3/include']
    libraries = ['mkl_rt', 'pthread']

为了比较,这里是np.__config__.show(),用于我的系统Python发行版,没有这个问题:

blas_opt_info:
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
    language = c
    library_dirs = ['/usr/local/lib']
openblas_lapack_info:
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
    language = c
    library_dirs = ['/usr/local/lib']
openblas_info:
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
    language = c
    library_dirs = ['/usr/local/lib']
lapack_opt_info:
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
    language = c
    library_dirs = ['/usr/local/lib']
blas_mkl_info:
  NOT AVAILABLE

我想知道 MKL 加速是否是问题所在。我已经在 Python 2 和 3 上重现了这个错误。

【问题讨论】:

  • 第一个问题:为什么? :-) ...您能否提供更多详细信息:您的阵列在复制之前/之后的dtype 是什么? np.arange(2 ** 31) 工作正常吗? np.arange(1, 2**31)np.arange(1, 2**31).copy() 呢?你电脑上np.intp的dtype是什么?
  • @MSeifert 前两个示例的 dtype 为 float64,后两个示例为 float32np.arange(2 ** 31)np.arange(1, 2**31) 都可以正常工作 - 这似乎是复制的问题。 np.arange(1, 2**31).copy() 也可以,可能是因为它低于 16 GB。 np.intpint64(我正在运行 64 位 Python 和操作系统)。
  • 零输出听起来像是开发人员在出现问题时回退到的东西。它也可以在 C 中解释为 null。我认为您应该提交错误报告。
  • MKL 不应该与它有任何关系。这仅用于线性代数例程,而不是ndarray.copy()。哪些版本的 numpy 有效,哪些 numpy 无效?我隐约记得前段时间出现了这样的错误,但后来它被修复了。
  • @RobertKern:它们都是 1.11.2 - 我应该提交错误报告还是比这更近修复?

标签: python numpy intel-mkl


【解决方案1】:

这只是一个猜测。目前我没有任何证据支持以下说法,但我的猜测是这是一个简单的溢出问题:

>>> np.arange(2 ** 31 - 1).size
2147483647

恰好是最大的int32 值:

>>> np.iinfo(np.int32)
iinfo(min=-2147483648, max=2147483647, dtype=int32)

因此,当您实际上有一个大小为 2147483648 (2**31) 的数组并使用 int32 时,这会溢出并给出实际的负值。那么numpy.ndarray.copy方法里面大概是这样的:

for (i = 0 ; i < size ; i ++) {
    newarray[i] = oldarray[i]
}

但鉴于大小现在为负,循环不会执行,因为0 &gt; -2147483648

新数组实际上是用零初始化的,这很奇怪,因为在复制数组之前实际放零是没有意义的(但它可能类似于in this question)。

再次:这只是猜测,但它会匹配行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多