在当今数据驱动的世界中,大型语言模型正在革新我们与技术的互动方式。这些模型的背后,隐藏着一个复杂而精密的基础设施,正是它支撑着这些智能奇迹的诞生。详细介绍大模型基础设置的搭建说明非常少,这篇文章将带领大家深入探索这个神秘的世界,揭示如何从裸机开始,一步步构建起一个强大的,可以完成70B参数大模型训练的基础设施。
翻译自“From bare metal to a 70B model: infrastructure set-up and scripts”
原文地址:
https://imbue.com/research/70b-infrastructure/
介绍
在几个月的时间里,我们与一小群研究人员和工程师一起,在我们自己的基础设施上从头开始训练了一个 70B 参数模型,该模型在推理相关任务上的表现优于零样本 GPT-4o。
今天,我们将分享一个用于设置所需基础设施的端到端指南:从启动初始集群和安装操作系统,到自动从训练期间遇到的错误中恢复。在每个步骤中,我们都会详细说明我们遇到的挑战以及我们如何解决这些挑战。除了我们的经验之外,我们还发布了许多为确保主机健康而开发的基础设施脚本,以便其他团队可以更轻松地为自己的模型训练创建稳定的基础设施。
除了我们的详细流程之外,我们还发布了:
- 主机级健康检查:确保给定主机不存在已知错误的脚本 (https://github.com/imbue-ai/cluster-health/tree/master/health_checks)
- NVIDIA Collective Communication Library (NCCL) 补丁,可改善错误和停顿的日志记录
- 压力测试,确认 GPU 能够分配大张量并执行标准操作 https://github.com/imbue-ai/cluster-health/tree/master/gpu_stress_test
- 网络测试,检查给定机器上的 GPU 是否能够相互通信(通过 NVLink)以及与其他机器上的 GPU 通信(通过 InfiniBand)https://github.com/imbue-ai/cluster-health/tree/master/host_validation
- 解析 Unified Fabric Manager (UFM) 事件日志、检查相关事件并确定应禁用哪些网络端口的脚本 https://github.com/imbue-ai/cluster-health/tree/master/ufm_events
- 为 InfiniBand 结构生成全面的老化工作负载的脚本,旨在测试每个可用链接 https://github.com/imbue-ai/cluster-health/tree/master/ib_burn
在整个过程中,我们的工程团队成员与Voltage Park 的合作伙伴合作,准备集群以供生产使用。完整流程涉及:
- 配置单独的机器
- 配置 InfiniBand
- 确保机器完全健康
- 诊断常见培训问题
- 改进基础设施工具
下面更详细地描述每个步骤。
背景:这应该如何运作
我们计算的目的是实现大规模语言模型的快速实验。为此,我们需要大量能够高速相互通信的快速 GPU。
本文重点介绍一个集群,该集群拥有分布在 台计算机上的 4, 个 H100 GPU,其中一台计算机有 8 个 GPU。有 台计算机配备 GPU,因为需要为管理 InfiniBand 网络的 Unified Fabric Manager 节点保留一些连接。在配备 GPU 的 主机上,每个 GPU 直接连接到 ConnectX-7 卡,该卡可以通过自己的 ConnectX-7 卡以 Gbps 的速度同时向 InfiniBand 网络上的任何其他 GPU 进行传输和接收。
我们的 InfiniBand 网络拓扑被称为“完全无阻塞(fully non-blocking)”,因为理论上每个 GPU 都可以以最大速率同时与另一个 GPU 通信。这是通过三层 InfiniBand 网络架构实现的:三层 InfiniBand 交换机在正确连接时,可以在整个网络上实现这种高水平的吞吐量。请参阅下文了解 InfiniBand 网络的概述:
请注意,训练网络的通信是通过 InfiniBand 进行的,而不是通过以太网进行的。虽然这些机器也连接到以太网,但该网络用于传输数据集、检查点和其他数据。通过以太网发送数据的速度会慢得多,因为数据首先从 GPU 传输到 CPU,然后从其中一张 Gbps 以太网卡发出。虽然可以使用名为RDMA over Converged Ethernet (RoCE) 的技术通过以太网进行训练,但这需要在硬件和软件方面进行大量额外工作,并且通常不如 InfiniBand 可靠(请参阅此概述了广泛过程的论文)。
还有一个纯粹用于配置和管理的辅助以太网,支持访问基本输入/输出系统 (BIOS) 的控制器接口、电源和其他低级机器接口。如果没有这个管理网络,我们将不得不使用 USB 驱动器、键盘和显示器手动设置节点,这对于数百台机器来说并不是不可持续的方法。
使用我们的集群进行高性能训练意味着每个组件(InfiniBand、以太网、GPU 和节点本身)都必须近乎完美地工作。如果 , 多个连接中哪怕只有一个连接有点不稳定,都可能会减慢整个训练运行的速度。
这篇文章的其余部分详细介绍了实际达到一切完美状态并确保保持这种状态的过程。
流程:如何从裸机过渡到完全运行的集群
配置单独的机器
通过管理网络与集群建立初始以太网连接后,我们获得了基板管理控制器 (BMC) 的访问凭据。BMC 是一种专门的服务处理器,用于远程监控主机系统,通常连接到单独的网络。它使我们能够与每台机器进行交互,就好像我们亲自在场一样,并为硬件健康状况、BIOS 设置和电源管理提供了额外的 API。
这些组件就位后,我们就卷起袖子开始设置集群。
第 0 步:配置一台机器
我们首先使用 iDRAC(戴尔的底板管理控制器)在一台服务器上安装 Ubuntu ,该服务器将用于设置其他所有内容。除此之外,iDRAC 允许我们通过浏览器中提供的虚拟控制台从本地计算机安装和启动 ISO 映像。理想情况下,这是此过程中唯一的手动安装。
第 1 步:在每台机器上安装操作系统
在处理了零号病人后,我们继续安装了 Ubuntu 的 Metal-as-a-Service (MAAS) 软件来帮助配置其余的服务器。使用预启动执行环境协议 (PXE) 引导和自动化的 iDRAC 工具,我们指示每台机器从网络引导,并配置 MAAS 以响应 PXE 引导请求。在执行初始网络引导时,服务器通过动态 IP 分配协议 (DHCP) 从 MAAS 接收 IP 和初始内核,而不需要在本地驱动器上安装任何东西。这种精简环境被自动用于执行持久的操作系统安装。理论上,我们只需等待第一次引导,一切都会被处理好。然而,实际上,MAAS 与 BMC 的集成并不可靠,因此我们使用 iDRAC API 预先收集每台机器的 MAC 地址(唯一的物理硬件标识符)。
在整个培训过程中,MAAS 通常是堆栈中可靠的组件。然而,我们在开始时遇到了一些特定于我们设置的困难。例如,在最初的几次配置中,时钟偏差如此之大,以至于 HTTPS 证书验证问题阻止了通过 apt 安装任何东西。同样,因为 MAAS 服务器必须负责许多职责(DHCP 服务器、主机名到 IP 解析的 DNS 服务器、主机和官方 Ubuntu 包服务器之间的 HTTP 代理、NTP 服务器、cloud-init 配置管理以及连接 MAC 地址到 IP 到主机名到自定义元数据的基准数据库),我们难以追踪问题的根本原因。此外,还有 MAAS 配置生命周期的学习曲线,因为它被设计用于处理管理全新部署以及节点的逐步迁移和各种调试/不健康的中间状态的复杂性。
第 2 步:诊断损坏的机器
在设置大型 GPU 集群时,我们发现大约 % 的机器无法启动,主要是由于服务器的物理问题。我们遇到的一些问题包括:未连接或接线错误的以太网电缆、iDRAC 的硬件问题、损坏的电源单元、坏的 NVME(非易失性内存快车)驱动器、缺少的内部电缆以及无法显示的网络卡或 GPU。我们自动检查这些问题,将一些机器返还给戴尔进行重新测试,并为数据中心工作人员提交了适当的工单。自己动手设置集群的一个好处是,我们能够立即使用健康的机器,同时等待其他机器的维护。
第 3 步:最小(可行)可观测金属
我们在每台服务器上设置了以下内容:
- Docker(用于更轻松地运行服务和训练作业)
- 数据中心 GPU 驱动程序
- Prometheus 节点导出器(用于导出稳定的硬件/操作系统指标流)
- DCGM 导出器(来自 NVIDIA 的额外指标,用于 GPU 状态/时钟/利用率)
- 所有非操作系统驱动器上的 RAIDZ ZFS 池(这使得机器能够在一个驱动器故障时继续运行,还提供透明压缩功能,对于纯文本数据集和重复日志特别有用,通常使我们能够使用比平时多约 倍的空间)
然后我们运行基本的 GPU 诊断,以确定 GPU 是否大部分功能正常——那些不正常的通常会在几个小时内出现硬件问题。
在此期间,当我们尝试并行安装所有 个节点的软件包时,遇到了一些带宽瓶颈。这也是我们第一次在数据中心部署的各个组件上收到高温警报。第一批热量问题主要通过固件更新得到了缓解。
第四步:单节点GPU训练
下一步是确保每台机器都能独立处理真实的 GPU 工作负载。由于一些问题,许多人无法做到:
- 与 GPU 相关的错误,大多是通过将卡重新插入插槽来修复的:将 磅重的服务器从机架中物理滑出,拆下盖子和 GPU 之间的所有电缆,然后取出 GPU 并将其放入在更换所有电缆并重新安装服务器机架之前再次执行此操作。
- 根据 Ubuntu 服务器日志,GPU 和外围组件互连 Express (PCIe) 总线或网卡之间的许多电线报告“limited width: x4 < x16” 。更新 PCIe 交换机总线固件后,我们发现集群中大约四分之一的主机需要重新安装内部 PCIe 电缆 - 可能是因为相当脆弱的电缆位于外壳和 GPU 之间,这意味着它们会损坏每当有人想要对 GPU 进行维护时,就会被推挤或拔掉插头。
- 许多杂项故障影响了个位数的主机。戴尔通过固件升级帮助我们修复了这些问题:
- NVMe 驱动器没有显示故障,但在被触碰时锁住了整台机器。
- 硬盘在 Linux 下随机显示顺序,这使得 MAAS 产生混乱,并导致操作系统安装在错误的驱动器上。
- 错误的温度读取导致风扇一直以 % 的速度旋转。这部分是由于 NVIDIA 驱动程序问题,我们通过降级到以前的驱动程序版本解决了这个问题。
- CPU 的动态频率缩放失控,将活动核心限制在 2 GHz。
- 直接 GPU-GPU 通信(GDR 或 GPUDirect RDMA Peer Memory Client)无法成功应用。
配置 InfiniBand
第0步:安装UFM
InfiniBand的一个优势是其集中式设计,它为整个网络提供了一个大脑。因此,我们只需要处理织物中的个网络交换机中的一个实体。我们的第一项任务是找出哪个交换机连接到哪些机器,然后将其与布线图进行关联,并按其物理位置重命名交换机。
第1步:重新布线
最初,UFM无法检测到个网络交换机,更不用说织物中预计存在的所有主机了。与数据中心的合作伙伴协商后,我们确认交换机已通电并接线,但仍无法检测到。检查网络布线列表后,我们发现织物的顶层设计有误:我们有八个不相连的网络,而不是一个统一的织物,没有共同的路由路径。重新布线后,我们添加了检查,以验证所有物理连接是否与新设计一致。
第2步:一万个温度警报
解决物理布线问题后,UFM成功与织物中的所有InfiniBand交换机建立了联系。然而,几乎每个交换机端口都开始报告温度过高,有时甚至超过摄氏度,尽管它们还没有传输数据。我们发现问题在于同一网络机架内的交换机之间存在空隙,导致热空气回流到前面。我们的数据中心合作伙伴帮助我们迅速诊断并制定了合适的解决方案。
第3步:个警报
许多端口还显示出高错误率或在工作和故障状态之间波动,称为“flapping”。这些问题仅在端口被积极使用时才会出现,因此预先检测非常困难,因为整个织物由个链接组成,并且具有高度冗余性。我们的数据中心合作伙伴帮助清洁并重新插入警报端口,同时我们禁用了其余的警报收发器,并等待更换。
尽管InfiniBand对硬件故障具有很高的弹性,但一旦约%的织物开始出现问题,自适应路由等功能就无法可靠地工作,以应对随意丢失的链接。
在此期间,我们设法进行了到台机器的多节点训练运行。我们的过程基本上是即兴的:有时我们会在一组随机节点上启动,观察它们的性能,并尽量在尽可能多的这些节点上继续运行。这种方法使我们能够找到InfiniBand织物中可靠的子集,但很棘手,因为每次我们更改用于训练的节点集时,默认的InfiniBand链接集也会更改。
第4步:燃烧吧InfiniBand,迪斯科地狱
为了更有效地诊断InfiniBand问题,我们为整个集群设计了一种专门的工作负载,重点是在整个织物的每个端口同时推动尽可能多的数据。这与在整个集群上运行一个大型all-reduce工作负载不同,后者将利用NCCL在单个节点内优化通信,使GPU通过Server PCIe Module (SXM)插槽使用NVLink进行通信。
相反,我们选择了一种蛮力方法,并取得了显著成功。UFM开始发送警报,指出大多数端口的数据传输超过理论容量的%,有些交换机暂时崩溃。最终所有端口都被认为足够强大,可以继续操作,而其余的端口则被禁用或交给后续维修。
第5步:GPUDirect RDMA
为了使GPU能够进行通信而不产生CPU开销,我们启用了名为GPUDirect RDMA的功能,允许直接与InfiniBand网卡通信。这涉及两个关键步骤:
- 启用额外的内核模块
- 确保禁用PCIe访问控制服务(ACS)以防止立即挂起
第6步:扩大黄金服务器集
对于使用最新硬件的GPU集群,有一个经验法则:每周大约有3%的机器会出现故障。
然而,有一个关键的细微差别经常被忽视:并不是每台机器都有均匀的3%故障概率,而是少数几台问题机器以不同的方式反复出现故障,直到它们被正确修复。这突显了在同一织物上拥有大量机器的优势。与其在大型训练运行中对随机机器进行打地鼠游戏,不如专注于扩大已知可靠的或“黄金”机器集。
第7步:维护
InfiniBand的维护主要涉及响应UFM警报、更换故障电缆和收发器,有时还需要诊断更难解决的错误,如故障交换机。大规模回归通常由两个因素引起:
- 固件升级,特别是仅应用于集群的一半时,可能会破坏UFM状态,导致需要在所有InfiniBand交换机上重启UFM。
- 同时大规模重启GPU主机,可能会用更新淹没UFM状态,类似地需要重启UFM服务。
确保完全健康的机器
在这个过程中,我们发现了许多单独的机器可能失败或减慢训练运行的方式。许多这些故障模式并不立即显现,因此我们编写了许多健康检查来确定哪些主机足够健康以用于训练。我们在此发布了这些代码。
请注意,许多这些健康检查是特定于我们的运行时环境的,不一定与基础硬件有关,或者是极其琐碎的修复或自动化。这是有意为之的:为了使我们的机器准备好进行训练的总体目标,我们希望有一个单一的入口点来回答“是”或“否”,并且可以抽象掉任何数量的“琐碎”细节。
GPU健康检查
我们检查是否有正确数量的GPU,是否启用了ECC(错误校正码)检查,并且没有ECC错误。我们还检查了连接GPU之间的NVLink拓扑是否正常且无错误。
磁盘空间健康检查
我们检查主机的磁盘空间利用率不超过%。
Docker健康检查
我们检查Docker是否能够运行附有GPU的容器(即NVIDIA容器运行时是否正常工作),并且所有与监控/分析相关的Docker容器是否都处于活动状态并具有正确的主机权限。
Dmesg健康检查
我们检查dmesg中是否有硬件Xid或SXid错误(由NVIDIA GPU或GPU之间的NVIDIA交换机抛出的故障)。我们还读取所有dmesg日志行,以验证它们是否都可以分类为“常见/预期的日志行”。
iDRAC健康检查
我们检查主机上的iDRAC错误,忽略非致命的错误消息。这是我们戴尔机器特有的,不是我们开源的健康检查的一部分。
磁盘健康检查
我们检查zpool是否已挂载,Docker是否正确连接到它,并且可以实际使用而不会导致CPU锁定。
InfiniBand健康检查
我们检查是否存在增加的InfiniBand错误率和/或过时的驱动程序固件。
Nvlink健康检查
我们检查主机上的NVLink错误。根据经验,这似乎不会导致训练失败,但可能会导致速度变慢。
GDR健康检查
我们检查主机是否启用了GDR。
VBIOS健康检查
我们检查GPU的VBIOS版本以及H100基板固件是否为最新。
Flint健康检查
我们使用flint和hca_self_test检查是否拥有正确版本的Mellanox OFED驱动程序、卡固件和收发器固件,并且它们是否正确地与NVIDIA驱动程序编译。
PSB健康检查
我们查询PCIe设备,检查连接速度和宽度是否符合我们在GPU、PSB(PCIe交换总线)和网络卡之间的预期。我们还检查交换机固件是否为当前版本。此脚本由戴尔开发,而非Imbue,因此我们目前无法共享。
除了这些快速健康检查外,我们还有一些更复杂的健康检查,包括:
- 通过PyTorch初始化矩阵计算并测量NVLink带宽、GPU计算速度和内存。我们设置了适当的GDR标志,以测试InfiniBand和NVLink。
- 使用ib_write_bw和–use_cuda通过IB卡发送数据,并测量PCIe和InfiniBand卡带宽。我们运行了较长时间(约分钟),以确保捕获到不稳定的InfiniBand链接。
- 运行多节点诊断运行,以检查NCCL初始化能力及其是否会随机停止。如果停止,我们的NCCL代码分支会添加额外的日志记录。检测问题可能需要到小时,因此我们通常仅对新节点或怀疑有问题时运行此程序。
- 检查DCGM导出的任何GPU时钟节流事件(不包括预期的gpu_idle和power_cap)。同时锻炼所有GPU、InfiniBand卡、CPU和磁盘的多节点训练是锻炼这些功率事件的最佳方式。
诊断常见训练问题
硬件问题导致的典型NCCL错误包括:
- 由于某些节点的GPU间通信无法进行NCCL初始化,因此错误消息可能会提到卡上的某些GPU超时。解决此问题的最常见方法是更换问题节点,并重启NCCL会话。
- 如果GDR硬件有问题,可能会出现NCCL hanging(暂停)或性能下降。
- 由于NCCL使用GPU内存进行通信,因此任何内存硬件问题都会导致NCCL错误或性能下降。
调试这些问题的方法之一是运行带有适当日志记录的NCCL测试工作负载,并查找错误或挂起点。
启动时崩溃
在某些方面,这是最容易处理的错误,因为理论上它是容易重现和迭代的。
我们首先检查是否在正确的版本、配置和环境变量下运行代码。虽然这很基础,但我们发现确保启动训练是可重现且易于检查的至关重要,尤其是像Docker镜像缓存或不透明的秘密配置这样的中间抽象可能会让问题复杂化。
我们进行的另一个基本检查是确保所有机器都在线,并且可以轻松聚合和检查生成的堆栈跟踪或日志。我们使用了Loki、Prometheus和Grafana栈,但任何合适的日志聚合或跟踪SaaS都是适用的。由于这些运行是同步和分布式的,通常第一个触发的错误会导致一连串不相关的错误。在这里,健康检查也有助于即时检测明显的问题,例如硬盘损坏或GPU缺失或无效。
我们构建了一个在失败时自动重新启动的系统,这使得日志和错误聚合更加重要,以避免混淆来自不同重启的错误。我们遇到的一些常见错误包括:
- 错误如“各个等级的前向顺序不同:等级0正在全聚合个参数,而等级正在全聚合1个参数”。我们发现这是PyTorch全分片数据并行(FSDP)实现的一个怪癖,可以通过重新启动解决。
- GPU内存不足(OOM)错误,看起来像“CUDA内存不足。尝试分配...”。我们通过仔细检查配置和代码,并撤销任何可能导致GPU#0额外利用的不当PyTorch设备指定的最近代码更改来修复这些错误。
- CPU/RAM内存不足(OOM)错误,这些错误从错误日志中不容易发现,通常最好通过Docker容器外的主机的dmesg日志检测。我们主要通过dmesg日志中的CalledProcessError或ConnectionError来看到这些错误,当一个派生进程或网络对等体被OOM Killer调用收割时。我们更倾向于在检测到dmesg中的OOM Killer调用时仅失败健康检查并重新启动主机。我们还检查了代码路径是否有足够的手动垃圾收集量(参见以下关于如何禁用它的部分),并且不会意外地尝试在CPU上进行计算或移动张量。
训练中途崩溃
首先要做的是自动化系统以重新运行所有诊断健康检查(参见前几部分),然后在没有不健康主机的情况下自动重启运行。我们遇到了一些随机硬件故障,包括Xid和SXid错误,这些错误可能会在不发出有意义的Python堆栈跟踪的情况下使运行崩溃。有些实例(如行重映射)可以通过重启恢复。其他实例(如不可纠正的ECC错误)通常需要硬件维护或更换部件。
此外,我们观察到由特别畸形的训练数据引起的崩溃。例如,语料库中的单个非常大的文档可能会在GPU或CPU中引起OOM错误。为防止这些错误,我们有一个完全确定性的数据加载器,这使得每次崩溃都可以通过与epoch或步骤编号的相关性轻松重现。我们发现禁用数据加载或替换假数据(如全零)来确认数据是否确实是根本原因是有帮助的。
最后,通过任何首选的指标聚合方法记录网络和一般节点健康统计信息也是有帮助的。像以太网短暂中断或磁盘空间不足等问题可能不会显示为有用的错误消息,但可以通过收集的数据轻松关联。
没有堆栈跟踪信息的挂起(可能会在超时后出现)
这类错误由于缺乏有用的信息并且通常难以可靠重现,调试起来非常令人沮丧。
最令人印象深刻的类型以如下错误消息为特征:
css
复制代码
Watchdog caught collective operation timeout: WorkNCCL(SeqNum=, OpType=_ALLGATHER_BASE, ... , Timeout(ms)=) ran for milliseconds before timing out
这些错误消息会同时出现在训练运行中的所有GPU工作节点上。
这意味着一个或多个主机未能完成NCCL操作,甚至从NCCL和InfiniBand连接中崩溃,导致所有其他主机在特定张量操作上同步阻塞,直到达到NCCL_TIMEOUT。不幸的是,NCCL库的性质使得很难找到哪个特定主机是罪魁祸首。
我们对NCCL库进行了日志记录更改(参见我们的分支)以更好地显示崩溃时正在进行的消息或操作,从而识别出似乎阻止运行的主机或GPU。
请注意,为了识别行为不当的主机,我们通常需要找出哪些主机没有生成某些日志消息。缺少这些消息表明该主机上的工作节点是滞后的或已崩溃。
其他没有有用错误消息的不响应实例通常与硬件相关问题有关,例如上述Xid/SXid/ECC错误导致NVIDIA驱动程序或NVIDIA docker通信驱动程序锁定。为了区分NCCL挂起和驱动程序挂起以及Python代码中的竞争条件或死锁,我们使用了包括Py-Spy和GNU Project Debugger (GDB)在内的工具来实时调试遇到的停滞进程。通过这种方法,我们抓住了一个特定问题,由于Python线程设置中的配置错误,我们无法在某些主机上正确启动八个多线程NCCL GPU进程,这些主机在PyTorch初始化代码之前的某个阶段遇到了竞争条件。
训练速度减慢(以 MFU 衡量)
缺乏仪器可能会使这些类型的问题比前一类问题更加令人沮丧。除了突破 Py-Spy、堆栈跟踪检查和 GDB 之外,我们还推出了 NVIDIA Nsight 和分析工具来提供帮助,其中一些工具在高度分布式设置中很难使用。
遗憾的是,普遍的速度下降或低于之前演示的模型失败率利用率 (MFU) 可能是由多种原因引起的。
首先,事实证明,仔细检查配置、代码和环境变量很有帮助。我们经历过运行错误的模型、错误的批量大小、错误的 UFM 或 NCCL 设置、错误的
CUDA_DEVICE_MAX_CONNECTIONS,所有这些都会导致性能不佳。
我们还发现测量瞬时(即每批次)MFU 而不是平滑或窗口平均值很有用,因为 MFU 曲线的预平滑形状通常可以帮助我们诊断问题类别。问题包括:
训练立即以极低的 MFU(低于预期的 1/)开始并保持稳定
这通常是 InfiniBand 网络的硬件问题,例如 T2 或 T3 层的死交换机。它也可能是由 GPU 和 NIC 之间的硬件问题引起的,在 dmesg 中显示为PCIe x16 lanes limited by …
训练立即以预期 MFU 的 % 开始并保持稳定
这可能是由于一台主机的 GDR(NVIDIA 对等内存)设置不正确或 GDR 环境变量不正确造成的。
训练立即开始,约为预期 MFU 的 %,并保持稳定
最常见的是,这是由 InfiniBand 链路降级或故障引起的,特别是如果单个特定 GPU 的关联 InfiniBand NIC 出现故障,导致 NCCL 尝试通过本地 NVLink 路由流量并使用同一主机上另一个 GPU 上的 NIC。它还可能是由 CPU 节流引起的,这需要针对特定?主机调整一些 BIOS 设置。
定期发生的单批次突然大幅下降( 倍)
这几乎肯定与检查点或评估有关——可以通过检查纪元或步数来验证。令人烦恼的是,如果设置自动警报只是为了触发 MFU 异常,这会导致许多误报。
单批次突然急剧下降( 倍),这种情况随机发生且相当罕见(大约每 分钟一次),但随后立即完全恢复到良好的 MFU
这似乎最常见是由运行中的一台主机上安排的其他 CPU 密集型工作负载引起的。我们发现通过 PID 粗略地监控 CPU 使用情况更容易,而不是构建分析工具来识别特定主机。这也可能是由于网络偶尔较差造成的,例如数据加载器瓶颈。我们使用了指标监控,并为数据加载、检查点和任何非 NCCL 代码添加了 Python 代码计时日志,事实证明这非常可靠。
MFU 图在运行过程中逐渐下降,但在重新启动后恢复到 %
从理论上讲,这可能是由开关上的热量积聚引起的,但我们从未见过这种情况。相反,我们使用 Python 和 NVIDIA 分析器来确定性能下降似乎是自动垃圾收集的结果。
在调试这些减速过程时,我们注意到吞吐量周期性下降的模式几乎是确定性的。随着训练的进行,下降对分布式操作的影响逐渐增大。这导致了一个假设,即下降可能与自动垃圾收集有关,我们通过分析和测试验证了这一点。一旦我们禁用自动垃圾收集并在所有主机上按特定时间间隔进行计划垃圾收集,这些吞吐量“下降”就消失了。
我们使用了基于ZeRO-3的同步分布式训练算法 FSDP 。在阻塞操作期间,运行垃圾收集的单个工作进程可能会减慢所有其他工作进程的速度。对于数百个工作进程,这可能会导致速度显着下降。
开始时性能良好,然后突然下降(达到预期的 %),并且持续高频率(每 秒)
我们观察到这与 NVIDIA GPU“时钟节流原因”相关,我们通过对 NVIDIA DCGM 应用正确的设置来收集这些原因。热量问题(GPU 温度或主机冷却风扇损坏/性能下降)或电源故障导致了这种情况。此外,当我们同时最大化所有 8 个 GPU 利用率和 8 个 NIC InfiniBand 利用率以及 CPU/RAM/磁盘时,我们的一些具有特定电源硬件的主机会出现电压问题,但仅当所有这些都被使用时 - 通常仅在实际训练运行。
性能良好,但比平时“噪音更大”(高频白噪声方差在预期 MFU 的 % 到 % 之间)
这也与 InfiniBand 硬件相关,但通常是由于网络中较高层而不是冗余度较低的主机到 T2 层的链路适度降级或抖动所致。
不幸的是,其中许多问题并不容易确定到特定主机,而且由于 InfiniBand 交换机技术具有拓扑感知特性,与 InfiniBand 相关的问题尤其难以确定。InfiniBand 似乎更喜欢 InfiniBand 胖树设计中的相邻主机,并且 UFM 可能会以导致不对称链路速度的方式路由数据包。
以下是用于调试吞吐量回归的快速摘要/流程图/健全性检查表:
- 它曾经有效吗?
- 您最近是否更改过某些内容(例如合并代码、更新驱动程序)?
- 您是否在健康的主机上运行?您的所有依赖服务是否都在运行,包括第三方 SaaS,例如 Docker Hub、GitHub 或您的堆栈依赖的任何其他服务?
- 您确定您使用了与上次完全相同的代码、环境、配置、版本、主机列表、排名顺序、随机种子(如果可能)吗?
- 它可以重现吗?
- 它与其他什么相关吗?其他流程?每日定时任务?主机、DCGM 或 UFM 指标?
- 您衡量指标的工具正确吗?
- 运行减少的代码(较小的模型、伪造的数据、没有检查点保存或加载)时,问题是否仍然出现?
改进基础设施工具
完成上述步骤后,人们在训练模型时可以获得良好的性能……至少在出现不可避免的故障之前是这样。
在本节中,我们将介绍一些不同的工具和系统,这些工具和系统是为了确保训练继续顺利进行,理想情况下需要最少的人为干预。因为我们是一个小团队,所以我们根本没有足够的人员来不断进行手动修复,因此我们尝试尽可能多地实现流程自动化。
我们几乎所有的训练运行问题都可以追溯到有故障的机器或网络组件。这些故障在大型集群中经常发生,因此必须自动化禁用故障机器和网络组件并请求修复的过程。
机器故障
我们开发了一个系统,可以从最近的检查点自动重新启动崩溃的运行。重新启动过程将首先在每台可用机器上运行运行状况检查,并根据每台机器通过的运行状况检查对机器的运行状况进行分类;然后它会尝试在最健康的机器上重新启动训练工作。
网络组件故障
我们观察到的所有网络组件故障均由 UFM 检测到并注册在 UFM 事件日志中,因此响应网络组件故障只需解析 UFM 日志并针对每个事件采取适当的操作即可。
UFM事件系统相当复杂,包含数十种事件类型。然而,在实践中,我们发现只有少数事件存在问题,大部分与链接断开或符号错误计数较高有关。识别这些事件后,我们能够编写脚本来解析 UFM 事件日志、禁用最近事件中涉及的链接和端口、在这些网络组件上归档维护票据,并在维护完成后重新启用这些组件。
本地镜像文件系统
早期很明显,大型分布式训练运行的瓶颈之一是进出集群的以太网速度。如果数百名工作人员试图同时下载数据集和模型检查点,则带宽约为 10Gbit/s 的共享以太网连接很快就会饱和。
因此,我们决定在集群内构建一个本地文件系统来镜像云存储,并本质上充当缓存以减少我们需要从 S3 获取的文件数量。为了处理集群流失(机器通常会因维护原因而被禁用或更换),我们对每个文件进行了三倍复制,使用一致的散列以最小化流失期间文件移动的方式均匀分配负载。集群上有限的磁盘空间意味着我们还必须开发各种工具来跟踪文件生命周期并清除不再相关的文件。
本地分布式 Docker 注册表
我们还使用了Kraken,这是一款出色的开源软件,可以实现 Docker 镜像的点对点传输。我们几乎没有遇到任何问题,考虑到任务和实施的复杂性,这有点令人惊讶。
各种性能监控工具
我们设置了默认的 Torch 分析器以及 NVIDIA 的 Nsight 系统。后者有助于准确了解前向/后向传递和 NCCL 通信需要多长时间,以及确定我们是否因给定模型大小和工作人员数量的通信或计算而遇到瓶颈。然而,Nsight Systems 有点难以使用,因为它需要在特权模式下运行 Docker,禁用与性能监控事件相关的安全检查,并且保存配置文件通常需要停止整个训练过程。
此外,我们发现编写工具来检测缓慢的训练批次并了解缓慢的潜在原因很有帮助。其中最有用的是一个工具,它可以监视每个批次花费的时间,并在批次异常缓慢时转储每个工作人员的堆栈跟踪 - 这使得更容易识别具有细微硬件或软件问题的特定主机。
细分机器组以查明故障主机
在我们使用集群的最初几个月(当时我们的健康检查不像现在那么彻底),我们经常遇到这样的情况:在一组特定机器上运行的训练失败,但不清楚哪台机器是失败的有过错。为了查明有故障的主机,我们开发了一些工具,可以轻松地将一组机器划分为子集,并在每个机器子集上启动较小的作业。
例如,如果 台机器上的作业失败,我们将在 6 组(每组 8 台机器)上启动较小的运行,然后在 8 组(每组 6 台机器)上启动较小的运行。通常情况下,这两个阶段中的每一个阶段只有一次运行会失败,这使我们能够高度自信地得出结论,在两个阶段中都出现故障运行的机器是有问题的。
反思和学习
在建立和维护基础设施的过程中,我们收集了一些关于整个过程的有用知识:
- 能够互相交换机器是非常有用的。对于任何给定的训练运行,我们发现比运行所需的机器多 % 会很有帮助,这样我们就可以在机器故障时轻松重新启动。以每台机器都与其他机器紧密连接的方式设置集群网络意味着我们基本上可以使用机器的任何工作子集。
- 值得为您遇到的每种硬件或软件故障编写测试和自动化解决方案,因为训练期间遇到的每个问题都会再次出现。同样,对于每个不透明的错误消息,值得编写工具以使错误更易于解释。
- 可重复性是良好科学的关键。我们很快采用的一条规则是“一次只改变一件事”,即使是最简单的事情。
- 信任但要验证。每当我们在流程中引入外部工具或聘用新人员时,无论是外部还是内部,我们都会确保仔细检查他们的声明,特别是如果后续步骤取决于这些结果。
结论
训练大型语言模型需要复杂的基础设施才能开始。我们选择深入参与基础设施设置的细节,不仅因为我们相信充分了解我们使用的系统很重要,而且因为我们怀疑它最终会变得更加高效。现在,在完成了整个过程后,我们很高兴采用了这种方法 - 完全控制我们的基础设施并能够轻松调试每个抽象级别的问题至关重要。虽然这个过程需要大量的监督和迭代,但它使我们能够深入了解底层流程,构建一系列工具来确保主机健康,学习如何自动化系统以确保持续顺利的训练,
这个基础设施流程体现了我们研究和为人工智能代理构建坚实基础的方法:探究本质细节,不断改进现有流程,并构建有用的工具和系统,使我们斗志旺盛的团队能够应对更大的挑战。