CNN——AlexNet

1.AlexNet概述

论文原文:ImageNet Classification with Deep Convolutional Neural Networks

        在LeNet提出后,卷积神经网络在计算机视觉和机器学习领域中很有名气。但卷积神经网络并没有主导这些领域。这是因为虽然LeNet在小数据集上取得了很好的效果,但是在更大、更真实的数据集上训练卷积神经网络的性能和可行性还有待研究。事实上,在上世纪90年代初到2012年之间的大部分时间里,神经网络往往被其他机器学习方法超越,如支持向量机(support vector machines)。

        虽然上世纪90年代就有了一些神经网络加速卡,但仅靠它们还不足以开发出有大量参数的深层多通道多层卷积神经网络。此外,当时的数据集仍然相对较小。除了这些障碍,训练神经网络的一些关键技巧仍然缺失,包括启发式参数初始化、随机梯度下降的变体、非挤压激活函数和有效的正则化技术。

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

AlexNet和LeNet的设计理念非常相似,但也存在显著差异。

  1. AlexNet比相对较小的LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。

  2. AlexNet使用ReLU而不是sigmoid作为其激活函数。ReLU 能够提高计算速度的同时,有效地解决了梯度消失问题,从而使得训练更加高效。

        3.局部响应归一化(Local response nomalization,LRN)。在后来VGG的论文中发现没什么用,还会增加参数。

        4.重叠池化(Overlapping Pooling)。池化步长小于池化窗口的大小。现在也不再被采用。

        5.在训练阶段全连接层使用了Dropout降低过拟合,每次迭代随机使一半的神经元弃用

Dropout 是一种在神经网络训练过程中常用的正则化技术,通过在神经网络的训练过程中随机丢弃(或者说关闭)一些神经元节点来减少过拟合的发生。

1. 减少过拟合

        Dropout 强制让网络在训练时不能依赖于特定的神经元,因为它们在每次迭代中都有可能被随机丢弃。这样可以降低网络对某些特定特征的依赖性,使得网络更加泛化,从而减少了过拟合的风险。

2. 提升网络的鲁棒性

        通过随机丢弃节点,网络变得更加健壮。它鼓励网络中不同神经元之间学习到更加独立、更具有鲁棒性的特征表示,而不是过度依赖某些特定的神经元。

3. 防止神经元共适应

        神经元之间可能会相互适应,导致它们高度依赖彼此。Dropout 强制网络在训练过程中更加独立地学习,减少了神经元共适应的情况,从而使网络更加健壮。

4. 类似集成多个模型的效果

        每次训练迭代中,Dropout 随机地关闭一些神经元,相当于训练了许多不同的网络结构。最终,这些结构共同贡献了一个集成模型,提高了模型的表现力。

        6.分布式训练。在当时GPU性能并不高,内存比较小,AlexNet在使用GPU进行训练时,可将卷积层和全连接层分别放到不同的GPU上进行并行计算,从而大大加快了训练速度。

        7.数据增强。

                1.从256×256中随机裁剪出224×224再水平翻转。

                2.第二种数据增强方式是改变训练图像中RGB通道的强度。在整个ImageNet训练集中的RGB像素值集合上执行PCA,在每张训练图像中,我们都会添加所主成分的倍数

        整个网络结构图如下,网络结构被切割为两部分,每个GPU单独计算一半的通道数,其中会互相通信三次。

        输入尺寸是227,224是论文中写错了。如果是224,则第一次卷积后特征图尺寸((224-11)/4)+1=54.25会出现小数

        当然从现在的计算资源来看,AlexNet是一个非常简单的神经网络,已经不再需要分到2个GPU上并行计算了,于是网络结构可以简化如下

2.网络结构详解

1.输入层。227 × 227 × 3,三通道RGB图像

2.卷积C1

  1. 卷积。96个11×11×3的卷积核,padding = 0,stride = 4。特征图尺寸为((227-11)/4)+1=55,得到输出55×55×96的特征图
  2. ReLU激活
  3. 最大池化。核大小为3×3,padding = 0,stride = 2,特征图尺寸为((55-3)/2)+1=27,得到输出27×27×96的特征图

3.卷积C2

  1. 卷积。256个5×5×96的卷积核,padding = 2,stride = 1。特征图尺寸为((27-5+2×2)/1)+1=27,得到输出27×27×256的特征图
  2. ReLU激活
  3. 最大池化。核大小为3×3,padding = 0,stride = 2,特征图尺寸为((27-3)/2)+1=13,得到输出13×13×256的特征图

4.卷积C3

  1. 卷积。384个3×3×256的卷积核,padding = 1,stride = 1。特征图尺寸为((13-3+2×1)/1)+1=13,得到输出13×13×384的特征图
  2. ReLU激活

5.卷积C4

  1. 卷积。384个3×3×384的卷积核,padding = 1,stride = 1。特征图尺寸为((13-3+2×1)/1)+1=13,得到输出13×13×384的特征图
  2. ReLU激活

6.卷积C5

  1. 卷积。256个3×3×384的卷积核,padding = 1,stride = 1。特征图尺寸为((13-3+2×1)/1)+1=13,得到输出13×13×256的特征图
  2. ReLU激活
  3. 最大池化。核大小为3×3,padding = 0,stride = 2,特征图尺寸为((13-3)/2)+1=6,得到输出6×6×256的特征图

7.全连接层FC6

  1. 全连接,6×6×256–>>1×1×4096,并使用Dropout,随机50%神经元弃用
  2. ReLU激活

8.全连接层FC7

  1. 全连接,1×1×4096–>>1×1×4096,并使用Dropout,随机50%神经元弃用
  2. ReLU激活

9.全连接层FC8

        全连接softmax,1×1×4096–>>1×1×1000。1000是1000个分类类别

3.AlexNet实现CIFAR-10分类

1.读取数据集

        CIFAR-10数据集是32*32尺寸的,但AlexNet网络结构是针对ImageNet大尺寸设计的,但ImageNet数据集作为简单实践的话又太大了。这里直接简单的将图片拉大,但实际上这并不是一个好的操作,这里只是简单实践,毕竟AlexNet现在并不常使用。

# 数据预处理
transform = transforms.Compose([
    transforms.Resize((227, 227)),  
    transforms.ToTensor(),
    transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])

# 加载CIFAR-10数据集
train_dataset = datasets.CIFAR10(root='./dataset', train=True, download=True, transform=transform)
test_dataset = datasets.CIFAR10(root='./dataset', train=False, download=True, transform=transform)

# 数据加载器
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=64, shuffle=False)

        这个归一化的数据来源于ImageNet数据集百万张统计得到,通常可以作为一般数据集的归一化标准。当然也可以针对自己数据集重新计算均值和标准差用于归一化。

2.搭建AlexNet

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=11, stride=4),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(96, 256, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(256, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )
    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

# 打印模型结构
model = AlexNet().to(device)
summary(model, (3, 227, 227))

                        

3.使用GPU 

device = 'cuda' if torch.cuda.is_available() else 'cpu'

4.模型训练

def train(model, lr, epochs, train_dataloader, device, save_path):
    # 将模型放入GPU
    model = model.to(device)
    # 使用交叉熵损失函数
    loss_fn = nn.CrossEntropyLoss().to(device)
    # SGD
    optimizer = torch.optim.SGD(model.parameters(), lr=lr, weight_decay=5e-4, momentum=0.9)
    # 记录训练与验证数据
    train_losses = []
    train_accuracies = []
    # 开始迭代   
    for epoch in range(epochs):   
        # 切换训练模式
        model.train()  
        # 记录变量
        train_loss = 0.0
        correct_train = 0
        total_train = 0
        # 读取训练数据并使用 tqdm 显示进度条
        for i, (inputs, targets) in tqdm(enumerate(train_dataloader), total=len(train_dataloader), desc=f"Epoch {epoch+1}/{epochs}", unit='batch'):
            # 训练数据移入GPU
            inputs = inputs.to(device)
            targets = targets.to(device)
            # 模型预测
            outputs = model(inputs)
            # 计算损失
            loss = loss_fn(outputs, targets)
            # 梯度清零
            optimizer.zero_grad()
            # 反向传播
            loss.backward()
            # 使用优化器优化参数
            optimizer.step()
            # 记录损失
            train_loss += loss.item()
            # 计算训练正确个数
            _, predicted = torch.max(outputs, 1)
            total_train += targets.size(0)
            correct_train += (predicted == targets).sum().item()
        # 计算训练正确率并记录
        train_loss /= len(train_dataloader)
        train_accuracy = correct_train / total_train
        train_losses.append(train_loss)
        train_accuracies.append(train_accuracy)
        # 输出训练信息
        print(f"Epoch [{epoch + 1}/{epochs}] - Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f}")
    # 绘制损失和正确率曲线
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.plot(range(epochs), train_losses, label='Training Loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend()
    plt.subplot(1, 2, 2)
    plt.plot(range(epochs), train_accuracies, label='Accuracy')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend()
    plt.tight_layout()
    plt.show()
    torch.save(model.state_dict(), save_path)
model = AlexNet(num_classes=10) # 十分类
lr = 0.01 
epochs = 10
save_path = './modelWeight/AlexNet_CIFAR10'
train(model,lr,epochs,train_dataloader,device,save_path)

        这里只训练了10个epoch,也没有使用验证集调参,仅仅是简单实践而已。可以看到损失还在不断降低,还没收敛。

5.模型测试

def test(model, test_dataloader, device, model_path):
    # 将模型设置为评估模式
    model.eval()
    # 将模型移动到指定设备上
    model.to(device)

    # 从给定路径加载模型的状态字典
    model.load_state_dict(torch.load(model_path))

    correct_test = 0
    total_test = 0
    # 不计算梯度
    with torch.no_grad():
        # 遍历测试数据加载器
        for inputs, targets in test_dataloader:  
            # 将输入数据和标签移动到指定设备上
            inputs = inputs.to(device)
            targets = targets.to(device)
            # 模型进行推理
            outputs = model(inputs)
            # 获取预测结果中的最大值
            _, predicted = torch.max(outputs, 1)
            total_test += targets.size(0)
            # 统计预测正确的数量
            correct_test += (predicted == targets).sum().item()
    
    # 计算并打印测试数据的准确率
    test_accuracy = correct_test / total_test
    print(f"Accuracy on Test: {test_accuracy:.4f}")
    return test_accuracy
model_path = './modelWeight/AlexNet_CIFAR10'
test(model, test_dataloader, device, save_path)

6.使用Pytorch自带的AlexNet

        Pytorch有官方实现的AlexNet以及它在ImageNet上预训练好的权重,如果数据集的分类类别都在ImageNet中存在,而且想快速训练,可以使用预训练好的权重。地址:alexnet — Torchvision main documentation (pytorch.org)

        此外还需要修改最后一层全连接层的输出数目

from torchvision import models
# 初始化预训练的AlexNet模型
modelPre = models.alexnet(weights='DEFAULT')
num_ftrs = modelPre.classifier[6].in_features
modelPre.classifier[6] = nn.Linear(num_ftrs, 10)  # CIFAR-10有10个类别
modelPre = modelPre.to(device)
summary(modelPre, (3, 224, 224))

        weights='DEFAULT'就是使用默认最新最好的预训练权重,直接指定weights='IMAGENET1K_V1'也是一样的,因为AlexNet在pytroch中只有一个权重,其他模型会可能有多个版本权重,可以在官方文档中看。如果只想使用他的模型而不使用预训练权重,直接不设定这个参数就可以了。

        Pytorch实现的AlexNet还是有些不同的,一般输入224×224,还使用了全局平均池化支持不同的尺寸输入,AlexNet出来的时候全局平均池化还没被提出。

                        

lr = 0.01 
epochs = 10
save_path = './modelWeight/AlexNetPreTrain_CIFAR10'
train(modelPre,lr,epochs,train_dataloader,device,save_path)

        可以看到收敛更快 

lr = 0.01 
epochs = 10
save_path = './modelWeight/AlexNetPreTrain_CIFAR10'
train(modelPre,lr,epochs,train_dataloader,device,save_path)

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

保姆级教程:从0到1搭建web自动化测试环境

之前都是在linux上安装,第一次在windows上配置环境,加上距离上次配置环境有点久了,竟也花了点时间。特此记录下保姆级教程,给初学者一个有效的参考! 一. 环境搭建 工具清单 工具工具名版本Java开发工具包JDK1.8浏览…

AI边缘计算智能分析网关V4如何配置周界入侵检测算法

旭帆科技的智能分析网关V4内含近40种智能分析算法,包括人体、车辆、消防、环境卫生、异常检测等等,在消防安全、生产安全、行为检测等场景应用十分广泛,如常见的智慧工地、智慧校园、智慧景区、智慧城管等等,还支持抓拍、记录、告…

C++第四天

定义一个Person类,私有成员int age,string &name,定义一个Stu类,包含私有成员double *score,写出两个类的构造函数、析构函数、拷贝构造和拷贝赋值函数,完成对Person的运算符重载(算术运算符、条件运算…

【DevOps-03】Build阶段-Maven安装配置

一、简要说明 下载安装JDK8下载安装Maven二、复制准备一台虚拟机 1、VM虚拟复制克隆一台机器 2、启动刚克隆的虚拟机,修改IP地址 刚刚克隆的虚拟机 ,IP地址和原虚拟的IP地址是一样的,需要修改克隆后的虚拟机IP地址,以免IP地址冲突。 # 编辑修改IP地址 $ vi /etc/sysconfig…

感觉软件测试很简单,但为何这么多劝退的?

上一个说软件测试简单的,已经被面试官问死了。。。 现在已经过了 ”不会但我会学“ 就能感动面试官的时代,随着供需关系的变化,不论是对于面试官还是面试者,面试的成本越来越高。为了筛选到更优秀的程序员,面试官们可谓…

iptables

iptables有多种功能,每一种功能都用一张表来实现 最常用的功能是防火墙和NAT 从RHEL7开始,默认的防火墙为firewalld,但是它的底层仍然调用iptables 安装iptables服务 # 关闭firewalld [rootnode1 ~]# systemctl stop firewalld [rootnode…

在Gradle工程中使用checkstyle来规范你的项目

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列专栏目录 [Java项…

深度学习 | 多模态算法

AIGC也就是AI内容生成已经成为新一轮人工智能发展的热点和必然趋势,它使得大规模高质量的创作变得更加容易。 一 、InstructGPT模型 1、GPT系列回顾 chatGPT和InstructGPT都使用了指示学习和基于人工反馈的强化学习来指导模型的训练,不同点仅仅是在采集数…

ECharts配置个性化图表:圆环、立体柱状图

ECharts配置个性化图表:圆环、立体柱状图 圆环图双纵轴多数据面积图折柱混合图3D立体圆环饼图3D立体饼图参考文章 官网调试地址:点击跳转调试 圆环图 效果图: 配置: option {color: [#29BEFF, #A2DC00, #FFC400, #FF7F5C, #C…

c jpeg 编码解码验证数据

1. yuv420p 1616 像素点 384字节全部数据 把上面的384个char从左到右,从上到下的顺序输入文件,就能显示红绿蓝白4个水平条

SwiftUI之深入解析ContentUnavailableView的实战应用

一、基本用法 SwiftUI 引入了新的 ContentUnavailableView 类型,允许在应用程序中展示空状态、错误状态或任何其他内容不可用的状态。那么,如何使用 ContentUnavailableView 引导用户浏览应用程序中的空状态呢?首先看看 ContentUnavailableV…

python中的selenium安装的步骤(浏览器自动化测试框架)

一、前言 我们今天要安装的selenium 就是浏览器自动化测试框架,是一个用于Web应用程序的测试工具,就是模拟用户操作。支持的浏览器包括Chrome,IE,Mozilla Firefox,Safari,Opera等。今天我们以Chrome为例讲…

msvcr120.dll丢失怎样修复,教你msvcr120.dll丢失的解决办法

在使用电脑的过程中出现关于msvcr120.dll丢失的问题,那么出现这样的问题应该怎么解决呢?其实解决的办法也很简单,今天就和大家说说msvcr120.dll丢失怎样修复,同时给大家介绍一些关于msvcr120.dll文件的相关内容,了解ms…

CMake入门教程【核心篇】添加库(add_library)

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「本文的内容」:CMake入门教程 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 1. 基本用法2.STATIC…

python爬虫实现获取招聘信息

使用的python版本: 3.12.1 selenium版本:4.8.0 urllib版本:1.26.18 from selenium import webdriver from selenium.webdriver import ActionChains import timeimport re import xlwt import urllib.parsedef get_html(url):chrome_drive…

将linux的代码上传至gitte,从创建到linux命令详解

目录 1:创建gitte的代码仓库 1:登录gitte网页 https://gitee.com/ 2:点击导航栏的+号 3:点击新建仓库​编辑4:仓库配置 ​编辑5:复制仓库的路径 linux操作系统命令行 1: linux…

Hadoop集群三节点搭建(一)

一、第一台虚拟机准备 确认是可以上网,方便下载文件和工具,使用ping命令测试下 安装工具 net-tool:工具包集合,包含ifconfig等命令,大家可以根据自己需要按需下载 创建普通用户attest,并修改attest用户的密…

MO 2023 年度回顾

PART-ONE 行业态势 随着供需关系的变化,数据库的竞争在经历了 3 年 “百花齐放” 般的发展后,终于在 2023 年进入到了一个相对收拢的阶段。 2023 年,各个数据库厂商间很有默契地在两个方面达成了一致: HTAP 已经成为新一代数据…

YOLO算法入门指南:了解门槛、学习路径及其易学性

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通Golang》…

基于Segformer实现PCB缺陷检测(步骤 + 代码)

导 读 本文主要介绍基于Segformer实现PCB缺陷检测 ,并给出步骤和代码。 背景介绍 PCB缺陷检测是电子制造的一个重要方面。利用Segformer等先进模型不仅可以提高准确性,还可以大大减少检测时间。传统方法涉及手动检查,无法扩展且容易出错…