第五章:模型训练与部署
5.1 模型训练流程
模型训练是人工智能应用中的核心步骤之一,它决定了模型的性能和适用性。一个完整的模型训练流程通常包括数据准备、模型定义、损失函数选择、优化器设置、训练迭代和评估等关键环节。首先,模型的训练依赖于高质量的大规模数据集。数据的多样性、标注的准确性以及与目标任务的匹配度会直接影响模型的学习效果。因此,数据准备通常包括数据清洗、预处理、数据增强等步骤,确保训练数据符合模型需求。
在数据准备之后,下一步是定义模型的结构。对于深度学习模型来说,这通常意味着选择适当的神经网络架构,如卷积神经网络(CNN)、循环神经网络(RNN)或基于 Transformer 的架构。根据任务的不同,模型的设计会有较大差异,通常需要考虑模型的深度、参数数量、特征提取方式等。模型结构的选择会直接影响训练过程中的计算复杂度和模型的泛化能力。
最后,训练过程中的关键环节是选择损失函数和优化器。损失函数是衡量模型预测与真实标签之间差异的指标,常见的损失函数有均方误差(MSE)、交叉熵(Cross-Entropy)等。优化器则负责调整模型的权重参数,常见的优化器有随机梯度下降(SGD)、Adam 等。通过不断调整模型参数,模型的损失逐渐减少,预测能力逐步提升。训练结束后,通常会进行验证和评估,确保模型在测试数据上表现良好。
# 分布式训练技术原理
- 数据并行
- FSDP
- FSDP算法是由来自DeepSpeed的ZeroRedundancyOptimizer技术驱动的,但经过修改的设计和实现与PyTorch的其他组件保持一致。FSDP将模型实例分解为更小的单元,然后将每个单元内的所有参数扁平化和分片。分片参数在计算前按需通信和恢复,计算结束后立即丢弃。这种方法确保FSDP每次只需要实现一个单元的参数,这大大降低了峰值内存消耗。(数据并行+Parameter切分)
- DDP
- DistributedDataParallel (DDP), **在每个设备上维护一个模型副本,并通过向后传递的集体AllReduce操作同步梯度,从而确保在训练期间跨副本的模型一致性** 。为了加快训练速度, **DDP将梯度通信与向后计算重叠** ,促进在不同资源上并发执行工作负载。
- ZeRO
- Model state
- Optimizer->ZeRO1
- 将optimizer state分成若干份,每块GPU上各自维护一份
- 每块GPU上存一份完整的参数W,做完一轮foward和backward后,各得一份梯度,对梯度做一次 **AllReduce(reduce-scatter + all-gather)** , **得到完整的梯度G,由于每块GPU上只保管部分optimizer states,因此只能将相应的W进行更新,对W做一次All-Gather**
- Gradient+Optimzer->ZeRO2
- 每个GPU维护一块梯度
- 每块GPU上存一份完整的参数W,做完一轮foward和backward后, **算得一份完整的梯度,对梯度做一次Reduce-Scatter,保证每个GPU上所维持的那块梯度是聚合梯度,每块GPU用自己对应的O和G去更新相应的W。更新完毕后,每块GPU维持了一块更新完毕的W。同理,对W做一次All-Gather,将别的GPU算好的W同步到自己这来**
- Parameter+Gradient+Optimizer->ZeRO3
- 每个GPU维护一块模型状态
- 每块GPU上只保存部分参数W,做forward时,对W做一次 **All-Gather** ,取回分布在别的GPU上的W,得到一份完整的W, **forward做完,立刻把不是自己维护的W抛弃,做backward时,对W做一次All-Gather,取回完整的W,backward做完,立刻把不是自己维护的W抛弃. 做完backward,算得一份完整的梯度G,对G做一次Reduce-Scatter,从别的GPU上聚合自己维护的那部分梯度,聚合操作结束后,立刻把不是自己维护的G抛弃。用自己维护的O和G,更新W。由于只维护部分W,因此无需再对W做任何AllReduce操作**
- Residual state
- activation->Partitioned Activation Checkpointing
- 每块GPU上只维护部分的activation,需要时再从别的地方聚合过来就行。需要注意的是,activation对显存的占用一般会远高于模型本身,通讯量也是巨大的
- temporary buffer->Constant Size Buffer
- 提升带宽利用率。当GPU数量上升,GPU间的通讯次数也上升,每次的通讯量可能下降(但总通讯量不会变)。数据切片小了,就不能很好利用带宽了。所以这个buffer起到了积攒数据的作用:等数据积攒到一定大小,再进行通讯。
- 使得存储大小可控。在每次通讯前,积攒的存储大小是常量,是已知可控的。更方便使用者对训练中的存储消耗和通讯时间进行预估
- unusable fragment->Memory Defragmentation
- 对碎片化的存储空间进行重新整合,整出连续的存储空间。防止出现总存储足够,但连续存储不够而引起的存储请求fail
- offload
- ZeRO-Offload
- **forward和backward计算量高** ,因此和它们相关的部分,例如参数W(fp16),activation,就全放入GPU
- **update的部分计算量低** ,因此和它相关的部分,全部放入CPU中。例如W(fp32),optimizer states(fp32)和gradients(fp16)等
- ZeRO-Offload 分为 Offload Strategy 和 Offload Schedule 两部分,前者解决如何在 GPU 和 CPU 间划分模型的问题,后者解决如何调度计算和通信的问题
- ZeRO-Infinity
- 一是将offload和 ZeRO 的结合从 ZeRO-2 延伸到了 ZeRO-3,解决了模型参数受限于单张 GPU 内存的问题
- 二是解决了 ZeRO-Offload 在训练 batch size 较小的时候效率较低的问题
- 三是除 CPU 内存外,进一步尝试利用 NVMe 的空间
- 模型并行
- tensor-wise parallelism
- MLP切分
- 对第一个线性层按列切分,对第二个线性层按行切分
- ![图片](./img/分布式训练技术原理-幕布图片-36114-765327.jpg)
- ![图片](./img/分布式训练技术原理-幕布图片-392521-261326.jpg)
- ![图片](./img/分布式训练技术原理-幕布图片-57107-679259.jpg)
- self-attention切分
- attention的多头计算天然适合tensor并行,因为每个头上都可以独立计算最后再将结果concat起来,从而 **可以把每个头的参数放到一块GPU上**
- 对线性层, **按照“行切割”** 。切割的方式和MLP层基本一致,其forward与backward原理也一致
- 输入层Embedding切分
- 对positional embedding来说,max_s本身不会太长,因此每个GPU上都拷贝一份,对显存的压力也不会太大
- 将word embedding拆分到不同GPU上,每块GPU维护一分部词表。当输入X去GPU上查找时,能找到的词,就正常返回词向量,找到不到就把词向量中的全部全素都置0。按此方式查找完毕后,每块GPU上的数据做一次AllReduce,就能得到最终的输入。
- ![图片](./img/分布式训练技术原理-幕布图片-220157-552735.jpg)
- 输出层Embedding切分
- **输入层和输出层共用一个word embeding**
- **当模型的输入层到输入层都在一块GPU上时(即流水线并行深度=1),我们不必担心这点(实践中大部分用Megatron做并行的项目也是这么做的)。但若模型输入层和输出层在不同的GPU上时,我们就要保证在权重更新前,两块GPU上的word embedding梯度做了一次AllReduce** 。
- ![图片](./img/分布式训练技术原理-幕布图片-42284-124759.jpg)
- cross-entroy
- ![图片](./img/分布式训练技术原理-幕布图片-124076-270516.jpg)
- ![图片](./img/分布式训练技术原理-幕布图片-838373-426344.jpg)
- [pipeline paralelism]("https://zhuanlan.zhihu.com/p/629637468")
- GPipe
- PipeDream
- 1F1B
- 每个 GPU 以交替的方式执行每个 micro batch 的正向和反向过程,以尽早释放其占用的显存,进而减少显存占用
- ![图片](./img/分布式训练技术原理-幕布图片-20096-279847.jpg)
- 1F1B 并不能减少 bubble time, **为了进一步减少 bubble time,Megatron 又提出了 interleaved 1F1B 模式** 。也就是原本每个 GPU 负责连续 4 个层的计算,现在变成负责连续两个层的计算,只有原来的一半,从而 bubble time 也变成了原来的一半,即把一个设备上连续的层划分为若干不连续的层,负责的数量不变,但顺序变了。
- ![图片](./img/分布式训练技术原理-幕布图片-618350-869132.jpg)
- DAPPLE
- ![图片](./img/分布式训练技术原理-幕布图片-906937-836104.jpg)
- layer-wise parallelism
- sequence parallelism
- Sequence 并行的好处在于不会增加通信量,并且可以大大减少显存占用
- Layer-norm 和 Dropout 沿着序列的维度是独立的,因此可以按照 Sequence 维度进行拆分
- 使用了 Sequence 并行之后,对于超大规模的模型而言,其实显存占用量还是很大的。因此,Megatron 又引入了激活重计算技术,找到一些计算量很少但显存占用很大的算子,比如 Attention 里的 Softmax、Dropout 等算子,对这些算子进行激活重计算就可以显著减少显存,并且计算开销增加不大
- MoE
- 核心思想:将大模型拆分成多个小模型。每个样本只需要激活部分专家模型进行计算,从而大大节省计算资源。 **MoE 的基本思路是通过宽度换取深度,因为模型深度越深,计算层数越多,进而推理时间越长**
- Hard Gate MoE
- Sparse MoE
- 5. PEFT
- Lora类
- LoRA
- 用两个低秩矩阵替代待更新的权重矩阵的增量
- QLoRA
- 4 bit NormalFloat(NF4) 量化和双量化
- 引入了分页优化器,以防止梯度检查点期间的内存峰值
- AdaLoRA
- 用奇异值分解P \ Gamma Q代替AB,根据loss梯度评估对角线上值进行重要性评分,根据评分动态分配参数预算给权重矩阵
- AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练
- IA3
- 通过学习向量来对激活层加权进行缩放
- 学习到的向量被注入到attention和feedforward模块中
- ReLoRA
- **ReLoRA在合并和重新启动期间可以对优化器进行部分重置** ,并在随后的预热中过程中将学习率设置为0。 **具体来说,作者提出了一种锯齿状学习率调度算法**
- 出发点:通过不断叠加LoRA训练过程来达到更好的训练效果, **首先需要对LoRA过程进行重新启动,想要对已经完成的LoRA过程重新启动并不容易,这需要对优化器进行精细的调整,如果调整不到位,会导致模型在重启后立即与之前的优化方向出现分歧**
- Prompt类
- prompt tuning
- 在输入层加一个embedding层
- P-tuning
- 在输入层加一个embedding和一个LSTM或MLP
- prefix tuning
- 在每一层加入一个embedding和一个MLP
- P-tuning v2
- 在每一层都加一个embedding层
- Adapter类
- Adapter Tuning
- 针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后)
- Adapter Fusion
- 在 Adapter 的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现
- Adapter Drop
- 在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率
- 其他
- BitFit
- 疏的微调方法,它训练时只更新bias的参数或者部分bias参数
- 混合式
- MAM Adapter
- 用 FFN 层的并行Adapter和软提示的组合
- UniPELT
- 门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关
# 大模型指令对齐训练原理
- RLHF
- SFT
- RM
- PPO
- AIHF-based
- RLAIF
- 核心在于通过AI 模型监督其他 AI 模型,即在SFT阶段,从初始模型中采样,然后生成自我批评和修正,然后根据修正后的反应微调原始模型。在 RL 阶段,从微调模型中采样,使用一个模型来评估生成的样本,并从这个 AI 偏好数据集训练一个偏好模型。然后使用偏好模型作为奖励信号对 RL 进行训练
- ![图片](./img/大模型指令对齐训练原理-幕布图片-17565-176537.jpg)
- ![图片](./img/大模型指令对齐训练原理-幕布图片-95996-523276.jpg)
- ![图片](./img/大模型指令对齐训练原理-幕布图片-349153-657791.jpg)
- RRHF
- RRHF( **R** ank **R** esponse from **H** uman **F** eedback) 不需要强化学习,可以利用不同语言模型生成的回复,包括 ChatGPT、GPT-4 或当前的训练模型。RRHF通过对回复进行评分,并通过排名损失来使回复与人类偏好对齐。RRHF 通过通过排名损失使评分与人类的偏好(或者代理的奖励模型)对齐。RRHF 训练好的模型可以同时作为生成语言模型和奖励模型使用。
- ![图片](./img/大模型指令对齐训练原理-幕布图片-805089-731888.jpg)
- SFT-only
- LIMA
- LIMA(Less Is More for Alignment) 即浅层对齐假说,即一 **个模型的知识和能力几乎完全是在预训练中学习的,而对齐则是教会它与用户交互时如何选择子分布** 。如果假说正确,对齐主要有关于学习方式,那么该假说的一个推论是,人们可以用相当少的样本充分调整预训练的语言模型。因此, **该工作假设,对齐可以是一个简单的过程,模型学习与用户互动的风格或格式,以揭示在预训练中已经获得的知识和能力。**
- LTD Instruction Tuning
- ![图片](./img/大模型指令对齐训练原理-幕布图片-759487-923925.jpg)
- Reward-only
- DPO
- DPO(Direct Preference Optimization) 提出了一种使用二进制交叉熵目标来精确优化LLM的方法,以替代基于 RL HF 的优化目标,从而大大简化偏好学习 pipeline。也就是说,完全可以直接优化语言模型以实现人类的偏好,而不需要明确的奖励模型或强化学习。
- DPO 也依赖于理论上的偏好模型(如 Bradley-Terry 模型),以此衡量给定的奖励函数与经验偏好数据的吻合程度。然而,现有的方法使用偏好模型定义偏好损失来训练奖励模型,然后训练优化所学奖励模型的策略,而 DPO 使用变量的变化来直接定义偏好损失作为策略的一个函数。鉴于人类对模型响应的偏好数据集,DPO 因此可以使用一个简单的二进制交叉熵目标来优化策略,而不需要明确地学习奖励函数或在训练期间从策略中采样。
- RAFT
- ![图片](./img/大模型指令对齐训练原理-幕布图片-350029-666381.jpg)
- 参考文献
- [反思RLHF]("https://mp.weixin.qq.com/s/e3E_XsZTiNMNYqzzi6Pbjw")
- [RLHF笔记]("https://mathpretty.com/16017.html")
- [hf-blog]("https://huggingface.co/blog/zh/rlhf")
- ** [RLHF代码详解]("https://zhuanlan.zhihu.com/p/624589622")
LoRA(Low-Rank Adaptation)是一种针对大规模预训练模型的高效微调方法。它通过对模型的权重进行低秩分解来减少训练时的参数更新,从而提高训练效率。LoRA 主要应用于语言模型等大规模模型的微调中,尤其适用于参数量巨大的情况。
LoRA 代码示例
以下是一个简单的 LoRA 实现示例,演示了如何在 PyTorch 中应用 LoRA 对线性层进行低秩适配。这个示例展示了如何将 LoRA 应用于线性层的权重,通过引入低秩矩阵来减少训练时需要更新的参数数量。
import torch
import torch.nn as nn