昇腾社区首页
中文
注册

模型迁移训练

本节提供了一个简单的模型迁移样例,采用了最简单的自动迁移方法,帮助用户快速体验GPU模型脚本迁移到昇腾NPU上的流程。基于CNN模型识别手写数字的脚本,对在GPU上训练的该脚本代码进行修改,使其可以迁移到昇腾NPU上进行训练。

  1. 新建脚本train.py,写入以下原GPU脚本代码。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    # 引入模块
    import time
    import torch
    import torch.nn as nn
    from torch.utils.data import Dataset, DataLoader
    import torchvision
    
    # 初始化运行device
    device = torch.device('cuda:0')   
    
    # 定义模型网络
    class CNN(nn.Module):
        def __init__(self):
            super(CNN, self).__init__()
            self.net = nn.Sequential(
                # 卷积层
                nn.Conv2d(in_channels=1, out_channels=16,
                          kernel_size=(3, 3),
                          stride=(1, 1),
                          padding=1),
                # 池化层
                nn.MaxPool2d(kernel_size=2),
                # 卷积层
                nn.Conv2d(16, 32, 3, 1, 1),
                # 池化层
                nn.MaxPool2d(2),
                # 将多维输入一维化
                nn.Flatten(),
                nn.Linear(32*7*7, 16),
                # 激活函数
                nn.ReLU(),
                nn.Linear(16, 10)
            )
        def forward(self, x):
            return self.net(x)
    
    # 下载数据集
    train_data = torchvision.datasets.MNIST(
        root='mnist',
        download=True,
        train=True,
        transform=torchvision.transforms.ToTensor()
    )
    
    # 定义训练相关参数
    batch_size = 64   
    model = CNN().to(device)  # 定义模型
    train_dataloader = DataLoader(train_data, batch_size=batch_size)    # 定义DataLoader
    loss_func = nn.CrossEntropyLoss().to(device)    # 定义损失函数
    optimizer = torch.optim.SGD(model.parameters(), lr=0.1)    # 定义优化器
    epochs = 10  # 设置循环次数
    
    # 设置循环
    for epoch in range(epochs):
        for imgs, labels in train_dataloader:
            start_time = time.time()    # 记录训练开始时间
            imgs = imgs.to(device)    # 把img数据放到指定NPU上
            labels = labels.to(device)    # 把label数据放到指定NPU上
            outputs = model(imgs)    # 前向计算
            loss = loss_func(outputs, labels)    # 损失函数计算
            optimizer.zero_grad()
            loss.backward()    # 损失函数反向计算
            optimizer.step()    # 更新优化器
    
    # 定义保存模型
    torch.save({
                   'epoch': 10,
                   'arch': CNN,
                   'state_dict': model.state_dict(),
                   'optimizer' : optimizer.state_dict(),
                },'checkpoint.pth.tar')
    
  2. 在train.py中添加以下加粗部分库代码。
    • 若用户使用 Atlas 训练系列产品 ,则在迁移完成、训练开始之前,由于其架构特性需要,用户需要开启混合精度。
    • 若用户使用 Atlas A2 训练系列产品 Atlas A3 训练系列产品 ,则可以自行选择是否开启混合精度。

    具体介绍可参见《PyTorch 训练模型迁移调优指南》中的“(可选)混合精度适配”章节

    import time
    import torch
    ......
    import torch_npu
    from torch_npu.npu import amp # 导入AMP模块
    from torch_npu.contrib import transfer_to_npu    # 使能自动迁移

    若未使能自动迁移,用户可参考《PyTorch 训练模型迁移调优指南》中的“手工迁移”章节进行相关操作。

  3. 使能AMP混合精度计算。若用户使用 Atlas A2 训练系列产品 Atlas A3 训练系列产品 ,则可以选择跳过此步骤。
    在模型、优化器定义之后,定义AMP功能中的GradScaler。
    ......
    loss_func = nn.CrossEntropyLoss().to(device)    # 定义损失函数
    optimizer = torch.optim.SGD(model.parameters(), lr=0.1)    # 定义优化器
    scaler = amp.GradScaler()    # 在模型、优化器定义之后,定义GradScaler
    epochs = 10
    删除以下加粗部分的原GPU脚本代码。
    ......
    for epoch in range(epochs):
        for imgs, labels in train_dataloader:
            start_time = time.time()    # 记录训练开始时间
            imgs = imgs.to(device)    # 把img数据放到指定NPU上
            labels = labels.to(device)    # 把label数据放到指定NPU上
            outputs = model(imgs)    # 前向计算
            loss = loss_func(outputs, labels)    # 损失函数计算
            optimizer.zero_grad()
            loss.backward()    # 损失函数反向计算
            optimizer.step()    # 更新优化器

    添加以下加粗部分代码开启AMP。

    ......
    for i in range(epochs):
        for imgs, labels in train_dataloader:
            imgs = imgs.to(device)
            labels = labels.to(device)
            with amp.autocast():
                outputs = model(imgs)    # 前向计算
                loss = loss_func(outputs, labels)    # 损失函数计算
            optimizer.zero_grad()
            # 进行反向传播前后的loss缩放、参数更新
            scaler.scale(loss).backward()    # loss缩放并反向传播
            scaler.step(optimizer)    # 更新参数(自动unscaling)
            scaler.update()    # 基于动态Loss Scale更新loss_scaling系数
  4. 执行命令启动训练脚本(命令脚本名称可根据实际修改)。
    python3 train.py

    训练结束后生成如下图权重文件,则说明迁移训练成功。