前言
去年双十一,阿里云华南区的一台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通信),不会用hcclloss.backward()的时候,hccl会自动做梯度同步(AllReduce),你不用手动调用- 确保
world_size和rank设置正确,不然进程会卡死(我那个周末的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):