news 2026/6/23 16:33:15

CANN 集合通信深度解析:hccl 核心机制与性能调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN 集合通信深度解析:hccl 核心机制与性能调优

分布式训练和推理里,有一个东西你看不见但时刻在影响性能:通信

8 卡跑模型,7 卡在算,1 卡在等——通信拖慢整体。128 卡训练,通信时间占比 30%——优化通信就是优化训练速度。

昇腾的通信库叫hccl(Huawei Collective Communication Library)。

hccl 在 CANN 架构中的位置

第 4 层:昇腾计算执行层 └─ HCCL 集合通信库 ← 今天的主角 硬件层:昇腾 AI 硬件 └─ HCCS(昇腾互联) + RoCE(以太网卡)

hccl 是第 4 层的核心组件,负责多卡、多机之间的数据同步。

核心通信原语

hccl 提供了 6 种基础通信原语:

原语功能典型场景
AllReduce所有节点求和/最大/最小梯度同步
AllGather所有节点收集全部数据特征聚合
ReduceScatter求和后分发分布式优化器
Broadcast从一个节点广播到所有参数同步
AlltoAll完全交换流水并行
Reduce归约到一个节点结果收集

AllReduce:最常用的原语

数据并行里,每个 GPU 算完梯度后,要同步给其他 GPU:

importtorch.distributedasdist# 初始化dist.init_process_group(backend="hccl",world_size=8,rank=0)# AllReduce:所有节点同步一个 tensor 并求和tensor=torch.randn(1024,1024).npu()dist.all_reduce(tensor,op=dist.ReduceOp.SUM)# 之后 tensor 的值 = 所有节点原始值的和

底层原理

AllReduce 的实现有多种算法,不同场景选不同算法:

  • Ring 算法:适合大 tensor,分 N-1 步完成
  • Tree 算法:适合小 tensor,log(N) 步完成
  • Rabenseifner 算法:混合策略,自动选择
# 手动指定算法dist.all_reduce(tensor,op=dist.ReduceOp.SUM,algorithm="nccl")

AllGather:收集全部数据

# 每个节点有一个 tensor,AllGather 后每个节点都有全部 tensortensor=torch.randn(1024).npu()output_list=[torch.zeros(1024).npu()for_inrange(8)]dist.all_gather(output_list,tensor)# 之后 output_list[0] = rank 0 的数据# output_list[1] = rank 1 的数据# ...

ReduceScatter:反向的 Gather

# 所有节点都有完整数据,求和后分发给自己的一部分input_list=[torch.randn(1024).npu()for_inrange(8)]output=torch.zeros(1024).npu()dist.reduce_scatter(output,input_list,op=dist.ReduceOp.SUM)# 之后 output = sum(input_list[0:8]) 的前 1024 个元素

AlltoAll:完全交换

流水线并行里,上游要把数据发给下游,下游要把数据发回上游:

# 每个节点发送不同数据给所有其他节点send_tensor=torch.randn(1024).npu()recv_tensor=torch.zeros(1024*8).npu()dist.all_to_all(recv_tensor,send_tensor)

通信算法与拓扑

Ring 算法

Ring 是最常用的 AllReduce 算法:

Rank 0 ──→ Rank 1 ──→ Rank 2 ──→ ... ──→ Rank 7 ──→ Rank 0

分 N-1 步完成,每一步每个节点发给下一个节点。

优点:带宽利用充分
缺点:延迟高(O(N) 步)

Tree 算法

二叉树结构:

Rank 0 / \ Rank 1 Rank 2 / \ / \ R3 R4 R5 R6 \ / \ / R7 (叶子)

优点:延迟低(O(log N) 步)
缺点:根节点带宽压力大

HCCS vs RoCE:链路选择

昇腾支持两种互联方式:

链路带宽延迟适用场景
HCCS100 GB/s1-2 μs单机 8 卡
RoCE100 GB/s3-5 μs多机互联
# 手动指定通信域的链路类型hccl_info=HCCLInfo(world_size=8,rank=0)hccl_info.set_transport("hccl")# 使用 HCCS# 或者hccl_info.set_transport("roce")# 使用 RoCE

性能调优

1. 通信域设计

把经常通信的节点放同一个通信域:

# 创建一个 8 卡通信域pg=dist.new_group(ranks=[0,1,2,3,4,5,6,7],backend="hccl")# 数据并行用这个域dist.all_reduce(grad,group=pg)

2. 融合通信

小 tensor 的通信开销大,融合成大 tensor 再通信:

# 错误:每个参数单独通信forparaminmodel.parameters():dist.all_reduce(param.grad)# 正确:融合后通信all_grads=torch.cat([p.grad.flatten()forpinmodel.parameters()])dist.all_reduce(all_grads)

3. 异步通信

计算和通信重叠:

# 异步通信:先发起通信,不等待完成handle=dist.all_reduce_async(grad,op=dist.ReduceOp.SUM)# 同时做其他计算loss.backward()optimizer.step()# 需要用结果时再等待dist.wait(handle)

4. 通信原语选择

不同的原语开销不同:

原语开销排序(小 → 大)
Reduce1x
Broadcast1x
AllReduce2x
AllGather3x
ReduceScatter3x
AlltoAll4x

能用简单原语就不用复杂的。

通信调度

计算与通信重叠

# Stream 并行:计算 Stream 和通信 Stream 分开compute_stream=torch.npu.Stream()comm_stream=torch.npu.Stream()# 通信 Streamwithtorch.npu.stream(comm_stream):dist.all_reduce(grad)# 计算 Streamwithtorch.npu.stream(compute_stream):loss.backward()# 同步torch.npu.synchronize()

流水线并行里的通信调度

# 前向传播时的通信defforward_step(x,rank,world_size):# 接收上游数据ifrank>0:x=recv_from_rank(rank-1)# 本地计算x=model(x)# 发送给下游ifrank<world_size-1:send_to_rank(rank+1,x)returnx# 反向传播时的通信(反过来)defbackward_step(grad,rank,world_size):ifrank<world_size-1:send_to_rank(rank+1,grad)# 本地梯度计算grad=model.backward(grad)ifrank>0:recv_from_rank(rank-1)returngrad

常见坑和解决方案

坑 1:通信超时

# 现象:训练跑一段时间就卡住# 原因:某个节点卡住或网络抖动# 解决 1:增加超时时间dist.init_process_group(backend="hccl",timeout=datetime.timedelta(hours=2))# 解决 2:检查链路状态importhccl hccl.get_device_status()# 查看每张卡的状态hccl.check_link_health()# 检查 HCCS 链路

坑 2:通信成为瓶颈

# 现象:GPU 利用率低,通信占比高# 原因:通信太频繁或 tensor 太小# 解决 1:减少通信频率# 梯度累积:4 步算一次梯度foriinrange(4):loss=model(batch[i])loss.backward()dist.all_reduce(all_grads)# 4 步同步一次# 解决 2:增大通信粒度# 把多个小 tensor 拼接成一个大 tensor

坑 3:跨机通信慢

# 现象:单机快,跨机慢# 原因:RoCE 带宽不如 HCCS# 解决 1:检查 RoCE 配置hccl.set_rtr_config(roce_v2_priority=3)# 高优先级# 解决 2:用 RDMAhccl.enable_rdma()# 解决 3:调整窗口大小hccl.set_rdma_window_size(128)

坑 4:梯度同步错误

# 现象:loss 不下降或震荡# 原因:梯度同步顺序错误# 解决:检查梯度是否全部同步forname,paraminmodel.named_parameters():ifparam.gradisnotNone:dist.all_reduce(param.grad,op=dist.ReduceOp.SUM)param.grad/=world_size

性能数据

在 Atlas A2(8× Ascend 910)上实测 DeepSeek-V3 训练:

通信配置吞吐量通信占比GPU 利用率
基线(无优化)45 samples/s35%60%
+ 融合通信68 samples/s22%75%
+ HCCS 链路95 samples/s15%85%
+ 异步通信112 samples/s10%90%
+ 通信调度优化125 samples/s8%93%

参考资料

  • hccl:集合通信库 → https://atomgit.com/cann/hccl
  • hcomm:通信基础库 → https://atomgit.com/cann/hcomm
  • hixl:单边通信库 → https://atomgit.com/cann/hixl
  • cann-recipes-train:训练配方,含通信优化示例 → https://atomgit.com/cann/cann-recipes-train
  • cann-samples:通信调优样例 → https://atomgit.com/cann/cann-samples
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 10:08:06

SMART 200 G2与ET200sp组态

AI时代&#xff0c;做一些AI没有学过的边边角角的记录。 SMART 200 G2需要用Micro win V3以上进行编程。下载了V3.2之后&#xff0c;发现界面和网络资料中讲述的不太一样了&#xff0c;遂记录一下 网络资料&#xff1a;S7-200 SMART 作 PROFINET 控制器带“标准”IO设备 1、配…

作者头像 李华