当前位置: 首页 > news >正文

pytorch学习-11卷积神经网络(高级篇)

2.线性模型

3.梯度下降算法

4.反向传播(用pytorch算梯度)

5.用pytorch实现线性回归

6.logistic回归

7.处理多维特征的输入

8.加载数据集

9.多分类问题

10.卷积神经网络(基础篇)

11.卷积神经网络(高级篇)_哔哩哔哩_bilibili

11.1 GoogleNet

        GoogleNet其创新的Inception模块而闻名,这种模块允许网络在同一层次中进行不同尺寸的卷积操作,从而捕捉不同尺度的特征。

11.1.2 Inception模块

        它的主要思想是在同一层次中使用不同大小的卷积核进行特征提取,从而能够捕捉不同尺度的特征。设计神经网络时以模块为单位去组装整个网络结构,在神经网络中多次重复使用该模块,因此将其封装为类,来减少代码量。该模块构成如下图所示:

 

11.1.3 1*1convolution

        1x1卷积是一种在卷积神经网络中使用的特殊类型的卷积操作。它的主要作用是调整特征图的维度(即通道数),同时保持特征图的空间尺寸(高度和宽度),此外,它还能跨通道的特征整合(不同通道的卷积结果最后求和)。例如,数据集为3*3*3经过3*1*1的卷积操作后,输出结果为1*3*3,如下图所示:

 

        1x1卷积的计算量相对较小,因为卷积核的大小为1x1,只需要进行简单的点乘和加法操作。这使得1x1卷积在深层网络中非常有用,可以作为其他卷积操作的降维或升维层,提高整体网络的计算效率。如下图所示:经过1*1卷积后下方操作次数减少许多

 

11.1.4 Inception模块的实现

课上的Inception模块结构如下: 

  • 平均池化路径
    • 3x3平均池化。
    • 1x1卷积降维。
  • 1x1卷积:用于降维。
  • 5x5卷积路径
    • 1x1卷积降维。
    • 5x5卷积提取特征。 
  • 3x3卷积路径
    • 1x1卷积降维。
    • 3x3卷积提取特征。
    •  3x3卷积提取特征。

最后再将每条路径所得张量,沿着channel的方向整合成一个张量 

        

         代码演示:

import torch
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt#1.准备数据
#1.1 定义transform
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307),(0.3081))])#1.2 下载数据
trainset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定义dataloader
train_loader = DataLoader(trainset,batch_size=64,shuffle=True)#1.4测试集
testset=datasets.MNIST(root='../dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(testset,batch_size=64,shuffle=False)#2.定义网络#2.1 定义inception模块class Inception(torch.nn.Module):def __init__(self,in_channels):super(Inception,self).__init__()#2.1.1 平均池化路径,所用到的1x1的卷积层self.branch_pool = torch.nn.Conv2d(in_channels,24,kernel_size=1)#输入通道为in_channels,输出通道为24,卷积核大小为1x1#2.1.2 1x1卷积路径,仅用到1x1的卷积层self.branch1x1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#输入通道为in_channels,输出通道为16,卷积核大小为1x1#2.1.3 5x5卷积路径 ,用到1X1和5x5的卷积层self.branch5x5_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#输入通道为in_channels,输出通道为16,卷积核大小为1x1self.branch5x5_2 = torch.nn.Conv2d(16,24,kernel_size=5,padding=2)#输入通道为16,输出通道为24,卷积核大小为5x5,padding为2(保证输出尺寸不变)#2.1.4 3x3卷积路径,用到1x1、3x3的卷积层、3x3的卷积层self.branch3x3_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#输入通道为in_channels,输出通道为16,卷积核大小为1x1self.branch3x3_2 = torch.nn.Conv2d(16,24,kernel_size=3,padding=1)#输入通道为16,输出通道为24,卷积核大小为3x3,padding为1(保证输出尺寸不变)self.branch3x3_3 = torch.nn.Conv2d(24,24,kernel_size=3,padding=1)#输入通道为24,输出通道为24,卷积核大小为3x3,padding为1(保证输出尺寸不变)def forward(self,x):#2.1.1 平均池化路径,先经过平均池化,再经过1x1卷积branch_pool=F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)#输入为x,池化核大小为3x3,步长为1,padding为1branch_pool=self.branch_pool(branch_pool)#输入为branch_pool,卷积核大小为1x1,输出通道为24#2.1.2 1x1卷积路径,直接经过1x1卷积branch1x1=self.branch1x1(x)#输入为x,卷积核大小为1x1,输出通道为16#2.1.3 5x5卷积路径,先经过1x1卷积,再经过5x5卷积branch5x5=self.branch5x5_1(x)#输入为x,卷积核大小为1x1,输出通道为16branch5x5=self.branch5x5_2(branch5x5)#输入为branch5x5,卷积核大小为5x5,输出通道为24,padding为2#2.1.4 3x3卷积路径,先经过1x1卷积,再经过3x3卷积,再经过3x3卷积branch3x3=self.branch3x3_1(x)#输入为x,卷积核大小为1x1,输出通道为16branch3x3=self.branch3x3_2(branch3x3)#输入为branch3x3,卷积核大小为3x3,输出通道为24,padding为1branch3x3=self.branch3x3_3(branch3x3)#输入为branch3x3,卷积核大小为3x3,输出通道为24,padding为1#2.1.5 将所有路径的输出拼接起来outputs=[branch_pool,branch1x1,branch5x5,branch3x3]return torch.cat(outputs,dim=1)#将outputs中的元素沿着dim=1方向(即通道维度)拼接起来,输出为(batch_size,88,28,28)#2.2 定义网络结构
class Net(torch.nn.Module):def __init__(self):super(Net,self).__init__()self.conv1=torch.nn.Conv2d(1,10,kernel_size=5)self.conv2=torch.nn.Conv2d(88,20,kernel_size=5)self.inception1=Inception(in_channels=10)self.inception2=Inception(in_channels=20)self.maxpool=torch.nn.MaxPool2d(2)self.fc1=torch.nn.Linear(88*4*4,10)def forward(self,x):#获取batch_sizein_size=x.size(0)x=F.relu(self.maxpool(self.conv1(x)))x=self.inception1(x)x=F.relu(self.maxpool(self.conv2(x)))x=self.inception2(x)x=x.view(in_size,-1)x=self.fc1(x)return xmodel=Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)#3.定义损失函数和优化器
criterion=torch.nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)#4.训练网络
#4.1 训练函数
def train(epoch):running_loss=0.0for i,data in enumerate(train_loader,0):inputs,labels=datainputs,labels=inputs.to(device),labels.to(device)optimizer.zero_grad()#forward + backward + updateoutputs=model(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()running_loss+=loss.item()if i%300==299:print('[%d, %5d] loss: %.3f' %(epoch+1,i+1,running_loss/300))running_loss=0.0#4.2 测试函数
acuracy_list=[]
def Net_test():correct=0total=0with torch.no_grad():for data in test_loader:inputs,targets=datainputs,targets=inputs.to(device),targets.to(device)outputs=model(inputs)_,predicted=torch.max(outputs.data,1)total+=targets.size(0)correct+=predicted.eq(targets.data).sum().item()print('Accuracy of the network  test : %.2f %%' % (100.0*correct/total))acuracy_list.append(100.0*correct/total)#4.开始训练
for epoch in range(10):train(epoch)Net_test()#5.绘制准确率变化图
epochs=list(range(len(acuracy_list)))
plt.plot(epochs,acuracy_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy of the network')
plt.show()

        运行结果:

 

11.2  ResidualNet(ResNet)

11.2.1深度带来的问题

  • 一是vanishing/exploding gradient,导致了训练十分难收敛,这类问题能够通过normalized initialization 和intermediate normalization layers解决;
  • 另一个是被称为degradation的退化现象。对合适的深度模型继续增加层数,模型准确率会下滑(不是overfit造成),training error和test error都会很高,相应的现象在CIFAR-10和ImageNet都有出现。

        当梯度小于1时,由于backword()求梯度时遵循链式法则,致使梯度相乘后不断减小最终出现梯度消失,影响所求权重(W^{`}=W-\alpha G ),使得训练不充分,最终导致准确率下降。下图为深度增加而导致错误率增大

11.2.2 残差结构


        普通直连的卷积神经网络和 ResNet 的最大区别在于,ResNet 有很多旁路的支线将输入直接连到后面的层,使得后面的层可以直接学习残差,这种结构也被称shortcut connections

        传统的卷积层或全连接层在信息传递时,或多或少会存在信息丢失、损耗等问题。ResNet 在某种程度上解决了这个问题,通过直接输入信息绕道传到输出,保护信息的完整性,整个网络则只需要学习输入、输出差别的那一部分,简化学习目标和难度。注意:实线部分是深度未发生变化的连接,虚线部分是深度发生变化的连接。 对应深度有变化的连接有两种解决方案: 

  • 使用 zero-pading 进行提升深度 parameter-free。
  • 使用 1*1的卷积核提升维度 有卷积核的运算时间。

        两种方法,使用下面一种方法效果更好,但是运行会更耗时,一般还是更倾向于第一种方案节约运算成本。

 

11.2.3  残差块

在正常的神经网络中就是一层连一层,如下图所示:

        假定某段神经网络的输入是 x,期望输出是 H(x),即 H(x) 是期望的复杂潜在映射,但学习难度大;如果我们直接把输入 x 传到输出作为初始结果,通过下图“shortcut connections”,那么此时我们需要学习的目标就是 F(x)=H(x)-x,于是 ResNet 相当于将学习目标改变了,不再是学习一个完整的输出,而是最优解 H(X) 全等映射 x 的差值,即残差 F(x) = H(x) - x

        此时,梯度的计算公式\frac{\partial ( H(x))}{x}= \frac{\partial ( F(x))}{x}+1,确保梯度大于等于1,就不会造成梯度消失。

 11.2.4 ResNet 结构

Residual Block 实现

值得注意的是,我们需要输入通道和输出通道一致

第一层中先做卷积在做relu(conv1(x)),第二层中做卷积conv2(y),最后返回relu(x+y)

        代码演示:

import torch
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt#1.准备数据
#1.1 定义transform
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307),(0.3081))])#1.2 下载数据
trainset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定义dataloader
train_loader = DataLoader(trainset,batch_size=64,shuffle=True)#1.4测试集
testset=datasets.MNIST(root='../dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(testset,batch_size=64,shuffle=False)#2.定义网络
#2.1 定义残差块
class ResidualBlock(torch.nn.Module):def __init__(self, channels):super(ResidualBlock, self).__init__()self.channels = channelsself.conv1 =torch.nn.Conv2d(channels, channels,kernel_size=3, padding=1)self.conv2 = torch.nn.Conv2d(channels, channels,kernel_size=3, padding=1)def forward(self, x):y = F.relu(self.conv1(x))y = self.conv2(y)return F.relu(x + y)# 注:这里的x + y是残差单元的核心,即残差单元的输出等于输入与残差单元输出的和,# 其中残差单元输出经过两次卷积后与输入相加,再经过激活函数ReLU。#2.2 定义网络结构
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = torch.nn.Conv2d(1, 16, kernel_size=5)self.conv2 = torch.nn.Conv2d(16, 32, kernel_size=5)self.mp = torch.nn.MaxPool2d(2)self.rblock1 = ResidualBlock(16)self.rblock2 = ResidualBlock(32)self.fc =torch.nn.Linear(512, 10)def forward(self, x):in_size = x.size(0)x = self.mp(F.relu(self.conv1(x)))x = self.rblock1(x)x = self.mp(F.relu(self.conv2(x)))x = self.rblock2(x)x = x.view(in_size, -1)x = self.fc(x)return xmodel=Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)#3.定义损失函数和优化器
criterion=torch.nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)#4.训练网络
#4.1 训练函数
def train(epoch):running_loss=0.0for i,data in enumerate(train_loader,0):inputs,labels=datainputs,labels=inputs.to(device),labels.to(device)optimizer.zero_grad()#forward + backward + updateoutputs=model(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()running_loss+=loss.item()if i%300==299:print('[%d, %5d] loss: %.3f' %(epoch+1,i+1,running_loss/300))running_loss=0.0#4.2 测试函数
acuracy_list=[]
def Net_test():correct=0total=0with torch.no_grad():for data in test_loader:inputs,targets=datainputs,targets=inputs.to(device),targets.to(device)outputs=model(inputs)_,predicted=torch.max(outputs.data,1)total+=targets.size(0)correct+=predicted.eq(targets.data).sum().item()print('Accuracy of the network  test : %.2f %%' % (100.0*correct/total))acuracy_list.append(100.0*correct/total)#4.开始训练
for epoch in range(10):train(epoch)Net_test()#5.绘制准确率变化图
epochs=list(range(len(acuracy_list)))
plt.plot(epochs,acuracy_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy of the network')
plt.show()

        运行结果:

 

http://www.lryc.cn/news/581313.html

相关文章:

  • VS Code中使用Git的方法:环境配置与Git操作
  • JavaFX:观察者集合(Observable Collections)的监听事件处理
  • 业务快速接入OSS对象存储和文件上传下载SDK对接
  • VMware 17安装Centos8.5虚拟机
  • Bootstrap 5学习教程,从入门到精通,Bootstrap 5 表单验证语法知识点及案例代码(34)
  • 1. 两数之和 (leetcode)
  • Delta、Jackknife、Bootstrap
  • FreeCAD傻瓜教程-拉簧拉力弹簧的画法及草图的附着位置设定和Part工作台中形体构建器的妙用
  • Playwright 测试节奏控制指南
  • Node.js worker_threads深入讲解教程
  • Android NDK — 在Linux环境下使用NDK实现交叉编译
  • React Native 亲切的组件们(函数式组件/class组件)和陌生的样式
  • RabbitMQ 4.1.1初体验-队列和交换机
  • 快速掌握Python编程基础
  • 结构型智能科技的关键可行性——信息型智能向结构型智能的转变(修改提纲)
  • 小架构step系列05:Springboot三种运行模式
  • 黑马点评系列问题之基础篇p7 06初识redis无法在虚拟机查到图形化界面存进去的键
  • 运算方法和运算器补充
  • TCP协议概念和特性
  • AI Agent与Agentic AI原理与应用(下) - 主流Agent平台、框架与项目技术拆解
  • 编程中的英语
  • cocos 打包安卓
  • Rust与PyTorch实战:精选示例
  • 机器学习--实践与分析
  • python优先队列使用
  • NAT、代理服务、内网穿透
  • Ubuntu 22.04 修改默认 Python 版本为 Python3 笔记
  • C#使用开源框架NetronLight绘制流程图
  • C++------模板初阶
  • JS 网页全自动翻译v3.17发布,全面接入 GiteeAI 大模型翻译及自动部署