HCCL 集合通信库:大模型分布式训练的“协同语言“

前言
想象一下,你站在一座巨大的工厂里,数千个工人(AICore)正在同时处理同一个任务。每个工人手里都拿着一部分数据,他们需要不停地交换信息——“我算完了这部分梯度!”“我这里有个权重需要同步!”“大家准备好,我们要合并结果了!”
这可不是普通的聊天,这是昇腾异构计算架构中 HCCL(Huawei Collective Communications Library)每天都在上演的"协同喊话"。
当 AICore 们需要"喊话":集合通信的本质
在分布式深度学习训练中,模型参数往往庞大到无法放进单个芯片的记忆里。Ascend 910 芯片上的多个 AICore 并行计算时,就像工地上的工人需要协同作业——你算完梯度,我算完损失,他算完前向传播,大家必须时刻保持数据一致,否则训练就会"各说各话",模型永远收不到正确的信号。
HCCL 就是这套"喊话系统"的标准语言。它定义了一套集合通信原语(Collective Communication Primitives),让多个计算设备能够高效地交换数据。不同于点对点通信(两个工人私下耳语),集合通信是"一群人开大会"——所有参与者同时喊话、同时倾听、同时行动。
让我们走进 HCCL 的"喊话训练营",看看五种核心通信模式是如何让 AICore 们默契配合的。
五种"喊话"模式:从广播到全员交互
1. Broadcast:村长的喇叭喊话
比喻:村长站在村口,用大喇叭向全体村民广播一条消息。所有人都能听到,内容完全一致。
在分布式训练中,Broadcast 用于将数据从一个进程复制到所有其他进程。比如,主节点初始化模型参数后,需要把这份参数"广播"给所有工作节点。
// 代码示例:HCCL Broadcast 调用
#include "hccl/hccl.h"
// 第 1 行:初始化 HCCL 通信域
hcclComm_t comm;
hcclCommInitAll(&comm, rank, nRanks);
// 第 2 行:定义广播的根节点(村长)
int root = 0;
// 第 3 行:准备广播的数据缓冲区
float* data = (float*)malloc(bufferSize);
if (rank == root) {
// 根节点填充数据
initialize_model_parameters(data);
}
// 第 4 行:执行广播操作
hcclResult_t ret = hcclBroadcast(
data, // 发送/接收缓冲区
elementCount, // 元素数量
HCCL_FLOAT, // 数据类型
root, // 根节点编号
comm, // 通信域
stream // 昇腾达芬奇架构的流
);
// 第 5 行:同步等待广播完成
hcclCommStreamSynchronize(comm, stream);
逐行解释:
- 第 1 行:初始化 HCCL 通信域,让所有 AICore 加入"喊话群聊",
rank是当前设备的编号,nRanks是总设备数。 - 第 2 行:指定根节点(root),就像选村长,只有村长有喇叭。
- 第 3 行:准备数据缓冲区,根节点的缓冲区里有数据,其他节点的缓冲区是空的(等待接收)。
- 第 4 行:调用
hcclBroadcast,HCCL 会自动选择最优算法(Ring 或 Mesh),让数据像水波一样从根节点扩散到所有节点。 - 第 5 行:同步等待,确保所有 AICore 都收到了完整数据,避免"有人还在听,有人已经开始算了"的混乱。
2. AllReduce:全员投票汇总
比喻:村委会开会,每个人手里有一张选票(局部梯度),大家需要把所有选票加起来,得到总票数(全局梯度),然后每个人都拿到这份总和。
AllReduce 是分布式训练中最核心的操作——每个 AICore 计算完本地梯度后,通过 AllReduce 求和,得到全局梯度,再用于参数更新。
// 代码示例:HCCL AllReduce 调用
#include "hccl/hccl.h"
// 第 1 行:假设每个进程都计算完了本地梯度
float* localGrad = get_local_gradients();
// 第 2 行:准备接收全局梯度的缓冲区
float* globalGrad = (float*)malloc(bufferSize);
// 第 3 行:执行 AllReduce 操作
hcclResult_t ret = hcclAllReduce(
localGrad, // 发送缓冲区(本地梯度)
globalGrad, // 接收缓冲区(全局梯度)
elementCount, // 梯度元素数量
HCCL_FLOAT, // 数据类型
HCCL_SUM, // 归约操作:求和
comm, // 通信域
stream // 昇腾达芬奇架构的流
);
// 第 4 行:同步等待 AllReduce 完成
hcclCommStreamSynchronize(comm, stream);
// 第 5 行:使用全局梯度更新模型参数
update_model_parameters(globalGrad);
逐行解释:
- 第 1 行:每个 AICore 通过反向传播计算出本地梯度,存储在
localGrad中。 - 第 2 行:分配全局梯度缓冲区,AllReduce 的结果会写到这里。
- 第 3 行:调用
hcclAllReduce,HCCL 会使用 Ring 或 Tree 算法,让所有 AICore 的梯度"绕圈"传递并累加,最终每个人都拿到完整的全局梯度。 - 第 4 行:同步等待,确保所有 AICore 的梯度都计算完毕且通信完成。
- 第 5 行:用全局梯度更新模型参数,这一步每个 AICore 都会执行,因为大家都拿到了相同的
globalGrad。
3. AllGather:拼图游戏
比喻:五个人各自拿着拼图的一部分,大家需要把自己的部分展示给所有人,最终每个人都拥有完整的拼图。
AllGather 用于收集所有进程的张量,并在所有进程上拼接成完整的张量。在张量并行(TP)中,每一层的输出需要 AllGather 来聚合所有 AICore 的计算结果。
// 代码示例:HCCL AllGather 调用
#include "hccl/hccl.h"
// 第 1 行:每个进程持有部分张量
float* localTensor = get_local_tensor_part();
// 第 2 行:准备接收完整张量的缓冲区
float* fullTensor = (float*)malloc(fullBufferSize);
// 第 3 行:执行 AllGather 操作
hcclResult_t ret = hcclAllGather(
localTensor, // 发送缓冲区(本地张量部分)
fullTensor, // 接收缓冲区(完整张量)
localElementCount, // 每个进程的张量大小
HCCL_FLOAT, // 数据类型
comm, // 通信域
stream // 昇腾达芬奇架构的流
);
// 第 4 行:同步等待 AllGather 完成
hcclCommStreamSynchronize(comm, stream);
// 第 5 行:使用完整张量进行后续计算
compute_next_layer(fullTensor);
逐行解释:
- 第 1 行:在张量并行中,每一层会被切分成多份,每个 AICore 只计算其中一份,存储在
localTensor中。 - 第 2 行:分配完整张量的缓冲区,大小是所有进程张量之和。
- 第 3 行:调用
hcclAllGather,HCCL 会让每个 AICore 把自己的部分"喊"出来,其他人"听"到后拼接到自己的缓冲区。 - 第 4 行:同步等待,确保拼接完成。
- 第 5 行:用完整张量计算下一层,比如在 Transformer 的多头注意力中,AllGather 用于聚合所有头的输出。
4. ReduceScatter:分而治之的逆向操作
比喻:一群人手里都有完整的清单,但需要把清单按照某种规则切分,每个人只保留自己负责的那部分,同时把其他部分"扔"给对应的人。
ReduceScatter 是 AllGather 的逆操作——它先把所有进程的数据归约(求和、求最大值等),然后再散射到各个进程。在分布式优化器中,ReduceScatter 用于切分梯度,让每个 AICore 只更新自己负责的参数部分。
// 代码示例:HCCL ReduceScatter 调用
#include "hccl/hccl.h"
// 第 1 行:每个进程持有完整的梯度张量
float* fullGrad = get_full_gradients();
// 第 2 行:准备接收局部梯度的缓冲区
float* localGradPart = (float*)malloc(localBufferSize);
// 第 3 行:执行 ReduceScatter 操作
hcclResult_t ret = hcclReduceScatter(
fullGrad, // 发送缓冲区(完整梯度)
localGradPart, // 接收缓冲区(局部梯度)
localElementCount, // 每个进程的梯度大小
HCCL_FLOAT, // 数据类型
HCCL_SUM, // 归约操作:求和
comm, // 通信域
stream // 昇腾达芬奇架构的流
);
// 第 4 行:同步等待 ReduceScatter 完成
hcclCommStreamSynchronize(comm, stream);
// 第 5 行:每个进程只更新自己负责的参数部分
update_local_parameters(localGradPart);
逐行解释:
- 第 1 行:假设通过某种方式(比如 AllGather),每个 AICore 都拿到了完整的梯度张量。
- 第 2 行:分配局部梯度缓冲区,大小是完整梯度除以进程数。
- 第 3 行:调用
hcclReduceScatter,HCCL 会先对所有 AICore 的梯度进行归约(比如求和),然后再按照 rank 切分,每个 AICore 拿到自己对应的部分。 - 第 4 行:同步等待,确保切分完成。
- 第 5 行:每个 AICore 只用自己拿到的局部梯度更新对应的参数部分,实现参数的分布式更新。
5. AlltoAll:全员交叉换位
比喻:舞会上,每个人都要和所有人交换舞伴。你把手里的花给张三,李四把书给你,王五把帽子给张三……最终每个人都拿到了别人手里的东西。
AlltoAll 是最复杂的通信模式——每个进程都会向其他所有进程发送数据,同时从其他所有进程接收数据。在专家并行(EP)中,AlltoAll 用于在不同 AICore 之间重新分配数据,让每个专家都能处理自己擅长的样本。
// 代码示例:HCCL AlltoAll 调用
#include "hccl/hccl.h"
// 第 1 行:准备发送缓冲区(每个进程要给其他人发送的数据)
float* sendBuf = prepare_send_data();
// 第 2 行:准备接收缓冲区
float* recvBuf = (float*)malloc(recvBufferSize);
// 第 3 行:执行 AlltoAll 操作
hcclResult_t ret = hcclAlltoAll(
sendBuf, // 发送缓冲区
sendCountPerRank, // 给每个进程发送的元素数量
HCCL_FLOAT, // 发送数据类型
recvBuf, // 接收缓冲区
recvCountPerRank, // 从每个进程接收的元素数量
HCCL_FLOAT, // 接收数据类型
comm, // 通信域
stream // 昇腾达芬奇架构的流
);
// 第 4 行:同步等待 AlltoAll 完成
hcclCommStreamSynchronize(comm, stream);
// 第 5 行:使用重新分配后的数据
process_redistributed_data(recvBuf);
逐行解释:
- 第 1 行:在专家并行中,每个 AICore 负责一些专家,需要把输入数据按照专家分配情况发送给对应的 AICore。
- 第 2 行:分配接收缓冲区,用于存放其他 AICore 发来的数据。
- 第 3 行:调用
hcclAlltoAll,HCCL 会构建一个通信调度表,让所有 AICore 同时发送和接收数据,就像舞会上的"交叉换位"。 - 第 4 行:同步等待,确保数据重新分配完成。
- 第 5 行:用重新分配后的数据进行计算,每个专家现在拿到了自己需要处理的数据。
三种"喊话"算法:Ring、Mesh 与 RHD
HCCL 之所以高效,是因为它内置了多种集合通信算法,会根据通信域大小、消息大小、拓扑结构自动选择最优算法。让我们认识三位"喊话专家":
Ring 算法:击鼓传花
原理:所有进程排成一个环,数据像击鼓传花一样在环上传递。每个进程只和邻居通信,带宽利用率高,适合大规模集群。
适用场景:AllReduce、AllGather 等操作,特别是在进程数较多(>8)时,Ring 算法的延迟低、带宽利用率高。
Rank 0 → Rank 1 → Rank 2 → Rank 3 → Rank 4
↑ ↓
← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←
Mesh 算法:网格式协同
原理:进程按照物理拓扑排列成网格,每个进程和多个邻居同时通信。在多机多卡场景下,Mesh 算法能充分利用机内高速互联和机间网络。
适用场景:小规模集群(≤8 卡),或需要低延迟的场景。
RHD 算法:层级式动态调度
原理:Hierarchical + Dynamic,在多层网络拓扑中(如机内 HCCS + 机间 RoCE),先在每层内部做局部通信,再做跨层通信。同时动态感知网络状态,选择最优路径。
适用场景:超大规模集群(64+ 卡),跨机通信占比高的场景,比如大模型训练。
TP/PP/EP 并行中的 HCCL 配置与优化
在大模型训练中,HCCL 是三种并行策略的通信基础:
张量并行(TP):每个计算层被切分到多个 AICore。核心通信是 AllReduce(每层前向/反向传播后)和 AllGather(聚合多头输出)。通信量随切分粒度线性增长,是 HCCL 性能调优的重点。
流水线并行(PP):不同设备负责模型的不同层。核心通信是 Send/Recv(点对点),但 microbatch 在 PP 中的调度依赖 AllReduce 做梯度同步。
专家并行(EP):MoE 模型中,不同设备负责不同的专家。核心通信是 AlltoAll(输入数据在不同专家间的重新分配)。
大模型训练通信瓶颈分析:
TP(张量并行):AllReduce 频繁,通信带宽要求最高
↓
PP(流水线并行):点对点通信为主,但梯度同步依赖 AllReduce
↓
EP(专家并行):AlltoAll 频繁,数据重分配开销大
↓
混合并行(TP+PP+EP):多种通信模式叠加,HCCL 综合调度
优化建议:在大模型训练中,建议使用 HCCS 或 RoCE 网络(HBM 带宽可达 GB/s 级,远超 PCIe),并开启 HCCL 的拓扑感知,让 Ring 算法优先选择机内通信链路,减少跨机通信。
HCCS/RoCE/PCIe:三条高速公路的自适应选择
HCCL 支持三种物理链路,会根据硬件拓扑自动选择:
- HCCS(Huawei Collective Communication Service):昇腾自研高速互联总线,机内互联首选,延迟最低。
- RoCE(RDMA over Converged Ethernet):基于以太网的 RDMA,适合跨机通信,带宽高、成本低。
- PCIe:通用总线,兼容性好但带宽和延迟都不如前两者。
HCCL 会自动感知物理拓扑,优先使用 HCCS 做机内通信,只在必要时跨机使用 RoCE/PCIe。这种"近者优先"的策略,让通信效率始终保持在最优状态。
更多推荐

所有评论(0)