pytorch入门学习——网络搭建

目录

1. 网络初学:(即2.5. 定义卷积神经网络)

1.1. 导入torch相关包

1.2. 搭建网络

1.3. 对网络进行实例化 

1.4. 输入输出 

2. 第一个分类任务学习——十个类别进行分类 

2.1. 根据CIFAR-10数据集完成分类任务的操作如下:

2.2. 导包

2.3. 加载数据集 

2.3.1. 定义数据变换格式

2.3.2. 定义数据格式 

2.3.3. 读入批次数据 

2.3.4. 类别名的转换

2.4.  验证数据加载是否成功

2.4.1. 导包

2.4.2. 定义显示函数imshow(),去显示加载器中的图像。

2.4.3. 定义迭代器iter()去读一次迭代数据(4张图,batch_size=4)  

2.5. 定义卷积神经网络 

2.6. 定义损失函数criterion

2.6.1. 定义损失函数

2.6.2. 定义优化器 optimizer

2.7. 训练网络

3.7.1. 定义epoch对数据集遍历几次

3.7.2. 读批次信息

3.7.3. 网络策略学习

3.7.4. 看训练效果

3.7.5. 保存学习参数,下次直接调用模型完成预测

3.8. 测试网络

3.8.1. 先从测试数据集中读取一个批次数据

3.8.2. 加载学习好的权重

3.8.3. 做预测


前提:了解深度学习中的前向传播、反向传播、梯度更新

PyTorch是一个开源的Python机器学习框架,提供了丰富的工具和库,使得构建和训练深度学习模型变得更加简单和高效。

1. 网络初学:(即2.5. 定义卷积神经网络)

W:宽高;F:卷积核大小;P:padding,向图片外面补边,默认为0; S:步长,即该卷积核遍历图片的步长是多少,默认为1

1.1. 导入torch相关包

import torch
import torch.nn as nn
import torch.nn.functional as F

1.2. 搭建网络

pytorch中搭建网络通常用类来管理,同时还需要继承nn.Module这个类。搭建一个网络一般有两个函数:初始化函数、前向传播函数

        1.2.1. 初始化函数:初始化是在实例化时自动执行的一部分,即在初始化函数中放置网络需要初始化的内容,同时还要进行一个多继承(相当于把module中继承的类以及全部类的方法都继承下来供net去使用)的操作,使用super函数实现了多继承。网络搭建的基本模板如下:

class Net(nn.Module): 
    def __init__(self):
        super (Net,self).__init__()

    def forward(self,x)

对于下采样只需要2*2的和,不需要任何参数设置;对于卷积,涉及到输入输出以及很多参数的设置,需要初始化;对于全连接层也需要初始化。 

        1.2.2. forward函数里面要实现前向回归逻辑 ,该网络设计卷积、下采样(最大池化下采样方法)、全连接。

class Net(nn.Module): 
    def __init__(self):
        super (Net,self).__init__()
        #卷积=>第一个参数:输入的通道数;第二个参数:输出的通道数;第三个参数:卷积核大小
        # 32-F+1=28=>F=5
        self.conv1=nn.Conv2d(1,6,5)
        # 14-F+1=10=>F=5
        self.conv2=nn.Conv2d(6,16,5)
        #全连接层=>第一个参数:输入特征的维数大小;第二个参数:输出特征维数大小
        self.fc1=nn.Linear(16*5*5,120)
        self.fc2=nn.Linear(120,84)
        self.fc3=nn.Linear(84,10)
    def forward(self,x)
        #tensor[batch(批次信息),channel(通道数),H,W]
        #卷积操作
        x = self.conv1(x)
        x = F.relu(x)
        #下采样操作
        x = F.max_pool2d(x,(2,2))
        #再一次卷积、下采样
        x = F.max_pool2d(F.relu(self.conv2(x)),2)
        # [1:]是切片数据,切掉了batch信息.展平操作如下
        x = x.view(-1,x.size()[1:].numel())
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

定义一个网络是希望有可学习参数,经过输入数据的训练,让其参数不断更新,梯度下降更新到一个合适值后,再输入,就能进行分类或者预测。

1.3. 对网络进行实例化 

net = Net()
print(net)

1.4. 输入输出 

input = torch.randn(1,1,32,32)
print(input)

out = net(input)
print(out)

其输出是十个参数,即可分类十个类别

2. 第一个分类任务学习——十个类别进行分类 

2.1. 根据CIFAR-10数据集完成分类任务的操作如下:

  • 使用torch自带的torchvision(视觉工具,包含了常用数据集以及数据转化工具等)加载初始化数据集
  • 定义卷积神经网络
  • 定义损失函数,得到损失才能去更新网络的参数
  • 根据训练数据去训练网络
  • 根据测试数据去测试网络

2.2. 导包

import torch
import torchvision
import torchvision.transforms as transforms

2.3. 加载数据集 

Dataset:定义好数据的格式和数据变换形式。Dataset是DataLoader实例化的一个参数。
Dataloader:用iterative(迭代)的方式不断读入批次数据(增加网络效率)。这种数据集主要用于数据大小未知,或者以流的形式的输入,本地文件不固定的情况,需要以迭代的方式来获取样本索引。

两文读懂PyTorch中Dataset与DataLoader(一)打造自己的数据集 - 知乎 (zhihu.com)

2.3.1. 定义数据变换格式

——定义数据加载进来的一个初始化操作(叫做transform):用定义好的transforms工具去进行处理,Compose()相当于把所有要处理的操作给打包起来。

  • 首先进行ToTensor操作。pytorch处理的都是tensor数据,so读入进来的图片格式需要转换成tensor,tensor比普通图片三通道多了一个通道——batch通道。
  • 进行归一化。可加速网络的收敛、防止梯度消失、梯度爆炸等等。(归一化?)
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])

2.3.2. 定义数据格式 

第一个参数:数据集加载到哪里;第二个参数:是否是训练数据;第三个参数:本地是否下载该数据集;第四个参数:做哪些变化。

trainset = torchvision.datasets.CIFAR10(root='./data',train=True,
                                        download=True,transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data',train=False,
                                        download=True,transform=transform)

2.3.3. 读入批次数据 

第一个参数:数据;第二个参数:batch_size,即一次从所有数据中拿多少数据;第三个参数:是否打乱数据;第四个参数:几线程去读取数据,Windows默认0

trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,
                                          shuffle=True,num_workers=0)
testloader = torch.utils.data.DataLoader(trainset,batch_size=4,
                                          shuffle=False,num_workers=0)

2.3.4. 类别名的转换,即字典映射

该数据集读取进来其分类是0(对应airplane)、1(对应automobile)、2 ··· 9,不直观,可进行转换类别名操作。

classes = ('airplane','automobile','bird','cat','deer','dog','frog','horse','ship','truck')

2.4.  验证数据加载是否成功

2.4.1. 导包

import matp1otlib.pyp1ot as plt
import numpy as np

2.4.2. 定义显示函数imshow(),去显示加载器中的图像。

  • 需要反归一化去恢复为正常图片,再将tensor数据(四通道)转换成矩阵数据(numpy格式)以供plt去显示,即img.numpy()。转换后剩余channel、H、W三个通道数据。pytorch: tensor与numpy之间的转换_tensor转化为numpy-CSDN博客
  • tensor显示顺序:tensor[batch,channel,H,W];正常图片显示顺序:[H,W,channel]。so用np.transpose()进行通道转换。
  • 显示图片
def imshow(img):
    img = img/2 + 0.5 #unnormalize,恢复归一化
    npimg = img.numpy() #tensor转numpy
    plt.imshow(np.transpose(npimg,(1,2,0))) #通道顺序转换
    plt.show()

2.4.3. 定义迭代器iter()去读一次迭代数据(4张图,batch_size=4)  

Python迭代器基本方法iter()及其魔法方法__iter__()原理详解_涛涛ALG的博客-CSDN博客

dataiter = iter(trainloader) #定义迭代器
images,labels = dataiter.__next__() #获得图片和标签数据

imshow(torchvision.utils.make_grid(images))

print(labels) #打印标签
print(labels[0],classes[labels[0]]) #打印第一个
print(' '.join(classes[labels[j]] for j in range(4)))

结果: 

2.5. 定义卷积神经网络 

具体操作如目录1. 网络初学:部分

2.6. 定义损失函数criterion

2.6.1. 定义损失函数

criterion = nn.CrossEntropyLoss()

2.6.2. 定义优化器 optimizer

  • 导包
  • 调用包里的SGD,第一个参数:所更新的网络参数,该网络继承nn.Module类,包含net.perameters()方法;第二个参数:学习率;第三个参数:动量
import torch.optim as optim
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)

2.7. 训练网络

3.7.1. 定义epoch对数据集遍历几次

通常用for循环进行管理,去遍历整个数据集,遍历名称通常叫epoch,eopch从0开始,一个epoch代表对整个数据集遍历了一次。代表对整个数据学习2遍,for opoch in range(2)。

3.7.2. 读批次信息

  • enumerate(第一个参数:数据内容即trainloader , 第二个参数:0,即i从0开始记录批次信息)。
  • 读数据。一个trainloader包含图片(inputs)和标签labels()信息,从data中读出来。
  • 读出来后进行梯度清零操作。pytorch中会对梯度信息累加,学习过程中是希望对每一次数据进行更新,so需要清零,清零后才能对网络进行权重更新。

3.7.3. 网络策略学习

前向传播获取网络输出信息,做损失函数计算,做后向传播获取梯度信息去更新、优化(根据SGD策略),让输出结果不断靠近网络真实标签结果。

  • 通过预测值和正确值算损失函数,衡量网络该去哪更新。
  • 后向传播,获得梯度信息做梯度更新

3.7.4. 看训练效果

每次迭代够2000次/轮(根据数据集大小决定)时,让其输出,打印 (当前训练遍历数据是第几轮,显示迭代到第几批次数据,损失函数求平均值)。

for epoch in range(2):
    
    running_loss = 0.0 #running_loss值越低,学习效果越好,损失值越低
    for i,data in enumerate(trainloader,0):
        
        inputs,labels = data
        optimizer.zero_grad() #梯度清零
        
        # forward + loss + backward + optimizer
        outputs = net(inputs) #预测值outputs
        loss = criterion(outputs,labels) #第一个是输入参数,第二个是正确值。算损失函数
        loss.backward() #后向传播
        optimizer.step() #梯度更新
        
        running_loss += loss.item() 
        
        if i % 2000 == 1999:
            print('[%d,%5d] loss:%.3f' % (epoch +1,i+1,running_loss/2000))
            running_loss = 0.0
            
print("Finish")

3.7.5. 保存学习参数,下次直接调用模型完成预测

torch.save() 第一个参数:要保存的梯度,把学习好的参数读取出来net.state_dict();第二个参数:保存路径。

PATH='./cifar_net.pth'
torch.save(net.state_dict(),PATH)

3.8. 测试网络

3.8.1. 先从测试数据集中读取一个批次数据

定义迭代器,获得图片和标签信息,打印。拿该数据集去预测。

# 测试网络部分
dataiter = iter(testloader) #定义迭代器
images,labels = dataiter.__next__() #获得图片和标签数据
imshow(torchvision.utils.make_grid(images)) #把图片拼接起来
#打印标签信息,每个标签长度5个字符大小,一次读4张图so对for循环做4次遍历,去读4次标签信息再映射
print('GroundTruth:',' '.join('%5s'% classes[labels[j]] for j in range(4))) 

3.8.2. 加载学习好的权重

先实例化网络,再读取学习好的权重文件。

net = Net() #实例化网络
PATH='./cifar_net.pth'
net.load_state_dict(torch.load(PATH)) #让网络加载学习好的权重文件,是使用torch.load()函数读取进来的

3.8.3. 做预测

outputs = net(images)
print(outputs) #输出:每一行是一张图片的预测值

#加了_:获取最大值的标签位置;不加_:获取最大值
_,predicted = torch.max(outputs,1) #预测结果。 1:找出行最大值去返回;如果是0,则是列最大去返回
print('Predicted:',' '.join('%5s'% classes[predicted[j]] for j in range(4)))

在整个数据集上的预测结果:54%左右

torch.no_grad()关闭梯度。torch在预测中会进行梯度累加,做预测不需要保留梯度,训练中要保留梯度更新参数。

correct = 0 #正确率,即在整个数据集上预测正确的有几个
total = 0 #整个数据集的大小
with torch.no_grad():
    #遍历整个测试数据集 
    for data in testloader:
        images,labels = data
        outputs = net(images)
        _,predicted = torch.max(outputs,1) #找出预测信息
        total += labels.size(0) #记录读了几张图片
        correct += (predicted == labels).sum().item() #预测成功的照片数

correctGailv = 100*(correct / total)
print(correctGailv)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值