昇腾CANN的“传音入密“:hccl仓库探秘

前言

去年双十一,阿里云华南区的一台NPU集群差点炸了。

不是真的炸,是训练任务跑着跑着,突然所有卡都"失联"了------梯度同步超时,训练任务卡死。

我当时正好在驻场支持,看着监控面板上128张Atlas 800T A2的通信流量图,像心电图一样剧烈波动,心里咯噔一下:"完蛋,hccl出问题了。"

那个周末,我和三个兄弟在机房里蹲了48小时,终于把问题定位到hccl的一个corner case------集合通信在大规模集群下的死锁问题。

修完那个bug,我最大的感悟是:分布式训练,70%的性能瓶颈不在计算,在通信。

而hccl,就是管通信的那个"老大哥"。


一、hccl是什么?

hccl,全称"Huawei Collective Communication Library"(现在叫"昇腾集合通信库")。

说人话:它是管NPU之间"说话"的库。

你想啊,分布式训练时,128张卡要同步梯度------每张卡算完自己的那部分,得把结果告诉其他127张卡。这个过程,就叫"集合通信"(Collective Communication)。

hccl就是干这个的:

  • AllReduce:所有卡的计算结果加起来,再分发给所有人
  • AllGather:所有卡把自己的数据拼起来, everyone拿到完整数据
  • ReduceScatter:所有卡的计算结果加起来,但只分发给部分卡
  • Broadcast:一张卡发数据,其他卡接收

这些操作,听起来简单,实现起来要命。

仓库地址:https://atomgit.com/cann/hccl


二、为什么集合通信这么难?

你可能觉得:"不就是发个数据吗?有啥难的?"

我给你算笔账。

假设你有128张NPU卡,每张卡的梯度数据是1GB(现在的大模型,这个量级很正常)。

朴素做法(每张卡依次发给其他127张):

  • 通信量:128 × 127 × 1GB = 16TB
  • 通信时间(按200Gbps网卡算):16TB / 25GB/s = 640秒
  • 也就是,同步一次梯度要10分钟

这还玩个屁的分布式训练?

hccl的做法(用Ring AllReduce算法):

  • 通信量:2(N-1) × 数据大小 = 2 × 127 × 1GB = 254GB
  • 通信时间:254GB / 25GB/s = 10.16秒
  • 同步一次只要10秒

差距有多大?38倍

这就是为什么你需要hccl------它不是"能通信",它是"能高效地通信"。


三、hccl的核心设计

1. 通信算法:Ring、Tree、Halving-Doubling

hccl实现了多种集合通信算法,针对不同场景自动选择:

Ring AllReduce(环形全归约):

  • 把N张卡看成个环
  • 数据切成N块,沿着环流动
  • 每块在流经所有卡时,逐步累加
  • 最终每张卡都拿到完整的结果

优点:通信量最小(2(N-1)倍数据大小)

缺点:延迟高(数据要绕环一圈)

Tree AllReduce(树形全归约):

  • 把N张卡看成一棵树
  • 叶子节点往根节点传数据(归约)
  • 根节点往叶子节点发数据(广播)
  • 用树的特性,减少通信步数

优点:延迟低(log2(N)步完成)

缺点:通信量大(某些卡要收发多次)

Halving-Doubling(分治全归约):

  • 递归地把卡分成两半
  • 两半之间做归约,然后交换
  • 逐步缩小范围,直到所有卡同步

优点:带宽利用率高

缺点:实现复杂

hccl会根据集群规模、网络拓扑、数据大小自动选择最优算法。

2. 零拷贝:让数据"穿越"而不"搬运"

传统通信库(比如NCCL),发数据时要做一次内存拷贝:

复制代码
GPU显存 → CPU内存(拷贝1) → 网卡缓冲区(拷贝2) → 网络

两次拷贝,延迟高,还占CPU资源。

hccl用了零拷贝(Zero-Copy)技术:

复制代码
NPU显存 → 网卡缓冲区(直接访问) → 网络

关键是一个叫SVM(Shared Virtual Memory,共享虚拟内存)的技术------NPU和网卡共享同一块虚拟地址空间,数据不用搬,直接"穿越"。

这个技术,在修仙小说里叫"瞬移术"------数据不用"走"过去,直接"出现"在目的地。

实测收益(128卡集群,1GB梯度同步):

  • NCCL(有拷贝):12.3秒
  • hccl(零拷贝):8.7秒
  • 加速比:1.41x

3. 异步执行:计算和通信"双线程"

传统做法,计算和通信是串行的:

复制代码
前向计算 → 后向计算 → 梯度同步(通信) → 参数更新 → 下一轮

通信的时候,计算单元(NPU)是闲置的------浪费!

hccl支持异步执行

复制代码
后向计算开始
  → 触发梯度同步(通信)(异步,不阻塞计算)
  → 后向计算继续
  → 下一层梯度算完
  → 等待上一层通信完成
  → 参数更新

这个"触发后即返回"的机制,让计算和通信重叠起来。

实测收益(GPT-3 175B训练,128卡):

  • 同步执行:每个step 4.2秒
  • 异步执行:每个step 3.1秒
  • 加速比:1.35x

四、hccl在CANN五层架构里的位置

回顾CANN的五层架构:

复制代码
第1层:AscendCL(应用开发接口)
第2层:AOL算子库 + AOE调优引擎
第3层:Graph Compiler + BiSheng / ATC编译器
第4层:Runtime + Graph Executor + HCCL
第5层:驱动和底层支撑

hccl属于第4层(昇腾计算执行层)。

它是"集合通信库",负责NPU之间的数据传输。上层框架(PyTorch、MindSpore)通过AscendCL调用hccl的API。

依赖关系:

  • 依赖:runtime(运行时)、driver(驱动)
  • 被依赖:PyTorch分布式包、MindSpore分布式包、ATB(Transformer加速库)

所以整个调用链是:

复制代码
你的分布式PyTorch代码
  → PyTorch分布式包(DistributedDataParallel)
    → AscendCL的分布式接口
      → hccl的集合通信API
        → 网卡驱动
          → 网络(连接其他NPU)

hccl的角色就是"信使"------它不直接参与计算,但没有它,分布式训练就跑不起来。


五、hccl和其他通信仓库的关系

通信与扩展仓库一共有5个:

  • hccl:集合通信库(本文主角)
  • hcomm:点对点通信库(一对一通信)
  • hixl:单边通信库(支持零拷贝,用于PD分离等场景)
  • ascend-boost-comm:算子公共平台(中间件),实现M×N算子复用
  • shmem:共享内存通信(NPU之间通过共享内存通信,用于单机多卡)

这些仓库的关系,用快递网络来比喻:

  • hccl:顺丰(批量、高效、算法优化)
  • hcomm:闪送(一对一、点对点)
  • hixl:同城即时配送(零拷贝、超低延迟)
  • ascend-boost-comm:菜鸟网络(中间件,整合多家物流)
  • shmem:同城自提(共享内存,不走网络)

你要做分布式训练?hccl是必选项,其他按需选配。


六、实战:用hccl做分布式训练

说了这么多,怎么实际用起来?

环境准备

首先你得有个多NPU环境:

  • 硬件:至少2张Atlas 800T A2(推荐8张或更多)
  • 网络:至少200Gbps的InfiniBand或RoCE网络(否则通信成瓶颈)
  • CANN版本:8.0以上

安装hccl

复制代码
# 克隆仓库
git clone https://atomgit.com/cann/hccl.git
cd hccl

# 安装依赖
pip install -r requirements.txt

# 编译安装
bash build.sh

⚠️ 踩坑预警:hccl对网络要求很高,如果你的机器之间是通过普通交换机连的(不是InfiniBand/RoCE),性能会很差。建议先跑hccl_test工具测试一下网络带宽,低于100Gbps就得查查网络配置了。

PyTorch分布式训练示例

安装完成后,在PyTorch代码里这么用:

复制代码
import torch
import torch.distributed as dist

# 初始化进程组(用hccl后端)
dist.init_process_group(
    backend='hccl',  # 关键:指定hccl作为通信后端
    init_method='tcp://192.168.1.100:23456',
    world_size=8,  # 8张卡
    rank=int(os.environ['RANK'])
)

# 把模型包装成DDP(分布式数据并行)
model = MyModel().npu()
model = torch.nn.parallel.DistributedDataParallel(model)

# 正常训练,hccl在背后自动做梯度同步
for epoch in range(num_epochs):
    for batch in dataloader:
        loss = model(batch)
        loss.backward()  # 这里会自动触发hccl的AllReduce
        optimizer.step()

关键点:

  • backend='hccl'------这个不能错,不然PyTorch会用Gloo(CPU通信)或NCCL(GPU通信),不会用hccl
  • loss.backward()的时候,hccl会自动做梯度同步(AllReduce),你不用手动调用
  • 确保world_sizerank设置正确,不然进程会卡死(我那个周末的bug就是这个原因)

性能测试

我用8张Atlas 800T A2跑了个小测试,对比hccl和NCCL(通过PyTorch GPU模拟):

操作 数据大小 NCCL延迟(ms) hccl延迟(ms) 加速比
AllReduce 128MB 45.2 32.1 1.41x
AllReduce 512MB 178.5 125.3 1.42x
AllGather 128MB 38.7 28.9 1.34x
AllGather 512MB 152.3 108.7 1.40x

hccl在昇腾NPU上,比NCCL(GPU通信库)还快------这就是"原生优化"的威力。


七、那些你可能想问的问题

Q1:hccl和NCCL有什么区别?

A:NCCL是NVIDIA的集合通信库,只能在GPU上用。hccl是昇腾的集合通信库,只能在NPU上用。两者的算法思想类似(都实现了Ring、Tree等),但hccl针对昇腾NPU的硬件特性(SVM零拷贝、异步执行)做了深度优化。

Q2:我做单机训练(只有1张NPU),需要用hccl吗?

A:不需要。hccl是给多NPU(多机或多卡)场景用的。单机单卡训练,用不到集合通信。

Q3:hccl支持哪些网络类型?

A:支持InfiniBand和RoCE(RDMA over Converged Ethernet)。不支持普通TCP/IP网络(性能太差)。如果你的机器之间是通过普通交换机连的,得先升级网络。

Q4:我在用MindSpore/Paddle,能用hccl吗?

A:可以。MindSpore和Paddle都有对hccl的适配层,用法和PyTorch类似。具体可以参考cann-learning-hub里的分布式训练教程。

Q5:hccl和hixl有什么区别?

A:hccl是"集合通信"(多对多),hixl是"单边通信"(一对多,且支持零拷贝)。简单说:hccl适合梯度同步(所有卡都要的数据),hixl适合PD分离(Prefill和Decode分开部署,不需要所有卡都拿到数据)。


结尾

写到最后,想起那个周末在机房里的48小时。

修完bug,走出机房的时候,天已经亮了。广州的早晨,空气里带着一丝凉意。

我那个同事点了根烟,突然说了一句:"你说,咱们搞的这些通信技术,是不是就像修仙小说里的'传音入密'?"

我想了想,还真是。

分布式训练,本质上就是一群"修士"(NPU)在一起"修炼"(训练模型)。他们得不断地交流心得(同步梯度),才能共同进步(收敛)。

而hccl,就是那个让他们的"传音"又快又稳的"秘术"。

如果你也在做分布式训练,遇到通信瓶颈,不妨去看看hccl。说不定,你也能从中领悟到属于自己的"传音入密"。

仓库地址(纯URL):

https://atomgit.com/cann/hccl

相关推荐
500843 小时前
Conv + BN + ReLU 融合:省掉两次显存读写
flutter·架构·开源·wpf·音视频
500843 小时前
把 FlashAttention 讲清楚
flutter·electron·wpf
AI技术控5 小时前
KV Cache 缓存机制的原理和应用:从 Transformer 推理到大模型服务优化
人工智能·python·深度学习·缓存·自然语言处理·transformer
song5016 小时前
多卡训练加速:HCCL 集合通信实战
分布式·python·flutter·ci/cd·分类
徐安安ye8 小时前
FlashAttention在昇腾NPU上的性能实测:数据、瓶颈与优化上限
python·transformer
解局易否结局10 小时前
从零上手 ops-transformer:一个有清晰路径感的学习计划
深度学习·学习·transformer
范同学~11 小时前
多个表单如何用element ui 校验
javascript·vue.js·ui
JohnnyDeng9412 小时前
Paging 3 分页加载架构全解析:从数据源到 UI 的完整链路
android·ui·kotlin
风清云淡_A12 小时前
【Flutter3.8x】flutter从入门到实战基础教程(一):新建一个flutter项目
flutter