昇腾NPU上编译Apex:从踩坑到搞定
我们用的是MindIE的openEuler镜像,先装基础依赖:暂时无法在飞书文档外展示此内容然后就可以开始执行编译:暂时无法在飞书文档外展示此内容Apex编译看似简单,实则暗藏许多细节。本文通过真实案例,深入剖析了从网络代理到系统库路径的各个环节。Docker守护进程代理配置容易漏lib和lib64路径差异编译脚本会覆盖手动修改希望大家可以学习一些经验教训,对于大模型训练来说,Apex基本是必备工
最近在昇腾平台上跑Qwen3-30B的训练任务,要用混合精度加速。PyTorch原生的AMP在昇腾上支持不太好,查了一圈发现得用Apex for Ascend。网上教程不少,但都是基于官方容器的,我们这边用的是自己的基础镜像,按照官方文档编译直接翻车。这篇文章记录完整的编译过程和遇到的几个大坑。
一、为什么要用Apex
1.1 混合精度训练
大模型训练最头疼的就是显存不够和速度慢。混合精度训练能在几乎不掉精度的情况下:
- 训练速度提升2-3倍
- 显存占用减半
原理很简单:计算密集的算子用FP16,精度敏感的算子用FP32。Apex帮你自动处理这个切换,不用手动改代码。
1.2 昇腾为啥要适配
NVIDIA的Apex直接调CUDA算子,在昇腾上跑不了。Apex for Ascend做了两件事:
- 把CUDA算子替换成CANN算子
- 保持API不变,用户代码不用改
代码仓库:
- 昇腾版:https://gitcode.com/Ascend/apex
- 原版:https://github.com/NVIDIA/apex
二、网络配置
2.1 为什么要配代理
编译过程需要拉取镜像和下载依赖包,网络不通的话啥都干不了。很多人以为在终端里export一下就行了,其实不够。
很多同学以为设置了export http_proxy就万事大吉,但实际上:
用户Shell → Docker守护进程 → 容器内进程
↓ ↓ ↓
需要代理 需要代理 需要代理
需要配置三层:
- Shell环境(影响curl、git等命令)
- Docker守护进程(影响镜像拉取)
- 容器内环境(影响pip安装)
2.2 Shell环境代理
暂时无法在飞书文档外展示此内容
这个配置重启终端就失效了,想永久生效写到~/.bashrc。
2.3 Docker守护进程代理
Docker daemon作为系统服务运行,不继承Shell环境变量,必须单独配置。
检查当前配置:
暂时无法在飞书文档外展示此内容
配置步骤:
- 创建配置目录:
暂时无法在飞书文档外展示此内容
- 创建HTTP代理配置
暂时无法在飞书文档外展示此内容
- 创建HTTPS代理配置(
https-proxy.conf):
暂时无法在飞书文档外展示此内容
- 重载并重启Docker服务:
暂时无法在飞书文档外展示此内容
排查技巧: 如果配置后仍无法拉取镜像,检查:
-
代理服务器是否允许Docker daemon的IP访问
-
防火墙规则是否拦截
-
/var/log/docker.log中的错误信息
如果还是拉不了镜像,检查一下防火墙和代理服务器的访问控制。
三、官方容器编译
先说一下官方推荐的流程,作为对照。

3.1 构建镜像
首先在我们的环境中直接拉取Apex的镜像:
暂时无法在飞书文档外展示此内容

这步会比较慢,等三四分钟左右,然后切换到apex目录:cd apex

根据CPU架构选择,因为我们的主机是x86_64架构,所以选择:cd scripts/docker/X86,如果是ARM就需要选择下面的指令:
暂时无法在飞书文档外展示此内容
上面的工作做完之后呢,直接去构建我们的镜像即可:
暂时无法在飞书文档外展示此内容

3.2 启动容器
镜像配置完成之后,我们直接启动容器,这里需要-v参数把代码挂载进去,编译产物会同步到宿主机:
暂时无法在飞书文档外展示此内容
3.3 安装环境
进入容器之后,首先安装torch:
暂时无法在飞书文档外展示此内容

然后去验证我们的torch是否安装成功,这里显示版本号就说明已经安装成功了:
暂时无法在飞书文档外展示此内容

这里一定要注意是指令python3,如果是python的话就很容易报错。
3.4 自定义镜像编译
我们用的是MindIE的openEuler镜像,先装基础依赖:
暂时无法在飞书文档外展示此内容
然后就可以开始执行编译:
暂时无法在飞书文档外展示此内容
四、踩坑记录
4.1 镜像拉取失败
执行docker build的时候报错:
暂时无法在飞书文档外展示此内容
或者:
暂时无法在飞书文档外展示此内容
原因就是Docker守护进程没配代理,按照前面的方法配置就行。

如果不想配代理,可以用国内镜像源:
暂时无法在飞书文档外展示此内容
4.2 找不到libtorch.so
这是最坑的一个问题。编译到最后报错:
暂时无法在飞书文档外展示此内容

一开始以为是torch没装上,用Python测试了一下:
暂时无法在飞书文档外展示此内容
输出:
暂时无法在飞书文档外展示此内容
torch装在lib64下,没问题啊。然后又试了找文件:
暂时无法在飞书文档外展示此内容

发现torch安装在<font style="color:rgb(216,57,49);">/usr/local/lib64/python3.8/site-packages/</font>,而非<font style="color:rgb(216,57,49);">/usr/local/lib/</font>。
那为什么链接器找不到呢?看了一下编译脚本,查看<font style="color:rgb(216,57,49);">apex/scripts/build.sh</font>:

scripts/build.sh调用的是setup.py,在<font style="color:rgb(216,57,49);">apex/setup.py</font>中搜索<font style="color:rgb(216,57,49);">torch</font>关键字:

搜索一下里面的路径相关代码,找到了这个函数:

暂时无法在飞书文档外展示此内容
问题找到了:脚本硬编码了/lib/,但openEuler上Python装在/lib64/下。
lib和lib64的区别
这不是bug,是Linux发行版的历史遗留设计。
Red Hat系(openEuler、CentOS、RHEL):
暂时无法在飞书文档外展示此内容
Debian系(Ubuntu、Debian):
暂时无法在飞书文档外展示此内容
Red Hat明确区分32位和64位库,Debian用子目录区分。Python的安装路径取决于:
- 包管理器安装:遵循发行版规范
- 源码编译:看configure参数
- pip安装:继承Python解释器的配置
解决办法
方法一:改setup.py
直接修正路径逻辑:
暂时无法在飞书文档外展示此内容
然后直接编译:
暂时无法在飞书文档外展示此内容
注意不要再用scripts/build.sh,因为它会重新clone代码把你的修改覆盖掉。
方法二:建软链接
不改代码,建个符号链接绕过:
暂时无法在飞书文档外展示此内容
这个方法简单快速,但可能影响其他程序。
方法三:虚拟环境
最推荐的方式:
暂时无法在飞书文档外展示此内容
虚拟环境统一用lib/路径,不会有lib64问题。
4.3 指令错误
刚开始的指令是:python -c “import torch; print(torch.version)”,会发现抛出错误:bash: python: command not found

需要我们换一个Python指令,也就是需要把Python版本几去指出来,这里python3是最常见的,换成这个指令即可:python3 -c “import torch; print(torch.version)”。
五、实验测试
实验测试分为两个阶段:基础环境验证和混合精度性能对比。基础测试是用来确定环境是否可行;性能对比测试则聚焦 Apex AMP 混合精度训练的作用,也就是是否可以提升训练速度并降低显存占用。
5.1 基础测试
基础测试的核心目标是校验环境是否可以,避免因环境配置问题导致后续训练测试失败。
暂时无法在飞书文档外展示此内容
测试结果如下:

Torch: 2.1.0
Apex available: True
NPU是否可用: True
当前NPU设备ID: 0
说明已经可以正常运行了。
5.2 混合精度训练测试
写个完整的脚本测试一下:
暂时无法在飞书文档外展示此内容
输出结果如下:

给我们的结果显示,FP32训练: 8.43秒,同时AMP训练: 4.21秒,加速比: 2.00x,AMP 混合精度训练耗时 4.21 秒,纯 FP32 训练耗时 8.43 秒,有了近两倍的加速,这一结果符合混合精度训练的预期。
六、总结
Apex编译看似简单,实则暗藏许多细节。本文通过真实案例,深入剖析了从网络代理到系统库路径的各个环节。在自定义镜像上编译Apex for Ascend,主要坑点总结为以下三点:
- Docker守护进程代理配置容易漏
- lib和lib64路径差异
- 编译脚本会覆盖手动修改
希望大家可以学习一些经验教训,对于大模型训练来说,Apex基本是必备工具。昇腾适配版虽然有些小坑,但整体可用性还不错,注明:昇腾PAE案例库对本文写作亦有帮助。
更多推荐

所有评论(0)