最近在昇腾平台上跑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守护进程 → 容器内进程

 ↓ ↓ ↓

 需要代理 需要代理 需要代理

需要配置三层:

  1. Shell环境(影响curl、git等命令)
  2. Docker守护进程(影响镜像拉取)
  3. 容器内环境(影响pip安装)

2.2 Shell环境代理

暂时无法在飞书文档外展示此内容

这个配置重启终端就失效了,想永久生效写到~/.bashrc

2.3 Docker守护进程代理

Docker daemon作为系统服务运行,不继承Shell环境变量,必须单独配置。

检查当前配置:

暂时无法在飞书文档外展示此内容

配置步骤:

  1. 创建配置目录:

暂时无法在飞书文档外展示此内容

  1. 创建HTTP代理配置

暂时无法在飞书文档外展示此内容

  1. 创建HTTPS代理配置(https-proxy.conf):

暂时无法在飞书文档外展示此内容

  1. 重载并重启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的安装路径取决于:

  1. 包管理器安装:遵循发行版规范
  2. 源码编译:看configure参数
  3. 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,主要坑点总结为以下三点:

  1. Docker守护进程代理配置容易漏
  2. lib和lib64路径差异
  3. 编译脚本会覆盖手动修改

希望大家可以学习一些经验教训,对于大模型训练来说,Apex基本是必备工具。昇腾适配版虽然有些小坑,但整体可用性还不错,注明:昇腾PAE案例库对本文写作亦有帮助。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐