卷积层的填充和步幅
卷积时,常常丢失边缘像素。如果想要网络很深的话,按照每一层(shape[0]-h+1),会在某一层消失。
所以需要填充
目的:高效计算、缩减采样次数
每次滑动元素的数量:步幅
import torch
from torch import nn
def comp_conv2d(conv2d,x):
#conv2d是传递进入的函数
x=x.reshape((1,1)+x.shape)
#1通道 1批量大小
y=conv2d(x)
#调用传进来的函数
return y.reshape(y.shape[2:])
#省略前两个维度:通道数、批量大小
conv2d=nn.Conv2d(1,1,kernel_size=3,padding=1)
#定义一个conv2d函数,表示输入维度为1、输出维度为1,卷积核大小为3*3,填充高宽:1*1
x=torch.rand(size=(8,8))
#随机生成8*8矩阵
comp_conv2d(conv2d,x).shape
conv2d=nn.Conv2d(1,1,kernel_size=3,padding=1,stride=2)
#加了一个步幅为2
comp_conv2d(conv2d,x).shape
也可以偶数。奇数是因为好填充。
机器学习本质:极端的压缩算法(一张图片压缩成一个很小很小的值,每个值都是有语义的)
是的,3*3==5个5*5,但是卷积核大的话,会贵,且运算时间要高一点。
卷积层的多输入输出通道
性能:计算性能、模型性能。计算性能,就只是加了一点点。模型性能,加了很多0,没有什么区别
每个通道的卷积核可以不一样,GoogleNet。一般都一样,计算方便,不一样的话,都要每个通道单独做一次卷积操作,一样的话,一起做了
偏移几乎无影响
核的参数是学出来的,不是选出来的。
池化
目的:降低卷积层对位置的敏感性、降低对空间降采样的敏感性
实际图像里,我们感兴趣的物体不会总出现在固定像素位置:即使我们用三脚架固定相机去连续拍摄同一个物体也极有可能出现像素位置上的偏移。这会导致同一个物体的边缘对应的输出可能出现在卷积输出中的不同位置,进而对后面的模式识别造成不便。
即,实际的物体在锁定像素点的左边1格,或者其他邻居位置。池化是目标像素点的四周比如3*3的位置选一个合适的。所以,实际的物体在锁定像素点位置还是邻居位置,也无所谓了。所以说,降低了卷积层的对位置的敏感性
最大池化
平均池化
使用大于1的池化层可以降维。
在每个输入通道上单独运算。跟卷积层不一样。卷积层是在通道上对输入进行汇总。输出通道数与输入通道数一致。
池化层,可以使得特征量减少,尺度减小。
pooling:目的是为了保持某种不变性(旋转不变性,平移不变性,伸缩不变性(尺度))
提取特征的主要误差来自以下两个方面:
邻域大小受限造成的估计值方差增大
卷积层参数误差造成估计均值的偏移
一般来说,
mean-pooling(平均池化),能减小第一种误差,更多的保留图像的背景信息
max-pooling(最大池化),能减小第二种误差,更多的保留纹理信息。
def pool2d(x,pool_size,mode='max'):
#默认最大,可以平均
p_h,p_w=pool_size
#池化层的高和宽
y=torch.zeros((x.shape[0]-p_h+1,x.shape[1]-p_w+1))
#池化后的高和宽
for i in range(y.shape[0]):
for j in range(y.shape[1]):
if mode=='max':#最大池化
y[i,j]=x[i:i+p_h,j:j+p_w].max()
elif mode=='avg':#平均池化
y[i:j]=x[i:i+p_h,j:j+p_w].mean()
return y
或者
pool2d =nn.MaxPool2d(3,padding=1,stride=2)
#调用框架,3*3,填充1*1,步幅为2*2