DTK 环境下的 DCU PyTorch 迁移与排障:从“能识别设备”到稳定运行
摘要:把一个 PyTorch 项目迁移到 DCU,真正费时间的部分通常不是修改模型,而是确认软件栈是否一致:驱动能否识别设备、PyTorch 是否链接到正确的 HIP 运行时、动态库路径是否混入其他版本、扩展是否为目标架构编译,以及错误究竟发生在 Python、框架还是设备侧。
本文以 DTK 环境为例,给出一套可复用的迁移和排障顺序。目标不是列一堆环境变量,而是建立分层诊断方法:先验证硬件,再验证运行时,然后验证框架,最后才运行应用。
关键词:DCU、DTK、PyTorch、HIP、环境迁移、故障排查
1. 先理解软件栈的分层
一个典型的 DCU PyTorch 任务至少经过四层:
Python应用
↓
PyTorch / 第三方框架
↓
HIP 运行时、数学库、通信库
↓
DCU 驱动与硬件
迁移失败时,如果直接从业务代码开始改,很容易把环境问题误判成模型问题。更稳妥的做法是从底层向上验证,每一层只回答一个问题。
| 层级 | 要回答的问题 | 常用检查方式 |
|---|---|---|
| 硬件与驱动 | 系统是否识别 DCU | rocminfo、设备管理工具 |
| 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。更好的原则是:
- 先使用镜像提供的环境脚本;
- 确认缺失的具体
.so; - 只补充对应版本的目录;
- 避免把不同 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版本的动态库。
更多推荐




所有评论(0)