当前位置: 首页 > news >正文

PyTorch 模型迁移实战:从 GPU 到 NPU

前言把在 GPU 上训练好的 PyTorch 模型迁到昇腾 NPU大部分时候不难但细节很多。这篇文章讲一个完整的迁移流程从环境准备到性能验证。环境准备安装驱动和工具包# 检查 NPU 设备lspci|grepd802# 安装驱动已安装则跳过./Ascend-driver_24.1.RC3_linux-x86_64.run--install# 安装 CANN 工具包./Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run--install# 设置环境变量source/usr/local/Ascend/ascend-toolkit/set_env.sh安装 PyTorch 和 torch_npu# 安装 PyTorchCPU 版本即可pipinstalltorch2.1.0cpu-fhttps://download.pytorch.org/whl/torch_stable.html# 安装 torch_npupipinstalltorch-npu2.1.0.post3# 验证安装python-cimport torch; import torch_npu; print(torch.npu.is_available())# 输出True模型迁移三种方式方式一自动迁移最简单importtorchimporttorch_npu# 自动把模型转到 NPUmodelMyModel()modelmodel.npu()# 等价于 model.to(npu:0)# 自动把数据转到 NPUinput_tensortorch.randn(1,3,224,224).npu()# 推理outputmodel(input_tensor)print(output.shape)适合模型没有自定义算子、没有动态控制流的情况。方式二手动迁移最可靠importtorchimporttorch.nnasnnimporttorch_npuclassMyModel(nn.Module):def__init__(self):super().__init__()self.convnn.Conv2d(3,64,3,padding1)self.bnnn.BatchNorm2d(64)self.relunn.ReLU()defforward(self,x):xself.conv(x)xself.bn(x)xself.relu(x)returnx# 手动迁移到 NPUmodelMyModel().npu()# 检查所有参数都在 NPU 上forname,paraminmodel.named_parameters():print(f{name}:{param.device})输出conv.weight: npu:0 conv.bias: npu:0 bn.weight: npu:0 bn.bias: npu:0方式三ONNX 中间表示最通用importtorchimporttorch.onnx# 1. 在 GPU 上加载模型modelMyModel().cuda().eval()# 2. 导出 ONNXdummy_inputtorch.randn(1,3,224,224).cuda()torch.onnx.export(model,dummy_input,model.onnx,opset_version11,input_names[input],output_names[output])# 3. 用 ATC 编译成 .om!atc--modelmodel.onnx \--framework5\--outputmodel \--input_shapeinput:1,3,224,224适合从其他框架TensorFlow、MXNet迁移或者需要部署到生产环境的情况。常见迁移问题问题一CUDA 算子不支持# GPU 代码报错outputtorch.nn.functional.interpolate(input,scale_factor2,modebilinear,align_cornersFalse)# NPU 代码正常outputtorch.nn.functional.interpolate(input,scale_factor2,modenearest# NPU 对 nearest 支持更好)问题二设备不匹配# 错误输入在 CPU模型在 NPUmodelmodel.npu()input_tensortorch.randn(1,3,224,224)# 在 CPU 上outputmodel(input_tensor)# 报错# 正确输入也要转到 NPUinput_tensorinput_tensor.npu()outputmodel(input_tensor)问题三优化器状态# 错误优化器在 CPUmodelmodel.npu()optimizertorch.optim.Adam(model.parameters())# 优化器在 CPU# 正确优化器参数也要在 NPUmodelmodel.npu()optimizertorch.optim.Adam(model.parameters())# PyTorch 会自动处理# 手动检查forparaminoptimizer.param_groups[0][params]:print(param.device)# 应该是 npu:0精度验证迁移后最重要的一步验证 NPU 上的输出和 GPU 上是否一致。逐层对比importtorchimportnumpyasnpdefcompare_model_outputs(gpu_model,npu_model,input_tensor):对比 GPU 和 NPU 模型的输出# GPU 推理gpu_model.eval()withtorch.no_grad():gpu_outputgpu_model(input_tensor.cuda())# NPU 推理npu_model.eval()withtorch.no_grad():npu_inputinput_tensor.npu()npu_outputnpu_model(npu_input).cpu()# 转成 NumPygpu_output_npgpu_output.cpu().numpy()npu_output_npnpu_output.numpy()# 计算余弦相似度cosine_simnp.dot(gpu_output_np.flatten(),npu_output_np.flatten())/\(np.linalg.norm(gpu_output_np)*np.linalg.norm(npu_output_np))# 计算最大绝对误差max_abs_errornp.max(np.abs(gpu_output_np-npu_output_np))print(f余弦相似度:{cosine_sim:.6f})print(f最大绝对误差:{max_abs_error:.6f})# 判断是否通过ifcosine_sim0.99andmax_abs_error0.01:print(✅ 精度验证通过)returnTrueelse:print(❌ 精度验证失败)returnFalse# 使用gpu_modeltorch.load(gpu_model.pth)npu_modeltorch.load(gpu_model.pth).npu()input_tensortorch.randn(1,3,224,224)compare_model_outputs(gpu_model,npu_model,input_tensor)完整验证流程deffull_precision_validation(gpu_model,npu_model,dataloader):用完整验证集做精度验证gpu_model.eval()npu_model.eval()gpu_outputs[]npu_outputs[]withtorch.no_grad():forinput_tensor,_indataloader:# GPUgpu_outgpu_model(input_tensor.cuda()).cpu()gpu_outputs.append(gpu_out)# NPUnpu_outnpu_model(input_tensor.npu()).cpu()npu_outputs.append(npu_out)# 拼接gpu_outputstorch.cat(gpu_outputs,dim0).numpy()npu_outputstorch.cat(npu_outputs,dim0).numpy()# 指标cosine_simnp.dot(gpu_outputs.flatten(),npu_outputs.flatten())/\(np.linalg.norm(gpu_outputs)*np.linalg.norm(npu_outputs))max_abs_errornp.max(np.abs(gpu_outputs-npu_outputs))mean_abs_errornp.mean(np.abs(gpu_outputs-npu_outputs))print(f余弦相似度:{cosine_sim:.6f})print(f最大绝对误差:{max_abs_error:.6f})print(f平均绝对误差:{mean_abs_error:.6f})returncosine_sim0.99性能优化迁移完成后做基本的性能优化。开启混合精度fromtorch_npu.contribimporttransfer_to_npu# 开启自动混合精度modeltransfer_to_npu(model)# 或者用 AMPscalertorch.npu.amp.GradScaler()forinput_tensor,targetindataloader:withtorch.npu.amp.autocast():outputmodel(input_tensor.npu())losscriterion(output,target.npu())scaler.scale(loss).backward()scaler.step(optimizer)scaler.update()optimizer.zero_grad()用 AOE 做自动调优# 调优模型aoe--modelmodel.onnx\--framework5\--job_type2\--moderl\--outputmodel_optimized性能对比importtimedefbenchmark(model,input_tensor,iterations100):性能测试# 预热for_inrange(10):model(input_tensor)torch.npu.synchronize()starttime.time()for_inrange(iterations):model(input_tensor)torch.npu.synchronize()endtime.time()latency(end-start)/iterations*1000# msthroughputiterations/(end-start)# FPSprint(f延迟:{latency:.2f}ms)print(f吞吐量:{throughput:.2f}FPS)returnlatency,throughput# 对比gpu_latency,gpu_fpsbenchmark(gpu_model,input_tensor.cuda())npu_latency,npu_fpsbenchmark(npu_model,input_tensor.npu())print(fNPU/GPU 延迟比:{npu_latency/gpu_latency:.2f}x)print(fNPU/GPU 吞吐量比:{npu_fps/gpu_fps:.2f}x)部署到生产环境导出 ONNX 并编译# 导出 ONNXmodel.eval()dummy_inputtorch.randn(1,3,224,224).npu()torch.onnx.export(model,dummy_input,model.onnx,opset_version11,input_names[input],output_names[output],dynamic_axes{input:{0:batch}})# 编译成 .omatc--modelmodel.onnx\--framework5\--outputmodel\--enable_fusiontrue\--op_precision_modeallow_fp32_to_fp16用 Ascend CL 做推理#includeacl/acl.hintmain(){// 初始化aclInit(nullptr);aclrtSetDevice(0);// 加载模型uint32_tmodelId;aclmdlLoadFromFile(model.om,modelId);// 准备输入aclmdlDataset*inputaclmdlCreateDataset();void*inputBuffer/* 输入数据 */;aclDataBuffer*inputDataaclCreateDataBuffer(inputBuffer,inputSize);aclmdlAddDatasetBuffer(input,inputData);// 推理aclmdlDataset*outputaclmdlCreateDataset();aclmdlExecuteAsync(modelId,input,output,nullptr);aclrtSynchronizeStream(nullptr);// 获取输出aclDataBuffer*outputDataaclmdlGetDatasetBuffer(output,0);void*outputBufferaclGetDataBufferAddr(outputData);// 后处理float*probs(float*)outputBuffer;intpredstd::max_element(probs,probs1000)-probs;std::coutPrediction: predstd::endl;// 释放资源aclmdlUnload(modelId);aclrtResetDevice(0);aclFinalize();return0;}参考资源PyTorch 模型迁移指南: https://www.hiascend.com/document/detail/zh/CANN/torch_npu API 文档: https://gitee.com/ascend/pytorchONNX 模型导出: https://pytorch.org/docs/stable/onnx.html精度调优指南: https://www.hiascend.com/document/detail/zh/CANN/总结PyTorch 模型迁移到 NPU 有三种方式自动迁移最简单、手动迁移最可靠、ONNX 中间表示最通用。迁移后要做精度验证确保余弦相似度 0.99。性能优化包括开启混合精度、用 AOE 调优、算子融合。生产部署时导出 ONNX 并编译成.om再用 Ascend CL 做高性能推理。
http://www.gsyq.cn/news/1374952.html

相关文章:

  • 2026年降AI工具会不会被知网检测到深度解读:使用降AI工具算学术不端吗免费完整分析
  • 2026年降AI后语义失真攻略:过度改写论点跑偏4.8元修复语义同时达标完整方案
  • 2026年海外留学论文降AI攻略:Turnitin AI检测超标4.8元彻底解决完整方案
  • 圆偏振光膜与AR抗反射膜原理评测:scinique双护技术如何实现“一柔一清”?
  • 温度如何重塑拉曼光谱偏振依赖性:非谐波效应与模式耦合的微观机制
  • 关于 Multi-Agent,我目前的一些思考
  • Go语言Redis缓存技术实战
  • MySQL安装与基础操作指南
  • 告别微信传文件!麒麟KYLINOS自带‘传书’工具,局域网互传文件保姆级教程
  • 2026年质量好的农村污水处理设备/工厂污水处理设备/潍坊工业污水处理设备/一体化污水处理设备厂家哪家好 - 行业平台推荐
  • 伽马暴宇宙学分析中流量阈值选择的敏感性研究
  • 基于变分自编码器的类星体光谱无监督分析:QUEST工具原理与实践
  • 2026年比较好的生活污水处理设备/污水处理设备/养殖污水处理设备/工厂污水处理设备公司哪家好 - 品牌宣传支持者
  • ARM SME指令集:矩阵运算优化与AI加速实践
  • 不止于仿真:在Ubuntu 20.04上把Gazebo Garden装进ROS2,我的机器人开发环境才算完整
  • 图自编码器在金融风控中的拓扑模式检测实践
  • 家庭账目不再是一笔糊涂账
  • ARM SME指令集与浮点运算优化实践
  • 机器学习监控与可观测性:从黑盒到白盒的实践指南
  • Spine Unity Runtime免费集成指南:合规运行时加载与URP适配
  • Windows屏幕录制全栈实现:Graphics Capture+FFmpeg零拷贝编码
  • 互联网大厂Java面试实录:严肃面试官 vs 求职程序员的三轮技术问答
  • ChatGPT绘画提示词生成效率革命(92%设计师不知道的5层语义嵌套法)
  • 物理信息神经网络QNM-Net:用准正规模理论实现电磁散射的高效可解释建模
  • 【C++ 知识点回顾】C++ 工程中真正常见的内存泄漏:不是忘记 delete,而是生命周期失控
  • 如何让政策数据在三个端保持同步?政策快报的实践方案
  • List<T>泛型列表
  • 二、大模型节点配置以及结束节点配置
  • 诗心撷珍 | 李白诗行里,那些被忽略的星辰与旷野
  • 别急着买云服务器!手把手教你用闲置Win10电脑搭建个人SSH服务器(保姆级教程)