Use of as_strided function
numpy.lib.stride_tricks.as_strided
is a function in the numpy package used to form submatrices.
It can generate submatrices from the original matrix, and the submatrices can be crossed.
It is mainly used to perform convolution operations on matrices, such as using a 2 * 2 matrix to convolve a 4 * 4 matrix. If stride is 1, then the convolution result is a 3 * 3 matrix, and this function can be used to generate A 3 * 3 * 2 * 2 tensor, that is, a 2 * 2 sub-region of the 3 * 3 input matrices that needs to be convolved.
Function API
numpy.lib.stride_tricks.as_strided(x, shape=None, strides=None, subok=False, writeable=True)
Generate a view of the original matrix through the given
shape
sumstrides
Parameters:
x
:ndarray
:- The matrix used to generate the new tensor
shape
: Aint
sequence (note: such as tuple, array), optional- The shape of the new tensor that needs to be generated, the default is
x.shape
- The shape of the new tensor that needs to be generated, the default is
strides
: aint
sequence (note: such as tuple, array), optional- The span of the new tensor to be generated, defaults to
x.strides
- The span of the new tensor to be generated, defaults to
subok
:bool
, optional- v 1.10 New
- If
True
so, save the generated new tensor (the default is just a view of the original matrix)
writeable
:bool
, optional- v 1.12 new
- If set to
False
then the returned tensor will be read-only, otherwise if the original matrix is writable, the resulting tensor will also be writable. Recommended to beFalse
Return:
view
:ndarry
Parameter analysis
shape
shape
That is the final generated tensor shape
.
For example, for the convolution operation, the output shape we want to get can be obtained by the calculation formula:
Assume: the input image is a matrix of W * H, the convolution kernel is a matrix of w * h, the stride is s, and padding is not considered ( Because padding has nothing to do with the generating submatrix and should be filled in advance), then the output w and h are respectively
wo = W − ws + 1 , ho = H − hs + 1 w_o = \frac{W - w}s + 1 ,\quad h_o = \frac{H - h}s + 1wo=sW−w+1,ho=sH−h+1
Then the shape should be( (W-w)/s+1,(H-h)/s+1)
, and each element is obtained by convolving the w * h sub-matrix in the input matrix and the convolution kernel. We want to stack all the sub-matrices that need to be convolved together and use parallel To speed up the operation, so we want to get a( (W-w)/s+1,(H-h)/s+1,w,h )
tensor, where the last two dimensions are the corresponding convolution areas in the input matrix.
If A
it is an input matrix and K
a convolution kernel, then this shape can be obtained in the following way
shape = tuple(np.subtrct(A.shape,K.shape) / s + 1 ) + K.shape
It is strongly recommended to perform calculations through existing shapes rather than setting them yourself, otherwise problems may easily occur.
strides
strides
and must shape
be of the same type. For example, if the above result shape
is 4 elements, then it strides
must also be 4 elements.
Each element in strides is the span of the corresponding dimension, and the unit is bytes.
First of all, add some knowledge. A matrix A
is stored one by one in the memory starting from the last dimension. For example, shape
for a (3,2)
matrix of , in the memory, the storage order is A[0,0]
, A[0,1]
, A[1,0]
, A[1,1]
, A[2,0]
, A[2,1]
. It can be regarded as a base number, and the base of a certain dimension is the number of elements in that dimension.
It can be seen that, while other dimensions remain unchanged, the closer a dimension is to the last dimension, the smaller the memory offset caused by changes in its index is actually.
Instructions below strides
:
In fact, each one ndarray
has an attribute strides
, for example , shape
if it is a matrix , then its is . It is obtained by:(3,2)
dtype
np.int16
A
strides
(4,2)
When other dimension indexes remain unchanged, for 0
the two adjacent indexes of the th dimension, such as A[0,c]
and A[1,c]
, there is a difference of 2 elements in memory between them. Each element is 16 bits or 2 bytes, so the total offset is is 4 bytes, so strides
the first element value is 4.
Similarly, for 1
two adjacent indexes in dimension: A[c,0]
, A[c,1]
, they are adjacent in memory, that is, the offset is only one element of bytes: 2, so the strides
second element value is 2.
In the same way, it is easy to get that for the tensor you want to generate, the 0th dimension is two submatrices adjacent on the row, and the offset is; the A.strides[0]
1st dimension is two submatrices adjacent on the column, and the offset is is A.strides[1]
, and the last two dimensions are the same as A, so the final strides can be obtained in the following way:
strides = A.strides * 2