内容:
- 池化层
- 池化层和卷积层的实现
池化层
(1).池化是缩小高、长方向上的空间的运算.池化方法:
- Max池化是从目标区域中取出最大值;
![](https://img-blog.csdnimg.cn/20190509104014508.gif)
- Average池化则是计算目标区域的平均值,只需要将上面的max–>>mean
(2)池化后的形状:
设输入图像尺寸为WxH,其中W:图像宽,H:图像高,D:通道数(图像深度),滤波器大小(FxF),S:步长,池化后输出图像大小:(若结果不是整数,可以参考上一节卷积的处理方式)
(3).池化层的特征:
- 没有要学习的参数:
池化层和卷积层不同,没有要学习的参数。池化只是从目标区域中取得最大值(或者平均值),所以不存在要学习的参数。
- 通道数不发生变化
经过池化运算,输入数据和输出数据的通道数不会发生变化。
- 对微小位置的变化具有鲁棒性(健壮)
输入数据发生微小偏差时,池化仍会返回相同的结果。因此,池化对输入数据的微小偏差具有鲁棒性。
池化层和卷积层的实现
基于im2col的展开
(1):im2col函数,将输入数据展开(将应用滤波器的区域横向展开为1列)以适合滤波器(权重)。(2):然后将卷积层的滤波器(权重)纵向展开为1列。(3):计算两个矩阵的乘积即可。
![](https://i-blog.csdnimg.cn/blog_migrate/6f203dc7842837b18ad43679866c90a7.png)
注:
- 在滤波器的应用区域重叠的情况下,使用im2col展开后,展开后的元素个数会多于原方块的元素个数。
- im2col的实现存在比普通的实现消耗更多内存的特点。
im2col函数
import numpy as np
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
"""
Parameters
----------
input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据,如np.random.rand(10,1,28,28)
filter_h : 滤波器的高
filter_w : 滤波器的长
stride : 步幅
pad : 填充
Returns
-------
col : 2维数组
"""
N, C, H, W = input_data.shape # batch_num:批数量
out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')#填充阵列
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))
for y in range(filter_h):
y_max = y + stride*out_h
for x in range(filter_w):
x_max = x + stride*out_w
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
return col
## 案例
x1=np.random.rand(1,3,7,7)
col1=im2col(x1,5,5,stride=1,pad=0)
print(col1.shape)#(9, 75)
x2=np.random.rand(10,3,7,7)
col2=im2col(x2,5,5,stride=1,pad=0)
print(col2.shape)#(90, 75)
源码学习:
np.pad#填充阵列
参数解释:
第一个参数array是待填充数组
第二个参数pad_with是:
Number of values padded to the edges of each axis(填充到每个轴的边的值数)。
((before_1, after_1), ... (before_N, after_N)) unique pad widthsfor each axis.
before = after = pad width for all axes。
填充的形状,
(1)1d--->>>(2,3)表示前面两个,后面三个,填充的元素取决于填充的方法
(2)维的见下图
第三个参数是填充的方法
填充方法:
constant---->>>连续一样的值填充,有关于其填充值的参数。
constant_values=(x, y)时前面用x填充,后面用y填充。缺参数是为0000。。。
edge--->>>用边缘值填充
linear_ramp--->>>边缘递减的填充方式
maximum, mean, median, minimum分别用最大值、均值、中位数和最小值填充
reflect, symmetric都是对称填充。前一个是关于边缘对称,后一个是关于边缘外的空气对称
wrap--->>>用原数组后面的值填充前面,前面的值填充后面
也可以有其他自定义的填充方法
以多维(常数填充)填充为例,第二个参数(元组的个数)的形状与array的形状一致;
图中通过不同的颜色标记了各个参数对应的操作。
![](https://i-blog.csdnimg.cn/blog_migrate/e514c5086923883e953db26fcccfa9bf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/96af54b1d50ecbd4898d4a3f89b3fca5.png)
- #reshape(FN,-1)表示reshape会自动计算-1维度上的元素个数,以使多维数据的元素个数前后一致。
- #transpose更改多维数据轴的顺序,其中的数值为索引。
![](https://i-blog.csdnimg.cn/blog_migrate/b75aab4cb2ec4e4350f44e071b0ccecf.png)
im2col函数的逆:col2im
def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):
"""
Parameters
----------
col :
input_shape : 输入数据的形状(例:(10, 1, 28, 28))
filter_h :
filter_w
stride
pad
Returns
-------
"""
N, C, H, W = input_shape
out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1
col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)
img = np.zeros((N, C, H + 2*pad + stride - 1, W + 2*pad + stride - 1))
for y in range(filter_h):
y_max = y + stride*out_h
for x in range(filter_w):
x_max = x + stride*out_w
img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]
return img[:, :, pad:H + pad, pad:W + pad]
卷积层
卷积层的类:
class Convolution:
def __init__(self,W,b,stride=1,pad=0):
self.W=W
self.b=b
self.stride=stride
self.pad=pad
def forward(self,x):
FN,C,FH,FW=self.W.shape #FN 表示滤波器的数量
N,C,H,W=x.shape
out_h=int(1+(H+2*self.pad-FH)/self.stride)
out_w=int(1+(W+2*self.pad-FW)/self.stride)
col=im2col(x,FH,FW,self.stride,self.pad)
col_W=self.W.reshape(FN,-1).T#滤波器的展开
out=np.dot(col,col_W)+self.b
out=out.reshape(N,out_h,out_w,-1).transpose(0,3,1,2)
return out
池化层的实现:
池化层的实现和卷积层相同,都使用im2col展开输入数据。
池化情况下,在通道方向上是独立的,这一点与卷积层不同。
class Pooling:
def __init__(self,pool_h,pool_w,stride=1,pad=0):
self.pool_h=pool_h
self.pool_w=self_w
self.stride=stride
self.pad=pad
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)
#展开(1):展开输入数据
col=im2col(x,seel.pool_h,self.pool_w,self.stride,self.pad)
col=col.reshape(-1,self.pool_h*self.pool_w)
#最大值(2):求各行的最大值
out=np.max(col,axis=1)
#转换(3):转换为合适的输出大小
out=out.reshape(N,out_h,out_w,C).transpose(0,3,1,2)
return out
![](https://i-blog.csdnimg.cn/blog_migrate/72524cf6a4842cad96ae1b3317c780ce.png)
关于卷积和池化的反向传播后补