池化层的实现和卷积层的实现差不多,都是使用im2col来展开输入数据,只不过在池化的应用区域是按照通道单独展开。看图更直观。
图中我们可以看出,对输入数据进行展开之后,再对展开的矩阵求各行的最大值,这个就是做max操作,然后再转换成合适的形状就可以了。所以这个池化层就分三步走:展开输入数据-->求最大值-->转换形状
class Pooling:
def __init__(self,pool_h,pool_w,stride=1,pad=0):
self.pool_h=pool_h
self.pool_w=pool_w
self.stride=stride
self.pad=pad
self.x=None
self.arg_max=None
def forward(self,x):
N,C,H,W=x.shape
out_h=int(1+(H-self.pool_h)/self.stride)
out_w=int(1+(W-self.pool_w)/self.stride)
col=im2col(x,self.pool_h,self.pool_w,self.stride,self.pad)
col=col.reshape(-1,self.pool_h*self.pool_w)
arg_max=np.argmax(col,axis=1)
out=np.max(col,axis=1)
out=out.reshape(N,out_h,out_w,C).transpose(0,3,1,2)
self.x=x
self.arg_max=arg_max
return out
def backward(self,dout):
dout=dout.transpose(0,2,3,1)
pool_size=self.pool_h*self.pool_w
dmax=np.zeros((dout.size,pool_size))
dmax[np.arange(self.arg_max.size),self.arg_max.flatten()]=dout.flatten()
dmax=dmax.reshape(dout.shape+(pool_size,))
dcol=dmax.reshape(dmax.shape[0]*dmax.shape[1]*dmax.shape[2],-1)
dx=col2im(dcol,self.x.shape,self.pool_h,self.pool_w,self.stride,self.pad)
return dx
其中max操作的axis轴的选择需要注意,来个例子就更清晰了
a=np.random.randn(2,3)
array([[ 0.33957879, 0.36144833, 2.26691385],
[-1.00157478, 1.4306799 , 0.66939851]])
np.max(a,axis=0)
array([ 0.33957879, 1.4306799 , 2.26691385])#argmax->[0, 1, 0]
np.max(a,axis=1)
array([ 2.26691385, 1.4306799 ])#argmax->[2, 1]
axis=1就是输入数据a在第1维的各个轴方向上求最大值