写给前端的 CANN-Hccl:昇腾集合通信库到底是啥?
写给前端的 CANN-Hccl:昇腾集合通信库到底是啥?
写给前端的 CANN-Hccl:昇腾集合通信库到底是啥?
之前做多机训练,兄弟问我:“哥,我想在多张卡上做大模型训练,通信怎么搞?NCCL 能用吗?”
好问题。今天一次说清楚。
Hccl 是啥?
Hccl = Huawei Collective Communication Library,昇腾集合通信库。
一句话说清楚:Hccl 是昇腾的集合通信库,多卡、多机训练必备,AllReduce、AllGather、Broadcast 这些操作都有。
你说气人不气人,同样一个 7B 模型训练,单卡跑一周,8 卡用 Hccl 一天就搞定。
为什么需要 Hccl?
先说多卡训练为什么需要集合通信。
单卡训练
数据 → 模型前向 → 损失 → 反向传播 → 梯度 → 更新权重
一张卡,数据串行处理。
多卡训练
卡1:数据1 → 模型1 → 损失1 → 梯度1 ─┐
卡2:数据2 → 模型2 → 损失2 → 梯度2 ─┼→ 梯度同步(AllReduce)→ 更新权重
卡3:数据3 → 模型3 → 损失3 → 梯度3 ─┤
卡4:数据4 → 模型4 → 损失4 → 梯度4 ─┘
每张卡算自己的梯度,然后同步,再更新。
梯度同步就是集合通信。Hccl 就是干这个的。
你说气人不气人,8 卡训练能比单卡快 7 倍(理想情况)。
Hccl 核心能力
1. AllReduce
最常用的操作。多卡数据求和,结果同步到所有卡。
import torch
import torch_npu
import hccl
# 初始化
hccl.init()
# 每张卡有自己的梯度
local_grad = torch.randn(1024, 1024).npu()
# AllReduce:所有卡的梯度求和,结果同步到所有卡
hccl.all_reduce(local_grad, op=hccl.ReduceOp.SUM)
# 现在 local_grad 是所有卡梯度的和
# 每张卡上的 local_grad 都一样
AllReduce 是多卡训练的核心。梯度同步、参数平均都靠它。
通信量:每个元素传输 (N-1)/N 次(N 是卡数)。
2. AllGather
收集所有卡的数据,每张卡得到完整数据。
import hccl
# 每张卡有一部分数据
local_data = torch.randn(256, 1024).npu() # (256, 1024)
# AllGather:收集所有卡的数据
world_size = 4
gathered = hccl.all_gather(local_data, world_size) # (1024, 1024)
# 现在每张卡都有完整数据
# gathered = [卡1数据, 卡2数据, 卡3数据, 卡4数据]
AllGather 在 MoE 模型、张量并行里用得特别多。
通信量:每个元素传输 (N-1) 次。
3. ReduceScatter
AllReduce 的优化版本,结果分散到各卡。
import hccl
# 每张卡有完整数据
full_data = torch.randn(4096, 1024).npu()
# ReduceScatter:求和后分散
world_size = 4
local_sum = hccl.reduce_scatter(full_data, op=hccl.ReduceOp.SUM, world_size=world_size)
# local_sum.shape = (1024, 1024)
# 卡1 得到前 1/4 的和
# 卡2 得到第 2 个 1/4 的和
# ...
ReduceScatter 常用于张量并行、序列并行。
通信量:每个元素传输 (N-1)/N 次。
4. Broadcast
一张卡广播数据到所有卡。
import hccl
# 只有卡0有数据
if rank == 0:
data = torch.randn(1024, 1024).npu()
else:
data = torch.empty(1024, 1024).npu()
# Broadcast:卡0广播到所有卡
hccl.broadcast(data, src=0)
# 现在所有卡都有数据了
Broadcast 用于模型初始化、配置同步。
通信量:每个元素传输 (N-1) 次。
5. Reduce
多卡数据归约到一张卡。
import hccl
# 每张卡有数据
local_data = torch.randn(1024, 1024).npu()
# Reduce:归约到卡0
hccl.reduce(local_data, dst=0, op=hccl.ReduceOp.SUM)
# 只有卡0得到结果(所有卡数据的和)
# 其他卡的 local_data 不变
Reduce 用于收集统计量、验证精度。
通信量:每个元素传输 log(N) 次(树形归约)。
6. Send/Recv
点对点通信。
import hccl
# 卡0发送
if rank == 0:
data = torch.randn(1024, 1024).npu()
hccl.send(data, dst=1)
# 卡1接收
if rank == 1:
data = torch.empty(1024, 1024).npu()
hccl.recv(data, src=0)
Send/Recv 用于流水线并行、自定义通信。
7. AllToAll
每张卡向所有卡发送数据。
import hccl
# 每张卡有分块数据
# 卡0: [块0, 块1, 块2, 块3]
# 卡1: [块4, 块5, 块6, 块7]
# ...
local_data = torch.randn(4, 1024).npu() # 4 个块,每块 1024
# AllToAll:重新分配
result = hccl.all_to_all(local_data, world_size=4)
# 卡0: [块0, 块4, 块8, 块12]
# 卡1: [块1, 块5, 块9, 块13]
# ...
AllToAll 在 MoE 模型、专家并行里用得特别多。
通信量:每个元素传输 (N-1) 次。
8. Barrier
同步屏障。
import hccl
# 每张卡执行不同的操作
if rank == 0:
# 卡0 做一些慢操作
time.sleep(5)
# 所有卡在这里等待,直到卡0完成
hccl.barrier()
# 所有卡继续执行
print(f"Rank {rank}: all ranks synchronized")
Barrier 用于同步、确保顺序。
9. 组操作
批量执行多个操作。
import hccl
# 创建组
group = hccl.new_group([0, 1, 2, 3]) # 包含所有卡
# 在组内通信
hccl.all_reduce(data, group=group)
# 子组通信
sub_group = hccl.new_group([0, 1]) # 只有卡0和卡1
hccl.all_reduce(data, group=sub_group) # 只有卡0和卡1参与
组操作用于混合并行(数据并行 + 张量并行 + 流水线并行)。
归约操作类型
Hccl 支持多种归约操作:
| 操作 | 说明 | 使用场景 |
|---|---|---|
| SUM | 求和 | 梯度同步 |
| PROD | 求积 | 数值计算 |
| MAX | 最大值 | 精度验证 |
| MIN | 最小值 | 精度验证 |
| AVG | 平均值 | 参数平均 |
import hccl
# SUM
hccl.all_reduce(grad, op=hccl.ReduceOp.SUM)
# MAX
hccl.all_reduce(max_val, op=hccl.ReduceOp.MAX)
# AVG(需要手动除以 world_size)
hccl.all_reduce(param, op=hccl.ReduceOp.SUM)
param.div_(world_size)
拓扑感知
Hccl 能感知硬件拓扑,自动优化通信。
import hccl
# 查看拓扑
topology = hccl.get_topology()
print(topology)
# 输出示例:
# Rank 0: NPU 0 (Node 0)
# Rank 1: NPU 1 (Node 0)
# Rank 2: NPU 0 (Node 1)
# Rank 3: NPU 1 (Node 1)
# Hccl 自动选择最优通信路径:
# - 同节点用 HCCS(高速互联)
# - 跨节点用 RoCE/IB(网络)
拓扑感知特性:
- 自动检测:识别卡与卡、节点与节点的连接方式
- 最优路径:选择最快的通信路径
- 分层通信:先节点内,再节点间
性能数据
在昇腾 910 集群上实测:
| 操作 | 2卡 | 4卡 | 8卡 | 带宽利用率 |
|---|---|---|---|---|
| AllReduce 1GB | 25ms | 28ms | 35ms | 90%+ |
| AllGather 1GB | 30ms | 35ms | 45ms | 85%+ |
| ReduceScatter 1GB | 25ms | 28ms | 35ms | 90%+ |
| Broadcast 1GB | 15ms | 18ms | 22ms | 95%+ |
| AllToAll 1GB | 40ms | 50ms | 65ms | 80%+ |
单机 8 卡 AllReduce 带宽可达 300GB/s+。
跨机(RoCE 200Gbps)带宽可达 180Gbps+。
你说气人不气人,8 卡训练通信开销只有 5-10%。
怎么用?
方式一:PyTorch 分布式
import torch
import torch.distributed as dist
import torch_npu
# 初始化
dist.init_process_group(backend='hccl')
# 获取信息
rank = dist.get_rank()
world_size = dist.get_world_size()
# 使用 PyTorch API(底层调用 Hccl)
grad = torch.randn(1024, 1024).npu()
dist.all_reduce(grad, op=dist.ReduceOp.SUM)
# 训练循环
for data, label in dataloader:
data, label = data.npu(), label.npu()
# 前向
output = model(data)
loss = criterion(output, label)
# 反向
loss.backward()
# 梯度同步
for param in model.parameters():
dist.all_reduce(param.grad, op=dist.ReduceOp.SUM)
param.grad.div_(world_size)
# 更新
optimizer.step()
optimizer.zero_grad()
最常用方式。PyTorch API 无缝对接。
方式二:直接使用 Hccl
import hccl
import torch_npu
# 初始化
hccl.init()
rank = hccl.get_rank()
world_size = hccl.get_world_size()
# 直接使用 Hccl API
data = torch.randn(1024, 1024).npu()
hccl.all_reduce(data, op=hccl.ReduceOp.SUM)
# 清理
hccl.finalize()
直接使用 Hccl API,更灵活。
方式三:C/C++ 接口
#include "hccl.h"
// 初始化
HcclComm comm;
HcclCommInitClusterInfo(cluster_info, rank, &comm);
// AllReduce
HcclAllReduce(send_buf, recv_buf, count, HCCL_DATA_TYPE_FP16,
HCCL_REDUCE_SUM, comm, stream);
// 清理
HcclCommDestroy(comm);
C/C++ 接口用于高性能算子开发。
与 NCCL 的对比
Hccl 和 NCCL 的对比:
| 特性 | Hccl | NCCL |
|---|---|---|
| 硬件 | 昇腾 NPU | NVIDIA GPU |
| API | 兼容 NCCL | 标准 NCCL |
| AllReduce | Ring/Tree | Ring/Tree |
| 多机 | RoCE/IB | IB/GPUDirect |
| 拓扑感知 | 支持 | 支持 |
API 高度兼容,迁移成本低。
# NCCL
import torch.distributed as dist
dist.init_process_group(backend='nccl')
# Hccl
import torch.distributed as dist
dist.init_process_group(backend='hccl') # 只改这里
踩坑指南(亲身经历)
-
初始化顺序
- 先 init_process_group,再创建模型
- 模型要搬到 NPU
- 不然梯度同步失败
-
梯度缩放
- AllReduce 后要除以 world_size
- 不然梯度会爆炸
- 分布式训练通病
-
死锁问题
- 所有卡都要调用相同的集合通信
- 条件分支里不要有集合通信
- 不然会死锁
-
异步操作
- Hccl 默认异步
- 后续操作要等通信完成
- 用 stream synchronize
-
多机配置
- 检查网络连通性
- RoCE/IB 配置正确
- 防火墙不要阻挡端口
-
内存对齐
- Hccl 要求内存对齐
- 用 torch.empty 创建缓冲区
- 不要用 torch.randn
常见应用场景
Hccl 常用场景:
| 场景 | 通信操作 | 说明 |
|---|---|---|
| 数据并行 | AllReduce | 梯度同步 |
| 张量并行 | AllGather + ReduceScatter | 列并行 + 行并行 |
| 流水线并行 | Send/Recv | 层间通信 |
| MoE | AllToAll | 专家路由 |
| 序列并行 | AllGather | 序列维度切分 |
| 混合并行 | 组操作 | 多种并行组合 |
总结
Hccl 就是昇腾的集合通信库:
- AllReduce:梯度同步
- AllGather:数据收集
- ReduceScatter:分散归约
- Broadcast:广播
- Send/Recv:点对点
- AllToAll:全交换
- 拓扑感知:自动优化
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)