Как Numpy перемещает данные при транспонировании матрицы? - PullRequest
0 голосов
/ 04 января 2019

Кажется, что numpy.transpose только сохранить шаги, и на самом деле транспонировать лениво в соответствии с this

Итак, когда действительно произошло перемещение данных и как перемещаться? использовать много много memcpy? или какой-то другой трюк?

Я иду по пути: array_reshape, PyArray_Newshape, PyArray_NewCopy, PyArray_NewLikeArray, PyArray_NewFromDescr, PyArray_NewFromDescrAndBase, PyArray_NewFromDescr_int но ничего не вижу в оси перестановки. Когда это действительно произошло?

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Отслеживание кода numpy C - медленный и утомительный процесс. Я предпочитаю выводить модели поведения из времени.

Создать образец массива и его транспонировать:

In [168]: A = np.random.rand(1000,1000)
In [169]: At = A.T

Сначала быстрый просмотр - копирование буфера данных не выполняется:

In [171]: timeit B = A.ravel()
262 ns ± 4.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Быстрое копирование (предположительно использует быстрое копирование памяти блока):

In [172]: timeit B = A.copy()
2.2 ms ± 26.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Медленная копия (предположительно, требует прохождения источника в его пошаговом порядке и цели в своем собственном порядке):

In [173]: timeit B = A.copy(order='F')
6.29 ms ± 2.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Копирование At без необходимости изменения порядка - быстро:

In [174]: timeit B = At.copy(order='F')
2.23 ms ± 51.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Подобно [173], но переход от «F» к «C»:

In [175]: timeit B = At.copy(order='C')
6.29 ms ± 4.16 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [176]: timeit B = At.ravel()
6.54 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Копии с более простым пошаговым переупорядочением находятся где-то посередине:

In [177]: timeit B = A[::-1,::-1].copy()
3.75 ms ± 4.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [178]: timeit B = A[::-1].copy()
3.73 ms ± 6.48 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [179]: timeit B = At[::-1].copy(order='K')
3.98 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Для этого astype также требуется более медленное копирование:

In [182]: timeit B = A.astype('float128')
6.7 ms ± 8.12 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

PyArray_NewFromDescr_int описывается как Generic new array creation routine. Хотя я не могу понять, куда он копирует данные из источника в цель, он явно проверяет order и strides и dtype. Предположительно, он обрабатывает все случаи, когда требуется общая копия. Перестановка осей не является частным случаем.

0 голосов
/ 04 января 2019

Ответ на ваш вопрос: Numpy не перемещает данные.

Вы видели PyArray_Transpose в строке 688 ваших ссылок выше? В этой функции есть перестановка,

    n = permute->len;
    axes = permute->ptr;
    ...
    for (i = 0; i < n; i++) {
        int axis = axes[i];
        ...
        permutation[i] = axis;
}

Любая форма массива - это чисто метаданные, используемые Numpy для понимания того, как обрабатывать данные, поскольку память всегда хранится линейно и непрерывно. Поэтому нет причин перемещать или переупорядочивать какие-либо данные из документов здесь ,

Другие операции, такие как транспонирование, не перемещают элементы данных вокруг в массиве, но вместо этого измените информацию о форме и шагах так, чтобы индексирование массива изменилось, но данные в не изменились. Обычно эти новые версии метаданных массива, но тот же буфер данных новые «представления» в буфере данных. Существует другой объект ndarray, но он использует тот же буфер данных. Вот почему необходимо форсировать копии через использование метода .copy (), если вы действительно хотите создать новый и независимый копия буфера данных.

Единственная причина копирования может заключаться в максимизации эффективности кэша , хотя Numpy уже считает этим,

Как оказалось, numpy достаточно умен, когда имеет дело с ufuncs, чтобы определить, какой индекс является наиболее быстро меняющимся в памяти, и использует его для внутреннего цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...