现代卷积神经网络
现代卷积神经网络
对于最终模型精度影响来说,更大或更干净的数据集,稍微进行改进的特征提取,比任何学习算法带来的进步要大的多。
深度卷积学习网络 AlexNet
最火的机器学习是核方法,核心是特征提取,选择核函数来计算相关性,然后转换成凸优化问题,会有较好的定理,能够计算模型的复杂度。
在网络包含许多特征的深度模型需要大量的标签数据。训练可能需要数百个迭代轮数,对计算资源要求很高。AlexNet与LetNet在本质上没有任何区别。计算机视觉方法论的改变,之前专注于人工特征提取,但是后来利用CNN来进行学习特征,形成端到端的学习。
在最低层,模型学习到了一些类似于传统滤波器的特征提取器,AlexNet的更高层建立在这些底层表示的基础上,以表示更大的特征。最终的隐藏神经单元可以学习图像的综合表示,使得不同类别的数据易于区分。
AlexNet由八层组成,五个卷积层、两个全连接层和一个全连接输出层,使用ReLU作为激活函数,使用不同的参数初始化方法,ReLU激活函数使训练模型更加容–sigmoid函数的输出非常接近0时,这些区域的梯度几乎为0,会影响反向传播继续更新模型参数。使用暂退法(dropout=0.5)来控制全连接层的模型复杂度,为了进一步扩充数据,在训练时候增加了大量的图像增强数据,使得模型更加健壮,更大的样本量有效的减少过拟合。使用更大的卷积核,因为图片的输入更大了,同时输出的通道数也增加,希望在第一层的时候就能学到更多的特征。
import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(
nn.Conv2d(1,96,kernel_size = 11,stride=4,padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(96,256,kernel_size=5,padding=2),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(256,384,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(384,384,kernel_size=3,padding=1),
nn.ReLU(),
nn.Conv2d(384,256,kernel_size=3,padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Flatten(),
nn.Linear(6400,4096),nn.ReLU(),nn.Dropout(p=0.5),
nn.Linear(4096,4096),nn.ReLU(),nn.Dropout(p=0.5),
nn.Linear(4096,10))
# 构造一个单通道数据 来观察每一层的输出的形状
X= torch.randn(1,1,224,224)
for layer in net:
X = layer(X)
print(layer.__class__.__name__,'output shape:\t',X.shape)
运行结果:
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
# Fashion-MNIST图像的分辨率低于ImageNet图像,我们将他增加到224*224
batch_size = 128
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size,resize=224)
#训练AlexNet 学习率的下降会增加训练的时间
lr,num_epochs = 0.01,10
d2l.train_ch6(net,train_iter,test_iter,num_epochs,lr,d2l.try_gpu())
运行结果:
1.使用更多的卷积层和更多的参数来拟合大规模的数据集
2.Dropout(正则项)、ReLU和预处理是提升计算机视觉任务性能的关键
3.使用了数据增强(随机截取,调整图片的亮度色温等)
4.ALexNet比LeNet学习的参数更多,机器找到的特征是不符合人类逻辑的。论文中提及的LRN是正则化技术,但是用处不大。因为前面的卷积特征抽取的不够深刻,所以需要两个dense来进行补充。
使用块的网络VGG
AlexNet没有提供一个通用的模板来指导后续的研究人员设计新的网络,结构不够清晰,研究人员开始从单个神经元的角度思考问题,发展到整个层,现在又转向块,重复层的模式。
思考怎样才能获得更深和更大的网络?更多的全连接层?更多的卷积层?将卷积层组合成块?
经典的卷积神经网络的基本组成部分:
1.带填充以保持分辨率的卷积层 2.非线性激活层 3.汇聚层
VGG块由一系列的卷积层组成,后面再加上用于空间下采样的最大池化层。使用了带有33卷积核,填充为1的卷积层,和带有22窗口,步幅为2的最大池化层。
VGG神经网络连接几个VGG块,其中有超参数变量conv_arch。该变量指定了每个VGG块里卷积层个数和输出通道数。全连接模块则与AlexNet中的相同。原始VGG网络有5个卷积块,其中前两个块各有一个卷积层,后三个块各包含两个卷积层。第一个模块有64个输出通道,每个后续模块将输出通道数量翻倍,直到该数字达到512。由于该网络使用8个卷积层和3个全连接层,被称为VGG-11。
VGG-11使用可复用的卷积块构造网络。不同的VGG模型可以通过每个块中卷积层的数量和输出通道数量的差异来定义。块的使用导致网络定义的非常简洁,使用块可以有效的设计更复杂的网络。在VGG论文中,发现深层且窄的卷积比较浅层且宽的卷积更有效。
import torch
from torch import nn
from d2l import torch as d2l
# 参数:重复的卷积层的个数,输出的通道数,输入的通道数
def vgg_block(num_convs,in_channels,out_channels):
layers =[]
for _ in range(num_convs):
layers.append(nn.Conv2d(
in_channels,out_channels,kernel_size=3,padding=1))
layers.append(nn.ReLU())
in_channels = out_channels
layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
# 放入sequential中变成一个vgg的块
return nn.Sequential(*layers)
#VGG网络
# 每块会做最大池化,输入尺寸减半
conv_arch = ((1,64),(1,128),(2,256),(2,512),(2,512))
def vgg(conv_arch):
conv_blks=[]
in_channels=1
for (num_convs,out_channels) in conv_arch:
conv_blks.append(vgg_block(
num_convs,in_channels,out_channels))
in_channels = out_channels
return nn.Sequential(
*conv_blks,nn.Flatten(),
nn.Linear(out_channels*7*7,4096),nn.ReLU(),
nn.Dropout(0.5),nn.Linear(4096,4096),nn.ReLU(),
nn.Dropout(0.5),nn.Linear(4096,10))
net = vgg(conv_arch)
# 观察每一层的输出形状
X = torch.randn(size=(1,1,224,224))
for blk in net:
X = blk(X)
print(blk.__class__.__name__,'output shape:\t',X.shape)
Sequential output shape: torch.Size([1, 64, 112, 112])
Sequential output shape: torch.Size([1, 128,