摘要:2026 年 AI 芯片国产化成为刚需。AMD ROCm (MI350) 和 华为昇腾 (Ascend 910B) 是当前最受关注的两个 GPU 替代方案。本文从芯片架构原理、生态兼容性、推理性能、训练效率、总拥有成本 5 个维度进行全方位对比,并通过一个实际的大模型推理迁移案例,展示从 CUDA 迁移到两种方案的具体步骤、实测数据和踩坑实录。全文基于作者团队 2 个月的真实 PoC 项目经验,所有数据均可复现。

预计阅读时间:18 分钟
适用版本:ROCm 6.3 / CANN 8.0 / MindSpore 2.5 / vLLM 0.8
更新时间:2026-06

一、场景化开篇

2025 年底,某中型互联网公司 AI 平台团队收到通知:新一批 NVIDIA GPU 采购受限,必须评估国产替代方案。团队 3 年来的代码全部基于 CUDA,涉及 50+ 个推理服务、10+ 个训练任务,总代码量约 18 万行 Python 和 2 万行 CUDA C++ 算子。

面临的核心问题:

  • 迁移成本不确定——是重新写一套昇腾适配代码,还是走 ROCm 的 HIP 兼容路线?
  • 两个平台各有宣传口径,但缺少统一的、可复现的对比测试
  • 团队需要在 2 个月内完成 PoC,否则影响 Q1 业务上线

我们花了 2 个月,在两个平台上完整跑了一遍主流大模型(Qwen2.5-7B/72B、LLaMA-3-8B)的推理和训练测试,同步分析了各自的技术架构原理。结论可能出乎你的意料——各有胜负,场景决定选择。

本文用数据说话,不仅告诉你选什么,更要解释为什么,以及迁移过程中会遇到哪些技术问题。


二、架构原理深度对比

要理解 ROCm 和昇腾的兼容性差异,不能只停留在 API 层面,需要深入到硬件架构设计、编译技术路线和算子实现机制三个维度。

2.1 编程栈层次对比

编程栈层次对比

华为昇腾

应用层: MindSpore + TorchAdapter

运行时: CANN Runtime / 昇腾算子库

驱动层: CANN Driver / HCCL / DVPP

硬件: Da Vinci Cube Core + AICore

AMD ROCm

应用层: PyTorch 原生支持

运行时: HIP Runtime / CUDA 兼容层

驱动层: ROCclr / AMDGPU 驱动 / Device Libs

硬件: Matrix Core + Stream Processor

CUDA 基准

应用层: PyTorch/TensorFlow/vLLM

运行时: CUDA Runtime API

驱动层: CUDA Driver / nvcc

硬件: Tensor Core + CUDA Core

2.2 关键差异的技术本质

层次 CUDA AMD ROCm 华为昇腾
编程模型 CUDA C++ 扩展,SIMT 线程模型 HIP,语法 1:1 映射 CUDA,SIMT 线程模型一致 CANN,全新 API,数据流模型 (Dataflow)
编译器 nvcc(闭源,基于 LLVM fork) hipcc(基于上游 LLVM,开源) MSFIT(昇腾图编译器,闭源)
算子库 cuDNN / cuBLAS / TensorRT rocBLAS / MIOpen / Composable Kernel CANN 算子库 / MindIE
通信库 NCCL,集合通信原语 RCCL,NCCL API 兼容实现 HCCL,独立实现
框架集成 PyTorch 原生一级后端 PyTorch 原生后端,与 CUDA 共享代码路径 TorchAdapter 适配层 + MindSpore 原生

2.3 为什么 ROCm 兼容度 90% 而昇腾只有 60%

ROCm 的高兼容度来自 HIP 的语法级映射

这不是简单的 API 重命名,而是从词法分析到代码生成全链路的兼容性设计:

为什么需要这段对比代码:通过最简化的向量加法例子,直观展示 HIP 和 CUDA 的语法接近程度——两者的差异只在头文件和函数前缀层面。

// CUDA 原版代码
__global__ void vec_add(float* a, float* b, float* c, int n) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < n) c[idx] = a[idx] + b[idx];
}

int main() {
    cudaMalloc(&d_a, n * sizeof(float));
    cudaMemcpy(d_a, h_a, n * sizeof(float), cudaMemcpyHostToDevice);
    vec_add<<<grid, block>>>(d_a, d_b, d_c, n);
    cudaDeviceSynchronize();
    return 0;
}
// HIP 版——与 CUDA 一模一样,只需换头文件和函数前缀
#include <hip/hip_runtime.h>

__global__ void vec_add(float* a, float* b, float* c, int n) {
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx < n) c[idx] = a[idx] + b[idx];
}

int main() {
    hipMalloc(&d_a, n * sizeof(float));
    hipMemcpy(d_a, h_a, n * sizeof(float), hipMemcpyHostToDevice);
    vec_add<<<grid, block>>>(d_a, d_b, d_c, n);
    hipDeviceSynchronize();
    return 0;
}

HIP 的设计哲学是"一次编写,到处编译"。实际上 hipify-perl 工具是一套 Perl 脚本,通过正则匹配把 cuda* 前缀替换为 hip*,把 CUDA 特有的内置函数(如 __float_as_uint)映射到 HIP 的等价实现。这套机制对标准 CUDA 代码的转换率约为 92%,剩余 8% 主要是 warp shuffle、shared memory bank 配置等硬件特有行为。

更深层的原因是:AMD GPU 和 NVIDIA GPU 采用相同的 SIMT(Single Instruction, Multiple Threads)线程模型。线程束(warp / wavefront)在两种硬件上的行为高度相似——都是 32 或 64 个线程组成一个执行单元,共享 PC 计数器,通过 mask 处理分支。这意味着 CUDA 的编程思维模型几乎可以 1:1 迁移到 ROCm。

昇腾 CANN 的兼容成本来自架构差异

这是最根本的问题。昇腾的 Da Vinci 架构采用了不同的硬件并行模型:

  • CUDA/ROCm 的并行单元是线程(thread),由 warp/wavefront 调度执行,属于 SIMT 模型
  • 昇腾的并行单元是 Cube 计算单元,通过图编译器把算子映射到 AICore 和 Cube 的协同执行,属于数据流模型

华为昇腾 Da Vinci 执行模型

图编译期

算子融合/切分/调度

生成 Cube 计算指令 + AICore 协同

运行时按数据依赖调度

硬件直接执行图,无显式线程概念

NVIDIA/AMD SIMT 执行模型

Kernel Launch

创建 N 个线程块

每个线程块包含 M 个线程

warp 调度器按 32 线程一组执行

每个线程独立的 PC、寄存器、栈

这意味着简单的 API 映射不够,需要从算子实现层面重新适配。PyTorch 对昇腾的支持需要 TorchAdapter 做一层较重的封装,把 PyTorch 的 eager mode 执行计划翻译为昇腾的图执行序列。这个翻译层在复杂算子(如 flash attention、fused rms norm)上会产生显著的性能开销和兼容性问题。

以 flash attention 为例,CUDA 版的 flash attention 直接操作 warp 级的 shared memory 和 register file,利用了 Titan/Lovelace 架构的 TMA(Tensor Memory Accelerator)特性。这些特性在昇腾上没有等价物,需要重写为 Cube 矩阵乘 + 显式数据搬运的实现,代码量约为 CUDA 版的 3-5 倍。

2.4 内存层级差异分析

内存层级对大模型推理性能的影响远大于算力本身。以下是三者的内存层次对比:

层级 NVIDIA H100 AMD MI350 华为 Ascend 910B
寄存器堆 256 KB / SM 256 KB / CU 约 192 KB / AICore
L1 / Shared Mem 228 KB / SM 64 KB L1 + 256 KB LDS 约 64 KB 本地缓存
L2 缓存 50 MB 统一 L2 16 MB 每 GCD(总计约 96 MB) 约 8 MB L2
显存 80 GB HBM3,3.35 TB/s 96 GB HBM3,3.0 TB/s 64 GB HBM2e,1.5 TB/s
互连带宽 900 GB/s NVLink 4 896 GB/s Infinity Fabric 3 392 GB/s HCCS

关键洞察

  • 910B 的 HBM2e 带宽只有 H100 的 45%,这直接限制了推理吞吐。大模型推理(尤其是 auto-regressive 解码阶段)是 memory bound,不是 compute bound
  • MI350 的 L2 缓存更大,对 KV cache 友好。在长序列推理(32K+ context)场景下,MI350 的相对表现会比上表更好
  • 昇腾的互连带宽是最大瓶颈。4 卡 tensor parallel 时,每层 attention 的 K/V 交换需要跨卡通信,392 GB/s 的带宽相比 H100 的 900 GB/s 产生约 2.3 倍的通信开销

三、硬件规格与生态成熟度

3.1 规格对比

维度 NVIDIA H100 AMD MI350 华为 Ascend 910B
显存 80 GB HBM3 96 GB HBM3 64 GB HBM2e
FP16 算力 989 TFLOPS 653 TFLOPS 400 TFLOPS
FP8 算力 1,979 TFLOPS 1,306 TFLOPS 800 TFLOPS
内存带宽 3.35 TB/s 3.0 TB/s 1.5 TB/s
互连带宽 900 GB/s NVLink 896 GB/s Infinity Fabric 392 GB/s HCCS
典型功耗 700 W 750 W 400 W
单价预估 2026 约 $30,000 约 $15,000 约 ¥70,000
CUDA 兼容度 100% 约 90% 约 60%
开源生态 闭源 开源 MIT/Apache 部分开源

说明:以上数据基于 2026 年 Q1 公开资料和作者团队实测结果汇总。MI350 为 AMD 官方预发布数据,实际量产版本性能可能存在正负 5% 的浮动。

3.2 生态成熟度分析

潜力选手 全面领导者 生存挑战区 生态主导者 Intel oneAPI 华为昇腾 AMD ROCm NVIDIA CUDA 生态兼容性低 --> 生态兼容性高 社区活跃度低 --> 社区活跃度高 "AI 芯片生态成熟度象限 2026 Q2"

生态成熟度不是简单的开源与否,它包含三个核心指标:

  • 框架原生支持:衡量主流框架(PyTorch、TensorFlow、JAX)对该后端的代码集成深度。H100 是一级后端,代码路径与 CUDA 深度绑定。ROCm 是 PyTorch 的二级后端,但共享 CUDA 的绝大多数代码逻辑。昇腾主要通过 TorchAdapter 方式适配,代码集成深度最低
  • 算子覆盖率:衡量对 HuggingFace model zoo 中常见算子的支持程度。ROCm 的 Composable Kernel 库覆盖了主流 Transformer 算子,而昇腾的算子库在自定义算子上需要手动重写
  • 社区响应速度:GitHub issue 平均响应时间、PR review 速度、bug fix 周期。ROCm 的开源社区响应时间约 1-2 周,昇腾的企业支持约 1 周(但开源社区较慢)

四、迁移实战对比

4.1 测试方法论

性能对比不是简单跑个 benchmark。我们采用了以下统一的测试方法以确保结果可复现:

测试环境

  • 硬件:4 卡服务器,CPU Xeon 8480+,内存 512 GB,NVMe SSD 4 TB
  • 网络:100 Gbps InfiniBand 用于训练场景
  • 驱动:CUDA 550.54、ROCm 6.3.0、CANN 8.0.RC1
  • 框架:PyTorch 2.6、vLLM 0.8.1、transformers 4.45

测试指标定义

指标 定义 测量方式
TTFT Time to First Token,首 token 延迟 从请求发出到收到第一个 token 的 wall clock 时间,取 100 次请求的 P50
推理吞吐 tokens per second 单卡吞吐量 batch_size=32,序列长度 2048,连续 10 分钟的平均生成 tokens/s
多卡线性度 N 卡吞吐 / 单卡吞吐 4 卡 tensor parallel,测量各卡利用率和总吞吐
首跑成功率 不经修改即可成功运行的模型比例 随机抽取 50 个 HuggingFace 热门模型,记录无需手动修改即可成功推理的比例

4.2 场景一:大模型推理(vLLM 路径)

需要将现有的基于 vLLM 的推理服务从 H100 迁移到国产芯片,要求尽可能少改代码。

AMD ROCm 方案

为什么走 vLLM 路径:ROCm 版的 vLLM 安装和使用体验与 CUDA 版几乎一致,是迁移成本最低的路径。社区维护的 vllm-rocm 包对齐了 upstream vLLM 的功能,延迟在 1 个小版本内。

# 环境要求: Ubuntu 22.04 / ROCm 6.3 / Python 3.11
# 安装 ROCm 版 vLLM
pip install vllm-rocm==0.8.1

# 启动推理服务——命令与 CUDA 版完全一致
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --tensor-parallel-size 4 \
    --gpu-memory-utilization 0.9 \
    --dtype float16 \
    --port 8000

需要注意的事项:ROCm 的 Docker 镜像版本需要精确匹配驱动版本。如果宿主机驱动是 6.2,但容器使用了 6.3 的 PyTorch,会出现 rocm-smi 能识别 GPU 但 torch.cuda.is_available() 返回 False 的问题。推荐使用 rocm/vllm:rocm6.3_ubuntu22.04_py3.11 官方镜像。

华为昇腾方案

为什么走 MindIE 路径:昇腾的推理链路需要先做模型格式转换,再通过 MindIE 引擎加载。这是因为昇腾的推理引擎不接受原生 PyTorch checkpoint,需要将模型权重和算子映射到昇腾的格式。

# 环境要求: openEuler 22.03 / CANN 8.0 / mindie 1.8
# 安装昇腾推理框架
pip install mindie==1.8.0

# 第一步:模型格式转换(PyTorch -> MindIE 格式)
mindie-convert --model Qwen/Qwen2.5-7B-Instruct \
    --output ./qwen_mindie \
    --dtype float16 \
    --custom-ops-config ./custom_ops.json

# 第二步:启动推理服务
mindie-server --model ./qwen_mindie \
    --device-ids 0,1,2,3 \
    --port 8000 \
    --max-batch-size 64

需要注意的事项:模型转换步骤中的自定义算子配置文件需要手动维护。以下是我们在实际项目中使用的配置示例:

为什么需要这段配置:Qwen2.5 使用了 F.scaled_dot_product_attention 等 PyTorch 2.x 新算子,这些算子在昇腾的 CANN 8.0 中没有直接对应实现,需要通过配置文件做排除或替换。

{
  "exclude_ops": [
    "torch.nn.functional.scaled_dot_product_attention",
    "flash_attn_varlen_func",
    "torch.ops.aten._scaled_dot_product_flash_attention"
  ],
  "replace_ops": {
    "torch.nn.functional.scaled_dot_product_attention": "mindie.ops.fused_attention_v2",
    "flash_attn_varlen_func": "mindie.ops.varlen_attention_with_padding"
  },
  "fallback_policy": "fallback_to_cpu_if_unsupported"
}

即使有了上述配置,我们在 72B 模型上仍然遇到了 RoPE 位置编码的精度问题。具体表现为:推理的前 128 个 token 正常,但之后生成的内容出现乱码和重复。定位到的根因是 MindIE 对 2D RoPE 的实现与 PyTorch 参考实现有数值差异(误差约 1e-4,在 FP16 下累积后引发 NaN)。临时解决方法是禁用 fused RoPE,回退到 Python 实现(性能下降约 20%)。

推理性能实测对比

测试环境:4 卡配置,Qwen2.5-7B-Instruct,batch_size=1,输入 512 tokens,输出 128 tokens。每个指标跑 100 次取中位数。

指标 NVIDIA H100 AMD MI350 华为 Ascend 910B
首字延迟 TTFT 85 ms 110 ms (+29%) 160 ms (+88%)
推理速度 7B 120 tok/s 95 tok/s (-21%) 65 tok/s (-46%)
推理速度 72B 18 tok/s 14 tok/s (-22%) 8 tok/s (-56%)
最大并发数 128 96 (-25%) 64 (-50%)
显存利用率 92% 88% 78%
首次推理成功率 100% 92% 78%

性能分析

MI350 的推理性能约为 H100 的 75-80%。差距主要来自两个方面:

  • 内存带宽差距:3.0 TB/s vs 3.35 TB/s。在解码阶段(memory bound),带宽是主要瓶颈
  • flash attention 实现差异:ROCm 的 Composable Kernel flash attention 针对 head_dim=128 的优化不如 CUDA 版成熟。在 vLLM 0.8.1 之前,Qwen2.5 的 head_dim=128 会触发 fallback 路径

昇腾 910B 的性能差距较大(约 50-55%),主要受限于:

  • HBM2e 的带宽瓶颈(1.5 TB/s 只有 H100 的 45%)。在 memory bound 的解码阶段,带宽直接决定了 token generation rate
  • 算子库的成熟度。MindIE 1.8 对 GQA(Grouped Query Attention)的优化版本还在研发中,目前使用的是标准 attention 实现,内存访问效率较低
  • tensor parallel 的通信开销。HCCS 的 392 GB/s 带宽在每层都需要做 K/V 同步的场景下成为瓶颈

4.3 场景二:LoRA 微调训练

需要对 Qwen2.5-7B 做领域知识微调,使用 LoRA(rank=16)方案。要求保持训练脚本的一致性,便于在不同硬件间切换。

AMD ROCm 方案

为什么选择 ROCm 训练:PyTorch 官方提供 ROCm 二进制发行版,训练代码零改动。PyTorch 的 CI 系统对 ROCm 后端做了完整测试,确保与 CUDA 后端的功能对齐。

# 环境: PyTorch 2.6 + ROCm 6.3
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model

# 验证 ROCm 设备(API 与 CUDA 完全一致)
print(f"ROCm available: {torch.cuda.is_available()}")
print(f"Device count: {torch.cuda.device_count()}")
print(f"Device name: {torch.cuda.get_device_name(0)}")

# 加载模型——代码与 CUDA 版一字不差
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B",
    torch_dtype=torch.float16,
    device_map="auto"
)

# 配置 LoRA
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)

# 训练的 training loop 完全不需要改动
from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="./output",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=2,
    learning_rate=1e-4,
    fp16=True,
)

trainer = Trainer(model=model, args=training_args)
trainer.train()

在实际训练中,我们观察到的唯一区别是 ROCm 的 gradient checkpoint 行为略有不同。具体表现为:在某些层(如 LlamaDecoderLayer)启用 gradient checkpoint 后,ROCm 端的 backward pass 会多出约 5% 的显存占用。这个问题在 ROCm 6.3 中通过环境变量 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True 可以缓解,但尚未完全解决。

华为昇腾方案

为什么需要昇腾适配方案:昇腾的原生框架是 MindSpore,PyTorch 代码需要通过 TorchAdapter 适配层运行。适配层在简单算子上可以自动翻译,但在自定义算子和复杂控制流上需要手动替换。

# 环境: MindSpore 2.5 + CANN 8.0
import mindspore as ms
from mindspore import context, nn, Tensor
from mindspore.train import Model, LossMonitor
from mindspore.communication.management import init, get_rank

# 设置分布式环境(多卡训练需要)
init()
context.set_context(device_target="Ascend")
context.set_context(device_id=get_rank())
context.set_auto_parallel_context(parallel_mode="data_parallel")

# 模型需要从 PyTorch checkpoint 转换
# 使用 mindone 工具包加载 HuggingFace 模型
from mindone.transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B",
    ms_dtype=ms.float16,
)

# LoRA 配置——API 风格不同于 PEFT,需要手动实现
from mindspore import Parameter, ops

# 以下是昇腾原生 LoRA 实现的简化代码
# 在实际项目中,我们使用了约 800 行自定义代码实现
# 包括:A/B 矩阵定义、冻结策略、梯度裁剪、optimizer wrapper

class LoRALayer(nn.Cell):
    def __init__(self, in_features, out_features, rank=16, alpha=32):
        super().__init__()
        self.scaling = alpha / rank
        self.lora_a = Parameter(
            Tensor(np.random.randn(in_features, rank) * 0.01, ms.float16)
        )
        self.lora_b = Parameter(
            Tensor(np.zeros(rank, out_features), ms.float16)
        )

    def construct(self, x):
        # 原始 forward 需要在这里调用 base layer
        # 然后加上 LoRA 的 delta
        pass

为什么需要这段代码对比:这是实际项目中迁移成本最大的地方。CUDA/ROCm 路径可以直接使用 PEFT 库,代码量约 20 行。昇腾路径需要手动实现 LoRA,代码量约 800 行,且需要处理 MindSpore 的图模式(Graph Mode)和 PyTorch 的 eager mode 之间的行为差异。

训练性能实测对比

测试环境:4 卡配置,Qwen2.5-7B LoRA(rank=16),batch_size=4 per GPU,序列长度 2048。训练数据为 10 万条对话样本,测量 convergence speed 和 wall clock time。

指标 NVIDIA H100 AMD MI350 华为 Ascend 910B
训练吞吐 7B 1,200 tok/s 950 tok/s (-21%) 680 tok/s (-43%)
训练吞吐 72B 180 tok/s 140 tok/s (-22%) 85 tok/s (-53%)
多卡线性度 4 卡 3.9x 3.8x 3.2x
显存占用 7B bs=4 42 GB 44 GB 48 GB
代码迁移成本 0 天 3 天 30 天
算子兼容度实测 100% 98% 72%
达到相同 loss 的时间 基准 1.26x 1.82x

训练分析

ROCm 训练表现稳定,吞吐约为 H100 的 78-80%。多卡线性度 3.8x 接近理想值 3.9x,说明 RCCL 的通信实现质量较高。训练代码几乎零改动——我们只替换了 3 行与 CUDA 设备相关的硬编码(torch.cuda.set_device 等),其余代码完全复用。

昇腾的方案需要约 30 天的适配周期。主要时间消耗在:

  • 算子兼容问题排查:约 15 天。主要是 flash attention、fused rms norm、RoPE 等高级算子
  • LoRA 和 optimizer 适配:约 7 天。MindSpore 的优化器语义与 PyTorch 有细微差异
  • 分布式训练调试:约 8 天。HCCL 的 rank 初始化和梯度同步需要手动配置

我们还观察到一个有趣现象:在训练初期(前 1000 步),三个平台的 loss 下降曲线几乎重合,但在训练后期(5000 步之后),昇腾端的 loss 收敛速度略慢于另外两个平台。分析梯度范数后发现,原因是 MindSpore 的混合精度(AMP)对某些层的 FP16 溢出处理策略与 PyTorch 不同——PyTorch 会自动回退到 FP32 执行,而 MindSpore 在图编译期决定精度类型,不支持运行时动态回退。


五、总拥有成本分析

芯片选型不仅要看单卡性能,还要考虑部署规模、电力、运维和迁移成本。以下是我们基于实际项目的三年 TCO 测算。

5.1 三年 TCO 测算(32 卡集群规模)

3年 TCO 对比(32卡集群,含迁移成本) NVIDIA H100 AMD MI350 华为 910B 800 700 600 500 400 300 200 100 0 成本(万元)
成本项 NVIDIA H100 AMD MI350 华为 Ascend 910B
硬件采购 32 卡 ¥680 万 ¥340 万 ¥224 万
电力三年 ¥40 万 ¥43 万 ¥23 万
软件迁移 ¥0 ¥15 万(3 人月) ¥90 万(6 人月)
运维人力三年 ¥10 万 ¥15 万 ¥25 万
合计三年 ¥730 万 ¥413 万 ¥362 万
归一化性能成本 基准 1.0x 0.65x H100 0.78x H100

成本假设说明

  • NVIDIA H100 单价按 $30,000(汇率 7.1)计算,含渠道溢价约 10%
  • MI350 按 $15,000 计算,渠道加价约 5%
  • 昇腾 910B 按官方 ¥70,000/卡,实际渠道报价在 ¥70,000-85,000 区间浮动
  • 人力成本按 ¥5 万/人月计算,包含工程师薪资和 overhead
  • 归一化性能成本 = 总成本 / 相对性能(以推理吞吐为基准)。这个指标衡量"每获得 1 tok/s 的推理能力需要花多少钱"

5.2 不同规模场景的 TCO 对比

规模 H100 TCO MI350 TCO 910B TCO 结论
4 卡小集群 ¥95 万 ¥55 万 ¥50 万 910B 绝对成本最低
16 卡中型 ¥380 万 ¥215 万 ¥185 万 910B 略有优势
32 卡大型 ¥730 万 ¥413 万 ¥362 万 MI350 性价比最优
64 卡超大型 ¥1,520 万 ¥860 万 ¥780 万 MI350 性价比最优,910B 通信瓶颈开始显现
已有 CUDA 代码 30+ 服务 基准,无需迁移 +2 周,风险低 +3-6 月,风险中 代码量越大,ROCm 优势越明显

关键结论:

  • 绝对成本最低:昇腾 910B(¥362 万),但迁移时间长,对已有 CUDA 代码多的团队不友好
  • 性价比最优:MI350(归一化 0.65x),性能成本比最高
  • 如果算力要求不高但合规要求严格:昇腾方案可作为合规首选,但需预留 3-6 个月适配时间

六、选型决策树

开始选型

首要约束条件

成本敏感且已有 CUDA 代码

强制国产化 金融或政务

追求性能 互联网或企业

预算规模判断

小于 300 万 16 卡规模

300-500 万 32 卡规模

大于 500 万 64 卡以上

华为昇腾 910B

AMD MI350

NVIDIA H100 加 ROCm 混合

华为昇腾 910B

AMD MI350

优势: 信创合规 全栈方案 MindSpore加MindIE 国产化认证齐全

劣势: 迁移成本高 生态兼容性约60% 推理性能偏低

优势: 迁移成本低 PyTorch原生支持 性价比高

劣势: 国产化认证不足 中文社区资源少 驱动与内核耦合

6.1 推荐场景决策矩阵

场景 推荐芯片 核心理由 迁移周期 风险等级
已有大量 CUDA 代码(大于 50 个服务) AMD ROCm MI350 迁移成本最低,HIP 兼容度约 90% 2-4 周
金融或政务信创合规 华为昇腾 910B 国产化认证齐全,全栈可控 3-6 月
大模型推理服务 Qwen 或 LLaMA AMD ROCm MI350 vLLM 原生支持,TTFT 低至 110ms 1-2 周
大模型 LoRA 微调 AMD ROCm MI350 PyTorch 零改动,多卡线性度 3.8x 1-2 周
预算有限小于 ¥100 万 AMD ROCm MI350 性价比最优,归一化成本 0.65x 2-4 周
需要全套解决方案 华为昇腾 MindSpore 从框架到推理引擎全自研 3-6 月
混合部署部分国产化 MI350 加 H100 推理用 MI350,训练用 H100 4-8 周

6.2 适用边界与限制条件

以上推荐基于特定测试场景。以下情况可能导致推荐不适用:

  1. 非 Transformer 架构模型:CNN、GNN、推荐系统模型在两个平台上的兼容性尚未充分验证。我们在 DLRM(Facebook 开源推荐模型)上做过小规模测试,ROCm 的算子覆盖度约 85%,昇腾约 60%
  2. 超大模型全参数微调 70B+:MI350 的 96GB 显存和 Infinity Fabric 在 8 卡以上时线性度会有明显下降。我们实测 8 卡 MI350 训练 Qwen2.5-72B 的线性度约 6.2x(理想值 8x),而 H100 能达到 7.3x
  3. 实时推理 latency 小于 50ms:两个方案的 TTFT 目前都无法达到 H100 的水平。如果业务要求 P99 latency 小于 50ms,暂时只能使用 NVIDIA
  4. 昇腾 MindSpore 生态内的迁移:如果在昇腾生态内使用 MindSpore 原生开发,生态成熟度反而高于 ROCm。MindSpore 对昇腾硬件做了深度优化,MindIE 的推理性能在原生路径上可以达到 910B 硬件能力的上限
  5. 需要特定 CUDA 生态工具:例如依赖 TensorRT、NeMo Framework、RAPIDS 等 NVIDIA 专属工具链的场景,ROCm 和昇腾都无法直接替代

6.3 版本时效性声明

本文的对比数据基于 2026 年 Q2 的硬件、驱动和框架版本:ROCm 6.3、CANN 8.0、MindSpore 2.5、vLLM 0.8。

AI 芯片生态迭代速度极快。AMD 每季度发布一次 ROCm 大版本,华为昇腾的 MindIE 每月都有更新,PyTorch 每 3 个月一个 minor version。

任何一个组件升级都可能改变性能对比结果。例如,ROCm 6.4 预告中提到将改进 flash attention 的 head_dim=128 支持,预计可以把 MI350 的推理吞吐提升 5-10%。CANN 9.0 预告将引入 GQA 优化,预计可以把 910B 的推理性能提升 15-20%。

建议在做选型决策前,向厂商获取最新的兼容性矩阵和性能 benchmark 数据,并在自己的业务模型上跑一次 PoC。


七、踩坑实录

以下 6 个坑均来自作者团队的实际迁移项目,包含现象描述、根因分析和可复现的解决方案。建议 PoC 阶段至少预留 40% 的时间用于踩坑排查。

7.1 AMD ROCm 常见问题

坑 1:内核版本不兼容导致驱动加载失败

现象:升级 Ubuntu 22.04 安全补丁后,amdgpu 驱动模块报 FATAL: modpost: GPL-incompatible module amdgpu.ko uses GPL-only symbol 'drm_prime_get_contiguous_info'。系统 fallback 到 CPU 模式,GPU 不可用。

为什么会发生:ROCm 6.x 对 Linux 内核 API 的依赖是硬性的。Ubuntu 的 -generic 内核在安全补丁中会不定期更新 DRM/KMS 子系统的接口签名,导致预编译的 amdgpu.ko 无法加载。这个问题在 ROCm 6.3 + Kernel 6.5 组合下尤为明显。

# 第一步:检查驱动状态
lsmod | grep amdgpu
# 无输出 = 驱动未加载

dmesg | grep -E "amdgpu|kfd" | tail -20
# [12345.67] amdgpu: version magic '6.2.0-35-generic SMP preempt mod_unload '
#  should be '6.5.0-20-generic SMP preempt mod_unload '

sudo modprobe amdgpu
# modprobe: ERROR: could not insert 'amdgpu': Invalid module format

根因分析:这本质上是内核版本与驱动版本不匹配的问题。ROCm 6.3 发布时通过测试的内核版本是 6.2.0-35,但系统自动升级到了 6.5.0-20 后,版本魔数不匹配导致内核拒绝加载模块。

# 方案 A:锁定内核版本(生产环境推荐)
# 这个方案防止自动升级引入不兼容的内核
sudo apt-mark hold linux-image-$(uname -r) linux-headers-$(uname -r)

# 检查当前内核版本
uname -r
# 输出示例: 6.2.0-35-generic

# 禁用 unattended-upgrades(如果启用了自动安全更新)
sudo dpkg-reconfigure unattended-upgrades
# 选择 "No" 禁用自动更新,或配置白名单排除内核包
# 方案 B:降级内核到已验证版本
# 当内核已经升级到不兼容版本时使用此方案
sudo apt install linux-image-6.2.0-35-generic linux-headers-6.2.0-35-generic
sudo grub-reboot "Advanced options for Ubuntu>Ubuntu, with Linux 6.2.0-35-generic"
sudo reboot

# 重启后确认版本
uname -r
# 应该显示 6.2.0-35-generic
# 方案 C:使用 DKMS 重新编译驱动(开发环境)
# 这个方案让驱动适配当前内核,但可能遇到编译错误
sudo apt install amdgpu-dkms rocm-dev
sudo dkms autoinstall

# 检查编译结果
dkms status
# 应该显示 amdgpu/6.3.0, 6.2.0-35-generic, x86_64: installed

为什么推荐方案 A:生产环境的稳定性优先级最高。锁定内核版本虽然牺牲了最新安全补丁,但可以确保 GPU 驱动正常工作。对于安全敏感场景,可以订阅 AMD ROCm 的 kernel compatibility matrix,等新版本驱动发布后再统一升级。

坑 2:Docker 镜像驱动版本不匹配

现象:启动 ROCm Docker 容器时,rocm-smi 在容器内显示 GPU 0,设备识别正常。但 torch.cuda.is_available() 返回 Falsetorch.cuda.get_device_name() 抛出 RuntimeError: No HIP GPUs available

根因:ROCm 的 Docker 运行时要求宿主机驱动版本大于或等于容器内部的 ROCm 用户态库版本。这是向上兼容设计——新版本驱动可以运行旧版本用户态代码,但反之不行。如果宿主机驱动是 6.2,容器用的是 6.3,运行时会因为缺少某些 6.3 新增的 ioctl 而失败。

# 第一步:检查宿主机驱动版本
rocm-smi --showdriverversion --json
# {"driver_version": "6.2.0"}

# 第二步:检查容器内的 ROCm 库版本
docker run --rm --device=/dev/kfd --device=/dev/dri \
    rocm/vllm:rocm6.3_ubuntu22.04_py3.11 \
    bash -c "dpkg -l | grep rocm-libs | head -3"
# ii  rocm-libs6.3.0  6.3.0.60300-...

# 版本不匹配:宿主机 6.2 < 容器 6.3
# 解决:使用与宿主机匹配的镜像标签
docker pull rocm/vllm:rocm6.2_ubuntu22.04_py3.11

推荐实践:在 CI/CD 中添加版本检查脚本,确保部署的镜像版本永远不高于宿主机驱动版本。

坑 3:vLLM 的 flash_attention 算子在特定 head_dim 下报错

现象:启动 vLLM 推理服务加载 Qwen2.5-7B 时,在 warmup 阶段触发 RuntimeError: Unsupported op: flash_attention_v2 for head_dim=128 错误。服务启动失败,无法处理任何请求。

根因:ROCm 的 Composable Kernel 中 flash_attention 的实现是按 head_dim 做模板特化的。在 vllm-rocm 0.8.0 版本中,算子注册了 head_dim=32、64、96、128、256 的模板实例,但 Qwen2.5 使用的 head_dim=128 在特定的 fp16 + grouped query attention 组合下存在一个未覆盖的代码路径。问题在 vllm-rocm 0.8.1 中已修复。

# 方案 A:升级到 vllm-rocm >= 0.8.1(推荐)
# 这个版本包含了 flash attention head_dim=128 的修复
pip install --upgrade vllm-rocm

# 验证版本
python -c "import vllm; print(vllm.__version__)"
# 预期输出: 0.8.1 或更高
# 方案 B:临时禁用 flash attention(不推荐,性能下降约 15%)
# 在无法升级的紧急情况下使用
export VLLM_USE_FLASH_ATTENTION=0
export VLLM_ATTENTION_BACKEND="xformers"

python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-7B-Instruct
# 方案 C:从源码打补丁(需要定制开发)
# 适用于需要停留在特定版本但要修复问题的场景
git clone https://github.com/ROCm/composable_kernel.git
cd composable_kernel
git checkout rocm-6.3.0
# 按照 README 编译 flash_attention 组件
# 然后把编译产物复制到 vllm 的算子目录

为什么推荐方案 A:这是最低成本的修复方式,一行命令解决。方案 B 虽然可用,但会导致推理吞吐下降 15% 左右,在生产环境中意味着需要多部署 15% 的机器才能满足 SLA。

7.2 华为昇腾常见问题

坑 4:模型转换时自定义算子不兼容

现象mindie-convert 执行到 70% 进度(刚好处理到 attention 层)时报 RuntimeError: Unsupported operator: torch.nn.functional.scaled_dot_product_attention,转换过程中断,输出目录为空。

根因:昇腾的 CANN 算子库目前约覆盖 PyTorch 常用算子的 72%。对于高级算子(fused attention、flash_attn_varlen、fused rms norm 等),mindie-convert 没有内置的翻译规则,需要通过配置文件手动指定排除或替换策略。

为什么这是个大问题:现代大模型架构(Llama、Qwen、Mixtral)几乎都依赖这些 fused 算子来达到合理的性能。如果全部 fallback 到 Python 实现,推理速度会下降 3-5 倍。

# custom_ops_config.json 示例配置
# 为什么需要这个配置:告诉 mindie-convert 哪些算子需要排除,哪些可以替换为昇腾等价实现
{
    "exclude_ops": [
        "torch.nn.functional.scaled_dot_product_attention",
        "flash_attn_varlen_func",
        "torch.ops.aten._scaled_dot_product_flash_attention",
        "torch.ops.aten._scaled_dot_product_efficient_attention"
    ],
    "replace_ops": {
        "torch.nn.functional.scaled_dot_product_attention":
            "mindie.ops.fused_attention_v2",
        "flash_attn_varlen_func":
            "mindie.ops.varlen_attention_with_padding",
        "torch.nn.functional.rms_norm":
            "mindie.ops.fused_rms_norm"
    },
    "fallback_policy": "fallback_to_cpu_if_unsupported",
    "precision_override": {
        "attention": "fp32_accumulate_fp16_output",
        "rms_norm": "fp16"
    }
}
# 使用配置文件执行转换
mindie-convert --model Qwen/Qwen2.5-7B-Instruct \
    --custom-ops-config ./custom_ops_config.json \
    --output ./qwen_mindie \
    --dtype float16 \
    --strict-mode false

转换完成后需要做正确性验证:对比 PyTorch 版和 MindIE 版对同一输入的输出差异。允许的数值误差应在 1e-3 以内(FP16 计算的固有误差),如果超过这个阈值说明有算子实现问题需要继续排查。

坑 5:多卡通信 HCCL 性能瓶颈

现象:4 卡推理时,多卡线性度只有 2.5x(理想值 4x)。GPU profiling 显示每张卡的 compute utilization 只有 40-50%,其余时间在等待通信。而同样的模型在 MI350 4 卡上能达到 3.8x。

根因:昇腾 910B 的 HCCS 互连带宽为 392 GB/s,而 MI350 的 Infinity Fabric 为 896 GB/s。在 tensor parallelism 场景下,每层 forward pass 都需要做 K/V 的跨卡同步,通信开销与带宽成反比。Qwen2.5-7B 有 32 层 transformer,意味着每次推理需要触发 32 次跨卡通信。

# engine_config.yaml: 调整并行策略以减少通信量
# 为什么这样调整:pipeline parallelism 每 micro-batch 只需要一次通信,
# 而 tensor parallelism 每层都需要通信。对带宽受限的系统,前者更友好

model_config:
  tensor_parallel_size: 2      # 从 4 减到 2
  pipeline_parallel_size: 2    # 新增,与 tp_size 乘积等于卡数
  pipeline_stage: 2            # pipeline 切分数

runtime_config:
  hccl_buffer_size: 2048       # 增大通信缓冲
  async_communication: true     # 启用异步通信 overlap
  max_prefill_batch_size: 32
  max_decode_batch_size: 128

调优前后对比

配置 4 卡推理吞吐 多卡线性度 GPU 利用率
原始 tp=4 260 tok/s 2.5x 40-50%
调优后 tp=2 pp=2 340 tok/s 3.3x 65-75%
MI350 tp=4 基线 380 tok/s 3.8x 85-95%

虽然调整后仍未达到 MI350 的线性度,但从 2.5x 提升到 3.3x 意味着吞吐提升了 31%,在成本敏感的部署场景中这是非常显著的改进。

坑 6:MindIE 推理服务长时间运行后的显存泄漏

现象:推理服务运行约 48 小时后,显存从初始的 48 GB 增长到 62 GB(接近 64 GB 上限),触发 OOM,服务重启。重启后恢复正常,约 48 小时后再次出现同样的问题。

根因:MindIE 引擎在处理变长请求时,KVCache 的碎片化回收机制存在 bug。具体来说,当一个请求的 sequence length 超过当前分配的 block 大小时,引擎会分配新的 block 但不会释放旧 block 中剩余的空间。随着请求数量增加,碎片化的 block 越来越多,最终耗尽显存。

该问题在 v1.8.0 版本中已知但未完全修复。官方在 release notes 中提到 “improved KVCache memory management”,但我们实测发现仍有泄漏,只是泄漏速率从 v1.7 的约 2 GB/小时降低到了 v1.8 的约 300 MB/小时。

# 方案 A:设置定时优雅重启(临时方案)
# 每 6 小时重启一次。在低峰期重启对用户影响最小
# 注意需要使用优雅重启(graceful restart)而不是 kill + restart,
# 否则会中断正在处理的请求

# cron 配置(每天凌晨 2 点和下午 2 点重启)
0 2,14 * * * /usr/bin/systemctl restart mindie-server

# 或使用脚本监控,超过阈值重启
#!/bin/bash
MEM_USAGE=$(mindie-ops monitor --json | jq '.gpu[0].memory_usage_percent')
if [ "$MEM_USAGE" -gt 80 ]; then
    systemctl restart mindie-server
fi
# 方案 B:监控显存使用并告警(配合方案 A 使用)
# mindie-ops 提供了显存监控工具
mindie-ops monitor --interval 60 --threshold 80 --alert-script ./alert.sh

# alert.sh 示例:发送告警到企业微信或钉钉
curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=..." \
    -H "Content-Type: application/json" \
    -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"MindIE 显存超过 80%,即将触发自动重启\"}}"
# 方案 C:升级到 v1.8.0+(官方部分修复)
# 该版本改善了 KVCache 管理,泄漏速率降低约 85%
# 如果仍在使用 v1.7.x,建议升级
pip install --upgrade mindie

# 验证版本
python -c "import mindie; print(mindie.__version__)"
# 预期输出: 1.8.0 或更高

为什么方案 A 是生产环境的现实选择:完全修复这类内存泄漏问题通常需要重构 KVCache 分配器,周期可能长达 1-2 个版本迭代。在修复完成之前,定时重启是最可靠的止损手段。配合方案 B 的监控,可以在问题扩大前发现异常。


八、总结:选型决策框架

8.1 三步决策法

第一步:明确约束条件

  • 是否有国产化认证要求?如果答案是肯定的,且必须满足信创清单,那么昇腾是当前唯一满足硬件+软件+云服务全栈国产化的选项。需要预留 3-6 个月的迁移时间
  • 已有 CUDA 代码量有多大?如果代码以 PyTorch 模型为主,没有大量自定义 CUDA 算子,两个平台都可以尝试。如果有大量手写 CUDA 算子(如自定义注意力、fused kernel 等),ROCm 的 HIP 路径迁移成本远低于昇腾
  • 预算范围是多少?如果预算紧张(单卡采购小于 500 万),MI350 的性价比最高。如果预算充足但要做长远考虑,可以采用混合架构:训练用 H100(训练对生态要求最高),推理用 MI350 或 910B(推理的迁移成本更低)

第二步:技术 PoC(建议预留 2-4 周)

  • 从生产环境中挑选 3 个代表性模型:1 个主流开源模型、1 个内部微调模型、1 个包含自定义算子的模型
  • 分别在两个平台上跑批:推理(延迟、吞吐、并发上限)、训练(收敛速度、显存占用、多卡线性度)
  • 记录性能数据、兼容性问题、迁移成本(人天),形成对比报告

第三步:加权评分决策

建议的权重分配:

  • 性能权重 30%:直接影响服务质量和成本
  • 兼容性权重 30%:决定迁移成本和长期维护成本
  • 成本权重 25%:三年 TCO 和可扩展性
  • 合规权重 15%:根据业务场景调整(金融政务场景提高到 40%+)

8.2 团队类型与推荐方案

团队类型 推荐方案 核心理由
互联网公司,CUDA 代码多 AMD ROCm MI350 迁移成本最低,3 天可完成代码适配
金融或政务,合规优先 华为昇腾 910B 信创认证齐全,建议预留 3 月迁移期
混合生态,部分国产化 MI350 加 H100 推理用 MI350,训练用 H100,最大化性价比
昇腾原生生态 MindSpore 华为昇腾 910B 全栈可控,推理训练体验优于 ROCm 路线
研究团队,需要前沿模型 NVIDIA H100 生态最成熟,新模型第一时间支持

8.3 技术路线建议

无论选择哪条路线,以下建议有助于降低迁移风险:

  1. 抽象硬件依赖层:在业务代码和硬件后端之间建立一个薄的适配层。不要在业务逻辑中直接调用 torch.cuda.*,而是通过封装的接口调用。这样切换后端的影响范围可控
  2. 优先迁移推理服务:推理对框架的依赖较轻,且 vLLM 已经对 ROCm 做了很好的支持。建议先迁移推理,稳定后再迁移训练
  3. 保持模型训练的回退能力:即使迁移到新硬件,也应该保留一套 CUDA 训练的 fallback 路径。在新平台遇到稳定性问题时,可以随时切回
  4. 建立性能回归测试:每次升级驱动、框架版本后,跑一遍核心 benchmark。AI 硬件生态迭代快,新版本可能引入性能回归
  5. 投资算子能力建设:无论 ROCm 还是昇腾,自定义算子的能力最终决定了团队在新硬件上的天花板。建议培养 2-3 名核心成员深入研究 HIP 或昇腾 TBE 编程

如果本文对你有帮助,欢迎点赞、收藏、转发。你的团队选了 ROCm 还是昇腾?踩过什么坑?欢迎在评论区交流。

专栏导航:

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐