语言模型发展历程#
涌现能力(Emergent Ability) 指的是当模型扩展到一定规模时,模型的特定任务性能突然出现显著跃升的趋势。具体来说包括三种 - 上下文学习、指令遵循和逐步推理的能力。
扩展法则#
扩展法则(Scaling Law) 指的是在大语言模型中,模型的性能随着模型规模(N)、数据规模(D)和计算算力(C)的增长而呈现可预测的提升趋势。也就是在给定算力(FLOPs)的情况下,如何对其余参数进行合理的分配能够使得模型的性能最好。
记住几个核心结论:1) 对于仅编码器的模型来说,三种因素满足 ;2) 固定模型的总参数量,调整层数/深度/宽度对模型的性能影响很小;3) 当单个因素不受另外两个因素制约的时候,模型的性能与每个因素都呈现幂律关系;4) 为了提升模型性能,模型规模和数据规模需要同步放大。
推理阶段扩展法则#
增加并行搜索计算量 - 模型采样多个输出(Best-of-N、Beam Search、Lookahead Search),通过奖励模型(Verifier)来选择最优的输出。训练奖励模型有两种方法:
- 结果奖励模型(ORMs) - 只关心最终答案
- 过程奖励模型(PRMs) -
增加串行修改计算量 - 模型给出一个初始输出,然后巡礼哪一个 Revision 模型基于该输出进行修正/调整输出的概率分布,直到得到一个最佳输出。
分词(Tokenization)#
分词可视化网址 - https://tiktokenizer.vercel.app/ ↗
分词指的是将输入文本转换成若干词元(Token),且保证每个词元拥有相对完整和独立的语义。
- 字符粒度 - 单个字符视为一个词元,词表较小,但是无法表述语义信息;
- 词粒度 - 单个词视为一个词元,词的含义得到保留但是稀有词的长尾效应较大,且无法处理单词变化;
- 子词粒度(subword) - 常用词保持原状,生僻词拆分成子词以共享 token 节省空间,较为常用。
目前最常用的子词粒度算法是 Byte-level BPE(B-BPE),其核心思想是通过滑动窗口来统计字节对而找到最频繁的连续字节对,然后将它们合并成一个新的字节对,重复这个过程直到达到预设的子词数量。
词表是由词元到索引的映射组成的字典,即 {'<pad>': 0, 'hello': 1, 'world': 2}
。
词嵌入(Embedding)#
分词过程结束之后,会得到一个优化后的词表,然后我们使用嵌入层将每个词元映射为一个稠密向量,全部映射完成之后得到一个可学习的参数矩阵/查找表,其大小为 [vocab_size, embed_dim]。
"hello world" ↓ 分词['hello', 'world'] ↓ 映射为 ID - 由词表确定[1, 2] ↓ 查找嵌入(lookup) - 大小为(2, 5)[[0.1234, -0.5678, 0.9012, -0.3456, 0.7890], [-0.1111, 0.2222, 0.3333, -0.4444, 0.5555]]
Word2Vec#
基于分布式假设,即语义相近的文本在向量空间中的距离也相近。其模型的本质是具有一个隐藏层的网络,最后取输入层到隐藏层的权重矩阵作为词的分布式表示。
word2vec 包含两种任务类型:
- CBOW - 上下文窗口内的词元向量平均值作为输入,目标词元作为输出,最大化目标词元的条件概率;
- Skip-Gram - 目标词元作为输入,上下文窗口内的词元作为输出,最大化上下文词元的条件概率。
由于要进行条件概率的计算,所以涉及 softmax 操作,但是该操作在词汇量较大的时候计算效率低,因此引入了两种优化算法:
- 层级 Softmax(Hierarchical Softmax) - 构建一个树形结构来代替隐藏层到 softmax 层的映射,根据词频构建哈夫曼树,高频词在浅层,低频词在深层。将输出词的概率分布建模为从根节点到叶子结点的路径选择(多分类 -> 二分类),复杂度从 降低到 ;
- 负采样(Negative Sampling) - 从噪声分布中随机采样负样本(词表中词频较大的无关词),并且使用词频的 0.75 次方作为权重,以平衡高频词和低频词的采样概率。目标是最大化正例的概率,同时最小化负例的概率。在更新的过程中也仅更新正例和负例的权重。
负采样的训练目标为:
其中 是中心词的词向量, 是正例上下文词的词向量, 是噪声分布。
FastText#
FastText 在 Word2Vec 的基础上进行了改进,引入了子词嵌入,即将输入文本拆分成子词,然后将子词嵌入向量进行平均得到输入文本的嵌入向量,有效提升了模型对 OOV 和形态变化的处理。
在 n-gram 序列的构建上采用了滑动窗口的方式,假设窗口大小为 3,对于输入文本 “hello”,其序列为:
<he, hel, ell, llo, lo>
并且为了避免显示存储所有子词的词向量,使用哈希函数将 n-gram 序列映射到固定大小的哈希表中。
预训练任务#
语言建模(NTP)#
给定一个词元序列 ,语言建模的任务为基于当前位置之前的词元序列 以自回归的方式对目标词元进行预测,形式化表达为:
代表性的模型为 GPT 和 LLaMA 等。
前缀语言建模(Prefix LM) - 专为前缀解码器架构而设计,本质是利用前缀信息来预测后缀的词元,并且只有后缀中的词元计入总损失。形式化表达为:
该架构对因果解码器的掩码机制进行了修改,即对输入(前缀)部分采用双向注意力机制进行编码,而对输出部分利用单向的掩码注意力进行自回归地预测。与编码器-解码器架构不同的是,其在编码和解码的过程中是参数共享的,代表性的模型为 ChatGLM 和 U-PaLM。
去噪自编码(DAE)#
输入序列经过一系列的随机替换和删除操作之后形成损坏的文本 ,模型的目标就是根据损坏的文本来恢复被替换或删除的词元片段 。形式化表达为:
代表性的模型为 BERT 和 T5 等。
混合去噪器(MoD)#
混合去噪器将语言建模任务和去噪自编码任务进行了统一,包括三种去噪器(Denoiser):S-去噪器、R-去噪器、X-去噪器。其中 S 与前缀语言建模任务一致。而 R 和 X 与去噪自编码任务一致,区别在于屏蔽片段(Span)的跨度和损坏比例上有所区别。R 屏蔽序列中约 15% 的词元,且每个被屏蔽的片段仅包含 3 到 5 个词元。而 X 则采用更长的片段(12 个词元以上)或更高的损坏比例(50%)。
为了引导模型针对不同类型的输入选择相应的去噪器,输入句子会以特殊词元([R], [S], [X])作为开头。这种标记方式引导模型识别输入中使用的去噪器,并对该去噪器损坏的词元进行还原。代表性的模型为 UL2 和 PaLM2 等。
指令微调#
指令微调(Instruction Tuning) 指的是用自然语言形式的数据对预训练模型进行参数微调,使得模型具备指令遵循的能力,能够完成各类预先设置的任务,并且可以在零样本的情况下完成诸多下游任务。
指令微调最重要的一环是指令数据的构建,即 [指令+输入+输出] 对,例如下面的翻译任务:
{ "instruction": "将下述中文翻译为英文", "input": "中国的首都是北京。", "output": "China's capital city is Beijing."}
主要有三种构建方式 - 在已有的 NLP 数据集上添加指令、人类专家编写的指令数据集以及通过大模型来生成指令数据集(Self-Instruct)。
数据合成#
- 生产合成 Prompt - 1)Self-Instruct - 首先为每条样本精细地附加任务描述,然后针对每个描述设计若干种子提示词,随机抽样后输入大规模模型,由其基于种子提示生成新的问题;2)启发式规则 - 收集具有多样任务描述的原始数据集,对其进行结构化改写,以合成不同格式与风格的 Prompt;
- 生产合成 Answer - 采用性能优异的模型生成参考答案,比如可先由 GPT-4 生成高质量回答,然后用 Self-Consistency 投票进一步筛选,用筛选之后的数据集来微调小模型;
- 工业界做法 - 1)通过 Best-of-N 对同一个 Prompt 采样多个路径,然后通过人工或者奖励模型挑选最佳路径作为 Response。2)构造 Chosen 和 Rejected 偏好数据,然后进行 SFT 或 DPO。
数据过滤#
- IFD 过滤 - 通过比较模型在有无指令作为上下文时的响应的困惑度之比,得到每个样本的 IDF 分数。分数越高,说明样本信息含量越丰富;
- MoDS 过滤 - 基于质量、覆盖度和必要性三个维度综合筛选指令数据集,旨在从海量数据中挑选最有价值的小规模子集:
- 质量 - 选出内容准确、无明显噪声或格式问题的样本;
- 覆盖度 - 选出在任务类型、主题领域、指令风格等方面具有多样性的样本;
- 必要性 - 利用初步调优后的模型,找出其”表现欠佳”的指令样本,纳入最终子集。
数据评估#
- 数据质量
- 数据多样性
参数高效微调#
Adapter Tuning#
Adapter Tuning 指的是在模型中引入适配器(瓶颈网络架构)从而不需要训练整个模型,只需要更新适配器参数即可,不同的任务可以使用不同的适配器。形式化表示为:
其中 、、。
具体来说,首先将特征向量压缩到较低维度,然后使用激活函数进行非线性变换,最后恢复到初始维度。并且使用残差连接来保证梯度的传递。
LoRA#
LoRA 指的是在预训练模型的参数矩阵的旁路添加低秩分解矩阵来近似每层的参数更新。形式化表示为:
其中 、、、 ,且矩阵 、 分别通过高斯、零初始化。
具体来说,模型在前向传播的过程中,原始参数矩阵保持不变,而引入的低秩矩阵会被更新。训练完成之后将二者合并得到新的参数矩阵。推理阶段,相较于 Adapter 的串行来说,并行推理速度会更快。
人类对齐#
人类对齐(Human Alignment)指的是大语言模型的行为与人类价值观、人类真实意图和社会伦理相一致。我们希望对齐之后的大模型是有用的、诚实的、无害的(3H 标准)。
RLHF#
(1)监督微调 - 使用标注数据 训练基于 GPT-3 的微调模型
(2)奖励模型训练 - 使用筛选的偏好数据 基于 训练奖励模型 来输出标量分数
基于 Bradley-Terry 模型,给出人类偏好片段 超过 的概率:
对该模型做最大似然估计,希望偏好/非偏好输出之间的奖励差值较大:
(3)PPO 优化 - 初始策略为 ,结合奖励模型和 KL 惩罚优化策略从而最大化奖励模型的输出期望
加入 KL 惩罚是希望模型的优化目标不会太过偏离微调结果,减少奖励模型对 OOD 数据的敏感性以及避免 Reward Hacking 问题,需要注意分布之间的 KL 散度是逐词元计算(Per-Token KL Penalty)。加入预训练目标函数是希望模型能够保留基础能力,避免遗忘预训练知识(减轻对齐税)。
但是 KL 散度的优化是二阶问题,通过引入 Clip 机制裁剪策略更新的概率比,直接限制策略变化范围,将它转换为一阶优化问题。此时目标函数变为:
其中 是优势函数,定义为实际奖励与基准奖励的差值:
其中实际奖励通过奖励模型输出得到,而基准奖励则由可学习的价值模型 提供。通过引入广义优势估计(GAE),单步优势函数进一步扩展为多步优势的指数加权平均(Per-Token):
在实践中,通常使用奖励模型来初始化价值模型,并且采用时序差分误差作为目标函数:
引入 Clip 机制的好处是可以通过优势函数的正负来判断是否更新策略,而优势函数通过对比模型回答内容的实际奖励是否高于基准奖励来实现策略更新的定向调节。如果高于基准奖励,则指导模型增大当前输入下相应输出的概率(增大策略在这个状态下采取对应动作的概率),反之减小。
GRPO#
由于价值模型是与策略模型是类似规模的,且都要进行参数更新,因此会引入较大的内存和计算负担。且价值模型本身的作用就是输出基准奖励用来调整策略。
GRPO 的思想是消除价值模型,并将相同问题不同输出的归一化奖励作为基准奖励。形式化表达为:
使用无偏差估计方法来计算 KL 散度:
此时优势函数有两种估计方法:
结果奖励模型(ORMs) - 使用每个输出的最后一个词元计算奖励值,然后使用下述公式更新:
过程奖励模型(PRMs) - 使用每个输出的每个词元计算奖励值,然后使用下述公式更新:
DPO#
上述两种对齐方法都依赖显式奖励模型,且需要复杂的策略优化过程(多阶段)。而 DPO 提出我们可以直接绕过奖励模型直接优化人类偏好策略,从而将多阶段学习转换为端到端学习。
根据 KL 约束下的最优策略表达式反解得到关于策略的奖励函数:
其中 是配方函数。然后将关于策略的奖励函数 代入奖励模型目标函数得到(奖励模型的重参数化):
从上述公式可以看出 DPO 通过隐式定义奖励函数 使其与策略函数 关联,将强化学习的策略优化问题转换为直接优化策略参数 的监督学习问题。
提示工程#
提示工程(Prompt Engineering)指的是通过在提示词中写入有价值的信息从而提示大语言模型的现有能力。提示工程指南 ↗收集了非常多的方法。Prompting Guide 101 ↗有非常多的实践方法。
上下文学习#
上下文学习(In-Context Learning)指的是大语言模型在推理阶段无需参数更新,仅通过在输入中添加任务示例即可快速适应并完成新任务的能力。
思维链#
思维链(Chain-of-Thought)指的是在给定的示例中添加具体推理步骤使得模型能够应对复杂推理问题。
如果仅是使用 “Let’s think step by step.” 而不提供示例,则为 Zero-shot CoT。
思维链的生成方法
- 基于采样的方法(CoT-SC) - 使用模型生成多条推理路径和对应的答案,然后选取多数答案为最终答案;
- 基于验证的方法 - 比对真实答案和生成答案训练分类器,并对整个推理路径和中间推理步骤进行验证。
通过思维链的生成方法,能够有效避免单一推理路径不稳定以及推理错误累积现象。
拓展的推理结构
- 思维树(ToT) - 在每个推理步骤(节点)中,“前瞻” 剩余的步骤并计算分数,“后验” 已生成内容的一致性;
- 思维图(GoT) - 生成中间推理步骤的同时汇聚其他节点的推理步骤,通过交叉验证来得到最终输出。
检索增强生成#
检索增强生成(Retrieval-Augmented Generation)指的是通过检索与问题相似的外部数据来增强提示词,指导模型生成正确结果。有助于解决大模型知识的局限性、幻觉以及数据安全性问题。主要包含三个步骤:
- 索引 - 将文档库进行拆分并分块,转换成嵌入向量并存储到向量数据库中,从而构建向量索引;
- 检索 - 将输入内容和向量数据库中的内容进行相似度检索,选取若干最优相关片段;
- 生成 - 将选取到的片段拼接到输入中提供给大模型,生成回答。
推荐查看 - RAG techniques ↗
智能体#
智能体(Agent)指的是基于大语言模型的智能代理,能自主理解任务、规划步骤并调用工具以完成复杂目标。它主要包含四个部分:
- 规划 - 子任务分解、反思与完善(ReAct、Reflexion);
- 记忆 - 长期记忆(RAG)、短期记忆(上下文学习);
- 工具使用 - 调用外部 API 补全模型权重信息、使用预训练模型;
- 行动 - 与环境交互并更改环境的状态。
多智能体系统是指通过多个自主或半自主的智能体进行协作、竞争或角色分工,以动态交互和互补能力解决复杂任务,并提升生成结果的可靠性、一致性和创造性。
推荐查看 - Building effective agents ↗
模型部署#
模型量化#
后训练量化(PTQ) - 量化已经训练好的模型参数
- GPT-Q - 通过分层优化和 Hessian 矩阵补偿,在量化过程中动态调整权重(对某一权重量化后,需要调整其他权重来补偿误差)。开销较高,适用超大参数模型;
- AWQ - 通过分析激活分布识别权重的重要性,对关键权重通道保留更高精度。并采用逐通道缩放技术确定最佳缩放因子。开销较低,能够低资源部署。
量化感知训练(QAT) - 在训练过程中将量化模块添加到模型中
- LLM-QAT 同时量化权重、激活和 KV Cache,旨在增强吞吐量的同时支持更长的序列。
投机采样#
在自回归模型的 token-by-token 模式中,串行输出会导致推理较慢。投机采样(Speculative Decoding)的思想就是通过小模型生成候选序列,大模型评估候选序列是否符合自身分布。通过批处理概率计算,有效减少了自回归模型对于词元生成的串行依赖(生成 39 个词元只前向计算了 9 次)。
- 候选序列 - 小模型生成候选序列 ,概率为 ;
- 并行验证 - 把候选序列和前缀拼接输入给大模型,大模型并行计算每个位置的条件概率 ;
- 接受规则 - 对每个位置 ,大模型以概率 拒绝采样。并从 分布中重新采样。如果接受小模型输出,则用大模型采样下一个词元。重复候选序列的步骤(注意进行拼接)。
若 ,则表示小模型和大模型的输出分布不同,需要一定概率拒绝采样。并从正常分布 中重新采样使结果符合大模型输出分布。
多模态基础模型#
多模态的核心是在语言模型中通过可训练的 连接模块(Connection Module) 来注入视觉特征,通过自回归预测下一个文本令牌。
CLIP#
CLIP(Contrastive Language-Image Pretraining)是由 OpenAI 提出的第一个 多模态预训练算法。它首次将图像和文本映射到同一个高维空间(多模态嵌入空间),使得跨模态的相似度计算成为可能。
CLIP 采用 对比学习(Contrastive Learning) 预训练,即训练两个编码器 - 图像编码器和文本编码器。
在训练过程中,将每个批量的 图像-文本对 传入模型,得到若干个图像特征向量和文本特征向量。我们希望正确的图像-文本对的特征向量相似度尽量高(对角线),而不是一对的相似度尽量低。这里相似度的计算方式为余弦相似度。此外由于不同编码器输出的特征向量长度不一样,因此使用线形映射统一向量长度。训练完成后可以通过 Prompt 实现零样本推理能力(在庞大数据集的基础上,对没有见过的样本效果还是不行)。
在推理过程中,以 ImageNet 为例,对一千个类别标签,分别生成一千个对应的文本,比如 A photo of a #Class,然后通过 CLIP 匹配相似度最高的图像和文本。
Flamingo#
Flamingo 是由 DeepMind 提出的多模态大模型,它的核心目标是实现 跨模态的少样本学习,即通过大量图文交织的数据来确保模型的少样本、上下文学习能力。
感知重采样器 - 类似于 DETR,学习一组固定数量的潜在输入查询,这些查询通过交叉注意力机制与视觉特征进行交互。从而 将变长的视觉向量压缩为定长的多模态语义向量。
门控交叉注意力单元 - 在原先固定的模型结构的每一层上添加门控交叉注意力单元,它通过门控机制控制视觉和文本的信息流,使得浅层提取基础特征,深层提取丰富特征(随着训练过程和层数的加深,门控值也逐渐变大)。
BLIP-2#
BLIP-2(Bootstrapping Language-Image Pre-training)是由 Salesforce Research 提出的多模态预训练模型,它的核心目标是通过 轻量级模块连接冻结的视觉编码器与大语言模型,实现跨模态理解与生成任务。
Q-Former - 将视觉特征映射到语言模型能够理解的的语义特征,由 Image & Text Transformer 两个子模块构成,它们共享相同的自注意力层。
表示学习阶段 - 引入可学习的 Query 与 Image Encoder 输出特征进行交互,通过联合优化三个预训练目标来学习高质量的跨模态对齐表示。
- 图文对比任务(ITC) - 计算来自 Image Transformer 的 Query 特征和 Text Transformer 的 Text 特征之间的相似度,且通过 InfoNCE 损失函数进行对比训练;
- 图生文任务(ITG) - 训练 Q-Former 模块能够根据图像生成自然语言描述,使得 Query 能够提取包含文本信息的视觉特征;
- 图文匹配任务(ITM) - 将 Image Transformer 输出的每个 Query 特征输入到一个二分类器中,将结果平均之后获得对应的 logit,且通过交叉熵损失函数进行训练。
生成学习阶段 - 将一阶段提取的视觉特征映射到大模型输入特征的相同维度,作为前缀传入大模型,指导模型生成与图像相关的文本。
LLaVA#
LLaVA 的核心是通过多模态对齐和协同推理,来实现端到端的生成式学习系统(基于多模态输入,生成连贯的问答、描述、推理输出)。并且通过指令微调的方式来增强模型的零样本、少样本学习能力。
它的主要架构为 Llama、CLIP-ViT-L、线形投影层。采用二阶段指令微调:
- 预训练阶段用来进行模态特征对齐 - 只更新线形投影层,冻结视觉编码器和语言模型权重;输入的构造 - 对于图像 ,随机采样一个问题 ,要求助手简要描述图像,真是答案 是原始标题;
- 端到端微调阶段用来适应多样化的指令要求 - 只更新语言模型和线形投影层,冻结视觉编码器权重。
指令跟随数据集构建过程 - 将带有 Caption 和 Bbox 信息的 COCO 数据集提供给 GPT-text-only 让它输出三种指令数据,分别是对话数据、描述数据和复杂推理数据,形成 LLaVA-Instruct-158K 数据集。
大模型幻觉#
高效训练技术#
3D 并行训练#
数据并行(Data Parallelism) - 该方法将完整的模型参数和优化器状态同步至所有参与训练的 GPU,将训练数据均匀地划分成多个批次,每个 GPU 处理一个批次,然后各 GPU 同步执行前向/反向传播。计算完成后通过 All-Reduce 操作对各 GPU 的梯度进行平均,确保所有设备基于统一的梯度进行更新。
流水线并行(Pipeline Parallelism) - 该方法将模型的不同层的参数分配到不同的 GPU 上,每个设备负责一部分前向和反向计算,该方法可以有效解决单个设备显存不足的情况;
张量并行(Tensor Parallelism) - 该方法将计算过程中的参数矩阵进行按列/行分块,分别分配到不同的 GPU 上,然后并行地执行矩阵乘法,最后将结果进行合并。需要注意针对不同的算子类型采用不同的切分方法。
推荐查看 - 深入理解 Megatron-LM 系列 ↗
零冗余优化器(ZeRO)#
该方法由 DeepSpeed 团队提出,旨在解决数据并行中的模型冗余问题。其通过分片存储策略,将模型参数、优化器状态和梯度分散到不同的 GPU 上,从而减少单设备的显存需求。
- ZeRO-1 - 将优化器状态平摊到每台设备上,而模型参数和梯度各自保留;
- ZeRO-2 - 在 ZeRO-1 的基础上,将梯度也平摊到每台设备上;
- ZeRO-3 - 在 ZeRO-2 的基础上,将模型参数也平摊到每台设备上。
激活重计算#
激活重计算也称为梯度检查点(Gradient Checkpointing),该技术在前向计算的过程中保留部分激活值,在反向传播的过程当中重新激活需要的激活值,从而达到节约显存的目的。
混合精度训练#
混合精度训练指的是同时使用半精度浮点数(2 个字节)和单精度浮点数(4 个字节)进行运算,以实现显存开销减半、训练效率翻倍的效果。即在前向/反向传播中使用半精度计算,在参数更新的时候使用单精度计算。
常见的半精度浮点数表示方式为 FP16,包含 1 位符号位、5 位指数位、10 位尾数位。进一步 Google 研究人员开发出了 BF16,其包含 1 位符号位、8 位指数位、7 位尾数位,表示范围可以达到 数量级,在模型训练中被广泛使用。