文章目录

写在前面

实战

  • 分析结构:
  • 代码实现
  • 完善补充1
  • 完善补充2
  • 使用GPU来训练网络
  • 测试模型

写在前面

本系列笔记为pytorch入门学习,所以主要学习使用pytorch框架进行神经网络的实现过程,对于神经网络的基本原理可能不会做过多解释,主要着重于用法。 传送门:PyTorch入门(一)数据集的一些基础操作PyTorch入门(二)从零开始搭建一个神经网络PyTorch入门(三)损失函数与反向传播

实战

那么,现在我们以CIFAR10的网络模型为例子,尝试写一个完整的神经网络

网络架构如图:(这个架构我们在第二篇文章中其实已经写过了,但是这次写的更加完整一些)

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_神经网络

分析结构:

有了前面的基础,那么现在我们已经了解了构建网络的步骤了:

  • 准备数据: dataset
  • 加载数据: dataloader
  • 准备模型: 写好网络模型,引入进来
  • 设置损失函数:分类问题一般用交叉熵
  • 设置优化器:
  • 开始训练
  • 验证训练进度:每训练一轮就到测试集上去试试效果
  • 模型保存: 每一轮的训练结果都保存下来
代码实现

这代码都是严格按照上面说的步骤写的,注释也给的很详细。 这就是完整的神经网络训练过程

import torch
import torchvision
from model import * # 引入我们写好的神经网络
from torch import nn
from torch.utils.data import DataLoader
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

# 准备训练数据集
train_data = torchvision.datasets.CIFAR10("../dataset",train=True,transform=torchvision.transforms.ToTensor(),
                                       download=True)
# 准备测试数据集
test_data = torchvision.datasets.CIFAR10("../dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                       download=True)
# 输出数据集的长度
train_data_size = len(train_data)
test_data_siez = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_siez))

# 加载数据集
train_dataloader = DataLoader(train_data,batch_size=64)
test_dataloader = DataLoader(test_data,batch_size=64)

# 创建网络模型
# 这个网络模型是我们提前写好的 写在model.py文件里面 所以from model import *
test = Network()

# 创建损失函数
loss_fn = nn.CrossEntropyLoss()

# 构造优化器
# 这里我们选择的优化器是SGD 随机梯度下降 传入模型参数和学习速率
learning_rate = 0.01
optimizer = torch.optim.SGD(test.parameters(),lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 记录训练的轮数
epoch = 10

# 开始训练
for i in range(epoch):
    print("开始第{}轮训练".format(i+1))
    # 遍历训练集
    for data in train_dataloader:
        imgs,targets = data # 取出图像和target
        outputs = test(imgs) # 数据送进网络 拿到输出
        loss = loss_fn(outputs,targets) # 计算损失函数
        # 优化
        optimizer.zero_grad() # 梯度清零
        loss.backward() # 反向传播
        optimizer.step() # 参数优化

        # 训练一次结束 更新训练次数
        total_train_step =total_train_step + 1
        if total_train_step % 100 == 0 : # 避免打印太多 影响查看
            print("训练次数:{},Loss值:{}".format(total_train_step,loss))
    # 当一次训练结束之后 我们就让他在测试数据集上验证一下
    # 这样就知道模型是否训练好了 是否符合我们的要求了
    # 测试步骤
    total_test_loss = 0 # 用来记录模型在全部测试数据上的loss之和
    with torch.no_grad():
        """
        在使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。
        而对于tensor的计算操作,默认是要进行计算图的构建的,
        在这种情况下,可以使用 with torch.no_grad():,强制之后的内容不进行计算图构建。
        """
        for data in test_dataloader:
            imgs,targets = data
            outputs = test(imgs)
            loss = loss_fn(outputs,targets)
            total_test_loss = total_test_loss + loss
    print("测试集上的loss:{}".format(total_test_loss))
    # 把每一轮训练得到的结果保存下来
    torch.save(test,"result_model_{}.pth".format(i))
    print("模型已保存")

这里面引入的神经网络,是我们提前写好的,放在moudel.py文件里面

import torch
from torch import nn

# 搭建神经网络
class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),# 卷积层
            nn.MaxPool2d(2), # 池化层
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10),
        )
    def forward(self,x):
        x = self.model1(x)
        return x

if __name__ == '__main__':
    # 实例化这个网络
    test = Network()
    # 测试一下网络 查看输出结果是否符合要求
    input = torch.ones((64,3,32,32))
    output = test(input)
    print(output.shape)
完善补充1

我们在训练的过程中,每一轮都进行了测试,看看训练结果在测试集上的loss表现。不过呢,我们这是一个分类网络,目的是为了识别图像类别,那么其实我们可以把识别率这个指标也展示出来。之所以上面没写,是因为这不是所有网络都需要的步骤,不同的任务我们做出不同的操作,对于这个分类任务,我们可以在验证的时候,给出识别率来,这样更加清晰。 如何得到准确率呢? 需要用到几个函数:

import torch

outputs = torch.tensor([[0.2,0.5],
                        [0.3,0.4]])
print(outputs.argmax(1)) # 横着看
print(outputs.argmax(0)) # 竖着看

输出结果:tensor([1, 1]) tensor([1, 0])

这个函数argmax的意思就是:找出最大的值的下标,当设置为1的时候,就是横着找出这一排的最大值,输出下标(下标从0开始),设置为0的时候,就是竖着找出最大值,输出下标。 那么我们网络训练出来的,最终得到的一些值,比如十分类问题就是十个值,我们其实就是选出最大的那个,就认为网络识别的图像为这一类。 然后再拿我们运算出来的结果和真实的target做运算,就可以求出分类准确的数量了,所以准确率就出来了。

import torch
outputs = torch.tensor([[0.2,0.5],
                        [0.3,0.4]])
# print(outputs.argmax(1)) # 横着看
# print(outputs.argmax(0)) # 竖着看
preds = outputs.argmax(1)
targets = torch.tensor([0,1])
print(preds == targets)
print((preds == targets).sum())

输出结果:tensor([False, True]) tensor(1) 所以,我们只需要在我们的代码里简单修改几处,即可显示测试的准确率

# 开始训练
for i in range(epoch):
    print("开始第{}轮训练".format(i+1))
    # 遍历训练集
    for data in train_dataloader:
        imgs,targets = data 
        outputs = test(imgs) 
        loss = loss_fn(outputs,targets) 
        # 优化
        optimizer.zero_grad() 
        loss.backward() 
        optimizer.step() 
        
        total_train_step =total_train_step + 1
        if total_train_step % 100 == 0 : 
            print("训练次数:{},Loss值:{}".format(total_train_step,loss))
   
    # 测试步骤
    total_test_loss = 0 # 用来记录模型在全部测试数据上的loss之和
    total_accuracy = 0 #用来记录准确的数量
    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets = data
            outputs = test(imgs)
            loss = loss_fn(outputs,targets)
            total_test_loss = total_test_loss + loss
            accuracy = (outputs.argmax(1) == targets).sum()  # 求得准确的数量
            total_accuracy = total_accuracy + accuracy # 每次累加
    print("测试集上的loss:{}".format(total_test_loss))
    print("整体测试集上的准确率为:{}".format(total_accuracy/test_data_size))
    # 把每一轮训练得到的结果保存下来
    torch.save(test,"result_model_{}.pth".format(i))
    print("模型已保存")

运行结果:

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_pytorch 搭建并列神经网络_02

保存的模型:

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_pytorch_03

完善补充2

还有两处需要强调一下:

在网络开始训练之前和开始测试之前,你可能看别人的代码会看到两句话

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_pytorch 搭建并列神经网络_04

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_神经网络_05

其实这个的作用呢,我们可以看下官网

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_神经网络_06

可以看到,调用这个就是把网络设置为了训练模式,但是我们之前没写这个,我们的网络也没啥问题,原因就是因为,这个模式也就对一些网络层有影响,图上指示的那块。之前我们写的网络没用到这些,所以写这行代码也可,不写也可。eval同理

使用GPU来训练网络

其实使用GPU很简单,只需要改动几行代码。 我们只需要找到三种模块,使用他们的CUDA方法即可:网络模型、数据、损失函数 那我们分别找到这三部分,进行修改 网络模型

# 创建网络模型
test = Network()
if torch.cuda.is_available():
    test = test.cuda()

数据 训练集和测试集都可以用,取数据的时候调用

# 遍历训练集
    for data in train_dataloader:
        imgs,targets = data 
        if torch.cuda.is_available(): # 如果cuda可用 就调用cuda
            imgs = imgs.cuda()
            targets = targets.cuda()
        outputs = test(imgs) 
        loss = loss_fn(outputs,targets) 
        optimizer.zero_grad() 
        loss.backward() 
        optimizer.step()

损失函数

# 创建损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():
    loss_fn = loss_fn.cuda()

除了这种方式,还有另一种方式使用GPU训练: 提前定义好训练的设备:device = torch.device("cuda") 如果你电脑上只有一张显卡的话,那么下面这两种写法都是指定这个显卡device = torch.device("cuda")device = torch.device("cuda:0") 如果有多个显卡,那就指定你想指定的显卡device = torch.device("cuda:1") 然后代码里面,调用To即可

# 创建网络模型
test = Network()
test = test.to(device)

损失函数和数据也是一样的方式,通过这样来调用GPU

测试模型

那么,模型训练好了,接下来我们测试一下效果

其实就是输入一个图片,看一下这个模型能不能完成任务

我们写一个test.py文件

我们找一张狗的图片:路径写好

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_pytorch 搭建并列神经网络_07

import torch

import torchvision
from PIL import Image

image_path = "../dataset/dog.png"
image = Image.open(image_path)
print(image)
image = image.convert('RGB') # 确保其颜色通道为RGB
# 设置对图像的处理(调整大小、转换tensor)
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                            torchvision.transforms.ToTensor()])
# 对图像处理
image = transform(image)
# batch size
image = torch.reshape(image,(1,3,32,32))


# 加载模型
model = torch.load("result_model_0.pth",map_location=torch.device('cpu'))
print(model)
# 把模型转换为测试类型
model.eval()

with torch.no_grad():
    output = model(image)
print(output)
print(output.argmax(1)) # 输出结果值最大的那个下标

运行它,试一下,输出结果:tensor([[-0.3786, 0.3839, 0.2930, 0.3845, -0.3165, 0.4834, -0.3922, -0.2882, 0.0089, -0.3664]])

tensor([5])

可以看到,值最高的是0.4834,这是第5个(从0开始数)

也就是说,网络认为这是第5类。那么我们看下数据集的类别,第五类是dog,说明预测正确了。

pytorch 搭建并列神经网络 利用pytorch搭建神经网络_pytorch_08

当然了,你这里预测错误也是很有可能的,因为我使用的模型是训练了一轮得到的模型,准确率并不高。我们可以使用训练多轮的模型试试,准确率会有所提升。

ps:注意一个问题

假如你运行代码,报错如下

RuntimeError: Input type (torch.FloatTensor) and weight type (torch.cuda.FloatTensor) should be the same or input should be a MKLDNN tensor and weight is a dense tensor

这个多半是因为,你使用的模型是你用GPU训练出来的,但是呢现在测试,你是使用cpu跑的,所以提示你这个

解决办法就是加载模型的时候,添加这么一个参数:map_locatinotallow=torch.device(‘cpu’)

做一个映射

# 加载模型
model = torch.load("result_model_0.pth",map_location=torch.device('cpu'))