你是一家深度学习餐饮连锁的总厨。招牌菜谱(PyTorch 框架)在 NVIDIA 的商场里开得风生水起——那里有现成的燃气管道、排烟系统和水电接口,这套标准叫 CUDA。可最近商场的租金水涨船高,隔壁 AMD 商场给出了诱人的免租期,唯一的问题是:它家的厨房插座、灶台火力、货架尺寸全都自成一套。你要做的,不是把菜谱改成另一本菜谱,而是用上 AMD 商场提供的“厨房改造包”——ROCm,让总店的菜谱原封不动地在新厨房里照样出菜。这篇文章就是你的《AMD 分店开业指南》:从认识 ROCm 生态里每个部件是什么,到安装调试、把食材(张量)在两个厨房间搬运、把每道菜的做法翻译成新厨房的操作手册(算子编译)、管理冷库货架(显存池)、优化厨房动线(性能),再到出问题时怎么调监控(性能剖析)。跟着这条线走完,你就能底气十足地说:换厨房,不换菜谱。
对 AI 从业者来说,掌握 PyTorch ROCm 后端,意味着你在 GPU 紧缺、算力涨价的年代多了一把打开 AMD 算力的钥匙,能无缝迁移训练与推理任务,成为团队里稀缺的跨平台 AI 工程人才。
可视化演示
展示ROCm技术栈架构、CUDA与ROCm接口差异映射及算子覆盖度性能三种核心模式,直观呈现PyTorch ROCm后端从API层到硬件层的跨平台GPU编程方案。
本节配有交互动效(进入视口后自动加载,约 3KB)。
ROCm技术栈架构 PyTorch经ROCm运行时HIP驱动层直达AMD GPU硬件 四层抽象实现跨平台GPU编程统一接口 PyTorch → ROCm → HIP → GPU ROCm是AMD GPU生态的CUDA替代方案
ROCm生态全景
想象你是一家连锁 AI 餐厅的总厨,正打算在 AMD 这家新商场开分店。商场招商经理递给你一张《基础设施清单》:燃气管道走哪堵墙、水电表装在几楼、排烟通道是否合规。这套清单对应到 GPU 计算世界,就是 ROCm——AMD 为自家显卡准备的一整套“厨房基础设施方案”。
我们知道 NVIDIA 的厨房标准叫 CUDA,老分店全靠它。而 AMD 商场不认 CUDA 的接口,它有自己的标准叫 ROCm(Radeon Open Compute)。ROCm 不是单个软件,而是一个从底层驱动到高层算子库的完整软件栈,对标 NVIDIA 的 CUDA 全家桶。
从下往上看,ROCm 分三层:驱动层负责最底层硬件控制,由 amdgpu 内核模块和 ROCk(ROCm Kernel Driver)组成,相当于大楼的总水管和总电闸;运行时层是 HIP Runtime,通过 ROCclr 桥接驱动,提供 hipMalloc、hipLaunchKernel 等 API——HIP 的语法与 CUDA 高度相似,这也是 PyTorch 能“源码级”移植的前提;算子库层则是现成的“半成品食材包”,包括 rocBLAS(线性代数)、MIOpen(卷积等深度学习算子)、rocFFT、RCCL(通信库),分别对标 cuBLAS、cuDNN、NCCL。
就像开分店必须先确认燃气、水电、排烟三项到位,理解 ROCm 的三层结构,是后面一切安装、调试、优化工作的地基。下一节,我们就拿着这份清单开始“装修”。
环境安装配置
基础设施确认了,接下来是“进厨具”。总店的菜谱是 PyTorch,好消息是——菜谱不用改,但得买专供 AMD 厨房的“定制菜谱版本”:PyTorch 官方发布的 ROCm 轮子(wheel 包,相当于预装好依赖的安装包)。
为什么不能直接 pip install torch?因为官方默认 wheel 捆绑的是 CUDA 运行时,在 AMD 厨房里属于“异国标准”。安装 ROCm 版要指定独立下载源,例如:
安装成功不等于能用。三个版本的匹配至关重要:Linux 内核 → AMD 驱动/ROCm 运行库 → PyTorch wheel 里链接的 ROCm 库 SOVERSION(库版本标识),任何一层对不上都可能 import 崩溃。装好后用三个命令验证可用性:rocm-smi 看 GPU 状态;python -c "import torch; print(torch.cuda.is_available())" 返回 True 才代表后端真通了;python -c "print(torch.cuda.get_device_name(0))" 确认能看到 MI210 之类的 AMD 卡名。
是不是很像买锅碗瓢盆?品牌型号对不上,锅盖就盖不上灶台。搞定安装,接下来就看食材怎么在两个厨房之间流动。
pip install torch --index-url https://download.pytorch.org/whl/rocm6.0设备与张量流动
食材(模型权重和中间张量)平时住在 CPU 的“大冰箱”里,做菜时必须先搬进 GPU 的“灶台冷库”。两个厨房的储物柜物理上不互通,搬运就成了每次计算前最直观的开销。
PyTorch 的精妙之处在于“设备统一抽象”:无论底层是 NVIDIA 还是 AMD,你写的都是 tensor.to('cuda')。在 ROCm 后端,这个 'cuda' 设备会被映射到 HIP(AMD 的类 CUDA 编程接口)设备,上层代码几乎察觉不到换了厨房。
张量搬运调用的是 HIP 的异步拷贝(hipMemcpyAsync),它把任务丢进 GPU 队列就立即返回,并不等数据到达。如果你要“确认收到”,得调用 torch.cuda.synchronize()。这个异步语义也是很多“看起来没算完” bug 的来源——测速时少一次同步,数字就会虚高。真正可感知的搬运速度,要用有效带宽来衡量:
所以测搬运效率别只盯着数据手册上的理论带宽——就像请搬家师傅,装车和验货的时间也算钱。掌握了搬运开销,下一步我们看看真正“做菜”时发生了什么。
- 分子 D(数据量)待搬运张量的字节数,例如 1 GB 的模型权重,单位是字节。
- 拷贝时间 T_copyHIP 引擎真正执行 memcpy 的耗时,受限于 PCIe 或 HBM 带宽。
- 同步时间 T_sync调用 synchronize 等待异步队列排空的时间,相当于搬运后的“验货”环节。
- 有效带宽 BW_eff数据量除以两者之和,得到实际可感知的搬运速率,呼应了“异步≠免费”这个直觉。
算子编译执行
同一句“大火颠勺”,在 NVIDIA 厨房是灶台 A 的操作,到了 AMD 厨房得翻译成灶台 B 的操作。PyTorch 里每一个算子(卷积、矩阵乘、归一化)在 ROCm 上都面临一次“翻译”。
这个翻译是“惰性”的:不是装好环境就全翻译完,而是第一次用哪个算子,才翻译哪个。翻译发生在运行时——PyTorch 的前台接待员(dispatcher)收到算子调用后,把它派发到 ROCm 后端的底层算子库 ATen 实现,再由 HIP 编译器生成 AMD GPU 内核。
首次执行某类算子时,还可能触发算法自动调优(例如 MIOpen 对不同卷积形状 benchmark,挑选最快的实现);调优结果连同编译产物一起进入缓存。之后的调用直接命中缓存,Python 侧成本趋近于零——这就是“训练前几步慢、之后变快”的原因。平均时延能把这笔账算清楚:
翻译手册再厚,只要后面复印几千份,单价就趋近于零。所以别被“首次执行慢”吓到——只要训练循环够长,编译成本自然消失。翻译完了,食材也在灶台上了,剩下的问题是“菜放哪儿”。
- 一次性编译成本 T_compile首次调用时的源码翻译加自动调优耗时,可能高达数十秒,但只发生一次。
- 调用次数 N同一算子在训练循环中的执行次数,通常等于 step 数乘以网络层数。
- 单次执行时间 T_exec内核真正在 GPU 上的运行时间,与编译无关,是“做菜本身”的耗时。
- 摊薄效果当 N 趋向无穷时,平均时延收敛到 T_exec,编译成本被完全摊平。
显存池化管理
后厨的冷库货架有限,每道菜的食材用完就关一次库门很浪费。于是总店设了个“缓存货架”:食材用完不立即退租仓库,先摆在货架上,下道菜同样食材直接拿。
PyTorch 的缓存分配器(caching allocator)就是这个货架。在 ROCm 后端它同样生效:当你 torch.randn(..., device='cuda') 申请显存时,它先从自己的内存池里划一块给你,而不是直接调用昂贵的 hipMalloc。hipMalloc 相当于每次都要找房东签约,耗时巨大。
池子按显存块大小分桶管理,同一形状的张量反复申请/释放时极易命中。命中率 HR 直接决定分配开销:
还要注意碎片问题:形状忽大忽小的张量会让池子里的块无法拼接成大块。torch.cuda.empty_cache() 可以把池中闲置块归还给驱动,但代价是下次申请会重新走 hipMalloc。冷库管理好了,出菜速度就稳;但真正拉开差距的,是厨房动线——性能优化。
- 命中率 HR请求的显存块在池中直接找到的比例,稳定 shape 的训练循环里接近 1。
- 命中时延 tau_hit从池中划块的时间,通常微秒级,相当于货架上直接取货。
- 未命中时延 tau_miss被迫调用 hipMalloc 向驱动申请的时间,比命中贵几个数量级。
- 加权平均两者按命中率加权,就是实际感受到的分配速度,HR 越接近 1 越接近“秒取”。
性能优化路径
同样一桌菜,新手后厨来回跑 50 趟,熟手大厨设计动线后只跑 10 趟。GPU 计算里,“跑”的主要是内核启动和数据搬运。
PyTorch ROCm 后端的性能优化有三板斧:算子融合、混合精度、图捕获。算子融合把多个小算子合并成一个大内核,减少内核启动次数和中间张量的显存读写;混合精度用 float16/bfloat16 让单次搬运的数据量减半,对带宽瓶颈特别有效(torch.cuda.amp 在 ROCm 后端同样可用);图捕获(torch.cuda.graphs)把一串算子序列一次性捕获成可重放的计算图,把 CPU 侧的调度开销摊到零。
这三板斧能带来多少收益,服从 Amdahl 定律:
动线再优化,端菜出门那几步永远省不掉——先定位你自己的"1−p"在哪儿,再动手优化,才是最高效的路径。
- 可优化占比 p被融合、精度、图捕获覆盖的时间占比,例如矩阵乘占训练总耗时的 85%。
- 优化倍数 N单点优化带来的加速,比如带宽需求减半相当于 N=2。
- 串行部分 1-p数据搬运、同步、CPU 调度等难以消除的开销,是“端菜必走的那几步路”。
- 理论上限 S_max当 N 无限大时,加速比收敛到 1/(1-p),串行部分决定天花板。
调试性能剖析
出餐慢了、菜烧糊了,总得看监控才知道是切菜工位堵了还是灶台火力不够。GPU 后厨的监控,就是 ROCm 的 profiling 工具链。
调试分两层:一是“报错了怎么定位”,二是“没报错但慢,慢在哪”。常见报错定位包括:版本不匹配通常在 import 阶段就炸;显存不足会报 OOM 并给出分配栈;内核静默出错时,可以用环境变量 HIP_LAUNCH_BLOCKING=1 关闭异步执行,让每个内核串行运行并精确报出错行。
性能剖析则要看数据:rocprof 输出内核级时间线,rocprof-compute(Omniperf)读取硬件计数器,rocm-smi 看实时功耗与温度;PyTorch 侧可用 torch.profiler 对算子打点。总耗时可以精确拆成两项:
监控装好了,才知道后厨瓶颈在哪儿。而要把这套经验固化到每家分店,就得靠最后一节的标准化作业。
- 内核项 T_kernelGPU 真正执行计算的时间总和,是“有效做功”的部分。
- 间隙项 T_gapCPU 启动内核、等待同步、数据搬运之间的空档,是“等菜时间”。
- 总和两项相加就是墙上时钟看到的总时间,剖析目标就是把间隙压到最低。
工程落地实践
一家分店开好不算本事,能把“开分店”复制到十家商场才是连锁品牌的护城河。工程落地就是把 PyTorch ROCm 后端的经验写进标准化手册。
工程落地的三个关键词:兼容性注意点、CI 矩阵测试、容器化部署。兼容性方面,务必建立自己的版本兼容矩阵:内核版本 → AMD 驱动 → ROCm 版本 → PyTorch wheel → 依赖算子库(MIOpen/rocBLAS),任何升级都要在矩阵里联动验证,而不是“赌一把”。
CI 方面,同一套测试用例可以同时在 CUDA 节点与 ROCm 节点上跑(例如 GitLab CI 的双 runner),用 HIP_VISIBLE_DEVICES 控制设备可见性。容器化方面,官方镜像 rocm/pytorch 已预装好环境,运行时注入设备即可启动:
还有两个实操提醒:ROCm wheel 体积大,下载要预留磁盘和带宽;多卡场景用 RCCL 替代 NCCL 做集合通信。标准手册在手,无论下个月商场把哪块 GPU 摆上货架,你都能淡定地说:换厨房,不换菜谱。
docker run --device=/dev/kfd --device=/dev/dri rocm/pytorch:latest python -c "import torch; print(torch.cuda.is_available())"AI 应用场景
场景一:低成本推理集群的“换厨房”迁移
阶段:模型部署与推理
解决的问题:NVIDIA GPU 价格高、交付周期长,而 AMD MI210/MI300 算力相当但采购成本低 30%-40%;团队担心“换卡如换代码”,迟迟不敢迁移。PyTorch ROCm 后端让大部分模型代码零改动落地,迁移风险大幅下降。
具体案例:某 AI 绘画创业公司在算力紧张时,将 Stable Diffusion 推理服务从 A100 迁移到 MI210 集群。做法很简洁:安装 ROCm 版 torch 轮子、核对版本兼容矩阵、把 Docker 镜像换成 rocm/pytorch 基础镜像,启动命令加入 --device 参数。最终推理吞吐保持 90% 以上,硬件总成本下降约 35%,整个迁移只花了两个工程师一周。
场景二:多厂商硬件的 CI 矩阵测试
阶段:模型开发与测试
解决的问题:算法团队交付的代码要同时支持 NVIDIA 与 AMD 客户,人工在两套机器上反复测试效率极低,且容易漏测后端差异。
具体案例:某自动驾驶算法团队在 GitLab CI 中配置双 runner:一个 CUDA 节点、一个 ROCm 节点,同一份 pytest 用例矩阵并行执行;通过 HIP_VISIBLE_DEVICES 控制测试卡,把版本兼容矩阵写成 CI 配置文件,任何依赖升级都自动触发全量回归。两周内把回归周期从 3 天压到 6 小时。
场景三:千卡级大模型训练的异构容灾
阶段:模型训练
解决的问题:超算中心同时采购 NVIDIA 与 AMD 节点,训练任务可能因硬件故障需要在异构池内迁移;若代码绑死 CUDA,迁移意味着重写。
具体案例:某高校智算中心用 PyTorch 在 CUDA 与 ROCm 两套节点上拉起同一套 LLM 预训练任务。ROCm 后端通过 RCCL 完成跨节点集合通信,断点续训的 checkpoint 可直接在异构节点间恢复。在一次显卡故障演练中,任务在 10 分钟内从 NVIDIA 节点漂移到 AMD 节点继续训练,损失步数不到 20。
Python 演示
import torchimport time def check_rocm(): if not torch.cuda.is_available(): print("ROCm 后端不可用: 请检查内核/驱动与 torch 轮子版本是否匹配") return False props = torch.cuda.get_device_properties(0) print("可用设备:", torch.cuda.get_device_name(0)) print("显存总量: %.1f GB" % (props.total_memory / 1024**3)) return True def test_transfer(): for mb in (64, 256, 1024): n = mb * 1024 * 1024 // 4 src = torch.randn(n, device="cpu") t0 = time.time() dst = src.to("cuda") torch.cuda.synchronize() dt = time.time() - t0 bw = mb / 1024 / dt print("%d MB 搬运耗时 %.4f s, 有效带宽 %.2f GB/s" % (mb, dt, bw)) del dst def test_pool(): torch.cuda.empty_cache() n = 256 * 1024 * 1024 # 1 GB 浮点数 t0 = time.time() for _ in range(5): x = torch.randn(n, device="cuda") del x torch.cuda.synchronize() dt = (time.time() - t0) / 5 print("显存池平均分配时延: %.3f ms" % (dt * 1000)) def main(): if not check_rocm(): return test_transfer() test_pool() if __name__ == "__main__": main()
if not torch.cuda.is_available():在 ROCm 轮子里 torch.cuda 命名空间被映射到 HIP 后端,这个调用实际检查的是 AMD GPU 与 ROCm 运行时是否就绪。src.to("cuda")张量从 CPU 搬到 AMD 显存,底层走 hipMemcpyAsync 异步拷贝,与普通 CUDA 完全同款 API。torch.cuda.synchronize()排队等待异步操作完成,测速必须先同步,否则时间统计会“虚低”。bw = mb / 1024 / dt用墙钟时间算有效带宽,正是第 3 节公式的代码形态。torch.cuda.empty_cache()把缓存分配器池中的闲置块归还给驱动,确保后续计时不受历史残留影响。torch.randn(n, device="cuda")向缓存分配器申请显存并执行生成内核;循环里的申请/释放高度命中池子。for _ in range(5)多次取均值,避免单次调度抖动。if __name__ == "__main__":可执行入口,保证脚本既可被 import 也可直接运行。
常见误区
误区我以为从 NVIDIA 换到 AMD,模型代码和数据处理都得用新语言新 API 重写,相当于把整个项目推翻重来。
正解PyTorch 已经把设备差异吸收进了框架抽象层。ROCm 版轮子上,你仍然写 torch.nn、.to('cuda'),连 torch.cuda 命名空间都保留(内部映射 HIP)。需要真正动手移植的只是手写的 CUDA kernel——用 hipify-perl 做一次源码级转换即可。就像换厨房不用改菜谱,只需要把“用哪个灶眼”的说明换成新厨房版本。
为何常见:CUDA 时代“换平台 = 换语言”的印象太深,忽略了 PyTorch 这类框架早已把平台差异封装在底层运行时里。
误区我一看显存占用高或出现碎片,就在每个 step 里调 torch.cuda.empty_cache(),觉得把池子清空、还给系统,性能就上来了。
正解empty_cache() 只是把缓存分配器池中的空闲块归还给驱动。下一次显存申请又得重新调用 hipMalloc,一来一回反而比直接从池中命中更贵。显存池存在的意义就是“不归还、反复用”。真正的碎片问题应在代码层面解决:统一张量形状、复用 buffer、减少动态 shape,而不是频繁清池。
为何常见:函数名带着“empty“和”cache“,直觉上”清理=提速”,没有意识到池化分配器牺牲一点显存换取的正是分配速度。
误区我觉得像 NVIDIA 一样,在 Windows 装好官方驱动,然后 pip install torch 就能用 AMD 卡训练模型。
正解ROCm 官方主战场是 Linux;Windows 上只有实验性的 WSL2 支持,且部分算子库和通信库(如 RCCL)支持并不完整。生产环境跑 PyTorch ROCm,默认请选择 Ubuntu 等受支持的 Linux 发行版 + 官方 rocm/pytorch 容器镜像。
为何常见:NVIDIA 的 Windows 体验太好了,容易让人默认 AMD 也是“装驱动即用”,忽略了 ROCm 目前对 Linux 的强依赖。
误区我拿到新机器就装最新版 ROCm、最新版 PyTorch,认为新版本一定更快更稳,结果训练时各种不兼容报错。
正解GPU 软件栈是强耦合系统:内核、AMD 驱动、ROCm 运行库、PyTorch wheel 的 SOVERSION 必须互相匹配,官方兼容矩阵才是唯一标准。最新 ROCm 往往要求最新内核与驱动,强行搭配旧 wheel 会导致 import 崩溃或静默错误。
为何常见:普通软件“升级无害”的直觉不适用于 GPU 栈;大家都忽视了版本强绑定带来的复杂连锁反应。
面试题
Q1. PyTorch 的 ROCm 后端主要对标 NVIDIA 的哪套 GPU 计算生态?
- A.英伟达的 CUDA 生态← 正确答案
- B.开源的 OpenCL 框架
- C.微软的 DirectML 生态
- D.苹果的 Metal 图形生态
答案:A。ROCm 是 AMD 对 NVIDIA CUDA 的完整替代方案,HIP 甚至能在源码层兼容 CUDA 写法;OpenCL 是通用异构标准但 PyTorch 不走它;DirectML 与 Metal 分别是微软和苹果的方案,与本题无关。
Q2. 在 ROCm 生态中,HIP 最核心的职责是什么?
- A.把 CUDA 内核翻译给 AMD 硬件执行← 正确答案
- B.把网络请求路由到多张显卡上
- C.把 Python 代码编译成汇编指令
- D.把显存数据定期备份到磁盘中
答案:A。HIP 是“可移植异构接口”,提供类 CUDA 的 API,上游写一套代码即可在 AMD 上编译运行;B 描述的是负载均衡,C 是通用编译器,D 是数据备份,都与 HIP 无关。
Q3. 下列哪些属于 ROCm 生态的核心组件?
- A.rocBLAS 线性代数算子库← 正确答案
- B.MIOpen 卷积加速算子库← 正确答案
- C.NCCL 英伟达通信算子库
- D.rocprof 性能剖析工具族← 正确答案
答案:ABD。rocBLAS、MIOpen、rocprof 都是 ROCm 官方组件,分别对标 cuBLAS、cuDNN、nvprof;NCCL 是 NVIDIA 的集合通信库,AMD 阵营对应的是 RCCL,所以 C 错。
Q4. 在 PyTorch ROCm 后端中,把张量从 CPU 搬到 AMD 显存的惯用写法是?
- A.调用张量的 cuda 方法← 正确答案
- B.调用张量的 cpu 方法
- C.调用张量的 numpy 方法
- D.调用张量的 clone 方法
答案:A。在 ROCm 版 PyTorch 中 .to('cuda') 与 .cuda() 都可用,内部映射到 HIP 设备搬运;.cpu() 是反向搬运;numpy() 只转换不涉及 GPU;clone() 只复制数据不改变设备。
Q5. 某个算子在 AMD GPU 上首次执行耗时较长,随后明显变快,最可能的原因是?
- A.GPU 温度下降性能回升
- B.首次执行触发 HIP 编译缓存← 正确答案
- C.网络带宽波动造成误判
- D.显存池把数据移入更快层
答案:B。首次执行触发 HIP 编译与 MIOpen 自动调优,产物缓存后后续直接复用,因此明显变快;GPU 温度只会随负载上升而非下降;带宽波动与显存池移动都不能解释“首次慢、后面快”的稳定模式。
Q6. torch.cuda.empty_cache() 在 ROCm 后端下的实际行为是?
- A.把池中缓存归还驱动并留空← 正确答案
- B.删除模型已学习的全部参数
- C.触发一次完整的垃圾回收
- D.关闭设备并释放全部显存
答案:A。empty_cache() 把所有缓存块归还给驱动并清空池子,下次申请会走更慢的 hipMalloc;它不会删除模型参数(那是优化器的职责)、不会触达 Python 对象(GC 是解释器的事)、更不会关闭设备。
Q7. 在 PyTorch ROCm 后端,以下哪些手段能有效提升训练吞吐?
- A.将多个小算子融合成大算子← 正确答案
- B.使用混合精度降低带宽压力← 正确答案
- C.每次迭代加入大量调试打印
- D.用图捕获减少内核启动开销← 正确答案
答案:ABD。算子融合减少内核启动与中间张量读写;混合精度把带宽压力减半;图捕获把 CPU 调度开销摊平。大量 print 会强制同步并拖慢吞吐,属于反面操作。
Q8. 在 ROCm 环境,控制 PyTorch 可见 GPU 的 HIP 原生环境变量是?
- A.HIP_VISIBLE_DEVICES← 正确答案
- B.CUDA_VISIBLE_DEVICES
- C.ROCM_VISIBLE_DEVICES
- D.AMD_VISIBLE_DEVICES
答案:A。HIP 原生的设备可见性控制变量是 HIP_VISIBLE_DEVICES,例如设为 "0,2" 表示只让进程看到物理卡 0 和 2;CUDA_VISIBLE_DEVICES 在部分构建里为兼容会被识别,但 HIP 原生变量是 A;其余两个变量并不存在。
Q9. MIOpen 在 PyTorch ROCm 后端主要负责加速哪类算子?
- A.卷积与池化等视觉算子← 正确答案
- B.文本分词与编码算子
- C.梯度下降的更新算子
- D.数据增强的图像裁剪
答案:A。MIOpen 是 AMD 的深度学习原语库(对标 cuDNN),覆盖卷积、池化、RNN 等算子的高性能实现;文本分词是 torchtext 的职责,梯度更新是优化器的职责,图像裁剪属于数据增强工具链。
Q10. 关于 PyTorch ROCm 后端,下列说法正确的有哪些?
- A.内核驱动与 ROCm 版本需匹配← 正确答案
- B.上层代码与 CUDA 版保持一致← 正确答案
- C.不支持卷积神经网络的推理
- D.torch.cuda 命名空间继续可用← 正确答案
答案:ABD。ROCm 强绑定内核、驱动与库版本,所以 A 正确;PyTorch 的 ROCm 版保持同一套上层 Python API,B 正确;torch.cuda 命名空间在 ROCm 版中映射 HIP 后端,D 正确。MIOpen 广泛支持 CNN 的前向与反向,因此 C 明显错误。