Врезка в NumPy и CuPy фактически не копирует данные куда-либо, а просто возвращает новый массив, в котором данные совпадают, но с указателем, смещенным к первому элементу нового среза и скорректированной форме. Обратите внимание, как исходный массив и срез имеют одинаковые шаги:
In [1]: import cupy as cp
In [2]: a = cp.zeros((432, 432, 400), dtype=cp.float32)
In [3]: b = a[100:120, 100:120, 100:120]
In [4]: a.strides
Out[4]: (691200, 1600, 4)
In [5]: b.strides
Out[5]: (691200, 1600, 4)
То же самое можно проверить, заменив CuPy на NumPy.
. Для реальной операции нарезки наиболее надежным способом сделать это было бы добавление .copy()
к каждой операции, тем самым обеспечивая доступ к памяти / копирование в память:
cp_code = 'arr2 = cp_arr[100:120, 100:120, 100:120].copy()' # 0.771 seconds
np_code = 'arr2 = np_arr[100:120, 100:120, 100:120].copy()' # 0.154 seconds
К сожалению, для приведенного выше шаблона памяти плохо для графических процессоров, так как маленькие куски не смогут насытить каналы памяти, поэтому все равно медленнее, чем NumPy. Однако CuPy может быть намного быстрее, если порции способны приблизиться к насыщению канала памяти, например:
cp_code = 'arr2 = cp_arr[:, 100:120, 100:120].copy()' # 0.786 seconds
np_code = 'arr2 = np_arr[:, 100:120, 100:120].copy()' # 2.911 seconds