在《70B大模型训练秘方① :数据集创建与评估》一文中,他们分享了用于模型评估的数据集,包含11个公共数据集的高质量子集,以及一套用于代码理解的原始问题。重点分享了为什么选择这些特定的数据集,以及数据创建过程和实际数据集的详细信息。
主机级健康性检查(https://github.com/imbue-ai/cluster-health/tree/master/health_checks):用于确保特定主机无已知错误的脚本
NVIDIA集群通信库(NCCL) 补丁,优化错误和延迟的日志记录
压力测试,确认GPU能够分配大型张量并执行标准操作(https://github.com/imbue-ai/cluster-health/tree/master/gpu_stress_test)
网络测试(https://github.com/imbue-ai/cluster-health/tree/master/host_validation) ,以检查特定机器上的GPU能否相互通信(通过 NVLink),并且是否能够与其他机器上的GPU进行通信(通过 InfiniBand)
用于解析统一网络管理器(UFM)事件日志的脚本(https://github.com/imbue-ai/cluster-health/tree/master/host_validation) ,检查相关事件,并确定哪些网络端口应被禁用
一个用于为InfiniBand网络结构生成全面预热工作负载的脚本,目的是测试每一个可用的链路。
本文重点介绍一个由511台服务器构成的集群,其中部署了4088枚H100 GPU,均匀分布在每台服务器上,每台服务器搭载8个GPU。考虑到统一网络结构管理节点对连接的需求,保留了部分连接并且用于管理 InfiniBand 网络。
请注意,训练网络的通信是通过InfiniBand而非以太网进行的。尽管这些计算机也连接到了以太网,但该网络主要用于传输数据集、检查点和其他数据。如果通过以太网发送数据将会非常缓慢,因为数据需要首先从GPU传输到CPU,然后再通过一根100 Gbps的以太网卡发送。虽然理论上可以通过称为融合以太网的RDMA(RoCE)技术在以太网上进行训练,但在硬件和软件两方面都需要大量额外工作,并且通常比InfiniBand更不可靠(详情参见论文(https://arxiv.org/pdf/2402.15627),其中概述了整体流程)。
使用我们的集群进行高性能训练意味着每个组件——InfiniBand、以太网、GPU以及节点本身——都必须近乎完美地协同工作。如果超过12000个连接中的任何一个稍微不稳定,都可能拖慢整个训练过程的进度。本文剩余部分将详细阐述实现所有组件完美运行的过程,并确保其持续稳定运行的方法。
步骤 0:获取一台预配机器
步骤 1:在每台机器上安装操作系统
步骤 2:诊断故障机器
步骤 3:最小可观测机器
Docker(更轻松地运行服务和训练任务)
数据中心GPU驱动程序
Prometheus节点导出器(导出硬件/操作系统的稳定指标流)
DCGM导出器(NVIDIA 的额外GPU 状态/时钟/利用率指标)
在所有非操作系统驱动器上配置RAIDZ ZFS存储池(这使机器能够在一块驱动器故障的情况下继续运行,同时提供免费的透明压缩功能,这对于纯文本数据集和重复性日志特别有用,使我们能够常规性地利用比原本多约10倍的空间)。
步骤 4:单节点GPU训练
NVMe驱动器未显示故障,但一旦触碰机器,整个系统都会被锁定。 在Linux系统中,硬盘驱动以随机顺序出现,这一现象导致MAAS服务混淆,导致操作系统被安装到了错误的驱动上。 错误的温度读数,导致风扇一直以100%的功率旋转。此问题部分源于所使用的NVIDIA驱动程序存在缺陷。我们已通过降级至先前的驱动程序版本,成功解决了驱动相关的问题。 CPU的动态频率调整功能失控,导致活跃core的频率限制在2 GHz。 直接GPU-GPU 通信(GDR,或 GPUDirect RDMA Peer Memory Client)无法成功应用。
预置InfiniBand
步骤0:安装通用固件模块(UFM)
步骤1:重新布线的时间
步骤2:一万条温度预警
步骤3:1800条预警
尽管InfiniBand对硬件故障具有极高的容错率,但一旦大约10%的网络结构开始出现故障,自适应路由等特性就难以可靠地工作,从而无法有效地应对链路随机中断的情况。
步骤四:极限测试InfiniBand
步骤5:GPUDirect RDMA
启用一个额外的内核模块 (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:维护
固件更新,尤其是当这种更新仅针对一般集群进行时,可能会破坏UFM的状态,并导致所有InfiniBand交换机上的UFM都需要重启。
同时进行的大规模GPU服务器重启,可能会向UFM状态中涌入大量更新数据,从而同样引发对UFM服务的重启需求。
确保机器完全健康
GPU健康检查
磁盘空间健康检查
Docker健康检查
DMESG健康检查
iDRAC健康检查
磁盘健康检查
InfiniBand 健康检查
Nvlink健康检查
GDR健康检查
VBIOS健康检查
Flint健康检查
PSB健康检查
利用PyTorch初始化矩阵计算,并评估NVLink的带宽以及GPU的计算速度和内存效率。我们设置了正确的GDR标志以测试InfiniBand和NVLink的性能。
通过ib_write_bw并激活-use_cuda,我们实现了在InfiniBand卡上传输数据,并对PCIe及InfiniBand卡的带宽进行了精确测量。为了确保能够捕捉出现“抖动”的InfiniBand链路,我们进行了长达15分钟的持续测试。
我们执行了多节点诊断运行,以检验NCCL的初始化功能以及是否存在随机停滞的情况。如果发生停滞,我们分支的NCCL代码会添加额外的日志记录。这个过程可能需要12到24小时,因此,我们通常只在添加新节点或怀疑存在问题时才会运行此测试。
检查DCGM导出中是否存在任何GPU时钟节流事件(不包括预期的gpu_idle和power_cap)。进行多节点训练,激活所有GPU、InfiniBand卡、CPU和磁盘,是测试这些功耗事件的最佳方法。
诊断常见的训练问题
启动时崩溃
像 'Forward order differs across ranks: rank 0 is all-gathering 43 parameters while rank 1228 is all-gathering 1 parameters' 的错误 。我们发现,这属于PyTorch完全分片数据并行(FSDP)实现中的一个特性,可以通过重启来解决这个问题。
GPU内存不足(OOM)错误,表现类似 'CUDA out of memory Tried to allocate … '。为了解决这个问题,我们双重检查了配置和代码,并回滚了所有可能因启动时PyTorch设备指定不当而导致的GPU#0额外资源占用的新近代码更改。
CPU/RAM内存不足(OOM)错误,这类错误在错误日志中往往不易察觉,通常最佳检测手段是通过主机外部的dmesg日志来识别。我们主要在遇到子进程或网络对等方被OOM Killer回收时,遭遇以 'CalledProcessError' 或 'ConnectionError' 形式出现的错误。我们倾向于在检测到dmesg中的OOM Killer调用时,直接使健康检查失败并重启系统。我们还检查了代码路径中是否包含了足够的手动垃圾回收(参见下文关于如何禁用垃圾回收的章节),并确保没有意外尝试在CPU上进行计算或将张量搬运到CPU上。
训练途中故障
此外,我们还观察到由异常格式化的训练数据引起的崩溃。例如,语料库中的一个超大型单一文档可能导致GPU或CPU出现内存不足(OOM)错误。为了规避这类问题,我们实施了一个完全确定性的数据加载器,这使得每次崩溃都能通过关联到特定的epoch或步骤编号来轻松地重现。我们发现,通过禁用数据加载或用假数据(例如全零数据)替换,可以有效确认数据是否真的是导致崩溃的根本原因。
无堆栈跟踪信息导致的挂起(可能随后出现超时)
训练速度放缓(以模型浮点运算利用率(MFU)衡量)
训练一开始就立即达到了极低的MFU(低于预期值的1/10),并且保持稳定
训练一开始就达到了预期MFU的30%,并且保持稳定
训练一开始就达到了预期MFU的约60-80%,并且保持稳定
单组batch频繁出现的剧烈下降(降低10倍)
随机且罕见地(大约每15分钟发生一次)出现单组batch突然急剧下降(下降10倍),随后立即完全恢复到良好的MFU
在运行过程中,MFU图表呈现出逐渐下滑的趋势,但在每次重启后都能迅速回升至100%
初期性能表现良好,随后突然下降(降至预期的70%),并且以高频率(每15秒一次)持续发生
性能良好,但比平时更“嘈杂”(高频白噪声在预期MFU的90%到100%之间的方差较大)
它奏效过吗?
你最近有改变过什么吗 (例如, 合并了代码,更新了驱动程序)?
你是在健康主机上运行的吗?所有依赖的服务是否都在运行,包括第三方SaaS服务,如Docker Hub、GitHub或其他你所用的堆栈依赖的服务?
你确定你使用的是与上次完全相同的代码、环境、配置、版本、主机列表、排名顺序和随机种子吗(如果可能的话)?
这个问题可以复现吗?
它与其他事情有关联吗?其他进程?每日定时任务?主机或DCGM、UFM指标?
你的度量工具是否正确?
当运行缩减代码(较小的模型、伪造的数据、不保存或加载检查点)时,问题仍然存在吗?
改进基础设施工具
故障机器
网络组件故障
本地镜像文件系统
本地分布式Docker注册表
各种性能监控工具
将机器分组细化以定位故障主机
反思和学习
能够相互替换机器极为实用。对于任何特定的训练运行,我们发现拥有比实际需要多出10-20%的机器是有益的,这样在机器发生故障时,我们能够轻松地重新启动运行。通过设置集群网络使每台机器都与所有其他机器紧密相连,我们实际上可以利用任何处于工作状态的子集机器。
对于每一次在训练过程中遇到的硬件或软件故障,编写相应的测试和自动化解决方案是非常值得的,因为这些已解决的问题可能会再次发生。同样地,对于每一个难以理解的错误信息,开发工具使其更加清晰易懂也是十分有价值的。
重现性是优质科学研究的基础。我们迅速采纳的一个原则是“每次只变动一个因素”,即便是处理最简单的情况也不例外。
“信任,但需实践检验”。每当我们在流程中引入新的外部工具,或无论是内部还是外部新加入团队成员时,我们确保对其声明进行复核,特别是当后续步骤依赖于这些结果时。
