1. 项目背景与整体思路拆解
1.1 为什么需要关注PyTorch与昇腾平台的适配
这两年国产算力平台的关注度肉眼可见地在提升,而昇腾(Ascend)作为其中落地较早、生态相对完整的一支,在高校实验室、国企研究机构还有不少互联网公司的推理集群里,出镜率越来越高。很多朋友第一次接触昇腾,其实不是主动选择,而是“被选择”——公司采购了一批Atlas 800/900系列的服务器,或者合作方那边只开放了昇腾算力,你手里的PyTorch代码、训练脚本、推理服务,能不能直接跑上去,就成了第一个必须回答的问题。
先说结论:PyTorch模型在昇腾上是可以跑的,但并不是“装个PyTorch一键搞定”这么简单。PyTorch原生版本通过CANN的适配层,经过ASCEND加速算子库的映射才能在昇腾硬件上执行。这中间最关键的一环,就是昇腾官方提供的torch_npu插件,算力资源调度则由CANN(Compute Architecture for Neural Networks)负责。换句话说,昇腾平台对PyTorch的支持,走的是“PyTorch原生框架 + torch_npu适配层 + CANN底层运行库”的组合路线。
这篇文章面向的读者,是那些正准备在昇腾设备上搭建PyTorch环境、或者已经拿到昇腾机器但还在摸索安装流程的同学。我会从硬件确认、固件驱动、CANN安装、torch_npu编译安装,到环境验证、常见报错排查,完整走一遍实操流程。内容尽量做到“照着做就能跑通”,同时把每一步背后的原理讲明白。
1.2 生态适配的整体架构与关键组件
在动手安装之前,先把整条技术链路的组成弄清楚,后面遇到报错才不会一脸茫然。
昇腾平台上运行PyTorch的整体结构,从下往上大致是:
- 昇腾硬件层:也就是昇腾310/310P(推理卡)、910A/910B(训练卡)这些物理设备,还有板载的AI Core、HBM显存等。
- 固件与驱动层:NPU设备需要加载对应的固件(Firmware)和驱动(Driver),系统才能识别到设备,并正常申请算力资源。这一层出了问题,往往是
slogd起不来或者npu-smi看不到设备。 - CANN软件层:这一层提供算子库(AscendCL、算子的TBE实现等)、图编译引擎(GE,Graph Engine)、运行时(Runtime)和集合通信库(HCCL)。它等价于NVIDIA生态中的CUDA Toolkit + cuDNN + NCCL的角色。
- 框架适配层:对PyTorch来说,就是torch_npu。它以PyTorch插件的形式存在,把PyTorch的算子调用、Device管理、通信原语等,映射到CANN的底层接口上。
- 上层业务:也就是你在torch.npu上写的模型代码、训练脚本、推理服务。
可以这样理解:如果PyTorch是“一套标准的厨房设备”,那么torch_npu就是专门定制的一根“燃气管道适配器”,而CANN则是你所在小区的那套“燃气管网”。没有适配器,设备不管多好都接不上;没有管网,适配器也无用武之地。整个环境搭建工作,实际上就是把“管网”铺好,再把“适配器”正确装上。
这套架构里,有两个概念在安装时最容易混淆,先说清楚:
第一,torch_npu的版本必须严格对齐两个东西:PyTorch的版本和CANN的版本。官方发布的torch_npu包,轮子命名里通常带Python版本、CANN版本号,选择不对,import阶段就会报ModuleNotFoundError或者undefined symbol这类错误。
第二,昇腾的推理部署,除了跑PyTorch原生模型之外,更推荐走MindIE或者TensorRT-Like的固化模型路线。但本文聚焦的是PyTorch训练和PyTorch推理的生态适配,所以不会展开MindIE引擎的推理部署细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与核心前置判断
2.1 硬件确认:你的机器是什么卡,决定后面怎么走
拿到一台昇腾服务器,第一件事不是急着装软件,而是确认硬件型号和系统状态。因为昇腾310和910的操作路径完全不同,910A和910B的驱动固件版本要求也有差异,用错了包,轻则报错,重则设备异常。
最基本的确认命令是npu-smi info。这个命令由驱动提供,如果系统里已经装过驱动,可以直接看到设备列表。比较典型的信息包括:
code复制+---------------------------------------------------------------------------------------+
| npu-smi 24.1.rc1 Version: 24.1.rc1 |
+-------------------------------+-----------------+--------------------------------------+
| NPU Name | Health | Power | HBM Memory |
| 0 910B | OK | 78.5W | 62336MiB |
+-------------------------------+-----------------+--------------------------------------+
如果机器是全新的,还没装驱动,npu-smi是不存在的。这时候可以用lspci | grep -i acceleration查看PCIe设备,一般能看到Huawei的设备ID。
确认硬件型号之后,去昇腾社区找到对应的CANN版本。这里有一个很容易踩的坑:CANN版本和固件驱动版本必须配套。昇腾社区每个CANN版本的发布说明中,都会有一个“配套的固件与驱动版本”的对照表,装上不配套的驱动,CANN能装上,但一跑算子就崩。
2.2 操作系统与Python版本选择
昇腾环境对操作系统有一定限制,官方主推的是openEuler、Ubuntu Server、CentOS 7.6/8.4这些。如果你拿到的是全新服务器,建议优先选openEuler 22.03 LTS或Ubuntu 20.04/22.04 LTS。我自己的经验是,Ubuntu 22.04的社区资料比较多,踩坑后容易搜到解决方案;openEuler在商业项目里更常见,但部分依赖包需要自己找源。
Python版本这边,训练场景建议Python 3.8到3.11之间,具体要看PyTorch版本和torch_npu版本支持矩阵。以当前主流的PyTorch 2.1/2.3版本为例,一般配套Python 3.8/3.9/3.10。不建议直接用系统自带的Python,操作系统的Python是系统包管理器的重要依赖,动它容易出连锁问题。比较好的方案是用Miniconda或Anaconda管理Python环境——这也符合大多数PyTorch用户的使用习惯。
顺带强调一下,千万别图省事直接pip install torch之后就想跑昇腾,必须明确当前环境的PyTorch是CPU版还是CUDA版。只要import torch之后,torch.cuda.is_available()返回False,而环境变量里有ASCEND_HOME或CANN相关路径,那torch_npu在import时大概率会因为torch的device后端不一致而炸掉。后面会专门讲到这个。
2.3 依赖组件:驱动、固件、CANN与Python虚拟环境的关系
整个安装链路里,有几个关键组件的命名和关系,值得一开始就理顺:
- 驱动(Driver):负责NPU设备的管理、资源分配、上下文建立。安装后会有
npu-smi工具和内核模块。 - 固件(Firmware):NPU芯片上的底层运行固件,驱动和固件通常作为一个安装包统一发布,安装时会一起装上。昇腾社区提供的包名一般是
Ascend-hdk-<版本号>_linux-<arch>.run。 - CANN Toolkit:提供算子、图编译、运行时等开发组件,是torch_npu真正依赖的库。安装完需要source环境变量:
/usr/local/Ascend/ascend-toolkit/set_env.sh。 - CANN Kernels:算子包,一般随Toolkit配套安装,也可以单独补装。
- torch_npu:PyTorch和CANN之间的适配插件,在conda环境里通过pip安装。
四者之间的关系是:驱动和固件负责“硬件和操作系统对话”,CANN负责“应用层和硬件对话”,torch_npu负责“PyTorch和CANN对话”。任何一层装错版本或漏装,最终的表现都是“某个算子执行时报错”,但根因往往藏在很底层的地方。
建议在动手之前,先建一个干净的conda环境,比如:
bash复制conda create -n ascend_pytorch python=3.10 -y
conda activate ascend_pytorch
后面所有的pip安装都在这个环境里进行,不要污染base环境。这一点在多人共用的服务器上尤其重要——我见过不少同事因为把torch装到了base环境,导致别人的服务起不来。
3. 昇腾PyTorch适配的安装实操全流程
3.1 安装CANN Toolkit与配套Kernels
以昇腾910B和CANN 8.0.RC3为例,完整的安装步骤大致如下:
第一步,从昇腾社区下载对应版本的Ascend-cann-toolkit_8.0.RC3_linux-aarch64.run(如果是x86机器,选择x86_64版本)。下载后先赋予执行权限再运行:
bash复制chmod +x Ascend-cann-toolkit_8.0.RC3_linux-aarch64.run
./Ascend-cann-toolkit_8.0.RC3_linux-aarch64.run --install
安装过程中会提示选择安装方式,一般选默认的全量安装即可。默认安装路径是/usr/local/Ascend/ascend-toolkit/。
第二步,配置环境变量。我把这段写进~/.bashrc,这样每次登录自动生效:
bash复制source /usr/local/Ascend/ascend-toolkit/set_env.sh
set_env.sh会把CANN的库路径、工具路径注入到LD_LIBRARY_PATH、PATH等环境变量中。这一步必须做,少了它,torch_npu就算装上了,import也会因为找不到libruntime.so之类的动态库失败。
第三步,验证CANN是否安装成功。可以运行:
bash复制/usr/local/Ascend/ascend-toolkit/latest/bin/atc --version
如果能看到版本信息,说明CANN环境OK。
有一个细节值得强调:安装CANN不需要重启机器,但安装固件驱动后通常需要重启。如果服务器是生产环境,驱动升级这种操作要申请窗口期来做,别在业务跑着的时候偷偷装。
3.2 使用pip安装PyTorch与torch_npu
CANN装完之后,重点来了。torch_npu的安装,说白了就是两条路:官方提供预编译的wheel包,或者从源码编译。
如果你使用的是昇腾官方支持矩阵内的PyTorch版本,直接走wheel路线,简单高效。先体验一下pip源的选择。昇腾官方提供了AI源的加速,也可以直接用PyPI的源。实际使用中,我更推荐用官方源来装torch_npu,因为版本匹配关系在官方源里索引得更准确。
bash复制pip install torch==2.3.0
pip install torch_npu==2.3.0.post2
注意这里的版本号对应关系:PyTorch 2.3.0对应的torch_npu是2.3.0.post2(具体以安装时的为准)。torch_npu的版本号规则是<torch版本>.<补丁号>,比如2.3.0.post2适用于PyTorch 2.3.0加CANN 8.0.RC3,这个对应关系官方文档写得很清楚,装之前务必确认。
如果你需要的PyTorch版本比较新,或者官方还没有出对应wheel,那就只能走源码编译路线。昇腾Gitee仓库里有torch_npu的源码,编译步骤一般是:
bash复制git clone https://gitee.com/ascend/pytorch.git -b v2.3.0-6.0.0
cd pytorch/torch_npu
source /usr/local/Ascend/ascend-toolkit/set_env.sh
python setup.py build_ext --inplace
源码编译最大的坑是编译时间和依赖:我第一次编译的时候,因为没装好pybind11和ninja,大概排查了半小时才把构建环境理顺。在Python环境下先装好这两个工具,会省不少事。另外,编译过程大概需要15到30分钟,中间如果报内存不足,可以加上-j 4这种参数限制并行编译数量。
3.3 验证安装:import torch_npu成功不等于万事大吉
环境装好之后,最基础也是最关键的验证逻辑,在于确认以下几点:
import torch能成功。import torch_npu能成功。- 执行设备查询能返回设备信息。
- 跑一个小算子,确认真实计算没问题。
我建议把下面的验证脚本存成一个check_env.py,每次环境变了都跑一遍:
python复制import torch
import torch_npu
print("torch version:", torch.__version__)
print("torch_npu version:", torch_npu.__version__)
print("npu count:", torch.npu.device_count())
print("npu name:", torch.npu.get_device_name(0))
a = torch.randn(3, 4).npu()
b = torch.randn(3, 4).npu()
c = torch.matmul(a, b)
print("matmul result shape:", c.shape)
如果输出中npu count大于0,并且matmul的结果shape正常,这套环境就能用了。
这里有一个新手很容易误判的地方:import torch_npu成功,只是说明插件加载了,并不能说明CANN的算子能正常工作。上面那个简单的矩阵乘法,才是真正验证算子通路的方式。如果矩阵乘法都能跑通,后面训练的90%的问题都不在环境侧,而是模型代码或算子兼容性侧了。
3.4 设置设备与日常使用注意事项
编译安装完,日常使用PyTorch在昇腾上跑,有几个和CUDA习惯不太一样的地方,单独列一下:
- 设备名称:CUDA设备编号是
cuda:0,昇腾的设备编号是npu:0。代码里要用.to('npu')或者.npu(),比如model = model.to('npu:0')。 - 环境变量:通过
ASCEND_RT_VISIBLE_DEVICES指定对进程可见的NPU设备,等价于CUDA的CUDA_VISIBLE_DEVICES。比如只用第0号和第1号设备,就设置export ASCEND_RT_VISIBLE_DEVICES=0,1。 - 内存管理:PyTorch在昇腾上的显存管理默认是CANN的
aclrtMalloc,和CUDA的cudaMalloc有区别,一般不推荐直接操作显存地址,而是让框架自己管理。 - 混合精度:昇腾的混合精度(AMP)支持是具备的,官方推荐使用
torch.npu.amp模块或者保持已有的AMP代码兼容。但前提是scaler的device也要在NPU上。
这些差异本身不难,但它们会在代码迁移的时候成为“隐性坑”。特别是从CUDA平台迁移过来的项目,如果源代码里写死了cuda关键字,到了昇腾上就会报Torch not compiled with CUDA enabled之类的错误。迁移时要做的就是全局替换设备关键字,同时在关键节点验证设备归属。
4. 不同场景下的适配策略与选型对比
4.1 直接运行PyTorch模型 vs 使用MindFormers等上层框架
很多刚接触昇腾的团队,都会纠结一个问题:既然昇腾支持PyTorch,那我直接把原来的PyTorch代码搬上来跑不就行了,为什么还要关注MindFormers、ModelZoo这些上层框架?
答案是“能跑”和“跑得好”是两码事。PyTorch + torch_npu这套组合,本质上是提供了一条通用迁移路径。如果你的模型结构特别复杂,或者用了大量自定义算子,走torch_npu是必须的。但如果你用的是常见的GPT类、BERT类模型,昇腾自家的MindFormers已经对网络结构做了深度优化,算子融合得更彻底,训练效率可能比直接跑PyTorch版本高不少。
这就有点像买了一个通用转换插头,可以接到各种电器上;但如果你常用的电器本身就是这个品牌的定制插头,那原装适配器的体验往往更好。昇腾的MindFormers就是那个“原装适配器”。
各条路径的适用场景,我整理了一个对照表:
| 方案 | 适用场景 | 迁移成本 | 性能上限 | 生态兼容性 |
|---|---|---|---|---|
| PyTorch + torch_npu | 已有PyTorch代码,快速迁移 | 低 | 中高 | 好 |
| MindFormers + MindSpore | 从零训练常见大模型 | 中 | 高 | 依赖社区支持 |
| MindIE推理引擎 | 推理部署高吞吐场景 | 中 | 高 | 中等 |
我的建议是:训练代码以PyTorch为主,可以先用torch_npu跑通,再逐步针对性能瓶颈做算子替代或图模式优化;如果是从零开始做,可以认真评估一下MindFormers是否覆盖了你的模型类型。推理部署则优先考虑MindIE路线,性能和吞吐量优势明显。
4.2 分布式训练在昇腾上的适配:HCCL与分布式通信
分布式训练这块,昇腾提供的集合通信库叫HCCL(Huawei Collective Communication Library),作用等价于NVIDIA的NCCL。PyTorch的分布式训练框架(DDP、FSDP)在昇腾上跑,需要底层通信后端走HCCL。
torch_npu的适配思路是:把torch.distributed的通信后端绑定到HCCL。实际操作中,只需要在初始化进程组时这样写:
python复制import torch.distributed as dist
import torch_npu
dist.init_process_group(backend='hccl', init_method='tcp://...', rank=rank, world_size=world_size)
有一点需要提前说的:HCCL的通信初始化依赖ASCEND_RT_VISIBLE_DEVICES环境变量。多机多卡场景下,每台机器的进程都要正确设置这个变量,否则会出现通信组初始化失败,报HCCL_Bcast之类的错误。单机8卡的场景相对简单,只要设置export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,然后正常用torchrun启动即可。
多机场景下,除了设置设备可见性,还要求所有节点的NPU直连网络(RoCE)配置正确。昇腾910B通常带有RoCE网卡,要做网络规划,确保HCCL集合通信能走RDMA链路。官方推荐的网卡配置在/etc/hccn.conf中,需要根据实际网络规划填写HCCL_IF_IP等参数。这个配置不太起眼,但一旦想用多机多卡,它会成为一个大型的“卡点”。
单机环境下调分布式训练,可能感觉不到HCCL的存在;一旦上到多机,通信拓扑、网卡配置、Net-Turn参数这些全都会冒出来。这一点和NCCL调优的思路是类似的。
4.3 推理场景的实践:vLLM与昇腾的适配现状
推理这块,业界用vLLM的团队很多,所以经常有人问我:昇腾910B上能不能用vLLM启动embedding向量模型和reranker模型?
这个问题其实在技术社区里经常能看到。先说结论:通常没问题,但需要昇腾适配版本的vLLM,不能直接拿社区版vLLM跑昇腾。昇腾社区维护了自己的vLLM分支(Ascend/vllm-ascend),针对昇腾算子库做了适配,支持了常见的LLM和向量模型的推理。
embedding模型和reranker模型无法启动,常见的原因有这几个:
第一,模型权重格式问题。有些向量模型实际上是基于BERT或DeBERTa结构,而昇腾vLLM分支的主要优化对象是Decoder-only的LLM(如Qwen、Llama)。如果你的embedding模型不是标准的Transformer Encoder结构,昇腾vLLM分支可能没有对该结构的完整算子覆盖,启动时会报Unsupported op。
第二,模型版本不匹配。昇腾vLLM在支持特定模型时,对模型配置(config.json)中的一些参数有约束,比如某些版本的注意力实现方式,或某些已弃用的参数。新版本的模型配置可能不被旧版vLLM支持。
第三,Ascend vLLM分支本身的版本兼容性。昇腾vLLM一般会和CANN版本、torch_npu版本绑定发布,如果你安装的CANN太高或太低,vllm-ascend的轮子也装不上或起不来。
如果是这种情况,我的建议是先在昇腾社区issue区搜一遍该模型名称,如果有人验证过OK,就直接照着操作。如果没有,也可以考虑用torch_npu + HuggingFace Transformers(AutoModel)走原生PyTorch推理,虽然吞吐量比vLLM低一些,但胜在兼容性好,对于embedding这种短文本、低并发的场景反而够用。
4.4 ComfyUI等AIGC工具在昇腾上的适配情况
除了vLLM,也经常看到有朋友问ComfyUI这类AIGC前端工具在昇腾上的适配情况。
实事求是地说,ComfyUI在昇腾上的社区支持还在完善中。如果你有SD图生图、ControlNet这类需求,直接跑ComfyUI大概率会遇到一些算子兼容性报错,因为ComfyUI依赖的许多底层自定义节点并没有针对昇腾做适配。
目前比较现实的路径是两条:一条是等昇腾社区或第三方开源社区逐渐完善ComfyUI-NPU插件;另一条是自己基于torch_npu写一套底层的节点实现,把CUDA算子换成昇腾实现。后者工作量不小,如果不是专门做集成,我个人不建议自己造轮子。
对于想快速在昇腾上体验AIGC流程的同学,昇腾模型仓(ModelZoo)里其实已经有一些图像生成模型的参考实现,比如Stable Diffusion的昇腾适配版本,可以先从那里面找找灵感。
5. 常见报错与排查经验
5.1 安装阶段的典型失败与对策
昇腾环境安装的报错,看起来五花八门,但归纳起来不外乎下面这几种。
报错一:torch_npu import失败,报ModuleNotFoundError: No module named 'torch_npu._C'
这个问题90%是torch_npu版本和torch版本不匹配导致的。torch_npu._C是编译好的C扩展,它的符号链接依赖于特定版本的PyTorch ABI。如果你用的是PyTorch 2.3.0,却装了适配2.1.0的torch_npu,import必然失败。
排查方法很简单:
bash复制pip show torch torch_npu
看看两个版本号是否在官方匹配矩阵中。建议直接卸载重装,不要试图用软链接等方式硬凑。
报错二:ImportError: libascendcl.so: cannot open shared object file
这个报错说明CANN的环境变量没有加载。检查一下:
bash复制echo $LD_LIBRARY_PATH
如果输出里没有/usr/local/Ascend/ascend-toolkit/latest/lib64这样的路径,说明set_env.sh没有执行或者没写进bashrc。还要注意,如果你的shell是zsh,~/.bashrc不会自动加载,需要放到~/.zshrc里。
报错三:RuntimeError: soc version is null
这个报错在有些环境下会出现,原因是CANN在初始化时读不到NPU的SoC版本信息。常见原因有两类:一是固件驱动没装好,设备没有正常上电,先用npu-smi info确认设备信息是否正常;二是环境变量里没有设置soc_version,可以尝试显式指定:
bash复制export ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest
这个变量一般会在set_env.sh里自动设置,但如果手动source过其他版本的CANN,可能会被覆盖。
5.2 运行阶段的常见报错与性能排查
报错四:torch.cuda.is_available()返回False导致代码走偏
很多从CUDA迁移过来的代码,第一行就写着assert torch.cuda.is_available()。昇腾环境下,torch.cuda.is_available()确实返回False,这是正常的,但它不代表昇腾不可用。正确的判断方式是:
python复制import torch
import torch_npu
print(torch.npu.is_available())
如果返回True,说明NPU就绪了。需要注意的是,迁移代码时务必把所有的cuda关键字替换成npu,包括.cuda()、torch.cuda.FloatTensor、device='cuda'等。
报错五:运行时报Not implemented或Unsupported op
这是算子兼容性问题。torch_npu虽然适配了大部分PyTorch算子,但总有一些冷门算子没覆盖。遇到这种情况,排查思路是:
- 看是哪个算子报的错,一般报错信息里会包含算子名。
- 去昇腾社区或Gitee的issue里搜这个算子,看看有没有人提过。
- 如果算子确实不支持,可以尝试在模型里替换等价实现(比如用多个基础算子拼出目标功能),或者在昇腾社区提交支持请求。
从我的经验看,90%的情况出在比较冷门的自定义算子和部分torch.nn.functional接口上。常见的标准模型结构(Transformer、ResNet、Bert)基本都能正常跑。
关于性能的提醒:有些模型在昇腾上第一次跑,性能可能不理想。这未必是环境问题,而可能是PyTorch Eager模式下的算子调度开销。昇腾提供了图模式(torch.npu.set_compile_mode(jit_compile=True))来提升执行效率,但这涉及更深入的性能调优,不是环境搭建的基础范畴。
5.3 避免踩坑的十条经验
整理的这些经验是实操中积累的,按重要性排序:
- 第一条:配置前先确认硬件型号、CANN版本、PyTorch版本三者的匹配关系,别凭感觉装。
- 第二条:驱动装完必须重启,重启后先用
npu-smi info确认设备状态,再继续下一步。 - 第三条:所有环境变量统一写到
~/.bashrc或~/.zshrc,不要每次都手动source,否则容易漏。 - 第四条:用conda环境隔离不同项目,不要共用base环境。
- 第五条:升级CANN后必须重新装torch_npu,即使版本号没变,动态库路径也变了。
- 第六条:
flash_attn这类CUDA专有扩展在昇腾上不能直接用,需要找昇腾替代实现。 - 第七条:不要试图在容器里直接安装驱动,昇腾容器场景需要用
Ascend Docker Runtime,驱动保留在宿主机层。 - 第八条:训练代码里如果用了
torch.cuda.amp,迁移到昇腾后需要改成torch.npu.amp,或者用混合精度自动适配的方式。 - 第九条:遇到报错先看日志,CANN日志路径在
/root/ascend/log,里面有详细的算子和运行时报错信息,比console输出完整得多。 - 第十条:在昇腾社区提问前,先把自己的CANN版本、PyTorch版本、torch_npu版本、设备型号和报错日志贴全,不然很难定位问题。
5.4 一个真实案例:vLLM启动embedding模型失败的全过程
最后分享一个真实案例,就是标题里提到的那个典型问题——昇腾910B-A2服务器上用vLLM启动embedding向量模型,报了Unsupported op错误。
背景:用户使用昇腾vLLM分支,想要部署一个基于BERT结构的embedding模型,启动时直接在初始化阶段就崩了,日志里出现了不支持的算子名。
我们的排查过程是:
第一步,确认CANN版本和vLLM-Ascend版本的匹配关系。用户用的CANN 7.0,而vLLM-Ascend要求的CANN是8.0.RC1及以上,这里先差了一截。升级CANN后,算子报错少了一些。
第二步,确认模型结构。用户部署的模型是基于BERT架构的向量模型,而昇腾vLLM主要针对Decoder-only模型优化,Encoder结构支持有限。在vLLM-Ascend的文档中,明确写了目前对Encoder-only模型支持不完整,这也是后来在社区看到其他用户反馈同样问题的结论。
第三步,给出替代方案。用torch_npu + Transformers库直接加载模型进行推理。虽然并发能力不如vLLM,但对于embedding和reranker这种低延迟短文本场景,效果完全够用。
这个案例的复盘结论是:不是昇腾“不能”跑vLLM,而是昇腾vLLM目前主要面向LLM生成场景。你拿它跑非主流模型结构,就要做好“该模型可能不兼容”的准备。跑通之前先用社区issue搜一遍,是最高效的做法。
6. 实操体验总结
整套环境搭下来,我个人最深的体会有三点。
第一,昇腾适配PyTorch的完整度,比很多人想象中的要好,但需要有一定的心理预期。你不能拿它跟CUDA生态去硬比“开箱即用”,毕竟CUDA发展了多少年,昇腾生态才几年。但如果你愿意花点时间把版本匹配关系弄对,把常见报错的经验积累起来,日常训练和推理的体验是能保障的。
第二,遇到问题一定要会看日志。很多人一遇到报错就卡死,然后疯狂百度搜不到答案,最后发现日志里其实已经把原因写得明明白白。CANN的日志目录、Ascend社区的issue区,是我解决最多问题的地方。
第三,版本管理是关键中的关键。我在给多个团队做环境适配的时候,发现绝大多数环境问题都源于版本之间的不匹配。如果能从第一天就建立一套“固定硬件驱动版本-固定CANN版本-固定torch_npu版本-固定PyTorch版本”的记录机制,后面所有人在同一套组合上开发,问题会少很多。
如果这篇文章能帮你在昇腾上顺利跑通第一个PyTorch模型,那就算没白写。环境装好只是第一步,后面真正开始适配模型、调优性能的时候,你会发现还有很多有意思的细节值得深入研究。到时候再回头看,这一步反而是整个过程中最简单、也最值得打好基础的一环。
