Как Numpy перемещает данные при транспонировании матрицы?

1

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

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

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

  • 0
    Данные копируются из исходного массива в соответствии с его шагами в назначенную цель в соответствии с ее шагами.
  • 0
    @hpaulj спасибо за комментарий, не могли бы вы сказать мне код об этом? Я хочу знать о его алгоритме транспонирования.
Теги:
numpy

2 ответа

0

Трассировка через 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

Ответ на ваш вопрос: 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, чтобы определить, какой индекс является наиболее быстро меняющимся в памяти, и использует его для внутреннего цикла.

  • 0
    Я знаю np.transpose вызов не будет перемещать данные, но reshape или copy после будет перемещать данные на самом деле. так, где код перемещает данные, когда я вызываю reshape ?
  • 0
    @HaoZhang в alloc.c , в строке 221 result = malloc(size); ( github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/… ). Слово «перемещение» здесь немного странно, я предполагаю, что Numpy выделит новый массив данных в np.copy с помощью PyDataMem_NEW а затем заполнит его скопированными значениями массива, прежде чем устанавливать / копировать метаданные формы перестановки / массива.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню