NCCL源码解读3.1:double binary tree双二叉树构建算法,相比ring环算法的优势

news2025/1/7 6:47:08

目录

一、双二叉树出现的原因

二、双二叉树介绍

三、双二叉树大规模性能

四、双二叉树源码解读

双二叉树注意事项

核心逻辑

源码速递


视频分享在这,未完待补充:

3.1 NCCL源码解读双二叉树构建算法,double binary tree相比ring环算法的优_哔哩哔哩_bilibili

一、双二叉树出现的原因

ring环算法,延迟随 GPU 数量线性扩展,从而无法扩展到数百个 GPU 以上。

想象一下,使用数以万计的 GPU 来训练您的神经网络。使用多个 GPU 来训练神经网络在所有深度学习框架中都已变得非常普遍,提供优化的多 GPU 和多机器训练。用于对多个 GPU 上的梯度求和的 Allreduce 操作通常使用环 [1] [2] 来实现,以实现全带宽。环的缺点是延迟随 GPU 数量线性扩展,从而无法扩展到数百个 GPU 以上。进入 NCCL 2.4。

许多大规模实验已经用分层的 2D 环算法 [3] [4] [5] 取代了平面环,以获得相当好的带宽,同时降低延迟。

NCCL 2.4 现在增加了双二叉树,它提供完整的带宽和甚至低于 2D 环形延迟的对数延迟。

二、双二叉树介绍

双二叉树于 2009 年在 MPI 中引入 [6],其优势是将广播和 reduce 操作的全带宽(可以组合成一个执行 reduce,然后执行广播的 allreduce)和对数延迟相结合,从而在中小型操作中实现良好的性能。

在 NCCL 中,我们使用一种易于实现的模式构建二叉树,该模式使局部性最大化,如图 1 所示。

二叉树图

图 1.二叉树

双二叉树依赖于这样一个事实,即二叉树中一半或更少的秩是节点,而一半(或更多)秩是叶。因此,我们可以用叶子作为节点来构建第二棵树,反之亦然。可能有一个等级在两棵树上都是叶子,但没有一个等级是两棵树上的节点。

图 2 显示了如何使用上面的模式通过翻转树来反转节点和叶子来构建双二叉树。

双互补二叉树图

图 2.两个互补的二叉树,其中每个秩最多是一个树中的一个节点和另一个树中的一个叶子。

如果将这两个树叠加,则所有等级都同时具有两个父级和两个子级,但根级除外,根级只有一个父级和一个子级。如果我们用两棵树中的每一棵来处理一半的数据,那么每个 rank 最多会收到两次一半的数据,两次发送一半的数据,这在发送/接收的数据方面就像 rings 一样最优。

三、双二叉树大规模性能

我们在各种大型机器上测试了 NCCL 2.4,包括 Summit [7] 超级计算机,最高可达 24,576 个 GPU。如图 3 所示,使用树时延迟显著改善。与ring的差异随着规模的增加而增加,在 24k GPU 上提升高达 180 倍。

Summit Latency 图表

图 3.NCCL 延迟高达 24,576 个 GPU

我们确认该系统使用双二叉树保持全带宽。在规模上,当我们在 InfiniBand 结构中跨越 L3 交换机时,带宽会略有下降,我们认为这是由于 NCCL 通信模式和 InfiniBand 路由算法之间的效率低下造成的。

虽然并不完美,但将来可能会改进。即便如此,由于初始延迟较小,即使带宽受限,树仍然显示出明显的优势。但是,当该模式导致更大的带宽时,NCCL 会自动切换回环。

峰会带宽图

图 4.多达 24,576 个 GPU 上的 NCCL 总线带宽

四、双二叉树源码解读

4.1 双二叉树注意事项

在正式开始源码解读之前,有几点是需要大家注意的!

待补充。。。。

 4.2 connectTrees()
核心逻辑

1、connectTrees()中调用ncclGetDtree()构建双二叉树

2、ncclGetDtree()调用ncclGetBtree()构建树

这里重点想和大家强调ncclGetDtree()的输入,注意看是node不是rank。

源码速递

源码位置:nccl-2.19\src\graph\connect.cc

static ncclResult_t connectTrees(struct ncclComm* comm, int* treeToParent, int* treeToChild0, int* treeToChild1, int* treePatterns) {
  const int nChannels = comm->nChannels, nNodes = comm->nNodes, node = comm->node;

  // Compute tree depth. Not an exact value but a good approximation in most
  // cases
  int depth = comm->nRanks/nNodes - 1 + log2i(nNodes);

  int t0u, t0d0, t0d1, t0ChildType, t1u, t1d0, t1d1, t1ChildType;
  int* ttp, *ttc0, *ttc1;
  NCCLCHECK(ncclGetDtree(nNodes, node, &t0u, &t0d0, &t0d1, &t0ChildType, &t1u, &t1d0, &t1d1, &t1ChildType));

  //其它代码...................

}
 4.3 ncclGetDtree() 
核心逻辑

1、调用ncclGetBtree来生成第一棵树

2、nranks是奇数时,通过“移位”操作生成第二颗树。即,每个rank的排名都会向前移动一个位置(通过取模操作处理边界情况),再调用ncclGetBtree来生成第二棵树。

3、nranks是偶数时,通过“镜像”操作生成第二颗树。即,每个rank的排名都会取镜像值(nranks-1-rank),再调用ncclGetBtree来生成第二棵树。

源码速递

源码位置:nccl-2.19\src\graph\trees.cc

/* Build a double binary tree. Take the previous tree for the first tree.
 * For the second tree, we use a mirror tree (if nranks is even)
 *
 * 0---------------8                   3----------------11
 *          ______/ \                 / \______
 *         4         \               /         7
 *       /   \        \             /        /   \
 *     2       6       10         1        5      9
 *    / \     / \     /  \       / \      / \    / \
 *   1   3   5   7   9   11     0   2    4   6  8   10
 *
 * or shift it by one rank (if nranks is odd).
 *
 * 0---------------8            1---------------9
 *          ______/ \______              ______/ \______
 *         4               12           5                0
 *       /   \            /           /   \            /
 *     2       6       10           3       7       11
 *    / \     / \     /  \         / \     / \     /  \
 *   1   3   5   7   9   11       2   4   6   8  10   12
 */
// 定义一个函数,用于获取双通信树。输入参数包括总节点数、当前节点标识符,以及指向存储树信息的指针。

ncclResult_t ncclGetDtree(int nranks, int rank, int* s0, int* d0_0, int* d0_1, int* parentChildType0, int* s1, int* d1_0, int* d1_1, int* parentChildType1) {


  // 首先构建第一个通信树(基础树),使用B树(Binary Tree)的构建方法。
  // 该步骤填充了s0, d0_0, d0_1, parentChildType0指针所指向的数组。
  ncclGetBtree(nranks, rank, s0, d0_0, d0_1, parentChildType0);


  // 接下来构建第二个通信树。根据总节点数nranks的奇偶性,决定是构建镜像树还是位移树。
  // 如果nranks是奇数,则构建位移树。
  if (nranks % 2 == 1) {
    // 计算位移后的节点标识符。这里通过(rank-1+nranks) % nranks来确保结果是非负的。
    int shiftrank = (rank-1+nranks) % nranks;

    // 临时变量,用于存储B树构建过程中得到的父节点、两个子节点的标识符。
    int u, d0, d1;

    
    // 使用B树的构建方法,根据位移后的节点标识符来获取位移树的父节点和子节点。
    ncclGetBtree(nranks, shiftrank, &u, &d0, &d1, parentChildType1);

    // 由于是位移树,所以需要将得到的节点标识符进行模nranks运算,以确保它们在有效范围内。
    // 注意这里的+1操作,是因为位移树的构建是基于位移后的节点标识符,而我们需要的是原始标识符空间中的对应值。
    *s1 = u == -1 ? -1 : (u+1) % nranks;
    *d1_0 = d0 == -1 ? -1 : (d0+1) % nranks;
    *d1_1 = d1 == -1 ? -1 : (d1+1) % nranks;

  } else {
    // 如果nranks是偶数,则构建镜像树。
    // 临时变量,用途同上。
    int u, d0, d1;
  

    // 使用B树的构建方法,但这次是根据镜像后的节点标识符(即nranks-1-rank)来获取镜像树的父节点和子节点。
    ncclGetBtree(nranks, nranks-1-rank, &u, &d0, &d1, parentChildType1);

    
    // 由于是镜像树,所以需要将得到的节点标识符进行镜像处理,即使用nranks-1减去对应的标识符。
    *s1 = u == -1 ? -1 : nranks-1-u;
    *d1_0 = d0 == -1 ? -1 : nranks-1-d0;
    *d1_1 = d1 == -1 ? -1 : nranks-1-d1;
  }
 
  // 函数执行成功,返回ncclSuccess。
  return ncclSuccess;

}
 4.4 ncclGetBtree
核心逻辑

1、通过位操作找到rank中的第一个非零位(bit)。

2、rank0是树的根节点,父节点为-1(无父节点),并计算第一个子节点(如果存在)

3、对于非根节点,计算父节点的排名。

4、对于非根节点,计算两个子节点的排名。

源码速递

源码位置:

nccl-2.19\src\graph\trees.cc

/* Btree which alternates leaves and nodes.
 * Assumes root is 0, which conveniently builds a tree on powers of two,
 * (because we have pow2-1 ranks) which lets us manipulate bits.
 * Find first non-zero bit, then :
 * Find the parent :
 *   xx01[0] -> xx10[0] (1,5,9 below) or xx00[0] if xx10[0] is out of bounds (13 below)
 *   xx11[0] -> xx10[0] (3,7,11 below)
 * Find the children :
 *   xx10[0] -> xx01[0] (2,4,6,8,10,12) or -1 (1,3,5,7,9,11,13)
 *   xx10[0] -> xx11[0] (2,4,6,8,10) or xx101[0] (12) or xx1001[0] ... or -1 (1,3,5,7,9,11,13)
 *
 * Illustration :
 * 0---------------8
 *          ______/ \______
 *         4               12
 *       /   \            /  \
 *     2       6       10     \
 *    / \     / \     /  \     \
 *   1   3   5   7   9   11    13
 */

// 定义一个函数,用于获取B树的结构信息。输入参数包括总节点数、当前节点标识符,以及指向存储父节点和两个子节点标识符的指针。
ncclResult_t ncclGetBtree(int nranks, int rank, int* u, int* d0, int* d1, int* parentChildType) {

  int up, down0, down1; // 声明用于存储父节点和两个子节点标识符的变量
  int bit; // 声明用于位操作的变量

  // 通过位操作找到rank中第一个非零位的位置
  for (bit=1; bit<nranks; bit<<=1) {
    if (bit & rank) break; // 若bit位与rank的对应位均为1,则跳出循环
  }

  // 处理根节点(rank为0)的特殊情况
  if (rank == 0) {
    *u = -1; // 根节点没有父节点
    *d0 = -1; // 根节点可能没有第一个子节点(取决于nranks)

    // 根节点的第二个子节点(如果存在)是bit右移一位得到的节点
    *d1 = nranks > 1 ? bit >> 1 : -1;
    return ncclSuccess; // 函数执行成功
  }

 
  // 根据位操作计算父节点的标识符
  up = (rank ^ bit) | (bit << 1); // 若rank的bit位为1,则将其翻转并设置更高一位为1,得到父节点的候选值

  // 若候选父节点标识符超出范围,则使用另一个候选值(仅翻转bit位)
  if (up >= nranks) up = (rank ^ bit);
  *parentChildType = (rank < up) ? 0 : 1; // 根据当前节点与父节点的关系设置父子关系类型(0为第一个子节点,1为第二个子节点)

  *u = up; // 存储父节点标识符

 
  int lowbit = bit >> 1; // 计算低位的值(用于确定子节点的位置)
  // 第一个子节点总是在当前节点的低位侧,但需注意边界情况
  down0 = lowbit == 0 ? -1 : rank-lowbit;

 
  // 第二个子节点的计算需要考虑边界情况,确保其标识符在有效范围内内
  down1 = lowbit == 0 ? -1 : rank+lowbit;
  while (down1 >= nranks) { // 若第二个子节点标识符超出范围,则通过不断右移lowbit来尝试修正
    down1 = lowbit == 0 ? -1 : rank+lowbit;
    lowbit >>= 1;
  }

  // 存储两个子节点的标识符
  *d0 = down0;
  *d1 = down1; 

  return ncclSuccess; // 函数执行成功

}

参考资料

Massively Scale Your Deep Learning Training with NCCL 2.4 | NVIDIA Technical Blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2271444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux部署web项目【保姆级别详解,Ubuntu,mysql8.0,tomcat9,jdk8 附有图文】

文章目录 部署项目一.安装jdk1.1 官网下载jdk81.2 上传到Linux1.3 解压1.4 配置环境变量1.5 查看是jdk是否安装成功 二.安装TomCat2.1 官网下载2.2 上传到Linux2.3 解压2.4配置2.5 启动Tomcat2.6 验证是否成功 三.安装mysql四.部署javaweb项目4.1 打包4.2 启动tomcat 部署项目 …

unity中的UI系统---GUI

一、工作原理和主要作用 1.GUI是什么&#xff1f; 即即时模式游戏用户交互界面&#xff08;IMGUI&#xff09;&#xff0c;在unity中一般简称为GUI&#xff0c;它是一个代码驱动的UI系统。 2.GUI的主要作用 2.1作为程序员的调试工具&#xff0c;创建游戏内调测试工具 2.2为…

MySQL 【多表查询】

一 . 概述 多表关系&#xff1a; 一对多(多对一) &#xff0c; 多对多 &#xff0c;一对一 1&#xff09; 一对一 案例: 用户 与 用户详情的关系 关系: 一对一关系&#xff0c;多用于单表拆分&#xff0c;将一张表的基础字段放在一张表中&#xff0c;其他详情字段放在另 一张表…

【大模型】ChatGPT 数据分析与处理使用详解

目录 一、前言 二、AI 大模型数据分析介绍 2.1 什么是AI数据分析 2.2 AI数据分析与传统数据分析对比 2.2.1 差异分析 2.2.2 优劣势对比 2.3 AI大模型工具数据分析应用场景 三、AI大模型工具数据分析操作实践 3.1 ChatGPT 常用数据分析技巧操作演示 3.1.1 快速生成数据…

【面试系列】深入浅出 Spring Boot

熟悉SpringBoot&#xff0c;对常用注解、自动装配原理、Jar启动流程、自定义Starter有一定的理解&#xff1b; 面试题 Spring Boot 的核心注解是哪个&#xff1f;它主要由哪几个注解组成的&#xff1f;Spring Boot的自动配置原理是什么&#xff1f;你如何理解 Spring Boot 配置…

【Java项目】基于SpringBoot的【新生宿舍管理系统】

【Java项目】基于SpringBoot的【新生宿舍管理系统】 技术简介&#xff1a;本系统使用采用B/S架构、Spring Boot框架、MYSQL数据库进行开发设计。 系统简介&#xff1a;管理员登录进入新生宿舍管理系统可以查看首页、个人中心、公告信息管理、院系管理、班级管理、学生管理、宿舍…

【AI学习】Transformer深入学习(二):从MHA、MQA、GQA到MLA

前面文章&#xff1a; 《Transformer深入学习&#xff08;一&#xff09;&#xff1a;Sinusoidal位置编码的精妙》 一、MHA、MQA、GQA 为了降低KV cache&#xff0c;MQA、GQA作为MHA的变体&#xff0c;很容易理解。 多头注意力&#xff08;MHA&#xff09;&#xff1a; 多头注…

IP5385应用于移动电源快充方案的30W到100W大功率电源管理芯片

英集芯IP5385一款专为智能手机&#xff0c;平板&#xff0c;移动电源&#xff0c;手持电动工具等便携式电子设备提供快充解决方案的30W到100W大功率电源管理SOC芯片。集成了快充协议芯片、MCU、同步升降压控制器等多种功能于一个封装内部&#xff0c;有效减小了整体方案的尺寸。…

信息科技伦理与道德1:研究方法

1 问题描述 1.1 讨论&#xff1f; 请挑一项信息技术&#xff0c;谈一谈为什么认为他是道德的/不道德的&#xff0c;或者根据使用场景才能判断是否道德。判断的依据是什么&#xff08;自身的道德准则&#xff09;&#xff1f;为什么你觉得你的道德准则是合理的&#xff0c;其他…

.Net加密与Java互通

.Net加密与Java互通 文章目录 .Net加密与Java互通前言RSA生成私钥和公钥.net加密出数据传给Java端采用java方给出的公钥进行加密采用java方给出的私钥进行解密 .net 解密来自Java端的数据 AES带有向量的AES加密带有向量的AES解密无向量AES加密无向量AES解密 SM2(国密)SM2加密Sm…

西安电子科技大学初/复试笔试、面试、机试成绩占比

西安电子科技大学初/复试笔试、面试、机试成绩占比 01通信工程学院 02电子工程学院 03计算机科学与技术学院 04机电工程学院 06经济与管理学院 07数学与统计学院 08人文学院 09外国语学院 12生命科学与技术学院 13空间科学与技术学院 14先进材料与纳米科技学院 15网络与信息安…

服务器信息整理

文章目录 引言I BIOS时间Windows查看BIOS版本安装日期linux查看BIOS时间II 操作系统安装日期LinuxIII MAC 地址IV 设备序列号Linux 查看主板信息引言 信息内容:重点信息:用途、操作系统安装日期、设备序列化、IP、MAC地址、BIOS时间、系统 Linux查看工具:ifconfig、宝塔运维…

关于PINN进一步的探讨

pinn 是有监督、无监督、半监督&#xff1f; PINN&#xff08;Physics-Informed Neural Networks&#xff0c;物理信息神经网络&#xff09;通常被归类为一种有监督学习的方法。在PINN中&#xff0c;神经网络的训练过程不仅依赖于数据点&#xff08;例如实验观测数据&#xff0…

Linux-Ubuntu之I2C通信

Linux-Ubuntu之I2C通信 一&#xff0c;I2C通信原理1.写时序2.读时序 二&#xff0c;代码实现三&#xff0c;显示 一&#xff0c;I2C通信原理 使用I2C接口驱动AP3216C传感器&#xff0c;该传感器能实现两个效果&#xff0c;一个是感应光强&#xff0c;另一个是探测物体与传感器…

Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】

随着城市化进程的快速推进&#xff0c;城市高层建筑不断增多&#xff0c;对建筑质量的要求也在不断提高。建筑外墙检测&#xff0c;如平整度和垂直度检测&#xff0c;是衡量建筑质量的重要指标之一。传统人工检测方法不仅操作繁琐、效率低下&#xff0c;还难以全面反映墙体的真…

主机A与主机B建立TCP连接的三次握手过程

&#xff08; 1 &#xff09;主机 A 的 TCP 向主机 B 发出连接请求 SYN 报文段&#xff08;第一次握手&#xff09;。&#xff08; 1 分&#xff09; &#xff08; 2 &#xff09;一旦包含 SYN 报文段的 IP 数据报到达主机 B &#xff0c; SYN 报文段被从数据报…

【GUI-pyqt5】QObject类

1. QObject模块详解 1.1 描述 所有Qt对象的父类 1.2 功能和作用 1.2.1 对象名称和属性 1.2.1.1 API API功能备注 setObjectName("唯一名称") 给一个Qt对象设置一个名称 一般这个名称是唯一的&#xff0c;当做对象ID来使用 objectName() 获取一个对象名称 - set…

C++Primer 变量

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

VScode怎么重启

原文链接&#xff1a;【vscode】vscode重新启动 键盘按下 Ctrl Shift p 打开命令行&#xff0c;如下图&#xff1a; 输入Reload Window&#xff0c;如下图&#xff1a;

(leetcode算法题)382. 链表随机节点

如果给你一个 智能记录 k行内容的小笔记本&#xff0c;从一本你也不知道有多少行的 C Primer 中进行摘抄&#xff0c;你应该怎么做才能让抄写的时候能让书中的每一行都等概率的出现在小笔记本中&#xff1f; 答&#xff1a;准备好一个公平的轮盘和一个巨大的摇奖机&#xff0c…