摘要:把一个 PyTorch 项目迁移到 DCU,真正费时间的部分通常不是修改模型,而是确认软件栈是否一致:驱动能否识别设备、PyTorch 是否链接到正确的 HIP 运行时、动态库路径是否混入其他版本、扩展是否为目标架构编译,以及错误究竟发生在 Python、框架还是设备侧。

本文以 DTK 环境为例,给出一套可复用的迁移和排障顺序。目标不是列一堆环境变量,而是建立分层诊断方法:先验证硬件,再验证运行时,然后验证框架,最后才运行应用。

关键词:DCU、DTK、PyTorch、HIP、环境迁移、故障排查

1. 先理解软件栈的分层

一个典型的 DCU PyTorch 任务至少经过四层:

Python应用
    ↓
PyTorch / 第三方框架
    ↓
HIP 运行时、数学库、通信库
    ↓
DCU 驱动与硬件

迁移失败时,如果直接从业务代码开始改,很容易把环境问题误判成模型问题。更稳妥的做法是从底层向上验证,每一层只回答一个问题。

层级要回答的问题常用检查方式
硬件与驱动系统是否识别 DCUrocminfo、设备管理工具
HIP 运行时目标架构和运行时是否可用hipcc --version、运行时库检查
PyTorch当前 Python 是否为 HIP 构建torch.version.hip、设备张量测试
应用数据、模型和算子是否兼容最小输入、单步前向、日志

这套顺序的价值在于:上一层没有通过,就不进入下一层。

2. 第一层:确认设备和目标架构

首先查看设备信息:

rocminfo

重点不是保存整份输出,而是确认:

  • 能否枚举到目标 DCU;
  • 设备架构名称是否符合预期;
  • wavefront 宽度、可用显存和计算单元是否正常;
  • 当前用户是否有访问设备节点的权限。

如果 rocminfo 都无法识别设备,继续检查 PyTorch 没有意义。此时应优先排查驱动、容器设备映射和用户权限。

设备显存和运行状态可通过环境提供的管理工具观察。诊断时要记录空闲基线:一个看似"刚启动"的任务,也可能继承同卡其他进程或运行时上下文的显存占用。

3. 第二层:确认 DTK 与动态库来源

同一台机器上可能存在多个 DTK 目录。最常见的问题不是缺少库,而是加载了错误版本的同名库。

进入容器后先加载官方环境:

source /opt/dtk-25.04.2/env.sh

再检查编译器:

which hipcc
hipcc --version

如果非交互 shell 没有完整继承环境,可检查:

echo "$LD_LIBRARY_PATH"

不建议无条件把大量路径追加到 LD_LIBRARY_PATH。更好的原则是:

  1. 先使用镜像提供的环境脚本;
  2. 确认缺失的具体 .so
  3. 只补充对应版本的目录;
  4. 避免把不同 DTK 版本混在同一搜索路径中。

遇到 undefined symbol 时,文件"存在"不代表版本正确。应使用 ldd 检查实际链接目标:

ldd /path/to/extension.so

4. 第三层:确认当前 PyTorch 真正在用 HIP

很多 HIP 版 PyTorch 仍沿用 `torch.cuda` API。看到 `torch.cuda.is_available()` 不应直接推断它在使用 NVIDIA CUDA;需要同时检查 HIP 版本和设备信息。

最小验证脚本:

import torch

print("torch:", torch.__version__)
print("hip:", torch.version.hip)
print("available:", torch.cuda.is_available())
print("device_count:", torch.cuda.device_count())

if torch.cuda.is_available():
print("device:", torch.cuda.get_device_name(0))
x = torch.arange(8, device="cuda", dtype=torch.float32)
print((x * 2).cpu())

这段代码同时验证:Python 环境、PyTorch 构建、设备枚举、显存分配、kernel launch 和 D2H 回传。只有它通过后,才值得加载大型模型。

5. 第四层:用最小应用逐步放大

不要第一次就运行完整训练或完整评测。建议按以下顺序:

导入依赖
→ 构造单个设备张量
→ 加载配置
→ 构造模型但不加载权重
→ 加载权重
→ 单个算子
→ 单个最小样本前向
→ 完整数据管线

每一步都应打印明确的边界日志。例如,把“模型加载失败”拆成:配置解析、模型构造、checkpoint反序列化、state-dict匹配和模型迁移到设备五个步骤。这样错误发生时,不必从几千行日志中猜测。

6. PyTorch项目迁移时的兼容原则

6.1 不要用平台字符串判断后端

应用代码应优先使用 PyTorch 能力检查:

if not torch.cuda.is_available():
raise RuntimeError("No accelerator is available")

需要区分 HIP 与 CUDA 时,再检查:
 

is_hip = torch.version.hip is not None

6.2 避免在模块导入阶段分配设备资源

Python import 时就创建 stream、event 或大 tensor,会让错误难以定位,也会让单元测试必须依赖设备。更合理的做法是在显式初始化函数中创建资源,并允许 CPU 环境只做源码检查。

6.3 固定dtype和shape要有断言

如果某条路径只支持 FP16 或固定宽度,应在入口立即检查:

if x.dtype != torch.float16:
raise TypeError("expected FP16 input")
if not x.is_contiguous():
raise ValueError("expected contiguous input")

静默接受错误输入,往往会把问题推迟到设备 kernel 中,最终只得到难以解释的非法访存。

7. 常见故障及定位顺序

7.1 `No device` 或设备数为0

依次检查:

1. 宿主机能否识别设备;
2. 容器是否映射设备节点;
3. 当前用户权限;
4. PyTorch是否为HIP构建;
5. 环境变量是否隐藏了全部设备。

7.2 动态库找不到

先记录缺失库名,再用 `ldd` 和系统搜索定位。不要通过不断追加未知目录来“碰运气”,否则很容易从“找不到库”变成“加载了错误库”。

7.3 扩展编译成功但加载失败

重点检查:

  • 编译目标架构是否与设备一致;
  • C++ ABI是否与当前PyTorch匹配;
  • 扩展链接到了哪个运行时;
  • 编译缓存是否来自旧环境;
  • Python实际导入的是不是刚编译的文件。

7.4 首次运行很慢

首次运行可能包含扩展编译、动态库加载和后端算法初始化。应把“启动时间”和“稳定执行时间”分别记录,不能把两者混成一个平均数。

8. 建议保存的环境快照

为了让问题能够复现,至少保存:

  • 操作系统和容器镜像标识
  • DTK版本
  • hipcc版本
  • PyTorch版本
  • torch.version.hip
  • 设备架构名称
  • Python版本
  • 关键依赖版本
  • 运行命令
  • 必要的环境变量

快照中不应包含账号、口令、token或内部下载地址。

9. 一份可执行的迁移检查清单

  • `rocminfo` 能识别目标DCU;
  • `hipcc --version` 与容器DTK版本一致;
  • `torch.version.hip` 非空;
  •  设备张量的创建、计算和回传通过;
  •  应用可以构造模型并加载权重;
  •  最小样本前向通过;
  •  dtype、shape、device和contiguous条件有明确检查;
  •  完整运行前保存环境快照;
  •  不混用不同DTK版本的动态库。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐