一、相关概念
对于(10,3,227,227)数据表示,10张3通道的图,图的大小(特征数)为227*227.
通道数:作为卷积的输入通道数和输出通道数。
特征数:特征图的大小
步长stride和填充padding:线性减小特征图的尺寸
池化pooling:非线性且高效减小特征图的尺寸
计算公式:hout = (hin +2p -k) /s +1
二、LeNet5:现代CNN的奠基者
LeNet的核心思想“卷积+池化+线性”。在PyTorch中实现其架构的代码如下:
import torch
from torch import nn
from torch.nn import functional as F
from torchinfo import summary
data = torch.ones(size=(10,1,32,32))
class Model(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1,6,5) #(H+2p-K)/S + 1
self.pool1 = nn.AvgPool2d(kernel_size=2,stride=2)
self.conv2 = nn.Conv2d(6,16,5)
self.pool2 = nn.AvgPool2d(2)
self.fc1 = nn.Linear(5*5*16,120)
self.fc2 = nn.Linear(120,84)
def forward(self,x):
x = F.tanh(self.conv1(x))
x = self.pool1(x)
x = F.tanh(self.conv2(x))
x = self.pool2(x)
x = x.view(-1,5*5*16) #-1,我不关心-1这个位置上的数是多少,你根据我输入的x的结构帮我自己计算吧
x = F.tanh(self.fc1(x))
output = F.softmax(self.fc2(x),dim=1) #(samples, features)
net = Model() #实例化
net(data) #相当于在执行 net.forward(data)
net = Model() #实例化
summary(net, input_size=(10,1,32,32))
结果显示:
==========================================================================================
Layer (type:depth-idx) Output Shape Param #
==========================================================================================
Model -- --
├─Conv2d: 1-1 [10, 6, 28, 28] 156
├─AvgPool2d: 1-2 [10, 6, 14, 14] --
├─Conv2d: 1-3 [10, 16, 10, 10] 2,416
├─AvgPool2d: 1-4 [10, 16, 5, 5] --
├─Linear: 1-5 [10, 120] 48,120
├─Linear: 1-6 [10, 84] 10,164
==========================================================================================
Total params: 60,856
Trainable params: 60,856
Non-trainable params: 0
Total mult-adds (M): 4.22
==========================================================================================
Input size (MB): 0.04
Forward/backward pass size (MB): 0.52
Params size (MB): 0.24
Estimated Total Size (MB): 0.81
==========================================================================================
三、AlexNet:从浅层到深度
AlexNet的架构若用文字来表现,则可以
打包成4个组合:
输入→(卷积+池化)→(卷积+池化)→(卷积x3+池化)→(线性x3)→输出
相对的,LeNet5的架构可以打包成3个组合:
输入→(卷积+池化)→(卷积+池化)→(线性x2)→输出
和只有6层(包括池化层)的LeNet5比起来,AlexNet主要做出了如下改变:
1、相比之下,卷积核更小、网络更深、通道数更多,这代表人们已经认识到了图像数据天生适合于多次
提取特征,“深度”才是卷积网络的未来。LeNet5是基于MNIST数据集创造,MNIST数据集中的图片尺寸
大约只有30*30的大小,LeNet5采用了5x5的卷积核,图像尺寸/核尺寸大约在6:1。而基于ImageNet
数据集训练的AlexNet最大的卷积核只有11x11,且在第二个卷积层就改用5x5,剩下的层中都使用3x3
的卷积核,图像尺寸/核尺寸至少也超过20:1。小卷积核让网络更深,但也让特征图的尺寸变得很小,
为了让信息尽可能地被捕获,AlexNet也使用了更多的通道。小卷积核、多通道、更深的网络,这些都
成为了卷积神经网络后续发展的指导方向。
2、使用了ReLU激活函数,摆脱Sigmoid与Tanh的各种问题。
3、使用了Dropout层来控制模型复杂度,控制过拟合。
4、引入了大量传统或新兴的图像增强技术来扩大数据集,进一步缓解过拟合。
5、使用GPU对网络进行训练,使得“适当的训练“(proper training)成为可能。
1、AlexNet的架构复现
在PyTorch中来复现AlexNet的架构:
import torch
from torch import nn
from torch.nn import functional as F
data = torch.ones(size=(10,3,227,227)) #224 x 224
class Model(nn.Module):
def __init__(self):
super().__init__()
# 大卷积核、较大的步长、较多的通道
# 为了处理尺寸较大的原始图片,先使用11x11的卷积核和较大的步长来快速降低特征图的尺寸
# 同时,使用比较多的通道数,来弥补降低尺寸造成的数据损失
self.conv1 = nn.Conv2d(3,96, kernel_size=11, stride=4)
self.pool1 = nn.MaxPool2d(kernel_size=3, stride=2) #overlap pooling
#卷积核、步长恢复正常大小,进一步扩大通道
# 已经将特征图尺寸缩小到27x27,计算量可控,可以开始进行特征提取了
# 卷积核、步长恢复到业界常用的大小,进一步扩大通道来提取数据
self.conv2 = nn.Conv2d(96,256,kernel_size=5,padding=2)
self.pool2 = nn.MaxPool2d(kernel_size=3, stride=2)
# 疯狂提取特征,连续用多个卷积层
# kernel 5, padding 2, kernel 3, padding 1 可以维持住特征图的大小
self.conv3 = nn.Conv2d(256,384,kernel_size=3, padding =1)
self.conv4 = nn.Conv2d(384,384,kernel_size=3, padding =1)
self.conv5 = nn.Conv2d(384,256,kernel_size=3, padding =1)
self.pool3 = nn.MaxPool2d(kernel_size=3, stride=2)
# 进入全连接层,进行信息汇总
self.fc1 = nn.Linear(6*6*256,4096) #上层所有特征图上的所有像素
self.fc2 = nn.Linear(4096,4096)
self.fc3 = nn.Linear(4096,1000)
def forward(self,x):
x = F.relu(self.conv1(x))
x = self.pool1(x)
x = F.relu(self.conv2(x))
x = self.pool2(x)
x = F.relu(self.conv3(x))
x = F.relu(self.conv4(x))
x = F.relu(self.conv5(x))
x = self.pool3(x)
x = x.view(-1,6*6*256) #将数据拉平
x = F.dropout(x,p=0.5) #dropout:随机让50%的权重为0
x = F.relu(F.dropout(self.fc1(x),p=0.5)) #dropout:随机让50%的权重为0
x = F.relu(self.fc2(x))
output = F.softmax(self.fc3(x),dim=1)
net = Model()
net(data)
from torchinfo import summary
summary(net,input_size=(10,3,227,227))
结果显示:
==========================================================================================
Layer (type:depth-idx) Output Shape Param #
==========================================================================================
Model -- --
├─Conv2d: 1-1 [10, 96, 55, 55] 34,944
├─MaxPool2d: 1-2 [10, 96, 27, 27] --
├─Conv2d: 1-3 [10, 256, 27, 27] 614,656
├─MaxPool2d: 1-4 [10, 256, 13, 13] --
├─Conv2d: 1-5 [10, 384, 13, 13] 885,120
├─Conv2d: 1-6 [10, 384, 13, 13] 1,327,488
├─Conv2d: 1-7 [10, 256, 13, 13] 884,992
├─MaxPool2d: 1-8 [10, 256, 6, 6] --
├─Linear: 1-9 [10, 4096] 37,752,832
├─Linear: 1-10 [10, 4096] 16,781,312
├─Linear: 1-11 [10, 1000] 4,097,000
==========================================================================================
Total params: 62,378,344
Trainable params: 62,378,344
Non-trainable params: 0
Total mult-adds (G): 11.36
==========================================================================================
Input size (MB): 6.18
Forward/backward pass size (MB): 52.74
Params size (MB): 249.51
Estimated Total Size (MB): 308.44
==========================================================================================