ARM64麒麟V10离线部署PyTorch:从架构原理到完整踩坑指南
发布时间:2026/10/2 19:04:05 作者:尧图编辑部 阅读量:1,286

前阵子帮朋友在一台只能访问内网的麒麟V10 ARM服务器上部署深度学习环境折腾了整整一个周末。PyTorch装上之后一跑就崩崩完再装装完再崩最后甚至怀疑是机器硬件坏了。其实问题的根源就三个字不匹配。架构不匹配、系统源不匹配、Python版本不匹配。这篇文章就是把我当时的完整踩坑过程和最终验证可行的方案整理出来目标很简单让同样拿到ARM64麒麟V10机器、又处于离线环境的你尽量少走弯路照着一步步来就能把PyTorch装起来。这篇文章适合两类人一类是在信创或内网环境做算法部署的工程师另一类是刚接触国产化服务器、被aarch64架构搞得一头雾水的小白。文中的命令我都在银河麒麟V10服务器版上实际执行过不同的SP小版本可能会有细微出入但整体流程是通用的。1. 先把ARM64、麒麟V10、PyTorch三件事拆透1.1 为什么ARM64服务器上下载了却装不上先记住一个结论ARM64和x86_64也就是大家常说的amd64是两套完全不同的指令集所有二进制程序、动态库、安装包都不能混用。x86_64用的是CISC复杂指令集一条指令能拆成好几条微指令执行所以软件生态极其庞大几乎所有的Linux发行版都有现成的x86_64包。ARM64走的是RISC精简指令集路线指令短小、功耗低服务器芯片厂商特别喜欢用它来做高密度计算节点。问题在于很多软件官方只发布x86_64的预编译包ARM64用户要么等官方适配要么自己编译要么找社区构建。用大白话类比x86_64的安装包是一本中文翻译书ARM64是英文原版书。你把中文版拿到只懂英文的人面前对方看不懂也装不进脑子里。也因此很多人在麒麟机器上执行pip3 install torch时pip会去搜索匹配当前平台标签的wheel包。如果官方没有对应的manylinux_aarch64版本pip就会尝试下载源码包现场编译——然后在内网离线环境里因为缺这个缺那个依赖直接翻车。这就是下载了却装不上的根本原因不是网不好是平台的二进制包不对。1.2 麒麟V10的包管理身世服务器版和桌面版不一样麒麟V10这个系列其实包含了好几个不同底座的产品这是很多教程含糊其辞的地方但恰恰是安装成败的关键。银河麒麟高级服务器操作系统V10技术路线兼容Red Hat Enterprise Linux / CentOS包管理工具是yum/dnf离线环境下可以挂载ISO做本地仓库。大部分服务器场景用的是这个。银河麒麟桌面操作系统V10有基于Ubuntu的衍生版本包管理工具是apt。部分信创台式机上见到的是这种。还有一些专用版本比如ARM版、龙芯版、飞腾版虽然都叫V10但库的细节可能不同。所以拿到机器第一步就是要搞清楚自己面对的是哪个底子。如果你用yum去装包但系统其实是apt体系操作当然会失败。好在PyTorch的安装其实对包管理器依赖不大核心靠pip。系统包管理器只负责补齐一些底层的运行时库例如libgomp、libatomic、libstdc。搞清楚系统底子才知道缺库的时候该用哪种方式补。1.3 PyTorch对Linux aarch64的支持比你想象中乐观很多人在网上搜ARM64 PyTorch会看到一堆老旧的社区编译教程然后默认以为PyTorch官方不支持ARM64。这是一个很深的误解。实际情况是PyTorch从1.10版本开始官方就正式发布Linux aarch64的wheel包。也就是说从2021年底开始ARM64再也不是PyTorch的弃儿。到了2.0时代官方对aarch64的支持已经相当成熟torch 2.0.x在ARM64上跑CPU推理、训练都没有问题。但这又带来一个新的隐含问题Numerous老教程基于1.8甚至更早的版本里面的下载链接早就失效了。如果你还在按2020年的教程找ARM64的预编译包大概率找不到或者找到一堆非官方的社区包质量参差不齐。正确姿势是直接去PyTorch官方whl索引页面筛选aarch64的包。PyTorch官方对aarch64的wheel命名大概长这样torch-2.0.1cpu-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl拆开来看2.0.1cpu版本号cpu表示CPU专用版cp38Python 3.8aarch64ARM64架构看懂这个命名规则后以后再看到任何wheel包你基本能在三秒钟内判断出它能不能装到当前机器上。2. 动手前花十分钟确认环境省下后面十小时2.1 确认架构uname -m之外还要看什么不要相信机器外壳上的标签也不要相信售前给的那张参数表。我见过一台标注ARM的机器实际用x86_64系统跑着——因为厂商拿x86主板刷了个KVM虚机给你。务必登进系统自己看。uname -m输出如果是aarch64那就是ARM64。如果输出x86_64那就是x86请直接CtrlF搜索其他x86教程本文不适用。更进一步我还建议看这两个输出lscpu | grep Architecture file /bin/bashlscpu会显示完整的CPU架构、型号、虚拟化特性。file /bin/bash告诉你系统自带的bash是什么格式的二进制。这两个输出交叉验证基本不会看走眼。还有一个容易被忽略的点有些麒麟系统跑在虚拟机里虚拟机的CPU模式可能被配置成兼容模式导致/proc/cpuinfo里的信息看起来怪怪的。不过只要uname -m是aarch64你就按ARM64的路子走不会有问题。2.2 确认系统、glibc与Python版本这个必须在安装之前全部确认清楚因为PyTorch wheel包对glibc和Python版本有硬性要求任何一个不满足都会导致安装失败或import阶段报错。cat /etc/kylin-release这条命令能看到麒麟系统的具体版本号和SP版本比如Kylin Linux Advanced Server release V10 (Tercel)之类的输出。注意SP1、SP2、SP3的glibc版本会有细微差异SP3一般比SP1的glibc要新。ldd --versionglibc版本如果大于等于2.17官方wheel基本都能满足。麒麟V10的glibc通常在2.28左右这一项一般没问题。python3 -V这一步最容易翻车。麒麟V10服务器版自带Python的情况各个版本不太一样有的自带Python 3.6有的自带3.8个别精简版可能连pip3都没有。PyTorch 2.x要求Python 3.8及以上版本如果你机器上是Python 3.6直接安装PyTorch 2.x必然失败。2.3 用一张表定下PyTorch版本基于上面确认的Python版本你就知道自己可以选哪个档位的PyTorch了。我整理了一张参考表按Python版本和PyTorch版本的兼容关系来选Python版本最高可用的PyTorch版本推荐搭配备注3.61.8.1社区/ 不推荐尽量避免官方aarch64支持始于1.103.6很难找到新wheel3.71.13.xtorch 1.13.1 torchvision 0.14.1老算法兼容性较好3.82.xtorch 2.0.1 torchvision 0.15.2最推荐稳定性好3.92.xtorch 2.0.1 torchvision 0.15.2推荐3.102.xtorch 2.0.1 torchvision 0.15.2推荐3.112.1torch 2.1.x较新的版本配合新Python选版本的原则是你的Python版本能跑哪个就用哪个不要盲目追求最新。PyTorch的版本和Python版本、torchvision的版本三者之间存在严格的对应关系错一个数字都可能导致module torchvision has no attribute models这种诡异问题。2.4 准备一台搬运工同架构有网机器或提前打包离线安装的核心思路就是在一台能访问互联网的机器上把需要的东西全部下载好拷贝到内网机器上安装。最佳情况你有一台和麒麟机器同架构aarch64而且联网的Linux机器。那么可以直接用pip download拉取wheel包不会有跨平台问题。如果没有同架构Linux机器也问题不大。PyTorch的wheel包可以通过pip download指定--platform参数来交叉下载后面我会详细写命令。但系统级的rpm依赖包最好还是从麒麟ISO镜像里获取不要尝试在x86机器上交叉下载rpm——虽然也能下但依赖解析会让人崩溃。3. 离线资源打包在一台能联网的机器上备好弹药3.1 pip download指定平台交叉拉包假设家里只有一台x86_64的Ubuntu笔记本但目标机是aarch64的麒麟V10Python版本是3.8。可以这样拉取PyTorch相关包mkdir -p /tmp/pytorch_offline pip download torch2.0.1 torchvision0.15.2 \ --platform manylinux2014_aarch64 \ --python-version 38 \ --only-binary:all: \ --index-url https://download.pytorch.org/whl/cpu \ -d /tmp/pytorch_offline解释一下这几个参数--platform manylinux2014_aarch64告诉pip我只要Linux aarch64平台的多版本wheel包。--python-version 38目标机的Python是3.8。--only-binary:all:只接受预编译的wheel禁止下载源码包去编译。这一条极其重要否则pip会下载一堆.tar.gz源码包在目标机上编译几乎必败。--index-url https://download.pytorch.org/whl/cpu从PyTorch官方的CPU版whl索引下载确保拿到的是cpu变体。如果目标机Python是3.9把--python-version 39即可wheel的cp39标签会匹配上。再把常用的Python依赖一起打包比如numpy、pillow、typing-extensions这些它们会作为torch的依赖出现。建议用同样的platform参数再执行一次pip download numpy1.24.4 pillow10.0.0 \ --platform manylinux2014_aarch64 \ --python-version 38 \ --only-binary:all: \ -d /tmp/pytorch_offline3.2 从官方地址手工下载wheel看懂命名规则如果你在联网机器执行上面的命令时报了一堆无法找到匹配版本的错或者你的网络环境访问不了PyPI也可以直接手动从PyTorch官方whl索引页面下载。地址是https://download.pytorch.org/whl/torch/页面里会列出海量的wheel文件。先在浏览器里按CtrlF搜索aarch64然后根据你需要的torch版本和Python版本找对应的文件。比如你要装torch 2.0.1、Python 3.8就应该找torch-2.0.1cpu-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl下载完把它拖进/tmp/pytorch_offline目录。同样的方法下载torchvisionhttps://download.pytorch.org/whl/torchvision/命名规则同上注意torch和torchvision版本要对齐不能随便拿个torch 2.0.1去配torchvision 0.10.0——那会直接报版本冲突。3.3 顺手把系统依赖rpm一起拖回来PyTorch在运行时还依赖一些系统级的共享库最典型的是libgomp.so.1。这个库在RHEL/CentOS系系统里由libgomp这个rpm包提供。如果目标机器已经被裁剪过很可能没有装它。系统依赖包最稳的来源是麒麟V10安装ISO镜像。你可以在联网机器上下载对应的麒麟V10 ISO然后挂载提取rpm包mount -o loop KylinLinuxAdvancedServerV10.iso /mnt/kylin_iso/ISO里通常会有BaseOS/Packages和AppStream/Packages目录从里面把libgomp、glibc、libstdc、gcc-gfortran相关的rpm拷出来一并放进离线资源包。不过这些rpm一般不大也能在安装了麒麟同版本系统的联网机器上直接yum install --downloadonly抓取方式更灵活。这里建议把ISO本身的文件也拷贝到内网机器上因为后文配置本地yum源时还要用。4. 正式安装能用系统Python就别动版本太老就上Miniforge4.1 路径A系统Python直接pip离线安装如果你的麒麟V10自带Python版本满足PyTorch要求3.8及以上而且pip3可用这条路是最简单的。先把离线资源目录拷贝到目标机比如放到/data/pytorch_offline/。然后执行pip3 install --no-index --find-links/data/pytorch_offline/ torch torchvision numpy--no-index告诉pip不要通过网络索引查找包。--find-links指定本地目录作为包的来源。实测中如果/data/pytorch_offline/里各种依赖都齐了这条命令能顺利完成。它会自动解析依赖关系从本地目录中找合适的wheel。如果你下载的时候只下载了torch和torchvision没有下载它们的依赖那么需要先给pip装一个numpy、pillow、typing-extensions等基础库。这也是为什么我建议在联网机器上把整个依赖树都下载下来的原因。4.2 路径BMiniforge自建高一版Python环境如果系统python是3.6你只有两条路要么把Python整个升级要么用一个环境管理工具自建一个独立Python。升级系统Python我强烈不建议arm架构下从源码编译Python是精力黑洞而且会破坏系统包管理器的依赖关系。更理智的选择是使用Miniforgeconda的aarch64发行版。Miniforge支持Linux aarch64并且内置了mamba和conda可以在用户目录下安装不污染系统环境。离线机器上装Miniforge的步骤在联网机器上下载Miniforge3-Linux-aarch64.sh注意一定是aarch64版本不要下x86_64的。把安装脚本拷贝到目标机。执行bash Miniforge3-Linux-aarch64.sh -b -p /data/miniforge3-b表示静默安装-p指定安装路径。安装完成后激活环境export PATH/data/miniforge3/bin:$PATH然后创建Python 3.8环境conda create -n torch38 python3.8 -y conda activate torch38接下来用这个环境里的pip执行离线安装pip install --no-index --find-links/data/pytorch_offline/ torch torchvision numpyMiniforge这条路线的最大优点是所有Python层面的依赖都隔离在这个独立环境里不会跟系统python的模块打架。尤其适合那些后续要跑多个不同深度学习项目的场景一个环境一套依赖互不干扰。4.3 挂载麒麟安装镜像补齐libgomp等系统级依赖离线环境下yum默认是连不上外网源的。很多教程会直接跳过这一步结果装完torch一import就报ImportError: /lib64/libgomp.so.1: cannot open shared object file: No such file or directory这个错就是系统级运行库缺失。解决思路是用麒麟ISO做本地yum源。把ISO文件上传到目标机后mkdir -p /media/kylin_iso mount -o loop /data/KylinLinuxAdvancedServerV10.iso /media/kylin_iso然后创建本地repo文件# /etc/yum.repos.d/kylin-local.repo [BaseOS] nameKylin BaseOS baseurlfile:///media/kylin_iso/BaseOS enabled1 gpgcheck0 [AppStream] nameKylin AppStream baseurlfile:///media/kylin_iso/AppStream enabled1 gpgcheck0清理缓存并刷新yum clean all yum makecache然后再装缺的库yum install -y libgomp libatomic libstdc glibc如果系统的/media/kylin_iso目录名或ISO内的目录结构和上面的示例不一致用ls查看一下实际结构再改repo文件。不同SP版本的麒麟ISO目录组织会有一点差异但BaseOS和AppStream这两个目录通常都在。4.4 验证import、张量计算、模型前向一次性跑通安装完成后不要急着部署应用先跑一个完整验证脚本。我习惯用下面这一段import torch import torchvision.models as models print(PyTorch版本:, torch.__version__) print(编译配置:, torch.__config__.show()) # 基础张量计算 x torch.rand(3, 3) y x x.t() print(张量计算验证:, y.sum().item()) # 检测CUDA是否可用 print(CUDA可用:, torch.cuda.is_available()) # 模型前向推理验证注意pretrainedFalse避免离线时下载权重 model models.resnet18(pretrainedFalse) model.eval() dummy torch.randn(1, 3, 224, 224) out model(dummy) print(ResNet18输出形状:, out.shape)如果这段脚本完整跑完不报错说明PyTorch和torchvision环境是通的。pretrainedFalse这个参数一定要带否则程序会尝试联网下载预训练权重在离线环境里卡在进度条上。torch.__config__.show()会打印编译时的版本信息包括是否开启了AVXx86或NEONARM向量指令优化以及OpenMP线程库的状态。如果看到OpenMP相关的问题通常和前面说的libgomp有关。5. 离线安装后的高频异常从报错到解决5.1 cannot open shared object file: libgomp.so.1报错现场 import torch ImportError: /lib64/libgomp.so.1: cannot open shared object file: No such file or directory原因PyTorch的manylinux wheel在编译时链接了OpenMP多线程库。目标系统上缺少对应的运行库文件时动态加载器就找不到符号直接抛错。排查链路先用ldconfig -p | grep libgomp看系统里是否真的有这个库。如果输出为空说明确缺失。再用ls -l /lib64/libgomp*确认是不是只有一个版本。解决按4.3的流程挂载ISO后yum install -y libgomp。如果安装完还是报错执行ldconfig刷新一下动态库缓存。这个库很小几百KB但缺了它整个PyTorch就无法加载。5.2 GLIBCXX_3.4.x not foundconda和系统动态库打架报错现场ImportError: /usr/lib64/libstdc.so.6: version GLIBCXX_3.4.21 not found原因这个错在Miniforge路径下出现频率最高。conda环境自带的libstdc.so.6版本较老而PyTorch的wheel需要较新的GLIBCXX符号。或者反过来系统库和新环境库混用导致加载到旧版本。排查链路strings /usr/lib64/libstdc.so.6 | grep GLIBCXX | sort -V | tail这条命令能看到当前库支持哪些GLIBCXX版本。如果最高只到3.4.20而torch要求3.4.21就必然报错。解决首选办法是升级conda环境里的libstdcxx-ngconda install -c conda-forge libstdcxx-ng -y如果升级不了离线环境下载不了conda包可以临时把系统的库路径放到LD_LIBRARY_PATH最前面强制使用系统新版库export LD_LIBRARY_PATH/usr/lib64:$LD_LIBRARY_PATH但这个设置只对当前shell有用最好写进~/.bashrc持久化。5.3 numpy版本过低引发numpy.float64 object is not iterable报错现场TypeError: numpy.float64 object is not iterable原因PyTorch新版本对numpy有最低版本要求一般是numpy1.21。如果系统里残留了老版本的numpy比如通过yum装的1.16pip在装torch时认为依赖已满足就不去升级导致运行时行为异常。排查链路分别检查两个位置的numpy版本python3 -c import numpy; print(numpy.__version__)如果输出小于1.21说明版本太老。再看一下自己是在系统环境还是Miniforge环境里两个环境site-packages下的numpy可能不是同一个。解决在离线资源包里备好一个适配Python版本的numpy版本统一安装。比如Python 3.8就用numpy 1.24.4pip install --no-index --find-links/data/pytorch_offline/ --force-reinstall numpy1.24.4装完再python3 -c import numpy; print(numpy.__version__)确认。5.4 明明Successfully installedimport torch却报No module named报错现场pip install --no-index --find-links/data/pytorch_offline/ torch torchvision # 显示Successfully installed torch-2.0.1 torchvision-0.15.2 python3 -c import torch ModuleNotFoundError: No module named torch原因这种诡异情况大概率是pip3和python3指向了不同的解释器。比如pip3是/usr/local/bin下的而python3是/usr/bin下的。pip把包装到了/usr/local/lib/python3.8/site-packages但python3启动时加载的是/usr/lib/python3.8/site-packages。排查链路which python3 which pip3 python3 -m pip --version第三个命令最关键——python3 -m pip会用python3对应的解释器去执行pip这样可以确认它们是否一致。解决不要裸调pip3 install一律用python3 -m pip install来安装确保包装到当前python3解释器的sys.path里。如果Miniforge环境里出现这个问题多半是activate环境时PATH顺序被覆盖检查conda info --envs和which pip。5.5 一跑就崩段错误(Segmentation fault)多半是BLAS库冲突报错现场Segmentation fault (core dumped)原因ARM64架构下PyTorch的wheel内部自带OpenBLAS实现如果系统也装了OpenBLAS且LD_PRELOAD或LD_LIBRARY_PATH里有指向系统OpenBLAS的路径就会发生符号冲突导致段错误。排查链路gdbserver --attach :1234 pid # 如果gdb不方便就直接看ldd ldd /data/miniforge3/envs/torch38/lib/python3.8/site-packages/torch/lib/libtorch.so | grep -E openblas|blas重点看有没有同时加载了libopenblas.so而且路径不是conda环境内部的。解决最直接有效的方法是把LD_LIBRARY_PATH清理掉让PyTorch加载自己wheel里的BLAS实现unset LD_LIBRARY_PATH如果必须在LD_LIBRARY_PATH里加系统库那就要精确到具体路径不要一个目录全放进去。另外也可以试验设置环境变量OPENBLAS_NUM_THREADS1避免多线程竞争导致的崩溃。6. GPU和国产加速卡装之前先想清楚这一步6.1 NVIDIA GPU在ARM Linux上的安装门槛如果你手上的ARM服务器恰好装了NVIDIA GPU比如英伟达的某些ARM服务器方案那么需要确认驱动和CUDA版本都是针对aarch64的。NVIDIA有提供ARM64版本的CUDA ToolkitPyTorch官方也会发布cu118、cu121等aarch64变体的wheel。安装命令和x86机器类似但要注意pip install --no-index --find-links/data/pytorch_offline_cuda/ torch torchvision前提是你的离线资源包里放的是CUDA版wheel而且是aarch64平台标签。CUDA环境下NVIDIA驱动安装尤其繁琐rpm包依赖多如果驱动装不上后面一切都免谈。建议先跑通CPU版再把CUDA版当作增量升级。6.2 昇腾、寒武纪等国产加速卡的PyTorch生态思路国内ARM服务器上最常碰到的其实是昇腾、寒武纪、天数智芯、海光等加速卡。它们的PyTorch适配思路大同小异官方提供一个插件或配套wheel安装之后再打一个补丁或通过环境变量让PyTorch调用自家设备。以昇腾为例通常的路径是安装CANN工具包这是昇腾的计算框架基础。安装torch_npu插件包并选择与CANN版本、PyTorch版本匹配的版本。在代码里通过import torch_npu来激活NPU设备。对这些国产加速卡最关键的还是版本匹配矩阵。厂商官网都会有一张表格说明CANN、PyTorch、torch_npu三者版本怎么配对。填错了就是各种undefined symbol和段错误而且离线环境下错误信息往往非常隐晦。我的建议是初始部署阶段不要一上来就搞GPU/NPU加速先用CPU版把代码逻辑跑通确认PyTorch环境没问题之后再叠加厂商加速卡适配。否则两个陌生变量叠加在一起出了问题根本分不清是PyTorch的问题还是驱动的问题。6.3 一个务实提前量先规划好推理与训练的场景有些项目其实根本用不到GPU/NPU加速比如轻量级模型的在线推理或者做特征提取。ARM服务器的CPU核数通常很多配合OpenMP跑batch size较小的推理任务完全够用。这种情况下CPU版PyTorch反而是最稳定、最干净的选择。反过来如果你确认要跑大模型训练那么从一开始就要把厂商加速卡的配套环境规划进去离线资源包里除了torch还要下载厂商提供的运行时和插件。不要等到模型跑起来了再回头补环境那时候改起来比现在麻烦得多。我在实际部署中的体会是离线安装这事情八成的工作量花在确认版本匹配上真正敲命令的时间很少。尤其是ARM架构一个wheel选错后面所有步骤全是白费。建议你把官方whl索引页的aarch64过滤结果截个图选好版本后对照Python版本再核对一遍再挂到目标机上安装。这种笨功夫看起来慢实际是内网环境里最省时间的做法。