适配样例(梯度累加场景)

梯度累加场景是每计算一个batch的梯度后,进行梯度的累加而不是清零,当累加到一定次数再更新参数、清零梯度的场景。梯度累加可以在不显著增加显存消耗的情况下,获得使用更大batch size进行训练的效果。

导入AMP模块

在构建神经网络前,我们需要torch_npu中导入AMP模块。

import time 
import torch 
import torch.nn as nn 
import torch_npu 
from torch_npu.npu import amp    # 导入AMP模块 
from torch.utils.data import Dataset, DataLoader 
import torchvision 
 
device = torch.device('npu:0')    # 用户请自行定义训练设备 
...... # 如样例代码所示,定义一个简单的神经网络

定义损失缩放参数

在模型、优化器定义之后,定义AMP功能中的GradScaler。

# 数据集获取 
train_data = torchvision.datasets.MNIST( 
    root = 'mnist', 
    download = True, 
    train = True, 
    transform = torchvision.transforms.ToTensor() 
) 
# 定义训练相关参数 
batch_size = 64 
train_dataloader = DataLoader(train_data, batch_size=batch_size)    # 定义DataLoader 
model = CNN().to(device)     # 把模型放到指定NPU上 
loss_func = nn.CrossEntropyLoss().to(device)    # 定义损失函数 
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)    # 定义优化器 
scaler = amp.GradScaler()    # 在模型、优化器定义之后,定义GradScaler 
epochs = 10 # 设置循环次数

适配AMP并训练

在训练代码中添加AMP功能适配代码。最后运行整个脚本进行混合精度训练。

iters_to_accumulate = 8    # 设置梯度累加多少个step后更新参数、清零。用户请根据自己的模型实际情况设置。 
for epoch in range(epochs): 
    i = 0 
    for imgs, labels in train_dataloader: 
        imgs = imgs.to(device)     # 把img数据放到指定NPU上 
        labels = labels.to(device) # 把label数据放到指定NPU上 
        with amp.autocast():   # 设置amp 
            outputs = model(imgs)    # 前向计算 
            loss = loss_func(outputs, labels)    # 损失函数计算 
            loss = loss / iters_to_accumulate 
        # 进行反向传播前后的loss缩放、参数更新 
        scaler.scale(loss).backward()    # loss缩放并反向转播 
        if (i + 1) % iters_to_accumulate == 0:    # 在达到设置好的step数之后更新参数、清零梯度 
            scaler.step(optimizer)    # 更新参数(自动unscaling) 
            scaler.update()    # 基于动态Loss Scale更新loss_scaling系数 
            optimizer.zero_grad()    # 梯度清零 
        i + = 1    #step计数