当前位置:   article > 正文

模型训练+验证(train+demo)套路_一个模型的train文件

一个模型的train文件

以 CIFAR10 数据集为例,分类问题(10分类)

模型训练(train)套路

model.py

  1. import torch
  2. from torch import nn
  3. # 搭建神经网络
  4. class Overwatch(nn.Module):
  5. def __init__(self):
  6. super(Overwatch, self).__init__()
  7. self.model = nn.Sequential(
  8. nn.Conv2d(3, 32, 5, 1, 2),
  9. nn.MaxPool2d(2),
  10. nn.Conv2d(32, 32, 5, 1, 2),
  11. nn.MaxPool2d(2),
  12. nn.Conv2d(32, 64, 5, 1, 2),
  13. nn.MaxPool2d(2),
  14. nn.Flatten(),
  15. nn.Linear(64*4*4, 64),
  16. nn.Linear(64, 10),
  17. )
  18. def forward(self, x):
  19. x = self.model(x)
  20. return x
  21. if __name__ == '__main__': # 输入main即可跳出完整代码
  22. OW = Overwatch()
  23. input = torch.ones((64, 3, 32, 32))
  24. output = OW(input)
  25. print(output.shape)

train.py

  1. from model import * # 引入模型
  2. import torchvision.datasets
  3. from torch.utils.data import DataLoader
  4. # 准备数据集,CIFAR10数据集是PIL Image,要转换为tensor数据类型
  5. train_data = torchvision.datasets.CIFAR10('../data', train=True, transform=torchvision.transforms.ToTensor(),download=True)
  6. test_data = torchvision.datasets.CIFAR10('../data', train=False, transform=torchvision.transforms.ToTensor(),download=True)
  7. # 查看训练数据集和测试数据集数量
  8. train_data_size = len(train_data)
  9. test_data_size = len(test_data)
  10. print('训练数据集长度为:{}'.format(train_data_size))
  11. print('测试数据集长度为:{}'.format(test_data_size))
  12. # 利用DataLoader加载数据集
  13. train_dataloader = DataLoader(train_data, batch_size=64)
  14. test_dataloader = DataLoader(test_data, batch_size=64)
  15. # 创建网络模型
  16. OW = Overwatch()
  17. # 损失函数
  18. loss_function = nn.CrossEntropyLoss()
  19. # 优化器
  20. learning_rate = 0.01
  21. optimizer = torch.optim.SGD(OW.parameters(), lr=learning_rate)
  22. # 设置训练网络的参数
  23. # 记录训练的次数
  24. total_train_step = 0
  25. # 记录测试的次数
  26. total_test_step = 0
  27. # 训练的轮数
  28. epoch = 10
  29. for i in range(epoch): # 0~9
  30. print('-----第 {} 轮训练开始-----'.format(i+1)) # 1~10
  31. # 训练步骤开始
  32. for data in train_dataloader:
  33. imgs, targets = data
  34. outputs = OW(imgs)
  35. loss = loss_function(outputs, targets) # 输出与target计算loss
  36. # 优化器优化模型
  37. optimizer.zero_grad() # 梯度清零:把上一步训练的每个参数的梯度清零
  38. loss.backward() # 反向传播:调用反向传播得到每个要更新参数的梯度
  39. optimizer.step() # 参数优化:每个参数根据上一步得到的梯度进行优化
  40. total_train_step = total_train_step + 1
  41. if total_train_step % 100 == 0: # 每100次才打印
  42. print('训练次数:{},Loss:{}'.format(total_train_step, loss.item()))

 tips:

print(loss) 和 print(loss.item()) 的区别

  1. import torch
  2. a = torch.tensor(5)
  3. print(a) # tensor(5)
  4. print(a.item()) # 5

如何知道模型是否训练好,或达到需求?

每次训练完一轮就进行测试,以测试数据集上的损失或正确率来评估模型有没有训练好

测试过程中不需要对模型进行调优,利用现有模型进行测试

  1. # 测试步骤开始(评估模型)
  2. total_test_loss = 0
  3. with torch.no_grad(): # 无需梯度调优
  4. for data in test_dataloader:
  5. imgs, targets = data
  6. outputs = OW(imgs)
  7. loss = loss_function(outputs, targets)
  8. total_test_loss = total_test_loss + loss.item()
  9. print('整体测试集上的Loss:{}'.format(total_test_loss))

与 TensorBoard 结合

正确率的实现(对分类问题) 

即便得到整体测试集上的 loss,也不能很好说明在测试集上的表现效果

  • 分类问题中可以用正确率表示(下述代码改进)
  • 在目标检测/语义分割中,可以把输出放在tensorboard里显示,看测试结果

  1. outputs = torch.tensor([[0.1,0.2],
  2. [0.3,0.4]])
  3. print(outputs.argmax(1)) # 0或1表示方向,1为横向比较大小. 运行结果:tensor([1, 1])

argmax相当于就是返回数组中最大值的索引

 preds 预测

  1. preds = outputs.argmax(1)
  2. targets = torch.tensor([0,1])
  3. print(preds == targets) # tensor([False, True])
  4. print(preds == targets.sum()) # tensor(1),对应位置相等的个数
  1. # 测试步骤开始(评估模型)
  2. # 初始化测试集上的总损失和总准确率
  3. total_test_loss = 0
  4. *total_accuracy = 0
  5. with torch.no_grad(): # 无需梯度调优
  6. for data in test_dataloader:
  7. imgs, targets = data
  8. outputs = OW(imgs)
  9. loss = loss_function(outputs, targets)
  10. total_test_loss = total_test_loss + loss.item()
  11. *accuracy = (outputs.argmax(1) == targets).sum() # 得到预测正确的样本数量
  12. *total_accuracy = total_accuracy + accuracy
  13. print('整体测试集上的Loss:{}'.format(total_test_loss))
  14. *print('整体测试集上的正确率:{}'.format(total_accuracy/test_data_size))
  15. # 画test_accuracy & test_loss
  16. *writer.add_scalar('test_accuracy', total_accuracy/test_data_size, total_test_step)
  17. writer.add_scalar('test_loss', total_test_loss, total_test_step)
  18. total_test_step = total_test_step + 1

完整代码

  1. from model import * # 引入模型
  2. import torchvision.datasets
  3. from torch.utils.data import DataLoader
  4. from torch.utils.tensorboard import SummaryWriter
  5. # 准备数据集,CIFAR10数据集是PIL Image,要转换为tensor数据类型
  6. train_data = torchvision.datasets.CIFAR10('../data', train=True, transform=torchvision.transforms.ToTensor(), download=True)
  7. test_data = torchvision.datasets.CIFAR10('../data', train=False, transform=torchvision.transforms.ToTensor(), download=True)
  8. # 查看训练数据集和测试数据集数量
  9. train_data_size = len(train_data)
  10. test_data_size = len(test_data)
  11. print('训练数据集长度为:{}'.format(train_data_size))
  12. print('测试数据集长度为:{}'.format(test_data_size))
  13. # 利用DataLoader加载数据集
  14. train_dataloader = DataLoader(train_data, batch_size=64)
  15. test_dataloader = DataLoader(test_data, batch_size=64)
  16. # 创建网络模型
  17. OW = Overwatch()
  18. # 损失函数
  19. loss_function = nn.CrossEntropyLoss()
  20. # 优化器
  21. learning_rate = 0.01
  22. optimizer = torch.optim.SGD(OW.parameters(), lr=learning_rate)
  23. # 设置训练网络的参数
  24. total_train_step = 0 # 记录训练的次数
  25. total_test_step = 0 # 记录测试的次数
  26. epoch = 10 # 训练的轮数
  27. # 添加TensorBoard
  28. writer = SummaryWriter('../logs')
  29. for i in range(epoch):
  30. print('-----第 {} 轮训练开始-----'.format(i+1))
  31. # 训练步骤开始
  32. OW.train()
  33. for data in train_dataloader:
  34. imgs, targets = data
  35. outputs = OW(imgs)
  36. loss = loss_function(outputs, targets) # 输出与target计算loss
  37. # 优化器优化模型
  38. optimizer.zero_grad() # 梯度清零:把上一步训练的每个参数的梯度清零
  39. loss.backward() # 反向传播:调用反向传播得到每个要更新参数的梯度
  40. optimizer.step() # 参数优化:每个参数根据上一步得到的梯度进行优化
  41. total_train_step = total_train_step + 1
  42. if total_train_step % 100 == 0: # 每100次才打印
  43. print('训练次数:{},Loss:{}'.format(total_train_step, loss.item()))
  44. # 画train_loss
  45. writer.add_scalar('train_loss', loss.item(), total_train_step)
  46. # 测试步骤开始(评估模型)
  47. OW.eval()
  48. # 初始化测试集上的总损失和总准确率
  49. total_test_loss = 0
  50. total_accuracy = 0
  51. with torch.no_grad(): # 无需梯度调优
  52. for data in test_dataloader:
  53. imgs, targets = data
  54. outputs = OW(imgs)
  55. loss = loss_function(outputs, targets)
  56. total_test_loss = total_test_loss + loss.item()
  57. accuracy = (outputs.argmax(1) == targets).sum() # 得到预测正确的样本数量
  58. total_accuracy = total_accuracy + accuracy
  59. print('整体测试集上的Loss:{}'.format(total_test_loss))
  60. print('整体测试集上的正确率:{}'.format(total_accuracy/test_data_size))
  61. # 画test_accuracy & test_loss
  62. writer.add_scalar('test_accuracy', total_accuracy/test_data_size, total_test_step)
  63. writer.add_scalar('test_loss', total_test_loss, total_test_step)
  64. total_test_step = total_test_step + 1
  65. # 保存模型
  66. torch.save(OW, 'OW_{}.pth'.format(i)) # 每一轮保存一个结果
  67. # torch.save(OW.state_dict,'OW_{}.pth'.format(i)) save2
  68. print('模型已保存')
  69. writer.close()

总结:

准备数据→加载数据→准备模型→设置损失函数→设置优化器→开始训练→最后验证→结果聚合展示

利用GPU训练

方式一

网络模型: 

数据(包括输入、标注):

训练过程

损失函数:

更好的写法:这种写法在CPU和GPU上都可以跑,优先在GPU上跑

比较CPU/GPU训练时间 

为了比较时间,引入 time 这个 package

 

方式二(更常用)


以下两种写法对于单显卡来说等价:

  1. device = torch.device("cuda")
  2. device = torch.device("cuda:0")

语法糖(一种语法的简写),程序在 CPU 或 GPU/cuda 环境下都能运行: 

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

通过这个变量可以控制是在CPU上运行还是GPU(改成 "cuda" 或 "cuda:0" )上运行

  1. OW = OW.to(device)
  2. loss_function.to(device)
  3. imgs = imgs.to(device)
  4. targets = targets.to(device)
train_gpu.py
  1. from model import * # 引入模型
  2. import torch
  3. import time
  4. import torchvision.datasets
  5. from torch import nn
  6. from torch.utils.data import DataLoader
  7. from torch.utils.tensorboard import SummaryWriter
  8. # 定义训练设备
  9. device = torch.device('cuda')
  10. # 准备数据集,CIFAR10数据集是PIL Image,要转换为tensor数据类型
  11. train_data = torchvision.datasets.CIFAR10('../data', train=True, transform=torchvision.transforms.ToTensor(), download=True)
  12. test_data = torchvision.datasets.CIFAR10('../data', train=False, transform=torchvision.transforms.ToTensor(), download=True)
  13. # 查看训练数据集和测试数据集数量
  14. train_data_size = len(train_data)
  15. test_data_size = len(test_data)
  16. print('训练数据集长度为:{}'.format(train_data_size))
  17. print('测试数据集长度为:{}'.format(test_data_size))
  18. # 利用DataLoader加载数据集
  19. train_dataloader = DataLoader(train_data, batch_size=64)
  20. test_dataloader = DataLoader(test_data, batch_size=64)
  21. # 创建网络模型
  22. OW = Overwatch()
  23. # 将OW送给device
  24. OW = OW.to(device)
  25. # 损失函数
  26. loss_function = nn.CrossEntropyLoss()
  27. loss_function.to(device)
  28. # 优化器
  29. learning_rate = 0.01
  30. optimizer = torch.optim.SGD(OW.parameters(), lr=learning_rate)
  31. # 设置训练网络的参数
  32. # 记录训练的次数
  33. total_train_step = 0
  34. # 记录测试的次数
  35. total_test_step = 0
  36. # 训练的轮数
  37. epoch = 10
  38. # 添加TensorBoard
  39. writer = SummaryWriter('../logs')
  40. start_time = time.time() # 记录下此时的时间,赋值给开始时间
  41. for i in range(epoch):
  42. print('-----第 {} 轮训练开始-----'.format(i+1))
  43. # 训练步骤开始
  44. OW.train()
  45. for data in train_dataloader:
  46. imgs, targets = data
  47. imgs = imgs.to(device)
  48. targets = targets.to(device)
  49. outputs = OW(imgs)
  50. loss = loss_function(outputs, targets) # 输出与target计算loss
  51. # 优化器优化模型
  52. optimizer.zero_grad() # 梯度清零:把上一步训练的每个参数的梯度清零
  53. loss.backward() # 反向传播:调用反向传播得到每个要更新参数的梯度
  54. optimizer.step() # 参数优化:每个参数根据上一步得到的梯度进行优化
  55. total_train_step = total_train_step + 1
  56. if total_train_step % 100 == 0: # 每100次才打印
  57. end_time = time.time()
  58. print(end_time - start_time) # 第一次训练100次所花费的时间
  59. print('训练次数:{},Loss:{}'.format(total_train_step, loss.item()))
  60. # 画train_loss
  61. writer.add_scalar('train_loss', loss.item(), total_train_step)
  62. # 测试步骤开始(评估模型)
  63. # 初始化测试集上的总损失和总准确率
  64. OW.eval()
  65. total_test_loss = 0
  66. total_accuracy = 0
  67. with torch.no_grad(): # 无需梯度调优
  68. for data in test_dataloader:
  69. imgs, targets = data
  70. imgs = imgs.to(device)
  71. targets = targets.to(device)
  72. outputs = OW(imgs)
  73. loss = loss_function(outputs, targets)
  74. total_test_loss = total_test_loss + loss.item()
  75. accuracy = (outputs.argmax(1) == targets).sum() # 得到预测正确的样本数量
  76. total_accuracy = total_accuracy + accuracy
  77. print('整体测试集上的Loss:{}'.format(total_test_loss))
  78. print('整体测试集上的正确率:{}'.format(total_accuracy/test_data_size))
  79. # 画test_accuracy & test_loss
  80. writer.add_scalar('test_accuracy', total_accuracy/test_data_size, total_test_step)
  81. writer.add_scalar('test_loss', total_test_loss, total_test_step)
  82. total_test_step = total_test_step + 1
  83. # 保存模型
  84. torch.save(OW, 'OW_{}.pth'.format(i)) # 每一轮保存一个结果
  85. # torch.save(OW.state_dict,'OW_{}.pth'.format(i)) save2
  86. print('模型已保存')
  87. writer.close()


模型验证(demo)套路

核心:利用已经训练好的模型,给它提供输入进行测试

注意:load的模型当时保存的时候是用gpu训练的,因此这里需要定义device到cuda,再把image进行to(device)操作:device = torch.device('cuda')、image = image.to(device)

或者 model =torch.load("OW_30.pth",map_location=torch.device('cpu'))

采用GPU训练的模型,在CPU上加载,要从GPU上映射到CPU上

模型要求是四维的输入 [batch_size,channel,length,width],但是获得的图片是三维的 —— 图片没有指定 batch_size(网络训练过程中是需要 batch_size 的,而图片输入是三维的,需要reshape() 一下)

test.py:

  1. import torch
  2. import torchvision.transforms
  3. from PIL import Image
  4. # from model import *
  5. # device = torch.device('cuda')
  6. image_path = '../imgs/dog.png' # 或绝对路径
  7. image = Image.open(image_path)
  8. print(image)
  9. image = image.convert('RGB')
  10. '''因为png格式是四通道,除了RGB三通道外,还有一个透明度通道,所以要调用上述语句保留其颜色通道
  11. 如果图片本来就是三颜色通道,经过此操作,不变。加上这一步后,可以适应 png jpg 各种格式的图片'''
  12. # 网络模型的输入只能是32x32,进行一个Resize()
  13. transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)), # 32x32大小的PIL Image
  14. torchvision.transforms.ToTensor()]) # 转为Tensor数据类型
  15. image = transform(image)
  16. print(image.shape) # torch.Size([3, 32, 32])
  17. # model = torch.load('OW_9.pth')
  18. model =torch.load("OW_9.pth",map_location=torch.device('cpu'))
  19. print(model)
  20. image = torch.reshape(image,(1, 3, 32, 32))
  21. # image = image.to(device)
  22. model.eval() # 模型转化为测试类型
  23. with torch.no_grad(): # 节约内存和性能
  24. output = model(image)
  25. print(output)
  26. print(output.argmax(1))

CIFAR10 对应的真实类别:

  

 

GitHub

下载代码用 PyCharm 打开后,查看代码里有没有 required=True,若有,删掉 required=True ,加一个默认值 default="./dataset/maps" ,就可以在 PyCharm 里右键运行了

即找到所有 required=True 的参数,将它删去并添加上默认值default 

 required的意思就是执行代码的时候需要手动输入文件目录,改为默认之后就不用再输入了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/955457
推荐阅读
相关标签
  

闽ICP备14008679号