【深度学习|基础算法】2.AlexNet学习记录

news2024/12/24 10:28:28

AlexNet示例代码与解析

  • 1、前言
  • 2、模型tips
  • 3、模型架构
  • 4、模型代码
    • backbone
    • train
    • predict
  • 5、模型训练
  • 6、导出onnx模型

1、前言

AlexNet由Hinton和他的学生Alex Krizhevsky设计,模型名字来源于论文第一作者的姓名Alex。该模型以很大的优势获得了2012年ISLVRC竞赛的冠军网络,分类准确率由传统的 70%+提升到 80%+,自那年之后,深度学习开始迅速发展。
ImageNet是一个在2009年创建的图像数据集,从2010年开始到2017年举办了七届的ImageNet 挑战赛——ImageNet Large Scale Visual Recognition ChallengeI (LSVRC),在这个挑战赛上诞生了AlexNet、ZFNet、OverFeat、VGG、Inception、ResNet、WideResNet、FractalNet、DenseNet、ResNeXt、DPN、SENet 等经典模型。
摘录:CNN经典网络模型(二):AlexNet简介及代码实现(PyTorch超详细注释版)

2、模型tips

  • 使用了多GPU训练,当时的硬件资源有限,一块显卡的显存并不能满足AlexNet的训练,因此作者将其分成了两部分,每一块显卡负责一部分的特征图,最后在全连接层的时候,将每块显卡提取的特征拼接成一个,当时使用了分组卷积来完成这个需求,后来证实了分组卷积能够达到普通卷积的精度。
  • 使用了ReLu作为激活函数来训练模型。
  • 使用了局部响应归一化来对网络层进行归一化,目的是抑制反馈较小的神经元的值,增大反馈明显的神经元的值。(在VGG的论文中指出,LRN并灭有什么明显的效果,新的深度学习网络中已使用其他归一化方法来代替LRN)。
  • 使用了覆盖池化,覆盖池化的意思即当池化的步长小于池化核时,相邻的池化核之间会互相重叠。论文中指出这种池化方式可以缓解过拟合。
  • 使用了dropout来缓解过拟合。dropout即在训练的过程中随机的让一些隐层中的节点置为0(在本轮训练中不参与前向传播与反向传播),因此,在每一轮训练的时候,模型都会随机的得到一个与上一论训练中不太一样的网络架构,这样的做法可以降低神经元之间的依赖性(耦合性),使每个神经元能够在一次次的训练中学习到更为可靠的特征。尽管dropout会降低训练收敛的速度,但是可以有效的缓解过拟合程度。

3、模型架构

在这里插入图片描述

4、模型代码

我们将使用开源的深度学习框架PyTorch来搭建并训练我们的模型

backbone

import torch
import torchvision
from torch import nn

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        #特征提取层
        self.CONV = nn.Sequential(
            nn.Conv2d(3, 96, 11, 4, 2),     # 1 * 224 * 224 * 3 ---> 1 * 55 * 55 * 96
            nn.ReLU(),
            nn.MaxPool2d(3, 2),             # 1 * 55 * 55 * 96 ---> 1 * 27 * 27 * 96

            nn.Conv2d(96, 256, 5, 1, 2),    # 1 * 27 * 27 * 96 ---> 1 * 27 * 27 * 256
            nn.ReLU(),
            nn.MaxPool2d(3, 2),             # 1 * 27 * 27 * 256 ---> 1 * 13 * 13 * 256

            nn.Conv2d(256, 384, 3, 1, 1),   # 1 * 13 * 13 * 256 ---> 1 * 13 * 13 * 384
            nn.ReLU(),

            nn.Conv2d(384, 384, 3, 1, 1),   # 1 * 13 * 13 * 384---> 1 * 13 * 13 * 384
            nn.ReLU(),

            nn.Conv2d(384, 256, 3, 1, 1),   # 1 * 13 * 13 * 384 ---> 1 * 13 * 13 * 256
            nn.ReLU(),
            nn.MaxPool2d(3, 2),             # 1 * 13 * 13 * 256 ---> 1 * 6 * 6 * 256
        )

        #将多维的张量进行平坦化处理
        #默认从第一个维度到最后一个维度拼接
        self.flatten = nn.Flatten()         # 1 * 6 * 6 * 256 ---> 1 * 9216

        #全连接层
        self.FC = nn.Sequential(
            # 全连接层1
            nn.Linear(in_features=6 * 6 * 256, out_features=4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 全连接层2
            nn.Linear(in_features=4096, out_features=4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 全连接层3
            nn.Linear(in_features=4096, out_features=1000),
            nn.Dropout(0.5),
            # 全连接层4 分类层,几分类就是降维到几
            nn.Linear(in_features=1000, out_features=10),
        )

    def forward(self, x):
        x = self.CONV(x)
        x = self.flatten(x)
        x = self.FC(x)
        return x

if __name__ == "__main__":
    x = torch.randn([1,3,224,224])
    model = AlexNet()
    y = model(x)
    print(x)

注意这里的输入是224 * 224的宽高,有的输入是227 * 227的宽高,可以根据不同的输入来计算对应的卷积与池化的参数,对最终的结果几乎没有影响。

搭建模型时用到的torch库的api:
nn.Sequential(): 可以允许将整个容器视为单个模块(即相当于把多个模块封装成一个模块),forward()方法接收输入之后,nn.Sequential()按照内部模块的顺序自动依次计算并输出结果。
nn.Conv2d():in_channel,out_channel,kernel_size,stride,padding。
nn.ReLu():ReLu激活函数。
nn.MaxPool2dkernel_size,stride。
nn.Flatten():将张量扁平化处理,默认从第一个维度到最后一个维度的所有信息进行一维处理。start_dim=1,end_dim=-1。
nn.Linear():线性层,或者叫全连接层。in_features,out_features,is_bias(bool)。
nn.Dropout():dropout方法,随机失活神经元节点。p(失活节点的占比),in_place(是否改变输入数据),dropout只在训练阶段开启,在推理阶段不开启。

train

import torch
import torch.nn as nn
from AlexNet import AlexNet
from torch.optim import lr_scheduler
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import os
import matplotlib.pyplot as plt

# 解决中文显示问题
# 运行配置参数中的字体(font)为黑体(SimHei)
plt.rcParams['font.sans-serif'] = ['simHei']
# 运行配置参数总的轴(axes)正常显示正负号(minus)
plt.rcParams['axes.unicode_minus'] = False

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

ROOT_TRAIN = 'dataset'
ROOT_TEST = 'dataset'

normalize = transforms.Normalize(
    [0.5, 0.5, 0.5],
    [0.5, 0.5, 0.5]
)

train_transform = transforms.Compose([
    transforms.Resize((224, 224)),
    #以0.5的概率来竖直翻转给定的PIL图像
    transforms.RandomVerticalFlip(),
    transforms.ToTensor(),
    normalize,
])

val_transform = transforms.Compose([
    transforms.Resize((224,224)),
    transforms.ToTensor(),
    normalize,
])

#加载训练数据集
train_datasets = datasets.ImageFolder(ROOT_TRAIN, transform=train_transform)
train_dataloader = DataLoader(train_datasets, batch_size=32, shuffle=True)

val_datasets = datasets.ImageFolder(ROOT_TEST, transform=val_transform)
val_dataloader = DataLoader(val_datasets, batch_size=32, shuffle=True)

#实例化模型对象
model = AlexNet().to(device)

#定义交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()

#定义优化器
optimizer_ = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

#学习率每十轮降低为之前的0.5
lr_scheduler = lr_scheduler.StepLR(optimizer_, step_size=10, gamma=0.5)

#定义训练函数
def train(dataloader, model, loss_fn, optimizer):
    loss, current, n = 0.0, 0.0, 0.0
    #batch为索引, x和y分别是图片和类别
    for batch, (x, y) in enumerate(dataloader):
        #前向传播
        image, y = x.to(device), y.to(device)
        output = model(image)
        curr_loss = loss_fn(output, y)
        _, pred = torch.max(output, dim=1)
        #计算每个批次的准确率
        curr_acc = torch.sum(y == pred)/output.shape[0]

        #反向传播
        #清空之前的梯度
        optimizer.zero_grad()
        #计算当前的梯度
        curr_loss.backward()
        #根据梯度更新网络参数
        optimizer.step()

        #损失叠加
        loss += curr_loss.item()
        #精度叠加
        current += curr_acc.item()
        n = n + 1

    #训练的平均损失和平均精度
    train_loss = loss / n
    train_acc = current / n
    print('train loss = ' + str(train_loss))
    print('train accuracy = ' + str(train_acc))
    return train_loss, train_acc

#定义验证函数
def val(dataloader, model, loss_fn):
    loss, current, n = 0.0, 0.0, 0.0
    #eval():如果模型中存在BN和dropout则不启用,以防改变权值
    model.eval()
    with torch.no_grad():
        for batch, (x, y) in enumerate(dataloader):
            #前向传播
            image, y = x.to(device), y.to(device)
            output = model(image)
            curr_loss = loss_fn(output, y)
            _, pred = torch.max(output, dim=1)
            curr_acc = torch.sum(y == pred) / output.shape[0]
            loss += curr_loss.item()
            current += curr_acc.item()
            n = n + 1

    val_loss = loss / n
    val_acc = current / n
    print('val loss = ' + str(val_loss))
    print('val accuracy = ' + str(val_acc))
    return val_loss, val_acc

#定义画图函数
def plot_loss(train_loss, val_loss):
    plt.plot(train_loss, label='train loss')
    plt.plot(val_loss, label='val loss')

    plt.legend(loc='best')
    plt.xlabel('loss')
    plt.ylabel('epoch')
    plt.title("训练集和验证集的loss值对比图")
    plt.show()

def plot_acc(train_acc, val_acc):
    plt.plot(train_acc, label='train acc')
    plt.plot(val_acc, label='val acc')

    plt.legend(loc='best')
    plt.xlabel('acc')
    plt.ylabel('epoch')
    plt.title("训练集和验证集的acc值对比图")
    plt.show()

#开始训练
loss_train = []
acc_train = []
loss_val = []
acc_val = []

#训练次数
epoch = 200
#用于判断什么时候保存模型
min_acc = 0
for t in range(epoch):
    # lr_scheduler.step()
    print(f"epoch{t+1}-------------------------------")
    #训练模型
    train_loss, train_acc = train(train_dataloader, model, loss_fn, optimizer_)
    #验证模型
    val_loss, val_acc = val(val_dataloader, model, loss_fn)
    print("\n")
    loss_train.append(train_loss)
    acc_train.append(train_acc)
    loss_val.append(val_loss)
    acc_val.append(val_acc)
    folder = 'save_model'

    # 保存最好的模型权重
    if val_acc > min_acc:
        if not os.path.exists(folder):
            os.mkdir(folder)
        min_acc = val_acc
        torch.save(model.state_dict(), f"{folder}/model_best.pth")

    if t == epoch - 1:
        torch.save(model.state_dict(), f"{folder}/model_last.pth")
        print("=============训练完毕==============\n" + f"best pth saved as {folder}/model_best.pth\n" + f"last pth saved as {folder}/model_last.pth\n")

plot_loss(loss_train, loss_val)
plot_acc(acc_train, acc_val)

predict

import torch
from AlexNet import AlexNet
from torch.autograd import Variable
from torchvision import transforms
from torchvision.transforms import ToPILImage
from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader

# ROOT_TRAIN = 'D:/pycharm/AlexNet/data/train'
ROOT_TEST = 'dataset'

# 将图像的像素值归一化到[-1,1]之间
normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])

val_transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    normalize
])

# 加载训练数据集
val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)

# 如果有NVIDA显卡,转到GPU训练,否则用CPU
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 模型实例化,将模型转到device
model = AlexNet().to(device)

# 加载train.py里训练好的模型
model.load_state_dict(torch.load(r'save_model/model_best.pth'))

# 结果类型
classes = [
    "cat",
    "dog"
]

# 把Tensor转化为图片,方便可视化
show = ToPILImage()

# 进入验证阶段
model.eval()
for i in range(10):
    x, y = val_dataset[i][0], val_dataset[i][1]
    # show():显示图片
    show(x).show()
    # torch.unsqueeze(input, dim),input(Tensor):输入张量,dim (int):插入维度的索引,最终扩展张量维度为4维
    x = Variable(torch.unsqueeze(x, dim=0).float(), requires_grad=False).to(device)
    with torch.no_grad():
        pred = model(x)
        # argmax(input):返回指定维度最大值的序号
        # 得到预测类别中最高的那一类,再把最高的这一类对应classes中的那一类
        predicted, actual = classes[torch.argmax(pred[0])], classes[y]
        # 输出预测值与真实值
        print(f'predicted:"{predicted}", actual:"{actual}"')

5、模型训练

猫狗训练集训练二分类模型,生成pth模型。

在这里插入图片描述

在这里插入图片描述

6、导出onnx模型

from AlexNet import AlexNet
import torch
import onnx
import os

def export_onnx(pt_path:str, onnx_path:str):
    model = AlexNet()

    model.load_state_dict(torch.load(pt_path))

    dummy_inputs = {
        "input": torch.randn(1, 3, 224, 224, dtype=torch.float),
    }

    output_names = {
        "classes"
    }

    if not os.path.exists(os.path.dirname(onnx_path)):
        os.makedirs(os.path.dirname(onnx_path))

    with open(onnx_path, "wb") as f:
        print(f"Exporting onnx model to {onnx_path}...")
        torch.onnx.export(
            model,
            tuple(dummy_inputs.values()),
            f,
            export_params=True,
            verbose=False,
            opset_version=17,
            do_constant_folding=True,
            input_names=list(dummy_inputs.keys()),
            output_names=output_names,
            # dynamic_axes=dynamic_axes,
        )

if __name__ == "__main__":
    pt_path = "save_model/model_best.pth"
    onnx_path = "save_model/model_best.onnx"
    export_onnx(pt_path, onnx_path)

onnx模型可视化架构图:

在这里插入图片描述

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

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

相关文章

循环神经网络之序列模型

自回归模型 自回归模型: 只与x 有关 ,对自己执行回归隐变量自回归:与X 和过去观测总结h 都有关 案例 %matplotlib inline import torch from torch import nn from d2l import torch as d2lT 1000 # 总共产生1000个点 time torch.aran…

【深度学习基础(4)】pytorch 里的log_softmax, nll_loss, cross_entropy的关系

一、常用的函数有: log_softmax,nll_loss, cross_entropy 1.log_softmax log_softmax就是log和softmax合并在一起执行,log_softmaxlogsoftmax 2. nll_loss nll_loss函数全称是negative log likelihood loss, 函数表达式为:f(x,class)−x[…

备考ICA----Istio实验11---为多个主机配置TLS Istio Ingress Gateway实验

备考ICA----Istio实验11—为多个主机配置TLS Istio Ingress Gateway实验 1. 部署应用 kubectl apply -f istio/samples/helloworld/helloworld.yaml -l servicehelloworld kubectl apply -f istio/samples/helloworld/helloworld.yaml -l versionv12. 证书准备 接上一个实验…

Day23:事务管理、显示评论、添加评论

事务管理 事务的定义 什么是事务 事务是由N步数据库操作序列组成的逻辑执行单元,这系列操作要么全执行,要么全放弃执行。 事务的特性(ACID) 原子性(Atomicity):事务是应用中不可再分的最小执行体(事务中部分执行失败就会回滚 。一致性(C…

开源大数据集群部署(十八)Hive 安装部署

作者:櫰木 1 创建hive Kerberos主体 bash /root/bigdata/getkeytabs.sh /etc/security/keytab/hive.keytab hive2 安装 在hd1.dtstack.com主机root权限下操作: 解压包 [roothd3.dtstack.com software]# tar -zxvf apache-hive-3.1.2-bin.tar.gz -C …

树与二叉树的应用试题解析

01.在有n个叶结点的哈夫曼树中,非叶结点的总数是( A ). A. n-1 B. n C. 2n-1 D.2n 02.给定整数集合{3,5,6,9,12},与之对应的哈夫曼树是( D…

设计模式——行为型——策略模式Strategy

Q:策略模式的特点 A: 具体算法从具体的业务方法中独立出来策略模式是同行为的不同实现 Q:什么时候使用策略模式 A:多个if-else使用策略模式 收费对象类 public class CashContext {private CashStrategy cashStrategy;public…

iphoneX系统的参数

1. 2. 3. 4. 5.相关的网址信息 Apple iPhone X 規格、价格和评论 | Kalvo Apple iPhone X 規格、价格和评论 | Kalvo

Apache Hive的基本使用语法

一、数据库操作 创建数据库 create database if not exists myhive;查看数据库 use myhive; desc database myhive;创建数据库并指定hdfs存储 create database myhive2 location /myhive2;删除空数据库(如果有表会报错) drop database myhive;…

【二叉树】Leetcode 102. 二叉树的层序遍历【中等】

二叉树的层序遍历 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点) 示例1: 输入:root [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]] 解题思路…

LabVIEW无人机大气数据智能测试系统

LabVIEW无人机大气数据智能测试系统 随着无人机技术的迅速发展,大气数据计算机作为重要的机载设备,在确保飞行安全性方面发挥着重要作用。设计了一套基于LabVIEW的无人机大气数据智能测试系统,通过高效、稳定的性能测试,及时发现…

Chakra UI:重塑React组件开发的未来

随着前端开发技术的不断演进,React已经成为了一个不可或缺的开源JavaScript库,用于构建用户界面。然而,虽然React提供了构建用户界面的强大工具,但在组件的可访问性、可重复使用性和可组合性方面仍存在挑战。Chakra UI正是一个为解…

数据处理库Pandas的数据结构Series

Series是一种一维数据结构,每个元素都带有一个索引,与一维数组的含义相似,其中索引可以为数字或字符串,如图3-1所示。 Series 对象包含两个主要的属性:index 和 values,分别为上例中的左右两列。因为传给构…

春秋云境CVE-2022-23880

简介 taoCMS v3.0.2 文件管理处存在任意文件上传漏洞,攻击者可执行任意代码 正文 首先进入靶场,我们发现在首页底部有个管理界面,那么就直接点进去进入后台。 找到后台 找到后台,尝试弱口令,发现不成功&#xff0c…

Zookeeper的系统架构

先看一张图: ZooKeeper 的架构图中我们需要了解和掌握的主要有: 1: ZooKeeper分为服务器端(Server) 和客户端(Client),客户端可以连接到整个ZooKeeper服务的任意服务器上&#xff…

Jenkins安装配置部署

Jenkins安装配置部署 一、什么是CI/CD 1.CI(Continuous integration) 中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了 新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码…

第3章:角色提示,强化Chatgpt输出新篇章!

角色提示技术 角色提示技术(role prompting technique),是通过模型扮演特定角色来产出文本的一种方法。用户为模型设定一个明确的角色,它就能更精准地生成符合特定上下文或听众需求的内容。 比如,想生成客户服务的回复…

未来制造:机器人行业新质生产力提升策略

机器人行业新质生产力提升咨询方案 一、机器人行业目前发展现状及特点: 创新活跃、应用广泛、成长性强。 二、机器人企业发展新质生产力面临的痛点: 1、高端人才匮乏 2、核心技术受限 3、竞争日益国际化 4、成本控制挑战 5、用户体验提升需求 三…

Flink on Kubernetes (flink-operator) 部署Flink

flink on k8s 官网 https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-release-1.1/docs/try-flink-kubernetes-operator/quick-start/ 我的部署脚本和官网不一样,有些地方官网不够详细 部署k8s集群 注意,按照默认配置至少有两台wo…

【C++】STL 标准模板库

前言 在前一章种我们介绍了C中的模板的使用,这是一种泛型编程,模板的使用能让我们减少大量的相似代码,减少我们的代码量与工作量,写出更加高效简洁的代码,模板如此好用,但还是要我们先出写一个泛型类或函数…