AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


imbue:从裸机到70B模型-基础设施设置和脚本
发布日期:2024-09-03 09:16:56 浏览次数: 1620


    在当今这个数据驱动的时代,大型语言模型正不断革新我们与技术的交互方式。这些模型的背后,是一个复杂且精密的基础设施在默默支撑,它如同智能奇迹的摇篮。然而,关于如何搭建这样的大型模型基础设施的详细介绍却十分罕见。
    文章“From bare metal to a 70B model: infrastructure set-up and scripts”,将引领大家深入探索这一神秘领域,从裸机开始,一步步揭秘如何构建一个能够支撑70B参数级别大型模型训练的强大基础设施。

地址:https://imbue.com/research/70b-infrastructure/

时间:June 25, 2024

    In the span of a few months, with a small team of researchers and engineers, we trained a 70B parameter model from scratch on our own infrastructure that outperformed zero-shot GPT-4o on reasoning-related tasks.    Today, we’re sharing an end-to-end guide for setting up the required infrastructure……    Along with our detailed process, we are releasing:
  • Host-level health checks: scripts to ensure that a given host is free from known errors;
  • An NVIDIA Collective Communication Library (NCCL) patch that improves logging around errors and stalls;
  • A stress test to confirm that GPUs are able to allocate large tensors and perform standard operations;
  • Networking tests to check that the GPUs on a given machine are able to communicate with each other (via NVLink) and with GPUs on other machines (via InfiniBand);
  • A script which parses the Unified Fabric Manager (UFM) event log, checks for relevant events, and determines which network ports should be disabled;
  • A script which generates a comprehensive burn-in workload for InfiniBand fabrics, aiming to exercise every available link;

一 介绍
   在几个月的时间里,我们与一小群研究人员和工程师一起,在我们自己的基础设施上从头开始训练了一个 70B 参数模型,该模型在推理相关任务上的表现优于零样本 GPT-4o。
   今天,我们将分享一个用于配置所需基础设施的端到端指南:从启动初始集群和安装操作系统,到自动从训练期间遇到的错误中恢复。在每个步骤中,我们都会详细说明我们遇到的挑战以及我们如何解决这些挑战。除了我们的经验之外,我们还发布了许多为确保主机健康而开发的基础设施脚本,以便其他团队可以更轻松地为自己的模型训练创建稳定的基础设施。
  除了我们的详细流程之外,我们还发布了:
  • 主机级健康检查:确保给定主机不存在已知错误的脚本
    (https://github.com/imbue-ai/cluster-health/tree/master/health_checks)
  • NVIDIA Collective Communication Library (NCCL) 补丁,可改善错误和停顿的日志记录
  • 压力测试,确认 GPU 能够分配大张量(large tensors)并执行标准操作
    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。

    本文重点介绍一个集群,该集群拥有分布在 511 台计算机上的 4,088 个 H100 GPU,其中一台计算机有 8 个 GPU。有 511 台计算机配备 GPU,因为需要为管理 InfiniBand 网络的 Unified Fabric Manager 节点保留一些连接。在配备 GPU 的 511 主机上,每个 GPU 直接连接到 ConnectX-7 卡,该卡可以通过自己的 ConnectX-7 卡以 400 Gbps 的速度同时向 InfiniBand 网络上的任何其他 GPU 进行传输和接收。

    我们的 InfiniBand 网络拓扑被称为“完全无阻塞(fully non-blocking)”,因为理论上每个 GPU 都可以以最大速率同时与另一个 GPU 通信。这是通过三层 InfiniBand 网络架构实现的:三层 InfiniBand 交换机在正确连接时,可以在整个网络上实现这种高水平的吞吐量。请参阅下文了解 InfiniBand 网络的概述:

   请注意,训练网络的通信是通过InfiniBand进行的,而不是通过以太网进行的。虽然这些机器也连接到以太网,但该网络用于传输数据集、检查点和其他数据。通过以太网发送数据的速度会慢得多,因为数据首先从 GPU 传输到 CPU,然后从其中一张 100 Gbps 以太网卡发出。虽然可以使用名为RDMA over Converged Ethernet (RoCE) 的技术通过以太网进行训练,但这需要在硬件和软件方面进行大量额外工作,并且通常不如 InfiniBand 可靠(请参阅此论文https://arxiv.org/pdf/2402.15627)。

   还有一个单纯用于配置和管理的辅助以太网,支持访问基本输入/输出系统 (BIOS) 的控制器接口、电源和其他低级机器接口。如果没有这个管理网络,我们将不得不使用 USB 驱动器、键盘和显示器手动设置节点,这对于数百台机器来说并不是不可持续的方法。(这里所说就是BMC网络)

    使用我们的集群进行高性能训练意味着每个组件(InfiniBand、以太网、GPU 和节点本身)都必须近乎完美地工作。如果 12,000 多个连接中哪怕只有一个连接有点不稳定,都可能会减慢整个训练运行的速度。

    本文其余部分详细介绍了实际达到一切完美状态并确保保持这种状态的过程。

三 流程:如何从裸机过渡到完全运行的集群
1 主机单独配置
    通过管理网络与集群建立初始以太网连接后,我们获得了基板管理控制器 (BMC) 的访问凭据。BMC 是一种专门的服务处理器,用于远程监控主机系统,通常连接到单独的网络。它使我们能够与每台机器进行交互,就好像我们亲自在场一样,并为硬件健康状况、BIOS 设置和电源管理提供了额外的 API。
    这些组件就位后,我们就卷起袖子开始设置集群。
第 0/4 步:配置一台机器
   我们首先使用 iDRAC(戴尔的底板管理控制器)在一台服务器上安装 Ubuntu 22.04,该服务器将用于设置其他所有内容。除此之外,iDRAC 允许我们通过浏览器中提供的虚拟控制台从本地计算机安装和启动 ISO 映像。理想情况下,这是此过程中唯一的手动安装。
第 1/4 步:在每台机器上安装操作系统
    在处理完第0步后,我们继续安装了 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/4 步:诊断损坏的机器
    在设置大型GPU集群时,我们发现大约10%的机器无法启动,主要是由于服务器的物理问题。我们遇到的一些问题包括:未连接或接线错误的以太网电缆、iDRAC 的硬件问题、损坏的电源单元、坏的 NVME(非易失性内存快车)驱动器、缺少的内部电缆以及无法显示的网络卡或 GPU。我们自动检查这些问题,将一些机器返还给戴尔进行重新测试,并为数据中心工作人员提交了适当的工单。自己动手设置集群的一个好处是,我们能够立即使用健康的机器,同时等待其他机器的维护。
第 3/4 步:最小(可行)可观测金属
    我们在每台服务器上设置了以下内容:
(1)Docker(用于更轻松地运行服务和训练作业)
(2)数据中心 GPU 驱动程序
(3)Prometheus 节点导出器(用于导出稳定的硬件/操作系统指标流)
(4)DCGM 导出器(来自 NVIDIA 的额外指标,用于 GPU 状态/时钟/利用率)
    所有非操作系统存储驱动器(数据盘)配置RAIDZ ZFS 池(这使得机器能够在一个存储驱动器故障时继续运行,还提供透明压缩功能,对于纯文本数据集和重复日志特别有用,通常使我们能够使用比平时多约 10 倍的空间)
    然后我们运行基本的 GPU 诊断,以确定GPU是否大部分功能正常——那些不正常的通常会在几个小时内出现硬件问题。
   在此期间,当我们尝试并行安装所有 400 个节点的软件包时,遇到了一些带宽瓶颈。这也是我们第一次在数据中心部署的各个组件上收到高温警报。第一批热量问题主要通过固件更新得到了缓解。
第4/4步:单节点GPU训练
    下一步是确保每台机器都能独立处理真实的 GPU 工作负载。由于一些问题,许多人无法做到:
  • 与 GPU 相关的错误,大多是通过将卡重新插入插槽来修复的:将 200 磅重的服务器从机架中物理滑出,拆下盖子和 GPU 之间的所有电缆,然后取出 GPU 并将其放入在更换所有电缆并重新安装服务器机架之前再次执行此操作。
  • 根据 Ubuntu 服务器日志,GPU 和外围组件互连 Express (PCIe) 总线或网卡之间的许多电线报告“limited width: x4 < x16” 。更新 PCIe 交换机总线固件后,我们发现集群中大约四分之一的主机需要重新安装内部 PCIe 电缆 - 可能是因为相当脆弱的电缆位于外壳和 GPU 之间,这意味着它们会损坏每当有人想要对 GPU 进行维护时,就会被推挤或拔掉插头。
  • 许多杂项故障影响了个位数的主机。戴尔通过固件升级帮助我们修复了这些问题:
    • NVMe 驱动器没有显示故障,但一旦发生,可能导致整个设备故障。
    • 在Linux下,硬盘的盘符顺序随机显示,导致MAAS混淆,并使操作系统安装到了错误的驱动器上。
    • 温度读数错误,导致风扇始终以100%的速度旋转。部分原因是NVIDIA驱动程序存在问题,我们通过降级到之前的驱动程序版本解决了这个问题。
    • CPU的动态频率调整失控,活动核心被限制在2 GHz。
    • 无法成功应用GPU间直接通信(GDR,或GPUDirect RDMA对等内存客户端)。
2 配置InfiniBand
第0/7步:安装UFM
  InfiniBand的一个优势是它的集中式设计,因为整个网络只有一个“大脑”。因此,对于该结构中的320个网络交换机,我们只需处理一个实体。我们的首要任务是弄清楚哪台交换机连接到哪台机器,然后将其与布线图进行关联,并根据物理位置对交换机重新命名。
第1/7步:重新布线
    最初,UFM无法检测到320个网络交换机,更不用说结构中预期存在的所有主机了。在与我们的数据中心合作伙伴商议后,我们确认交换机已经通电并接入线路,但仍然无法检测到。在检查网络布线列表时,我们注意到结构的顶层设计有误:我们没有得到一个统一的单一结构,而是得到了八个没有共同路由路径的分离网络。重新连接线路后,我们增加了检查步骤,以验证所有物理连接是否符合新设计。

第2/7步:一万次温度警报

    解决物理布线问题后,UFM成功与结构中所有InfiniBand交换机建立了联系。然而,几乎每个交换机端口都开始报告过高的温度,有时甚至超过70摄氏度,尽管它们还没有传输数据。我们发现,问题源于同一网络机架中的交换机之间存在空隙,导致热空气重新循环回到前部。我们的数据中心合作伙伴帮助我们迅速诊断出问题并制定了合适的解决方案。
第3/7步:1800个警报

    许多端口还表现出高错误率或在工作状态和故障状态之间波动,这被称为“抖动”。这些问题仅在端口被积极使用时才出现,因此由于整个结构由10000条具有高度冗余性的链路组成,所以预先检测证明具有挑战性。我们的数据中心合作伙伴帮助清理并重新安置了发出警报的端口,我们在等待更换的同时禁用了其余发出警报的收发器。

   尽管InfiniBand对硬件故障具有高度恢复能力,但一旦结构中约有10%的部分开始出现问题,自适应路由等功能就无法可靠地运行,以应对随意断开的链路。

   在此期间,我们设法使用100至200台机器进行了多节点训练运行。我们的过程基本上是即兴发挥的:我们有时会在随机的一组节点上启动,观察它们的性能,并尝试在尽可能多的节点上保持运行。这种方法使我们能够找到InfiniBand结构中可靠的一部分,但证明很棘手,因为每当我们更改用于训练的节点集时,默认的InfiniBand链路集也会更改。

第4/7步:燃烧吧,InfiniBand,地狱之舞

    为了更有效地诊断InfiniBand问题,我们为整个集群设计了一个专门的工作负载,重点是同时尽可能多地将数据推送到整个结构中的每个端口。这与在集群上运行一个大型的全规约工作负载不同,后者将使用NCCL,通过服务器PCIe模块(SXM)插槽使GPU使用NVLink进行通信,从而优化单个节点内的通信。
    相反,我们选择了蛮力方法,并且取得了成功。UFM开始发送警报,指出大多数端口的数据传输超过了理论容量的97%,并且一些交换机暂时崩溃。当天结束时,仍在使用的每个端口都被认为足够强大,可以继续使用,而其余的端口则被禁用或留待以后修复。
第5/7步:GPUDirect RDMA
    为了使GPU能够进行通信而不产生CPU开销,我们启用了名为GPUDirect RDMA的功能,允许直接与InfiniBand网卡通信。这涉及两个关键步骤:
  • 启用额外的内核模块

    https://download.nvidia.com/XFree86/Linux-x86_64/535.183.01/README/nvidia-peermem.html

  • 确保禁用PCIe访问控制服务(ACS)以防止立即挂起

    https://docs.nvidia.com/deeplearning/nccl/archives/nccl_2114/user-guide/docs/troubleshooting.html#pci-access-control-services-acs


第6/7步:扩大“黄金”服务器集
    对于使用最新硬件的GPU集群,有一个经验法则:每周大约有3%的机器会出现故障。
    然而,这里有一个常常被忽略的关键细微差别:并不是说每台机器都有均等的3%的故障率;相反,少数问题机器会以不同的方式反复出现故障,直到它们被彻底修复。这凸显了在同一结构上拥有大量机器的优势。与其在我们的大型训练运行中像打地鼠游戏一样随机使用机器,我们不如专注于扩大一组已知可靠或“黄金”机器的数量。
第7/7步:维护

    InfiniBand的维护工作主要包括响应UFM警报、更换损坏的电缆和收发器,以及偶尔诊断更复杂的错误,如交换机故障。大规模回归通常由两个因素引起:

(1)固件升级,特别是如果仅对集群的一半进行升级,可能会损坏UFM状态,并需要在所有InfiniBand交换机上重新启动UFM。

(2)MAAS会在同时大规模重启GPU boxes,这可能会导致UFM状态被大量更新淹没,同样需要重启UFM服务。


3 确保完全健康的机器

     在这个过程中,我们发现了许多单个机器可能发生故障或减慢训练运行速度的方式。许多故障模式并不明显,因此我们编写了许多健康检查来确定哪些主机足够健康,可以用于训练。我们已发布这些代码:https://github.com/imbue-ai/cluster-health。

    请注意,许多健康检查是特定于我们的运行环境的,它们不一定与基础硬件相关,或者非常容易修复或自动化。这是有意为之的:为了达成使我们的机器准备好进行训练的整体目标,我们想要一个单一的入口点,它可以回答“是”或“否”,并且可以抽象化任何数量的“琐碎”细节。
(1)GPU健康检查
   我们检查是否有正确数量的GPU,是否启用了ECC(错误校正码)检查,并且没有ECC错误。我们还检查了连接GPU之间的NVLink拓扑是否正常且无错误。
(2)磁盘空间健康检查
    我们检查主机的磁盘空间利用率不超过95%。
(3)Docker健康检查
    我们检查Docker是否能够运行附有GPU的容器(即NVIDIA容器运行时是否正常工作),并且所有与监控/分析相关的Docker容器是否都处于活动状态并具有正确的主机权限。
(4)Dmesg健康检查
    我们检查dmesg中是否有硬件Xid或SXid错误(由NVIDIA GPU或GPU之间的NVIDIA交换机抛出的故障)。我们还读取所有dmesg日志行,以验证它们是否都可以分类为“常见/预期的日志行”。
(5)iDRAC健康检查
    我们检查主机上的iDRAC错误,忽略非致命的错误消息。这是我们戴尔机器特有的,不是我们开源的健康检查的一部分。
(6)磁盘健康检查
    我们检查zpool是否已挂载,Docker是否正确连接到它,并且可以实际使用而不会导致CPU锁定。
(7)InfiniBand健康检查
    我们检查是否存在增加的InfiniBand错误率和/或过时的驱动程序固件。
(8)Nvlink健康检查
    我们检查主机上的NVLink错误。根据经验,这似乎不会导致训练失败,但可能会导致速度变慢。
(9)GDR健康检查
    我们检查主机是否启用了GDR。
(10)VBIOS健康检查
    我们检查GPU的VBIOS版本以及H100基板固件是否为最新。
(11)Flint健康检查
    我们使用flint和hca_self_test检查是否拥有正确版本的Mellanox OFED驱动程序、卡固件和收发器固件,并且它们是否正确地与NVIDIA驱动程序编译。
(12)PSB健康检查

     我们查询了PCIe设备,以检查GPU、PSB(PCIe交换总线)和网络卡之间的连接速度和宽度是否符合预期。我们还检查了交换机固件是否为当前版本。此脚本由Dell开发,而非Imbue,因此我们目前无法共享。

     除了这些快速健康检查外,我们还进行了一些更为复杂的健康检查,包括:

  • 通过PyTorch初始化矩阵计算,并测量NVLink带宽、GPU计算速度和内存。我们设置了适当的GDR标志来测试InfiniBand和NVLink。

  • 使用带有“-use_cuda”参数的ib_write_bw通过IB卡发送数据,并测量PCIe和InfiniBand卡的带宽。我们运行了较长时间(约15分钟),以确保捕捉到不稳定的InfiniBand链路。

  • 运行多节点诊断,以检查NCCL初始化能力及其是否会随机停滞。如果停滞,我们分叉的NCCL代码会添加额外的日志记录。这可能需要12到24小时才能检测到问题,因此我们通常只在新节点上或怀疑存在问题时运行此检查。

  • 检查DCGM导出的任何GPU时钟节流事件(排除预期的gpu_idle和power_cap)。同时锻炼所有GPU、InfiniBand卡、CPU和磁盘的多节点训练是锻炼这些电源事件的最佳方式。

4 诊断常见训练问题

硬件问题导致的典型NCCL错误包括:
  • 由于某些节点的GPU间通信无法进行NCCL初始化,因此错误消息可能会提到卡上的某些GPU超时。解决此问题的最常见方法是更换问题节点,并重启NCCL会话。

  • 如果GDR硬件有问题,可能会出现NCCL hanging(暂停)或性能下降。

  • 由于NCCL使用GPU内存进行通信,因此任何内存硬件问题都会导致NCCL错误或性能下降。

     调试这些问题的方法之一是运行带有适当日志记录的NCCL测试工作负载,并查找错误或挂起点。

(1)启动时崩溃

    从某些方面来说,遇到这种错误反而是最好的,因为(理论上)它易于重现和迭代。

    我们首先检查代码是否在正确的版本、配置和环境变量下运行。虽然这是基本操作,但我们发现确保训练启动的可重现性和易检查性至关重要,尤其是像Docker镜像缓存或不透明的密钥配置这样的中间抽象可能会混淆问题。

   我们进行的另一项基本检查是确保所有机器都在线,并且发出的堆栈跟踪或日志可以轻松地聚合和检查。我们使用了Loki、Prometheus和Grafana技术栈,但任何合适的日志聚合或追踪SaaS都适用。由于这些运行的同步和分布式特性,通常第一个触发的错误会导致一系列不相关的错误。在这里,健康检查也有助于立即检测明显的问题,如硬盘损坏或丢失或无效的GPU。

   我们建立了一个系统,在失败时自动重新启动,这使得日志和错误聚合变得更加重要,以避免混淆来自不同重启的错误。我们遇到的一些常见错误包括:

  • 诸如“不同等级的转发顺序不同:等级0正在全收集43个参数,而等级1228正在全收集1个参数”之类的错误。我们发现这是PyTorch的Fully Sharded Data Parallel(FSDP)实现中的一个特殊问题,可以通过重新启动来解决。

  • GPU内存不足(OOM)错误,看起来像是CUDA内存不足。尝试分配……我们通过仔细检查我们的配置和代码,并撤销任何可能由于在启动时PyTorch设备规范不当而导致额外利用GPU#0的最近代码更改来解决这些问题。

  • CPU/RAM内存不足错误,这些错误在错误日志中较不易被发现,通常最好通过Docker容器外部主机的dmesg日志来检测。我们主要看到它们表现为CalledProcessError或ConnectionError,当一个派生进程或网络对等体被OOM Killer调用时终止。当从dmesg检测到OOM Killer调用时,我们更倾向于直接使健康检查失败并重启机器。我们还检查了我们的代码路径是否有足够的手动垃圾收集(见下文关于如何禁用它的部分),并且没有意外地尝试在CPU上进行计算或移动张量。

(2)训练中途崩溃

    首要任务是自动化系统,以重新运行所有诊断性健康检查(见前几节),然后在没有不健康主机的情况下自动重新启动运行。我们遇到了一些随机的硬件故障,包括Xid和SXid错误,这些错误可能导致运行崩溃,而不会发出有意义的Python堆栈跟踪。某些情况,如行重映射,可以通过重新启动来恢复。其他情况,如不可纠正的ECC错误,通常需要硬件维护或更换零件。

     此外,我们还观察到由特别畸形的训练数据导致的崩溃。例如,语料库中的一个非常大的单个文档可能会导致GPU或CPU出现OOM错误。为了防止这些问题,我们使用了一个完全确定性的数据加载器,这使得每个崩溃都可以通过与时期或步骤号的相关性轻松重现。我们发现禁用数据加载或用假数据(如全为零的数据)替换以确认数据是否确实是根本原因的做法很有帮助。

     最后,通过任何首选的指标聚合方法来记录网络和一般节点健康统计信息也很有帮助。诸如以太网短暂中断或磁盘空间不足等问题可能不会显示为有用的错误消息,但可以很容易地与收集到的数据进行关联。

(3)没有堆栈跟踪信息的挂起(可能会在超时后出现)

    这类错误由于缺乏有用的信息并且通常难以可靠重现,调试起来非常令人沮丧。

    最令人印象深刻的类型以如下错误消息为特征:

Watchdog caught collective operation timeout: WorkNCCL(SeqNum=408951, OpType=_ALLGATHER_BASE, ... , Timeout(ms)=600000) ran for 600351 milliseconds before timing out

     这意味着在训练运行期间,一个或多个主机未能完成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初始化之前的代码中遇到了竞态条件。

(4)训练速度减慢(以 MFU 衡量)

    缺乏检测工具可能会使这类问题比前一类问题更加令人沮丧。除了使用Py-Spy、堆栈跟踪检查和GDB之外,我们还使用了NVIDIA Nsight和性能分析工具来帮助解决问题,但在高度分布式的设置中,其中一些工具很难使用。

    遗憾的是,通用的性能下降或低于之前演示的模型浮点运算利用率(MFU)可能由多种原因造成。

    首先,事实证明,再次检查配置、代码和环境变量是很有帮助的。我们经历过运行错误模型、错误的批次大小、错误的UFM或NCCL设置、错误的CUDA_DEVICE_MAX_CONNECTIONS等问题,这些都导致了性能不佳。

    我们还发现,测量瞬时(即每个批次)的MFU而不是平滑或窗口化的平均值也很有用,因为MFU曲线的预平滑形状经常帮助我们诊断问题类别。问题包括:

训练立即以极低的MFU(低于预期的1/10)开始并保持稳定

    这最常见的是InfiniBand网络的硬件问题,如T2或T3层的死交换机。这也可能是由GPU和NIC之间的硬件问题引起的,这些问题会在dmesg中显示为PCIe x16通道受限……

训练立即以预期MFU的30%开始并保持稳定

    这可能是由于一个主机的GDR(NVIDIA Peer Memory)设置不当或GDR环境变量不正确造成的。

训练立即以预期MFU的60-80%开始并保持稳定。

    最常见的原因是InfiniBand链路退化或故障,尤其是如果单个特定GPU关联的InfiniBand NIC出现故障,导致NCCL尝试通过本地NVLink路由流量并使用同一主机上另一个GPU的NIC。这也可能是由CPU节流引起的,这需要为特定主机调整一些BIOS设置。

单个批次突然出现大幅度的下降(降低10倍),且这种情况定期发生

    这几乎肯定与检查点或评估有关,可以通过检查时期或步骤计数来验证。令人恼火的是,如果自动化警报仅设置为在MFU异常时触发,这会导致许多误报。

单个批次突然出现大幅度的下降(降低10倍),且这种情况随机发生且相当罕见(大约每15分钟发生一次),并且之后立即完全恢复到良好的MFU。

    这似乎最常见的原因是在运行中的一个主机上安排了其他CPU密集型工作负载。我们发现,与其构建分析工具来识别特定主机,不如通过PID粗略地监控CPU使用情况来得更容易。这也可能归因于偶尔的网络状况不佳,如数据加载器瓶颈。我们使用了指标监控,并为数据加载、检查点和任何非NCCL代码添加了Python代码计时日志,这证明相当可靠。

MFU图在运行过程中逐渐下降,但在任何重启后都会恢复到100%。

    理论上,这可能是由于交换机上的热量积累造成的,但我们从未见过这种情况。相反,我们使用Python和NVIDIA性能分析工具来确定,这种性能下降似乎是自动垃圾收集的结果。

     在调试这些性能下降问题时,我们注意到吞吐量出现了几乎呈确定性的周期性下降模式。随着训练的进行,这种下降影响了越来越大的分布式操作比例。这导致我们提出了一个假设,即这种下降可能与自动垃圾收集有关,我们通过分析和测试验证了这个假设。一旦我们禁用了自动垃圾收集,并安排在所有主机上以特定间隔进行垃圾收集,这些吞吐量“下降”就消失了。

     我们使用了基于ZeRO-3(https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/)的同步分布式训练算法FSDP。在阻塞操作中,单个工作进程运行垃圾收集可能会减慢其他所有工作进程的速度。如果有数百个工作进程,这可能会导致显著的性能下降。

性能一开始很好,然后突然下降到预期值的70%,并且以高频率(每15秒)持续出现。

     我们观察到这与NVIDIA GPU的“时钟节流原因”有关,我们通过将适当的设置应用于NVIDIA DCGM来收集这些信息。这是由散热问题(GPU温度过高或主机冷却风扇损坏/性能下降)或电源供应故障引起的。此外,当我们同时最大化所有8个GPU的利用率、8x NIC InfiniBand的利用率以及CPU/RAM/磁盘的利用率时,我们的一些具有特定电源供应硬件的主机会出现电压问题,但这种情况仅发生在所有资源都被使用时,通常只在实际的训练运行过程中出现。

性能良好,但比平时更“嘈杂”(预期MFU的90%至100%之间存在高频白噪声方差)。

   这也与InfiniBand硬件有关,但通常是由于网络中较高层的链路适度退化或波动,而不是主机到T2层之间冗余较少的链路。

    不幸的是,许多问题并不容易定位到特定的主机,而与InfiniBand相关的问题尤其难以确定,因为InfiniBand交换技术具有拓扑感知特性。InfiniBand似乎更倾向于在InfiniBand胖树设计中选择相邻的主机,而UFM可能会以导致链路速度不对称的方式路由数据包。

以下是调试吞吐量回归的快速总结/流程图/健全性检查清单:

  1. 它之前工作过吗?

  2. 你最近是否更改了什么(例如合并了代码、更新了驱动程序)?

  3. 你是否在健康的主机上运行?你的所有依赖服务是否都在运行,包括第三方SaaS,如Docker Hub、GitHub或你的堆栈所依赖的其他服务?

  4. 你确定你使用的是与上次完全相同的代码、环境、配置、版本、主机列表、排名顺序、随机种子吗(如果可能)?

  5. 这个问题是可复现的吗?

  6. 它与其他任何东西相关吗?其他进程?每日crontab?主机或DCGM或UFM指标?

  7. 你用来测量指标的工具是否正确?

  8. 在运行简化的代码(更小的模型、伪造的数据、不保存或加载检查点)时,问题是否仍然存在?

5 完善基础设施工具
   完成上述步骤后,在训练模型时可以获得良好的性能……但直到某些东西不可避免地出现故障。

   在本节中,我们将介绍我们制作的一些不同的工具和系统,以确保训练能够继续顺利进行,理想情况下只需最少的人工干预。由于我们的团队规模较小,我们没有足够的人手来进行不断的手动修复,因此我们尝试尽可能多地自动化这一过程。

    我们几乎所有的训练运行问题都可以归结为机器或网络组件的故障。在一个大型集群中,这些故障经常发生,因此自动化禁用故障机器和网络组件并请求修复的过程至关重要。

(1)故障机器
    我们开发了一个系统,用于从最近的检查点自动重新启动崩溃的运行。重新启动过程将首先对每个可用的机器运行健康检查,并根据其通过的健康检查对每台机器的健康状况进行分类;然后,它会尝试在最健康的机器上重新启动训练作业。

(2)故障网络组件
    我们观察到的所有网络组件故障都被UFM检测到并记录在UFM事件日志中,因此应对网络组件故障只是解析UFM日志并针对每个事件采取适当行动的问题。

    UFM事件系统相当复杂,包含数十种事件类型。然而,在实际应用中,我们发现只有少数几种事件是有问题的,主要与链路故障或高符号错误计数有关。在识别出这些事件后,我们能够编写脚本来解析UFM事件日志,禁用与最近事件相关的链路和端口,对这些网络组件提交维护工单,并在维护完成后重新启用这些组件。

(3)本地镜像文件系统
     很明显,大型分布式训练运行的一个瓶颈将是集群内外的以太网速度。如果数百个工作进程同时尝试下载数据集和模型检查点,那么带宽约为10Gbit/s的共享以太网连接将很快达到饱和。

    因此,我们决定在集群内构建一个本地文件系统来镜像云存储,并作为缓存来减少我们需要从S3获取的文件数量。为了处理集群的周转(机器经常因维护原因而被禁用或替换),我们对每个文件进行了三副本,并使用一致性哈希来均匀分配负载,以最大限度地减少周转期间的文件移动。集群上有限的磁盘空间意味着我们还必须开发各种工具来跟踪文件生命周期并清除不再相关的文件。

(4)本地分布式Docker注册表
    我们还使用了Kraken,这是一个出色的开源软件,能够实现Docker镜像的P2P传输。考虑到任务和实现的复杂性,我们几乎没有遇到任何问题,这有点令人惊讶。

(5)各种性能监控工具
     我们设置了默认的Torch分析器以及NVIDIA的Nsight Systems。后者有助于准确了解前向/后向传递和NCCL通信所需的时间,并确定在给定的模型大小和工作进程数下,我们是否受到通信或计算的瓶颈限制。然而,Nsight Systems的使用有些困难,因为它需要在特权模式下运行Docker,禁用与性能监控事件相关的安全检查,并且保存配置文件通常需要停止整个训练过程。

    此外,我们发现编写工具来检测训练批次缓慢并了解其潜在原因很有帮助。其中最有用的是一个工具,它监控每个批次所需的时间,并在批次异常缓慢时转储每个工作进程的堆栈跟踪,这使得更容易识别具有细微硬件或软件问题的特定主机。

(6)细分机器组以定位故障主机
    在使用集群的前几个月(当时我们的健康检查并不像现在这样彻底)中,我们经常遇到一种情况,即在特定的一组机器上进行训练运行失败,但不清楚是哪台机器出了问题。为了定位故障主机,我们开发了工具,以便轻松地将机器集划分为子集,并在每个机器子集上启动较小的作业。

     例如,如果一组48台机器上的作业失败,我们将在六组八台机器上启动较小的运行,然后在八组六台机器上启动较小的运行。通常情况下,在这两个阶段中,只有一个运行会失败,从而使我们能够高度确信这两个阶段中都出现故障运行的机器是有问题的。


四 反思与收获

在搭建和维护我们的基础设施的过程中,我们对整个流程有了一些有用的收获:

  1. 能够互相替换机器是非常有用的。对于任何给定的训练运行,我们发现拥有比运行所需多出10-20%的机器是很有帮助的,这样我们可以在机器出现故障时轻松重新启动。将集群网络设置成每台机器都与其他每台机器紧密相连,意味着我们基本上可以使用任何工作的机器子集。

  2. 值得为遇到的每一种硬件或软件故障编写测试和自动化解决方案,因为训练过程中遇到的每个问题都会再次出现。同样,对于每一个模糊的错误信息,编写工具使其更易于解释也是值得的。

  3. 可重复性是良好科学的关键。我们迅速采纳的一条规则是“每次只改变一件事”,即使是最简单的事情也是如此。

  4. 信任,但要验证。每当我们在流程中引入外部工具或吸纳新成员(无论是外部还是内部),我们都会确保对他们的说法进行复核,特别是如果后续步骤依赖于这些结果的话。

五 结论

     训练大型语言模型从一开始就需要复杂的基础设施。我们选择深入参与基础设施设置的细节,既因为我们相信完全理解我们工作的系统很重要,也因为我们怀疑这最终会证明更高效。现在,经历了整个过程,我们很高兴我们采取了这种方法——它最终对完全控制我们的基础设施以及能够在每个抽象层次上轻松调试问题至关重要。虽然这个过程需要广泛的监督和迭代,但它使我们能够深入理解底层程序,构建一系列工具来确保主机健康,学习如何自动化系统以确保持续平稳的训练,并最终创建基础设施,使我们能够快速迭代前沿语言模型的训练。

这个基础设施过程体现了我们研究和构建人工智能代理坚实基础的方法:探究细微末节,不断改进现有流程,并构建有用的工具和系统,使我们的精悍团队能够应对更大的挑战。



53AI,企业落地应用大模型首选服务商

产品:大模型应用平台+智能体定制开发+落地咨询服务

承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询