2026/3/15 14:26:22
网站建设
项目流程
开个小网站要怎么做的,门户网站怎么建设,爱站网是怎么回事,无上升级系统目录 文章目录目录经典优化方向显存优化技术训练优化器ZeROCheckpointing activation混合精度训练计算优化技术降低计算精度#xff08;Precision Reduction#xff09;算子融合#xff08;Kernel Fusion#xff09;重计算/激活检查点#xff08;Recomputation/Activation…目录文章目录目录经典优化方向显存优化技术训练优化器ZeROCheckpointing activation混合精度训练计算优化技术降低计算精度Precision Reduction算子融合Kernel Fusion重计算/激活检查点Recomputation/Activation Checkpointing内存访问合并Memory Coalescing分块计算Tiling经典优化方向GPU 的操作可以分为 3 类计算类COMP执行矩阵乘法等数值计算负责模型的所有数值运算处理。通信类COMM负责 GPU 设备间的数据交换与同步通常使用 NCCL 库。访存类MEM管理 GPU 内存分配与释放处理主机与设备间的数据传输 H2D/D2D/D2H 等等。理想的状态下我们需要 GPU 的计算类工作始终在执行。但计算收到通信和访存的制约所以如何权衡 3 者之间的协同工作就是性能优化的主要目的。显存优化技术显存优化技术包括 ZeRODistributed Optimizer、Checkpoint Activations、混合精度训练、Kernel Fusion 和 Flash Attention 等。训练优化器在 AI/ML 中梯度下降Gradient Descent是一种关键的 loss 损失函数极值优化方法根据使用的数据量不同梯度下降可以分为 3 种不同的变体Batched 梯度下降Batch Gradient Descent每次更新权重时使用整个训练集来计算损失函数的梯度。假设有 N 个样本则每个 Weight 在反向传播后都有 N 个梯度会先计算 N 个梯度的平均然后使用平均值更新 Weight。优点由于使用所有的训练数据梯度估计非常准确收敛过程稳定。缺点当训练数据集很大时每次计算梯度都非常耗时而且内存需求高不适合处理大规模数据。随机梯度下降Stochastic Gradient DescentSGD每次更新模型参数时只使用单个训练样本来计算梯度。每个 Weight 在反向传播后都只有 1 个梯度直接使用这 1 个梯度更新 Weight。优点只用一个样本进行更新所以计算速度快适合大规模数据集且内存占用较小。缺点由于梯度是基于单个样本计算的梯度估计不准确容易导致梯度更新过程中的 “噪声”使得收敛过程不稳定并可能在接近最优解时出现振荡。Mini-batch 梯度下降Mini-batch Gradient Descent介于 Batched 梯度下降和随机梯度下降之间。每次更新模型参数时使用一小部分训练数据即 Mini-batch来计算梯度。优点Mini-batch 梯度下降结合了全量梯度下降和随机梯度下降的优点计算速度比全量梯度下降快同时比随机梯度下降更加稳定减少了更新中的“噪声”。缺点虽然它比 SGD 更稳定但仍然可能面临一个 mini-batch 中样本不够多导致梯度估计仍有一定的偏差。但实际上上述传统的梯度下降优化算法在 DL 实践中非常低效且复杂。因为每个参数都有自己的 “梯度方向” 和 “学习率步长”有些参数可能需要更快地更新而另一些则需要更慢、更稳定如下图所示。而训练优化器就是一种专用于高效更新 Weight、优化 loss 损失函数的自适应学习率的优化算法其核心目标是自适应学习率即为每个参数自动计算其独特的学习率。常见的有 AdamAdaptive Moment estimation自适应矩估计优化器它是一个结合了动量Momentum和自适应学习率RMSprop技术的优化算法其旨在让模型训练得更快、更稳减少人为调参的工作量广泛用于 DL 的训练场景。动量Momentum机制管理 “梯度方向”在正确的方向加速而在不稳定方向减速能够有效缓解局部极小值问题。自适应学习率RMSprop机制管理 “学习率步长”根据历史梯度的大小为每个参数自适应地调整学习率。例如如果一个参数的历史梯度一直很大说明它很不稳定则应该给它一个很小的学习率避免它 “跳过头”。多种优化算法的比较如下图所示。Adam 优化器的核心优势在于能够根据参数的更新历史自适应调整每个参数的学习率这有助于加快收敛速度并提高训练稳定性。为了实现这一点Adam 优化器会在 GPU 显存中维护 2 份额外的状态数据参数矩阵m_t 和 v_t直到权重参数更新完成。并且这 2 份状态数据的大小和权重参数量一致所以在计算 GPU 显存资源时需要乘以优化器的份数。一阶矩m_tMomentum作用于动量机制是梯度的一阶指数移动平均它记住了梯度的主要方向起到了平滑噪声、正确方向加速的作用。二阶矩v_tVariance作用于 RMSProp 机制是梯度平方的二阶指数移动平均它记住了梯度的变化幅度起到了在陡坡小步走、缓坡大步走的作用。对应的Adam 优化器有几个关键的超参数可以被调节β₁Beta1一阶矩的衰减率默认为 0.9。控制着“速度”的记忆周期。β₂Beta2二阶矩的衰减率通常设置为 0.999。这个值非常接近 1意味着它对历史梯度平方的记忆很长这使得学习率调整非常平滑。εEpsilon一个非常小的数如 1e-8主要是为了防止除以零的错误。Pytorch 的 Adam 优化器实现https://docs.pytorch.org/docs/stable/generated/torch.optim.Adam.html虽然 Adam 优化算法相较 SGD 算法效果更好也更稳定但 是对计算设备内存的占用显著增大。ZeRO零冗余优化器Zero Redundancy Data ParallelismZeRO的目标是针对模型状态的存储进行去除冗余的优化。ZeRO 使用分区的方法即将模型状态量分割成多个分区每个计算设备只保存其中的一部分。这样整个训练系统内只需要维护一份模型状态减少了内存消耗和通信开 销。在模型训练时Optimizer 状态是模型固定占用显存的主要部分。假如模型参数量是 m则 Optimizer 的显存开销是 16*m 字节。Zero-1 的思想是在不同的 DP rank 上对 Optimizer 状态做拆分所以 Distributed OptimizerZero-1在每个 DP rank 占用的显存是 16 * m 除以 DP size明显降低了显存开销同时也带来了通信模式的改变。例如我们可以直接对梯度做 Reduce-scatter之后再对自己的那一部分参数做Optimizer 相关的状态更新Optimizer 状态更新完毕后再用一个 All-gather 操作收集模型权重。这样由 DP 并行的一个 All-reduce 变成了一个 Reduce-scatter 加上一个 All-gather。根据前面的介绍这个 All-reduce 的通信量是 Reduce-scatter 或 All-gather 的两倍所以整体的通信量是没有变化的但通信的次数变多了。其次使用比较多的是 Zero-2 和Zero-3。Zero-2 和 Zero-3 需要每次进行额外的 forward 和 backward 计算并且每次都需要做通信但是流水线并行会将一个大的 batch 拆分成很多个小的 forward 和 backward也就会造成大的通信量。所以当同时使用 Zero-2 或 Zero-3 加上流水线并行时通信量会大幅上升因此这里不推荐大家同时使用流水线并行和 Zero-2 或 Zero-3但流水线并行可以和 Zero-1 同时使用。DP 是最常用的并行策略因为它与其他并行策略正交实现简单并且通信量相对不是很大很容易扩展训练的规模。但是 DP 也存在一个比较明显的问题在每个 DP Group 内都有完整的模型、优化器状态和梯度副本导致内存开销比较大。为了解决内存开销大的问题微软提出了 ZeRO可以根据不同的程度充分将优化器状态os、梯度g和模型参数p切分到所有的 GPU 中也就是不同的 DP Group 中会存储不同的优化器状态、梯度和参数切片。ZeRO-0禁用所有类型的分片仅做存粹的 DP。ZeRO-1P_os对优化器状态进行分片占用内存为原始的 1/4通信容量与数据并行性相同。将优化器状态切分到所有 GPU每块 GPU 还有全量的模型参数和梯度。先切分优化器状态是因为其占用内存更多并且与 Forward 和 Backward 的反向传播无关只影响 Backward 的权重参数更新阶段。由于 ZeRO-1 中每个 GPU 只需要对应部分的平均梯度而不像传统 DP 那样需要梯度的 all-gather因此总的通信量不变。也就是说在极大降低显存开销的情况下并不会增加通信量所以常见的并行方案中基本都会默认采用 ZeRO-1。ZeRO-2P_osg对优化器状态和梯度进行分片占用内存为原始的 1/8通信容量与数据并行性相同。在 ZeRO-1 的基础上进一步切分梯度切分梯度不影响 Forward 过程。ZeRO-3P_osgp对优化器状 态、梯度及模型参数进行分片内存减少与数据并行度和复杂度成线性关系同时通信容量是数 据并行性的 1.5 倍。在 ZeRO-2 的基础上进一步切分模型参数会影响 Forward 阶段需要 all-gather 所有参数才能计算会引入更多通信。采用 ZeRO-3 几乎可以将内存需求降低到 1/N其中 N 表示 GPU 数量。ZeRO-Infinity是 ZeRO-3 的拓展允许通过使用 NVMe 固态硬盘扩展 GPU 和 CPU 内存来训练大语言模型。对 Adam 优化器状态进行分区图中的 Pos 部分。模型参数和梯度依然是每个计算设备保存一份。此时每个计算设备所需内存是 4Φ 12Φ/N 字节其中 N 是计算设备总数。当 N 比较大时每个计算设备占用内存趋向于 4ΦB也就是 16ΦB 的 1/4。对模型梯度进行分区图中的 Posg 部分。模型参数依然是每个计算设备保存一份。此时每个计算设备所需内存是 2Φ (2Φ12Φ)/N 字节。当 N 比较大时每个计算设备占用内存趋向于 2ΦB也就是 16ΦB 的 1/8。对模型参数进行分区图4.17 中的 Posgp 部分。此时每个计算设备所需内存是 16Φ/N B。当 N 比较大时每个计算设备占用内存趋向于 0。Zero-1 和 Zero-2 对整体通信量没 有影响虽然对通信有一定延迟影响但是整体性能受到的影响很小。Zero-3 所需的通信量则是 正常通信量的 1.5 倍。Checkpointing activation其中 Selective Activation Checkpoint 是目前 Megatron 中用的比较多的也是比较高效的一个 Checkpoint 技术。Checkpointing activation 就是做重新计算。例如在 Forward 计算时得到的 Activation 不再保留做 Backward 计算时对这些 Activation 进行重新计算这样可以极大程度上减少对 GPU 显存的开销。Checkpointing activation 的实现方式有下边示意图列出来的几种。其中一种比较 Native 的实现是 Full checkpointing也即对 Transformer 的每个层都进行重新计算。例如在最后一层做 Backward 计算时需要这个 Transformer layer 在 Backward 计算之前重新执行一次 Forward 计算当重新计算 Forward 后再开始这个层的 Backward 计算。Full checkpointing 对每个 Transformer layer 都打了一个重算点。所以 Full checkpointing 的好处在于将显存开销降低到 O(n) 的复杂度而不足在于对每个 Transformer layer 都要重新计算一遍从而带来了近 36% 的额外计算开销。另一个优化 Activation 的方式是 Sequence Parallelism 加上 Selective checkpointing将这个重算的开销从 36% 降低到 4%。Selective checkpointing 会选择一些重算性价比高的 OP对一些计算时间比较小但产生 Activation 占用的显存很大的 OP 进行重算。例如下边示例图左边的 Self-attention 模块通过对比分析后得出对 Self-attention 这块做重算的收益是非常高的因为它的计算量相对会少一点但它的一些中间结果输出占用的显存开销非常大。因此我们就可以只对这块做重算。对其他的层例如 Linear 和 Layernorm 层可以采用其他的优化方法对 Activation 进行优化。Selective checkpointing 的核心思想是对一些性价比高的 OP 做重算并与其他的并行优化方法联合使用达到 112 的效果。混合精度训练混合精度训练Mixed PrecisionTraining方式即同时存在F P3 与 FP16 或者 BF16 格式。FP32 中第 31 位为符号位第 30 位∼第 23 位用于表示指数第 22 位∼第 0 位用于表示尾数。FP16 中第 15 位为符号位第 14 位∼第 10 位用于表示指数第 9 位∼第 0 位用于表示尾数。BF16 中第 15 位为符号位第 14 位∼第 7 位用 于表示指数第 6 位∼第 0 位用于表示尾数。由于 FP16 的值区间比 FP32 的值区间小很多所以 在计算过程中很容易出现上溢出和下溢出。BF16 相较于 FP16 以精度换取更大的值区间范围。由 于 FP16 和 BF16 相较 FP32 精度低训练过程中可能会出现梯度消失和模型不稳定的问题因此 需要使用一些技术解决这些问题例如动态损失缩放Dynamic Loss Scaling和混合精度优化器Mixed Precision Optimizer等。混合精度优化的过程如下图所示。Adam 优化器状态包括采用 FP32 保存的模型参数备份 一阶动量和二阶动量也都采用 FP32 格式存储。假设模型参数量为 Φ模型参数和梯度都是用 FP16 格式存储则共需要 2Φ 2Φ (4Φ 4Φ 4Φ) 16Φ 字节存储。其中Adam 状态占比 75%。动态损失缩放在反向传播前将损失变化dLoss手动增大 2K 倍因此反向传播时得到的激活函数梯度不会溢出反向传播后将权重梯度缩小 2K 倍恢复正常值。举例来说有 75 亿个参数 的模型如果用 FP16 格式只需要 15GB 计算设备内存但是在训练阶段模型状态实际上需要耗费 120GB 内存。计算卡内存占用中除了模型状态还有剩余状态Residual States包括激活值Activation、各种临时缓冲区Buffer及无法使用的显存碎片Fragmentation等。可以使用激活值检查点Activation Checkpointing方式使激活值内存占用大幅减少因此如何减少模型状态尤其是 Adam 优化器状态是解决内存占用问题的关键。计算优化技术降低计算精度Precision Reduction使用更低精度的数据类型FP16, BF16, INT8是最高效的 GPU 优化手段之一。其核心优势体现在两个方面减少内存带宽压力利用专用计算单元更低的数据精度意味着每个参数占用的比特数更少。在计算密集型任务中这意味着在计算量FLOPs不变的情况下需要从内存中读取和写入的数据量Bytes成比例减少。这直接降低了对内存带宽的压力对于内存瓶颈Memory-Bound的算子尤其有效。识别 memory bound 类型并做出针对性优化是关键。横轴计算强度代表每字节内存访问平均发生了多少次计算FLOPs/Byte。纵轴性能代表实际达到的计算性能GFLOPs/s。Roofline 模型是一种直观的性能分析模型。高效利用 GPU 的关键在于让计算任务处于计算瓶颈Compute-Bound区域而非内存瓶颈Memory-Bound区域。优化工作的核心就是通过各种手段将应用性能推向屋顶线。以一个简单的 ReLU 操作为例我们可以量化其计算强度Arithmetic Intensity即每字节内存访问对应的计算次数。FP32每次操作需要读写 8 字节数据执行 1 次浮点运算计算强度为 1⁄8 FLOPs/Byte。FP16每次操作需要读写 4 字节数据执行 1 次浮点运算计算强度为 1⁄4 FLOPs/Byte。如此精度减半计算强度翻倍程序更不容易受到内存带宽的限制。GPU Tensor Cores 旨在极大地加速特定精度的矩阵乘加MMA运算。它们采用混合精度计算模式以低精度如 FP16, BF16, INT8输入进行乘法但在高精度FP32累加器中进行求和从而在保证速度的同时最大限度地减少了精度损失。Tensor Core 接收两个 16-bit 的输入执行乘法后将结果与一个 32-bit 的累加值相加最终输出一个 32-bit 结果。这种设计使得 GPU 能够以远超通用计算单元CUDA Cores的速度执行矩阵运算。算子融合Kernel Fusion将多个连续执行的核函数Kernel合并为一个核函数。优势减少启动多个小核函数的开销。避免中间结果写回和读取慢速的全局内存直接在快速的寄存器或共享内存中进行数据传递。重计算/激活检查点Recomputation/Activation Checkpointing不保存 Forward Pass 中的中间激活值节省显存而是在 Backward Pass 的时候重新计算它们。这是一种用算力换显存的策略。原文https://dev-discuss.pytorch.org/t/min-cut-optimal-recomputation-i-e-activation-checkpointing-with-aotautograd/467内存访问合并Memory Coalescing组织线程的内存访问模式使得同一个线程束Warp中的线程访问全局内存中连续对齐的内存地址。这样多个内存请求可以被合并成一个大的事务极大提高内存带宽利用率。分块计算Tiling将大型数据集的计算分解为更小的 “块” 或 “瓦片 (Tile)”使其能够放入高速的共享内存或寄存器中进行计算。这是充分利用内存层次结构、减少低速全局内存访问的关键技术。