如果你在昇腾 NPU 上做多卡训练,一定会碰到一个词:hccl

这个名字听起来很像 NVIDIA 的 NCCL(NVIDIA Collective Communications Library),很多人第一反应就是"昇腾版的 NCCL 嘛"。——没错,但也不完全对。hccl 的定位确实和 NCCL 类似,但昇腾的硬件特性决定了它的实现和 NCCL 有本质差异。

今天把 hccl 说清楚,顺便把 hccl、hcomm、hixl 这三个通信库的关系彻底理一遍。


hccl 到底是什么

hccl 是昇腾 CANN 生态里的集合通信库,全称是 Huawei Collective Communication Library(现在官方材料里一般叫"昇腾集合通信库")。

集合通信(Collective Communication)是干什么的?简单说,就是多卡之间做数据同步——AllReduce、AllGather、ReduceScatter、Broadcast 这些操作,都是集合通信。

为什么需要这个?因为多卡训练的时候,每张卡算完自己的梯度,需要把所有卡的梯度汇总求平均,再同步回每张卡。这个"汇总求平均"的操作,就是 AllReduce。

如果你用 PyTorch 的 DistributedDataParallel(DDP)做多卡训练,底层调的就是 hccl 的 AllReduce。

import torch
import torch.distributed as dist

# PyTorch DDP 多卡训练,底层自动调 hccl
# 不需要手动写通信逻辑
model = YourModel().npu()
model = torch.nn.parallel.DistributedDataParallel(model)

# 前向 + 反向
output = model(input_npu)
loss = criterion(output, target)
loss.backward()   # 这里自动触发 AllReduce,底层调 hccl

# 这就是 hccl 的核心使用场景

hccl 支持哪些通信原语

hccl 支持所有主流的集合通信原语,我列一下最常用的:

AllReduce:所有卡的计算结果汇总,再分发给所有卡。这是多卡训练梯度同步的标准操作,用得最多。

AllGather:所有卡各自有一块数据,汇总成完整数据给所有卡。Transformer 模型里的张量并行(Tensor Parallelism)常用这个。

ReduceScatter:所有卡的计算结果汇总,但汇总后的结果分散存储在不同卡上(每张卡存一部分)。和 AllGather 配合使用,实现高效的张量并行。

Broadcast:一张卡的数据广播给所有卡。推理场景里,模型权重只需要加载一次,然后 Broadcast 给所有卡。

Reduce:所有卡的计算结果汇总到一张指定卡。和 AllReduce 的区别是,结果只给一张卡,不是所有卡都要。

这些原语的底层实现,hccl 会根据硬件拓扑(卡和卡之间怎么连的)自动选择最优路径。如果你有 8 张 NPU 卡,它们之间可能是通过 CCIe Switch 连接的,hccl 会自动识别这个拓扑,选择最短路径做数据传输。


hccl 和 NCCL 的详细对比

既然大家都拿 hccl 和 NCCL 比,那我就认真比一下。

维度 NCCL (NVIDIA) hccl (昇腾)
目标硬件 NVIDIA GPU 昇腾 NPU
通信后端 NVLink / PCIe / InfiniBand CCIe / CCIe Switch / 超节点
编程接口 CUDA + nccl API AscendCL + hccl API
支持原语 AllReduce / AllGather / … 和 NCCL 基本一致
性能优化 针对 NVLink 拓扑优化 针对 CCIe 拓扑优化

相同点:都解决集合通信问题,都支持主流通信原语,都根据硬件拓扑自动选择最优路径。

核心不同点:NCCL 深度绑定 NVIDIA 的硬件互联(NVLink、NVSwitch),hccl 深度绑定昇腾的硬件互联(CCIe、超节点)。你不能用 NCCL 的通信策略直接套到 hccl 上——硬件特性不一样,最优通信路径也不一样。

如果你是从 NVIDIA 生态迁移过来的,hccl 的编程体验和 NCCL 有点像——都是"调 AllReduce API,底层自动搞定"。但底层的硬件语义完全不同,不能指望"学会了 NCCL 就能直接上手 hccl"。AscendCL 的通信模型和 CUDA 还是有差异的,这个要心里有数。


hccl、hcomm、hixl 到底怎么分

这三个名字太像了,我专门说一下。

hccl:集合通信库,做 AllReduce、AllGather 这些多卡同步操作。多卡训练必须用 hccl 做梯度同步。

hcomm:昇腾的通信抽象层,对上封装 hccl,对下对接硬件。你可以理解成:hcomm 是 hccl 的上层封装,提供更友好的编程接口。大多数应用开发者直接调 hcomm 就行,不需要直接接触 hccl 的底层 API。

hixl:单边通信库,做异步、单边的数据传输。和 hccl/hcomm 的最大区别是:hixl 不需要双方同时参与通信,发送端自己就能完成传输。PD 分离架构里传 KV Cache 就用 hixl。

它们的关系是这样的:

应用层(PyTorch DDP / ATB / ...)
  └─ hcomm(通信抽象层,上层接口)
      └─ hccl(集合通信库,底层实现)
          └─ 昇腾硬件互联层(CCIe / 超节点)
hixl(单边通信,独立路径,和 hccl 并列)

一句话总结:多卡同步用 hccl/hcomm,异步单边传输用 hixl,别用错


hccl 怎么用:一个最小示例

假设你要在昇腾 NPU 上做多卡训练,用 hccl 做梯度同步,最小流程是这样的:

第一步:初始化 hccl 通信域。 所有参与训练的 NPU 卡要组成一个通信域(communication group),hccl 在这个域里做集合通信。

import torch
import torch.distributed as dist

# 初始化进程组,后端选 hccl(昇腾 NPU 用 hccl)
dist.init_process_group(
    backend="hccl",           # 关键:用 hccl 后端,不是 nccl
    rank=int(os.environ["RANK"]),
    world_size=int(os.environ["WORLD_SIZE"]),
)

第二步:用 DistributedDataParallel 包装模型。 PyTorch 会自动在反向传播的时候调 hccl 的 AllReduce,不需要你手动写通信代码。

model = YourModel().npu()
model = torch.nn.parallel.DistributedDataParallel(
    model,
    device_ids=[int(os.environ["LOCAL_RANK"])],
    broadcast_buffers=True,    # 广播 buffer(BatchNorm 的 running stats 等)
)

# 训练循环
for batch in dataloader:
    output = model(batch.npu())
    loss = criterion(output, target)
    loss.backward()   # 自动触发 AllReduce,底层调 hccl
    optimizer.step()

第三步(可选):手动调 hccl 原语。 如果你在做自定义的多卡逻辑(比如张量并行),可能需要手动调 hccl 的 AllGather / ReduceScatter:

import hccl

# 手动调 AllGather(张量并行场景)
tensor_list = [torch.zeros_like(local_tensor) for _ in range(world_size)]
hccl.all_gather(tensor_list, local_tensor)
# 结果:所有卡的 local_tensor 汇总到 tensor_list 里

几个踩坑经验

坑一:backend 要写对。 PyTorch 里 init_process_groupbackend 参数,昇腾 NPU 要写 "hccl",不是 "nccl"。写错了会在运行时报一个很隐晦的错误,说"后端不支持"。这个坑我见过好几次,都是 CUDA 生态迁移过来的人容易犯的。

坑二:多卡训练的 batch_size 要按卡数放大。 DDP 的训练逻辑是:每张卡算自己的 batch,然后梯度 AllReduce 求平均。所以有效的 batch_size = 单卡 batch_size × 卡数。如果你发现多卡训练收敛速度没变快,先检查一下有效 batch_size 有没有按卡数放大。

坑三:hccl 的 AllReduce 是同步操作。 默认情况下,AllReduce 会阻塞等待所有卡都完成计算,再做梯度同步。如果你的卡之间计算时间差异很大(比如某张卡算力不够),其他卡会空等。这种情况可以考虑用梯度累积(gradient accumulation)或者异步 AllReduce 来缓解这个问题。


结尾

hccl 是昇腾 CANN 生态里多卡训练的基石,它不性感,但每个多卡训练的任务都依赖它。

理解 hccl 的价值不在于"怎么直接调它的 API"(大多数时候 PyTorch DDP 帮你调了),而在于理解你的多卡训练底层在怎么通信、通信瓶颈可能在哪里、有没有可能用别的方式优化

和 hcomm(上层封装)、hixl(单边通信)一起,构成了昇腾 NPU 完整的通信体系。每个库定位不同,用错地方性能差别很大。

源码在 https://atomgit.com/cann/hccl

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐