土堆Pytorch学习笔记(三)

2023.04.02

(一)优化器

同样是在pytorch官网找到优化器(optim),查看官方文档。下面以

optim = torch.optim.SGD(nerualnetwork.parameters(), lr=0.01) 为例
optim = torch.optim.SGD(nerualnetwork.parameters(), lr=0.01)

for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        output = nerualnetwork(imgs)
        # 计算交叉熵损失函数  网络的输出和真实的target之间的差距
        result_loss = loss(output, targets)
        # 梯度下降(反向传播
        optim.zero_grad()
        result_loss.backward()
        optim.step()
        running_loss = running_loss + result_loss
    print(running_loss)

使用优化器时要先调用 optim.zero_grad() 将原来的梯度置零,然后再进行反向传播。

一般网络会进行成百上千甚至上万次学习(这里设置的是20次),理论上来说误差函数要越来越小。

(二)Pytorch提供的网络模型及修改使用

以vgg16为例:

vgg16能够将图片分成1000个类别,我们只需要10个类别就足够了,所以修改的办法是:

1. 加入一个线性层(将1000映射到10)

2.直接将最后一个线性层的参数修改(1000修改成10)

1. 加入一个线性层

vgg16_true.add_module('add_linear', nn.Linear(1000, 10))

这么做的结果是在网络最后多了一个名为(add_linear)的 model

 那么要是希望将此线性层加在上一个(或任一个)model 中:

vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))

 2. 直接将最后一个线性层的参数修改

vgg16_false.classifier[6] = nn.Linear(4096, 10)

 (三)网络模型的保存与读取

1.保存方式1:模型结构+模型参数

torch.save(vgg16, 'vgg16_method1.pth')

加载模型:

model = torch.load('vgg16_method1.pth')

2.保存方式2:模型参数(官方推荐)

torch.save(vgg16.state_dict(), 'vgg16_method2.pth')   # 将vgg16保存成字典形式

加载模型:

model = torch.load('vgg16_method2.pth')

结果是由参数组成的字典,没有网络结构的相关信息

要显示网络相关结构的话,需要下面代码:

# model = torch.load('vgg16_method2.pth')
vgg16 = torchvision.models.vgg16(weights=None)
vgg16.load_state_dict(torch.load('vgg16_method2.pth'))

print(vgg16)

(四)完整的模型训练套路

4.1 首先测试网络的正确性

        一般网络模型是单独放在一个.py文件里的,并在里面测试网络的正确性

比如有这样一个网络(CIFAR 10):

# 搭建神经网络
class CIFAR10(nn.Module):
    def __init__(self):
        super(CIFAR10, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, 32, 5, 1, 2),
            nn.MaxPool2d(2,),
            nn.Conv2d(32, 32, 4, 1 ,2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x

测试输出结果的正确性:

if __name__ =='__main__'
    cifar10 = CIFAR10()
    # 创建输入尺寸
    input = torch.ones((64, 3, 32, 32))
    output = cifar10(input)
    print(output)

4.2 进行训练前的一些初始化

# 初始化网络
cifar10 = CIFAR10()
# 创建损失函数  (因为网络处理的是分类问题,所以可以使用交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
learning_rate = 0.01
optim = torch.optim.SGD(cifar10.parameters(), lr=learning_rate)
# 设置训练网络的参数
# 1. total_train_step:记录训练次数
total_train_step = 0
# 2. total_test_step: 记录测试的次数
total_test_step = 0
# 3. epoch:记录训练的轮数
epoch = 10

4.3 训练网络

for i in range(epoch):
    print('----------第{}轮训练开始----------'.format(i+1))
    # 训练步骤开始
    for data in train_dataloader:
        imgs, targets = data
        outputs= cifar10(imgs)
        loss = loss_fn(outputs, targets)
        # 调用优化器通过计算出的损失进行优化
        optim.zero_grad()
        loss.backward()
        optim.step()
        total_train_step += 1
        print('训练次数是:{},loss:{}'.format(total_train_step, loss.item))

4.4检验模型是否训练好或者是否达到需求 

首先在训练集上要去除梯度,定义整体的测试loss和准确性,通过调用output的 argmax(1) 属性来检验正确性,代码如下:

# 为了检验模型是否训练达标,需要每训练一次都验证一下,验证时不需要调优
# 测试步骤开始
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad():    # 表示没有梯度(因为梯度是用来调优的,这里不需要
        for data in test_dataloader:
            imgs, targets = data
            outputs = cifar10(imgs)
            loss = loss_fn(outputs, targets)
            # 需要的是整个数据集的Loss
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print('整体测试集上的loss:{}'.format(total_test_loss))
    print('整体测试集上的正确率:{}'.format(total_accuracy/test_data_size))
    writer.add_scalar('test_accuracy', total_accuracy/test_data_size, total_test_step)
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    total_test_loss += 1

    # 保存每一轮训练的模型
    torch.save(cifar10, 'cifar10_{}.pth'.format(i))
    print('模型已保存')

4.5 添加tensorboard来实时查看loss

writer = SummaryWriter('logs_train')
writer.add_scalar("train_loss", loss.item(), total_train_step)

...

整体的训练代码:

import torch.optim
from torch import nn
from torch.utils.data import DataLoader
import torchvision.datasets


from torch.utils.tensorboard import SummaryWriter
# 准备数据集
train_data = torchvision.datasets.CIFAR10(root='./new_dataset', train=True, transform=torchvision.transforms.ToTensor(), download=True)
# 准备测试集
test_data = torchvision.datasets.CIFAR10(root='./new_dataset', train=False, transform=torchvision.transforms.ToTensor(), download=True)
# 查看训练/测试数据集的大小(有多少张图片
train_data_size = len(train_data)
test_data_size = len(test_data)

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

# 搭建神经网络
class CIFAR10(nn.Module):
    def __init__(self):
        super(CIFAR10, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, 32, 5, 1, 2),
            nn.MaxPool2d(2,),
            nn.Conv2d(32, 32, 4, 1 ,2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x
# 以上为整个网络模型,一般是单独放在一个.py文件里的,并在里面测试网络的正确性


# 初始化网络
cifar10 = CIFAR10()
# 创建损失函数  (因为网络处理的是分类问题,所以可以使用交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
learning_rate = 0.01
optim = torch.optim.SGD(cifar10.parameters(), lr=learning_rate)
# 设置训练网络的参数
# 1. total_train_step:记录训练次数
total_train_step = 0
# 2. total_test_step: 记录测试的次数
total_test_step = 0
# 3. epoch:记录训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter('logs_train')

for i in range(epoch):
    print('----------第{}轮训练开始----------'.format(i+1))
    # 训练步骤开始
    for data in train_dataloader:
        imgs, targets = data
        outputs= cifar10(imgs)
        loss = loss_fn(outputs, targets)
        # 调用优化器通过计算出的损失进行优化
        optim.zero_grad()
        loss.backward()
        optim.step()
        total_train_step += 1
        # 由于数据太多了,所以只打印逢100的损失
        if total_train_step % 100 == 0:
            print('训练次数是:{},loss:{}'.format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_train_step)

# 为了检验模型是否训练达标,需要每训练一次都验证一下,验证时不需要调优
# 测试步骤开始
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad():    # 表示没有梯度(因为梯度是用来调优的,这里不需要
        for data in test_dataloader:
            imgs, targets = data
            outputs = cifar10(imgs)
            loss = loss_fn(outputs, targets)
            # 需要的是整个数据集的Loss
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print('整体测试集上的loss:{}'.format(total_test_loss))
    print('整体测试集上的正确率:{}'.format(total_accuracy/test_data_size))
    writer.add_scalar('test_accuracy', total_accuracy/test_data_size, total_test_step)
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    total_test_loss += 1

    # 保存每一轮训练的模型
    torch.save(cifar10, 'cifar10_{}.pth'.format(i))
    print('模型已保存')

writer.close()

(五)使用GPU训练

方法一:对网络模型、数据(输入和标定)和损失函数进行 ' .cuda '操作,具体看自己电脑上的P30_train_GPU1

方法二:device = torch.device('cuda')

                然后同样的进行‘. to(device)’ 操作

(六)完整的模型验证(测试、demo)套路

利用已经训练好的模型,然后给他提供输入。

1.首先网络模型中的图片是32 * 32 大小的,所以要先将图片进行reshape。

2.另外,如果图片是png格式的(png格式是4通道的,RGB和一个透明度通道),要调用下行代码保留其颜色通道,除去透明度通道。

image = image.convert('RGB') 

3.搭建神经网络模型,并加载模型

4.这里测试的是胰脏图片,所以batch_size = 1 

image = torch.reshape(image, (1, 3, 32, 32))

5.最后有两行很重要的代码,model.eval()表示是用来测试的;with torch.no_grad():目的是将梯度置零(因为我们是测试模型,并不进行调优),这样做还可以节省空间

6.最后就将图片放入网络,再打印其输出就能查看其准确性了

output = model(image)

整体代码:

import torch
import torchvision.transforms
from PIL import Image
from torch import nn

img_path = 'dog.png'
image = Image.open(img_path)    # 将图片读取成PIL类型

# 因为网络模型中的图片大小是32 * 32 ,所以要将图片大小进行调整
image = image.convert('RGB')  # 由于图片是png形式的,有四个通道,需要调用此行代码进行保留颜色通道除去透明度通道
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
                                            torchvision.transforms.ToTensor()])
image = transform(image)
# 搭建神经网络
class CIFAR10(nn.Module):
    def __init__(self):
        super(CIFAR10, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, 32, 5, 1, 2),
            nn.MaxPool2d(2,),
            nn.Conv2d(32, 32, 4, 1 ,2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, 1, 2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x
# 加载网络模型
model = torch.load('cifar10_0.pth')
print(model)
image = torch.reshape(image, (1, 3, 32, 32))
model.eval()
with torch.no_grad():
    output = model(image)
print(output)

print(output.argmax(1))   # 打印输出对应的类别(通过调试可以看到类别对应的target)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值