理解现代分布式机器学习:从高性能计算调度器到大型语言模型服务引擎

作者
Lang Wang
35 分钟阅读

理解现代分布式机器学习:从 HPC 调度器到 LLM 服务引擎

现在的机器学习工程师需要处理各种工具和概念,以便大规模训练和部署模型。本文深入探讨了几个关键主题:使用深度学习容器 (DLC) 运行作业、使用像 Volcano (VOLC)SLURM 这样的 HPC 批处理调度器、使用 vLLMSGLang 实现高效的 LLM 服务、典型的训练框架和参数、运行模式(训练与推理)、并行策略(DPTPPP – 数据、流水线、张量并行)、路由器和控制器在分布式系统中的作用,以及用于高吞吐量的数据加载策略。我们将解释每个概念,提供示例(包括代码和配置示例),并以技术和精确的方式提供实用的见解。让我们开始吧。

深度学习容器 (DLC) 和运行 ML 作业

深度学习容器 (DLC) 是指预先构建的 Docker 容器镜像,其中包含优化的、可立即运行的常用深度学习框架和依赖项。例如,AWS 提供了用于 TensorFlow、PyTorch、MXNet 等的 DLC,其中包括优化的构建版本(通常具有 GPU 支持、已安装的 CUDA/cuDNN 等库,甚至还有像 EFA 这样的网络优化,用于多节点训练)。这些容器确保了一致的环境,因此研究人员无需在每台机器上手动安装框架。根据 AWS 的说法,DLC 作为 Docker 镜像在 Amazon ECR(弹性容器注册表)上提供,并且每个镜像都针对特定的框架版本和任务(训练或推理)进行了定制(使用 AWS 上的 PyTorch 2.0 构建高性能 ML 模型 – 第 1 部分 | AWS 机器学习博客)。这意味着您可以选择与您所需的框架(例如带有 CUDA 11 的 PyTorch 2.0)匹配的容器,并且确信它具有所有正确的库。

其运作方式: 在实践中,使用 DLC 涉及拉取容器镜像并在其中运行您的训练或推理。这可以在安装了 Docker 的云 VM 或本地服务器上完成。例如,在启动 EC2 GPU 实例后,可以执行以下操作:

# 第 1 步:登录到 AWS ECR public(如果需要)并拉取 DLC 镜像
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <aws_account>.dkr.ecr.us-west-2.amazonaws.com
docker pull <aws_account>.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.0.0-gpu-py310-cu118-ubuntu20.04-ec2

# 第 2 步:使用训练脚本运行容器
docker run --gpus all -v /data:/data -it <aws_account>.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.0.0-gpu-py310-cu118-ubuntu20.04-ec2 \
    python /data/train.py --epochs 5 --batch-size 32

在上面的示例中,我们拉取了一个 AWS PyTorch 2.0 训练 DLC,然后在其中执行了一个训练脚本 (train.py)。--gpus all 标志允许容器访问主机上的 NVIDIA GPU,-v /data:/data 将主机数据目录挂载到容器中。这种方法确保了容器内部的环境具有正确版本的 PyTorch、CUDA 等,从而简化了作业的运行。它也具有可移植性 – 同一个容器可以在任何安装了 Docker 的机器上运行,因此实验具有可重复性。

何时使用 DLC: DLC 在云平台和托管服务上尤其方便。例如,Amazon SageMaker 训练作业在后台使用 DLC 镜像,因此您可以只指定镜像和您的训练代码,平台会处理其余的事情。即使在 HPC 集群上,团队有时也会使用 Singularity 或 Docker 在容器化环境中运行作业,以保持一致性。总之,DLC 通过为深度学习任务提供一致的运行时来简化“它可以在我的机器上运行”的问题。它们附带经过测试的、优化的库(可以提高性能 – 例如,AWS 报告说,在某些实例上使用其优化的 PyTorch 2.0 DLC 可以提高高达 42% 的速度(使用 AWS 上的 PyTorch 2.0 构建高性能 ML 模型 – 第 1 部分 | AWS 机器学习博客))。

Volcano (VOLC) – 用于 AI 作业的 Kubernetes 批处理调度

Volcano (VOLC) 是一个构建在 Kubernetes 上的批处理调度系统,旨在在云原生环境中运行高性能计算 (HPC) 和 AI 工作负载。虽然 Kubernetes 的默认调度器非常适合微服务,但它缺少深度学习作业所需的一些功能(如整体调度、队列管理和优先级调度)。Volcano 通过在 Kubernetes 之上提供自定义调度器和作业管理 CRD(自定义资源定义)来解决这些问题(Volcano:容器与批处理计算之间的碰撞 | CNCF)。本质上,Volcano 使 Kubernetes 的行为更像 HPC 集群调度器,用于批处理作业。

它是什么: 引入 Volcano 是为了桥接容器和批处理计算。它支持像 TensorFlow、PyTorch、Spark 和 MPI 这样的框架,允许用户提交需要多个资源的作业(例如,一个需要 2 个节点上的 8 个 GPU 的作业),并确保在作业启动之前一起分配这些资源(Volcano:容器与批处理计算之间的碰撞 | CNCF)。这种“整体调度”确保了分布式训练作业(可能会产生许多 pod)不会在所有必需的 pod 都可以启动之前启动,从而防止一半作业正在运行而另一半正在等待的情况(这会浪费资源)。Volcano 还提供公平策略、优先级队列和共同调度混合工作负载的能力。

其运作方式: Volcano 作为调度插件与 Kubernetes 集成。用户通常定义一个 Volcano Job YAML,其中指定任务及其副本计数、资源需求等。例如,一个 YAML 可能会声明一个具有 4 个副本的作业,每个副本需要 1 个 GPU,并且 minAvailable: 4(意味着只有在可以放置 4 个 pod 时才调度此作业)。提交后,Volcano 的调度器将在集群上找到所有 4 个 pod 的空间并同时启动它们。如果只有 3 个 GPU 是空闲的,它将等到第 4 个 GPU 空闲(而不是现在启动 3 个,以后启动 1 个)。这对于像 Horovod 或 PyTorch DDP 这样的分布式训练框架至关重要,这些框架希望所有 rank 一次性启动以进行同步。

Volcano 的架构包括一个中央控制器和调度插件。它通过插件机制考虑诸如公平共享、优先级等调度算法。例如,它可以强制执行排队策略(因此某些作业不会使其他作业匮乏)和拓扑感知调度(将作业分布在节点或机架上以提高性能)。从用户的角度来看,使用 Volcano 感觉就像使用 Kubernetes,但具有不同的作业 API,并且可以确保您的 ML 作业将以整体方式进行调度。简而言之,VOLC 将 Kubernetes 变成了一个 HPC 感知的调度器Volcano:容器与批处理计算之间的碰撞 | CNCF),将容器的便利性与批处理作业编排的强大功能结合起来。

用例示例: 假设您有一个带有 GPU 节点的 Kubernetes 集群,并且您想运行一个基于 MPI 的分布式训练作业。使用 Volcano,您可以提交一个 MPI 作业(Volcano 与 MPI Operator 集成),请求(例如)2 个 pod,每个 pod 具有 4 个 GPU。Volcano 将确保两个 pod 在两个节点上一起启动并分别具有 4 个 GPU。如果 pod 发生故障,它也会处理,并在需要时重新调度整个作业,以维持整体语义。这样,您的 MPI mpirun 命令就可以在 pod 中可靠地跨两个 pod 启动。如果没有 Volcano,默认调度器可能会启动一个 pod,然后延迟第二个 pod,直到资源释放出来,这会导致第一个 pod 的 MPI 进程挂起或超时。

SLURM:经典 HPC 作业调度(深入探讨)

SLURM(Simple Linux Utility for Resource Management)是一个广泛使用的开源作业调度器,用于 HPC 集群。它的功能类似于集群的“操作系统”,将资源(CPU 核心、GPU、内存、节点)分配给作业,将作业排队直到资源可用,并启动和监视这些作业。Slurm 具有高度可扩展性,并用于许多顶级超级计算机。它提供了一个集群管理和作业调度工具,专注于有效地将作业与可用资源匹配(为 ML 工作负载选择正确的编排工具:Slurm 与 Kubernetes | Nscale)。

SLURM 的工作原理: 一个 Slurm 集群由一个中央控制器 (slurmctld) 组成,它管理队列和调度,以及在每个计算节点上运行的代理守护进程 (slurmd),用于启动和监督任务。用户通过诸如 sbatch(提交批处理作业脚本)、salloc(请求交互式分配)或 srun(启动并行任务)之类的命令与 Slurm 交互。Slurm 维护一个分区列表(将它们视为命名的队列或节点组),每个分区都有一定的限制或硬件特性,并且它根据配置的策略(优先级、公平性、回填调度等)将作业调度到这些分区中的节点上。

作业提交示例: 下面是一个示例 Slurm 批处理作业脚本 (train.sbatch),它请求资源并运行一个训练程序:

#!/bin/bash
#SBATCH --job-name=train_model       # 作业名称
#SBATCH --nodes=1                    # 在单个节点上运行
#SBATCH --ntasks=4                   # 总任务数(进程数)= 4
#SBATCH --gres=gpu:4                 # 请求 4 个 GPU(在一个节点上)
#SBATCH --cpus-per-task=4            # 每个任务 4 个 CPU 核心(总共 16 个核心)
#SBATCH --mem=64G                    # 作业 64 GB 内存
#SBATCH --time=02:00:00              # 时间限制 hh:mm:ss
#SBATCH --partition=ml_gpu           # 分区(队列)名称

module load anaconda/2023a           # 加载任何必要的模块(例如 Anaconda)
source activate myenv               # 如果需要,激活虚拟环境
echo "Running on $SLURM_NNODES node(s) with $SLURM_NTASKS tasks..."
srun python train.py --epochs 10 --batch-size 128

在此脚本中,#SBATCH 行是指示 Slurm 的指令。我们请求 1 个具有 4 个 GPU 的节点,并将作业设置为通过 srun 运行 python train.py。当我们运行 sbatch train.sbatch 时,Slurm 会将作业排队。一旦分区 ml_gpu 中具有 4 个空闲 GPU 和 16 个空闲 CPU 核心的节点可用,Slurm 会将该节点分配给该作业,启动该作业,并且 srun 将启动 4 个任务(因为 --ntasks=4)。如果这是一个使用 MPI 或 PyTorch 分布式的分布式训练场景,则这 4 个任务可能对应于 4 个 worker(每个 worker 分配一个 GPU)。Slurm 负责使用 MPI 或 torch.distributed 的适当环境变量启动它们(如果配置为这样做)。

有效使用 Slurm: Slurm 提供了许多功能,例如作业数组(可以轻松提交许多类似的作业)、依赖链(在作业 A 完成后启动作业 B)和资源分析。对于 ML,一种常见的模式是请求 --gres=gpu:N 以获取 N 个 GPU,并使用 srun 或 MPI 生成 N 个进程。Slurm 确保所有这些进程都在分配的节点上运行并且可以通信(通常它会在 SLURM_HOSTNAMES 中设置主机名,并且 MPI 可以使用这些主机名)。Slurm 还允许调度策略;例如,作业可以被抢占或回填。回填调度在 HPC 中很有用,可以最大限度地提高利用率:如果一个短作业可以容纳在大型作业之间的间隙中,则它可能会在队列中向前跳。作为一名工程师,当您有大型训练作业时,您可能会请求更长的挂钟时间;但是,如果您可以将工作分解为更短的块或进行检查点并重新启动,您可能会利用回填来更快地分段运行它们。

总之,Slurm 是在集群上运行批处理 ML 作业的强大工具。它比 Kubernetes 或云服务更底层 – 您通常 SSH 进入登录节点并使用 sbatch 提交 – 但它提供了细粒度的控制。许多研究人员通过简单地编写启动其训练代码的 Slurm 脚本,在 Slurm 集群上运行 PyTorch 或 TensorFlow,从而受益于集群的 GPU 资源调度。

vLLM:高吞吐量 LLM 推理引擎

随着大型语言模型 (LLM) 从研究走向生产,如何高效地服务它们成为了一项挑战。vLLM 是一个开源库和引擎,专为快速、经济高效的 LLM 推理而设计。vLLM 由加州大学伯克利分校的 Sky Computing Lab 开发,引入了一种称为 PagedAttention 的新型内存管理技术,以优化模型注意力键值缓存的存储和访问方式(vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客)。结果是与传统实现相比,吞吐量(每秒请求数)显着提高。事实上,在 GPT 风格的模型服务上,vLLM 比基线 Hugging Face Transformers 库实现了高达 24 倍的吞吐量vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客),所有这些都不需要更改模型架构。

vLLM 的工作原理: 在自回归生成中(LLM 逐个 token 生成文本的典型方式),会为每个序列维护过去注意力键和值的缓存。这个 KV 缓存 随着序列长度的增长而增长,并且会消耗大量 GPU 内存(例如,对于 LLaMA-13B 上的单个长序列,约为 1.7 GB(vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客))。大多数框架为最大可能长度分配一个连续的块,从而导致大量未使用的空间(碎片)。vLLM 的 PagedAttention 而是 将 KV 缓存视为虚拟内存页面,以块的形式分配它并允许非连续存储(vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客)。这样,内存可以灵活地管理:完成生成的序列会释放其页面,这些页面可以重复用于新序列。它可以显着减少内存浪费(在典型情况下减少 60-80%),并允许 vLLM 比其他系统处理更多的并发序列。

此外,vLLM 实现了 连续批处理:它可以在其他请求正在生成过程中时,动态地将新的传入请求添加到批处理中。传统的系统通常为每个生成步骤从头到尾处理一批固定的请求;vLLM 的调度器经过微调,可以在可能的情况下合并请求,使 GPU 保持繁忙。它还使用优化的 CUDA 图来避免服务循环中的 Python 开销,支持 NVIDIA 和 AMD GPU,并与 Hugging Face Transformers 集成(因此您可以通过名称加载模型并为其提供服务)。

使用示例: 使用 vLLM 感觉类似于使用高级推理服务器。您可以以编程方式使用它,也可以通过 API 服务器使用它。例如,以编程方式:

from vllm import LLM, SamplingParams

# 加载一个 7B 模型(假设权重在本地或通过 HuggingFace Hub 可用)
llm = LLM(model="facebook/opt-6.7b", tensor_parallel_size=1)  # tensor_parallel_size 可以 >1 以在 GPU 上拆分模型
prompts = [
    "User: Hello, how are you?\nAssistant:",
    "User: What is the capital of France?\nAssistant:"
]
# 使用某些解码参数生成
outputs = llm.generate(prompts, sampling_params=SamplingParams(top_p=0.95, max_tokens=100))
for out in outputs:
    print("Prompt:\n", out.prompt)
    print("Completion:\n", out.outputs[0].text)

此代码创建一个 LLM 实例并为批处理中的两个提示生成响应。在后台,vLLM 将使用 PagedAttention 来管理这些提示的 KV 缓存,甚至可以在可能的情况下将它们批处理在一起。outputs 将包含每个提示的完成。也可以使用诸如 python -m vllm.entrypoints.openai.api_server --model your_model_name 之类的命令将 vLLM 作为服务器启动(该服务器提供与 OpenAI 兼容的 REST API)。这使得将 vLLM 与期望 OpenAI API 的应用程序集成变得容易(只需将它们指向此服务器)。

为什么它很重要: vLLM 本质上突破了 LLM 服务的吞吐量限制。如果您有固定的 GPU 预算,每秒服务更多的请求意味着每个请求的成本更低。报告的 24 倍改进是在生成具有相对较长输出的许多并发请求的场景中(vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客)。即使在不太极端的情况下,vLLM 通常也会比简单的实现产生多倍的加速,并且在许多设置中比 Hugging Face 的 TGI 服务器产生约 3 倍的加速(vLLM:使用 PagedAttention 实现简单、快速、廉价的 LLM 服务 | vLLM 博客)。它还高效地支持高级解码算法(如束搜索、并行采样)(vLLM 和 PagedAttention:全面概述 | 作者:Abonia Sojasingarayar | Medium)。对于工程师来说,采用 vLLM 可以像交换您的推理代码以使用 vLLM 的 API(或运行其服务器)一样简单。好处是在不购买更多 GPU 的情况下处理更多用户或减少延迟。

SGLang:结构化生成语言和服务框架

虽然 vLLM 专注于单步提示完成的原始吞吐量,但 SGLang 有效地解决了编排与 LLM 的复杂、结构化交互的问题。SGLang(结构化生成语言的缩写)是一个系统,它将用于描述多步骤 LLM 程序的 前端 DSL(特定领域语言) 与用于执行它们的高度优化后端运行时相结合([2312.07104] SGLang:有效执行结构化语言模型程序)(SGLang:深入了解高效的 LLM 程序执行 - DEV Community)。就好像 SGLang 既是一种用于提示的编程语言(具有循环、条件和并行调用等功能),又是一种服务引擎,可以确保这些程序快速运行。

它是什么: SGLang 背后的核心思想是,许多实际应用程序需要多次调用 LLM 和结构化输出。例如,AI 代理可能会计划步骤并为每个步骤调用 LLM,或者您可能需要 LLM 输出具有特定架构的 JSON。天真地这样做可能会很慢:多次调用会产生开销,并且 LLM 可能会重复处理相同的提示部分等。SGLang 的前端允许您编写单个“脚本”,该脚本可以包括多个生成调用、分支逻辑和外部工具的集成。然后,SGLang 编译器/运行时将有效地执行此操作。运行时引入了诸如 RadixAttention(一种用于跨提示前缀重用 KV 缓存的算法,在精神上类似于 vLLM 的分页,但面向共享提示部分)和 用于输出语法的压缩有限状态机(用于更快地处理结构化输出)之类的优化([2312.07104] SGLang:有效执行结构化语言模型程序)。简单来说,RadixAttention 意味着如果您有许多请求共享一个共同的前缀(例如,系统或少样本提示),SGLang 将计算一次该部分并重复使用它,从而通过避免冗余工作使诸如聊天机器人或检索增强生成之类的事情更快(什么是 SGLang 以及为什么它很重要?| 作者:Emad Dehnavi | Medium)。结构化输出 FSM 意味着如果您期望,例如,具有固定键的 JSON,SGLang 可以跳过逐个 token 生成固定标点/键并向前跳转,因为它知道这些部分是确定性的(什么是 SGLang 以及为什么它很重要?| 作者:Emad Dehnavi | Medium)。这为生成长 JSON 或 XML 输出提供了 3 倍以上的速度提升什么是 SGLang 以及为什么它很重要?| 作者:Emad Dehnavi | Medium)。

其运作方式: SGLang 由两个部分组成 – 一个基于 Python 的 DSL 和一个运行时。DSL 允许用户编写如下内容:

from sglang import sg  # 假设的接口

# 伪代码:定义一个结构化的生成流程
with sg.session(model="Llama-2-13b-chat") as sess:
    # 一个简单的程序,具有两个顺序的 LLM 调用和一个结构化的输出
    user_input = "Translate the following English text to French and give sentiment: I love this product."
    sg.prompt(f"User asks: {user_input}\nYou are a translator and sentiment analyzer.")
    translation = sg.generate("First, translate to French:")
    sentiment = sg.generate("Now, analyze the sentiment of the original text:")
    sg.return_json({"translation": translation, "sentiment": sentiment})

(注意:以上是说明性伪代码。SGLang 的实际语法可能不同,但在概念上,它允许顺序和并行生成以及返回结构化数据。)

当此 SGLang“程序”运行时,运行时将接管:它可能会执行第一个生成调用以进行翻译,然后执行第二个调用以进行情感分析,最后组装一个 JSON。在后台,它使用一个或多个 LLM 推理后端(具有类似于 vLLM 的优化)。因为两个提示共享初始指令上下文,所以 SGLang 可以重用该前缀的计算以进行第二次调用。并且在返回 JSON 时,如果 JSON 键和格式由 sg.return_json 预先确定,则它可以确保输出这些键和格式,而无需花费多个 token 在大括号/逗号上。

主要功能: SGLang 的作者重点介绍了以下功能,包括零开销调度(其用于编排多个调用的调度程序几乎没有增加额外的延迟)、缓存感知负载平衡(它可以以最大限度地提高缓存命中的方式将请求路由到 worker)和多模态支持(它也可以处理视觉语言模型,例如用于图像的 LLaVA)(GitHub - sgl-project/sglang: SGLang 是一个用于大型语言模型和视觉语言模型的快速服务框架。)(GitHub - sgl-project/sglang: SGLang 是一个用于大型语言模型和视觉语言模型的快速服务框架。)。它还支持常见的效率技巧:量化(int8/4 位等)、推测解码(提前生成多个 token 以进行验证,这可以加速长时间生成)和多模型编排(例如,使用一个模型来处理程序的一部分,而使用另一个模型来处理不同的部分)。本质上,它是一个一体化框架,用于编写 LLM 驱动的应用程序 并以高性能运行它们。

性能和用例: 在复杂的任务上,SGLang 的吞吐量比最先进的系统提高了高达 6.4 倍[2312.07104] SGLang:有效执行结构化语言模型程序)。考虑一个检索增强生成 (RAG) 管道:通常,您可能会对上下文进行向量搜索,然后将其添加到提示中,然后生成一个答案。使用 SGLang,您可以将整个序列(向量搜索结果输入到提示模板,然后生成)表示为一个程序。运行时可以并行化某些步骤(如果可能)并重用缓存的组件。类似地,对于具有会话历史记录的聊天机器人,SGLang 可以跨回合重用提示的不变部分(而不是每次都重新处理整个会话)。对于诸如确保模型的答案遵循 JSON 架构之类的结构化输出,SGLang 的有限状态机方法可以通过注入固定语法来防止模型偏离格式并更快地完成它。从工程的角度来看,SGLang 为构建复杂的 LLM 工作流程提供了生产力提升(通过 DSL)性能提升(通过优化的执行)

谁在背后: SGLang 是一个开源项目(由包括来自斯坦福大学/伯克利大学的研究人员和 LinkedIn 等公司在内的社区支持,根据他们的感谢)。它已被 ByteDance 和 xAI 等公司在生产中使用(SGLang:深入了解高效的 LLM 程序执行 - DEV Community)。它相对较新(arXiv 论文于 2023 年末发布),但它在高级 LLM 应用程序中越来越受欢迎。如果您的用例超出了单个提示-完成对 – 比如您需要一个多次调用模型的代理,或者您需要超快速的结构化响应 – 那么探索 SGLang 可能是值得的。它确实比简单的服务器具有更多的活动部件,但它可以自动执行您原本必须自己构建的大量优化。

训练框架和典型训练参数

当我们谈论训练框架时,我们指的是用于实现模型训练的库和工具。主要的训练框架包括 PyTorchTensorFlowJAX 和更高级的接口,如 PyTorch LightningHugging Face Transformers Trainer,以及位于这些框架之上的分布式训练框架,如 HorovodDeepSpeedColossalAI。无论使用哪种框架,实践者都必须管理一组常见的训练参数(超参数)。这些旋钮定义了训练设置并影响模型的收敛性和性能。

典型的训练参数包括:

  • 学习率 (LR): 也许是最关键的超参数。它控制梯度下降中的步长。学习率太高,训练可能会发散;学习率太低,它会收敛缓慢或陷入次优结果。我们通常使用学习率计划(如余弦衰减、线性预热然后衰减等)来随着时间的推移调整 LR。
  • 批大小: 模型在更新其权重之前看到的样本数。有每设备批大小全局批大小(全局 = 每设备 * 设备数 * 梯度累积步数)。较大的批大小可以加速训练(更多并行性),但可能需要较低的学习率或仔细的调整以维持泛化。内存是批大小的限制因素。
  • 周期数或迭代次数: 周期 = 在整个数据集上进行多少次传递。或者,如果数据是流式的,则可以设置训练步数的总数。您通常会训练直到模型收敛(监视验证指标)。
  • 优化算法: 例如,SGD、Adam、AdamW、RMSprop 等。每个算法都有诸如动量(对于 SGD)或 beta1/beta2(对于 Adam)之类的参数。例如,AdamW 是具有权重衰减(L2 正则化)的 Adam,这对于 transformer 来说非常常见。
  • 权重衰减: 一种正则化参数,控制权重上的 L2 惩罚(以减少过拟合)。对于大型语言模型,它通常设置为 0.01 或 0.1 左右。
  • Dropout 率: 如果模型架构包括 dropout 层,则此比率(通常在 0.1 到 0.5 之间)决定了在训练期间要删除的神经元的比例。它在训练模式下处于活动状态,并在评估模式下自动关闭。
  • 梯度裁剪: 一个阈值(如将范数裁剪为 1.0 或 5.0)以避免 RNN/transformer 中的梯度爆炸。这不完全是模型的超参数,而是训练过程的超参数。
  • 梯度累积步数: 如果您的批大小受到 GPU 内存的限制,您可以在更新权重之前在几个小批次上累积梯度。例如,如果您想要一个有效的批大小为 256,但一次只能容纳 64,您可以累积超过 4 个小批次。这可以有效地增加批大小,而无需额外的内存(但必须相应地调整学习率)。
  • 分布式训练参数: 如果使用多个 GPU 或节点,则诸如进程数之类的参数,或者对于 Horovod/分布式数据并行,通信后端(GPU 的 NCCL)等,会发挥作用。许多框架让您在很大程度上忽略这一点(它们从环境中找出这一点),但您可以在手动启动时指定 world_size(进程总数)和 rank(进程 ID)。

这些参数通常在代码或配置文件中指定。例如,使用 PyTorch:

import torch
import torch.optim as optim

model = MyModel()
learning_rate = 3e-4
optimizer = optim.AdamW(model.parameters(), lr=learning_rate, weight_decay=0.01)
num_epochs = 10
clip_grad_norm = 1.0

for epoch in range(num_epochs):
    model.train()  # 设置训练模式(启用 dropout 等)
    for batch in train_loader:
        inputs, labels = batch
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = compute_loss(outputs, labels)
        loss.backward()
        # 裁剪梯度以防止爆炸
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=clip_grad_norm)
        optimizer.step()

在此代码段中,我们

您可能也喜欢

本文是根据我们的用户在 新闻提交规则和指南下提交的。封面照片是计算机生成的艺术作品,仅用于说明目的;不表明实际内容。如果您认为本文侵犯了版权,请毫不犹豫地通过 发送电子邮件给我们来举报。您的警惕和合作对帮助我们维护尊重和合法合规的社区至关重要。

订阅我们的通讯

通过独家预览了解我们的新产品,获取企业业务和技术的最新资讯

我们网站使用Cookie来启用某些功能,为您提供更相关的信息并优化您在我们网站上的体验。更多信息请参阅我们的 隐私政策 和我们的 服务条款 。强制性信息可在 法律声明