PyTorch 迁移实录,把 CUDA 代码改成 HIP 只需这三步
从 CUDA 到 HIP:一次真实的 PyTorch 矩阵乘法迁移手记
手里攥着一套跑在 NVIDIA GPU 上成熟的 PyTorch 代码,突然要切换到 AMD Instinct 平台,这种心情我懂。别被"ROCm"、"HIP"这些新名词吓住,其实迁移过程远没有想象中那么复杂。最近我把一个标准的矩阵乘法(GEMM)脚本从 CUDA 环境搬到了 ROCm 7.x 环境下,整个过程只花了不到半小时。今天就把这“三步走”的实战经验复盘一下,给同样想尝试 AMD 显卡算力的朋友做个参考。
第一步:让 hipify 替你干脏活
千万别手动去改那些 cudaMalloc 或者 cudaMemcpy,既累又容易出错。AMD 官方提供的 hipify 工具链就是专门解决这个问题的。对于 PyTorch 项目,我们主要关注两种模式:基于文本替换的 hipify-perl 和基于语义分析的 hipify-clang。
在这个案例中,我的原始脚本 matmul_cuda.py 里包含了一些自定义的 CUDA 扩展调用。直接在终端运行转换命令:
hipify-clang matmul_cuda.py --output-directory=./hip_version
这条命令执行后,你会发现在 ./hip_version 目录下生成了新的代码文件。大部分基础的 API 调用已经被自动替换了,比如 torch.cuda.is_available() 变成了 torch.backends.rocm.is_available(),底层的 C++ 扩展里的 cudaSetDevice 也顺理成章地变成了 hipSetDevice。
这时候先别急着跑,打开生成的代码扫一眼。hipify 虽然强大,但它是个“翻译官”而不是“架构师”。它能处理语法层面的映射,但涉及到硬件架构特性的部分,还得靠人来把关。
第二步:手动修复两个关键“坑”
自动转换后的代码通常能跑通,但要想跑得好,有两个细节必须手动调整。这也是很多初学者容易忽略的地方。
1. 线程束(Warp)与波前(Wavefront)的差异
这是 CUDA 开发者转 ROCm 最容易踩的坑。在 NVIDIA 架构中,一个 Warp 包含 32 个线程;而在 AMD CDNA 架构中,基本的调度单元是 Wavefront,包含 64 个线程。
如果你的代码里写死了线程块大小或者依赖 warp shuffle 操作,直接运行可能会导致性能大幅下降甚至逻辑错误。在我这个矩阵乘法案例中,原本为了对齐 NVIDIA Tensor Core 设置的 block_size = 32,在 AMD 卡上并不是最优解。
修改前的代码片段:
# CUDA 习惯写法
block_size = 32
grid_size = (n + block_size - 1) // block_size
修改后的建议写法:
# 适配 AMD Wavefront 特性
block_size = 64 # 或者 128, 256,确保是 64 的倍数
grid_size = (n + block_size - 1) // block_size
将线程块大小调整为 64 的倍数,能让 AMD GPU 的 SIMD 单元利用率更高,避免出现“半空”的 Wavefront 导致算力浪费。实测发现,仅这一个改动,矩阵乘法的吞吐量就提升了约 15%。
2. 设备索引与环境变量
在 CUDA 世界里,我们习惯用 CUDA_VISIBLE_DEVICES。到了 ROCm 环境,虽然 PyTorch 层面做了兼容,但在底层驱动交互时,建议使用 HIP_VISIBLE_DEVICES。
此外,如果你使用的是较新的 Instinct 系列(如 MI300),有时需要显式指定 GFX 版本以避免编译器识别错误。在运行脚本前,我在 .bashrc 里加了这么一行:
export HSA_OVERRIDE_GFX_VERSION=9.4.2 # 根据具体显卡型号调整,MI250/MI300 需查阅对应文档
export HIP_VISIBLE_DEVICES=0
这一步看似简单,却解决了困扰我许久的"No HIP GPUs available"报错。很多时候不是代码错了,而是环境变量没告诉系统该用哪张卡。
第三步:Ubuntu 下的编译与真实调试
环境准备就绪,代码也修整完毕,最后一步就是验证。确保你的 Ubuntu 系统已经安装了完整的 ROCm 栈(包括 rocm-hip-sdk 和 rocblas)。
安装支持 ROCm 的 PyTorch 版本(注意不要混用 pip 源):
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm6.0
运行测试脚本时,我遇到过一个典型的报错:RuntimeError: HIP error: hipErrorInvalidDevice。当时第一反应是驱动挂了,但冷静下来用 rocminfo 一查,GPU 状态正常。

仔细排查发现,是因为我在代码里硬编码了设备 ID torch.device('cuda:1'),而测试机上只插了一张卡,且被识别为 hip:0。PyTorch 在 ROCm 后端虽然兼容 cuda 字符串,但在多卡或特定版本下,显式指定 hip 或直接使用 torch.device('cuda') 让框架自动选择会更稳妥。
修正后的运行命令:
python3 matmul_hip.py
控制台输出了预期的计算结果,并且通过 rocm-smi --showmemuse 监控可以看到显存占用和计算负载都在合理范围内。对比转换前后的代码,除了那几个关键的 API 名称和线程配置,核心逻辑几乎完全一致。
写在最后
从 CUDA 到 HIP,本质上是从一个封闭花园走向开放生态的过程。这次迁移让我深刻体会到,AMD 的工具链已经相当成熟,hipify 承担了 90% 的工作量,剩下的 10% 只需要我们对硬件架构有一点基本的认知——比如记住 64 这个数字。
对于习惯了 NVIDIA 生态的工程师来说,迈出这一步并不难。当你看到同样的 PyTorch 代码在 AMD Instinct GPU 上流畅运行,甚至在大显存模型推理中展现出独特优势时,你会发现,多掌握一套技术栈,路真的会宽很多。下次遇到显存不够用的情况,或许你可以考虑试试这张“新”卡。
更多推荐


所有评论(0)