赞
踩
目录
我们有时需要把训练好的模型部署到很多不同的设备。在这种情况下,我们可以把内存中训练好的模型参数存储在硬盘上供后续读取使用。
我们想要保存训练好的模型,等需要用来进行图像分类等任务的时候,不经训练,直接加载使用。
这时,可以采用torch.save(model, 'best.pt')保存模型。
代码所需文件请点击此处免费下载
接下来用一个小案例来解释模型的读取
- import torch #这行代码引入了PyTorch库,可以用于张量计算和神经网络的构建。
- #从PyTorch库中引入了Dataset和DataLoader类。Dataset类是用于加载和预处理数据的,而DataLoader则是用于批量加载和打散数据
- from torch.utils.data import Dataset,DataLoader
-
- import numpy as np #用于处理数组
- from PIL import Image #引入了Pillow库中的Image模块,可以用于处理图像
- from torchvision import transforms #这个模块包含了很多用于图像预处理的函数,例如裁剪、旋转、翻转等
- data_transforms = {
- 'train': #训练集
- transforms.Compose([ #transforms.Compose对象的列表,该列表包含一系列的图像转换操作。
- transforms.Resize([300,300]), #是图像变换大小
-
- transforms.RandomRotation(45),#随机旋转,-45到45度之间随机选
- transforms.CenterCrop(256),#从中心开始裁剪
- transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
- transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
- # transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
- transforms.RandomGrayscale(p=0.1),#概率转换成灰度率,3通道就是R=G=B
- transforms.ToTensor(),
- transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#归一化,均值,标准差
- ]),
- 'valid': #测试集
- transforms.Compose([
- transforms.Resize([256,256]),
- transforms.ToTensor(),
- transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
- ]),
- }
- class food_dataset(Dataset): #food_dataset是自己创建的类名称,可以改为你需要的名称
- ##file_path是包含图像文件路径和标签的文本文件的路径,transform是一个可选的图像转换操作,默认为None
- def __init__(self, file_path,transform=None):
- self.file_path = file_path
- self.imgs = [] #初始化两个空列表,用于存储图像文件路径和对应的标签
- self.labels = []
- self.transform = transform # 将传入的transform参数存储在类的实例变量transform中
- with open(self.file_path) as f:
- #读取文件的每一行,去除首尾空格并使用空格分割,形成一个列表。
- samples = [x.strip().split(' ') for x in f.readlines()]
- #遍历列表中的每个元素,其中img_path是图像文件的路径,label是对应的标签
- for img_path, label in samples:
- #将图像文件路径添加到self.imgs列表中
- self.imgs.append(img_path)
- #将标签添加到self.labels列表中
- self.labels.append(label)
-
- def __len__(self): #类实例化对象后,可以使用len函数测量对象的个数
- return len(self.imgs)
-
- def __getitem__(self, idx): #关键,可通过索引的形式获取每一个图片数据及标签
- image = Image.open(self.imgs[idx]) #使用PIL库的Image.open方法打开指定路径的图像文件
- if self.transform:
- image = self.transform(image)
-
- label = self.labels[idx] #获取与图像对应的标签
- #将标签转换为NumPy数组,然后使用torch.from_numpy将其转换为PyTorch张量,并指定数据类型为torch.int64。
- label = torch.from_numpy(np.array(label,dtype = np.int64))
- return image, label #返回图像和标签的元组
-
- #传入训练数据文件的路径和指定的图像转换操作
- training_data = food_dataset(file_path = './train.txt',transform = data_transforms['train'])
- #用于测试数据
- test_data = food_dataset(file_path = './test.txt',transform = data_transforms['valid'])
目的:GPU检测的目的是充分利用可用的硬件资源,提高计算性能,并确保代码在不同环境中的稳定运行。这对于深度学习等需要大量计算的应用尤为重要。
- device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
- print(f"Using {device} device"
运行结果:
- from torch import nn
- class CNN(nn.Module):
- def __init__(self): # 输入大小 (3, 256, 256)
- super(CNN, self).__init__()
- self.conv1 = nn.Sequential( #将多个层组合成一起。
- nn.Conv2d( #2d一般用于图像,3d用于视频数据(多一个时间维度),1d一般用于结构化的序列数据
- in_channels=3, # 图像通道个数,1表示灰度图(确定了卷积核 组中的个数),
- out_channels=16,# 要得到几多少个特征图,卷积核的个数
- kernel_size=5, # 卷积核大小,5*5
- stride=1, # 步长
- padding=2, # 一般希望卷积核处理后的结果大小与处理前的数据大小相同,效果会比较好。那padding改如何设计呢?建议stride为1,kernel_size = 2*padding+1
- ), # 输出的特征图为 (16, 256, 256)
- nn.ReLU(), # relu层
- nn.MaxPool2d(kernel_size=2), # 进行池化操作(2x2 区域), 输出结果为: (16, 128, 128)
- )
- self.conv2 = nn.Sequential( #输入 (16, 128, 128)
- nn.Conv2d(16, 32, 5, 1, 2), # 输出 (32, 128, 128)
- nn.ReLU(), # relu层
- nn.Conv2d(32, 32, 5, 1, 2), # 输出 (32, 128, 128)
- nn.ReLU(),
- nn.MaxPool2d(2), # 输出 (32, 64, 64)
- )
-
- self.conv3 = nn.Sequential( #输入 (32, 64, 64)
- nn.Conv2d(32, 64, 5, 1, 2),
- nn.ReLU(), # 输出 (64, 64, 64)
- )
-
- self.out = nn.Linear(64 * 64 * 64, 20) # 全连接层得到的结果
-
- def forward(self, x):
- x = self.conv1(x)
- x = self.conv2(x)
- x = self.conv3(x)# 输出 (64,64, 32, 32)
- x = x.view(x.size(0), -1) # flatten操作,结果为:(batch_size, 64 * 32 * 32)
- output = self.out(x)
- return output
-
- model = CNN().to(device)
-
- loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
- optimizer = torch.optim.Adam(model.parameters(), lr=0.001)#创建一个优化器Adam
- def train(dataloader,model,optimizer,loss_fn):
- model.train()
-
- for x,y in dataloader: #x,y 分别是图像和标签
- x,y = x.to(device),y.to(device) #将数据放入GPU,提高训练结果
-
- pred = model.forward(x) #对x进行前向传播,得到训练模型的预测结果
- loss = loss_fn(pred,y) #使用损失函数来计算预测值pred 和 真实标签y 之间的损失
- optimizer.zero_grad() # PyTorch 优化器的方法,用于将模型参数的梯度归零,以准备进行新一轮的反向传播。
- loss.backward() #执行反向传播,计算模型参数相对于损失的梯度
- optimizer.step() #PyTorch 优化器的方法,用于根据梯度更新模型参数,以减小损失
- best_acc = 0
- #dataloader(用于提供测试数据批次的数据加载器)、model(深度学习模型),和 loss_fn(损失函数,用于计算模型的预测与真实标签之间的损失)
- def test(dataloader, model, loss_fn):
- global best_acc #全局变量 best_acc
- size = len(dataloader.dataset) #获取测试数据集的大小,用于计算准确率
- num_batches = len(dataloader) #获取数据加载器中批次的数量,用于计算平均损失
- model.eval() #将模型设置为评估模式。在评估模式下,模型不会进行训练
- test_loss, correct = 0, 0 #初始化测试损失和正确分类的样本数
- with torch.no_grad(): #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。
- for X, y in dataloader: # 循环,用于迭代测试数据集中的批次。X 表示图像数据,y 表示标签
- X, y = X.to(device), y.to(device)
- pred = model.forward(X) #执行前向传播,将输入数据 X 通过深度学习模型 model,并得到模型的预测结果 pred
- test_loss += loss_fn(pred, y).item() #计算模型的预测结果 pred 和真实标签 y 之间的损失,并将其累加到 test_loss 变量中
- #使用 argmax 函数找到最大概率的类别)和真实标签 y,然后将匹配的结果转换为浮点数类型,累加到 correct 变量中
- correct += (pred.argmax(1) == y).type(torch.float).sum().item()
- test_loss /= num_batches #计算平均测试损失,将总测试损失除以批次的数量
- correct /= size #计算准确率,将正确分类的样本数除以测试数据集的总大小
- #印测试结果,包括准确率和平均损失
- print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")
- acc_s.append(correct)
- loss_s.append(test_loss)
(模型的文件扩展名一般为:pt)
方法一:
- if correct > best_acc:
- best_acc = correct
- # (w, b) ) 通常用来表示模型的参数,具体指模型的权重 ( w ) 和偏置 ( b )。
- # 1、保存模型参数方法:torch.save(model.state_dict(), path)(w,b)
- print(model.state_dict().keys()) # 输出模型参数名称
- torch.save(model.state_dict(), "model_parameter.pt") #保存模型的参数到名为 "model_parameter.pt" 的文件中
方法二:
- # 2、保存完整模型(w,b,模型cnn),
- torch.save(model, 'best.pt')
这里我们不做深度的解析,(详解请点击此处)
- acc_s = []
- loss_s = []
-
- # 提取模型的2种方法:
- # 1、读取参数的方法
- # model = CNN().to(device)
- # model.load_state_dict(torch.load("model_parameter.pt"))
- # 2、读取完整模型的方法,无需提前创建model
- model = torch.load('best.pt')
- model.eval() #固定模型参数和数据,防止后面被修改
- test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
- test(test_dataloader, model, loss_fn) #执行测试
输出结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。