> **来源:[研报客](https://pc.yanbaoke.cn)** # 大模型能力技术培训 让数据智能像水电一样简单 # 语言模型发展历程 - 上世纪90年代:语言模型出现,统计学方法,使用前面的词预测下一个词 2003年:Bengio《A Neural Probabilistic Language Model》,首度将深度学习思想融入语言模型 2018年:Google提出Transformer神经网络架构,并通过大量文本训练理解语言规则和模式 # 大语言模型:包含百亿或更多参数的语言模型 - 国外:GPT-3(175B)、GPT-4、PaLM(540B)、Galactica和LLaMA等 - 国内:ChatGLM、文心一言、通义千问、讯飞星火等 - 大语言模型和小语言模型(如GPT2)采用相似的架构和预训练任务,但是能力截然不同(涌现能力) - 涌现能力使得大语言模型只使用很少的样本就可以处理全新的任务 # 对技术领域的影响 - 自然语言处理:理解和生成文本,意图理解、写文章、回答问题、翻译等等 - 信息检索:智能检索,改进搜索引擎 - 计算机视觉:文生图、多模态交互 # 对商业领域的影响 - AI Agent:数字人、个人智能助理、情感分析师、口语陪练、智能运营助手,等等 通用人工智能AGI:大语言模型是AGI的早期形式,引发了对未来人工智能发展的思考和规划 # 涌现能力 - 上下文学习的能力:GPT3首次引入,instruction + few shot learning,无需额外训练和参数更新。 - 指令遵循:可以使用指令进行微调,在同样使用指令形式化描述的未见过的任务上表现良好 - 逐步推理:“思维链”推理策略,可以利用包含中间推理步骤的提示机制来解决复杂推理任务 # 作为基座模型支持多元应用的能力 - 全新的AI范式,借助于海量无标注数据的训练,获得可以适用于大量下游任务的统一大模型 - 可以缩短每个具体应用的开发周期,人力投入,也可以基于大模型的推理、常识和写作能力,获得更好的应用效果 # 支持对话作为统一入口的能力 - Conversation as a Platform(陆奇,2016),以对话形态完成各种各样的任务 # 大语言模型的特点 巨大的规模:十亿到万亿,能够捕捉更多的语言知识和复杂的语法结构 - 预训练和微调:先用无标签数据在大规模文本上预训练,再用有标签数据微调特殊任务 - 上下文感知:能够理解和生成依赖于前文的文本内容。在对话、文章生成和情境理解方面表现出色 - 多语言支持:可以构建跨文言和跨文化的应用 - 多模态支持:文本、图像、语音 - 涌现能力:能用更少的数据处理更复杂的任务 - 多领域应用:文本生成、自动翻译、信息检索、摘要生成、聊天机器人、虚拟助手等等 - 伦理和风险问题:生成有害内容、隐私问题、认知偏差等,这是需要重点解决的问题 - 幻象、资源消耗、推理速度 语言模型(Language Model,LM)目标是建模自然语言的概率分布 词汇表 V 上的语言模型由函数 $\mathrm{P}\left(\mathrm{w}_{1} \mathrm{~w}_{2} \dots \mathrm{w}_{\mathrm{m}}\right)$ 表示,表示词序列 $\mathrm{w}_{1} \mathrm{~w}_{2} \dots \mathrm{w}_{\mathrm{m}}$ 作为一个句子出现的可能性大小。对于任意词串 $\mathrm{w}_{1} \mathrm{~w}_{2} \dots \mathrm{w}_{\mathrm{m}} \in \mathrm{V}+$ ,则有 $\mathrm{P}\left(\mathrm{w}_{1} \mathrm{~w}_{2} \dots \mathrm{w}_{\mathrm{m}}\right)=0$ ,并且对于所有词串,函数 $\mathrm{P}\left(\mathrm{w}_{1} \mathrm{~w}_{2} \dots \mathrm{w}_{\mathrm{m}}\right)$ 满足归一化条件: $$ \sum_ {w _ {1} w _ {2} \dots w _ {m} \in \mathbb {V} ^ {+}} P (w _ {1} w _ {2} \dots w _ {m}) = 1 $$ 由于联合概率 $P\left(w_{1} w_{2} \ldots w_{m}\right)$ 的参数量十分巨大, 直接计算 $P\left(w_{1} w_{2} \ldots w_{m}\right)$ 非常困难。如果把 $w_{1} w_{2} \ldots w_{m}$ 看作一个变量, 那么它具有 $|V|^{m}$ 种可能。 按照《现代汉语词典(第七版)》包含7万词条,句子长度按照20个词计算,模型参数量达到 $7.9792^{*} 10^{96}$ 的天文数字。 为了减少 P (W₁W₂...Wₘ) 模型参数量,可以利用句子序列通常情况下从左至右的生成过程进行分解,使用链式法则得到: $$ \begin{array}{l} P \left(w _ {1} w _ {2} \dots w _ {m}\right) = P \left(w _ {1}\right) P \left(w _ {2} \mid w _ {1}\right) P \left(w _ {3} \mid w _ {1} w _ {2}\right) \dots P \left(w _ {m} \mid w _ {1} w _ {2} \dots w _ {m - 1}\right) \\ = \prod_ {i = 1} ^ {m} P \left(w _ {i} \mid w _ {1} w _ {2} \dots w _ {i - 1}\right) \\ \end{array} $$ 由此, $w_{1}w_{2}\ldots w_{m}$ 的生成过程可以看作单词逐个生成的过程。首先生成 $w_{1}$ ,之后根据 $w_{1}$ 生成 $w_{2}$ ,再根据 $w_{1}$ 和 $w_{2}$ 生成 $w_{3}$ ,以此类推,根据前 $m - 1$ 个单词生成最后一个单词 $w_{m}$ $P$ (把努力变成一种习惯) $= P$ (把) $\times P$ (努力|把) $\times P$ (变成|把努力) $P$ (一种把努力变成) $\times P$ (习惯把努力变成一种) 语言模型通常用于反映一个句子出现的可能性,给定由单词序列 $w_{1} w_{2} \ldots w_{n}$ 组成的句子 $S$ ,可以利用语言的特性,使用链式法分解则得到: $$ P (S) = \prod_ {i = 1} ^ {n} P \left(w _ {i} \mid w _ {1} w _ {2} \dots w _ {i - 1}\right) $$ 其中,词 $w_{i}$ 出现的概率受它前面的 $i - 1$ 个词 $w_{1}w_{2}\ldots w_{i - 1}$ 影响,我们将这 $i - 1$ 个词 $w_{1}w_{2}\ldots w_{i - 1}$ 称之为词 $w_{i}$ 的历史。如果历史单词有 $i - 1$ 个,那么可能的单词组合就有 $|V|^{i - 1}$ 种。最简单的根据语料库对 $\mathrm{P}(\mathrm{wi}| \mathrm{w1w2}\dots \mathrm{wi} - 1)$ 进行估计的方法是基于词序列在语料中出现次数(也称为频次)的方法: $$ P (w _ {i} | w _ {1} w _ {2} \dots w _ {i - 1}) = \frac {\mathrm {C} (w _ {1} w _ {2} \dots w _ {i - 1} w _ {i})}{\mathrm {C} (w _ {1} w _ {2} \dots w _ {i - 1})} $$ 随着历史单词数量增多,绝大多数的历史并不会在训练数据中出现,这也意味着 P $\left(w_{i} \mid w_{1} w_{2} \dots w_{i-1}\right)$ 就很可能为 0 , 使得概率估计失去了意义。为了解决上述问题, 可以进一步假设任意单词 $w_{i}$ 出现的概率只与过去 $n - 1$ 个词相关 $$ \begin{array}{l} P \left(w _ {i} \mid w _ {1} w _ {2} \dots w _ {i - 1}\right) = P \left(w _ {i} \mid w _ {i - (n - 1)} w _ {i - (n - 2)} \dots w _ {i - 1}\right) \\ P \left(w _ {i} \mid w _ {1} ^ {i - 1}\right) = P \left(w _ {i} \mid w _ {i - n + 1} ^ {i - 1}\right) \\ \end{array} $$ 满足上述条件的模型被称为n元语法或n元文法(n-gram) 模型。其中 n-gram 表示 n 个连续单词构成的单元,也被称为n元语法单元。 以二元语法为例,一个词的概率只依赖于前一个词,则句子 S 的出现概率可以表示为: $$ P (S) = \prod_ {i = 1} ^ {n} P \left(w _ {i} \mid w _ {i - 1}\right) $$ n元语言模型从整体上来看与训练语料规模和模型的阶数有较大的关系,不同的平滑算法在不同情况下的表现有较大的差距。 平滑算法虽然较好解决了零概率问题,但是基于稀疏表示的n元语言模型仍然有三个较为明显的缺点: (1) 无法建模长度超过 $n$ 的上下文; (2) 依赖人工设计规则的平滑技术; (3) 当 $n$ 增大时, 数据的稀疏性随之增大, 模型的参数量更是指数级增加, 并且模型受到数据稀疏问题的影响, 其参数难以被准确学习。 此外,n元文法中单词的离散表示也忽略了单词之间的相似性 Bengio等人在2000年提出了使用前馈神经网络对 $P(w_{i}|w_{i - n + 1}^{i - 1})$ 进行估计的语言模型。 词的独热编码被映射为一个低维稠密的实数向量,称为词向量(Word Embedding)。 循环神经网络、卷积神经网络、端到端记忆网络等神经网络方法都成功应用于语言模型建模。 相较于n元语言模型,神经网络方法可以在一定程度上避免数据稀疏问题,有些模型还可以避免对历史长度的限制,从而更好建模长距离依赖关系。这类方法通常称为神经语言模型(Neural Language Models, NLM)。 $$ \boldsymbol {x} _ {i} = \left[ \boldsymbol {v} _ {i - 1}; \boldsymbol {h} _ {i - 1} \right] $$ $$ \boldsymbol {h} _ {i} = f (\boldsymbol {U} \boldsymbol {v} _ {i - 1} + \boldsymbol {V} \boldsymbol {h} _ {i - 1} + \boldsymbol {b} ^ {h i d}) $$ $$ \boldsymbol {y} _ {i} = \operatorname {S o f t m a x} \left(\boldsymbol {W} ^ {\text {o u t}} \boldsymbol {h} _ {i} + \boldsymbol {b} ^ {\text {o u t}}\right) $$ 以ELMo为代表的动态词向量模型开启了语言模型预训练的大门。此后,以GPT和BERT为代表的基于Transformer架构的大规模预训练语言模型的出现,使自然语言处理全面进入预训练微调范式新时代。这类方法通常称为预训练语言模型(Pre-trained Language Models, PLM) BERT GPT BART/T5 2020年,OpenAI发布了由包含1750亿参数的神经网络构成的生成式大规模预训练语言模型GPT-3(Generative Pre-trained Transformer 3)。开启了大语言模型的新时代。在不同任务上都进行微调需要消耗大量的计算资源,因此预训练微调范式不再适用于大语言模型。 通过语境学习(In-Context Learning,ICL)等方法,直接使用大语言模型就可以在很多任务的少样本场景下取得很好的效果。此后,研究人员提出了面向大语言模型的提示词(Prompt)学习方法、模型即服务范式(Model as a Service,MaaS)、指令微调(Instruction Tuning)等方法。 Kaplan 等人在中提出了缩放法则(Scaling Laws),指出模型的性能依赖于模型的规模,包括参数数量、数据集大小和计算量,模型的效果会随着三者的指数增加而线性提高。 PF-days, non-embedding tokens non-embedding 按照时间线给出了 2019 年至 2023 年 6 月比较有影响力并且模型参数量超过 100 亿的大语言模型 # 大语言模型的发展可以粗略地分为如下三个阶段:基础模型阶段、能力探索阶段和突破发展阶段基础模型阶段主要集中于2018年至2021年: 2017年,Vaswani等人提出了Transformer架构,在机器翻译任务上取得了突破性进展。 2018年,Google和OpenAI分别提出了BERT和GPT-1模型,开启了预训练语言模型时代。 - 2019年,OpenAI发布了GPT-2,参数量15亿。Google发布了参数规模为110亿的T5模型。 2020年,OpenAI进一步将语言模型参数量扩展到1750亿,发布了GPT-3。 # 此阶段的研究主要集中在语言模型本身,包括对仅编码器(Encoder Only)、编码器-解码器 (Encoder-Decoder)、仅解码器(Decoder Only)等各种类型的模型结构都有相应的研究。模型大小与BERT相类似的算法,通常采用预训练微调范式,针对不同下游任务进行微调。但是模型参数量在10亿以上时,由于微调的计算量很高,这类模型的影响力在当时相较BERT类模型有不小的差距。 # 能力探索阶段集中于2019年至2022年 由于大语言模型很难针对特定任务进行微调,研究人员开始探索在不针对单一任务进行微调的情况下如何发挥大语言模型的能力 2019 年, Radford等人使用GPT- 2 模型研究了大语言模型在零样本情况下的任务处理能力 - Brown 等人在GPT-3模型上研究了通过语境学习进行少样本学习的方法 - 指令微调将大量各类型任务,统一为生成式自然语言理解框架,并构造训练语料进行微调 2022年,Ouyang等人提出了使用“有监督微调+强化学习”的InstructGPT算法 这些方法在直接利用大语言模型进行零样本和少样本学习的基础上,逐渐扩展到利用生成式框架针对大量任务进行有监督微调的方法,有效提升了模型的性能。 # 突破发展阶段以2022年11月ChatGPT的发布为起点 ChatGPT 通过一个简单的对话框,利用一个大语言模型就可以实现问题回答、文稿撰写、代码生成、数学解题等过去自然语言处理系统需要大量定制开发才能分别实现的能力 2023年3月GPT-4发布,相较于ChatGPT又有了非常明显的进步,并具备了多模态理解能力。GPT-4在多种基准考试测试上的得分高于 $88\%$ 的应试者 各大公司和研究机构相继发布了此类系统,包括Google 推出的Bard、百度的文心一言、科大讯飞的星火大模型、智谱ChatGLM、复旦大学MOSS等 表 1.1 典型开源大语言模型汇总 <table><tr><td>模型名称</td><td>发布时间</td><td>模型参数量</td><td>基础模型</td><td>模型类型</td><td>预训练数据量</td></tr><tr><td>T5[19]</td><td>2019年10月</td><td>110亿</td><td>-</td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>mT5[26]</td><td>2020年10月</td><td>130亿</td><td>-</td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>PanGu-α[22]</td><td>2021年4月</td><td>130亿</td><td>-</td><td>语言模型</td><td>1.1万亿Token</td></tr><tr><td>CPM-2[27]</td><td>2021年6月</td><td>1980亿</td><td>-</td><td>语言模型</td><td>2.6万亿Token</td></tr><tr><td>T0[28]</td><td>2021年10月</td><td>110亿</td><td>T5</td><td>指令微调模型</td><td>-</td></tr><tr><td>CodeGen[29]</td><td>2022年3月</td><td>160亿</td><td>-</td><td>语言模型</td><td>5770亿Token</td></tr><tr><td>GPT-NeoX-20B[30]</td><td>2022年4月</td><td>200亿</td><td>-</td><td>语言模型</td><td>825GB数据</td></tr><tr><td>OPT[31]</td><td>2022年5月</td><td>1750亿</td><td>-</td><td>语言模型</td><td>1800亿Token</td></tr><tr><td>GLM[32]</td><td>2022年10月</td><td>1300亿</td><td>-</td><td>语言模型</td><td>4000亿Token</td></tr><tr><td>Flan-T5[23]</td><td>2022年10月</td><td>110亿</td><td>T5</td><td>指令微调模型</td><td>-</td></tr><tr><td>BLOOM[33]</td><td>2022年11月</td><td>1760亿</td><td>-</td><td>语言模型</td><td>3660亿Token</td></tr><tr><td>Galactica[34]</td><td>2022年11月</td><td>1200亿</td><td>-</td><td>语言模型</td><td>1060亿Token</td></tr><tr><td>BLOOMZ[35]</td><td>2022年11月</td><td>1760亿</td><td>BLOOM</td><td>指令微调模型</td><td>-</td></tr><tr><td>OPT-IML[36]</td><td>2022年12月</td><td>1750亿</td><td>OPT</td><td>指令微调模型</td><td>-</td></tr><tr><td>LLaMA[37]</td><td>2023年2月</td><td>652亿</td><td>-</td><td>语言模型</td><td>1.4万亿Token</td></tr><tr><td>MOSS</td><td>2023年2月</td><td>160亿</td><td>Codegen</td><td>指令微调模型</td><td>-</td></tr><tr><td>ChatGLM-6B[32]</td><td>2023年4月</td><td>62亿</td><td>GLM</td><td>指令微调模型</td><td>-</td></tr><tr><td>Alpaca[38]</td><td>2023年4月</td><td>130亿</td><td>LLaMA</td><td>指令微调模型</td><td>-</td></tr><tr><td>Vicuna[39]</td><td>2023年4月</td><td>130亿</td><td>LLaMA</td><td>指令微调模型</td><td>-</td></tr><tr><td>Koala[40]</td><td>2023年4月</td><td>130亿</td><td>LLaMA</td><td>指令微调模型</td><td>-</td></tr><tr><td>Baize[41]</td><td>2023年4月</td><td>67亿</td><td>LLaMA</td><td>指令微调模型</td><td>-</td></tr><tr><td>Robin-65B[42]</td><td>2023年4月</td><td>652亿</td><td>LLaMA</td><td>语言模型</td><td>-</td></tr><tr><td>BenTsao[43]</td><td>2023年4月</td><td>67亿</td><td>LLaMA</td><td>指令微调模型</td><td>-</td></tr></table> <table><tr><td>模型名称</td><td>发布时间</td><td>模型参数量</td><td>基础模型</td><td>模型类型</td><td>预训练数据量</td></tr><tr><td>StableLM</td><td>2023年4月</td><td>67亿</td><td>LLaMA</td><td>语言模型</td><td>1.4万亿Token</td></tr><tr><td>GPT4All[44]</td><td>2023年5月</td><td>67亿</td><td>LLaMA</td><td>指令微调模型</td><td></td></tr><tr><td>MPT-7B</td><td>2023年5月</td><td>67亿</td><td></td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>Falcon</td><td>2023年5月</td><td>400亿</td><td></td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>OpenLLaMA</td><td>2023年5月</td><td>130亿</td><td></td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>Gorilla[45]</td><td>2023年5月</td><td>67亿</td><td>MPT/Falcon</td><td>指令微调模型</td><td></td></tr><tr><td>RedPajama-INCITE</td><td>2023年5月</td><td>67亿</td><td></td><td>语言模型</td><td>1万亿Token</td></tr><tr><td>TigerBot-7b-base</td><td>2023年6月</td><td>70亿</td><td></td><td>语言模型</td><td>100GB语料</td></tr><tr><td>悟道天鹰</td><td>2023年6月</td><td>330亿</td><td></td><td>语言模型和指令微调模型</td><td></td></tr><tr><td>Baichuan-7B</td><td>2023年6月</td><td>70亿</td><td></td><td>语言模型</td><td>1.2万亿Token</td></tr><tr><td>Baichuan-13B</td><td>2023年7月</td><td>130亿</td><td></td><td>语言模型</td><td>1.4万亿Token</td></tr><tr><td>Baichuan-Chat-13B</td><td>2023年7月</td><td>130亿</td><td>Baichuan-13B</td><td>指令微调模型</td><td></td></tr><tr><td>LLaMA2</td><td>2023年7月</td><td>700亿</td><td></td><td>语言模型和指令微调模型</td><td>2.0万亿Token</td></tr></table> 表 1.2 典型闭源大语言模型汇总 <table><tr><td>模型名称</td><td>发布时间</td><td>模型参数量</td><td>基础模型</td><td>模型类型</td><td>预训练数据量</td></tr><tr><td>GPT-3</td><td>2020年5月</td><td>1750亿</td><td>-</td><td>语言模型</td><td>3000亿Token</td></tr><tr><td>ERNIE 3.0</td><td>2021年7月</td><td>100亿</td><td>-</td><td>语言模型</td><td>3750亿Token</td></tr><tr><td>FLAN</td><td>2021年9月</td><td>1370亿</td><td>LaMDA-PT</td><td>指令微调模型</td><td>-</td></tr><tr><td>Yuan 1.0</td><td>2021年10月</td><td>2450亿</td><td>-</td><td>语言模型</td><td>1800亿Token</td></tr><tr><td>Anthropic</td><td>2021年12月</td><td>520亿</td><td>-</td><td>语言模型</td><td>4000亿Token</td></tr><tr><td>GLaM</td><td>2021年12月</td><td>12000亿</td><td>-</td><td>语言模型</td><td>2800亿Token</td></tr><tr><td>LaMDA</td><td>2022年1月</td><td>1370亿</td><td>-</td><td>语言模型</td><td>7680亿Token</td></tr><tr><td>InstructGPT</td><td>2022年3月</td><td>1750亿</td><td>GPT-3</td><td>指令微调模型</td><td>-</td></tr><tr><td>Chinchilla</td><td>2022年3月</td><td>700亿</td><td>-</td><td>语言模型</td><td></td></tr><tr><td>PaLM</td><td>2022年4月</td><td>5400亿</td><td>-</td><td>语言模型</td><td>7800亿Token</td></tr><tr><td>Flan-PaLM</td><td>2022年10月</td><td>5400亿</td><td>PaLM</td><td>指令微调模型</td><td>-</td></tr><tr><td>GPT-4</td><td>2023年3月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr></table> <table><tr><td>模型名称</td><td>发布时间</td><td>模型参数量</td><td>基础模型</td><td>模型类型</td><td>预训练数据量</td></tr><tr><td>PanGu-Σ</td><td>2023年3月</td><td>10850亿</td><td>PanGu-α</td><td>指令微调模型</td><td>3290亿Token</td></tr><tr><td>Bard</td><td>2023年3月</td><td>-</td><td>PaLM-2</td><td>指令微调模型</td><td>-</td></tr><tr><td>ChatGLM</td><td>2023年3月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>天工3.5</td><td>2023年4月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>知海图AI</td><td>2023年4月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>360智脑</td><td>2023年4月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>文心一言</td><td>2023年4月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>通义千问</td><td>2023年5月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>MinMax</td><td>2023年5月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>星火认知</td><td>2023年5月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr><tr><td>浦语书生</td><td>2023年6月</td><td>-</td><td>-</td><td>指令微调模型</td><td>-</td></tr></table> 体验地址:https://chat.openai.com/ - OpenAI在2018年提出GPT,通过语言建模将世界知识压缩到仅解码器的Transformer模型中 - ChatGPT本质上是基于GPT-3.5/GPT-4的会话应用,是人工智能史上最强大的聊天机器人 - GPT-4扩展到支持多模态输入,安全性更好,并应用了一些干预策略来缓解LLM可能出现的问题,如幻觉、隐私和过度依赖[2],模型参数猜测是1.8万亿,最新发布的GPT-4 turbo有128k token 体验地址:https://claude.ai/chats 由 OpenAI 离职人员创建的 Anthropic 公司开发的闭源语言大模型,有以下特点: - 致力于提高 Claude 作为编码助理的能力,Claude 2 在编码基准和人类反馈评估方面性能显著提升 - Claude 的上下文窗口从 9K token 扩展到了 100K token (Claude 2 已经扩展到 200K token) - 可以进行连贯长输出,可以生成最多 4000 个token 的连贯文档,相当于大约 3000 个单词 - Claude 通常用于将长而复杂的自然语言文档转换为结构化数据格式,可以更好地生成 JSON、XML、YAML、代码和 Markdown 格式的正确输出 - Claude 2 的训练数据包括 2022 年和 2023 年初更新的数据,这意味着它知道最近发生的事件 体验地址:https://ai.google/discover/palm2/ 2023.3:PaLM基于Google提出的Pathways机器学习系统搭建,8B,62B,540B三个版本 2023.5:发布PaLM 2,是PaLM 540B的升级版,系列模型,最小模型可以部署在移动端,已部署在 Google 25个产品和功能中,同时也有专有模型版本,如Med-PaLM 2 # PaLM的几大突破: - 最优的缩放比例(训练数据大小/模型参数量),数据和模型大小大致按照 1:1 的比例缩放,可以达到最佳性能 - 训练数据集非纯英文语料,混合了百种语言,包括了网络文档、书籍、代码、数学和对话数据,比用于训练PaLM的语料库大得多 Bard是基于PaLM 2的会话类应用 体验地址:https://yiyan.baidu.com/ 文心一言是基于百度文心大模型的知识增强语言大模型 文心大模型包括 NLP 大模型、CV 大模型、跨模态大模型、生物计算大模型、行业大模型,其中 NLP 大模型主要为 ERNIE 系列模型,是打造文心一言的关键。文心大模型参数量达到了 2600 亿 # 2023.8.31:率先向全社会开放 - 有监督精调 - 人类反馈强化学习 知识增强 - 插件机制 体验地址:https://xinghuo.xfyun.cn/ 科大讯飞与2023.5.6发布1.0版本,8.15升级到2.0版本,10.24升级到3.0版本,包含1700亿参数。 可以支持图像描述、图像理解、图像推理、识图创作、文图生成、虚拟人合成等功能讯飞和华为还联合重磅发布了国内首款支持大模型训练私有化的产品“星火一体机” 体验地址:https://github.com/facebookresearch/llama Meta 开源的一组参数规模 从 7B 到 70B 的大语言模型,展示了如何仅使用公开可用的数据集来训练最先进的模型,而不需要依赖专有或不可访问的数据集。 - 数据集包括Common crawl、Wikipedia、OpenWebText2、RealNews、Books等 - 大规模的数据过滤和清洗技术,以提高数据质量和多样性,减少噪声和偏见 - 使用了高效的数据并行和流水线并行技术,以加速模型的训练和扩展 模型结构上,和chatGPT一样,也适用decoder-only的结构,但是做了一些改进 - Pre-normalization: 对每个 Transformer子层的输入进行了 RMSNorm 归一化 - SwiGLU激活函数:增加网络的表达能力和非线性,同时减少参数量和计算量 - RoPE位置编码:模型的输入不再使用位置编码,而是在网络的每一层添加了位置编码 体验地址:https://chatglm.cn/,开源地址:https://github.com/THUDM GLM 系列模型是清华大学和智谱 AI 等合作研发的开源语言大模型,6月发布glm2,10月27日发布glm3 GLM2使用了包含1.4万亿字符的中英预料进行预训练,并使用人类偏好的数据对模型进行对齐训练 - 通过 FlashAttention 技术,支持的长下文长度达到了 3.2 万字符 - 通过 Multi-Query Attention 技术,能够进一步地提升推理速度,减小对显卡的显存占用 GLM3引入更多特性: - 更强大的基础模型:ChatGLM3-6B 的基础模型具有在 10B 以下的基础模型中最强的性能 - 更完整的功能支持:采用了全新设计的 Prompt 格式,支持function call,代码执行和Agent等复杂功能 - 更全面的开源序列:ChatGLM3-6B,ChatGLM3-6B-Base,ChatGLM3-6B-32K,免费商业使用 体验地址:https://chatglm.cn/,开源地址:https://github.com/THUDM 体验地址:https://tongyi.aliyun.com/,开源地址:https://github.com/QwenLM/Qwen/tree/main 通义千问由阿里巴巴基于“通义”大模型研发,于2023年4月正式发布。2023年8月,阿里云开源了Qwen(通义千问)系列工作,当前开源模型的参数规模为70亿(7B)和140亿(14B) 它能够以自然语言方式响应人类的各种指令,拥有强大的能力,如回答问题、创作文字、编写代码、提供各类语言的翻译服务、文本润色、文本摘要以及角色扮演对话等。 开源地址:https://github.com/baichuan-inc Baichuan 是由百川智能开发的开源可商用的语言大模型,分为7B和13B。 Baichuan-7B 是在大约 1.2 万亿字符上训练,支持中英双语,4096 的上下文窗口长度。Baichuan-13B 在 Baichuan-7B 的基础上进一步扩大参数量到 130 亿,并且在高质量的语料上训练了 1.4 万亿字符。 - Baichuan 2 是百川智能推出的新一代开源大语言模型,Baichuan2-7B 和 Baichuan2-13B,均基于 2.6 万亿 Tokens 的高质量语料训练 2023年10月30日,百川智能发布Baichuan2-192K大模型 参考文献:https://github.com/baichuan-inc # 预训练阶段 原始数据 数千亿单词:图书、百科、网页等 语言模型预训练 基础模型 1000+GPU 月级别训练时间 GPT 3.0、LLaMa、PaLM # 指令微调 标注用户指令 数万用户指令和对应的答案 语言模型预训练 SFT模型 1-100GPU 天级别训练时间 MOSS、ChatGLM6b、Vicuna-13B等 # 奖励函数 标注对比对 百万标注对比对 二分类模型 RM 模型 1- 100GPU 天级别训练时间 # 强化学习 用户指令 十万用户指令 强化学习方法 RL模型 1-100GPU 天级别训练时间 ChatGPT、Claude 预训练(Pretraining)阶段需要利用海量的训练数据,数据来自互联网网页、维基百科、书籍、GitHub、论文、问答网站等,构建包含数千亿甚至数万亿单词的具有多样性的内容。 利用由数千块高性能GPU和高速网络组成超级计算机,花费数十天完成深度神经网络参数训练,构建基础语言模型(Base Model) 在预训练语料集方面,GPT-3中通过主要包含经过过滤的Common Crawl数据集、WebText2、Books1、Books2以及英文Wikipedia等数据集合。其中CommonCrawl的原始数据有45TB,进行过滤后仅保留了570GB的数据。通过子词方式对上述语料进行切分,大约一共包含5000亿子词。为了保证模型使用更多高质量数据进行训练,在GPT-3训练时,根据语料来源的不同,设置不同的采样权重。在完成3000亿子词训练时,英文Wikipedia的语料平均训练轮数为3.4次,而CommonCrawl和Books2仅有0.44次和0.43次。由于CommonCrawl数据集合的过滤过程繁琐复杂,OPT则采用了混合RoBERTa、Pile和PushShift.io Redit数据的方法。由于这些数据集合中包含的绝大部分都是英文数据,因此OPT也从CommonCrawl数据集中抽取了部分非英文数据加入训练语料。 由于模型参数量和所使用的数据量都非常巨大,普通的服务器单机无法完成训练过程,因此通常采用分布式架构完成训练。GPT-3和OPT中没有对这个部分给出详细的描述。 - OPT使用了992块NVIDIA A100 80G GPU,采用全分片数据并行(Fully Shared Data Parallel以及Megatron-LM张量并行(Tensor Parallelism),整体训练时间将近2个月。 - BLOOM则公开了更多在硬件和所采用的系统架构方面的细节。该模型的训练一共花费3.5个月,使用48个计算节点。每个节点包含8块NVIDIA A100 80G GPU(总计384GPU),并且使用4 NVLink用于节点内部GPU之间通信。节点之间采用四个Omni-Path 100 Gbps网卡构建的增强8维超立方体全局拓扑网络通信。 BLOOM使用Megatron-DeepSpeed框架进行训练,主要包含两个部分:Megatron-LM提供张量并行能力和数据加载原语;DeepSpeed提供ZeRO优化器、模型流水线以及常规的分布式训练组件。通过这种方式可以实现数据、张量和流水线三维并行。 有监督微调(Supervised Finetuning),也称为指令微调,利用少量高质量数据集合,包含用户输入的提示词和对应的理想输出结果。用户输入包括问题、闲聊对话、任务指令等多种形式和任务。 例如:提示词(Prompt):中国电信有哪些业务? 理想输出: 中国电信主要提供以下业务: 1. 移动通信服务:包括4G和5G网络服务,提供语音、短信、数据传输等服务。 2. 固定通信服务:提供固定电话、宽带互联网接入和相关服务。 3. 企业信息化服务:为企业客户提供包括云计算、大数据、物联网、信息安全等在内的综合信息化解决方案。 4. 国际通信服务:提供国际长途电话服务、国际数据服务等。 5. 其他增值服务:如彩铃、短信增值服务、视频点播、在线游戏等。 中国电信还不断开发新的业务和技术,以适应市场的变化和客户的需求。 利用这些有监督数据,使用与预训练阶段相同的语言模型训练算法,在基础语言模型的基础上进行训练,得到有监督微调模型(SFT 模型)。 - 经过训练的SFT模型具备初步的指令理解能力和上下文理解能力,能够完成开放领域问答、阅读理解、翻译、生成代码等任务,也具备了一定的对未知任务的泛化能力。 - 很多类ChatGPT的模型都属于该类型,包括Alpaca、Vicuna、MOSS、ChatGLM-6B等。很多这类模型的效果非常好,甚至在一些评测中达到了ChatGPT的 $90\%$ 的效果 奖励建模(Reward Modeling)阶段的目标是构建一个文本质量对比模型,对于同一个提示词,SFT 模型给出的多个不同输出结果的质量进行排序。奖励模型(RM 模型)可以通过二分类模型,对输入的两个结果之间的优劣进行判断。RM 模型与基础语言模型和SFT 模型不同,RM 模型本身并不能单独提供给用户使用。 奖励模型的训练通常和SFT模型一样,使用数十块GPU,通过几天时间完成训练。由于RM模型的准确率对强化学习阶段的效果有至关重要的影响,因此通常需要大规模的训练数据对该模型进行训练 # 大语言模型构建流程 - 奖励建模阶段 Playground task # Talk to the assistant Task 1 of 5 Decide on a task you'd like the assistant to help with and enter it into the task box. Interact with the AI assistant. When you're finished, select a final response from the assistant and leave a comment on how the assistant did in the comment box. Click to go to the next task. # Comments I thought the assistant was .. % # Rating 。 Bad Good Next Task # Human I have to come up with a conversation with an Al assistant for the purposes of showing it off in a demo. What sorts of conversation topics would you recommend? # Assistant I think the best topics for conversation are common themes and interests that everyone could have. Things like weather, sports, hobbies, current events, popular culture, and general life topics like relationships and work would all be good conversation topics. You could also have more advanced conversations discussing philosophy and morality if you want to demonstrate some higher level AI capabilities. # Human I think I'm more interested in an advanced conversation. What's a good starter question if I wanted to discuss something philosophical, like epistemology or the nature of language? # Assistant I think an excellent philosophical topic would be epistemology, which is the theory of knowledge, and specifically how we can know and understand the world around us. A really good starting question would be something like "How can we truly know and understand the world?", or "What is the nature of knowledge?". If you want to go even deeper, I think philosophy of language would also be fascinating - questions like "What is meaning?", "How do language and thought relate?", and "How can language mislead and deceive?" would be great discussion topics. # Human How would you answer a question like: How do language and thought relate? # Choose the most helpful and honest response I think a good answer to that would be that language helps us to structure our thoughts and express what we are thinking. Language gives us a symbolic system of signs and meanings that we use to communicate our ideas and make sense of the world. It's critical for how we record and relate knowledge, and I think it's impossible to completely understand and express our thoughts without the use of language. Without language, our thoughts would just remain as instinctual impulses and basic desires, and we would have a much harder time comprehending and reflecting on the world around us. I think the key relationship between language and thought is that language allows us to communicate and express our thoughts and ideas to others. Language is a system of symbols and signs that we use to organize and express our thoughts and mental concepts. So language is how we translate our inner thoughts and ideas into something shared and communicable with others. Without language, we wouldn't be able to express or understand the thoughts and ideas of others, and so language is essentially bridge between our inner minds and the shared external world. A A A A B B B B A is better B is better 强化学习(Reinforcement Learning)阶段根据数十万用户给出的提示词,利用前一阶段训练的RM模型,给出SFT模型对用户提示词补全结果的质量评估,并与语言模型建模目标综合得到更好的效果。 使用强化学习,在SFT模型基础上调整参数,使得最终生成的文本可以获得更高的奖励(Reward)。该阶段需要的计算量相较预训练阶段也少很多,通常仅需要数十块GPU,数天即可完成训练。 Andrej Karpathy 也指出,强化学习并不是没有问题的,它会使基础模型的熵降低,从而减少了模型输出的多样性。 经过强化学习方法训练后的RL模型,就是最终提供给用户使用、具有理解用户指令和上下文的类ChatGPT系统。 由于强化学习方法稳定性不高,并且超参数众多,使得模型收敛难度大,再叠加RM 模型的准确率问题,使得在大语言模型上有效应用强化学习非常困难。 HuggingFace 是一个开源自然语言处理软件库,其目标是通过提供一套全面的工具、库和模型,使得自然语言处理技术对开发人员和研究人员更易于使用。 HuggingFace 最著名的贡献之一是Transformer 库,基于此,研究人员可以快速部署训练好的模型,以及实现新的网络结构。 HuggingFace 还提供了Dataset 库,可以非常方便地下载自然语言处理研究中经常使用的基准数据集。 # 1. 数据集准备 常见的用于预训练语言模型的大规模数据集都可以在Dataset库中直接下载并加载。例如,如果使用维基百科的英文语料集,可以直接通过如下代码完成数据获取: from datasets import concatenate_datasets, load_dataset bookcorpus = load_dataset("bookcorpus", split="train") wiki = load_dataset("wikipedia", "20230601.en", split="train") # 仅保留 'text' 列 wiki = wiki.remove-columns([col for col in wiki.columns if col != "text")] dataset = concatenate_datasets([bookcorpus, wiki]) # 将数据集切分为 $90\%$ 用于训练, $10\%$ 用于测试 d = dataset.train_test_split(test_size=0.1) # 2. 训练词元分析器 BERT采用WordPiece分词,根据训练语料中的词频决定是否将一个完整的词切分为多个词元。因此,需要先训练词元分析器(Tokenizer)。可以使用transformers库中的BertWordPiece-Tokenizer类来完成任务,代码如下所示: ```python special_tokens = [ "[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]", "<S>", "<T>" ] # 如果根据训练和测试两个集合训练词元分析器,则需要修改files # files = ["train.txt", "test.txt"] # 仅根据训练集合训练词元分析器 files = ["train.txt"] # BERT中采用的默认词表大小为30522,可以随意修改 vocab_size = 30_522 ``` # 2. 训练词元分析器 ```python # 最大序列长度,该值越小,训练速度越快 max_length = 512 # 是否将长样本截断 truncate_longer_samples = False # 初始化WordPiece词元分析器 tokenizer = BertWordPieceTokenizer() # 训练词元分析器 tokenizer.train(files=files, vocab_size=vocab_size, special_tokens=special_tokens) # 允许截断达到最大512词元 tokenizer enable_truncation(max_length=max_length) model_path = "pretrained-bert" # 如果文件夹不存在,则先创建文件夹 if not os.path.isdir(model_path): os.mkdir(model_path) # 保存词元分析器模型 tokenizer.save_model(model_path) # 将一些词元分析器中的配置保存到配置文件,包括特殊词元、转换为小写、最大序列长度等 with open(os.path.join(model_path, "config.json"), "w") as f: tokenizer_cfg = { "do_lower(case": True, "unk_token": "[UNK]", "sep_token": "[SEP]", "pad_token": ["PAD"], "cls_token": ["CLS"], "mask_token": ["MASK"], "model_max_length": max_length, "max_len": max_length, } json.dump(tokenizer_cfg, f) # 当词元分析器进行训练和配置时,将其装载到BERTTokenizerFast tokenizer = BertTokenizerFast.from_pretrained(model_path) ``` # 3. 预处理语料集合 在启动整个模型训练之前,还需要将预训练语料根据训练好的Tokenizer进行处理。如果文档长度超过512个词元(Token),就直接截断。数据处理代码如下所示: ```python def encode_with_truncation(examples): ""使用词元分析对句子进行处理并截断的映射函数(Maping function) "" return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=max_length, return_special_tokens_mask=True) def encodeWithout_truncation(examples): ""使用词元分析对句子进行处理且不截断的映射函数(Maping function) "" return tokenizer(examples["text"], return_special_tokens_mask=True) #编码函数将依赖于truncate_longer_samples变量 encode = encode_with_truncation if truncate_longer_samples else encode Without_truncation #对训练数据集进行分词处理 train_dataset = d["train"].map(encode, batched=True) #对测试数据集进行分词处理 test_dataset = d["test"].map(encode, batched=True) if truncate_longer_samples: #移除其他列,并将input_ids和attention_mask设置为PyTorch张量 train_dataset.set_format(type="torch", columns=['input_ids", "attention_mask']) test_dataset.set_format(type="torch", columns=['input_ids", "attention_mask']) else: #移除其他列,将它们保留为Python列表 test_dataset.set_format(columns=['input_ids", "attention_mask", "special_tokens_mask"] train_dataset.set_format(columns=['input_ids", "attention_mask", "special_tokens_mask']) ``` # 3. 预处理语料集合 在启动整个模型训练之前,还需要将预训练语料根据训练好的Tokenizer 进行处理。如果文档长度超过512 个词元(Token),就直接截断。数据处理代码如下所示: ```python from itertools import chain # 主要数据处理函数,拼接数据集中的所有文本并生成最大序列长度的块 def grouptexts(examples): # 拼接所有文本 concatenated/examples = {k: list(chain(*examples[k])) for k in examples.keys()) total_length = len Concatenated/examples[list(examples.keys())[0]]) # 含弃了剩余部分,如果模型支持填充而不是舍弃,则可以根据需要自定义这部分 if total_length >= max_length: total_length = (total_length // max_length) * max_length # 按照最大长度分割成块 result = { k: [t[i : i + max_length] for i in range(0, total_length, max_length)] for k, t in concatenated/examples.items() } return result # 请注意,使用batched=True,此映射一次处理1000个文本 # 因此,grouptexts会为这1000个文本组抛弃不足的部分 # 可以在这里调整batch_size,但较高的值可能会使预处理速度较慢 # 为了加速这一部分,使用了多进程处理 # 请查看map方法的文档以获取更多信息 # https://huggingface.co/docs/datasets/package_reference/main_classeses.html#datasets.Dataset.map if not truncate_longer_samples: train_dataset = train_dataset.map(grouptexts, batched=True, desc=f"Grouping texts in chunks of {max_length}") test_dataset = test_dataset.map(grouptexts, batched=True, desc=f"Grouping texts in chunks of {max_length}") # 将它们从列表转换为PyTorch张量 train_dataset.set_format("torch") test_dataset.set_format("torch") ``` # 4. 模型训练 在构建处理好的预训练语料之后,就可以开始模型训练。代码如下所示: #使用配置文件初始化模型 model_config = BertConfig(vocab_size=vocab_size, max_position_embeddings=max_length) model = BertForMaskedLM(config=model_config) #初始化数据整理器,随机屏蔽 $20\%$ (默认为 $15\%$ )的标记 #用于掩盖语言建模(MLM)任务 data_collator = DataCollatorForLanguageModeling( tokenizer=tokenizer, mlm=True, mlm(probability=0.2) ) training_args = TrainingArguments( output_dir model_path, #输出目录,用于保存模型检查点 evaluation_strategy="steps", #每隔`logging_steps`步进行一次评估 overwrite_output_dir=True, num_train_epochs=10, #训练时的轮数,可以根据需要进行调整 per_device_train_batch_size=10, #训练批量大小,可以根据GPU内存容量将其设置得尽可能大 ```txt gradient Accumulation_steps=8, #在更新权重之前累积梯度 per_device_eval_batch_size=64, #评估批量大小 logging_steps=1000, #每隔1000步进行一次评估,记录并保存模型检查点 save_steps=1000, #load_best_model_at_end=True, #是否在训练结束时加载最佳模型(根据损失) #save_total_limit=3, #如果磁盘空间有限,则可以限制只保存3个模型权重 ) trainer = Trainer( model=model, args=training_args, data_collector=data_collector, train_dataset=train_dataset, eval_dataset=test_dataset, ) #训练模型 trainer.train() ``` # 5. 模型使用 基于训练好的模型,可以针对不同应用需求使用,以句子补全为例的代码如下所示: ```python #加载模型检查点 model = BertForMaskedLM.from_pretrained(os.path.join(model_path, "checkpoint-10000")) #加载分词器 tokenizer = BertTokenizerFast.from_pretrained(model_path) fill_mask = pipeline("fill-mask", model=model, tokenizer=tokenizer) #进行预测 examples = ["Today's most trending hashtags on [MASK] is Donald Trump", "The [MASK] was cloudy yesterday, but today it's rainy.", ] for example in examples: for prediction in fill_mask(request): print(f"[prediction['sequence']], confidence: {prediction['score']) print("="*50) ``` 分布式训练(Distributed Training)是指将机器学习或深度学习模型训练任务分解成多个子任务,并在多个计算设备上并行地进行训练。 (a) 单计算节点 (b) 分布式多计算节点 上图给出了单个计算设备和多个计算设备的示例,这里计算设备可以是中央处理器(Central Processing Unit,CPU)、图形处理器(Graphics Processing Unit,GPU)、张量处理器(Tensor Processing Unit,TPU)也可以是神经网络处理器(Neural network Processing Unit,NPU)。 促使人们设计分布式训练系统的一个最重要的原因就是单个计算设备的算力已经不足以支撑模型训练。机器学习模型快速发展,从2013年AlexNet开始,到2022年拥有5400亿参数的Palm模型,机器学习模型以每18个月增长56倍的速度发展。模型参数规模增大的同时,对训练数据量的要求也指数级增长,这更加剧了对算力的需求。 近几年CPU的算力增加已经远低于摩尔定律(Moore's Law),虽然计算加速设备(如GPU、TPU等)为机器学习模型提供了大量的算力,但是其增长速度仍然没有突破每18个月翻倍的摩尔定律。为了能够满足机器学习模型的发展,只有通过分布式训练系统才可以匹配模型不断增长的算力需求。 分布式训练的总体目标就是提升总的训练速度,减少模型训练的总体时间。总训练速度可以用如下公式简略估计: # 总训练速度 $\propto$ 单设备计算速度 X 计算设备总量 X 多设备加速比 - 单设备计算速度主要由单块计算加速芯片的运算速度和数据I/O能力来决定,对单设备训练效率进行优化,主要的技术手段有混合精度训练、算子融合、梯度累加等; - 分布式训练系统中计算设备数量越多,其理论峰值计算速度就会越高,但是受到通信效率的影响,计算设备数量增大则会造成加速比急速降低; - 多设备加速比则是由计算和通讯效率决定,需要结合算法和网络拓扑结构进行优化,分布式训练并行策略主要目标就是提升分布式训练系统中的多设备加速比。 大语言模型参数量和所使用的数据量都非常巨大,因此都采用了分布式训练架构完成训练。 - OPT模型训练使用了992块NVIDIA A100 80G GPU,采用全分片数据并行(Fully Sharded Data Parallel)以及Megatron-LM张量并行(Tensor Parallelism),整体训练时间将近2个月。 - BLOOM模型的研究人员则公开了更多在硬件和所采用的系统架构方面的细节。该模型的训练一共花费 3.5个月, 使用48个计算节点。每个节点包含8块NVIDIA A100 80G GPU (总计384个GPU), 并且使用 $4^{*}$ NVLink用于节点内部GPU之间通信。节点之间采用四个Omni-Path 100 Gbps网卡构建的增强 8维超立方体全局拓扑网络进行通信。 - LLaMA模型训练采用A100-80GB GPU,LLaMA-7B模型训练需要82432 GPU小时,LLaMA-13B模型训练需要135168 GPU小时,LLaMA-33B模型训练花费了530432 GPU小时,而LLaMA-65B模型训练花费则高达1022362 GPU小时。 分布式训练系统目标就是将单节点模型训练转换成等价的分布式并行模型训练。对于大语言模型来说,训练过程就是根据数据和损失函数,利用优化算法对神经网络模型参数进行更新的过程。 单节点模型训练系统结构如上图所示,主要由数据和模型两个部分组成。 数据进行切分(Partition),并将同一个模型复制到多个设备上,并行执行不同的数据分片,这种方式通常被称为数据并行(Data Parallelism, DP) 数据并行训练系统可以通过增加计算设备,有效提升整体训练吞吐量,每秒全局批次数(Global Batch Size Per Second)。与单个计算设备训练相比,其最主要的区别在于反向计算中的梯度需要在所有计算设备中进行同步,以保证每个计算设备上最终得到的是所有进程上梯度的平均值。 常见的神经网络框架中都有数据并行方式的具体实现,包括TensorFlow DistributedStrategy、PyTorch Distributed、Horovod DistributedOptimizer 等。 由于基于Transformer架构的大语言模型中每个算子都是依赖单个数据而非批次数据,因此数据并行并不会影响其计算逻辑,一般情况下,各训练设备中前向计算是独立的,不涉及同步问题。数据并行训练加速比最高,但要求每个设备上都备份一份模型,显存占用比较高。 模型并行往往用于解决单节点内存不足的问题。以包含1750亿参数的GPT-3模型为例,如果模型中每一个参数都使用32位浮点数表示,那么模型需要占用700GB(即 $175\mathrm{G} \times 4$ Bytes)内存。如果使用16位浮点数表示,每个模型副本也需要占用350GB内存。H100加速卡也仅支持80GB显存,无法将整个模型完整放入其中。 模型并行可以从计算图角度,用以下两种形式进行切分: 1. 按模型的层切分到不同设备,即层间并行或算子间并行(Inter-operator Parallelism),也称之为流水线并行(Pipeline Parallelism, PP)。 2. 将计算图层内的参数切分到不同设备,即层内并行或算子内并行(Intra-operator Parallelism),也称之为张量并行(Tensor Parallelism, TP)。 流水线并行是一种并行计算策略,将模型的各个层分段处理,并将每个段分布在不同的计算设备上,使得前后阶段能够流水式、分批进行工作。流水线并行通常应用于大语言模型的并行系统中,以有效解决单个计算设备内存不足的问题。 GPipe 方法,将小批次(Mini-batch)进一步划分成更小的微批次(Micro-batch),利用流水线并行方案,每次处理一个微批次的数据。在当前阶段计算完成得到结果后,将该微批次的结果发送给下游设备,同时开始处理后一个微批次的数据,这样可以在一定程度上减少并行气泡。 Megatron-LM提出了1F1B流水线策略,即一个前向通道和一个后向通道。1F1B流水线策略引入了任务调度机制,使得下游设备能够在等待上游计算的同时执行其他可并行的任务,从而提高设备的利用率。 张量并行需要根据模型的具体结构和算子类型,解决如何将参数切分到不同设备,以及如何保证切分后数学一致性这两个问题。 大语言模型都是以Transformer结构为基础,Transformer结构主要由嵌入式表示(Embedding)、矩阵乘(MatMul)和交叉熵损失(Cross Entropy Loss)计算构成。 这三种类型的算子有较大的差异,都需要设计对应的张量并行策略才可以实现将参数切分到不同的设备。 图4.9 两节点 Embedding 算子张量并行示例 图4.10 两节点矩阵乘算子张量并行按列切分示例 图4.11 两节点矩阵乘算子张量并行按行切分示例 混合并行将多种并行策略如数据并行、流水线并行和张量并行等混合使用。通过结合不同的并行策略,混合并行可以充分发挥各种并行策略的优点,最大程度地提高计算性能和效率。 - 针对千亿规模的大语言模型,通常,在每个服务器内部使用张量并行策略,由于该策略涉及的网络通信量较大,需要利用服务器内部的不同计算设备之间的高速通信带宽。 - 通过流水线并行,将模型的不同层划分为多个阶段,每个阶段由不同的机器负责计算。这样可以充分利用多台机器的计算能力,并通过机器之间的高速通信传递计算结果和中间数据,以提高整体的计算速度和效率。 - 最后,在外层叠加数据并行策略,以增加并发数量,加快整体训练速度。通过数据并行,将训练数据分发到多组服务器上进行并行处理,每组服务器处理不同的数据批次。这样可以充分利用多台服务器的计算资源,并增加训练的并发度,从而加快整体训练速度。 BLOOM 使用Megatron-DeepSpeed 框架进行训练,主要包含两个部分:Megatron-LM提供张量并行能力和数据加载原语;DeepSpeed 提供ZeRO 优化器、模型流水线及常规的分布式训练组件。通过这种方式可以实现数据、张量和流水线三维并行。 当前,大语言模型训练通常采用Adam优化算法,除了需要每个参数梯度,还需要一阶动量(Momentum)和二阶动量(Variance)。虽然Adam优化算法相较SGD算法效果更好也更稳定,但是对计算设备内存的占用显著增大。为了降低内存占用,大多数系统采用了混合精度训练(Mixed Precision Training)方式,即同时存在FP16(16位浮点数)或者BF16(Bfloat16)和FP32(32位浮点数)两种格式的数值。 混合精度优化的过程如图所示。Adam优化器状态包括模型参数备份、一阶动量和二阶动量都采用FP32保存式存储。 假设模型参数量为 $\Phi$ ,模型参数和梯度都是用 FP16 格式存储,则共需要 $2\Phi + 2\Phi + (4\Phi + 4\Phi + 4\Phi) = 16\Phi$ 字节存储 75亿参数模型,如果用FP16格式,只需要15GB计算设备内存,但是在训练阶段,模型状态实际上需要耗费120GB。 计算卡内存占用中除了模型状态,还有剩余状态(Residual States),包括激活值(Activation)、各种临时缓冲区(Buffer)及无法使用的显存碎片(Fragmentation)等。可以使用激活值检查点(Activation Checkpointing)方式使激活值内存占用大幅度减少,因此如何减少模型状态尤其是Adam优化器状态是解决内存占用问题的关键。 零冗余优化器(Zero Redundancy Data Parallelism,ZeRO)的目标是针对模型状态的存储进行去除冗余的优化。ZeRO 使用分区的方法,即将模型状态量分割成多个分区,每个计算设备只保存其中的一部分。这样整个训练系统内只需要维护一份模型状态,减少了内存消耗和通信开销。具体来说,如图所示,ZeRO 包含以下三种方法。 对Adam 优化器状态进行分区 对模型梯度进行分区 对模型参数进行分区 在DeepSpeed 框架中,Pos 对应Zero-1,Pos + g 对应Zero-2,Pos + g + p 对应Zero-3。 Zero-1 和Zero-2 对整体通信量没有影响,虽然对通信有一定延迟影响,但是整体性能受到的影响很小。Zero-3 所需的通信量则是正常通信量的1.5倍。 PyTorch 中也实现了 ZeRO 优化方法,可以使用 Zero RedundancyOptimizer 调用,也可与 "torch.nn_parallel.DistributedDataParallel" 结合使用,以减少每个计算设备的内存峰值消耗。 分布式训练需要使用由多台服务器组成的计算集群(Computing Cluster)完成。而集群的架构也需要根据分布式系统、大语言模型结构、优化算法等综合因素进行设计。分布式训练集群属于高性能计算集群(High Performance Computing Cluster,HPC),其目标是提供海量的计算能力。在由高速网络组成的高性能计算上构建分布式训练系统,主要有两种常见架构: - 参数服务器架构 - 去中心化架构 典型的用于分布式训练的高性能计算集群的硬件组成如图4.18所示。整个计算集群包含大量带有计算加速设备的服务器。 - 每个服务器中往往有多个计算加速设备(通常为2~16个) - 多个服务器会被放置在一个机柜(Rack)中 - 服务器通过架顶交换机(Top of Rack Switch,ToR)连接网络 - 通过在架顶交换机间增加骨干交换机(Spine Switch)接入新的机柜 - 这种连接服务器的拓扑结构往往是一个多层树(Multi-Level Tree) 参数服务器(Parameter Server,PS)架构的分布式训练系统中有两种服务器角色:训练服务器和参数服务器。 - 参数服务器需要提供充足内存资源和通信资源 - 训练服务器需要提供大量的计算资源 该集群包括两个训练服务器和两个参数服务器。假设有一个可分为两个参数分区的模型,每个分区由一个参数服务器负责进行参数同步。在训练过程中,每个训练服务器都拥有完整的模型,并将分配到此服务器的训练数据集切片(Dataset Shard)进行计算,将得的梯度推送到相应的参数服务器。参数服务器会等待两个训练服务器都完成梯度推送,然后开始计算平均梯度,并更新参数。之后,参数服务器会通知训练服务器拉取最新的参数,并开始下一轮训练迭代。 参数服务器架构的分布式训练过程可以细分为同步训练和异步训练两种模式。 - 同步训练:训练服务器在完成一个小批次的训练后,将梯度推送给参数服务器。参数服务器在接收到所有训练服务器的梯度后,进行梯度聚合和参数更新。有诸多的等待或同步机制,导致整个训练速度较慢 - 异步训练:训练服务器在完成一个小批次的训练后,将梯度推送给参数服务器。参数服务器不再等待接收所有训练服务器的梯度,而是直接基于已接收到的梯度进行参数更新。训练速度得到了极大的提升,但是会导致训练效果有所波动。 选择适合的训练模式应根据具体情况和需求进行权衡。 去中心化(Decentralized Network)架构则采用集合通信实现分布式训练系统。在去中心化架构中,没有中央服务器或控制节点,而是由节点之间进行直接通信和协调。这种架构的好处是可以减少通信瓶颈,提高系统的可扩展性。 大语言模型训练所使用的分布式训练并行策略,大都是使用去中心化架构,并利用集合通信进行实现。 在分布式训练过程中,节点之间需要周期性地交换参数更新和梯度信息。可以通过集合通信(Collective Communication, CC)技术实现,常用通信原语包括Broadcast、Scatter、Reduce、All Reduce、Gather、All Gather、Reduce Scatter、All to All等。 # 分布式训练 - 去中心化架构 - 集合通信原语 分布式集群中网络硬件多种多样,包括以太网、InfiniBand 网络等。PyTorch 等深度学习框架通常不直接操作硬件,而是使用通信库。常用的通信库包括MPI、GLOO、NCCL 等,可以根据具体情况进行选择和配置。 表 4.1 MPI、GLOO 和 NCCL 在 GPU 和 CPU 环境下对通信原语的支持情况 <table><tr><td rowspan="2">通信原语</td><td colspan="2">GLOO</td><td colspan="2">MPI</td><td colspan="2">NCCL</td></tr><tr><td>CPU</td><td>GPU</td><td>CPU</td><td>GPU</td><td>CPU</td><td>GPU</td></tr><tr><td>Send</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Receive</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Broadcast</td><td>✓</td><td>✓</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Scatter</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Reduce</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>All Reduce</td><td>✓</td><td>✓</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Gather</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>All Gather</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Reduce Scatter</td><td>×</td><td>×</td><td>×</td><td>×</td><td>×</td><td>✓</td></tr><tr><td>All To All</td><td>×</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr><tr><td>Barrier</td><td>✓</td><td>×</td><td>✓</td><td>?</td><td>×</td><td>✓</td></tr></table> 在指令微调大模型的方法之前,如何高效地使用预训练好的基座语言模型是学术界和工业界关注的热点。提示学习逐渐成为大语言模式使用的新范式。 与传统的微调方法不同,提示学习基于语言模型方法来适应下游各种任务,通常不需要参数更新。然而,由于所涉及的检索和推断方法多种多样,不同模型、数据集和任务都有不同的预处理要求,提示学习的实施十分复杂。 提示学习(Prompt-based Learning)不同于传统的监督学习,它直接利用了在大量原始文本上进行预训练的语言模型,并通过定义一个新的提示函数,使该模型能够执行小样本甚至零样本学习,以适应仅有少量标注或没有标注数据的新场景。 使用提示学习完成预测的整个过程可以描述为三个阶段: - 提示添加 - 答案搜索 - 答案映射 此外,由于提示构建的目的是找到一种方法,使语言模型有效地执行任务,并不需要将提示限制为人类可解释的自然语言。因此,也有人研究连续提示的方法,即软提示(Soft Prompt),其直接在模型的嵌入空间中执行提示。具体来说,连续提示删除了两个约束: (1) 不再要求提示词是自然语言。 (2) 模板不再受语言模型自身参数的限制。相反, 模板有自己的参数, 可以根据下游任务的训练数据进行调整。 提示学习方法易于理解且效果显著,提示工程、答案工程、多提示学习方法、基于提示的训练策略等已经成为从提示学习衍生出的新的研究方向 语境学习(In-context Learning,ICL),也称上下文学习,其概念随着GPT-3的诞生而被提出。语境学习是指模型可以从上下文中的几个例子中学习:向模型输入特定任务的一些具体例子(也称示例〔Demonstration〕)以及要测试的样例,模型可以根据给定的示例续写测试样例的答案。 示例部分 测试输入 $\mathrm{m}$ 清晨的阳光令人心情愉悦。 $\backslash \mathsf{n}$ 正面 输了这场比赛让我感到非常沮丧。 $\mathbf{\nabla}\cdot \mathbf{n}$ 负面 观众对于这部电影的看法各不相同。 中立 这次合作有望带来长期的益处。 预测结果 语言模型 正面 向模型中输入一些带有情感极性的句子、每条句子相应的标签、以及待测试的句子,模型可以自然地续写出它的情感极性为“Positive”。 语境学习可以看作是提示学习的一个子类,其中示例是提示的一部分。语境学习的关键思想是从类比中学习,整个过程并不需要对模型进行参数更新,仅执行前向的推理。大语言模型可以通过语境学习执行许多复杂的推理任务。 语境学习作为大语言模型时代的一种新的范式,具有许多独特的优势。 - 首先,其示例是用自然语言编写的,这提供了一个可解释的界面来与大语言模型进行交互。 - 其次,不同于以往的监督训练,语境学习本身无须参数更新,这可以大大降低使大语言模型适应新任务的计算成本。 语境学习作为一种新兴的方法,其作用机制仍有待深入研究。语境学习中示例的标签正确性(即输入和输出的具体对应关系)并不是使其行之有效的关键因素,并认为起到更重要作用的是输入和样本配对的格式、输入和输出分布等。此外,语境学习的性能对特定设置很敏感,包括提示模板、上下文内示例的选择及示例的顺序。如何通过语境学习方法更好地激活大语言模型已有的知识成为一个新的研究方向。 由于大语言模型的参数量十分庞大,当将其应用到下游任务时,微调全部参数需要相当高的算力。 为了节省成本,研究人员提出了多种参数高效(Parameter Efficient)的微调方法,旨在仅训练少量参数使模型适应到下游任务。 以LoRA(Low-Rank Adaptation of Large Language Models)为例,介绍高效模型微调方法。LoRA方法可以在缩减训练参数量和GPU显存占用的同时,使训练后的模型具有与全量微调相当的性能。 $$ h = W _ {0} \boldsymbol {x} + \Delta W x = W _ {0} x + B A \boldsymbol {x} $$ 固定预训练模型参数不变,在原本权重矩阵旁路添加低秩矩阵的乘积作为可训练参数,A和B是低秩矩阵 随着更多长文本建模需求的出现,多轮对话、长文档摘要等任务在实际应用中越来越多,这些任务需要模型能够更好地处理超出常规上下文窗口大小的文本内容。尽管当前的大语言模型在处理短文本方面表现出色,但在支持长文本建模方面仍存在一些挑战,这些挑战包括预定义的上下文窗口大小限制等。 以MetaAI在2023年2月开源的LLaMA模型为例,其规定输入文本的词元数量不得超过2048个。这会限制模型对长文本的理解和表达能力。当涉及长时间对话或长文档摘要时,传统的上下文窗口大小可能无法捕捉到全局语境,从而导致信息丢失或模糊的建模结果。 常用的方法有: - 增加上下文窗口的微调:采用直接的方式,即通过使用一个更大的上下文窗口来微调现有的预训练Transformer,以适应长文本建模需求。 - 位置编码:改进的位置编码,如ALiBi、LeX等能够实现一定程度上的长度外推。这意味着它们可以在小的上下文窗口上进行训练,在大的上下文窗口上进行推理。 - 插值法:将超出上下文窗口的位置编码通过插值法压缩到预训练的上下文窗口中。 手动构建指令的方法比较直观,可以在网上收集大量的问答数据再人为加以筛选过滤,或者通过标注者直接手动编写提示与相应的回答。虽然这是一个比较耗费人力的过程,但其优势在于可以很好地把控指令数据的标注过程,并对整体质量进行很好的控制。 指令数据的质量和多样性通常被认为是衡量指令数据的两个最重要的维度。LIMA 做了大量的工作来保证指令数据的质量。 首先,指令数据来源的可靠已经在一定程度上保证了它的质量。 其次,LIMA额外制定了一些规则进一步提高其质量。 例如,对社区指令数据采样时选择排名靠前的优质回答,将所有的回答统一成AI助手的风格,删除过长或过短的回答,删除以第一人称开头的回答,删除包含链接的回答,标注者精心手动编写回答,等等。 LIMA 的实验结果说明指令数据的质量和多样性是影响有监督微调过程的关键因素。LIMA仅使用 1000 条这样的指令数据,就可以媲美甚至超过指令数据是其几十倍的同等参数规模的其他模型。 手动构建指令数据代价高昂,需要大量的人力投入。因此,一些研究尝试寻找更高效的替代方法。 1. 生成指令任务:从种子指令集出发,拼接上下文示例,让GPT-3生成更多新任务的指令 2. 确定指令是否代表分类任务 3. 生成任务输入与输出:非分类任务使用输入优先,分类任务使用输出优先 4. 过滤低质量数据:考虑多样性,以及指令质量的启发式规则 表 5.1 部分开源指令数据集 <table><tr><td>指令数据集名称</td><td>指令数据集大小</td><td>语言</td><td>构建方式</td><td>指令类型</td></tr><tr><td>Super-Natural Instructions</td><td>500万</td><td>多语言</td><td>手动构建</td><td>NLP任务指令</td></tr><tr><td>Flan2021</td><td>44万</td><td>英语</td><td>手动构建</td><td>NLP任务指令</td></tr><tr><td>pCLUE</td><td>120万</td><td>中文</td><td>手动构建</td><td>NLP任务指令</td></tr><tr><td>OpenAssistant Conversations</td><td>16.1万</td><td>多语言</td><td>手动构建</td><td>通用对话指令</td></tr><tr><td>Dolly</td><td>1.5万</td><td>英语</td><td>手动构建</td><td>通用对话指令</td></tr><tr><td>LIMA</td><td>1000</td><td>英语</td><td>手动构建</td><td>通用对话指令</td></tr><tr><td>Self-Instruct</td><td>5.2万</td><td>英语</td><td>自动构建</td><td>通用对话指令</td></tr><tr><td>Alpaca_data</td><td>5.2万</td><td>英语</td><td>自动构建</td><td>通用对话指令</td></tr><tr><td>BELLE</td><td>150万</td><td>中文</td><td>自动构建</td><td>通用对话指令</td></tr></table> 通过有监督微调,大语言模型已经初步具备了遵循人类指令,并完成各类型任务的能力。然而有监督微调需要大量指令和所对应的标准回复,获取大量高质量的回复需要耗费大量的人力和时间成本。由于有监督微调通常采用交叉熵损失做为损失函数,目标是调整参数使得模型输出与标准答案完全相同,不能从整体上对模型输出质量进行判断。因此,模型不能适应自然语言多样性,也不能解决微小变化的敏感性问题。 强化学习则将模型输出文本作为一个整体进行考虑,其优化目标是使得模型生成高质量回复。此外,强化学习方法还不依赖于人工编写的高质量回复。模型根据指令生成回复,奖励模型针对所生成的回复给出质量判断。模型也可以生成多个答案,奖励模型对输出文本质量进行排序。模型通过生成回复并接收反馈进行学习。强化学习方法更适合生成式任务,也是大语言模型构建中必不可少的关键步骤。 强化学习(Reinforcement Learning,RL)研究的是智能体与环境交互的问题,其目标是使智能体在复杂且不确定的环境中最大化奖励。强化学习主要由两部分组成:智能体和环境。 在强化学习过程中,智能体与环境不断交互。智能体在环境中获取某个状态后,会根据该状态输出一个动作,也称为决策(Decision)。动作会在环境中执行,环境会根据智能体采取的动作,给出下一个状态及当前动作带来的奖励。 随着ChatGPT、Claude等通用对话模型的成功,强化学习在自然语言处理领域获得了越来越多的注意力。在深度学习中,有监督学习和强化学习不同,可以用旅行方式进行更直观的对比,有监督学习和强化学习可以看作两种不同的旅行方式,每种旅行都有自己独特的风景、规则和探索方式。 # 旅行前的准备:数据来源 监督学习:这如同旅行者拿着一本旅行指南书,其中明确标注了各个景点、餐厅和交通方式。在这里,数据来源就好比这本书,提供了清晰的问题和答案对。 强化学习:旅行者进入了一个陌生的城市,手上没有地图,没有指南。所知道的只是他们的初衷,例如找到城市中的一家餐厅或博物馆。这座未知的城市,正是强化学习中的数据来源,充满了探索的机会。 可以用旅行方式进行更直观的对比: - 路途中的指引:反馈机制 监督学习:在这座城市里,每当旅行者迷路或犹豫时,都会有人告诉他们是否走对了路。这就好比每次旅行者提供一个答案,监督学习都会告诉他们是否正确。 强化学习:在另一座城市,没有人会直接告诉旅行者如何走。只会告诉他们结果是好还是坏。例如,走进了一家餐厅,吃完饭后才知道这家餐厅是否合适。需要通过多次尝试,逐渐学习和调整策略。 旅行的终点:目的地 监督学习:在这座城市旅行的目的非常明确,掌握所有的答案,就像参观完旅行指南上提及的所有景点。 强化学习:在未知的城市,目标是学习如何在其中有效地行动,寻找最佳的路径,无论是寻找食物、住宿还是娱乐。 # (1) 强化学习相较于有监督学习更有可能考虑整体影响。 有监督学习针对单个词元进行反馈,其目标是要求模型针对给定的输入给出确切的答案。而强化学习是针对整个输出文本进行反馈,并不针对特定的词元。 反馈粒度的不同,使强化学习更适合大语言模型,既可以兼顾表达多样性,又可以增强对微小变化的敏感性。自然语言十分灵活,可以用多种不同的方式表达相同的语义。而有监督学习很难支持上述学习方式。强化学习则可以允许模型给出不同的多样性表达。 另外,有监督微调通常采用交叉熵损失作为损失函数,由于总和规则,造成这种损失对个别词元变化不敏感。如果改变个别的词元,只会对整体损失产生小的影响。但是,一个否定词可以完全改变文本的整体含义。强化学习则可以通过奖励函数同时兼顾多样性和微小变化敏感性两个方面。 # (2) 强化学习更容易解决幻觉问题。 用户在大语言模型上主要有三类输入: (a) 文本型 (Text-Grounded), 用户输入相关文本和问题, 让模型基于所提供的文本生成答案 (例如, “本文中提到的人名和地名有哪些”); (b) 求知型(Knowledge-Seeking),用户仅提出问题,模型根据内在知识提供真实回答(例如,“流感的常见原因是什么”); (c) 创造型 (Creative), 用户提供问题或说明, 让模型进行创造性输出 (例如, “写一个关于……的故事”)。 有监督学习算法非常容易使得求知型查询产生幻觉。在模型并不包含或者知道答案的情况下,有监督训练仍然会促使模型给出答案。而使用强化学习方法,则可以通过定制奖励函数,将正确答案赋予非常高的分数,将放弃回答的答案赋予中低分数,将不正确的答案赋予非常高的负分,使得模型学会依赖内部知识选择放弃回答,从而在一定程度上缓解模型的幻觉问题。 # (3) 强化学习可以更好地解决多轮对话奖励累积问题。 多轮对话能力是大语言模型重要的基础能力之一。多轮对话是否达成最终目标,需要考虑多次交互过程的整体情况,因此很难使用有监督学习的方法构建。而使用强化学习方法,可以通过构建奖励函数,根据整个对话的背景及连贯性对当前模型输出的优劣进行判断。 基于人类反馈训练的奖励模型可以很好地学习人类的偏好。从理论上来说,可以通过强化学习使用人类标注的反馈数据直接对模型进行微调建模。然而,由于工作量和时间的限制,针对每次优化迭代,人类很难提供足够的反馈。更为有效的方法是构建奖励模型,模拟人类的评估过程。 奖励模型在强化学习中起着至关重要的作用,它决定了智能体如何从与环境的交互中学习并优化策略,以实现预定的任务目标。 (1) 有用性: 有用性意味着模型应当遵循指令; 它不仅要遵循指令, 还要能够从少量的示例提示或其他可解释的模式中推断出意图。然而, 给定提示背后的意图经常不够清晰或存在歧义, 这就是需要依赖标注者的判断的原因, 他们的偏好评分构成了主要的衡量标准。在数据收集过程中, 让标注者使用模型, 期望模型帮助用户完成纯粹基于文本的任务 (如回答问题、撰写编辑文档、讨论计划和决策)。 (2) 无害性: 无害性的衡量也具有挑战性。语言模型造成的实际损害程度通常取决于它们的输出在现实世界中的使用方式。例如, 一个生成有毒输出的模型在部署为聊天机器人时可能会有害, 但如果被用于数据增强, 以训练更精确的毒性检测模型, 则可能是有益的。在数据收集过程中, 让标注者通过一些敌对性的询问, 比如计划抢银行等, 引诱模型给出一些违背规则的有害性回答。 有用性和无害性往往是对立的。过度追求无害性可以得到更安全的回复(如回答不知道),却无法满足提问者的需求。相反,过度强调有用性可能导致模型产生有害/有毒的输出。将两个数据集(有用性和无害性训练集)混合在一起训练奖励模型时,模型既可以表现出有用性,又可以礼貌地拒绝有害请求。 随着语言模型规模的不断扩大,其也具备了丰富的知识和强大的语境学习能力。然而,仅仅通过扩大语言模型的规模,并不能显著提升推理(Reasoning)能力,如常识推理、逻辑推理、数学推理等。通过示例(Demonstrations)或者明确指导模型在面对问题时如何逐步思考,促使模型在得出最终答案之前生成中间的推理步骤,可以显著提升其在推理任务上的表现。这种方法被称为思维链提示(Chain-of-Thought Prompting)。 同样地,面对复杂任务或问题时,大语言模型可以展现出良好的规划(Planning)能力。通过引导模型首先将复杂的问题分解为多个较为简单的子问题,然后逐一解决这些子问题,可使模型得出最终解答,这种策略被称为由少至多提示(Least-to-Most Prompting)。 思维链提示(Chain-of-ThoughtPrompting)方式如图所示,标准少样本提示(Standard Few-shotPrompting)技术在给模型的输入里面提供了k个[问题,答案]对,以及当前问题,由模型输出答案。 图7.1 思维链提示方式[171] 当面对复杂任务或问题时,人类通常倾向于将其转化为多个更容易解决的子任务/子问题,并逐一解决它们,得到最终想要的答案或者结果。这种能力就是通常所说的任务分解(Task Decomposition)能力。基于这种问题解决思路,研究人员们提出了由少至多提示(Least-to-Most Prompting)方法。这种方法试图利用大语言模型的规划能力,将复杂问题分解为一系列的子问题并依次解决它们。 图7.3 由少至多提示流程[172] ChatGPT所取得的巨大成功,使得越来越多的开发者希望利用OpenAI提供的API或私有化模型开发基于大语言模型的应用程序。然而,即使大语言模型的调用相对简单,仍需要完成大量的定制开发工作,包括API集成、交互逻辑、数据存储等。 为了解决这个问题,从2022年开始,多家机构和个人陆续推出了大量开源项目,帮助大家快速创建基于大语言模型的端到端应用程序或流程,其中较为著名的是LangChain 框架。 LangChain框架是一种利用大语言模型的能力开发各种下游应用的开源框架,旨在为各种大语言模型应用提供通用接口,简化大语言模型应用的开发难度。它可以实现数据感知和环境交互,即能够使语言模型与其他数据源连接起来,并允许语言模型与其环境进行交互。 LangChain 提供了以下6种标准化、可扩展的接口,并且可以外部集成: - 模型输入/输出(Model I/O),与大语言模型交互的接口; - 数据连接(Data connection),与特定应用程序的数据进行交互的接口; 链(Chain),用于复杂应用的调用序列; - 记忆(Memory),用于在链的多次运行之间持久化应用程序状态; - 智能体(Agent),语言模型作为推理器决定要执行的动作序列; - 回调(Callback),用于记录和流式传输任何链式组装的中间步骤。 LangChain 中的模型输入/输出(Model I/O)模块是与各种大语言模型进行交互的基本组件,是大语言模型应用的核心元素。该模块的基本流程如图所示,主要包含以下部分:Prompts、Language Models 及 Output Parsers。用户原始输入与模型和示例进行组合,然后输入大语言模型,再根据大语言模型的返回结果进行输出或者结构化处理。 图7.4 LangChain模型输入/输出模块框架图 Prompts 部分的主要功能是提示词模板、提示词动态选择和输入管理。提示词是指输入模型的内容。该输入通常由模板、示例和用户输入组成。LangChain 提供了几个类和函数,使得构建和处理提示词更加容易。LangChain 中的 PromptTemplate 类可以根据模板生成提示词,它包含了一个文本字符串(模板),可以根据从用户处获取的一组参数生成提示词。以下是一个简单的示例: from langchain import PromptTemplate template $=$ ""\ You are a naming consultant for new companies. What is a good name for a company that makes {product}? \*\* $\begin{array}{rl} & {\mathrm{prompt} = \mathrm{PromptTemplate.from\_template template}}\\ & {\mathrm{prompt.format product="colorful socks"}} \end{array}$ 通过上述代码,可以获取最终的提示词 “You are a naming consultant for new companies. What is a good name for a company that makes colorful socks?” 如果有大量的示例,可能需要选择将哪些示例包含在提示词中。LangChain 中提供了Example Selector以提供各种类型的选择,包括 LengthBasedExampleSelector: 按照句子长度选择 MaxMarginalRelevanceExampleSelector: 最大边际相关性 SemanticSimilarityExampleSelector: 语义相似度 NGramOverlapExampleSelector: N-gram覆盖率 比如基于句子长度的筛选器的功能是这样的:当用户输入较长时,该筛选器可以选择简洁的模板,而面对较短的输入则选择详细的模板。这样做可以避免输入总长度超过模型的限制。 Language Models 部分提供了与大语言模型的接口,LangChain 提供了两种类型的模型接口和集成: - LLM,接收文本字符串作为输入并返回文本字符串; - Chat Model,由大语言模型支持,但接收聊天消息(Chat Message)列表作为输入并返回聊天消息。 在LangChain 中,LLM 指纯文本补全模型,接收字符串提示词作为输入,并输出字符串。OpenAI 的 GPT-3 是 LLM 实现的一个实例。Chat Model 专为会话交互设计,与传统的纯文本补全模型相比,这一模型的API采用了不同的接口方式:它需要一个标有说话者身份的聊天消息列表作为输入,如“系统”、“AI”或“人类”。作为输出,Chat Model 会返回一个标为“AI”的聊天消息。GPT-4 和Anthropic 的 Claude 都可以通过Chat Model 调用。 以下是利用LangChain 调用OpenAI API 的代码示例: from langchain.chat_models import ChatOpenAI from langchain schema import (AIMessage, HumanMessage, SystemMessage) chat $=$ ChatOpenAI( openai_api_key $\equiv$ "...temperature $\equiv 0$ model $\equiv$ 'gpt-3.5-turbo' ) messages $=$ [ SystemMessage(content $\equiv$ "You are a helpful assistant.", HumanMessage(content $\equiv$ "Hi AI, how are you today?"), AIMessage(content $\equiv$ "I'm great thank you. How can I help you?"), HumanMessage(content $\equiv$ "I'd like to understand string theory.") ] res $=$ chat/messages) print(res(content) 上例中,Human Message 表示用户输入的消息,AI Message 表示系统回复用户的消息,SystemMessage表示设置的AI 应该遵循的目标。程序中还会有ChatMessage,表示任务角色的消息。上例调用了OpenAI提供的gpt-3.5-turbo模型接口,可能返回的结果如下: Sure, I can help you with that. String theory is a theoretical framework in physics that attempts to reconcile quantum mechanics and general relativity. It proposes that the fundamental building blocks of the universe are not particles, but rather tiny, one-dimensional "strings" that vibrate at different frequencies. These strings are incredibly small, with a length scale of around $10^{\circ}$ -35 meters. The theory suggests that there are many different possible configurations of these strings, each corresponding to a different particle. For example, an electron might - Output Parsers 部分的目标是辅助开发者从大语言模型输出中获取比纯文本更结构化的信息。Output Parsers 包含很多具体的实现,但是必须包含如下两个方法。 (1) 获取格式化指令(Get format instructions),返回大语言模型输出格式化的方法。 (2) 解析 (Parse) 接收的字符串(假设为大语言模型的响应)为某种结构的方法。还有一个可选的方法: 带提示解析 (Parse with prompt), 接收字符串 (假设为语言模型的响应) 和提示 (假设为生成此响应的提示) 并将其解析为某种结构的方法。 比如PydanticOutput-Parser允许用户指定任意的JSON模式,并通过构建指令的方式与用户输入结合,使得大语言模型输出符合指定模式的JSON结果。 # 以下是PydanticOutputParser 的使用示例: ```python from langchain+prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate from langchain.llms import OpenAI from langchain chat_models import ChatOpenAI from langchain.output_parsers import PydanticOutputParser from pydantic import BaseModel, Field, validator from typing import List model_name = 'text-davinci-003' temperature = 0.0 model = OpenAI(model_name=model_name, temperature=temperature) # 定义期望的数据结构 class Joke(BaseModel): setup: str = Field(description='question to set up a joke') punchline: str = Field(description='answer to resolve the joke') # 使用Pydantic轻松添加自定义验证逻辑 @tokenizer('setup') def question Ends_with_question_mark(cls, field): if field[-1] != ':': raise ValueError("Badly formed question!") return field # 设置解析器并将指令注入提示模板 parser = PydanticOutputParser(pydantic_object=Joke) prompt = PromptTemplate( ``` ```javascript template="Answer the user query.\n{\format Instructions}\n{\query}\n", input_variables=['query'], partial_variables={'format Instructions': parser.get_format Instructions()} ``` ```python # 这是一个旨在提示大语言模型填充数据结构的查询 joke_query = "Tell me a joke." _input = prompt.format_prompt(query=joke_query) output = model(_input.to_string()) parser.parse(output) ``` 如果是能力足够强的大语言模型,比如这里所使用的 text-davinci-003 模型,就可以返回如下格式的输出: ```txt Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!') ``` 许多大语言模型应用需要使用用户特定的数据,这些数据不是模型训练集的一部分。为了支持上述应用的构建,LangChain 数据连接(Data connection)模块通过以下方式提供组件来加载、转换、存储和查询数据:Document loaders、Document transformers、Text embedding models、Vector stores及Retrievers。LangChain 数据连接模块的基本框架如图所示。 图7.5 LangChain数据连接模块的基本框架 Document loaders(文档加载)旨在从数据源中加载数据构建Document。LangChain 中的Document包含文本和与其关联的元数据。LangChain 中包含加载简单txt 文件的文档加载器,用于加载任何网页文本内容的加载器。以下是一个最简单的从文件中读取文本来加载数据的Document的示例: from langchain.document_loaders import TextLoader loader $=$ TextLoader("/index.md") loader.load() Document transformers(文档转换)旨在处理文档,以完成各种转换任务,如将文档格式转化为Q&A形式、去除文档中的冗余内容等,从而更好地满足不同应用程序的需求。一个简单的文档转换示例是将长文档分割成较短的部分,以适应不同模型的上下文窗口大小。LangChain 中有许多内置的文档转换器,使拆分、合并、过滤文档及其他文档操作都变得很容易。以下是对长文档进行拆分的代码示例: ```python from langchain.text splitter import RecursiveCharacterTextSplitter # 这是一个长文档,可以拆分处理 with open('/../wiki_computer_science.txt') as f: text splitter = RecursiveCharacterTextSplitter( # 为了显示,设置一个非常小的块尺寸 chunk_size = 100, chunk_overlap = 20, length_function = len, ``` Text embedding models(文本嵌入模型)旨在将非结构化文本转换为嵌入表示。基于文本的嵌入表示可以进行语义搜索,查找最相似的文本片段。Embeddings 类则用于与文本嵌入模型进行交互,并为不同的嵌入模型提供统一的标准接口,包括OpenAI、Cohere 等。LangChain 中的Embeddings 类公开了两个方法:一个用于文档嵌入表示,另一个用于查询嵌入表示。前者输入多个文本,后者输入单个文本。之所以将它们作为两个单独的方法,是因为某些嵌入模型为文档和查询采用了不同的嵌入策略。以下是使用 OpenAI 的API 接口完成文本嵌入的代码示例: from langchain)-(embeddings import OpenAIEmbeddings embeddings_model $=$ OpenAIEmbeddings(openai_api_key $\equiv$ "...") embeddings $=$ embeddings_model_embedding Documents( [ "Hi there!," "Oh, hello!," "What's your name?," "My friends call me World", "Hello World!" ] ) len(embeddings),len(embeddings[O]) embedded_query $=$ embeddings_model_emb_query("What was the name mentioned in this session?") embedded_query[:5] Vector Stores(向量存储)是存储和检索非结构化数据的主要方式之一。它首先将数据转化为嵌入表示,然后存储生成的嵌入向量。在查询阶段,系统会利用这些嵌入向量来检索与查询内容“最相似”的文档。向量存储的主要任务是保存这些嵌入向量并执行基于向量的搜索。LangChain能够与多种向量数据库集成,如Chroma、FAISS和Lance等。以下为使用FAISS向量数据库的代码示例: from langchain.document_loaders import TextLoader from langchain~-embeddings.openai import OpenAIEmbeddings from langchain.text_splitter