浅谈大模型训练排障平台的建设

2023-11-17 16:49:56 浏览数 (2)

背景概述

OpenAI的Chat-GPT为我们揭示了通用人工智能的潜力,而GPT4-Turbo的发布进一步拓宽了我们对通用人工智能的想象边界,国内各种大型模型如同雨后春笋般涌现。同时,大模型训练所带来的各种工程化问题也接踵而至。 大模型训练通常涉及大量的参数、巨大的计算需求和复杂的网络结构,这使得整个训练过程变得极其复杂。在这种情况下,训练过程中可能出现的故障可以来自硬件、软件、网络、应用等多个方面,这使得故障定位和排除工作变得异常困难。 训练过程中的任何故障都可能导致训练中断,从而损失从上一个检查点到中断时的所有计算。重新启动训练任务也需要一定的时间,而昂贵的计算资源使得每一秒都显得尤为重要,毕竟“时间就是金钱”。 本文将专注于大模型训练的故障的定位,尝试提供一些解决思路和方法,希望能为读者带来一些帮助和启示。

分布式训练简介

在介绍大规模模型训练的方法之前,我们首先需要了解模型训练的基本过程。模型训练通常包括以下几个关键步骤:

  1. 数据准备:将原始数据预处理后输入到训练模型中。
  2. 模型构建:根据实际问题构建合适的模型结构。
  3. 参数初始化:为模型的神经元或权重分配初始值。
  4. 梯度计算:通过反向传播算法计算模型输出与实际目标值之间的误差,并计算梯度。
  5. 参数更新:根据计算得到的梯度,对模型参数进行调整,以减小误差。
  6. 迭代优化:重复进行上述步骤,直到达到预定的迭代次数或满足其他停止条件。

由于模型参数的数量和计算量非常庞大,传统单机训练方法通常需要较长的时间才能完成训练。为了解决这一问题,研究人员提出了大规模模型训练的分布式训练方法。这些方法可以将训练任务分散到多个计算节点上同时进行,从而大大缩短训练时间。

下面我们将简要介绍几种常见的分布式训练方法:

  1. 数据并行:将训练数据分成若干份,在每个计算节点上运行相同的模型,但使用不同的数据副本。这种方式可以有效地利用多个计算节点的计算资源,加速训练过程。
  2. 模型并行:将模型分解成若干个模块,在每个计算节点上运行其中一个模块。这种方式可以进一步减少模型训练的时间复杂度,提高训练效率。
  3. 流水线并行:将模型训练过程划分为多个阶段,每个阶段由一个计算节点负责,上一个阶段输出的数据作为下一个阶段的输入。这种并行方式可以更高效地利用计算资源,提高训练速度。
  4. 混合并行:结合数据并行、模型并行和流水线并行等方式,将训练任务分布到多个计算节点上。这种混合并行训练策略可以充分利用各种计算资源,提高训练效率。

在整个训练过程中,需要涉及到多种技术,如:图形处理单元(GPU)、远程直接内存访问(RDMA)网络、虚拟专用云网络(VPC)技术、虚拟化技术以及存储等。这些技术在训练过程中发挥着重要的作用,例如:

  1. 图形处理单元(GPU):GPU通常具有大量的计算核心和较高的并行计算能力,可以加快模型训练的速度。
  2. 远程直接内存访问(RDMA)网络:RDMA网络可以远程访问内存,实现数据的高效传输和无锁队列操作。这在训练大规模模型时尤为重要,可以避免数据传输过程中的瓶颈问题。
  3. 虚拟专用云网络(VPC)技术:VPC技术可以为训练任务提供虚拟隔离的网络环境,保证训练过程中数据安全的同时,提高训练效率。
  4. 虚拟化技术:虚拟化技术可以实现计算资源的抽象和隔离,使得不同的应用程序可以在同一台物理设备上运行。这在训练大规模模型时尤为重要,可以避免资源争抢的问题。
  5. 存储:存储技术可以为训练过程提供高效的数据存储和访问能力,例如:分布式文件系统、数据库等。

综上所述,大规模模型训练是一个复杂的过程,涉及到多种技术。采用合适的训练方法和技术,可以有效地提高训练效率,缩短训练时间。

应用架构示意应用架构示意

如图所示,应用程序通常部署在多台计算机上,通过VPC网络进行应用程序的部署和管理。在训练启动阶段,通常会使用VPC网络建立TCP连接(例如NCCL初始化),用于交换基本数据。在训练启动后,训练数据通常采用CFS存储,以实现多计算机共享。在获取数据后,GPU负责执行具体的计算任务。在训练过程中,参数的同步将通过集合通信方式使用RDMA网络进行传输。故障可能发生任意一个节点的任意阶段,排查和定位故障点,需要对整个训练的过程和相关技术栈有一定的了解,如何快速定位更是一个巨大的挑战。

常见故障分类

“战胜敌人首要的条件是了解敌人”,我们将故障按照其出现的位置划分为以下几类:应用层故障、集合通信层故障、GPU层故障以及网络层故障。根据故障的现象,我们也可以将其大致分为环境问题、性能问题和网络问题。

  • 环境问题:通常涉及配置不一致、软件版本及依赖项不一致以及驱动程序问题。
  • 性能问题:性能问题通常较为复杂,可能涉及单机单卡故障,导致集群速度降低,也可能是通信拓扑并非最优,通信效率较低所致,或者由于GPU过热而限制频率。
  • 网络问题:VPC层网络问题,其故障现象通常较为明显,通常表现为无法访问或无法建立TCP连接,以及TCP丢包或重传。RDMA网络问题,需要结合RDMA相关监控指标,如流量、PFC、ECN等进行观察分析。
故障分类故障分类

如何分析处理故障

从上一章节中的分类,我们根据故障出现的位置将问题划分为:包括应用层问题、集合通信层问题、GPU层问题和网络层问题。

  • 应用层问题:通常是PyTorch、DeepSpeed和Megatron报错,这可能是由于某些应用程序中的BUG引起的。
  • 集合通信层问题:通常表现为NCCL层抛出一些异常日志,或者在训练过程中通信耗时不稳定或突然增加。这可能是由于集合通信异常或链路问题造成的。
  • GPU层问题:GPU层的一些问题通常会导致应用程序崩溃,并且在系统日志中会有一些明显的XID异常等。
  • 网络层问题:VPC网络的一些问题可能导致训练无法启动,而RDMA网络层问题则可能导致训练中断。通常表现为应用层TCP超时。

针对各层次的问题,我们可以从现象出发,尝试重现问题,并运用一定的工具挖掘更多信息,进行详细分析,最终确定根本原因,并解决问题。在此过程中,我们将把分析定位的经验反馈至工具,不断完善工具,提升整体故障排除的效率。

问题&工具&思路问题&工具&思路

在每个层级的问题,目前都有一些工具帮助分析和处理问题。

  • 在应用层,可以通过 分析应用日志、使用 GDB 或 cuda-gdb 调试应用,pystack 查看调用栈信息。
  • 在集合通信层,可以使用 nccl-test 工具,执行 allreduce_pref. all2all_perf等各种测试,用于验证集合通信是否正常。
  • 在 GPU层,可以使用 nvidia-smi -q 指令查看 GPU状态,也可以使用 dcgmi 对 GPU进行诊断和收集相关的指标数据。
  • 在网络层,我们可以使用tcp dump 工具,抓包分析,使用 IB perf 工具,验证 rdma 是否正常。

针对实际故障,我们可根据实际情况,灵活选择和运用上述工具来分析定位问题。

排障平台建设思路

在集群规模较小的情况下,上述问题定位和处理思路在一定程度上可以发挥作用。然而,随着模型参数量的增加和训练复杂性的提高,所需的集群规模会越来越大。因此,我们需要不断将问题的处理经验进行工程化,并不断优化,同时应该站在更高的维度,去分析和处理故障,基于此,我们可以将整个故障处理的流程平台化。

从上述常规故障排查思路出发,我们可以进一步扩展,一种简单的思路是,按照 防范故障 → 监测故障 → 处理故障的步骤,将平台划分为三个模块:

  • 健康检查模块:致力于防范潜在风险,对集群、网络及训练任务进行定期巡查,并对潜在问题进行系统化管控,以防止恶化成为故障。
  • 质量监控模块:监测集群及任务的相关指标,并在异常情况下主动发出警报,同时提供基本指标的可视化展示。
  • 故障处理模块:负责对故障进行诊断及处理,整合排障工具,并及时恢复任务训练。

平台架构平台架构

在大规模集群中,故障的分析处理涉及大量数据。例如,一个包含156台机器的千卡集群,共有1248个rank,需要分析每个rank的数据,如果对网络层的数据进行处理,一台设备,若上联 16 个端口,则需要需要处理2596个端口的数据。

通常情况下,对于排障任务场景,我们可以简单地将任务分配给具体的节点机器,执行具体的检测或诊断逻辑(串行或并行可以根据实际情况进行编排),然后将结果收集并进行分析。

在分析过程中,通常需要进行以下三种分析:

  • 差异性分析:找出表现异常的点,例如某张卡的GPU利用率较低,某个端口的流量较低。这种分析反映了单卡故障或单网口故障,可能导致集群训练速度下降。
  • 一致性分析:分析某些配置项是否一致,例如某台机器上的bond口顺序不一致,cpu类型不一致等。在同一个集群下,训练所用的环境和硬件最好保持一致,CPU型号不一致时,也可能引发NCCL层通信问题。
  • 准确性分析:针对某些明确的检测项,例如XID异常,GPU降速等,需要明确比较检测值是否符合预期。不符合预期的检测项即为异常,需要进行处理。
排障工具流程图排障工具流程图

案例分享

故障现象:在某次训练中,使用 48 台机器训练某个任务,任务在持续一个月后,开始出现训练 hang 问题,应用层无日志输出,所有GPU功耗降低知 100w左右,但是 GPU 利用率持续为 100%。任务重启后,可以恢复训练,但是持续一段时间后就重新出现 hang。

故障排查处理过程:

  1. 对训练集群所涉及的机器,进行配置和指标检测,无明显异常。硬件层面也没有错误日志。
  2. 对集群网络层指标进行分析,没有发现丢包,RMDA网络层也没有发现PFC报文或其他异常。使用 NCCL-TEST 进行 allreduce_perf 测试,检测无异常。
  3. 对应用环境进行检测,48 台机器训练环境和配置无差异性。
  4. 开始对应用层进行分析,为方便调试,增加如下环境变量:
代码语言:shell复制
# 开启torch集合通信的耗时统计
export TORCH_CPP_LOG_LEVEL=INFO
export TORCH_DISTRIBUTED_DEBUG=DETAIL

# 启用pytorch集合通信监控,出现异常或超时时不再hang住,直接崩溃并打印调用栈
export NCCL_ASYNC_ERROR_HANDLING=1  

5. 问题复现后,使用 cuda-gdb 对所有 rank 进行调试分析,发现所有进程均hang在 ncclKernel_AllGather_Ring_LL_Sum_int8_t()中,确定和 NCCL 相关。

6. 添加`export NCCL_ASYNC_ERROR_HANDLING=1 ` 后,应用层日志显示,所有线程均卡在 WorkNCCL(SeqNum-5586566, OpType=_ALLGATHER_BASE, 这个操作中,确定 hang在集合通信层。

7. 明确未 NCCL问题后,开始对NCCL相关代码进行分析,发现类似问题:https://github.com/NVIDIA/nccl/pull/898。 分析: a. 集合通信中,任意两个节点的之间通信,每次告知对方需要读取什么数据时,会用到一个引用计数(comm->fifohead),每次通信后都会 1。

b. int 最大值,int 4 个字节 -2147483648 到 2147483647。int超过最大值后,会进行反转,从最小值重新开始。uint64, 8个字节 0~18446744073709551615。

c. 当 slots[x].idx > int_max 时,就会判定失败,会导致通信无法完成。

代码解释代码解释

8. 升级 NCCL修复的版本,并进行验证,问题消除。

在本案例的排查与处理过程中,我们首先借助平台的能力,对集群的各项指标及相关告警进行排查,以检测是否存在异常现象,排除机器故障或网络侧问题。同时,我们使用NCCL-TEST来验证RDMA网络问题。在缺乏线索的情况下,我们开始对应用层进行分析。首先,借助集群排障工具,对整个集群的应用环境进行检测,以检查每个节点的环境是否存在不一致之处。最后,我们对应用层进行分析,增加一些环境变量,增加程序hang超时退出时的日志,并利用集群排障工具,对所有rank,使用cuda-gdb进行调用栈分析,以检测是否有进程或线程存在不一致的情况。最终确认所有进程均挂起在NCCL集合通信中,进而并对NCCL层进行详细代码解读与分析,最终解决问题。

疑难杂症的处理思路

在大模型训练中,故障根因错综复杂,一些应用层和集合通信的故障,目前尚不能使用指标完全覆盖检测,需要我们静下来心来深入分析,一步步挖掘真相。

针对一些疑难杂症,也可以参考下面的一些基本思路,进行处理:

  1. 排查 硬件错误日志,系统 syslog, RDMA网络问题
  2. 添加应用层日志,添加 `export NCCL_ASYNC_ERROR_HANDLING=1; export NCCL_DEBUG=INFO` 环境变量, 增加一些日志信息, 更多的日志配置可以参考各个训练框架提供的配置文档。
  3. 使用 cuda-gdb 工具对调用栈进行分析 cuda-gdb 用于调试 cuda应用程序,是 GDB的扩展。官方介绍:https://docs.nvidia.com/cuda/cuda-gdb/index.html, cuda-gdb 通常情况下,一般会在驱动安装时安装好。需要注意的是,在容器中,需要使用 cuda-gdb 时,需要映射 libcudadebugger.so 文件到容器中,否则cuda-gdb可能无法正常工作。 映射方式:k8s 可以修改 yaml 文件,增加mount 选项。docker可以添加 -v 参数。具体文件的路径和版本,以实际的为准,下面仅作参考。
代码语言:yaml复制
# 注意下面的文件版本和具体位置,请以实际为准, 可以使用 ldconfig -p | grep libcudadebugger 确定实际位置
VolumeMounts:
    - mountPath: /lib64/libcudadebugger.so.535.129.03
      name: libcudadebugger  
 volumes:
        - name: "libcudadebugger"
          hostPath:
            - path: /lib64/libcudadebugger.so.535.129.03

4. 对所有数据进行分析整理,找到可疑点。

5. 对可疑点相关代码进行深入分析。

总结

本文概括性地介绍了大型模型训练中遇到的问题分类、基本排查方法以及排障工具平台构建的基本思路。随着大型模型的发展以及参数数量的增加,所需的计算资源也将逐步增加,集群规模的扩大以及对训练稳定性和集群排障效率的挑战也将愈发严峻,本文仅是抛砖引玉,提供了一些粗浅的思考,希望能给大家带来一些帮助。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞