卷积:
就是有一个卷积核,还有一个x*x的图片,卷积核大小是y*y的话,对图像做卷积就是将图片中和卷积核大小一样的部分进行运算,也就是相乘求和,有点类似算法中的滑动窗口,只不过这里是二维滑动窗口,比如说
[1,1,1,0,0
0,1,1,1,0
0,0,1,1,1
0,0,1,1,1
0,0,1,1,0
0,1,1,0,0]一个5*5的,卷积核是[[1,0,1],[0,1,1],[1,0,1]],那么如果对A33做卷积,那么就是对应位置相乘然后求和,也就是4,然后卷积后的大小等于(x-y/步长s)+1,所以写代码的时候经常会看到stride步长参数,但是这样也能看出卷积后大小会急速缩小,所以有时候为了让卷积后大小和输入一样,会在周围加上填充0,可以理解为补上n圈的0,代码中参数叫padding,padding=1就是补一圈,这样图片变成7*7,卷积后还是5*5(步长通常为1的情况下)
代码中常看见Conv2d,这就是卷积层,里面参数像filter是通道数,kernel_size就是卷积核大小,strides步长,padding填充,卷积过程也可以看出可以提取并增强特征
池化:
和卷积类似,也会给一个池化核,不过不像卷积核那样有个值,是个空的,运行过程和卷积一样,也是依次移动。池化规则又最大值池化,平均值池化等,所以代码中常常见到Maxpooling2d,里面参数也有pool_size,strides,padding,池化也可以降维提取特征
卷积池化在图片识别中很重要,主要是这三个特性,平移、旋转、尺度不变性,也就是说,不管特征怎么平移,旋转或者放缩,最后都能把特征提取出来。比如mnist识别,数字是站着还是躺着都能识别
相比于都用全连接层,比如MLP;CNN模型有俩特点,局部连接和权重共享,啥意思呢,这里没太懂,个人理解就是每次运算因为卷积核覆盖部分很多都是一样的,所以可以节省很多算力资源,
看个训练mnist的cnn模型代码
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()#两个卷积层self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5) #1为in_channels 10为out_channelsself.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)#池化层self.pooling = torch.nn.MaxPool2d(2) #2为分组大小2*2#全连接层 320 = 20 * 4 * 4self.fc = torch.nn.Linear(320, 10)def forward(self, x):batch_size = x.size(0)x = F.relu(self.pooling(self.conv1(x)))x = F.relu(self.pooling(self.conv2(x)))x = x.view(batch_size, -1) #将数据展开,为输入全连接层做准备x = self.fc(x)return x
conv1就是输入通道为1,输出10通道,这里10通道数代表输出十张特征图,卷积核5*5,然后池化后经过激活函数(也可以先relu后池化,能更好实现非线性特征学习,然后再池化减少尺寸),两层conv后经过个全连接层得出结果,这里320个神经元的由来:第一层卷积把28*28,变成(28-5)/1+1=24,然后池化层变成(24-2)/2+1=12层,然后第二层卷积(12-5)/1+1=8层,然后第二次池化(8-2)/2+1=4层,由于最后输出通道数有20,所以一共就是4*4的有20张,总特征数就是4*4*20=320,注意relu或sigmod这种激活函数层不会改变图片大小