赞
踩
写在最前面,为了彻底写清楚ChatGPT背后的所有关键细节,每个月不断深挖,从1月初写到6月底仍未完工,除了本文之外,过程中涉及到多篇文章(RL入门、论文解读、微调实战、代码实现、CV多模态),再加上之前写的Transformer、RL数学基础等多篇笔记,成了一个大系列
即:大模型/AIGC/ChatGPT系列:原理、论文、代码、实战,包含了
另,这些课程:ChatGPT原理、类ChatGPT微调实战、Stable Diffusion/MDJ的原理与实战、大模型论文100篇带读、LLM与langchain/KG/DB的结合实战、大模型项目开发线上营会比本系列讲的更加深入、细致、透彻
自从我那篇Transformer通俗笔记一经发布,然后就不断改、不断找人寻求反馈、不断改,其中一位朋友倪老师(之前我司NLP高级班学员现课程助教老师之一)在谬赞Transformer笔记无懈可击的同时,给我建议到,“后面估计可以尝试尝试在BERT的基础上,讲一讲prompt学习了”
再然后,当我还在各种改Transformer笔记的时候,12月初突然出来了一个ChatGPT刷爆朋友圈,即便很多之前不接触AI的朋友也在问ChatGPT这种类似聊天机器人却远胜一般聊天机器人各种问题(上一次出现这种盛况的还是16年的AlphaGo)。
据我观察,大家问ChatGPT的问题千奇百怪
所以ChatGPT就相当于你写代码或各类问题的私人顾问,而这个私人顾问能瞬间、精准理解你的意图,不会让你像用以前那种聊天机器人经常觉得智障甚至对牛弹琴,加之其背后依托的是人类级百科全书式的资料库,所以有人惊呼:ChatGPT会不会替代Google这类搜索引擎。
虽然一开始大部分技术者对待ChatGPT还是比较冷静的,毕竟它给的答案不像权威技术专家那样具备足够的公信力,也不像Google给出来源从而不能比较好的验证其正确程度,但后来很快发生的几件大事彻底改变了大家此前的看法
然目前关于ChatGPT中文的资料里,真正能让人一看就懂的非常非常少,当少数文章具备比较好的可读性之后,你又会发现一旦涉及算法细节就千篇一律的泛泛而谈,如果不是泛泛而谈的,则更多堆砌概念和公式,有的甚至漏洞百出
总之,中文资料里,可能因为instructGPT/ChatGPT刚出来不久的缘故,兼顾可读性、细节性、准确性的文章少的可怜
考虑到ChatGPT非一蹴而就,而是经过了各个前置技术的发展、迭代、结合而成,故本文逐一阐述
如你所见,自从1.6日开始写ChatGPT笔记,1.15日发布本文,但为把ChatGPT背后所涉及的关键技术阐述细致、透彻,故本文越写越长,长到最后成了一个系列,有的内容抽离出去独立成文,有的还在不断完善
再次强调说明下,本第一部分在23年2.10日有个重要修改
综上,为兼顾两者,且加之为避免本文篇幅过长而影响完读率,故把下面原先第一部分的大部分内容抽取出来放到了新一篇RL笔记里进一步细致阐述:强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO
第一部分 RL基础:什么是RL与MRP、MDP
1.1 入门强化学习所需掌握的基本概念
- 1.1.1 什么是强化学习:依据策略执行动作-感知状态-得到奖励
- 1.1.2 RL与监督学习的区别和RL方法的分类
1.2 什么是马尔科夫决策过程
- 1.2.1 MDP的前置知识:随机过程、马尔可夫过程、马尔可夫奖励
- 1.2.2 马尔可夫决策过程(MDP):马尔可夫奖励(MRP) + 智能体动作因素
第二部分 RL进阶之三大表格求解法:DP、MC、TD
2.1 动态规划法
- 2.1.1 什么是动态规划
- 2.1.2 通过动态规划法求解最优策略
2.2 蒙特卡洛法
2.3 时序差分法及与DP、MC的区别
2.4 RL的分类:基于模型(Value-base/Policy-based)与不基于模型
第三部分 价值学习:从n步Sarsa算法到Q-learning、DQN
3.1 TD(0)控制/Sarsa(0)算法与TD(n)控制/n步Sarsa算法
3.2 Q-learning
- 3.2.1 重要性采样:让同策略完成到异策略的转变
- 3.2.2 Sarsa算法与Q-learning更新规则的对比
3.3 DQN
第四部分 策略学习:从策略梯度、Actor-Criti到TRPO、PPO算法
4.1 策略梯度与其突出问题:采样效率低下
- 4.1.1 什么是策略梯度和梯度计算/更新的流程
- 4.1.2 避免采样的数据仅能用一次:重要性采样(为采样q解决p从而增加重要性权重)
4.2 优势演员-评论家算法(Advantage Actor-Criti):为避免奖励总为正增加基线
4.3 基于信任区域的TRPO:加进KL散度解决两个分布相差大或步长难以确定的问题
如上所述,PPO算法是针对TRPO计算量的大的问题提出来的,正因为PPO基于TRPO的基础上改进,故PPO也解决了策略梯度不好确定学习率Learning rate (或步长Step size) 的问题
毕竟通过上文,我们已经得知
具体做法是,PPO算法有两个主要的变种:近端策略优化惩罚(PPO-penalty)和近端策略优化裁剪(PPO-clip),其中PPO-penalty和TRPO一样也用上了KL散度约束。
近端策略优化惩罚PPO-penalty的流程如下
首先,明确目标函数,咱们需要优化,让其最大化
『注:如果你想仔细抠接下来各种公式但一上来就被上面这个弄迷糊了,说明还是需要先看下上文说过的这篇RL极简入门,而一旦踏入RL,便得做好两万五千里的准备,当然,如果只是想了解ChatGPT背后大概的技术原理,可以不用细抠PPO的公式怎么来的,不影响你对ChatGPT整体架构的理解,且下文会讲其在ChatGPT中是如何运用的』
接下来,先初始化一个策略的参数,在每一个迭代里面,我们用前一个训练的迭代得到的actor的参数与环境交互,采样到大量状态-动作对, 根据交互的结果,估测
当然,也可以把上述那两个公式合二为一『如此可以更直观的看出,PPO-penalty把KL散度约束作为惩罚项放在了目标函数中(可用梯度上升的方法去最大化它),此举相对TRPO减少了计算量』
上述流程有一个细节并没有讲到,即是怎么取值的呢,事实上,是可以动态调整的,故称之为自适应KL惩罚(adaptive KL penalty),具体而言
总之,近端策略优化惩罚可表示为
当然,如果觉得计算 KL散度很复杂,则还有一个PPO2算法,即近端策略优化裁剪PPO-clip,包括PPO算法的一个简单实现,均详见RL极简入门一文
虽然RL理论上虽不需要大量标注数据,但实际上它所需求的reward会存在缺陷:
比如游戏AI中,reward的制定非常困难,可能要制定成百上千条游戏规则,这并不比标注大量数据来得容易,又比如自动驾驶的多步决策(sequential decision)场景中,学习器很难频繁地获得reward,容易累计误差导致一些严重的事故
再比如聊天机器人方面,不好定义什么是好的对话、什么是不好的对话,当然,对此可以收集很多人类的对话当做范例,如此,模仿学习思路下的基于人来偏好的深度强化学习(对应论文为:Deep Reinforcement Learning from Human Preferences 2017,简称RLHF)应运而生
RLHF试图解决的问题是,在奖励函数不够明确的情况下,通过基于人类对事物比较的偏好而非绝对奖励值训练奖励函数
模仿学习的思路是不让模型在人类制定的规则下自己学习,而是让模型模仿人类的行为。而逆强化学习就是模仿学习的其中一种,何谓逆强化学习呢?
实际上,RLHF(Reinforcement Learning with Human Feedback)这一概念最早被定义为基于人类反馈的强化学习,它最早是在2008年《TAMER:Training an Agent Manually via Evaluative Reinforcement》一文中被提及的
在2017年前后,深度强化学习(Deep Reinforcement Learning)逐渐发展并流行起来,如你所见,2017年6月由OpenAI联合Google DeepMind一块推出:基于人类偏好的深度强化学习《Deep Reinforcement Learning from Human Preferences》,也简称RLHF
当让一个强化学习智能体探索环境并与之交互(比如Atari游戏),RLHF的核心步骤如下图所示:
再之后,OpenAI团队通过下述两篇论文进一步阐述了RLHF
NLP自发展以来,先后经历了4种任务处理范式
GPT由OpenAI在2018年通过此论文“Improving Language Understanding by Generative Pre-Training”提出,使用了一个大型的未标记文本语料库来进行生成式预训练(该语料库包含40GB的文本数据,比如互联网上抓取的网页、维基百科、书籍和其他来源的文本)
在GPT 被提出之前
在上一篇Transformer笔记中,我们已经了解到:GPT是“Generative Pre-Training Transformer”的简称,从名字看其含义是指的生成式的预训练,它和BERT都是(自监督)预训练-(有监督)微调模式的典型代表
由于Decoder具备文本生成能力,故作为侧重生成式任务的GPT选择了Transformer Decoder部分作为核心架构
不过,与原始的Transformer Decoder相比,GPT所用的结构删除了Encoder-Decoder Attention,只保留了多头注意力层Multi-Head Attention层和前馈神经网络Feed forward层(This model applies a multi-headed self-attention operation over theinput context tokens followed by position-wise feedforward layers to produce an output distributionover target tokens),最后再加上求和与归一化的前置LN层 + 残差,且在参数上有以下变化
通过这样的结构,GPT便可以利用无标注的自然语言数据进行训练:根据给定的前个token,预测第 个token,训练过程中使用的是基于最大似然估计的损失函数,即让模型预测的概率分布尽可能接近实际下一个单词的分布
具体来说,当你给定前面的若干个词后,它会给你下一个词;而当你有了下一个词后,它会再给你接一个词,以此递推
其中的关键便是这个Self-Attention,模型通过自注意力机制可以学习序列中不同位置之间的依赖关系,即在处理每个位置的信息时,模型会考虑序列中和该位置的信息有关联的其他所有位置上的信息,这种机制使得模型能够有效地处理长距离依赖关系
所谓自注意力,即指当我们需要用到自注意力编码单词 的时候,会按下面几个步骤依次处理(配图来自此文)
之后对每个token都进行上述同样的三步操作,最终会得到每个token新的表示向量,新向量中包含该token的上下文信息,之后再将这些数据传给Transformer组件的下一个子层:前馈神经网络
至于所谓Masked Self-Attention就是在处理当前词的时候看不到后面的词。举个例子,处理“it”的时候,注意力机制看不到“it”后面的词(通过将“it”后面的词的权重设置为一个非常大的负数,进一步softmax之后变为0,从而屏蔽掉),但会关注到“it”前面词中的“a robot”,继而注意力会计算三个词“it”、“a”、“robot”的向量及其attention分数的加权和
更多细节可以看下上篇BERT笔记(特别是此前还不了解Transformer的),或此文:图解注意力机制
GPT2相比GPT1的变动主要体现在两方面,一方面是模型结构上,一方面是推理模式上
在模型结构上
在推理模式上,虽然GPT1的预训练加微调的范式仅需要少量的微调即可,但能不能有一种模型完全不需要对下游任务进行适配就可以表现优异?GPT2便是在往这个方向努力:不微调但给模型一定的参考样例以帮助模型推断如何根据任务输入生成相应的任务输出
最终,针对小样本/零样本的N-shot Learning应运而生,分为如下三种
此外,只需将自然语言的任务示例和提示信息作为上下文输入给GPT-2,它就可以在小样本的情况下执行任何NLP任务,包括所谓的完形填空任务,比如
假如我要判断“我喜欢这个电影" 这句话的情感(“正面" 或者 "负面"),原有的任务形式是把他看成一个分类问题
输入:我喜欢这个电影
输出:“正面" 或者 "负面"
而如果用GPT2去解决的话,任务可以变成“完形填空",
输入:我喜欢这个电影,整体上来看,这是一个 __ 的电影
输出:“有趣的" 或者 "无聊的"
加的这句提示“整体上来看,这是一个 __ 的电影”对于让模型输出人类期望的输出有很大的帮助。
这个所谓的提示用NLP的术语表达就是prompt,即给预训练语言模型的一个线索/提示,帮助它可以更好的理解人类的问题
例如有人忘记了某篇古诗,我们给予特定的提示,他就可以想起来,例如当有人说:
白日依山尽
大家自然而然地会想起来下一句诗:黄河入海流
亦或者,搜索引擎,可以根据我们的输入,进行输出的提示:
GPT3简单来说,就是参数规模大(有钱)、训练数据规模大(多金)、效果出奇好,具体而言
为形象描述,举一个GPT3在0样本、单样本、少量样本下的机器翻译使用范例,如下图
零样本下 模型没法通过样本去学习/修正,但即便是少样本下,也有工作试图证明In Context Learning并没有从样本中学习,比如“Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?”,它发现了:
然而,有些工作认为LLM还是从给出的示例学习了这个映射函数,不过是种隐式地学习
OpenAI的GPT3虽然不再微调模型(pre-training + prompt),但Google依然坚持预训练 + 微调的模式
2021年9月,谷歌的研究者们在此篇论文中《Finetuned Language Models Are Zero-Shot Learners》提出了基于Instruction Fine-Tuning(指令微调,简称IFT)的FLAN大模型(参数规模为137B),极大地提升了大语言模型的理解能力与多任务能力,且其在评估的25个数据集中有20个数据集的零样本学习能力超过175B版本的GPT3(毕竟指令微调的目标之一即是致力于improving zero-shot generalization to tasks that were not seen in training),最终达到的效果就是:遵循人类指令,举一反三地完成任务
有两点值得注意的是
We take a pretrained language model of 137B parameters and perform instruction tuning—finetuning the model on a mixture of more than 60 NLP datasets expressed via natural language instructions.
We refer to this resulting model as FLAN, for Finetuned Language Net
至于IFT的数据通常是由人工手写指令和语言模型引导的指令实例的集合,这些指令数据由三个主要组成部分组成:指令、输入和输出,对于给定的指令,可以有多个输入和输出实例
相比于GPT-3,且区别在于Finetune,FLAN的核心思想是,当面对给定的任务A时,首先将模型在大量的其他不同类型的任务比如B、C、D...上进行微调,微调的方式是将任务的指令与数据进行拼接(可以理解为一种Prompt),随后给出任务A的指令,直接进行推断,如下图所示
例如,我们的最终目标是推理任务
相当于通过指令微调之后,模型可以更好的做之前预训练时没见过的新任务且降低了对prompt的敏感度(某些场景下不一定非得设计特定prompt才能激发模型更好的回答)
这或许也启发了OpenAI重新注意到了微调这一模式(毕竟如上文所述,原本GPT3在预训练之后已彻底放弃再微调模型),从而在InstructGPT中针对GPT3做Supervised fine-tuning(简称SFT)
自此,总结一下,关于「prompt learning」最简单粗暴的理解,其实就是让模型逐步学会人类的各种自然指令或人话,而不用根据下游任务去微调模型或更改模型的参数,直接根据人类的指令直接干活,这个指令就是prompt,而设计好的prompt很关键 也需要很多技巧,是一个不算特别小的工程,所以叫prompt engineering,再进一步,对于技术侧 这里面还有一些细微的细节
GPT3 出来之前(2020年之前),模型基本都是预训练 + 微调,比如GPT1和BERT
GPT3刚出来的时候,可以只预训练 不微调,让模型直接学习人类指令直接干活 即prompt learning,之所以可以做到如此 是因为GPT3 当时具备了零样本或少样本学习能力
当然,说是说只预训练 不微调,我个人觉得还是微调了的,只是如上文所说的某种隐式微调而已2021年,Google发现微调下GPT3后 比OpenAI不微调GPT3在零样本上的学习能力更加强大
从而现在又重新回归:预训练之后 再根据下游任务微调的模式,最后封装给用户,客户去prompt模型
所以现在的prompt learning更多针对的是 去提示/prompt:已具备零样本学习能力的且还做了进一步微调的GPT3.5/GPT4
(怎么微调呢,比如很快下文你会看到的SFT和RLHF,当然 也可以不做微调,比如后来Meta发布的类ChatGPT模型LLaMA本身便没咋做微调,虽它刚发布时比不上GPT3.5/4之类的,但其核心意义在于13B通过更多数据训练之后 在很多任务上可以强过175B的GPT3)再之后,就出来了很多个基于LLaMA微调的各种开源模型(这块可以查看本文开头所列的:类ChatGPT的部署与微调系列文章)
为让大语言模型进一步具备解决数学推理问题的能力,22年1月,谷歌大脑团队的Jason Wei、Xuezhi Wang等人提出了最新的Prompting机制——Chain of Thought(简称CoT),简言之就是给模型推理步骤的prompt,让其学习人类如何一步步思考/推理,从而让模型具备基本的推理能力,最终可以求解一些简单甚至相对复杂的数学推理能力
以下是一个示例(下图左侧为standard prompting,下图右侧为基于Cot的prompt,高亮部分为chain-of-thought),模型在引入基于Cot技术的prompt的引导下,一步一步算出了正确答案,有没有一种眼前一亮的感觉?相当于模型具备了逻辑推理能力
那效果如何呢,作者对比了标准prompting、基于Cot技术的prompting分别在这三个大语言模型LaMDA、GPT、PaLM(除了GPT由OpenAI发布,另外两个均由Google发布)上的测试结果,测试发现:具有540B参数的PaLM模型可以在一个代表小学水平的数学推理问题集GSM8K(GSM8K最初由OpenAI于2021年10月提出)上的准确率达到了60.1%左右
很快,这项技术引起了很多人的关注,比如不论是few-shot还是zero-shot,在加入Cot技术之后,都能回答此前不能回答的某些数学推理问题,甚至出现了风靡一时的“let's think step by step”的梗(通过该条语句可以激发模型的推理能力)
据OpenAI官网对GPT3.5的介绍,GPT3.5从2021年第四季度开始就混合使用文本和代码进行训练,我们来看下GPT3.5的各个系列模型及其各自的发展演变脉络图
基于GPT3的发展路线:一条是侧重代码/推理的Codex,一条侧重理解人类的instructGPT
基于GPT3.5的发展路线:增强代码/推理能力且更懂人类终于迭代出ChatGPT
通过OpenAI公布的ChatGPT训练图可知,ChatGPT的训练流程与InstructGPT是一致的,差异只在于
23年3月14日(国内3.15凌晨),OpenAI正式对外发布自从22年8月份便开始训练的GPT4,之前订阅ChatGPT plus版的可以直接体验GPT4
根据OpenAI官网发布的《GPT-4 Technical Report》可知
此外,通过GPT4的技术报告第60页可知,其训练方式和基于GPT3的instructGPT或基于GPT3.5的ChatGPT初版的训练方式如出一辙
先收集数据
- 一部分是人工标注问题-答案对:We collect demonstration data (given an input, demonstrating how the model should respond)
- 一部分是基于人类偏好对模型输出的多个答案进行排序的数据:ranking data on outputs from our models (given an input and several outputs, rank the outputs from best to worst) from human trainers
接下来三个步骤(具体下文第三部分详述)
- 通过人工标注的数据(问题-答案对)监督微调GPT4
We use the demonstration data to finetune GPT-4 using supervised learning (SFT) to imitate the behavior in the demonstrations.- 通过对模型多个回答进行人工排序的数据训练一个奖励模型,这个奖励模型相当于是模型输出好坏的裁判
We use the ranking data to train a reward model (RM), which predicts the average labeler’s preference for a given output- 通过最大化奖励函数的目标下,通过PPO算法继续微调GPT4模型
and use this signal as a reward to fine-tune the GPT-4 SFT model using reinforcement learning (specifically, the PPO algorithm)
至于GPT4背后多模态的能力起源与发展历史,请参见:上篇《AI绘画能力的起源:通俗理解VAE、扩散模型DDPM、DETR、ViT/Swin transformer》,下篇《AIGC下的CV多模态原理解析:从CLIP/BLIP到stable diffusion/Midjourney、GPT4》
根据InstructGPT的原始论文可知,InstructGPT的训练分为三个阶段(有监督微调“经过自监督预训练好的GPT3”、然后基于人类偏好排序的数据训练一个奖励模型、最终在最大化奖励的目标下通过PPO算法来优化策略):
阶段1:利用人类的问答数据去对GPT3进行有监督训练出SFT模型(作为baseline)
首先,OpenAI是先设计了一个prompt dataset,里面有大量的提示样本,给出了各种各样的任务描述
其次,找了一个团队对这个prompt dataset进行标注(本质就是人工回答问题)
最后,用这个来自OpenAI API和labeler-written的13k大小的标注好的数据集(问题-答案对)比如微调GPT3( trained for 16 epochs, 使用余弦学习率衰减, and residual dropout of 0.2)
这个微调好的GPT3我们称之为SFT模型(SFT的全称Supervised fine-tuning,监督微调之意),它作为baseline具备了最基本的预测能力(该基线模型有三个不同大小的版本,分别为1.3B、6B、175B)
说白了,让人类就一些问题写出人工答案,再把这些问题和答案丢给模型学习,这便是有监督训练,但人类不可能针对所有问题都写出答案给到模型(如果人类能把所有问题都标注/回答了,那还要模型干嘛,^_^)
所以我们需要让模型学到人类的喜爱偏好(训练出一个RM模型作为机器裁判从而代替人类当裁判,避免让实验人员守在电脑前对模型吐出来的结果不停地打分)
继而在遵循这种喜爱偏好下生成人类期待的答案,想达到这个效果就是得让模型明确什么是更好的输出,怎么明确?通过奖惩!
阶段2:通过RLHF的思路训练一个奖励模型RM
首先,通过『移除了最后一层unembedding layer的上一阶段的SFT模型』初始化出我们的RM模型,且考虑到175B计算量大且不稳定不适合作为奖励函数,故最后用的6B版本的SFT初始化RM模型「The final reward model was initialized from a 6B GPT-3 model that was fine-tuned on a variety ofpublic NLP datasets (ARC, BoolQ, CoQA, DROP, MultiNLI, OpenBookQA, QuAC, RACE, andWinogrande),这句话中的“a 6B GPT-3 model that was fine-tuned”说白了就是6B大小的SFT」
然后,让阶段1的SFT模型回答来自OpenAI API和labeler-written且规模大小为33k的数据集的一些问题比如,接着针对每个问题收集4个不同的模型输出从而获取4个回答「In Stiennon et al. (2020), the RM is trained on a dataset of comparisons between two model outputson the same input」
可能有的读者会疑问为何有多个输出,原因如李沐在其对instructGPT论文的解读视频中第24min所说:在于模型每次预测一个词都有对应的概率,根据不同的概率大小可以采样出很多答案,比如通过beam search保留k个当前最优的答案(beam search相当于贪心算法的加强版,除了最好的答案外,还会保留多个比较好的答案供选择)
接着,人工对这4个回答的好坏进行标注且排序,排序的结果用来训练一个奖励模型RM,具体做法就是学习排序结果从而理解人类的偏好『顺带提一嘴,如instructGPT论文第12页中所述:“We ran anexperiment where we split our labelers into 5 groups, and train 5 RMs (with 3 different seeds) using5-fold cross validation (training on 4 of the groups, and evaluating on the held-out group)”,你可以通过不同的数据组训练好几个RM,最终选择一个最优的』
但通过人来标注/排序的结果训练出奖励模型之后怎么用呢,这就是训练阶段3要做的事情
阶段3:通过训练好的RM模型预测结果且通过PPO算法优化模型策略
首先,让第一阶段微调好的SFT模型初始化出一个PPO模型(通过instructGPT论文第56页得知,experimented with a few variants of the SFT models as the PPO’s init model),且PPO模型有多个大小的版本,比如1.3B 6B 175B(可理解为带着RL且初始版本为SFT的模型)
然后,让PPO模型去回答仅来自OpenAI API不带人类任何标注的且规模大小为31k的一些新的问题比如
此时不再让人工评估好坏,而是让阶段2训练好的奖励模型RM去给PPO模型的预测结果比如进行打分进而排序(看是否优质,比如是否迎合人类偏好)
之后,通过不断更大化奖励而优化PPO模型的生成策略(因为生成策略更好,模型的回答便会更好),策略优化的过程中使用PPO算法限制策略更新范围
最后,根据优化后的策略再次生成 RM再评估 模型再优化后再生成,如此循环进行,直到策略最优为止
最终效果还不错,哪怕是1.3B的PPO模型的效果也要比175B的SFT、175B的GPT3的效果都要更好
当然 这三步下来,比如第一轮迭代出一个相对最优的策略后,后面某个时间段 比如第二轮是可以再次通过新一批人类排序的数据训练一个新的RM,然后再迭代出一个当下最优的策略
此外,如instructGPT论文第17页所述,这三步下来所花费的代价相比预训练GPT3要小很多:The costof collecting our data and the compute for training runs, including experimental runsis a fraction of what was spent to train GPT-3: training our 175B SFT model requires 4.9 petaflops/s-days and training our 175B PPO-ptx model requires 60 petaflops/s-days,compared to 3,640 petaflops/s-days for GPT-3 (Brown et al., 2020),且如论文第40页所说,所有模型都是用的Adam优化器训练,β1= 0.9和β2= 0.95
另 值得一提的是,上文反复提到策略,那怎么理解这个经常在RL中出现的“策略”呢,举几个例子
此外,可能有读者疑问,InstructGPT使用RLHF的思路,只是为了训练出一个奖励函数么?事实上,还有额外多方面的用途
因此,通过人工干预微调GPT,使其输出对用户友好(避免乱说话),且更好的和人类对话,所以,对InstructGPT的简单理解,可以是基于人类偏好的深度强化学习(RLHF)手段微调的GPT。
接下来,我们分别具体阐述上面的阶段1、阶段2、阶段3。
阶段1的本质就是使用监督学习方法对GPT-3模型进行微调(回归到预训练-微调模式),且使用labeler demonstrations作为训练数据,具体微调过程中
训练RM的核心是由人类对SFT生成的多个输出(基于同一个输入)进行排序,再用来训练RM。按照模仿学习的定义,直观上的理解可以是,RM需要模仿人类对回答语句的排序思路
为了更具体的说明,我们代入一个场景,假设你向一个六岁小孩解释什么是登陆月球或什么是RL,如下图
针对这个损失函数需要逐一说明的是
值得一提的是,通过在训练集上进行了一个周期(epoch)的训练,选择了学习率(lr)为 9e-6,且采用余弦学习率调度策略,在训练结束时,学习率降低至初始值的10%
最终,通过这种形式的梯度回传,RM逐渐学会了给D这类语句以高排名甚至打出一个高分,给A、B以低排名甚至打出一个低分,从而模仿到了人类偏好。到了这一步,不妨可以这么简单理解RLHF:所谓的基于人类偏好的深度强化学习,某种意义上来说,就是由人类的偏好来充当reward
简而言之,阶段3可以用下图形象化表示
具体而言,instructGPT原始论文中的目标函数如下所示
InstructGPT这篇论文吧,对大家实在是太“友好”了,“友好”到全篇论文就只给了两个公式(奖励函数的损失函数以及上面这个目标函数),关键这两个公式都还只是简写,针对这个目标函数在和交大张老师及七月在线赵、倪等老师核对之后,发现实际中真正要算的时候,需要先如下展开下(马上还有二次展开、三次展开,最终由一行变成四行,而在此23年3.2日之前,全网包括我在内无人把它展开过)
是基线策略,是『新策略』更新之前的旧策略,为何呢?考虑到大部分文章在分析上面的目标函数时基本都是人云亦云、一带而过,故再逐一拆解下这个被一次展开后的目标函数,分为三个部分
————————————————
考虑到有些读者对这一块 还是有些疑惑,故针对上述的前两个部分 我们再总结下。若简言之,/与PPO算法表达式中的一一对应,比如与环境交互的等同于旧策略,但具体而言,则有以下4点
a) 首先,使用旧策略生成一批数据,包括状态、动作和奖励等信息,这些数据可以类似Deep Q Network那样,存储在一个经验回放缓冲区(Experience Replay Buffer)中
b) 其次,在训练新策略时,从经验回放缓冲区中随机抽取一批数据(当然,你也可以一次性抽取全部的经验数据)
c) 对于旧策略采样到的每个数据样本,计算重要性采样权重
比如
前几轮通过旧策略π(RL')采样的数据放在经验缓冲区里,把新策略π(RL)多次迭代更新出π(RL2)、π(RL3),这个过程中重要性采样的比值为或或
再之后通过π(RL3)采样一批新数据再次放在经验缓冲区里,从而继续迭代π(RL3)更新出π(RL4)、π(RL5)、π(RL6),这个过程中重要性采样的比值为或或,以此类推..
且使用一些方法限制策略更新的幅度,例如PPO中的截断重要性采样比率(具体参见本文第一部分提到的RL极简入门一文)
相当于为了对重要性比值做约束,故在的部分里得加个截断处理「说白了,重要性比值 根据截断去约束,当然你也可以改成根据一个KL散度去约束,毕竟截断和KL散度约束都是实现PPO算法本身的方式,遗憾的是原instructGPT论文中的目标函数对于这点也未展开体现出来,算是简洁的不能再简洁了,所以你得再仔细体会下上面这几段 」,如下所示二次展开
d) 然后通过最大化奖励而不断迭代,迭代过程中可一定程度的重复使用旧策略生成的已有数据反复验证(注意这里的用词:一定程度的重复使用,就像蓄水池一样,提高水资源的利用率,但会适时更新):
e) 按照更新后的目标函数进行梯度计算和参数更新
f) 在训练过程中,可以多次重复使用经验回放缓冲区中的数据进行训练(这里的多次可以理解为有限次数)。但是,需要注意的是,随着策略更新,新旧策略之间的差异可能会变大,这时重要性采样权重可能变得不稳定,从而影响训练的稳定性
且慢,上述公式(总共三行)中的第二行基于当前(旧)策略的RM最大化,故的参数是θ’而非θ 能理解,然后拆开成第三行,大中括号里前面的部分也能理解了:加个截断处理 限制更新前后两个新旧策略的比值大小(相当于限制新策略的更新范围)
但第二和第三行大中括号里后面的部分中加的惩罚项是何意?下文马上具体阐述
上文更多说的是策略的迭代,而在Actor-Critic架构中,策略的迭代是一方面,对于状态-动作价值的评估则是另一重要的方面,为了更好的帮助大家理解critic这块,在和ChatGPT原理课学员春天讨论后,专门画了下面这个图帮助大家理解
最后,如春天所说,优势的计算、回报的计算、Critic的输出等等都是开放性的话题
除了相关论文之外,为了增进理解,还可以看下一些类ChatGPT项目的代码实现,比如ColossalChat和微软DeepSpeed Chat的实现(特别是后者微软那个)
对于colossalchat这幅图确实画的好,包括colossal之前画的关于PPO实现的那两个图也画的很好(详见本文1.4节),为和本文相关描述统一对应,更考虑到我讲的ChatGPT原理课中有学员对这个图有疑问,故还是结合微软deepspeed Chat的实现说明下这个图「需要注意的是,colossalchat和deepspeed chat的实现在一些细节上有所差异,所以有时图和公式/实现不一定完全百分百一致,这点 读者注意甄别,当然 必要时我会指出来,总之,本3.2.2小节中,上面和下面的图都是colossalchat的,下面的公式则是deepspeed chat的」
「注意上面那一行所表示的即是TD误差的表达式,里面的是带时间步 的序列,通过如此计算得到:[0 0 0 RM输出的reward] - [多个不同的KL值] = ,至于为何是如此计算的,下文会解释」
而经验回报returns则如此计算「A是优势,RL里面的优势就是被定义成“比均线要高的部分”,V是对回报的估计,相当于一个回报期望值(均线),也就是A = return -V,移项后就是return=A+V」
(如果这一段没怎么看明白,没关系,继续往下看,下文会解释,且下文3.2.4节还会有一个完整的示例)
当把对下一个token的预测对应到强化学习的框架中,环境从某种意义上说被直接被奖励模型RM取代了,如下图
至此,有一个细节问题,即阶段二训练出来的奖励函数是对整个输入语句和整个输出语句而言的(相当于奖励函数只能给出完整回答的奖励),可智能体是根据一个一个词来去拼凑出整个回答的。那么在智能体生成回答的过程中,每个动作action给出的词对应的奖赏是什么呢?
这个细节在InstructGPT的论文只浅浅提了一嘴:“Given the prompt and response, it produces a reward determined by the reward model and ends the episode.”。幸运的是,上文提到过的这篇论文《Learning from summarize from Human feedback》中的一个引脚标注给出了这个疑问的答案
论文里说,奖励模型只在最终生成回答之后才给出奖励,在中间的过程中是不给出奖励的(相当于不对序列的中间生成给予reward)
换言之,只有在ChatGPT输出了EOS token的时候,整个轨迹才结束(EOS token是NLP中用来表示一段话结束的标志)
如七⽉在线ChatGPT课学员春天所说,如果看下微软DeepSpeed Chat的代码实现之后,你会发现:
至于如果是多轮对话场景的,则存在某一轮对话中的代词指向上一轮对话中的某个人或物的可能,为此,ChatGPT多轮对话的核心关键是
如此⽂《从零实现带RLHF的类ChatGPT:逐行解析微软DeepSpeed Chat》3.4.2节所⾔
举个例⼦,假定在经验数据池里,有seq=[ i am learning machine learning with julyedu ],其
接下来的问题,便是整个序列seq=[ i am learning machine learning with julyedu ]中每个token所对应的回报returns序列长什么样
returns的计算也有两种算法
为进一步帮助大家理清相关概念的每一个细节,我们来具体看下DSC到底是怎么计算returns的
在DSC中,优势函数被定义为对未来所有时间步的TD误差(Temporal-Difference Error,也就是这里的δ)进行折扣求和,这种计算优势函数的方法,被称为Generalized Advantage Estimation (GAE)
- 首先,我们需要计算TD误差序列,在这里,我们使用提供的V_old值序列和奖励序列进行计算:
values = [-0.2761, -2.3945, 0.1729, -0.0919, -0.0867, -0.0818, -0.0758]
KL_rewards = [-4.6873e-04, -3.1257e-04, 5.8591e-05, -5.5084e-03, -4.0741e-03, -5.5275e-03, -8.5999e-02]
γ=0.9
「计算之前先回顾一下TD误差的含义:δ_1 = r1 + γV_old(2) - V_old(1)
比如对于上式:实际获得的即时奖励 r1 加上折扣后的未来奖励预测 γV_old(2),再减去我们原先预测的当前时间步的奖励 V_old(1),这就是后者的预测与前者实际经验之间的差距」
δ_1 = r1 + γV_2 - V_1 = -4.6873e-04 + 0.9 * (-2.3945) - (-0.2761) = −1.8794
δ_2 = r2 + γV_3 - V_2 = -3.1257e-04 + 0.9 * (0.1729) - (-2.3945) = 2.5498
δ_3 = r3 + γV_4 - V_3 = 5.8591e-05 + 0.9 * (-0.0919) - 0.1729 = −0.2556
δ_4 = r4 + γV_5 - V_4 = -5.5084e-03 + 0.9 * (-0.0867) - (-0.0919) = 0.0084
δ_5 = r5 + γV_6 - V_5 = -4.0741e-03 + 0.9 * (-0.0818) - (-0.0867) = 0.0090
δ_6 = r6 + γV_7 - V_6 = -5.5275e-03 + 0.9 * (-0.0758) - (-0.0818) = 0.0081
δ_7 = r7 + γV_8 - V_7 = -8.5999e-02 + 0.9 * 0 - (-0.0758) = −0.0102- 接下来,根据给出的公式计算优势函数
可以算出A_1到A_7的值分别如下
仔细观察这些式子,你会发现它们彼此之间的换算关系
比如,
等价为,而括号里的不就是么?也就意味着,依此类推:
、、、、、
所以我们实际计算的时候,为减少计算量,可以先计算A_7,再分别计算A_6、A_5、A_4、A_3、A_2、A_1
假设 λ = 0.95,则有
「也回顾下λ参数的含义,λ允许我们控制优势函数估计应该多大程度地考虑未来的奖励
较高的λ值会使我们更多地考虑未来的奖励(当λ=1时,GAE退化为蒙特卡洛估计,它会考虑所有的未来奖励,因为当λ接近1时,的值会保持较大)
而较低的λ值则更侧重于即时的奖励(当λ=0时,GAE退化为一步TD误差,这只考虑了最直接的下一步奖励,因为当λ接近0时,的值会迅速变小) 」
A_7 = δ_7 = -0.0102
A_6 = δ_6 + 0.9 * 0.95 * A_7 = 0.0081 + 0.9 * 0.95 * (−0.0102) = -0.0006
A_5 = δ_5 + 0.9 * 0.95 * A_6 = 0.0090 + 0.9 * 0.95 * (-0.0006) = 0.0085
A_4 = δ_4 + 0.9 * 0.95 * A_5 = 0.0084 + 0.9 * 0.95 * (0.0085) = 0.0157
A_3 = δ_3 + 0.9 * 0.95 * A_4 = (-0.2556) + 0.9 * 0.95 * (0.0157) = -0.2422
A_2 = δ_2 + 0.9 * 0.95 * A_3 = 2.5498 + 0.9 * 0.95 * (-0.2422) = 2.3426
A_1 = δ_1 + 0.9 * 0.95 * A_2 = (-1.8794) + 0.9 * 0.95 * (2.3426) = 0.1216- 最后,我们根据回报公式 计算每个时间步的回报:
R_1 = A_1 + V_1 = 0.1236 + -0.2761 = -0.1525
R_2 = A_2 + V_2 = 2.3426 + -2.3945 = -0.0518
R_3 = A_3 + V_3 = -0.2422 + 0.1729 = -0.0693
R_4 = A_4 + V_4 = 0.0157 + -0.0919 = -0.0763
R_5 = A_5 + V_5 = 0.0085 + -0.0867 = -0.0782
R_6 = A_6 + V_6 = -0.0006 + -0.0818 = -0.0824
R_7 = A_7 + V_7 = -0.0102 + -0.0758 = -0.0860所以,整个序列的回报序列是returns = [-0.1525, -0.0518, -0.0693, -0.0763, -0.0782, -0.0824, -0.0860]
顺带提一嘴,当我们得到整个序列的回报序列之后,我们便训练价值序列去拟合这个回报序列「且训练中还会和旧价值序列的差异做下约束,具体是通过截断的方式实现,最终通过去拟合returns序列之后,可以得到一个新的预测更准确的新values序列」
如此,是不就和3.2.2节中关于DSC一系列的公式 给对上了?哈,只要功夫深铁杵磨成针,古人诚不欺也 !
虽说GPT3在2020年就出来了,但OpenAI并未开源,所以直到一年半后以后才有国内外各个团队比如DeepMind等陆续复现出来,这些大厂的复现代码我们自然无法窥知一二,毕竟人家也未开源出来
再到后来基于GPT3的InstructGPT、基于GPT3.5的ChatGPT初版(GPT3.5的参数规模也尚无准确定论)、GPT4均未开源,OpenAI不再open,好在Meta等公司或研究者开源出了一系列类ChatGPT项目,本部分针对其中部分做下简要推荐..
...
为避免本文篇幅再次过长,本第4部分余下的内容已抽取出去独立成文,请点击:
事实上,可能很多朋友也已经意识到,本文的前大部分内容里,GPT-N理解起来相对轻松(包括Transformer通过理解上篇BERT笔记不算特别复杂),而instructGPT/ChatGPT的整体架构思想也不算复杂,但其中涉及到的RL部分则让想深挖细节的初学者变得立马吃力起来(除非你已“入一定门”,或者你有课程/老师可以不断问),比如一个PPO算法,要真正把这个概念讲清楚、讲透彻且从零推到尾则没那么容易了
为了写本笔记,过去两个月翻了大量中英文资料/paper(中间一度花了大量时间去深入RL),大部分时间读的更多是中文资料,2月最后几天读的更多是英文paper,正是2月底这最后几天对ChatGPT背后技术原理的研究才开始进入状态,之后不断深入『后还组建了一个“ChatGPT之100篇论文阅读组”,我和10来位博士、业界大佬从23年2.27日起半年之内读完ChatGPT相关技术的100篇论文,榜单见此文 』,由此而感慨:
总之,读的论文越多(论文之后 可以再抠代码实现/复现),博客内相关笔记的质量将飞速提升 自己的技术研究能力也能有巨大飞跃
再之后,则如本文最开头所述,为了彻底写清楚ChatGPT背后的所有关键细节,从1月初写到6月底仍未完工,除了本文之外,过程中涉及到多篇文章(RL入门、论文带读、微调实战、代码实现、CV多模态),再加上之前写的Transformer、RL数学基础等多篇笔记,成了一个大系列,始终保持不断深挖
此外,写过图解Word2vec、图解transformer的Jay Alammar也写过:图解GPT2(其翻译版)、图解GPT3(其翻译版)
GPT系列论文阅读笔记,另 300行代码实现GPT:GitHub - karpathy/minGPT: A minimal PyTorch re-implementation of the OpenAI GPT (Generative Pretrained Transformer) training
以下是本文的部分修改/完善/新增记录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。