【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】

news2025/1/18 4:36:24

目录

    • 1. AlexNet模型
      • 1.1 AlexNet与LeNet的区别
      • 1.2 简化的AlexNet实现
      • 1.3 各层输出形状详解
    • 2. 读取数据
    • 3. 模型训练
    • 4. 总结

上一篇文章中我们了解到神经网络可以直接基于图像的原始像素进行分类,这种称为端到端(end-to-end)的方法可以节省很多中间步骤。但在1989年LeNet模型提出之后,神经网络在很长一段时间都没有长足的发展,主要有以下几个原因:

1.训练数据的缺失

​ 包含许多特征的深度模型需要大量的有标签的数据才能表现得比其他经典方法更好。限于早期计算机有限的存储和90年代有限的研究预算,大部分研究只基于小的公开数据集。例如,不少研究论文基于加州大学欧文分校(UCI)提供的若干个公开数据集,其中许多数据集只有几百至几千张图像。这一状况在2010年前后兴起的大数据浪潮中得到改善。特别是,2009年诞生的ImageNet数据集包含了1,000大类物体,每类有多达数千张不同的图像。这一规模是当时其他公开数据集无法与之相提并论的。ImageNet数据集同时推动计算机视觉和机器学习研究进入新的阶段,使此前的传统方法不再有优势。

2.硬件条件的不足

​ 深度学习对计算资源要求很高。早期的硬件计算能力有限,这使训练较复杂的神经网络变得很困难。然而,通用GPU的到来改变了这一格局。很久以来,GPU都是为图像处理和计算机游戏设计的,尤其是针对大吞吐量的矩阵和向量乘法从而服务于基本的图形变换。值得庆幸的是,这其中的数学表达与深度网络中的卷积层的表达类似。通用GPU这个概念在2001年开始兴起,涌现出诸如OpenCL和CUDA之类的编程框架。这使得GPU也在2010年前后开始被机器学习社区使用。

1. AlexNet模型

一直到2012年,AlexNet横空出世,AlexNet使用了8层卷积神经网络,并以很大的优势赢得了ImageNet 2012图像识别挑战赛。它首次证明了学习到的特征可以超越手工设计的特征,从而一举打破计算机视觉研究的前状。

在这里插入图片描述

1.1 AlexNet与LeNet的区别

第一,与相对较小的LeNet相比,AlexNet包含8层变换,其中有5层卷积和2层全连接隐藏层,以及1个全连接输出层。下面我们来详细描述这些层的设计。

AlexNet第一层中的卷积窗口形状是 11 × 11 11\times11 11×11。因为ImageNet中绝大多数图像的高和宽均比MNIST图像的高和宽大10倍以上,ImageNet图像的物体占用更多的像素,所以需要更大的卷积窗口来捕获物体。第二层中的卷积窗口形状减小到 5 × 5 5\times5 5×5,之后全采用 3 × 3 3\times3 3×3。此外,第一、第二和第五个卷积层之后都使用了窗口形状为 3 × 3 3\times3 3×3、步幅为2的最大池化层。而且,AlexNet使用的卷积通道数也大于LeNet中的卷积通道数数十倍。

紧接着最后一个卷积层的是两个输出个数为4096的全连接层。这两个巨大的全连接层带来将近1 GB的模型参数。由于早期显存的限制,最早的AlexNet使用双数据流的设计使一个GPU只需要处理一半模型。幸运的是,显存在过去几年得到了长足的发展,因此通常我们不再需要这样的特别设计了。

第二,AlexNet将sigmoid激活函数改成了更加简单的ReLU激活函数。一方面,ReLU激活函数的计算更简单,例如它并没有sigmoid激活函数中的求幂运算。另一方面,ReLU激活函数在不同的参数初始化方法下使模型更容易训练。这是由于当sigmoid激活函数输出极接近0或1时,这些区域的梯度几乎为0,从而造成反向传播无法继续更新部分模型参数;而ReLU激活函数在正区间的梯度恒为1。因此,若模型参数初始化不当,sigmoid函数可能在正区间得到几乎为0的梯度,从而令模型无法得到有效训练。

第三,AlexNet通过丢弃法(dropout)来控制全连接层的模型复杂度,而LeNet并没有使用丢弃法。

第四,AlexNet引入了大量的图像增广,如翻转、裁剪和颜色变化,从而进一步扩大数据集来缓解过拟合。

1.2 简化的AlexNet实现

下面我们实现稍微简化过的AlexNet:

import time
import torch
from torch import nn, optim
import torchvision

import sys
import d2lzh_pytorch as d2l
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
            nn.ReLU(),
            nn.MaxPool2d(3, 2), # kernel_size, stride
            # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
            nn.Conv2d(96, 256, 5, 1, 2),
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
            # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
            # 前两个卷积层后不使用池化层来减小输入的高和宽
            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)
        )
         # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
        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),
            # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
            nn.Linear(4096, 10),
        )

    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output

打印看看网络结构。

net = AlexNet()
print(net)

输出:

AlexNet(
  (conv): Sequential(
    (0): Conv2d(1, 96, kernel_size=(11, 11), stride=(4, 4))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(96, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU()
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU()
    (8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU()
    (10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU()
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (fc): Sequential(
    (0): Linear(in_features=6400, out_features=4096, bias=True)
    (1): ReLU()
    (2): Dropout(p=0.5)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU()
    (5): Dropout(p=0.5)
    (6): Linear(in_features=4096, out_features=10, bias=True)
  )
)

1.3 各层输出形状详解

若输入图像形状为1 * 224 * 224,那么各层输出情况如下:

self.conv = nn.Sequential(
    		# 输入:1*224*224
            nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding	
    		# 输出:96*54*54      【54=(224-11+4)/4】
            nn.ReLU(),
            nn.MaxPool2d(3, 2), # kernel_size, stride
    		# 输出:96*26*26      【26=(54-3+2)/2】
            # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
            nn.Conv2d(96, 256, 5, 1, 2),
    		# 输出:256*26*26     【26=26-5+2*2+1】
            nn.ReLU(),
            nn.MaxPool2d(3, 2),
    		# 输出:256*12*12     【12=(26-3+2)/2】
            # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
            # 前两个卷积层后不使用池化层来减小输入的高和宽
            nn.Conv2d(256, 384, 3, 1, 1),
    		# 输出:384*12*12   【12=12-3+2+1】
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),
    		# 输出:384*12*12   【12=12-3+2+1】
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),
    		# 输出:256*12*12   【12=12-3+2+1】
            nn.ReLU(),
            nn.MaxPool2d(3, 2)
    		# 输出:256*5*5    【5=(12-3+2)/2】
        )
         # 这里全连接层的输出个数比LeNet中的大数倍。使用丢弃层来缓解过拟合
        self.fc = nn.Sequential(
            # 输入:256*5*5=6400
            nn.Linear(256*5*5, 4096),
            # 输出:4096
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输入:4096
            nn.Linear(4096, 4096),
            # 输出:4096
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输入:4096
            # 输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而不是模型中的1000
            nn.Linear(4096, 10),
            # 输出:10
        )

2. 读取数据

虽然论文中AlexNet使用ImageNet数据集,但因为ImageNet数据集训练时间较长,我们仍用前面的Fashion-MNIST数据集来演示AlexNet。读取数据的时候我们额外做了一步将图像高和宽(28*28)扩大到AlexNet使用的图像高和宽(224 * 224)。这个可以通过torchvision.transforms.Resize实例来实现。也就是说,我们在ToTensor实例前使用Resize实例,然后使用Compose实例来将这两个变换串联以方便调用。

def load_data_fashion_mnist(batch_size, resize=None, root='~/Datasets/FashionMNIST'):
    """Download the fashion mnist dataset and then load into memory."""
    trans = []
    if resize:
        trans.append(torchvision.transforms.Resize(size=resize))
    trans.append(torchvision.transforms.ToTensor())
    
    transform = torchvision.transforms.Compose(trans)
    mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)
    mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)

    train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True, num_workers=4)
    test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False, num_workers=4)

    return train_iter, test_iter

batch_size = 128
# 如出现“out of memory”的报错信息,可减小batch_size或resize
train_iter, test_iter = load_data_fashion_mnist(batch_size, resize=224)

3. 模型训练

这时候我们可以开始训练AlexNet了。相对于LeNet,由于图片尺寸变大了而且模型变大了,所以需要更大的显存,也需要更长的训练时间了。

lr, num_epochs = 0.001, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
d2l.train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)

输出:

training on  cuda
epoch 1, loss 0.0047, train acc 0.770, test acc 0.865, time 128.3 sec
epoch 2, loss 0.0025, train acc 0.879, test acc 0.889, time 128.8 sec
epoch 3, loss 0.0022, train acc 0.898, test acc 0.901, time 130.4 sec
epoch 4, loss 0.0019, train acc 0.908, test acc 0.900, time 131.4 sec
epoch 5, loss 0.0018, train acc 0.913, test acc 0.902, time 129.9 sec

4. 总结

  • AlexNet跟LeNet结构类似,但使用了更多的卷积层和更大的参数空间来拟合大规模数据集ImageNet。它是浅层神经网络和深度神经网络的分界线。
  • 虽然看上去AlexNet的实现比LeNet的实现也就多了几行代码而已,但这个观念上的转变和真正优秀实验结果的产生令学术界付出了很多年。

对文章存在的问题,或者其他关于Python相关的问题,都可以在评论区留言或者私信我哦

如果文章内容对你有帮助,感谢点赞+关注!

关注下方GZH:阿旭算法与机器学习,可获取更多干货内容~欢迎共同学习交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/93537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯实践:从推荐模型的基础特点看大规模推荐类深度学习系统的设计

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年11月份热门报告盘点腾讯新闻信息流推荐技术实践.pdf推荐系统在腾讯游戏中的应用实践.pdf基于深度学习的个性化推荐系统实时化改造与升级.pdf推荐技术在vivo互联网商业化…

Zabbix与乐维监控对比分析(四)——告警管理篇

在前面发布的Zabbix与乐维监控对比分析文章中,我们评析了二者在架构与性能、Agent管理、自动发现、权限管理、对象管理等方面的差异。接下来让我们一起看看二者在告警管理方面的差异。 告警管理是所有IT监控平台最重磅的功能之一,也是评判一个监控平台好…

cad2010怎么隐藏标注尺寸,cad2007怎么隐藏标注尺寸

1、CAD2007怎么隐藏所有的标注尺寸? 1、在"查看器"菜单面板中隐藏的工具有"线宽"、"测量"、"文本"三种工具,可用于隐藏或显示CAD图中的线条宽度、测量尺寸和文本内容。 2、点击选择"测量"工具,将尺寸内容的CAD图隐藏起来。…

JavaScript-BOM

💖通过看视频教程和红宝书浅浅的写下一些关于BOM的笔记 红宝书知识系统全面,精炼。大概是因为太干货了,涉及的知识点太多,所以我选择看着简单的视频教程,同时打开红宝书。笔记的内容以红宝书为基准。 window对象 BOM的…

艾美捷内皮细胞生长添加剂解决方案

内皮细胞生长添加剂是一种培养基补充物,旨在体外优化人原代微血管内皮细胞的生长。这是一种无菌浓缩(100X)溶液,含有培养正常人微血管内皮细胞所需的生长因子、激素和蛋白质。该补充剂的配制(定量和定性)旨…

Linux下的多线程编程

线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一…

基于java+springmvc+mybatis+vue+mysql的教资考前指导系统

项目介绍 对于本教资考前指导系统的设计来说,系统开发主要是采用java语言技术,后端采用springboot框架,前端采用vue技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据教资考前指导系统的现状来进行开发…

Metasploit Framework简介

没有框架渗透测试者的困扰 ● 需要掌握数百个工具软件,上千个命令参数,实在记不住 ● 新出现的漏洞PoC/EXP有不同的运行环境要求,准备工作繁琐 ● 大部分时间都在学习不同工具的使用习惯,如果能同意就好了 ● Metasploit能解决以上…

pyinstaller遇到的问题

我到底看看能有多少问题,真的烦死我了!!!!!!!!!!!!!!!!!&#…

[附源码]Python计算机毕业设计公交电子站牌管理系统软件Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

HAProxy走私漏洞

HAProxy走私漏洞 JFrog安全研究团队发布了一个HAProxy的严重漏洞的信息。HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。 参考文章:https://jfrog.com/blog/critical-vulne…

虚拟生产、交付、体验,元宇宙技术对供应链的深远影响#低碳生活

#背景自新冠肺炎疫情爆发以来,元宇宙增长速度加快,也推动了对远程工作工具的前所未有的需求。目前全球元宇宙市场估值高于 1000 亿美元,据预计,到 2029 年,预计年均增长 47 %,达到 15270 亿美元。#改造供应…

【DevOps实战系列】第三章:详解Maven仓库及环境搭建

个人亲自录制全套DevOps系列实战教程 :手把手教你玩转DevOps全栈技术 Maven私有仓库,就不多说了,我们这里选用最新的Nexus3的3.17版本,平时公司使用的都是Nexus 2.x,新的3.x版本做了很多的升级,包括存储方式等&#xf…

self.eval_net.forward(state)和self.eval_net.forward(state)区别

在根据状态获取一个动作:self.eval_net.forward(state) 在更新网络时:self.eval_net(state) 这2个有什么区别呀,为啥不都是forward 我打印了一下返回值的时候,我感觉格式是一样的 action_value tensor([[0.7177, 0.7369, 0.7124,…

amfori BSCI行为守则(2021)最新版-2023年生效

【amfori BSCI行为守则(2021)最新版-2023年生效】 amfori BSCI 商界社会责任倡议(Business Social Compliance Initiative, BSCI)是一套国际通用的企业社会责任管理工具和验厂标准。amfori BSCI 颁布行为守则(Code of Conduct)&am…

十大编程语言黑客向,学会一个不怕没工作,全部学会随便秀操作

首先文章并不是鼓励大家去成为黑客,毕竟这个用在错误的地方,您最终可能需要尝试牢狱之灾。因为有很多的编程语言我也不是很懂,所以借鉴了一些专业人员的看法。当然他们不是黑客。然后下面给大家大概的介绍下其中十个吧。下期为您介绍剩下的几…

非地面无线通信网络的增强技术

【摘 要】通过增强基础地面网络,使之与星载或空载网络融合,可将地面通信网络应用推广到覆盖范围更广的非地面通信网络。分析非地面网络超大传输时延、多普勒效应、小区移动等通信条件对无线通信接口设计的影响,从标准化角度分析同步过程、定时关系、HARQ、波束管理与极化方…

C语言之文件操作

个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C/C】 目录文件的打开和关闭文件打开"r""w"注意有一个小细节文件的顺序读写字符输入输出函数fgetc和fputcfputcfg…

转轮除湿机空调系统运行时的故障排查SICOLAB

在现代科技不断发展的过程中,除湿技术已经应用到各个行业,尤其是在进行除湿空调系统设计时,因为相关系统的性能更加稳定且除湿量比较大、使用寿命更长、使用的设备比较简单,所以可以实现湿度的有效控制。 转轮除湿机空调系统在运…

【快速学习系列】SpringMVC的使用、传递参数(request、session、对象、集合...)及显示风格

【快速学习系列】SpringMVC的使用、传递参数(request、session、对象、集合…)及显示风格 SpringMVC扮演的角色就相当于Servlet的角色 Spring MVC框架特点 清晰地角色划分 灵活的配置功能 提供了大量的控制器接口和实现类 真正做到与View层的实现无关&…