VGG16的加载与变化
import torchvision.datasets
from torch import nn
"""
主要对模型的加载,并用于自己的需求中修改网络层数。
pretrained是否下载对于成熟数据集的参数作为初始化参数使用.
"""
# import os
# os.environ['TORCH_HOME']='D:/technology/pycharmDown'
train_data = torchvision.datasets.CIFAR10("../DataSet/dataset", train=True, download=True,
transform=torchvision.transforms.ToTensor())
vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_True = torchvision.models.vgg16(pretrained=True)
# 使用vgg16去做10分类为题.本身vgg16是做1000分类的,如何修改呢.可以直接在原网络后面添加一层线性层进行一个1000转10的操作.
vgg16_True.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_True)
# 或者将vgg中最后一层的线性变换输出变成10也可
vgg16_false.classifier[6] = nn.Linear(4096,10)
print(vgg16_false)
模型保存与加载
model_save.py 保存模型
import torch
import torchvision
from torch import nn
"""
本文件用于去演示保存我们训练好的模型结构和模型参数
结合加载文件 model_load.py观看
两种方法进行存储!两种方式进行加载
"""
# 下载模型
vgg16 = torchvision.models.vgg16(pretrained=False)
# 方法一保存:模型结构+模型参数 会有陷阱!
torch.save(vgg16, "vgg16_method1.pth")
# 方法二保存:仅保存模型参数 官方推荐
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
# 自定义模型,使用第一种方式打包可能出现问题:
class MyModule(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
output = self.conv1(x)
return output
mymodule = MyModule()
torch.save(mymodule, "custom_module.pth")
model_load.py 加载模型
import torch
import torchvision.models
from model_save import MyModule
"""
加载已经训练好的模型数据,进行使用。配合model_save.py进行观看
两种方式进行加载。
"""
# 保存方式1对应的加载方式 model就是一个网络结构
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出现:针对自定义的模型
model = torch.load('custom_module.pth')
print(model)
# Can't get attribute 'MyModule' on <module '__main__' from 'E:\\technology\\pythongross\\Neural_Network\\model_load.py'>
# 如果当前文件没有你自己创建的网络结构,就会无法找到.需要将创建的结构类复制到当前文件中或导入模型名称即可。
完整的模型训练步骤–GPU
利用10分类问题来演示整个过程。数据集为CIFAR10
整个构建过程看代码详解:
import torch.optim
import torchvision.datasets
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from Classify_model import CIFAR10
# 准备数据集
train_data = torchvision.datasets.CIFAR10("../DataSet/dataset", train=True, transform=torchvision.transforms.ToTensor(),
download=False)
test_data = torchvision.datasets.CIFAR10("../DataSet/dataset", train=False, transform=torchvision.transforms.ToTensor(),
download=False)
# 观看数据集长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print(f"训练数据集的长度{train_data_size}") # 50000
print(f"训练数据集的长度{test_data_size}") # 10000
# 利用dataloader加载数据集
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
# 搭建神经网络 ---就是前面搭建的10分类的神经网络 这部分需要使用模块化思想所以将其单独成一个文件
myModule = CIFAR10()
# 创建损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
learning_rate = 0.01 # 1e-2
optimizer = torch.optim.SGD(myModule.parameters(), lr=learning_rate)
# 设置训练网络的一些参数
# 记录训练次数
total_train_step = 0
# 记录测试次数
total_test_step = 0
# 设置训练轮次
epoch = 10
# 添加tensorboard
writer = SummaryWriter("CIFAR10")
for i in range(epoch):
# 严格意思上需要我们去 书写 myModule.train()
print(f"----第{i + 1}轮训练开始----")
total_train_loss = 0.0 # 用于观测每轮计算后的损失值
# 开始传入loader数据开始训练
for data in train_dataloader:
imgs, targets = data
# 传入网络
output = myModule(imgs)
# 计算损失函数并反向传播
loss = loss_fn(output, targets)
total_train_loss += loss.item()
# 清除梯度数
optimizer.zero_grad()
loss.backward()
# 优化器步入
optimizer.step()
total_train_step += 1
writer.add_scalar("train_loss", total_train_loss, global_step=total_train_step)
print(f"当前轮训练总损失值为:{total_train_loss}")
# 测试步骤开始 没有梯度改变
# 严格意思上需要我们去书写 myModule.eval() 网络有特殊层时必须调用
total_test_loss = 0 # 总损失值
total_accuracy = 0 # 预测正确的个数
with torch.no_grad(): # 必须这样写让网络梯度不变化
for data in test_dataloader:
imgs, targets = data
outputs = myModule(imgs)
# 添加正确个数的计算
accuracy = (outputs.argmax(1) == targets).sum()
total_accuracy += accuracy
loss = loss_fn(outputs, targets)
total_test_loss += loss.item()
print(f"当前轮测试总损失值为:{total_test_loss}")
print(f"当前轮测试正确率为:{total_accuracy / test_data_size}")
total_test_step += 1
writer.add_scalar("test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_accuracy", total_accuracy / test_data_size, total_test_step)
print(f"----第{i + 1}轮训练结束----")
# 每轮结束后保存当前轮训练的参数:
torch.save(myModule, f"./Module/CIFAR10_{i + 1}.pth")
print("本轮模型已保存")
writer.close()
上述为分类问题观测损失函数。一般更会利用正确率来作为评价标准。
函数[].argmax(int)
- 当int 为0时 将会竖着对比(第一例中选出最大的值的行标)。
- 为1时,将会横着对比(第一行中选出最大值的列标)。
测试代码为下图:
在代码中添加计算每轮迭代过程的正确率并绘制图像。
利用GPU计算
有两种方式能够添加!
F1 针对网络模型、数据、损失函数 使用.cuda()
即可
- 像
myModule=myModuel.cuda() loss_fn=loss_fn.cuda() imgs=imgs.cuda() targets=targets.cuda()
- 良好的行为习惯为:先判断
if torch.cuda.is_avilable():
在执行
F2更适合可移植使用
- 对于模型、数据、损失函数调用
.to(device)
- 声明
device=torch.device("CPU")
或device=torch.device("cuda")
device=torch.device("cuda:0")
完整的模型验证步骤
- 测试 demo 利用已经训练好的模型,利用自己的输入进行预测。
import torch
import torchvision.transforms
from PIL import Image
from Classify_model import CIFAR10
"""
针对已经存在的模型进行导入自己的数据集进行验证测试的步骤。
必须获得网络定义的初始类才能够加载成功网络。比如上面导入的CIFAR10即为自定义的网络
引入自己的数据集,一定将数据集格式尺寸修改成网络传入初始的格式要求才可运行。
了解模型训练的方式,如果为GPU训练还需要将数据转成CUDA模式。两种方式!
注意模型导入方式。方式一、方式二的加载方式不同。
加载后需要将网络设置成测试模式进行测试。
"""
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
image_path = "../pytorch-tutorial-master/imgs/dog.png"
image = Image.open(image_path)
print(image)
image = image.convert('RGB')
transform = torchvision.transforms.Compose(
[torchvision.transforms.Resize((32, 32)), torchvision.transforms.ToTensor()])
image = transform(image)
# print(image.shape)
image = torch.reshape(image, (1, 3, 32, 32))
image = image.to(device)
# print(image.shape)
model = torch.load('./Module/CIFAR10_10.pth')
model.eval()
with torch.no_grad():
output = model(image)
print(output.argmax(1))
# 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训练的。所以你的图片也得使用GPU
# 如果想用cpu来观测结果,则在加载过程中model = torch.load('./Module/CIFAR10_10.pth' map_location = torch.device('CPU'))
实验结果为 tensor([5], device='cuda:0')
公开模型
pass