为应对这一挑战,PaddleNLP大语言模型套件针对大规模训练场景,研发并开源了大模型统一存储技术—— Unified Checkpoint。该技术集训推一体、异步保存、快速恢复、无损压缩等多重优势于一身,显著优化了 大模型训练流程。以下是其主要功能亮点:
工业级的大模型训练根据机器数量的变化,会涉及多种分布式策略的灵活组合和调整。Unified Checkpoint通过存储格式与分布式策略的解耦设计,支持Checkpoint在不同分布式策略间的自动切换, 用户无需感知这一变化,可显著提升大模型恢复训练的灵活性与可扩展性。
传统上,训练阶段Checkpoint的参数结构与推理阶段参数切分格式往往不相同,导致两者间额外的转换成本。PaddleNLP Unified Checkpoint实现了训练与推理参数格式的无感切换,极大降低了两者衔接的复杂度,进一步提升了PaddleNLP套件的便捷性。
大模型Checkpoint存储技术面临诸多挑战,特别是对于大规模分布式训练而言:
为了解决上述问题,我们提出了Unified Checkpoint统一存储的方案。
在Checkpoint存储格式上,我们在⻜桨框架原先的存储协议上,针对大模型引入了Safetensors作为Unified Checkpoint的序列化保存格式。使⽤Safetensors格式具有非常多的优势,具体可⻅下图:
https://github.com/huggingface/safetensors
Safetensors的优势主要有:
基于上述的这些特性,Unified Checkpoint的存储格式采用了Safetensors格式。
原始的Checkpoint存储⽅式,在存储时会按照实际使用的不同分布式策略进行保存,从而导致在进行分布式策略切换时难以灵活扩展。
具体⻅下图,固定形式的Checkpoint存储格式使得我们难以灵活应对不同的分布式情况,往往需要⼈工定制相应转换脚本,导致可扩展性低。下面是原始Checkpoint格式无法扩展的示意图。
Unified Checkpoint 设计了存储与分布式策略解耦的方案,做到Checkpoint灵活扩展的效果。其中最核心的模块是参数路由表的更新,路由表包含了模型参数名称、文件路径、机器结点三个关键信息。
在分布式训练中训练节点在加载(Load)模型⽂件阶段,通过路由表获取模型参数所在节点位置以及参数文件名称,通过网络传输获取模型参数;当分布式策略发生发变化模型参数的分布也随之变化,模型参数在保存(Save)模型文件阶段,各个节点需要更新参数的所在节点以及模型所在文件信息到全局路由表。
在Unified Checkpoint的设计原则中,需要确保每个参数被保存时需要是一个完整的张量,而不是被多个节点切分保存,这样可以做到存储下来的Checkpoint文件与分布式策略解耦。
如果同一个参数被多个节点保存,那在分布式策略发生变化时参数的切分将会极为复杂。上图中我们通过Gather的通信将参数进行融合,然后再将参数信息同步到路由表中。
同时为了加快模型参数的保存,每个worker进程都会并发保存部分的完整张量,提升保存效率,下面是参数融合的示意图。
在Checkpoint加载过程中,我们可以具体区分为两种情况,分别表示原地加载和动态加载。
我们将模型的 Checkpoint 通过 Unified Checkpoint 技术转换为 Safetensors 格式进行保存,这种统一的存储⽅案具备高度的灵活性和兼容性,可以无缝衔接到模型推理的不同环节,⽆论是在动态图直接推理,还是在将动态图转换为静态图的过程中,均能实现平滑切换。
这一特性消除了用户手动处理参数合并或切分的繁琐操作,不仅简化了使用流程,还显著提升了开发和部署效率,为⼤模型下游应⽤提供了更加便捷和高效的 支持。
除了统⼀训练推理存储格式,支持灵活切换不同的分布式策略以外,我们还针对Checkpoint存储速度和存储空间进行了优化。⼀般的Checkpoint存储⽅式往往⾯临两⼤挑战:
为了解决上述两个问题,我们分别进行了针对性解决和优化,最终使得Unified Checkpoint的存储效率相⽐原先最大可加速 95 %,存储空间最高可节省 78.5 %。
通常情况下,模型训练和模型存储是同步进行的。然而,在保存模型Checkpoint时,传统的做法会中断GPU训练进程以进行模型保存,这往往导致训练效率显著降低。具体来说,保存Checkpoint通常包含两个关键阶段:1.显存拷贝操作(D2H Copy):将GPU显存中的参数拷贝到主机内存。
2.模型参数持久化(Save to Disk):将内存中的模型参数通过序列化方式保存到硬盘中。
由于这两个阶段均涉及IO操作,因此存在将计算操作(训练)与IO操作(模型保存)并行的可能性,通过重叠(Overlap)这两种操作来减少存储开销。为了实现这一目标,我们采用了异步存储的流水线方法。
通过开辟异步存储⼦进程,我们显著降低了主进程被阻塞的时间,从而提升了系统整体的吞吐量。值得注意的是,显存拷贝操作(D2H Copy)需要在训练进程中执行,而异步存储子进程则需要访问主进程中的模型参数内存。
因此,在第一次进行Checkpoint保存 时,我们会分配一段连续且固定的共享内存作为主机端的存储位置。主进程将GPU端的数据拷贝到这段共享内存后,异步进程会从共享内存中读取数据,并将其持久化到磁盘。最终,PaddleNLP Unified Checkpoint的异步存储架构可简单描述如下:
在实际的存储测试中,我们对不同规模的模型进行了存储对⽐测试。以下表格对⽐中,保存介质均为NVMe SSD。我们目前测试情况下,发现存储耗时最大可减少95%。
(模型的保存时间和模型尺⼨、分布式策略有关,不⼀定和尺⼨完全成正⽐例关系)
在大模型训练过程中,为了能够在训练中断后从最新的Checkpoint快速恢复,我们需要不断地保存模型训练的Checkpoint。理论上,保存的Checkpoint频次越⾼,恢复训练时所需重训的step就越少。
但是大模型的 Checkpoint会占用大量的磁盘空间,从⽽限制了能够保存的Checkpoint数量。那么,我们是否可以对模型的 Checkpoint进行压缩以节省空间呢?当我们使⽤AdamW优化器和混合精度策略来训练一个参数量为Φ的⼤模型时,模型参数和优化器状态的总占⽤预计会达到14Φ的大小。
72B参数的模型,会占用接近1TB的磁盘空间。从下图展示的Checkpoint各权重参数所占⽤的空间量可以看出,FP32 格式的模型参数、动量1和动量2占据了绝大部分的磁盘空间。因此,这部分是我们需要重点优化的对象。
大模型训练常⽤的优化器为 Adam 优化器,其中会维护一二阶优化器动量权重:momentum 和 variance,每次对模型权重的更新需要先根据一二阶动量计算出 Adam 更新率:
Adam_ratio = momentum/(sqrt(variance) + ϵ)
最终以下公式更新模型权重:
θt = θt−1 − γ ∗ Adam_ratio
通过大量的推导和实验我们在PaddleNLP套件提供了两种Checkpoint量化的⽅法,即 Checkpoint O1、 O2方法,分别对优化器权重参数进行 INT8、INT4 的优化器压缩。
Checkpoint O1 压缩和恢复方法
使⽤channel-wise对称均匀量化方法,以权重的channel维度为粒度计算每个 channel 的最大绝对值,得到这个 channel 的 scales 张量(FP32)。通过 scales 张量,以公式:
quant_weight = clip(round(weight/scales ∗ bcnt), −bnt − 1, bnt)
其中bnt = 2quant_bit−1 − 1
将优化器的一阶动量(momentum)从 FP32 量化为 INT8 数据格式。最终 Checkpoint 中只需要存储INT8 类型的一阶动量与其对应的量化 scales。
实验中发现,独立量化一阶动量和二阶动量,恢复后计算出来的 Adam 更新率会因量化损失大幅振荡。因此本方法不直接量化二阶动量,⽽采取直接量化 Adam更新率中的部分:
1/(sqrt(v) + ϵ)
这⾥采取飞对称均匀量化法将其从 FP32 量化为INT8数据格式。量化完成后,原本 FP32 数据类型的⼀一二阶动量量化为 INT8 数据类型的格式保存,存储空间变为原来的 25%。
variance = (1/(ratio + ϵ) − ϵ)2
Checkpoint O2 压缩和恢复方法
O2 压缩⽅式中,对一阶动量进⾏ block-wise 的 INT4 对称均匀量化,对 Adam 更新率进行 block-wise 的 INT4 ⾮对称均匀量化,此外为了更好的保存数据,本方法通过二进制移位的⽅式将两个 INT4 数据合并成⼀个 INT8 数据来保存,进⼀步提升Checkpoint压缩率。
与 O1 压缩恢复类似,但在Checkpoint恢复阶段,首先会将 INT8 数据类型的一阶动量和 Adam 更新率合并张量根据位运算恢复成 2 份 INT4 张量,再根据各自的scales反量化为对应的 FP32 格式。最后通过 FP32 的 Adam 更新率重新计算二阶动量。
总方法示意图如下:
对于压缩可能带来的精度损失,我们使⽤ Llama3-8B 在 6 个数据集上进行了共计 1000 个 steps 的SFT训 练,其中会在第 500 个 steps 时进行 Checkpoint 保存并强行让训练从 Checkpoint 中恢复,由下表所示,使⽤Checkpoint O1 和 Checkpoint O2 压缩算法后,模型训练精度是基本无损的,最终评估精度误差在千分位以下。
从上面的表格来看 Checkpoint O1 和 Checkpoint O2算法在恢复训练后整体对模型的精度无影响。
想让原本1000GB 的 Checkpoint 瘦身成不到 300GB 么,只需三行!通过以下命令可快速体验 Unified Checkpoint 的使用。
skip_save_model_weight: 当master_weights存在时,跳过保存模型权重,与remove_master_weight 不兼容开启。
master_weight_compatible: 1. 仅当optimizer需要master_weights时,才进⾏加载;2. 如果Checkpoint中不存在master_weights,则将model weight作为master_weights进⾏加载。
remove_master_weight: 是否保存 master weight, 如果Checkpoint中不存在master_weights,则将model weight作为master_weights进⾏加载。
async_save: 在保存Checkpoint⾄磁盘时做异步保存,不影响训练过程,提⾼训练效率。
python -u -m paddle.distributed.launch \
--gpus "0,1,2,3,4,5,6,7" \
run_finetune.py \
./config/llama/sft_argument.json \
--unified_Checkpoint 1 \
--unified_Checkpoint_config "async_save remove_master_weight" \
--ckpt_quant_stage "O1"
更多参数配置选项可参考
https://github.com/PaddlePaddle/PaddleNLP/blob/develop/docs/trainer.md
PaddleNLP Unified Checkpoint是针对大模型大规模分布式训练设计和实现的开源存储工具,可以自适应感知分布式训练策略的组合变化,还可以通过异步保存策略以及⽆损压缩算法实现快速存储、降低存储空间。
在性能收益方面,Unified Checkpoint通过其独特的异步保存机制和无损压缩算法,实现了存储速度的⼤幅提升和存储空间的显著节省。
异步存储技术使得模型训练与保存操作能够并行进行,大幅减少了训练过程中的等待时间,根据测试数据,存储耗时减少最高可达95%,这意味着训练过程更加流畅,训练资源的利⽤率得到了极大提高。同时,⽆损压缩算法的应用使得Checkpoint的存储空间需求大幅降低,最高可节省78.5%的存储空间。
在使用效果方面,Unified Checkpoint的统一存储格式和分布式策略解耦设计,使得模型在不同分布式策略间切换变得轻松自如,无需担⼼因策略变化而导致的恢复训练难题。这⼀特性极大地增强了训练的灵活性和可扩展性,使得⽤户能够根据实际资源情况灵活调整训练策略,而无需担⼼存储格式的兼容性问题。
此外,训练和推理模型存储格式的无缝切换,更是为⽤户提供了从训练到部署的一站式解决⽅案,简化了模型应用的复杂度,提高了开发和部署效率。
综上所述,PaddleNLP Unified Checkpoint以其卓越的性能收益和便捷的使⽤效果,为大型语言模型的训练与部署提供了强有力的⽀持。
它不仅解决了大规模训练中存储效率和存储空间的瓶颈问题,还通过其灵活性和可扩展性,为用户带来了更加⾼效、便捷的训练体验。
Unified Checkpoint使用文档:https://paddlenlp.readthedocs.io/zh/latest/llm/docs/unified_Checkpoint.html
Paddle 链接:https://github.com/PaddlePaddle/Paddle
PaddleNLP 链接:https://github.com/PaddlePaddle/PaddleNLP