微分接口适配
方式一 适配MindSpore框架原生微分接口
由于MindSpore的自动微分采用函数式表达,和PyTorch的微分接口存在差异,目前需要用户手动适配训练部分的少量代码,即将PyTorch版本的训练流程代码转换为MindSpore的函数式编程写法,从而使能MindSpore动静统一、自动并行等竞争力功能。详细内容可参考MindSpore使用文档。以下示例展示了如何将PyTorch训练流程转换为MindSpore函数式训练流程:
迁移前网络表达:
net = LeNet().to(config_args.device)
optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=0.0005)
net.train()
# 数据迭代训练
for i in range(epochs):
for X, y in train_data:
X, y = X.to(config_args.device), y.to(config_args.device)
out = net(X)
loss = criterion(out, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("------>epoch:{}, loss:{:.6f}".format(i, loss))
替换为Mindspore函数式迭代训练表达,其中前向过程通常包含了模型网络接口调用
以及损失函数调用
,反向求导过程包含了反向梯度接口调用
以及优化器接口调用
部分,此外,MindSpore不需要调用loss.backward()
以及optimizer.zero_grad()
,具体示例如下:
import mindtorch.torch as torch
import mindspore as ms
net = LeNet().to(config_args.device)
optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=0.0005)
# 定义前向过程
def forward_fn(data, label):
logits = net(data)
loss = criterion(logits, label)
return loss, logits
# 反向梯度定义
grad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
# 单步训练定义
def train_step(data, label):
(loss, _), grads = grad_fn(data, label)
optimizer(grads)
return loss
net.train()
# 数据迭代训练
for i in range(epochs):
for X, y in train_data:
X, y = X.to(config_args.device), y.to(config_args.device)
res = train_step(X, y)
print("------>epoch:{}, loss:{:.6f}".format(i, res.numpy()))
方式二 使用Tensor.backward对标接口(实验功能)
当前MindTorch正在开发对标Tensor.backward()
接口功能,用户无需修改迁移前torch源码,迁移效率更高。需要注意的是,该功能当前为实验特性,存在如下使用约束:
须用户配置环境变量
export ENABLE_BACKWARD=1
主动使能;在动态图模式下使用;
目前仅支持 Python3.7和 Python3.9环境下使用;
可能存在少数使用场景报错;
网络执行性能可能变慢。
功能泛化性和性能正在完善中,如果使用过程中遇到问题,可以通过创建ISSUE 向我们反馈,我们会优先支持。