Почему копирование массивa>> 16 ГБ Numpy задает все его элементы в 0?
В моем дистрибутиве Anaconda Python копирование массива Numpy размером ровно 16 ГБ или больше (независимо от 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.
Ответы
Ответ 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 > -2147483648
.
То, что новый массив фактически инициализирован нулями, странно, потому что не имеет смысла фактически помещать нули перед копированием массива (но это может быть что-то вроде в этом вопросе).
Опять же: это просто угадывание в этот момент, но это будет соответствовать поведению.