CNN基础网络(一)
CNN基础网络介绍
- LeNet
- AlexNet
- VGG
- NiN
- GoogLeNet
CNN(卷积神经网络)借助卷积层保留了输入形状,使图像在宽和高两个方向上的相关性均可能被有效识别,另一方面卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免了参数尺寸过大。有效集解决了临近像素点的特征提取和模型参数过大的问题。
卷积神经网络就是包含卷积层的网络,这个名字最早来源于Lenet论文的第一作者Yann LeCun。Lenet展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当时最先进的成果。
LeNet
LeNet模型分为卷积层块和全连接层块。
卷积层块里的基本单位是卷积层后接最大池化层(Maxpool),卷积层用来识别图像里的空间模式,如线条和物体局部,之后的最大池化层则用来降低卷积层对位置的敏感性。卷积层块由两个这样的基本单位重复堆叠而成,每个卷积层都使用5x5的kernel,并在输出上使用sigmoid激活函数。最大池化层的kernel形状均为2x2,且步幅为2。
卷积层块的输出传入全连接层时,将输出的形状变为二维,其中第一维是小批量中的样本,第二维是每个样本的向量表示,向量长度为CxHxW。全连接层块包含三个全联接层,他们的输出个数分别是120、84、10。其中10位输出的类别个数。
Pytorch实现:
class LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv = nn.Sequential(nn.Conv2d(1, 6, 5),nn.Sigmoid(),nn.MaxPool2d(2, 2),nn.Conv2d(6, 16, 5),nn.Sigmoid(),nn.MaxPool2d(2, 2))self.fc = nn.Sequential(nn.Linear(16*4*4, 120),nn.Sigmoid(),nn.Linear(120, 84),nn.Sigmoid(),nn.Linear(84, 10))def forward(self, img):feature_map = self.conv(img)output = self.fc(feature_map.view(img.shape[0], -1))return output
AlexNet
在LeNet提出的近20年间,神经网络一度被其他机器学习方法取代,虽然LeNet在小数据集上取得了不错的成绩,但是在更大的真实数据集上的表现却不尽如人意。一方面受硬件水平限制,算力无法满足计算需求,另一方面,当年的研究者没有深入研究参数初始化和非凸优化算法等诸多领域,导致复杂的神经网络训练通常较为困难。
从LeNet可以看到,神经网络可以基于图像的原始像素进行分类。这种端到端的方法节省了很多中间步骤。然而,在很长一段时间里更流行的是研究者设计并生成手工的特征。这类图像分类研究的主要流程是:
- 获取图像数据集;
- 使用已有的特征提取函数提取图像特征;
- 使用机器学习模型对提取的特征进行分类。
当时认为的机器学习部分仅限于最后一步,然而另一部分人认为特征本身也应该由学习得来,并且,为了表征足够复杂的输入,特征本身应该分级表示,多层神经网络可以学习到数据的多级表征,并逐级表示越来越抽象的概念。在很长一段时间里,这部分人的理念并未实现,原因有二。
其一为数据集的限制,包含许多特征的深度模型需要大量的有标签数据集才能表现的比其他经典方法更好。这一状况在2010年前后兴起的大数据浪潮中得以改善,特别是2009年诞生的ImageNet数据集,包含1000类物体,每类多达数千张不同图像。ImageNet数据集同时推动计算机视觉和机器学习研究进入了新阶段。
其二为硬件资源限制,早期的硬件计算能力有限,使得训练较为复杂的神经网络非常困难,这一格局直到通用GPU的出现才得以改善。
2012年AlexNet使用8层卷积神经网络赢得了ImageNet 2012图像识别挑战赛,首次证明了学习到的特征可以超越手工设计的特征。Alexnet结构与Lenet类似,但使用了更多的卷积层和更大的参数空间拟合大规模数据集,是浅层神经网络和深层神经网络的分界。
AlexNet与Lenet有如下区别:
- 模型结构变化
AlexNet使用5层卷积和3层全连接,其中第一层卷积Kernel为11x11,这样做的目的是扩大感受野来捕获较大输入图像的特征。第二层的卷积kernel形状减小到5x5,之后全部采用3x3。此外,第一、第二和第五个卷积层之后都使用了窗口形状为3x3,步幅为2的最大池化层。接着最后一层卷积的是两个输出个数为4096的全连接层,最后使用一个输出个数为10的全连接。 - 激活函数变化
AlexNet将sigmoid激活函数改成了更加简单的Relu激活函数。一方面,ReLU激活函数的计算更加简单,另一方面,ReLU激活函数在不同的参数初始化方法下使模型更加容易训练。这是因为sigmoid激活函数输出接近0或1时,这些区域的梯度几乎为0,从而造成反向传播无法继续更新部分模型参数。 - Dropout
Alexnet中引入了Droupout层,用来控制全连接层的模型复杂度,避免出现过拟合。 - 图像处理
Alexnet引入了大量的图像增广,如翻转、裁剪和颜色变化,从而进一步扩大数据集来缓解过拟合。
Pytorch实现:
class AlexNet(nn.Module):def __init__(self):super(AlexNet, self).__init__()self.conv = nn.Sequential(nn.Conv2d(1, 96, 11, 4),nn.ReLU(),nn.MaxPool2d(3, 2),nn.Conv2d(96, 256, 5, 1, 2),nn.ReLU(),nn.MaxPool2d(3, 2),nn.Conv2d(256, 384, 3, 1, 1),nn.ReLU(),nn.Conv2d(384, 384, 3, 1, 1),nn.ReLU(),nn.Conv2d(384, 256, 3, 1, 1),nn.ReLU(),nn.MaxPool2d(3, 2))self.fc = nn.Sequential(nn.Linear(256*5*5, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 10))def forward(self, img):features = self.conv(img)output = self.fc(features.view(img.shape[0], -1))return output
VGG
AlexNet在Lenet的基础上加宽了卷积核获得更大的感受野,VGG则在AlexNet的基础上加深了卷积层。
VGG由多个VGG块组成,组成规律为:连续使用数个相同的pad为1,Kernel为3x3的卷积层后接上一个stride为2,kernel为2x2的最大池化层。卷积层保持输入的高和宽不变,而池化层则对其减半。
对于给定的感受野,采用堆积的小卷积核优于采用大的卷积核,因为可以增加网络深度来保证学习更复杂的模式,而且参数更少。例如,在VGG中,使用了3个3x3的卷积核来代替7x7的卷积核,使用2个3x3的卷积核来代替5x5卷积核。这样做的目的是在保证具有相同感受野的条件下,提升网络的深度来提升神经网络的效果。
与AlexNet和LeNet一样,VGG网络由卷积层模块后接全连接层模块构成。卷积层模块串联数个vgg_block,其超参数由变量conv_arch定义。该变量指定了每个VGG块里卷积层个数和输入输出通道数,全连接模块与AlexNet一样。
VGG-11 Pytorch实现:
def vgg_block(num_convs, in_channel, out_channels):blk = []for i in range(num_convs):if i == 0:blk.append(nn.Conv2d(in_channel, out_channels, kernel_size=3, padding=1))else:blk.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))blk.append(nn.ReLU())blk.append(nn.MaxPool2d(kernel_size=2, stride=2))return nn.Sequential(*blk)def VGG(conv_arch, fc_features, fc_hidden_units):net = nn.Sequential()for i, (num_convs, in_channels, out_channels) in enumerate(conv_arch):net.add_module('vgg_block_' + str(i), vgg_block(num_convs, in_channels, out_channels))net.add_module('fc', nn.Sequential(layer.FlattenLayer(),nn.Linear(fc_features, fc_hidden_units),nn.ReLU(),nn.Dropout(0.5),nn.Linear(fc_hidden_units, fc_hidden_units),nn.ReLU(),nn.Dropout(0.5),nn.Linear(fc_hidden_units, 10)))return net
NiN
NiN使用1x1卷积替代全连接层,通过串联多个由卷积层和1x1卷积层(全连接层)构成的小网络来构建一个深层网络。
NiN使用卷积窗口形状分别为11x11、5x5和3x3的卷积层。NiN块是NiN中的基础块,它由一个卷积层加两个充当全连接层的1x1卷积层串联而成。每个NiN块后接一个stride为2、窗口形状为3x3的最大池化层。
除了使用NiN块以外,NiN去掉了AlexNet最后的3个全连接层,取而代之地,NiN使用了输出通道数等于标签类别数的NiN块,然后使用全局平均池化层对每个通道中所有元素求平均并直接用于分类,这样设计显著减小了模型的参数尺寸。
Pytorch实现:
import torch.nn.functional as Fclass FlattenLayer(nn.Module):def __init__(self):super(FlattenLayer, self).__init__()def forward(self, x):x = x.view(x.shape[0], -1)return xclass GlobalAvgPool2d(nn.Module):def __init__(self):super(GlobalAvgPool2d, self).__init__()def forward(self, x):return F.avg_pool2d(x, kernel_size=x.size()[2:])def nin_block(in_channels, out_channels, kernel_size, stride, padding):blk = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding),nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=1),nn.ReLU(),nn.Conv2d(out_channels, out_channels, kernel_size=1),nn.ReLU())return blkdef Nin():net = nn.Sequential(nin_block(1, 96, kernel_size=11, stride=4, padding=0),nn.MaxPool2d(kernel_size=3, stride=2),nin_block(96, 256, kernel_size=5, stride=1, padding=2),nn.MaxPool2d(kernel_size=3, stride=2),nin_block(256, 384, kernel_size=3, stride=1, padding=1),nn.MaxPool2d(kernel_size=3, stride=2),nn.Dropout(0.5),nin_block(384, 10, kernel_size=3, stride=1, padding=1),GlobalAvgPool2d(),FlattenLayer())return net
GoogLeNet
GoogLeNet中的基础块叫做Inception块,与NiN块相比,这个基础块在结构上更加复杂:
Inception块里有4条并行线路,前三条分别使用窗口为1x1、3x3、5x5的卷积层来抽取不同空间尺寸下的信息,中间两个线路使用1x1卷积来减少输入的通道数,以降低模型复杂度。四条线路都使用了合适的填充来使输入与输出的高和宽一致。最后将每条线路的输出在通道维度上拼接,作为下一层的输入。Inception块中可以自定义每个层的输出通道数,以此来控制模型复杂度。
GoogLeNet主体卷积部分中使用了五个block,每个block之间使用stride为2的3x3最大池化层来减小输出的高和宽。
第一个block使用一个64通道的7x7卷积层,第二个block使用2个卷积层,分别为64通道的1x1卷积层,然后是将通道增大3倍的3x3卷积层。第三个block串联2个完整的Inception块。第四个block串联5个Inception块。第五个block串联两个Inception块,后面紧跟输出层,之后接全局平均池化层和全连接层。
Pytorch实现:
class Inception(nn.Module):def __init__(self, in_c, c1, c2, c3, c4):super(Inception, self).__init__()self.p1_1 = nn.Conv2d(in_c, c1, kernel_size=1)self.p2_1 = nn.Conv2d(in_c, c2[0], kernel_size=1)self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)self.p3_1 = nn.Conv2d(in_c, c3[0], kernel_size=1)self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)self.p4_2 = nn.Conv2d(in_c, c4, kernel_size=1)def forward(self, x):p1 = F.relu(self.p1_1(x))p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))p4 = F.relu(self.p4_2(self.p4_1(x)))return torch.cat((p1, p2, p3, p4), dim=1)def Googlenet():b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),nn.Conv2d(64, 192, kernel_size=3, padding=1),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),Inception(256, 128, (128, 192), (32, 96), 64),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),Inception(512, 160, (112, 224), (24, 64), 64),Inception(512, 128, (128, 256), (24, 64), 64),Inception(512, 112, (144, 288), (32, 64), 64),Inception(528, 256, (160, 320), (32, 128), 128),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),Inception(832, 384, (192, 384), (48, 128), 128),GlobalAvgPool2d())net = nn.Sequential(b1, b2, b3, b4, b5, FlattenLayer(), nn.Linear(1024, 10))return net
CNN基础网络(一)相关推荐
- CNN经典网络:LeNet、AlexNet、NIN、VGG
LeNet CNN的开山之作,是LeCun在98年解决手写是数字识别任务时提出的,从那时起CNN的基本架构就定下来了:卷积.池化.全连接层. 网络结构 如图 3.1 所示,最早的 LeNet 有 7 ...
- CNN基础论文 精读+复现----VGG(一)
文章目录 前言 第1页 第2-3页 第四页 第五页 前言 原文Github地址:https://github.com/shitbro6/paper/blob/main/VGG.pdf 原文arxiv地 ...
- CNN基础论文 精读+复现----LeNet5 (二)
文章目录 复现准备 数据部分 搭建网络结构 C1层: S2层: C3层: S4层: C5层: F6层: Output层: 损失函数与优化器: 复现准备 论文开头的一些概念和思想已经分析完.没看过的可以 ...
- CNN基础论文 精读+复现---- ResNet(二)
文章目录 准备工作 BasicBlock块 ResNet-18.34网络结构 完整代码: 小总结 准备工作 昨天把论文读完了,CNN基础论文 精读+复现---- ResNet(一) ,今天用pytor ...
- CNN基础论文 精读+复现----GoogleNet InceptionV1 (一)
文章目录 前言 第1页 摘要与引言 第2页 文献综述 第3-4页 第4-5页 inception模块细节 第5-7页 GoogLeNet 第8页 训练细节 第8-10页 ILSVRC 2014 inc ...
- 笔记|李沐-动手学习机器学习|CNN基础知识(视频19-23)
李沐-动手学习机器学习|CNN基础知识 卷积层(视频19) 从全连接到卷积(卷积算子) 进行图像识别的两个原则 如何从全连接层出发,应用以上两个原则,得到卷积 卷积层 二维交叉相关 二维卷积层 交叉相 ...
- 『中级篇』k8s基础网络Cluster Network(66)
原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』k8s基础网络Cluster Network(66) 通过国人大神的一键安装k8s集群安装了3个master节点和3 ...
- 基础网络和关键基础设施
1.基础网络和关键基础设施 基础通信网络安全防护水平进一步提升 基础电信企业逐年加大网络安全投入,加强通信网络安全防护工作的体系.制度和手段建设,推动相关工作系统化.规范化和常态化.2015年,工业和 ...
- 手撕 CNN 经典网络之 VGGNet(PyTorch实战篇)
大家好,我是红色石头! 在上一篇文章: 手撕 CNN 经典网络之 VGGNet(理论篇) 详细介绍了 VGGNet 的网络结构,今天我们将使用 PyTorch 来复现VGGNet网络,并用VGGNet ...
最新文章
- Spring Boot教程(三十四)整合elk(1)
- i5四核八线程怎么样_同样四核八线程,Ryzen 3 3100和3300X区别大了!
- Difference: throw or throw ex?
- Meteor:用户账号管理添加密码和微博weibo账号系统支持
- Angular 内嵌视图、宿主视图
- LeetCode 415. 字符串相加 (逢十进一模版字符处理)
- yolov3代码详细解读
- const int *p和int *const p的区别
- 使用pscp在Linux、Windows间互传文件
- html页面自动跳转
- webpack入坑之旅(一)不是开始的开始
- 【备忘】Java教学系列视频教程 孔浩老师 千课巨献全网最全 共26G
- 2020软考高级系统分析师,你想知道的全在这
- 微信小程序录制视频功能实现
- Latex图表设置中英文双标题(非ccaption宏包)
- android spinner 取消默认值,令请选择
- PMP证书现在还值得考吗?
- C语言之指向一维数组的指针
- 微信小程序接受服务器发过来的消息,微信小程序API 接收消息和事件
- 2020计算机科学第五轮评估,第五轮学科评估启动,这些非“双一流”建设高校可能获得A+学科...