• Pytorch网络模型训练


    现有网络模型的使用与修改

    1. vgg16_false = torchvision.models.vgg16(pretrained=False) # 加载一个未预训练的模型
    2. vgg16_true = torchvision.models.vgg16(pretrained=True)
    3. # 把数据分为了1000个类别
    4. print(vgg16_true)

    以下是vgg16预训练模型的输出 

    1. VGG(
    2. (features): Sequential(
    3. (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    4. (1): ReLU(inplace=True)
    5. (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    6. (3): ReLU(inplace=True)
    7. (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    8. (5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    9. (6): ReLU(inplace=True)
    10. (7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    11. (8): ReLU(inplace=True)
    12. (9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    13. (10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    14. (11): ReLU(inplace=True)
    15. (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    16. (13): ReLU(inplace=True)
    17. (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    18. (15): ReLU(inplace=True)
    19. (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    20. (17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    21. (18): ReLU(inplace=True)
    22. (19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    23. (20): ReLU(inplace=True)
    24. (21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    25. (22): ReLU(inplace=True)
    26. (23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    27. (24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    28. (25): ReLU(inplace=True)
    29. (26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    30. (27): ReLU(inplace=True)
    31. (28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    32. (29): ReLU(inplace=True)
    33. (30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
    34. )
    35. (avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
    36. (classifier): Sequential(
    37. (0): Linear(in_features=25088, out_features=4096, bias=True)
    38. (1): ReLU(inplace=True)
    39. (2): Dropout(p=0.5, inplace=False)
    40. (3): Linear(in_features=4096, out_features=4096, bias=True)
    41. (4): ReLU(inplace=True)
    42. (5): Dropout(p=0.5, inplace=False)
    43. (6): Linear(in_features=4096, out_features=1000, bias=True)
    44. )
    45. )

    预训练模型的输出从1000类别转为10类别

    1. import torchvision
    2. from torch import nn
    3. # 因为数据集过大,所以注释掉此行代码
    4. # train_data = torchvision.datasets.ImageNet("./data_image_net", split='train', download=True,
    5. # transform=torchvision.transforms.ToTensor())
    6. vgg16_false = torchvision.models.vgg16(pretrained=False) # 加载一个未预训练的模型
    7. vgg16_true = torchvision.models.vgg16(pretrained=True)
    8. # 把数据分为了1000个类别
    9. print(vgg16_true)
    10. # vgg16_true.add_module("add_linear", nn.Linear(1000, 10))
    11. vgg16_true.classifier.add_module("add_linear", nn.Linear(1000, 10))
    12. # 在预训练模型的最后添加了一个新的全连接层,用于将最后的输出转化为10个类别
    13. print(vgg16_true)
    14. print(vgg16_false)
    15. vgg16_false.classifier[6] = nn.Linear(4096, 10)
    16. # 未预训练模型的最后一层的输出特征数更改为了10
    17. print(vgg16_false)

    网络模型的保存与读取

    加载未预训练的模型

    vgg16 = torchvision.models.vgg16(pretrained=False)

    方式一

    1. # 保存方式1 保存的模型结构+模型参数
    2. torch.save(vgg16, "vgg16_method1.pyth")
    3. #读取方式1
    4. model = torch.load("vgg16_method1.pth")

    方式二

    1. # 保存方式2 不再保存模型结构,而是保存模型的参数为字典结构 推荐
    2. torch.save(vgg16.state_dict(), "vgg16_method2.pyth")
    3. # 方式2,加载模型
    4. # model = torch.load("vgg16_method2.pth") #这样输出的是字典类型
    5. # print(model)
    6. vgg16 = torchvision.models.vgg16(pretrained=False)
    7. vgg16.load_state_dict(torch.load("vgg16_method2.pth")) # 将其恢复为网络模型
    8. print(vgg16)

    完整的模型训练套路

    准备数据集

    1. # 准备数据集
    2. train_data = torchvision.datasets.CIFAR10("../data", train=True, transform=torchvision.transforms.ToTensor(),
    3. download=True)
    4. test_data = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(),
    5. download=True)
    6. train_data_size = len(train_data)
    7. test_data_size = len(test_data)
    8. print("训练数据集的长度为{}".format(train_data_size)) # 50000
    9. print("测试数据集的长度为{}".format(test_data_size)) # 10000
    10. # 利用Dataloader来加载数据集
    11. train_dataloader = DataLoader(train_data, batch_size=64)
    12. test_dataloader = DataLoader(test_data, batch_size=64)

    创建网络模型

    1. # 创建网络模型 神经网络的代码在train_module文件
    2. tudui = Tudui()

    train_module文件

    1. # 搭建神经网络
    2. class Tudui(nn.Module):
    3. def __init__(self):
    4. super(Tudui, self).__init__()
    5. # 简化操作,并且按顺序进行操作
    6. self.model1 = Sequential(
    7. Conv2d(3, 32, 5, padding=2),
    8. MaxPool2d(2),
    9. Conv2d(32, 32, 5, padding=2),
    10. MaxPool2d(2),
    11. Conv2d(32, 64, 5, padding=2),
    12. MaxPool2d(2),
    13. Flatten(),
    14. Linear(1024, 64),
    15. Linear(64, 10)
    16. )
    17. def forward(self, x):
    18. x = self.model1(x)
    19. return x

    构建损失函数

    1. # 损失函数
    2. loss_fn = nn.CrossEntropyLoss()

    构建优化器

    1. # 优化器
    2. # 如果学习率过大,模型可能会在最小值附近震荡而无法收敛;如果学习率过小,模型训练可能会过于缓慢
    3. learning_rate = 0.01
    4. # 使用随机梯度下降算法来更新模型的权重
    5. optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)

    设置训练集参数

    1. # 记录训练的次数
    2. total_train_step = 0
    3. # 记录测试的次数
    4. total_test_step = 0
    5. # 训练的轮数
    6. epoch = 10

    添加tensorboard

    1. # 将数据写入 TensorBoard 可视化的日志文件中
    2. writer = SummaryWriter("../logs_train")

    训练步骤

    1. # tudui.train()
    2. for data in train_dataloader:
    3. imgs, targets = data
    4. outputs = tudui(imgs)
    5. loss = loss_fn(outputs, targets)
    6. # 优化器优化模型
    7. optimizer.zero_grad()
    8. # 将优化器中的梯度缓存(如果有的话)清零
    9. loss.backward()
    10. # 计算损失函数(loss)相对于模型参数的梯度
    11. optimizer.step()
    12. total_train_step = total_train_step + 1
    13. if total_train_step % 100 == 0:
    14. # .item()是将tensor张量变为正常的数字
    15. print("训练次数:{},Loss:{}".format(total_train_step, loss.item()))
    16. # loss.item()是当前步骤的损失值
    17. writer.add_scalar("train_loss", loss.item(), total_train_step)
    18. # 使用add_scalar可以将一个标量添加到之前的所有标量值中,
    19. # 这样就可以在TensorBoard中绘制一个标量随时间变化的图表

    测试步骤

    1. # 测试步骤开始
    2. # tudui.eval()
    3. total_test_loss = 0
    4. total_accuracy = 0
    5. # 不会对以下的代码进行调优
    6. with torch.no_grad():
    7. for data in test_dataloader:
    8. imgs, targets = data
    9. outputs = tudui(imgs)
    10. loss = loss_fn(outputs, targets)
    11. total_test_loss = total_test_loss + loss.item()
    12. # argmax(1)是横向看,argmax(0)是纵向看
    13. accuracy = (outputs.argmax(1) == targets).sum()
    14. # argmax在找到模型预测的最大概率对应的类别
    15. # 预测正确的个数
    16. total_accuracy = total_accuracy + accuracy
    17. print("整体测试集上的Loss:{}".format(total_test_loss))
    18. print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    19. # 测试集上的总损失
    20. writer.add_scalar("test_loss", total_test_loss, total_test_step)
    21. writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    22. total_test_step = total_test_step + 1

    利用GPU训练

    1. # 定义训练的设备
    2. # device = torch.device("cpu/cuda")
    3. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    4. # GPU训练的关键
    5. tudui = tudui.cuda()
    6. # tudui = tudui.to(device)

  • 相关阅读:
    如何实现点击消息并刷新成消息置顶?
    vue.js 生命周期
    ROS action客户端和服务端通信(Ubuntu )
    一个支持IPFS的电子邮件——SKIFF
    Django笔记十二之defer、only指定返回字段
    [MAUI]模仿iOS多任务切换卡片滑动的交互实现
    九宫格抽奖动效
    设计模式——9. 桥接模式
    机器人操作系统ROS(19) 雷达和摄像头融合的资料
    pytest之fixture
  • 原文地址:https://blog.csdn.net/qq_47896523/article/details/134203988