4 复现经典网络:LeNet5与AlexNet

4.1 现代CNN的奠基者:LeNet5

使用卷积层和池化层能够创造的最简单的网络是什么样呢?或许就是下面这样的架构:
首先,图像从左侧输入,从右侧输出,数据传输方向与DNN一致。整个网络由2个卷积层、2个平均池化层和2个全连接层组成,虽然没有标注出来,但每个卷积层和全连接层后都使用激活函数tanh或sigmoid。

这个架构就是著名的LeNet5架构,它在1998年被LeCun等人在论文《Gradient-Based Learning Applied to Document Recognition》中正式提出,它被认为是现代卷积神经网络的奠基者。在LeNet5被提出后,几乎所有的卷积网络都会连用卷积层、池化层与全连接层(也就是线性层)。现在,这已经成为一种非常经典的架构:卷积层作为输入层,紧跟激活函数,池化层紧跟在一个或数个卷积+激活的结构之后。在卷积池化交替进行数次之后,转向线性层+激活函数,并使用线性层结尾,输出预测结果。由于输入数据结构的设置,以上架构图中的网络可能与论文中有一些细节上的区别(论文见下载资料),在其他教材中,你或许会见到添加了更多卷积层、或添加了更多池化层的相似架构,这些都是根据LeNet的核心思想“卷积+池化+线性”来搭建的LeNet5的变体。

在上面的架构中,每层的结构和参数都标识得非常清楚,在PyTorch中实现其架构的代码如下:

import torch
from torch import nn
from torch.nn import functional as F
data = torch.ones(size=(10,1,32,32))
class Model(nn.Module):def __init__(self):super().__init__()self.conv1 = nn.Conv2d(1,6,5)self.pool1 = nn.AvgPool2d(kernel_size=2,stride=2)self.conv2 = nn.Conv2d(6,16,5)self.pool2 = nn.AvgPool2d(kernel_size=2,stride=2)self.fc1 = nn.Linear(16*5*5,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,16*5*5) #需要将数据的特征部分“拉平”才能够进入FC层x = F.tanh(self.fc1(x))output = F.softmax(self.fc2(x),dim=1)
net = Model()
net(data) #卷积网络的一大特点是:改变输入数据的尺寸,整个网络就会开始花式报错
#你可以试试将数据32*32的结构修改至28*28
#安装torchinfo库,查看网络结构
!pip install torchinfo
from torchinfo import summary
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
#==========================================================================================

这是我们在之前的课程中学到的写法,这种写法适合层数较少、层次简单的神经网络,但这个网络和我们之前写的只有线性层的网络比起来还是略有些复杂了。在这段代码中你可以清晰地看见卷积层、池化层以及全连接层是如何链接在一起共同作用的。我们将“层”放在init中定义,而将“函数”放在forward中定义,令init中的结构与forward中的结构一一对应,并使用forward函数执行向前传播流程。

从今天的眼光来看,LeNet5无疑是很简单并且有些弱小的卷积网络,然而,当加入学习率衰减等优化方法并训练恰当时,单一的LeNet5模型可以在Fashion-MNIST数据集上获得超过91%的训练准确率(可参考kaggle kernel:https://www.kaggle.com/jaeboklee/pytorch-fashion-mnist-lenet5-ensemble)。

这个效果已经比只有线性层的网络提升了约5%的成绩。虽然简单,LeNet5却切实展示了卷积神经网络的实力。

4.2 从浅层到深度:AlexNet

在二十一世纪的前十年,LeNet5作为现代卷积网络的奠基者并没有引起太大的水花,大多数人并不相信机器提取的特征能够比人亲自提取的特征更强大,事实上,LeNet5也确实无法在复杂任务上战胜传统计算机视觉方法。卷积网络在被提出的几十年内一直在蛰伏,直到2012年,AlexNet横空出世,真正第一次证明了,当数据量达标、训练得当时,卷积神经网络提取的特征效果远远胜过人类提取的特征。


AlexNet诞生于有“视觉界奥林匹克”之称的大规模视觉识别挑战比赛ILSVRC(ImageNet Large Scale Visual Recognition Challenge)。ILSVRC使用ImageNet数据集,共有一千四百多万幅图像,共2万多个类别,图像的尺寸有224×224,227×227,256×256,299×299等不同类型。在ILSVRC中,参赛队伍需要使用大约包含一百万张图片的训练集来训练模型,并识别出测试集中的一千个类别,再按“错误率”从低到高进行排名(具体错误率是如何计算的,将在我们使用ImageNet进行训练的时候来说明)。在AlexNet出现之前,最好成绩一直由手工提取特征+支持向量机的算法获得,最低错误率为25.8%。2012年,AlexNet进入ILSVRC竞赛,一下将错误率降低到了15.3%。在过去的ImageNet竞赛中,哪怕有一个百分点的提升都是非常不错的成绩,而深度学习首次入场就取得了10个百分点的提升,这给整个图像领域带来了巨大的震撼,从那之后图像领域的前沿研究就全面向深度学习倾斜了。AlexNet无疑是真正让“深度视觉”出圈的架构,其架构如下所示:


AlexNet总共有11层,其中有5个卷积层、3个池化层、2个全连接隐藏层,1个全连接输出层,实际上,在全连接层的前后AlexNet使用了Dropout层,但在大部分架构上都不会把DP表现出来。

在有的文献上,你可能看到人们称AlexNet为8层(不计算池化层)。实际上,在学术界,我们对于神经网络的“层”的计数方法没有明确的定义,有的文献会将所有卷积中的元素都算做“层”,例如、池化、BN、Dropout等都是层,而有的文献认为,只有带有训练参数的才能够被称为“层”,其他对数据进行处理的、不带训练参数的功能(如池化、激活函数、Dropout等)都属于参数层的附属。大部分文献中的架构图只会写出卷积、池化以及全连接层是如何排列,即便文献中提到使用了Dropout或BN等计算方式,可能也不一定会明确这些计算在整体网络架构的哪一部分。在PyTorch中进行计算时,就连激活函数也可以是单独的层。因此,人们对于一个神经网络究竟有几层是没有明确定义的。在学习架构时,不用去纠结整体的层数,而要从层与层之间的组合入手。例如,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)成为可能。

除此之外,在原论文中,作者Alex Krizhevsky还提出了其他创新,例如,他们使用了overlap pooling的技术——一般的池化层在进行扫描的时候,都是步幅 >= 核尺寸,而在AlexNet中,池化层中的步幅是小于核尺寸的,这就让池化过程中的扫描区域出现重叠(overlap),根据论文所示,这个技术可以缓解过拟合。从以上这些点,很容易看出为什么AlexNet对于卷积神经网络而言如此地重要,它几乎从算法、算力、数据、架构技巧等各个方面影响了现代卷积神经网络地发展。AlexNet之后,ImageNet竞赛上就很少看到传统视觉算法的身影了。当然,竞赛环境与工业环境有极大的区别,在实际落地的过程中,深度学习还受到各种限制,因此传统方法依然很关键。

现在,让我们在PyTorch中来复现AlexNet的架构:

import torch
from torch import nn
from torch.nn import functional as Fdata = torch.ones(size=(10,3,227,227)) #假设图像的尺寸为227x227class Model(nn.Module):def __init__(self):super().__init__()       #大卷积核、较大的步长、较多的通道self.conv1 = nn.Conv2d(3,96,kernel_size=11, stride=4) self.pool1 = nn.MaxPool2d(kernel_size=3,stride=2)#卷积核、步长恢复正常大小,进一步扩大通道self.conv2 = nn.Conv2d(96,256,kernel_size=5, padding=2) self.pool2 = nn.MaxPool2d(kernel_size=3,stride=2)#连续的卷积层,疯狂提取特征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(256*6*6,4096) #这里的上层输入是图像中的全部像素self.fc2 = nn.Linear(4096,4096)self.fc3 = nn.Linear(4096,1000) #输出ImageNet的一千个类别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,256*6*6) #需要将数据的特征部分“拉平”才能够进入FC层x = F.relu(F.dropout(self.fc1(x),0.5)) #dropout:随机让50%的权重为0x = F.relu(F.dropout(self.fc2(x),0.5)) 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, 348, 13, 13]         802,140
# ├─Conv2d: 1-6                            [10, 348, 13, 13]         1,090,284
# ├─Conv2d: 1-7                            [10, 256, 13, 13]         802,048
# ├─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: 61,975,216
# Trainable params: 61,975,216
# Non-trainable params: 0
# Total mult-adds (G): 10.68
# ==========================================================================================
# Input size (MB): 6.18
# Forward/backward pass size (MB): 51.77
# Params size (MB): 247.90
# Estimated Total Size (MB): 305.85
# ==========================================================================================

与LeNet5实现时候的情况一致,由于输入数据的结构可能与原论文有区别,我们的网络架构中的小细节可能与原论文有些许不同。从代码量来看,其实AlexNet并没有比LeNet5复杂太多,当结构清晰时,我们甚至认为AlexNet有些简单。但在AlexNet出世之前,学术界普遍认为深度网络是不可能训练的,而今天我们都了解,只要有足够的算力和数据,即便是几亿参数的巨量网络也是可以训练的。AlexNet所带来的观念上的转变才是真正推动卷积神经网络向前发展的核心。

只要有架构图,复现经典架构其实并不是一件难事(照着敲代码,一点也不难),但我们不太可能完全记住经典架构中的每个细节。在复现架构时,我们应该注意哪些方面呢?

1、首先,代码可以不自己写,但一定要通
2、了解此架构的核心思想,以及在此思想下其结构大概如何排布。对于比较简单的网络(比如AlexNet),可以记住具体的层的结构(包括参数大概的大小),但对于复杂网络,可以不用难为自己,理解思想为主,看见代码能认出是该网络,并且看见代码之后能够理解每层具体在做什么,做的事情如何与该网络的核心思想一致。
3、了解此架构被提出的背景,即可了解它的突破与局限
4、发现架构与自己熟悉的不一致,先多谷歌下不同的架构图,或许你看到的只是别人基于经典架构修改的变体。实在纠结,再回看提出框架的具体论文。

到这里,相信大家对卷积层和池化层的应用已经有了基本的了解。作为进阶内容,大家可以试着摆脱课件中的代码,自己对着架构图复现网络架构,你甚至可以试着计算一下各层特征图的大小,将此架构改写为更简洁的形式,并利用这些架构在经典数据集上进行各种尝试。

Lesson 16.6Lesson 16.6 复现经典架构:LeNet5 复现经典架构 (2):AlexNet相关推荐

  1. 16 张图详解,淘宝十年架构演进过程

    文本文以淘宝为例讲解了大型网站的架构演进过程,特此分享给大家,相信看完会有所收获.整个架构的演进过程: 单机架构 第一次演进:Tomcat与数据库分开部署 第二次演进:引入本地缓存和分布式缓存 第三次 ...

  2. CV+Deep Learning——网络架构Pytorch复现系列——Detection(一:SSD:Single Shot MultiBox Detector 4.推理Detect)

    上一话 CV+Deep Learning--网络架构Pytorch复现系列--Detection(一:SSD:Single Shot MultiBox Detector 3.loss)https:// ...

  3. 进阶必备:CNN经典论文代码复现 | 附下载链接

    经常会看到类似的广告<面试算法岗,你被要求复现论文了吗?>不好意思,我真的被问过这个问题.当然也不是所有面试官都会问,究其原因,其实也很好理解.企业肯定是希望自己的产品是有竞争力,有卖点的 ...

  4. 撒花!算法岗必须复现的上百篇经典论文代码完结啦! | 附下载链接

    经常会看到类似的广告<面试算法岗,你被要求复现论文了吗?>不好意思,我真的被问过这个问题.当然也不是所有面试官都会问,究其原因,其实也很好理解.企业肯定是希望自己的产品是有竞争力,有卖点的 ...

  5. 16.4 配置Tomcat监听80端口 16.5/16.6/16.7 配置Tomcat虚拟主机16.8 Tomcat日志

    2019独角兽企业重金招聘Python工程师标准>>> 16.4 配置Tomcat监听80端口 直接访问,使用默认的web服务,需要改动端口为80,如果不是80端口那么访问页面的时候 ...

  6. Pytorch之CNN:基于Pytorch框架实现经典卷积神经网络的算法(LeNet、AlexNet、VGG、NIN、GoogleNet、ResNet)——从代码认知CNN经典架构

    Pytorch之CNN:基于Pytorch框架实现经典卷积神经网络的算法(LeNet.AlexNet.VGG.NIN.GoogleNet.ResNet)--从代码认知CNN经典架构 目录 CNN经典算 ...

  7. 回顾经典,Netflix的推荐系统架构

    这篇文章我们回顾一篇经典博客,Netflix官方博客介绍的推荐系统架构,虽然文章发布已有六年, 但是现在回看起来我自己还是蛮惊讶的,因为Netflix的推荐系统架构居然到现在依然是主流. 当然,框架中 ...

  8. 如何将32 x 32像素图标转换为16 x 16像素值的图标

    14.如何将32 x 32像素图标转换为16 x 16像素值的图标 HICON Convert32x32IconTo16x16(HICON h32x32Icon) { HDC hMainDC, hMe ...

  9. BitMEX将于2月16日16:00引入防止输入错误交易规则

    2月2日,BitMEX官方发文宣布,将于北京时间2月16日16:00引入"Fat Finger"交易规则."Fat Finger"实际上是指一些少数用户的输入错 ...

最新文章

  1. Altium Protel PCB Layer
  2. [转]浅谈:国内软件公司为何无法做大做强
  3. Future和CompletableFuture的区别和对比,以及Future主要的四个缺点——不能回调会阻塞、批量任务处理彼此依赖会阻塞、不能多个任务级联执行、得不到最先完成的任务
  4. Mac OS开发—Xcode给Mac应用添加编辑快捷键(剪切 复制 粘贴 全选 删除 撤销 重做)功能
  5. 学习Linux——计算机概论
  6. 忠言多少有些逆耳,创业的九条真经
  7. 【MAVEN】搜索错误“Index downloads are disabled,search results may be incomplete”
  8. 主成分与因子分析异同_主成分和因子分析原理及比较
  9. 计算数学领域一些期刊(持续更新)
  10. java连接twitter登录,android中接入twitter进行第三方登录
  11. 阿里云服务器实例规格选型推荐(根据使用场景、典型应用推荐)
  12. 阿伯丁大学计算机科学硕士申请,又双叒有更多硕士专业可以一月入学了 | 阿伯丁大学2021年春季入学专业名单更新(2020年8月更新)...
  13. GD25Qxxx使用笔记
  14. mcgs组态软件中字体如果从左到右变化_在MCGS嵌入版组态软件中,数据对象有开关型、数值型、字符型、事件型和组对象五种类型。( )...
  15. Windows截图操作
  16. 学会分析股票的基本面!使你顺水长流!
  17. IDEA JAVA 新建Spring Cloud项目报错问题解决记录
  18. newifi3 opkg 配置备忘
  19. ota升级过程提示cache分区太小导致升级失败
  20. 发票识别+查验API快速辨别发票真伪

热门文章

  1. shell脚本实战 pdf_Shell脚本实战:日志关键字监控+自动告警
  2. docker配置容器mysql启动参数_修改Docker容器启动配置参数
  3. java安全管理器视频_java安全-安全管理器
  4. unity3d做会减少的血条_Unity3d中NGUI加强版血条(Healthbar)的制作
  5. java 制作报表案例_javaweb项目报表案例
  6. 鸿蒙os即将升级,央视爆料鸿蒙OS即将升级,荣耀智慧屏强大自研开启国货新时代...
  7. cuda 编 程(六)简单CUDA程序的基本框架
  8. bigquery按照小时来聚合数据
  9. Mac~Terminal终端操作命令、vim操作命令、mac系统快捷键
  10. 生物计算:SIR模型笔记