深度学习:昇思MindSpore生态桥接工具——MindTorch实践

MindTorch入门

MindTorch是一款将PyTorch训练脚本高效迁移至MindSpore框架执行的实用工具,旨在不改变原生PyTorch用户的编程使用习惯下,使得PyTorch风格代码能在昇腾硬件上获得高效性能。用户只需要在PyTorch源代码主入口调用torch系列相关的包导入部分(如torch、torchvision等)之前调用from mindtorch.tools import mstorch_enable,加上少量训练代码适配即可实现模型在昇腾硬件上的训练。

官网链接:序言 — MindTorch dev 文档

MindTorch安装

通过pip安装稳定版本

pip install mindtorch

通过源码安装(开发版本)

git clone https://git.openi.org.cn/OpenI/MSAdapter.git
cd MSAdapter
python setup.py install

快速使用

在pytorch代码执行的主文件入口,import torch前,加入语句:

from mindtorch.tools import mstorch_enable

即可实现快速迁移

MindTorch进阶

MindTorch优化器与学习率适配

1. 打印学习率差异

PyTorch代码

import torch
optimizer = torch.optim.SGD([torch.nn.Parameter(torch.tensor(2.))], lr=0.01)
print('lr is {}'.format(optimizer.param_groups[0]['lr']))

 MindTorch代码

import mindtorch as torch
optimizer = torch.optim.SGD([torch.nn.Parameter(torch.tensor(2.))], lr=0.01)
print('lr is {}'.format(float(optimizer.param_groups[0]['lr'])))

需要将学习率转为Number类型。

2. 修改学习率差异

动态图模式下,与PyTorch代码没有差异。

静态图模式下,只能使用mindspore.ops.assign的方式修改学习率。

import mindspore
import mindspore as torch
optimizer = torch.optim.SGD([torch.nn.Parameter(torch.tensor(2.))], lr=0.01)
# 需要使用mindspore.ops.assign方式修改学习率
mindspore.ops.assign(optimizer.param_groups[0]['lr'], 0.1)

3. optimizer.step()的入参差异

PyTorch代码

...
net = Net()
loss = net(input)
loss.backward()
optimizer.step()

MindTorch代码

import mindspore
import mindspore.torch as torch...
net = Net()
grad_fn = mindspore.ops.value_and_grad(net, None, optimizer.parameters)
grads = grad_fn(input) # 通过value_and_grad接口求梯度
optimizer.step(grads) # 需要将计算出的梯度grads作为参数传入step函数中

调用optimizer.step时仍需将梯度作为入参传入。

4. 自定义优化器差异

PyTorch代码

import torch
class Ranger(torch.optim.Optimizer):def __init__(self, params, lr=1e-3. aplpha=0.5, k=6):defaults = dict(lr=lr, alpha=alpha)super().__init__(params, defaults)self.k = kdef __setstate__(self, state):print('set state called')super().__setstate__(state)def step(self, closure=None):loss = Nonefor group in self.param_groups:for p in group['params']:if p.grad is None:continuegrad = p.grad.data.float()p_data_fp32 = p.data.float()state = self.state[p]state['step'] += 1p+data_fp_32.add_(grad)p.data.copy_(p_data_fp32)return loss

MindTorch代码

import mindtorch.torch as torch
class Ranger(torch.optim.Optimizer):def __init__(self, params, lr=1e-3. aplpha=0.5, k=6):defaults = dict(lr=lr, alpha=alpha)super().__init__(params, defaults)self.k = kdef __setstate__(self, state):print('set state called')super().__setstate__(state)def step(self, grads, closure=None): # 需要新增grads作为参数以传入梯度loss = Nonei = -1 # 声明索引来遍历grads入参for group in self.param_groups:for p in group['params']:i = i + 1 # 索引递增grad = grads[i]p_data_fp32 = p.data.float()state = self.state[p]state['step'] += 1p+data_fp_32.add_(grad)p.data.copy_(p_data_fp32)return loss

需要新增grads作为step函数输入

5. 自定义LRScheduler

动态图下修改方式与PyTorch一致。

静态图下需要对mindspore.ops.assign对学习率进行修改以保证优化器中学习率一直是Parameter类型。

class TransformerLrScheduler():def __init__(self, optimizer, d_model, warmup_steps, multiplier=5):self._optimizer = optimizerself.d_model = d_modelself.warmup_steps = warmup_stepsself.n_steps = 0self.multiplier = multiplierdef step(self):self.n_steps += 1lr = self._get_lr()for param_group in self._optimizer.param_groups:mindspore.ops.assign(param_group['lr'], lr)def _get_lr(self):return self.multiplier * (self.d_model ** -0.5) * min(self.n_steps ** (-0.5))

MindTorch微分接口适配

方式一

PyTorch代码

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()

MindTorch代码

import mindtorch.torch as torch
import mindspore as msnet = 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# 定义反向求导过程:包含了前向函数和参数
'''
mindspore.value_and_grad:生成求导函数,用于计算给定函数的正向计算结果和梯度。
函数求导包含以下三种场景:对输入求导,此时 grad_position 非None,而 weights 是None;对网络变量求导,此时 grad_position 是None,而 weights 非None;同时对输入和网络变量求导,此时 grad_position 和 weights 都非None。weights (Union[ParameterTuple, Parameter, list[Parameter]]) - 训练网络中需要返回梯度的网络变量。一般可通过 weights = net.trainable_params() 获取。默认值: None 。has_aux (bool) - 是否返回辅助参数的标志。若为 True , fn 输出数量必须超过一个,其中只有 fn 第一个输出参与求导,其他输出值将直接返回。'''
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 lossnet.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)

方式二

MindTorch正在开发对标Tensor.backward()接口功能,用户无需修改迁移前torch源码,迁移效率更高。需要注意的是,该功能当前为实验特性,存在如下使用约束:

  • 须用户配置环境变量export ENABLE_BACKWARD=1;
  • 在动态图模式下使用ms.set_context(mode=PYNATIVE_MODE);
  • 目前仅支持 Python3.7和 Python3.9环境下使用;
  • 可能存在少数使用场景报错;
  • 网络执行性能可能变慢。

MindTorch混合精度训练与适配

混合精度训练(Mixed Precision Training)是一种在深度学习模型训练中使用不同精度浮点数的技术,旨在充分利用低精度计算的优势,同时保持模型的数值稳定性和准确性。具体来说,混合精度训练通常结合了单精度浮点数(Float32)和半精度浮点数(Float16)。

基本原理

  1. 前向传播和反向传播

    • 前向传播:大部分计算使用半精度浮点数(Float16)进行,以减少内存占用和加快计算速度。
    • 反向传播:同样使用半精度浮点数进行梯度计算。
  2. 权重更新

    • 权重和梯度的存储使用单精度浮点数(Float32),以确保数值稳定性。
    • 在权重更新时,将半精度梯度转换为单精度,并与单精度权重进行更新。
  3. 损失缩放

    • 为了避免梯度下溢(即梯度过小而无法表示),通常会使用一种称为损失缩放的技术。损失缩放的基本思想是在反向传播之前将损失值乘以一个较大的常数(通常是2的幂次方),然后在更新权重之前再将梯度除以相同的常数。

PyTorch代码

from torch.cuda.amp import autocast, GradScalermodel = Net().cuda()
optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=0.0005)scaler = GradScaler()model.train()for epoch in epochs:for inpus, target in data:optimizer.zero_grad()with autocast():output = model(input)loss = loss_fn(output, target)# 损失缩放loss = scaler.scale(loss)loss.backward()# 反向缩放梯度scaler.unscale_(optimizer)# 梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)# 梯度更新scaler.step(optimizer) scaler.update()

MindTorch代码

import mindtorch.torch as torch
from mindtorch.torch.cuda.amp import GradScaler
from mindspore.amp import auto_mixed_precisionmodel = Net().cuda()
optimizer = torch.optim.SGD(net.parameters(), lr=0.01, momentum=0.9, weight_decay=0.0005)scaler = GradScaler()# model方法调用需要放在混合精度模型转换前
model.train()
# model为混合精度模型,需要对输出的tensor进行类型转换
model = auto_mixed_precision(model, '03') # 03为昇腾环境 02为GPUdef forward_fn(data, target):logits = model(data)logits = torch.cast_tp_adapter_tensor(logits)loss = criterion(logits, target)loss = scaler.scale(loss) # 损失缩放return lossgrad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters)def train_step(data, target):loss, grads = grad_fn(data, target)return loss, gradsfor epoch in epochs:for inputs, target in data:loss, grads = train_step(inputs, target)scaler.unscale_(optimizer, grads) # 反向缩放梯度grads = ms.ops.clip_by_global_norm(grads, max_norm) # 梯度裁剪scaler.step(optimizer, grads) # 梯度更新scaler.update() # 更新参数
  1. 调用auto_mixed_precision自动生成混合精度模型,如果 需要调用原始模型的方法请在混合精度模型生成前执行,如 model.train();
  2. 如果后续有对网络输出Tensor的操作,需调用 cast_to_adapter_tensor手动将输出Tensor转换为MindTorch Tensor。
  3. 调用GradScaler对梯度进行缩放时,由于自动微分机制和 接口区别,unscale_和step等接口需要把梯度grads作为入参传入。

MindTorch使用MindSpore并行训练

MindTorch使用MindSpore数据并行

import mindtorch.torch as torch
from mindtorch.torch.utils.data import Dataloader, DistributedSampler
from mindspore.communication import init
import mindspore as msinit("hccl") # 初始化通信环境:“hccl"---Ascend,"nccl"---GPU,"mccl"---CPU
ms.set_auto_parallel_context(parallel mode=ms.Paral1e1Mode.DATA PARALLEL) # 配置数据并行模式torch.manual seed(1) #设置随机种子,使得每张卡上权重初始化值一样,便于收敛train_images = datasets.CIFAR10('./',train=True, download=True, transform=transform)
sampler = DistributedSampler(train_images)#分布式数据处理
train_data =  DataLoader(train_images, batch_size=32, num_workers=2, drop_last=True, sampler=sampler)def forward_fn(data,label):logits = net(data)loss = criterion(logits,label)return loss, logitsgrad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
grad_reducer= nn.DistributedGradReducer(optimizer.parameters) #定义分布式优化器def train_step(data,label):(loss,_), grads = grad_fn(data, label) # 确度聚合grads=grad_reducer(grads)optimizer(grads)return lossnet.train()
for i in range(epochs):for inputs, target in train_data:res = train_step(inputs, target)

MindTorch使用MindSpore自动并行

import mindtorch.torch as torch
from mindtorch.torch.utils.data import Dataloader, DistributedSampler
from mindspore.communication import init
import mindspore as ms# 自动并行仅支持静态图模式
ms.set_context(mode=ms.GRAPH_MODE, jit_syntax_level=True)
init("hccl") # 初始化通信环境:“hccl"---Ascend,"nccl"---GPU,"mccl"---CPU
ms.set_auto_parallel_context(parallel_mode=ms.Paral1e1Mode.AUTO_PARALLEL) # 配置数据并行模式torch.manual seed(1) #设置随机种子,使得每张卡上权重初始化值一样,便于收敛train_images = datasets.CIFAR10('./',train=True, download=True, transform=transform)
sampler = DistributedSampler(train_images) # 分布式数据处理
train_data =  DataLoader(train_images, batch_size=32, num_workers=2, drop_last=True, sampler=sampler)def forward_fn(data,label):logits = net(data)loss = criterion(logits,label)return loss, logitsgrad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)@ms.hit
def train_step(data,label):(loss,_), grads = grad_fn(data, label) # 确度聚合grads=grad_reducer(grads)optimizer(grads)return lossnet.train()
for i in range(epochs):for inputs, target in train_data:res = train_step(inputs, target)

MindTorch精度调优

Pytorch代码

import torch
from mindtorch.tools import debug_layer_infonet = Net()
net.load_state_dict(torch.load('pytorch.pth'))
net.eval()debug_layer_info(net, frame='pytorch')for X, y in data:pred = net(x)...exit()

MindSpore代码

import mindtorch.torch as torch
from mindtorch.tools import debug_layer_infonet = Net()
net.load_state_dict(torch.load('pytorch.pth'))
net.eval()debug_layer_info(net)for X, y in data:pred = net(X)...exit()

步骤 1:确保网络输入完全一致(可以使用固定的输入数据也可调用真实数据集)。

步骤 2:确保执行推理模式。

步骤 3:确保网络权重的一致性。

步骤 4:分别将PyTorch和MindTorch的模型推理结果打印出来进行比较,如果比较结果精度误差在1e-3范围内则表示迁移模型精度正常。

步骤 5:打印网络逐层信息协助定位精度异常。当出现网络输出误差过大情况,可以结合信息调试工具(debug_layer_info),检查各网络层输入输出的信息,便于快速定位导致精度异常的网络层,提升精度调试分析效率。同时也可以在动态图模式下基于关键位置添加断点,逐步缩小范围,直至明确误差是否合理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/14005.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL:left join后用on与where的区别

一、前言 前几天项目中,写SQL时本想通过 A left B join on and 后面的条件来使查出的两条记录变成一条,奈何发现还是有两条。在此记录一下,on与where的区别。 二、ON 原始数据展示 SELECT t1.*,t2.* FROM t_test_staff t1 left join t_te…

ANX9833FN-AA-R ANX9833 ANALOGIX QFN48 VGA视频转换器件

ANX9833概述:ANX9833是VGA显示接口适配器集成电路设计一个显示端口1.2/1.1源连接到一个VGA显示。与芯片上的单片机和记忆,ANX9833不需要任何外部配置或设置。它自动引导VGA显示接口适配器的输出,有效地处理所有类型的遗产显示器、投影仪,和电视。ANX9833提供Gbps带宽在两车道到…

2025全平台短剧系统 : 快手、抖音、微信全覆盖

之前,我曾详细阐述过公司短剧系统的一些功能,它们共同构建了一个全面、高效的短剧制作与运营平台。这些功能,无论是媒资管理、剧场设定,还是后期运营,都是经过深思熟虑、精心设计的,是一个成熟的短剧系统所…

机圈白刃战,vivo聚势成风

金秋十月,国产手机市场进入了空前激烈的竞争局势,几乎每天都有发布会,甚至隔段时间就有新机话题登上热搜。网友戏称,发布会密度高到“工作日都不够用了”。 10月14日,vivo X200系列率先登场,拉开了国产旗舰…

scp 或 ssh 报错no matching host key type found. Their offer: ssh-rsa 解决方案

报错如下: 解决方案: 在 scp 或 ssh 命令后面增加参数: -o HostKeyAlgorithmsssh-rsa 可以解决此问题, scp格式如下: scp -o HostKeyAlgorithmsssh-rsa [local_file_path] [user][hosts]:[remote_path]

ElasticSearch概述

ElasticSearch概述 Elaticsearch,简称为es, es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。es也使用Java开发并使…

一文彻底了解UDHCP源码核心☝️

🍄参考学习: udhcp源码剖析(一)——DHCP服务器和客户端的工作流程_udhcpc源码v1.29.2-CSDN博客 前言介绍 本文深入探讨了DHCP服务器和客户端的工作流程,以udhcp为例,详细阐述了udhcpd(服务器)…

开启鸿蒙开发之旅:静态页面搭建

写在前面 了解了一些常用的系统组件及其属性之后,我准备开始搭建我第一个页面,本次鸿蒙Next初体验我准备模仿这款“提醒事项”APP,从页面搭建到基本功能实现。今天从入口页开始: 布局思路 整体结构 从该页面的整体布局结构来看&…

C++20 STL CookBook 7 Containers(II)

让vector在插入删除的时候仍然保证是有序的 首先&#xff0c;STL的确提供了一种办法来检查我们的目标容器是不是有序的&#xff1a;std::is_sorted - cppreference.com&#xff0c;也就是std::is_sorted。我们当然可以这样做&#xff1a; #include <iostream> #include…

二叉树搜索树(下)

二叉树搜索树&#xff08;下&#xff09; 二叉搜索树key和key/value使用场景 key搜索场景 只有key作为关键码&#xff0c;结构中只需要存储key即可&#xff0c;关键码即为需要搜索到的值&#xff0c;搜索场景只需要判断 key在不在。key的搜索场景实现的二叉树搜索树支持增删查…

人力资源招聘系统-提升招聘效率与质量的关键工具

在当今这个竞争激烈的商业环境中&#xff0c;企业要想在市场中立于不败之地&#xff0c;关键在于拥有高素质的人才队伍。然而&#xff0c;传统的招聘方式往往效率低下&#xff0c;难以精准匹配企业需求与人才特质&#xff0c;这无疑给企业的发展带来了不小的挑战。 随着科技的飞…

【C++】类中的“默认成员函数“--构造、析构、赋值

目录 概念引入&#xff1a; 一、构造函数 问题引入&#xff1a; 1&#xff09;构造函数的概念 2&#xff09;构造函数的特性 二、析构函数 1&#xff09;析构函数概念 2&#xff09;析构函数特性 三、拷贝构造函数 1)拷贝构造函数概念 示例代码&#xff1a; 2)深拷…

环丙烷环辛炔聚乙二醇磷脂,淡黄色固体,BCN-PEG-DSPE

中文名称&#xff1a;环丙烷环辛炔聚乙二醇磷脂 英文名称&#xff1a;BCN-PEG-DSPE 外观&#xff1a;通常为黄色或淡黄色固体 材料来源&#xff1a;为华生物 溶解性&#xff1a;在有机溶剂&#xff08;如氯仿、乙醇&#xff09;中具有良好的溶解性&#xff0c;而在水中的溶…

202409电子学会青少年机器人技术等级考试(六级)理论综合真题

青少年机器人技术等级考试理论综合试卷&#xff08;六级&#xff09; 分数&#xff1a; 100 题数&#xff1a; 30 一、 单选题(共 20 题&#xff0c; 共 80 分) 1. 使用 ESP32 for Arduino SPI 类库&#xff0c; 下列选项中&#xff0c; 具有设置时钟模式功能的成员函数是&…

如何学习VBA_3.2.14:字符串的处理

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的劳动效率&#xff0c;而且可以提高数据处理的准确度。我推出的VBA系列教程共九套和一部VBA汉英手册&#xff0c;现在已经全部完成&#xff0c;希望大家利用、学习。 如果…

ABeam News | ABeam中国受邀参加2024中国知识管理年会暨第14届China MIKE颁奖典礼,并荣获大奖

“ABeam/ News ” 近日&#xff0c;2024中国知识管理年会暨第14届China MIKE颁奖典礼圆满召开&#xff0c;大会结合AI赋能新质生产力的热点话题&#xff0c;以“AI超能力KM新价值” 作为主题&#xff0c;为与会观众带来知识管理的一场盛宴。ABeam中国受邀参会并荣获2024 China…

Error: Could not find or load main class org.apache.catalina.startup.Bootstrap

#现象&#xff1a; 官网下载tomcat source包后&#xff0c;启动报错&#xff0c;等一系列缺包造成服务无法启动 Error: Could not find or load main class org.apache.catalina.startup.Bootstrapjava.lang.ClassNotFoundException: org.apache.juli.logging.LogFactory原因 …

论文解读《CTRLsum: Towards Generic Controllable Text Summarization》

引言&#xff1a;一篇上交大佬的著作 ✅ NLP 研 2 选手的学习笔记 笔者简介&#xff1a;Wang Linyong&#xff0c;NPU&#xff0c;2023级&#xff0c;计算机技术 研究方向&#xff1a;文本生成、大语言模型 论文链接&#xff1a;https://aclanthology.org/2022.emnlp-main.396.…

【spotfire】脚本相关

文章目录 ironpython脚本使用JS实现弹出窗口思路实现效果 脚本的使用可以极大扩展spotfire的功能&#xff0c;但如何使用脚本一直不得其门而入&#xff0c;咨询厂商、查询资料&#xff0c;特此记录备忘。 ironpython脚本使用 参见官网教程&#xff1b; 部分参考资料如下&#…

嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻

引言&#xff1a;对于嵌入式硬件这个庞大的知识体系而言&#xff0c;太多离散的知识点很容易疏漏&#xff0c;因此对于这些容易忘记甚至不明白的知识点做成一个梳理&#xff0c;供大家参考以及学习&#xff0c;本文主要针对推挽、开漏、高阻态、上拉电阻这些知识点的学习。 目…