numpy.lib.stride_tricks.as_strided的使用
as_strided函数的使用
numpy.lib.stride_tricks.as_strided
是numpy包中一个用以形成子矩阵的函数。
它可以从原矩阵中生成子矩阵,而且子矩阵可以交叉。
主要用于对矩阵进行卷积运算,如用2 * 2 矩阵对 4 * 4的矩阵进行卷积,如果stride为1,那么卷积结果为一个3 * 3的矩阵,该函数就可以用来生成一个3 * 3 * 2 * 2 的张量,即需要卷积的3 * 3个输入矩阵的 2 * 2 的子区域。
函数API
numpy.lib.stride_tricks.as_strided(x, shape=None, strides=None, subok=False, writeable=True)
通过给定的
shape
和strides
,生成一个原矩阵的view
Parameters:
x
:ndarray
:- 用以生成新张量的矩阵
shape
:一个int
的序列(注:如元组,数组),可选项- 需要生成的新的张量的shape,默认为
x.shape
- 需要生成的新的张量的shape,默认为
strides
: 一个int
的序列(注:如元组,数组),可选项- 需要生成的新的张量的跨度,默认为
x.strides
- 需要生成的新的张量的跨度,默认为
subok
:bool
,可选项- v 1.10新增
- 如果为
True
则保存生成的新张量(默认只是原矩阵的一种view)
writeable
:bool
,可选- v 1.12新增
- 如果设为
False
那么返回的张量将只读,否则如果原矩阵可写,生成的张量也可写。推荐设为False
Return:
view
:ndarry
参数解析
shape
shape
即为最终生成的张量的shape
。
如对于卷积操作,我们想要得到的输出的shape 可以通过计算公式得到:
假设:输入的图像为W * H 的矩阵,卷积核为w * h 的矩阵,stride为s,不考虑padding(因为padding和生成子矩阵无关,应该在先前提前填充),那么输出的w,h分别为
w
o
=
W
−
w
s
+
1
,
h
o
=
H
−
h
s
+
1
w_o = \frac{W - w}s + 1,\quad h_o = \frac{H - h}s + 1
wo=sW−w+1,ho=sH−h+1
那么shape应为( (W-w)/s+1,(H-h)/s+1)
,而其中每一个元素都是通过 输入矩阵中的 w * h 子矩阵和卷积核卷积得到的,我们想把所有需要进行卷积计算的子矩阵叠在一起,用并行来加速运算,所以我们想得到一个( (W-w)/s+1,(H-h)/s+1,w,h )
的张量,其中最后两维是输入矩阵中相应的卷积区域。
如果A
为输入矩阵,K
为卷积核,那么这个shape可以通过以下方式得到
shape = tuple(np.subtrct(A.shape,K.shape) / s + 1 ) + K.shape
强烈建议通过已有的shape进行计算而不要自己设置,不然很容易出现问题
strides
strides
必须和shape
是同型的,比如上面得出的shape
为4个元素,那么strides
也必须为4个元素。
strides中每个元素是对应维度的跨度,单位是字节。
首先补充一个知识,一个矩阵A
在内存中是从最后一维开始逐个存储的,如一个shape
为(3,2)
的矩阵,在内存中,存储顺序是A[0,0]
,A[0,1]
,A[1,0]
,A[1,1]
,A[2,0]
,A[2,1]
。可以把其看作是一个进制数,某维进制就是该维度的元素个数。
可以看到,在其他维保持不变的情况下,一个维度越靠近最后一维,它索引的变化引起的内存偏移实际上越小。
下面说明strides
:
其实每个ndarray
都有一个属性是strides
,例如一个shape
为(3,2)
,dtype
是np.int16
的一个矩阵A
,那么它的strides
即为(4,2)
。它是通过以下的方式得到:
在其他维索引不变的情况下,对于第0
维两个相邻的索引,如A[0,c]
和A[1,c]
,它们之间在内存上相差了2个元素,每个元素是16bit 即2字节,所以总共偏移量为4字节,所以strides
的第一个元素值为4.
同样,对于第1
维两个相邻索引:A[c,0]
,A[c,1]
,它们在内存上是相邻的,即偏移量仅为一个元素的字节:2,所以strides
的第二个元素值为2.
同理,很容易得到,对于想生成的张量,第0维是两个在行上相邻的子矩阵,偏移为A.strides[0]
;第1维是两个在列上相邻的子矩阵,偏移为A.strides[1]
,而后两维和A是一样的,所以最终的strides可以通过以下方式得到:
strides = A.strides * 2