梯度累加场景
梯度累加场景是每计算一个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') # 用户请自行定义训练设备
...... # 如样例代码所示,定义一个简单的神经网络
定义训练参数和数据
这一部分我们从torchvision中获取训练数据集,设置训练相关的参数batch_size、epochs,并在模型、优化器定义之后,定义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功能相关的代码开启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计数
父主题: 使用示例