Pytorch应用训练好的模型

您所在的位置:网站首页 傲胜os8008如何使用 Pytorch应用训练好的模型

Pytorch应用训练好的模型

2023-08-08 12:51| 来源: 网络整理| 查看: 265

Pytorch应用训练好的模型 1.保存训练好的模型:torch.save方法2.加载之前保存的模型:torch.load方法3.对于分类问题的补充4.CPU训练完整代码5.GPU训练方法一6.GPU训练方法二7.GPU训练过程的细节优化8.验证模型

1.保存训练好的模型:torch.save方法

保存训练好的模型有两种方式,第一种保存模型结构且保存模型参数,第一种方式存在一种陷阱,也就是每次加载模型都得把类定义,或者访问类所在的包。保存方式为:

torch.save(模型名, 以pth为后缀的文件)

第二种保存方式只保存模型参数,不保存模型结构,这样可以面对较大的网络模型,可以节省空间,是官方推荐的保存方式,具体为:

torch.save(模型名.state_dict(), 以pth为后缀的文件)

第一个参数,模型名.state_dict()意为只取模型的参数,且以字典方式存储;第二个参数存储模型的地址,一般都用以pth结尾的文件。 代码如下:

import torch import torchvision from torch import nn vgg16 = torchvision.models.vgg16(pretrained=False) # 保存方式1,模型结构+模型参数 torch.save(vgg16, "vgg16_method1.pth") # 保存方式2,模型参数(官方推荐) torch.save(vgg16.state_dict(), "vgg16_method2.pth") # 陷阱 class test_Model(nn.Module): def __init__(self): super(test_Model, self).__init__() self.conv1 = nn.Conv2d(3, 64, kernel_size=3) def forward(self, x): x = self.conv1(x) return x test_model = test_Model() torch.save(test_model, "test_model_method1.pth") 2.加载之前保存的模型:torch.load方法

对应两种不同的保存模型的方式,也相应地有两种加载模型的方式,第一种方式为:

读取出的模型名 = torch.load(之前保存的模型文件名)

第二种方式为:

读取出的模型名 = torchvision.models.vgg16(pretrained=False) 读取出的模型名.load_state_dict(torch.load(之前保存的模型文件名))

因为第二种方法没有保存模型结构,所以我们要先设计一个模型结构,本例中用的是直接下载VGG16模型结构;然后第二条语句用于将保存的参数值传入到模型结构中。代码如下:

import torch from model_save import * import torchvision from torch import nn # 方式1-》保存方式1,加载模型 model = torch.load("vgg16_method1.pth") # print(model) # 方式2,加载模型 vgg16 = torchvision.models.vgg16(pretrained=False) vgg16.load_state_dict(torch.load("vgg16_method2.pth")) # 只读取参数 # model = torch.load("vgg16_method2.pth") # print(vgg16) # 方式1,陷阱 # class test_Model(nn.Module): # def __init__(self): # super(test_Model, self).__init__() # self.conv1 = nn.Conv2d(3, 64, kernel_size=3) # # def forward(self, x): # x = self.conv1(x) # return x model = torch.load('test_model_method1.pth') print(model) 3.对于分类问题的补充

对于图像分类、目标检测或是语义分割等各种问题而言,单靠loss曲线还无法完全表现出模型的优劣,而在图像分类问题中,我们常用acc,即在测试集上的正确率来表示模型的训练情况及优劣。

在分类问题中,例如CIFAR10中,某张图片进入模型后的输出结果是形如([0.2, 0.1, 0.4, 0.6, 0.4, 0.4, 0.7, 0.2, 0.5, 0.1]),而targets是类似(5)这样的某个整型数字,表明该图片属于第5类。那么如和将输出结果与targets之间进行计算,产生正确率呢,我们采用argmax函数,该函数会找到数组中最大值并输出最大值的序号,那么如此一来,将输出结果的最大值序号和targets相比较,如果一致则说明该图像识别正确。代码如下:

import torch output = torch.tensor([[0.2, 0.3], [0.1, 0.5]]) # 纵向比较 print(output.argmax(0)) # 横向比较 print(output.argmax(1)) pred = output.argmax(1) targets = torch.tensor([0, 1]) print(pred == targets) # 输出正确的个数 print((pred == targets).sum())

注:因在验证过程中,因为不是一张图片,而是batch_size张图片验证,那么output应是二维数组,第二维的数目是batchsize个,此例中设为2个,相应的targets应是一个一维数组,数组中的每个数表示每张图对应的正确类别是哪类。另外,argmax(0)表示传入的数据纵向进行比较,在本例中是0.2和0.1比,0.3和0.5比;而argmax(1)表示传入的数据横向进行比较,在本例中是0.2和0.3比,0.1和0.5比,毫无疑问,运用在计算准确率中,我们应该使用的是argmax(1),那么记录所有output和targets相吻合的项的和除以总项数即可获得该batch_size的准确率。

4.CPU训练完整代码

CPU训练就是之前介绍的搭建模型和应用模型相结合,内容都是之前所讲,完整代码如下:

import torchvision from torch.utils.tensorboard import SummaryWriter from model import * # 准备数据集 from torch import nn from torch.utils.data import DataLoader train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(), download=True) test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(), download=True) # length 长度 train_data_size = len(train_data) test_data_size = len(test_data) # 如果train_data_size=10, 训练数据集的长度为:10 print("训练数据集的长度为:{}".format(train_data_size)) print("测试数据集的长度为:{}".format(test_data_size)) # 利用 DataLoader 来加载数据集 train_dataloader = DataLoader(train_data, batch_size=64) test_dataloader = DataLoader(test_data, batch_size=64) # 创建网络模型 tudui = Tudui() # 损失函数 loss_fn = nn.CrossEntropyLoss() # 优化器 # learning_rate = 0.01 # 1e-2=1 x (10)^(-2) = 1 /100 = 0.01 learning_rate = 1e-2 optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate) # 设置训练网络的一些参数 # 记录训练的次数 total_train_step = 0 # 记录测试的次数 total_test_step = 0 # 训练的轮数 epoch = 10 # 添加tensorboard writer = SummaryWriter("../logs_train") for i in range(epoch): print("-------第 {} 轮训练开始-------".format(i+1)) # 训练步骤开始 # 这句话在训练开始时调用,在有Dropout层和层起作用,在本例中可不写,但建议写,较为规范 tudui.train() for data in train_dataloader: imgs, targets = data outputs = tudui(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.item())) writer.add_scalar("train_loss", loss.item(), total_train_step) # 测试步骤开始 # 这句话在测试开始时调用,在有Dropout层和层起作用,在本例中可不写,但建议写,较为规范 tudui.eval() total_test_loss = 0 # 整体正确个数 total_accuracy = 0 # 设置测试模型不改变梯度 with torch.no_grad(): for data in test_dataloader: imgs, targets = data outputs = tudui(imgs) loss = loss_fn(outputs, targets) 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_loss", total_test_loss, total_test_step) writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step) total_test_step = total_test_step + 1 #此处用的模型保存方式为方式一,建议使用方式二 torch.save(tudui, "tudui_{}.pth".format(i)) print("模型已保存") writer.close() 5.GPU训练方法一

GPU训练大部分代码与CPU训练一致,调用GPU的方法有两种,第一种方式是在网络模型、损失函数、训练输入数据、测试输入数据四处加入自己 = 自己.cuda即可,即在不同的地方加入以下四句语句:

if torch.cuda.is_available(): tudui = tudui.cuda() if torch.cuda.is_available(): loss_fn = loss_fn.cuda() if torch.cuda.is_available(): imgs = imgs.cuda() targets = targets.cuda() if torch.cuda.is_available(): imgs = imgs.cuda() targets = targets.cuda() if torch.cuda.is_available(): imgs = imgs.cuda() targets = targets.cuda()

因此第一种GPU训练的完整代码为:

import time import torch import torchvision from torch.utils.tensorboard import SummaryWriter # from model import * # 准备数据集 from torch import nn from torch.utils.data import DataLoader train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(), download=True) test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(), download=True) # length 长度 train_data_size = len(train_data) test_data_size = len(test_data) # 如果train_data_size=10, 训练数据集的长度为:10 print("训练数据集的长度为:{}".format(train_data_size)) print("测试数据集的长度为:{}".format(test_data_size)) # 利用 DataLoader 来加载数据集 train_dataloader = DataLoader(train_data, batch_size=64) test_dataloader = DataLoader(test_data, batch_size=64) # 创建网络模型 class Tudui(nn.Module): def __init__(self): super(Tudui, self).__init__() self.model = nn.Sequential( nn.Conv2d(3, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, 1, 2), nn.MaxPool2d(2), nn.Flatten(), nn.Linear(64*4*4, 64), nn.Linear(64, 10) ) def forward(self, x): x = self.model(x) return x tudui = Tudui() if torch.cuda.is_available(): print("成功调用GPU") tudui = tudui.cuda() # 损失函数 loss_fn = nn.CrossEntropyLoss() if torch.cuda.is_available(): loss_fn = loss_fn.cuda() # 优化器 # learning_rate = 0.01 # 1e-2=1 x (10)^(-2) = 1 /100 = 0.01 learning_rate = 1e-2 optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate) # 设置训练网络的一些参数 # 记录训练的次数 total_train_step = 0 # 记录测试的次数 total_test_step = 0 # 训练的轮数 epoch = 10 # 添加tensorboard writer = SummaryWriter("../logs_train") # 记录最初时间 start_time = time.time() for i in range(epoch): print("-------第 {} 轮训练开始-------".format(i+1)) # 训练步骤开始 tudui.train() for data in train_dataloader: imgs, targets = data if torch.cuda.is_available(): imgs = imgs.cuda() targets = targets.cuda() outputs = tudui(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: # 记录结束时间 end_time = time.time() print("每100次训练花费时间为:{}秒".format(end_time - start_time)) # 重置开始时间 start_time = time.time() print("训练次数:{}, Loss: {}".format(total_train_step, loss.item())) writer.add_scalar("train_loss", loss.item(), total_train_step) # 测试步骤开始 tudui.eval() total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: imgs, targets = data if torch.cuda.is_available(): imgs = imgs.cuda() targets = targets.cuda() outputs = tudui(imgs) loss = loss_fn(outputs, targets) 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_loss", total_test_loss, total_test_step) writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step) total_test_step = total_test_step + 1 torch.save(tudui, "tudui_{}.pth".format(i)) print("模型已保存") writer.close() 6.GPU训练方法二

GPU第二种训练方式是先定义一个训练的设备,语句为device = torch.device(“cuda”),如果有多张显卡则语句为device = torch.device(“cuda:0”)代表用第0张显卡,要调用其它显卡则将0改成其它数字,然后将训练方法一中的.cuda改为.to(device),例如:

if torch.cuda.is_available(): tudui = tudui.cuda()

则完整代码为:

import torch import torchvision from torch.utils.tensorboard import SummaryWriter # from model import * # 准备数据集 from torch import nn from torch.utils.data import DataLoader # 定义训练的设备 device = torch.device("cuda") train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(), download=True) test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(), download=True) # length 长度 train_data_size = len(train_data) test_data_size = len(test_data) # 如果train_data_size=10, 训练数据集的长度为:10 print("训练数据集的长度为:{}".format(train_data_size)) print("测试数据集的长度为:{}".format(test_data_size)) # 利用 DataLoader 来加载数据集 train_dataloader = DataLoader(train_data, batch_size=64) test_dataloader = DataLoader(test_data, batch_size=64) # 创建网络模型 class Tudui(nn.Module): def __init__(self): super(Tudui, self).__init__() self.model = nn.Sequential( nn.Conv2d(3, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, 1, 2), nn.MaxPool2d(2), nn.Flatten(), nn.Linear(64*4*4, 64), nn.Linear(64, 10) ) def forward(self, x): x = self.model(x) return x tudui = Tudui() tudui = tudui.to(device) # 损失函数 loss_fn = nn.CrossEntropyLoss() loss_fn = loss_fn.to(device) # 优化器 # learning_rate = 0.01 # 1e-2=1 x (10)^(-2) = 1 /100 = 0.01 learning_rate = 1e-2 optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate) # 设置训练网络的一些参数 # 记录训练的次数 total_train_step = 0 # 记录测试的次数 total_test_step = 0 # 训练的轮数 epoch = 10 # 添加tensorboard writer = SummaryWriter("../logs_train") for i in range(epoch): print("-------第 {} 轮训练开始-------".format(i+1)) # 训练步骤开始 tudui.train() for data in train_dataloader: imgs, targets = data imgs = imgs.to(device) targets = targets.to(device) outputs = tudui(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.item())) writer.add_scalar("train_loss", loss.item(), total_train_step) # 测试步骤开始 tudui.eval() total_test_loss = 0 total_accuracy = 0 with torch.no_grad(): for data in test_dataloader: imgs, targets = data imgs = imgs.to(device) targets = targets.to(device) outputs = tudui(imgs) loss = loss_fn(outputs, targets) 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_loss", total_test_loss, total_test_step) writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step) total_test_step = total_test_step + 1 torch.save(tudui, "tudui_{}.pth".format(i)) print("模型已保存") writer.close() 7.GPU训练过程的细节优化

首先,对于网络模型和损失函数,不需要对其重新赋值,也就是说以下代码:

tudui = tudui.to(device) loss_fn = loss_fn.to(device) tudui = tudui.cuda() loss_fn = loss_fn.cuda()

可以直接写为:

tudui.to(device) loss_fn.to(device) tudui.cuda() loss_fn.cuda()

但imgs和targets不能省略前面的赋值。

其次,在方法二中可能出现没有GPU或是GPU未能成功调用,所以可以将代码:

device = torch.device("cuda")

改为:

device = torch.device("cuda" if torch.cuda.isavailable() else "CPU")

如此一来,如果无法调用GPU则会调用CPU训练,而不会报错。

8.验证模型

在训练并测试完之后,如果想要验证模型,类似与测试集的操作,可对某张特定图片或某些图片进行验证,观察其输出是否正确,代码如下:

import torch import torchvision from PIL import Image from torch import nn image_path = "../imgs/airplane.png" image = Image.open(image_path) print(image) # 该语句是因为不是所有类型的图片都是三通道的,通过这句代码可以将所有类型的通篇都转化成3通道 image = image.convert('RGB') transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)), torchvision.transforms.ToTensor()]) image = transform(image) print(image.shape) class Tudui(nn.Module): def __init__(self): super(Tudui, self).__init__() self.model = nn.Sequential( nn.Conv2d(3, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 32, 5, 1, 2), nn.MaxPool2d(2), nn.Conv2d(32, 64, 5, 1, 2), nn.MaxPool2d(2), nn.Flatten(), nn.Linear(64*4*4, 64), nn.Linear(64, 10) ) def forward(self, x): x = self.model(x) return x # map_location属性是在,当保存的模型是GPU训练的,而现在我们要用CPU验证时需要添加这样一句话 model = torch.load("tudui_29_gpu.pth", map_location=torch.device('cpu')) 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))

注:因为训练是我们采用是第一种方式保存模型,所有加载模型时我们需要将模型的类再写一次,或者调用定义了模型类的文件;另外注意image = image.convert(‘RGB’)将各种不同的图片转化为三通道;最后注意如果保存的模型是GPU训练的,而现在我们要用CPU验证时需要添加这样一句话model = torch.load(“tudui_29_gpu.pth”, map_location=torch.device(‘cpu’))。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3