VGG卷积神经网络实现Cifar10图片分类-Pytorch实战

news2024/9/24 1:25:04

前言

当涉足深度学习,选择合适的框架是至关重要的一步。PyTorch作为三大主流框架之一,以其简单易用的特点,成为初学者们的首选。相比其他框架,PyTorch更像是一门易学的编程语言,让我们专注于实现项目的功能,而无需深陷于底层原理的细节。

就像我们使用汽车时,更重要的是了解如何驾驭,而不是花费过多时间研究轮子是如何制造的。我将以一系列专门针对深度学习框架的文章,逐步深入理论知识和实践操作。但这需要在对深度学习有一定了解后才能进行,现阶段我们的重点是学会如何灵活使用PyTorch工具。深度学习涉及大量数学理论和计算原理,对于初学者来说可能会有些繁琐。然而,只有通过实际操作,我们才能真正理解所写代码在神经网络中的作用。我将努力将知识简化,转化为我们熟悉的内容,让大家能够理解和熟练使用神经网络框架。

如果你发现深度学习看似难以掌握,我将尽力简化知识,将其转化为我们更容易理解的内容。我会确保你能够理解知识并顺利运用到实践中。在后期,我将发布一系列专门解析深度学习框架的文章,但在开始学习之前,我们需要对深度学习的理论知识和实践操作有一定的熟悉度。

作为一个从事数据建模五年的专业人士,我参与了许多数学建模项目,了解各种模型的原理、建模流程和题目分析方法。我希望通过这个专栏让你能够快速掌握各类数学模型、机器学习和深度学习知识,并掌握相应的代码实现。每篇文章都包含实际项目和可运行的代码。我会紧跟各类数模比赛,将最新的思路和代码分享给你,保证你能够高效地学习这些知识。

博主非常期待与你一同探索这个精心打造的专栏,里面充满了丰富的实战项目和可运行的代码,希望你不要错过:专栏链接


一、VGGNet概述

VGGNet(Visual Geometry Group Network)是由牛津大学视觉几何组(Visual Geometry Group)提出的深度卷积神经网络架构,它在2014年的ImageNet图像分类挑战中取得了优异的成绩。VGGNet之所以著名,一方面是因为其简洁而高效的网络结构,另一方面是因为它通过深度堆叠的方式展示了深度卷积神经网络的强大能力。

VGGNet探索了卷积神经网络的深度与其性能之间的关系,成功地构筑了16~19层深的卷积神经网络,证明了增加网络的深度能够在一定程度上影响网络最终的性能,使错误率大幅下降,同时拓展性又很强,迁移到其它图片数据上的泛化性也非常好。到目前为止,VGG仍然被用来提取图像特征。

VGGNet包含两种结构,分别为16层和19层。VGGNet结构中,所有卷积层的kernel都只有3*3。VGGNet中连续使用3组3*3kernel的原因是它与使用1个7*7kernel产生的效果相同,然而更深的网络结构还会学习到更复杂的非线性关系,从而使得模型的效果更好。该操作带来的另一个好处是参数数量的减少,因为对于一个包含了C个kernel的卷积层来说,原来的参数个数为7*7*C,而新的参数个数为3*(3*3*C)。
下图给出了VGG16的具体结构示意图:

 根据VGG16进行具体分析,包含:

  • 13个卷积层(Convolutional Layer)
  • 3个全连接层(Fully connected Layer)
  • 5个池化层(Pool layer)

其中,卷积层和全连接层具有权重系数,因此也被称为权重层,总数目为13+3=16,这即是VGG16中16的来源。

 内存消耗主要来自早期的卷积,而参数量的激增则发生在后期的全连接层。由于采用了大量的卷积层,导致VGGNet的参数数量较大,训练和推理过程需要更多的计算资源。而且参数量较大,需要更多的数据来避免过拟合问题。

二、PyTorch网络搭建

我们参考上述网络结构,利用pytorch进行网络搭建,首先我们可以先搭建输出层,根据我上述提供的每一层具体的parameters搭建即可:

def __init__(self, num_classes=1000):
        super(VGG,self).__init()__
        self.features = self._make_layers()
        self.classifier = nn.Sequential(
            nn.Linear(512*7*7,4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn,Linear(4096,4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096,num_classes)
        )

 接下来我们来搭建卷积和全连接层,可以利用循环帮助我们省去每个步骤繁琐的写层:

        
def _make_layers(self):
    layers = []
    in_clannels = 3
    cfg =[64,64,'M',128,128,'M',256,256,256,'M',512,512,512,'M']
    for v in cfg:
        if v =='M':
            layers +=[nn.MaxPool2d(kernel_size=2,stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels,v,kernel_size)
            layers +=[conv2d,nn.ReLU(inplace=True)]
            in_channels = v
    return nn.Sequential(*layers)

 然后写入每个神经网络必备的传播:

def forward(self, x):
    x = self.features(x)
    x = x.view(x.size(0), -1)
    x = self.classifier(x)
    return x

 总体网络结构为:

VGGNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU(inplace=True)
    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (3): ReLU(inplace=True)
    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (6): ReLU(inplace=True)
    (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (8): ReLU(inplace=True)
    (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (13): ReLU(inplace=True)
    (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (15): ReLU(inplace=True)
    (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (18): ReLU(inplace=True)
    (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (20): ReLU(inplace=True)
    (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (22): ReLU(inplace=True)
    (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (classifier): Sequential(
    (0): Linear(in_features=25088, out_features=4096, bias=True)
    (1): ReLU(inplace=True)
    (2): Dropout(p=0.5, inplace=False)
    (3): Linear(in_features=4096, out_features=4096, bias=True)
    (4): ReLU(inplace=True)
    (5): Dropout(p=0.5, inplace=False)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)

定义损失函数和优化方法:

#定义损失函数和优化方式
criterion = nn.CrossEntropyLoss() #定义损失函数:交叉熵
optimizer = torch.optim.SGD(net.parameters(),lr=0.001,momentum=0.9)#定义优化方法,随机梯度下降

 进行卷积网络训练,这里需要微调一下原来vgg的模型,Cifar10的数据集有10个类别而且图片转换的矩阵需要加入自适应池化层,要一些改进:

import torch.nn as nn

# 设置随机种子以保证实验的可复现性
torch.manual_seed(0)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

class VGGNet(nn.Module):
    def __init__(self, num_classes=10):
        super(VGGNet, self).__init__()
        self.features = self._make_layers()
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(512*7*7,4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096,4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096,num_classes)
        )
        
    def _make_layers(self):
        layers = []
        in_channels = 3
        cfg =[64,64,'M',128,128,'M',256,256,256,'M',512,512,512,'M',512, 512, 512, 'M']
        for v in cfg:
            if v =='M':
                layers +=[nn.MaxPool2d(kernel_size=2,stride=2)]
            else:
                conv2d = nn.Conv2d(in_channels,v,kernel_size=3, padding=1)
                layers +=[conv2d,nn.ReLU(inplace=True)]
                in_channels = v
        return nn.Sequential(*layers)
    
    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x
    

 需要注意到是我们需要初始化网络的权重,不更新权重的话10000张图片和实际不借助算法猜测图片的概率是一致的,我们先不初始化网络的权重进行训练:

for epoch in range(1):
    train_loss=0.0
    for batch_idx,data in enumerate(train_loader,0):
        
        #初始化
        inputs,labels = data #获取数据
        inputs = inputs.to(device)
        labels = labels.to(device)
        
        optimizer.zero_grad() #梯度置0
        #优化过程
        outputs = net(inputs) #将数据输入到网络,得到第一轮网络前向传播的预测结果outputs
        loss = criterion(outputs,labels) #预测结果outputs和labels通过之前定义的交叉熵计算损失
        loss.backward() #误差反向传播
        optimizer.step() #随机梯度下降优化权重
        #查看网络训练状态
        train_loss += loss.item()
        if batch_idx % 2000 == 1 :
            print(batch_idx)
            print('[%d,%5d] loss: %.3f' % (epoch + 1,batch_idx + 1,train_loss / 2000))
            train_loss = 0.0
            
    print('Saving epoch %d model ...'%(epoch + 1))
    state = {
        'net':net.state_dict(),
        'epoch':epoch+1,
    }
    if not os.path.isdir('checkpoint'):
        os.mkdir('checkpoint')
    #torch.save(state,'./checkpoint/cifar10_epoch_%d.ckpt'%(epoch+1))
    
print('Finished Training')

 然后我们去计算整个测试集的预测效果:

#批量计算整个测试集的预测效果
correct= 0
total = 0
with torch.no_grad():
    for data in test_loader:
        images,labels = data
        images = images.to(device)
        labels = labels.to(device)
        outputs = net(images)
        _,predicted = torch.max(outputs.data,1)
        total += labels.size(0)
        correct += (predicted == labels ).sum().item() #当标记的label种类和预测的种类一致时认为正确,并计数
        
print('Accurary of the network on the 10000 test images : %d %%'%(100*correct/total))

 很明显和实际猜测的概率是一模一样的,总共十个类别1/10很正常:

Accurary of the network on the 10000 test images : 10 %

我们需要先进行初始化网络权重在训练:

def initialize_weights(module):
    if isinstance(module, nn.Conv2d):
        nn.init.kaiming_normal_(module.weight, mode='fan_out', nonlinearity='relu')
        if module.bias is not None:
            nn.init.constant_(module.bias, 0)
    elif isinstance(module, nn.Linear):
        nn.init.normal_(module.weight, 0, 0.01)
        nn.init.constant_(module.bias, 0)

之后在训练预测一版:

Accurary of the network on the 10000 test images : 47 %

 效果就十分明显了。


点关注,防走丢,如有纰漏之处,请留言指教,非常感谢

以上就是本期全部内容。我是fanstuck ,有问题大家随时留言讨论 ,我们下期见。

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

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

相关文章

计算机毕业设计选题推荐-springboot 教材管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…

Android项目打包aar(kts)

目录 app build.gradle.kts AndroidManifests 按步骤生成 生成结果 双击查看内容 app build.gradle.kts plugins {id("com.android.application")id("org.jetbrains.kotlin.android")id("kotlin-parcelize")id("kotlin-kapt") …

推荐开源工具带带弟弟ocr_ddddocr_各种验证码都可以识别_滑动_点击_等等---验证码识别工作笔记001

这个很强大了,常见的各种验证码都可以识别,如果你项目上也有需要,比如需要实现系统的自动登录,这个时候就很有用了,这里仅仅给出方案,具体如何用,用的时候在做研究吧,好东西要记录,分享给需要的人.使用的时候 自己去查一下如何使用非常简单. 支持点击的验证码,支持数字验证码就…

基于SSM的生活缴费系统的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

spring boot+ vue位置信息大数据综合管理平台源码

spring boot vue位置信息大数据综合管理平台源码 UWB技术的人员定位系统源码 智慧工厂是产业升级的外在表现形式,利用物联网技术加强信息管理的新模式,人员定位管理通过物联网技术、位置信息大数据的综合处理应用,在智慧工厂人员管理方面具有…

nexus部署私库及上传和拉包处理

部署不在此赘述,部署好后地址为:http://ip:8081/nexus 默认账号和密码:用户名:admin 密码:admin123 nexus里可以配置3种类型的仓库,分别是proxy、hosted、group proxy是远程仓库的代理。比如说在nexus中配置了一个central reposi…

c++视觉处理---霍夫变换

霍夫直线变换的函数 HoughLines 是OpenCV库中用于执行霍夫直线变换的函数。霍夫直线变换用于检测图像中的直线。下面是该函数的基本用法: cv::HoughLines(image, lines, rho, theta, threshold);image: 输入的二值图像,通常是通过边缘检测算法生成的。…

众佰诚:抖音开通橱窗的要求和流程有什么

在当下的社交媒体环境中,抖音作为一款短视频分享平台,已经吸引了大量的用户和商家。其中,抖音橱窗的功能使商家能够以一种更直接和吸引人的方式展示和销售他们的产品。下面,我们将详细介绍一下抖音橱窗的开通要求和流程。 开通要求…

SCI论文高效写作:Citespace、vosviewer和R语言在文献调研与论文撰写中的应用

文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…

Unity中Shader不同灯光类型的支持与区分

文章目录 前言一、在开始之前做一些准备1、在上一篇文章的场景基础上,增加一个Unity默认的球体作为对照组2、创建一个点光源,用来看点光源的影响 对 Unity默认的Shader效果 和 我们实现的Shader效果 之间的不同 二、点光源的适配把上一篇文章中 ForwardB…

16基于otsuf方法的图像分割,程序已调通,可更换自己的图片进行分割,程序具有详细的代码注释,可轻松掌握。基于MATLAB平台,需要直接拍下。

基于otsuf方法的图像分割,程序已调通,可更换自己的图片进行分割,程序具有详细的代码注释,可轻松掌握。基于MATLAB平台,需要直接拍下。 16matlab图像处理图像分割 (xiaohongshu.com)

微宏科技基于 KubeSphere 的微服务架构实践

作者:尹珉,KubeSphere Ambassador、contributor,KubeSphere 社区用户委员会杭州站站长。 公司简介 杭州微宏科技有限公司于 2012 年成立,专注于业务流程管理和自动化(BPM&BPA)软件研发和解决方案供应商。创始团队毕业于浙江大…

three.js学习之vR展厅

目标 1、需要会的知识点three.js的场景,摄像机,渲染器,轨道控制器,坐标轴,场景适配,渲染循环创建立方缓冲几何体、纹理、3d物体 实现:创建立方几何体,纹理贴图镜面反向渲染&#xf…

空转旋转 seurat spatial rotate 图片 翻转 数据结构 对象 seurat的空转数据存储

1seurat 取子集操作 3. 对象操作 ① 通过结构图上的,$符号依次取 ② 两个中括号操作,pbmc[[ ]]。 教程中,pbmc[[percent.MT]]向meta.data添加 percent.MT 这一列。 pbmc[[]],中括号取的是上面结构图中的二级数据名称以上两种方法的区别是&am…

《Unity Shader入门精要》笔记06

基础纹理 单张纹理纹理的属性Alpha SourceWrap ModeFilter Mode 凹凸映射高度纹理法线纹理实践在切线空间下计算在世界空间下计算 Unity中的法线纹理类型Create from Grayscale 渐变纹理遮罩纹理其他遮罩处理 单张纹理 我们通常会使用一张纹理来代替物体的漫反射颜色 Shader …

[SRT]1.协议简介

1.简介 ​ 安全可靠传输协议(Secure Reliable Transport)简称SRT,是一种基于UDT协议的开源互联网传输协议,Haivision和Wowza合作成立SRT联盟,管理和支持SRT协议开源应用的组织,这个组织致力于促进视频流解决方案的互通性&a…

041:mapboxGL移动到到某Layer上,更换鼠标形状

第041个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中通过鼠标hover的方式来更换鼠标形状。 通过mouseenter和mouseleave的方法,经过某个图层上的时候,更换鼠标的形状,从default到pointer。 离开后从pointer到default。 直接复制下面的 vue+mapbox源代码,操…

安信证券携手共议量化行业的赋能发展

9月22日,安信证券上海浦西分公司携手非凸科技、通联数据在上海共同开展“量化私募闭门交流会”,与资方管理人就如何赋能量化私募可持续发展,给出了精彩纷呈的见解与讨论。 安信证券以“打造数字化券商”为目标,加强科技创新与业务…

数据库常见面试题--MySQL

梳理面试过程中数据库相关的常见问题,需要说明的是,这篇文章主要是基于MySQL数据库,其他类型的数据库还请自行参考使用。 数据库概述 为什么使用数据库 1、数据库增删改查更方便 2、提供了事务的能力 本质是更好的管理数据。 数据库体系结…

Android rtmp 低延迟直播方案:简介

Android rtmp 低延迟直播方案:简介 Android RTMP 低延迟直播方案:使用 RTMP 推送至 ZLMediaKit,通过 WebRTC 进行拉流。