remodelando una vista de una matriz n-dimensional sin usar remodelar

tl; dr ¿Puedo cambiar la forma de una vista de una matriz numpy de 5x5x5x3x3x3 a 125x1x1x3x3x3 sin usar numpy.reshape?

Me gustaría realizar una operación de ventana deslizante (con diferentes zancadas) a un volumen (tamaño de MxMxM). La matriz de ventanas deslizantes se puede generar con el uso de numpy.lib.stride_tricks.as_strided , como lo sugirieron anteriormente Benjamin y Eickenberg , y se muestra en el siguiente fragmento de código, que usa un método auxiliar de skimage que usa as_strided .

La salida de este método auxiliar me da una forma de NxNxNxnxnxn, pero preferiría que la forma sea N ^ 3x1xnxnxn. Si bien puedo usar np.reshape para lograr esto, np.reshape es lento si el volumen aumenta (> 100x100x100), por lo que no estoy seguro de por qué. Pensé que puedo usar as_stride para cambiar la forma de la salida, pero hay muchos errores (fragmento de código a continuación). ¿Alguna idea sobre cómo puedo obtener una vista de la salida del método auxiliar como N ** 3x1xnxnxn sin usar np.reshape?

 import numpy as np import skimage l = 15 s = 3 X = np.ones((l,l,l)) print('actual shape',X.shape) view = skimage.util.shape.view_as_blocks(X,(s,s,s)) print('original view',view.shape) new_shape = ((l/s)**3,1,1,s,s,s) print('new view',new_shape) view_correct = view.reshape(new_shape) print(view_correct.shape) print('coord:','124,0,0,2,2,2','value:',view_correct[124,0,0,2,2,2]) view_incorrect = np.lib.stride_tricks.as_strided(view, shape=new_shape) print(view_incorrect.shape) print('coord:','124,0,0,2,2,2','value:',view_incorrect[124,0,0,2,2,2]) 

Tomé un ejemplo de view_as_blocks y probé su estilo de remodelación:

 A = np.arange(4*4).reshape(4,4) B = view_as_blocks(A, block_shape=(2, 2)) print(A.__array_interface__) print(B.__array_interface__) C = B.reshape((2*2,2,2)) print(C.__array_interface__) 

productor:

 {'typestr': ' 

El indicador de data para A y B es el mismo; B es una vista de A

Pero el puntero para C es diferente. Es una copia. Eso explica por qué toma tanto tiempo en tu caso.


Vamos a hacer eso un poco diferente:

 A = np.arange(4*4).reshape(4,4) B = view_as_blocks(A, block_shape=(2, 2)) print(A.__array_interface__) print(B.__array_interface__) C = B.reshape((2*2,1,2,2)) print(C.__array_interface__) D = as_strided(B, shape=(2*2,1,2,2)) print(D.__array_interface__) print(B[1,1,:,:]) print(C[3,0,:,:]) print(D[3,0,:,:]) 

productor

 1254:~/mypy$ python3 skshape.py {'strides': None, 'typestr': ' 

Nuevamente la remodelación crea una copia. El 2nd as_strides devuelve una vista, pero la zancada está arruinada. Es mirar la memoria fuera del búfer de datos original (eso es parte de por qué jugar con tus propios pasos es peligroso).


En mi ejemplo, mira el valor de la primera esquina de cada bloque

 print(B[:,:,0,0]) print(C[:,0,0,0]) [[ 0 2] [ 8 10]] [ 0 2 8 10] 

Para B , las filas aumentan en 8, las columnas en 2; eso se refleja en la zancada (32,8) (4 * 8,4 * 2).

Pero en C los pasos son (2,6,2), el paso no puede hacer eso.

De esto concluyo que la remodelación es imposible sin copia.