自从我那篇BERT通俗笔记一经发布,然后就不断改、不断找人寻求反馈、不断改,其中一位朋友倪老师(之前我司NLP高级班学员现课程助教老师之一)在谬赞BERT笔记无懈可击的同时,给我建议到,“后面估计可以尝试尝试在BERT的基础上,讲一讲prompt学习了”,然后我看了下prompt学习,一看果然牛..
再然后,当我还在各种改BERT笔记的时候,12月初突然出来了一个ChatGPT刷爆朋友圈,即便很多之前不接触AI的朋友也在问ChatGPT这种类似聊天机器人却远胜一般聊天机器人各种问题(上一次出现这种盛况的还是16年的AlphaGo)。
据我观察,大家问ChatGPT的问题千奇百怪,比如给他任意一段代码,要求它解释或添加对应的注释(这可不是单纯的翻译问题,需要有类似人的提炼、概括、总结能力),甚至有人让其根据要求排查代码bug,要知道此前debug想寻求帮助
所以ChatGPT就相当于你写代码或各类问题的私人顾问,而这个私人顾问能瞬间、精准理解你的意图,不会让你像用以前那种聊天机器人经常觉得智障甚至对牛弹琴,加之其背后依托的是人类级百科全书式的资料库,所以有人惊呼:ChatGPT会不会替代Google这类搜索引擎。
虽然大部分技术者对待ChatGPT还是比较冷静的,毕竟它给的答案不像权威技术专家那样具备足够的公信力,也不像Google给出来源从而不能比较好的验证其正确程度(注意我这里的措辞:“不能比较好的”、“正确程度”,^_^),但最近遇到的几件事改变了我的一些看法
本篇ChatGPT笔记会全力做到,通俗易懂且循序渐进(另,本文配图均来自文末的参考文献,可以认为是针对文末参考文献的学习笔记)
本笔记从1.6日开始写(1.15日完成初稿,之后反复修改,春节期间基本成型,预计1月底完全成型,届时质量将是1.15日初稿的1.5-2倍),ChatGPT之后,再下一篇笔记应该是强化学习极简入门了。
在上一篇BERT笔记中,我们已经了解到:GPT是“Generative Pre-Training”的简称,从名字看其含义是指的生成式的预训练。
GPT也采用两阶段过程,第一个阶段是利用语言模型进行预训练,第二阶段通过Fine-tuning的模式解决下游任务。
下图展示了GPT的预训练过程,其实和ELMO是类似的,主要不同在于两点:
有两点值得提一下
很多同学一看到DL,便会想到大数据,而数据量一大,还用CPU处理的话很可能训练一个小任务都得半天,而如果用GPU跑,可能一两分钟就出来了。于此,在深度学习大火的那几年,特别是AlphaGo出来的16年起,我司七月在线便分别为VIP、AI系统大课、在职提升大课、求职/论文/申博/留学1V1辅导提供GPU云平台进行实战训练。
然很多情况下,高质量数据的获取是比较困难的,比如医疗数据,那怎么办呢?既然暂时改变不了高质量数据匮乏的现状,那就改变模型! 如此,让模型能从少量样本中学习规律并具备推理能力便显得至关重要了。
最终,针对小样本/零样本的N-shotLearning应运而生,分为如下三种
而GPT-2不再使用二阶段训练模式(预训练+微调),而是彻底放弃了微调阶段,仅通过大规模多领域的数据预训练,让模型在Zero-shot Learming的设置下自己学会解决多任务的问题,而且效果还不错(虽然GPT2通过Zero-shot Learming在有些任务的表现上尚且还不如SOTA模型,但基本超越了一些简单模型,说明潜力巨大),你说神不神奇?
而GPT2在GPT1的基础上规模更大、模型更复杂。至于小样本学习的具体应用可以看下参考文献6。
GPT3简单来说,就是规模大、有钱多金、效果出奇好,具体而言,它的参数规模达到了1750亿,并且使用45TB数据进行训练,其预训练任务就是“句子接龙”,给定前文持续预测下一个字,而且只要有少量的文本数据就能作为模型的训练数据。
总之,只需将自然语言的提示信息(prompt)和任务示例(demonstration)作为上下文输入给GPT-3,它就可以在零样本或小样本的情况下执行任何NLP任务,包括所谓的完形填空任务,比如举个例子
比如,假如我要判断“我喜欢这个电影" 这句话的情感(“正面" 或者 "负面"),原有的任务形式是把他看成一个分类问题
输入:我喜欢这个电影
输出:“正面" 或者 "负面"
而如果用Prompt Learning去解决的话,任务可以变成“完形填空",
输入:我喜欢这个电影,整体上来看,这是一个 __ 的电影
输出:“有趣的" 或者 "无聊的"
言外之意即是,即便是面对完形填空似的任务,也能很好的解决
正因为GPT3首次把模型的规模带到了千亿级别,开辟了大模型赛道,其次也为NLP带来了一种新的范式prompt,prompt为GPT3带来了0样本、单样本、小样本的学习能力。而且更为关键的是,在小样本的情况下,其性能表现一度超越SOTA模型。
可想而知,prompt learning在GPT3中起到了一种极其关键的作用。所谓Prompt就是提示的意思。
例如我们有人忘记了某个事情,我们给予特定的提示,他就可以想起来,例如我们说:白日依山尽,大家自然而然地会想起来下一句诗:黄河入海流。
亦或者,搜索引擎,可以根据我们的输入,进行输出的提示:
那么在NLP中 Prompt 代表的是什么呢? prompt 就是给预训练语言模型的一个线索/提示,帮助它可以更好的理解人类的问题,这一创举揭开了GPT3在对话生成领域火力全开的序幕。
更多细节参见参考文献7。
为形象描述,举一个GPT-3在只有少量样本下的机器翻译使用范例,如下图
至此,我们对比下Fine-tuning和prompt learning的区别就是从Pre-train、Fine-tune到Pre-train、Prompt、Predict的过程
考虑到下文要讲的instructGPT和ChatGPT分别预计GPT3、GPT3.5,所以本文还得再讲下GPT3.5相比GPT3的差别。
粗略的讲,GPT-3.5 模型使用与 GPT-3 相同的预训练数据集,但进行了额外的微调,从而更擅长以下两点
考虑到本文的主旨核心ChatGPT用到了RLHF和PPO,所以本文的第二部分将从强化学习讲到PPO算法。
强化学习里面的概念、公式,相比ML/DL特别多,初学者刚学RL时,很容易被接连不断的概念、公式给绕晕,而且经常忘记概念与公式符号表达的一一对应,为此,我建议学习RL的第一步就是一定要扎实关于RL的一些最基本的概念、公式(不要在扎实基础的阶段图快或图囵吞枣,不然后面得花更多的时间、更大的代价去弥补),且把概念与公式的一一对应关系牢记于心,这很重要。
当然,为最大限度的提高本文的可读性,我会尽可能的多举例、多配图。
但RL之外,像高等数学里的什么叫导数、多元函数、偏导数、以及AI一些最基本的概念比如损失函数、梯度/梯度下降等,可以直接Wikipedia上查看相关概念,本文则不赘述了,毕竟可以为通俗而增加篇幅,但不为了介绍而介绍式的增加篇幅,避免影响完读率,^_^。话休絮烦,下面开始正题。
强化学习(reinforcement learning,RL),基于智能体(agent)在复杂、不确定的环境(environment)中最大化它能获得的奖励,从而达到自主决策的目的。
经典的强化学习模型可以总结为下图的形式(你可以理解为任何强化学习都包含这几个基本部分:智能体、行为、环境、状态、奖励):
一般的文章在介绍这些概念时很容易一带而过,这里我把每个概念都逐一解释下
总的而言,Agent通过感知环境Environment从而获取环境的状态state,进而依据策略决策从而执行动作action,最后得到奖励reward,然后再继续按此流程“感知状态-依据策略执行动作-得到奖励”循环进行。
另外,有两点值得一提
进一步,具体而言,“感知状态-依据策略执行动作-得到奖励”的整个过程分为两步
此外,RL和监督学习(supervised learning)的区别:
进一步,RL为得到最优策略从而获取最大化奖励,有
RL通常是一个马尔科夫决策过程,但何谓马尔科夫呢?据强化学习2一书的第47页所说
在马尔科夫决策过程中,和的每个可能的值出现的概率只取决于前一个状态和前一个动作,并且与更早之前的状态和动作完全无关,这个限制不是针对决策过程,而是针对状态的,状态必须包括过去智能体和环境交互的方方面面的信息,这些信息会对未来产生一定影响,这样,状态就被认为具有马尔科夫性。
换言之,下一步的状态取决于当前的状态以及当前采取的动作。它由状态转移概率和奖励函数两个部分组成
当我们有了策略、价值函数和模型3个组成部分后,就形成了一个马尔可夫决策过程(Markov decision process)。如下图所示,这个决策过程可视化了状态之间的转移以及采取的动作。
接下来,再介绍下KL散度,KL 散度衡量两个数据分布和之间的差异。
我们将其重新用于衡量两个分布之间的差异
本节推导的核心内容参考自Easy RL教程等资料(但修正了原教程上部分不太准确的描述,并补充了大量的解释说明和部分公式的拆解细节)。另,都说多一个公式则少一个读者,本文要打破这点,虽然本节推导很多,但每一步推导都有介绍到,不会省略任何一步推导,故不用担心看不懂(对本文任何内容有任何问题,都欢迎随时留言评论)。
策略梯度的核心算法思想是:参数为的策略接受状态,输出动作概率分布,在动作概率分布中采样动作,执行动作(形成运动轨迹),得到奖励,跳到下一个状态。在这样的步骤下,我们可以使用策略收集一批样本,然后使用梯度下降算法学习这些样本,不过当策略的参数更新后,这些样本不能继续被使用,还要重新使用策略与环境互动收集数据。类似下图所示(下图以及本节大部分配图/公式均来自easy RL教程)
接下来,详细阐述。首先,我们已经知道了策略函数可以如此表示:,如何评价策略的好坏呢?
假设机器人在策略的决策下,形成如下的运动轨迹(类似你玩三国争霸时,你控制角色在各种不同的游戏画面/场景/状态下作出一系列动作,而当完成了系统布置的某个任务时则会得到系统给的奖励,如此,运动轨迹用 表示,从而表示为一个状态、动作、奖励值不断迁移的过程)
给定智能体或演员的参数,我们可以计算某一条轨迹发生的概率为
那策略的评价函数便可以设为(以为参数的策略的条件下,产生一系列奖励值,且为客观综合起见,最终取的是多个策略的平均值,即总奖励的数学期望)
其中,可以理解为一个我们所熟知的神经网络
好手段,接下来我们把上面的改写一下。由于每一个轨迹 都有一个概率,所以我们要计算总奖励便得穷举所有可能的轨迹 ,然后对所有出现的概率进行加权并求和出总期望值:
上述整个过程如下图所示
通过上文我们已经知道,想让奖励越大越好,可以使用梯度上升来最大化期望奖励。而要进行梯度上升,我们先要计算期望奖励的梯度。
我们对 做梯度运算(其中,只有 与 有关。Em,忘了什么是梯度的,可以通过这个梯度的Wikipedia页面复习下)
考虑到,可得
从而进一步转化,可得
Em,怎么来的?别急,具体推导是,第一步 先分母分子都乘以一个,第二步 把上面公式代入计算,第三步 做个简单转换
然不巧的是,期望值 无法计算,所以我们只能用采样的方式采样 N 个并计算每一个的值,再把每一个的值加起来,如此得到梯度,即
任何必要的中间推导步骤咱不能省,所以还是要说明下。即,其中的具体计算过程是
完美!我们可以直观地理解上面的梯度计算公式
总之,至此,我们已经得到了的梯度计算的公式
有一点值得说明的是...,为了提高可读性,还是举个例子来说明吧。
比如到80/90后上大学时喜欢玩的另一个游戏CF(即cross fire,10多年前我在东华理工的时候也经常玩这个,另一个是DNF),虽然玩的是同一个主题比如沙漠战场,但你每场的发挥是不一样的,即便玩到同一个地方(比如A区埋雷的地方),你也可能会控制角色用不同的策略做出不同的动作,比如
- 在第一场游戏里面,我们在状态采取动作 ,在状态采取动作 。且你在同样的状态下,不是每次都会采取动作的,所以我们要记录,在状态 采取 、在状态 采取 等,整场游戏结束以后,得到的奖励是
- 在第二场游戏里面,在状态采取,在状态 采取 ,我们采样到的就是,得到的奖励是
这时我们就可以把采样到的数据用梯度计算公式把梯度算出来
这显然是非常花时间的,怎么解决这个问题呢?
首先,我们先来明确两个概念:
回到策略梯度这个采样到的数据只能使用一次的问题,是否可以把同策略模式转变成异策略模式呢?
这个过程具体的做法就叫重要性采样,即通过使用另外一种分布,来逼近所求分布的一种方法。
为备忘,我把2.3.1节得出的梯度计算的公式再贴一下
基于重要性采样的原则,我们用另外一个策略,它就是另外一个演员,与环境做互动采样数据来训练,从而间接计算
但具体怎么操作呢?为说明怎么变换的问题,再举一个例子。
假设有一个函数,需要从分布中采样,我们应该如何怎么计算()的期望值呢?
如果分布不能做积分,那么只能从分布尽可能多采样更多的,然后全都代入到,取它的平均值就可以得到近似()的期望值:
当不能在分布中采样数据,而只能从另外一个分布中去采样数据时(可以是任何分布),就需要做些变换。
整理下可得(左边是分布,右边是分布):
如此,我们便就可以从里面采样 ,再计算,再取期望值。所以就算我们不能从里面采样数据,但只要能从 里面采样数据,就可以计算从 采样 然后代入 以后的期望值。
类似的,当转用去采样数据训练后,得在的基础上补上一个重要性权重:,相当于原来的分布相当于变成了。这个重要性权重针对某一个轨迹用算出来的概率除以这个轨迹用算出来的概率。
最终加上重要性权重之后,可得
怎么来的?完整推导如下
梯度的计算好像差不多了?但实际在做策略梯度的时候,并不是给整个轨迹都一样的分数,而是每一个状态-动作的对会分开来计算,那具体怎么抽样呢?
实际上更新梯度的时候,如下式所示( 我们用演员去采样出跟,采样出状态跟动作的对,并计算这个状态跟动作对的优势 )
其中,要估测的是在状态采取动作是好的还是不好的:即如果是正的,就要增加概率;如果是负的,就要减少概率。
不过,是演员与环境交互的时候计算出来的,基于重要性采样的原则,现在当从 换到 的时候,就需要在
基础上, 变换成,一变换便得加个重要性权重(即把、用采样出来的概率除掉 、用采样出来的概率),公式如下(Easy RL原书上把下面公式中的写成了)
接下来,我们可以拆解和,即
于是可得公式
这里需要做一件事情,假设模型是的时候,我们看到的概率,跟模型是的时候,看到的概率是差不多的,即。
为什么可以这样假设呢?一种直观的解释就是很难算,这一项有一个参数,需要拿去跟环境做互动,算出现的概率。 尤其是如果输入是图片的话,同样的根本就不会出现第二次。我们根本没有办法估这一项,所以就直接无视这个问题。
但是是很好算,我们有这个参数,它就是个网络。我们就把带进去,就是游戏画面。 我们有个策略的网络,输入状态,它会输出每一个的概率。所以,我们只要知道和的参数就可以算。
所以,实际上在更新参数的时候,我们就是按照下式来更新参数:
所以实际上,我们可以从梯度来反推目标函数,当使用重要性采样的时候,要去优化的目标函数如下式所示,我们把它记
终于大功告成!
好巧不巧,看似大功告成了,但重要性采样还是有个问题。具体什么问题呢,为更好的说明这个问题,我们回到上文的那个例子中。
还是那两个分布:、,不能从里面采样数据,但只要能从 里面采样数据基于重要性采样的原则,虽然我们可以把 换成任何的 ,但是在实现上,和 的差距不能太大。差距太大,会出问题。
比如,虽然上述公式成立,但如果不是计算期望值,而是计算方差,和 是不一样的。因为两个随机变量的平均值相同,并不代表它们的方差相同。此话怎讲?以下是推导过程:
我们可以将 、分别 代入方差的公式,则分别可得(且考虑到不排除会有比初级更初级的初学者学习本文,故把第二个公式拆解的相对较细)
所以结论就是,如果我们只要对分布采样足够多次,对分布采样足够多次,得到的期望值会是一样的。但是如果我们采样的次数不够多,会因为它们的方差差距可能是很大的,所以就可能得到差别非常大的结果。
那怎么办呢?这就引出了:为解决两个分布差距大的问题,TRPO/PPO都增加了一个KL散度约束。
考虑到重要性采样有一个问题:如果 与 相差太多,即这两个分布相差太多,重要性采样的结果就会不好。怎么避免它们相差太多呢?这就是TRPO算法所要解决的
2015年John Schulman等人提出了信任区域策略优化(trust region policyopimization, TRPO),本质上,TRPO的出现解决了两个问题,一个解决重要性采样中两个分布差距太大的问题,一个是解决策略梯度算法中步长难以确定的问题
这是2.3.1节,我们已经得到的梯度计算和梯度更新公式
针对这个问题,我们考虑在更新时找到一块信任区域(trust region),在这个区域上更新策略时能够得到某种策略性能的安全性保证,这就是TRPO算法的主要思想
为进一步阐述后者,举个例子,比如爬两面都是悬崖的山。你首先选择最陡峭的方向,然后向前移动一个步长。如果步长太小,则需要很长时间才能到达峰值。但如果它太大,我们就会掉下悬崖。
信任域中的最大步长是多少?在信赖域方法中,我们从初始猜测开始可选地,然后动态地重新调整区域大小。例如,如果新政策和当前政策的差异越来越大,我们可以缩小信赖区域。
所以TRPO就是考虑到连续动作空间无法每一个动作都搜索一遍,因此大部分情况下只能靠猜。如果要猜,就最好在信任域内部去猜。而TRPO将每一次对策略的更新都限制了信任域内,从而极大地增强了训练的稳定性。
至此,PG算法的采样效率低下、步长难以确定的问题都被我们通过TRPO给解决了。但TRPO的问题在哪呢?
TRPO的问题在于把 KL 散度约束当作一个额外的约束,没有放在目标里面,导致TRPO很难计算,总之因为信任域的计算量太大了,John Schulman等人于2017年又推出了TRPO的改进算法:PPO
如上所述,PPO算法是针对TRPO计算量的大的问题提出来的,和TRPO一样也用上了KL散度约束,但PPO的改进在于把KL散度约束直接放在了目标函数里。
所以在 PPO 里面有两项:一项是优化本来要优化的,另一项是一个约束。这个约束就好像正则化(regularization)的项(term) 一样,它所做的就是希望最后学习出的 与 相差不大,如下所示
当然,你也也可以把上述那两个式子合二为一为(可以更直观的看出,PPO把约束作为惩罚项放在目标函数中,从而可以用梯度上升的方法去最大化它。
PPO 算法有两个主要的变种:近端策略优化惩罚(PPO-penalty)和近端策略优化裁剪(PPO-clip)。
我们先来看下近端策略优化惩罚PPO-penalty
上文有一个细节并没有讲到,即是怎么取值的呢,关于的设置有一个动态调整的方法,具体而言
综上,是可以动态调整的,因此我们称之为自适应KL惩罚(adaptive KL penalty)。最后,总结一下自适应KL惩罚:
近端策略优化惩罚可表示为
最后,如果我们觉得计算 KL散度很复杂,那么还有一个 PPO2算法,PPO2 即近端策略优化裁剪。近端策略优化裁剪的目标函数里面没有 KL 散度,其要最大化的目标函数为
整个目标函数在这个大括号里有两部分,最终对比两部分那部分更小,就取哪部分的值,这么做的本质目标就是为了让和可以尽可能接近,不至差距太大。
第一部分我们已经见过了,好理解,咱们来重点分析公式的第二部分
具体而言,针对目标函数
反之,如果小于0,则最终目标函数的取值为了更小则和大于0时反过来,毕竟加了个负号自然一切就不同了,为方便初学者一目了然,咱们还是把计算过程列出来,即
强化学习理论上可以不需要大量标注数据,然而实际上它所需求的reward存在一些缺陷,这导致强化学习策略很难推广:
reward的制定非常困难,比如说游戏AI中,可能要制定成百上千条游戏规则,这并不比标注大量数据来得容易
部分场景下reward的效果不好,比如说自动驾驶的多步决策(sequential decision)场景中,学习器很难频繁地获得reward,容易累计误差导致一些严重的事故
再比如聊天机器人方面,我们不好定义什么是好的对话、什么是不好的对话,但我们可以收集很多人类的对话当做范例,如此,模仿学习(Imitation Learning)应运而生。
模仿学习的思路是不让模型在人类制定的规则下自己学习,而是让模型模仿人类的行为。而逆强化学习就是模仿学习的其中一种,何谓逆强化学习呢?
总之,强化学习是由奖励函数推出什么样的动作/策略是最好的,逆强化学习则反过来
所以逆强化学习是先找出奖励函数,找出奖励函数以后,再用强化学习找出最优策略/动作。
根据instructGPT的原始论文可知,InstructGPT的训练分为三个阶段(总体上结合了监督学习和强化学习,先是监督学习让GPT3有一个大致的微调方向,然后用RL中的PPO算法来更新微调过的GPT3的参数):
阶段1:利用人类的标注数据(demonstration data)去对GPT3进行有监督训练
首先,OpenAI是先设计了一个prompt dataset,里面有大量的提示样本,给出了各种各样的任务描述
其次,找了一个标注团队对这个prompt dataset进行标注(本质就是人工回答问题)
最后,用这个标注过的数据集微调GPT3,这个微调好的GPT3我们称之为SFT模型(监督微调,全称Supervised fine-tuning,简称SFT),具备了最基本的预测能力
BTW,相信你还记得上文1.3节所说的GPT3通过prompt learning在小样本下令人惊艳的表现,另再说句题外话,咱们训练的最终目标就是通过不断缩小instructGPT与人类预测之间的差距,从而不断提高instructGPT的预测能力
阶段2:训练奖励模型RM
把微调好的SFT模型去回答prompt dataset某个问题,然后通过收集4个不同的SFT输出而获取4个回答,接着人工对这4个回答的好坏进行标注且排序,排序的结果用来训练一个奖励模型RM,具体做法就是学习排序结果从而理解人类的偏好
阶段3:通过训练好的RM模型预测结果且通过PPO算法优化SFT模型策略
具体做法是,再次让SFT模型去回答prompt dataset某个问题,然后此时不再让人工评估好坏,而是让阶段2训练好的奖励模型去给SFT模型的预测结果进行打分排序
就这样,一个初始的语言模型SFT模型来生成文本,以及一个奖励模型(RM)来判断模型生成的文本是否优质(迎合人类偏好),然后不断生成、不断评估,交替进行
此外,可能有读者疑问,InstructGPT为什么要做这样的改进,或者说它的novelty是什么?
所以,对InstructGPT的简单理解,可以是基于人类反馈的强化学习(RLHF)手段微调的GPT。
值得一提的是,这个训练过程是不和我们逆向强化学习很熟?
为什么呢,因为强化学习是利用奖励学习策略,而所谓的逆向强化学习一般是从策略中反推奖励函数,对应到这个instructGPT的训练过程中,它通过人类专家的行为逆向强化学习出一个奖励函数,最后再利用这个奖励函数进行强化学习训练,这不是很眼熟
这里先提一嘴,下文会再具体阐述
而通过OpenAI公布的ChatGPT训练图可知,ChatGPT的训练流程与InstructGPT是一致的,差异只在于
接下来,我们分别具体阐述上面的阶段2、阶段3。
这里插个观点。自AlphaGo使得强化学习猛然进入大众视野以来,大部分对于强化学习的理论研究都将游戏作为主要实验平台,这一点不无道理,强化学习理论上的推导看似逻辑通顺,但其最大的弱点在于,基于人工评判的奖励 Reward 的获得,让实验人员守在电脑前对模型吐出来的结果不停地打分看来是不现实的,游戏系统恰恰能会给出正确客观的打分(输/赢 或 游戏Score)。
基于RL的对话生成同样会面对这个问题,研究人员采用了类似AlphaGo的实现方式(AI棋手对弈)——同时运行两个机器人,让它们自己互相对话,同时,使用预训练(pre-trained)好的“打分器”给出每组对话的奖励得分,关于这个预训练的“打分器” R ,可以根据实际的应用和需求自己DIY,是否通顺是否辞不达意是否总说重复的废话
可能又有读者有疑问了,即instructGPT中,人类对模型的多个输出做个排序,为什么就能够提供监督信号,或者说在训练RM时如何怎么做到loss的梯度回传?
训练RM的核心是由人类对SFT生成的多个输出(基于同一个输入)进行排序,再用来训练RM。按照模仿学习的定义,直观上的理解可以是,RM在模仿人类对语句的排序思路,或者按照参考文献,即Google DeepMind和OpenAI团队2017年的论文《Deep reinforcement learning from human preferences》的说法是,模仿人类的偏好(Preference)。
那么到底是如何模仿的呢,或者说如何实现梯度回传?
这里我们代入一个场景,假设你向一个六岁小孩解释什么是登陆月球或什么是RL,如下图
针对这个损失函数需要逐一说明的是
如此,通过这种形式的梯度回传,RM逐渐学会了给D这类语句打高分,给A、B这类语句打低分,从而模仿到了人类偏好。到了这一步,不妨可以这么简单理解RLHF:所谓的人类反馈的强化学习,某种意义上来说,就是由人类的打分来充当reward。
instructGPT原始论文中的目标函数如下图所示
大部分文章在分析这个目标函数时基本都是人云亦云、一带而过,在这里,我们逐一拆接下这个目标函数,分为三个部分
最终,迭代式的更新奖励模型RM和策略模型SFT,让奖励模型对模型输出质量的刻画愈加精确,使得输出文本变得越来越符合人的认知
既然RLHF能很好地解决RL甚至IL的一些问题,也在InstructGPT中取得了很好的效果。那么,是否可以顺理成章地将之迁移到多轮对话场景中呢?或者说,ChatGPT是如何将这一套框架应用到多轮对话场景中的?
无限风光在险峰,故继续攀登,继续深入。
我们可以从强化学习的假设出发去理解这个问题。事实上,以PPO为代表的强化学习模型,基于马尔可夫性的假设。简单理解马尔科夫性就是,它将来的状态只取决于现在,与过去无关。也就是说,马尔可夫性有一个很重要的特点:无记忆性。
然而,在多轮人机对话场景中,模型却应该具备部分可观测马尔可夫性,即要求语言模型有“记忆性”。毕竟在多轮对话场景里,存在某一轮对话中的代词指向上一轮对话中的某个人或物的可能,假如模型不具备记忆性,那就无法很好地处理这种问题。显然,强化学习的假设与多轮对话场景的相背,不做一些优化的话很难直接应用。
那么进一步的问题来了,InstructGPT/ChatGPT是如何做优化的呢?
那么这个语言模型和强化学习又有什么样的联系呢?在强化学习中,我们有智能体/模型(Agent)和环境(Environment)交互这样的范式。但是在ChatGPT所使用的训练方式中,环境从某种意义上说被直接被奖励模型RM取代了,如下图
这里我们明白了在语言模型场景下,强化学习的状态和动作对应什么,那么奖励Reward呢?由于上文已经分析过instructGPT的目标函数了,这里就不再赘述,直接上图:
至此,还有一个细节问题,即这个奖赏函数是对整个输入语句和整个输出语句而言的,而我们又在之前讨论过,智能体是根据一个一个词来去拼凑出整个回答的。图中的奖赏函数只能给出完整回答的奖赏,那么在智能体生成回答的过程中,每个动作action给出的词对应的奖赏是什么呢?
这个细节在InstructGPT中并没有给出。幸运的是,OpenAI团队2020年的另一篇论文《Learning from summarize from Human feedback》中的一个引脚标注给出了关于这个疑问的答案。作者说,奖赏模型只在最终生成回答之后才给出奖赏,在中间的过程中是不给出奖赏的。在这里作者没有使用回答一词,而是使用总结一词,因为它的任务是将一篇长文章进行归纳总结。
同时,还有一个意外收获,发现这篇论文里就已经提出了instructGPT/chatgpt类似的训练模式:1 根据人来标注数据微调监督模型,2 训练一个奖励函数,3 通过PPO优化原始监督模型的策略
顺着这位作者的思路,只有在ChatGPT输出了EOS token的时候,整个轨迹才结束(EOS token是自然语言处理中用来表示一段话结束的标志)。
最后再让我们回顾梳理下这个问题:RLHF是如何运用到ChatGPT中的多轮对话场景中的?
问题又来了,什么是SeqGAN(Sequence Generative Adversarial Nets with Policy Gradient)呢?
非连续性序列生成,比如说文本生成(注意,图像和文本的核心区别在于图像的Pixel表示是连续的,而文本是由离散的token组成),为什么单纯的使用GAN没有取得很好的效果呢?主要的屏障有两点:
如果有办法解决上面的两个问题,便可以尝试将GAN用于NLP中。SeqGAN就提供了一种很巧妙的思路来解决这两个问题:
因此,强化学习和对抗思想的结合,理论上可以解决非连续序列生成的问题,而SeqGAN模型,正是这两种思想碰撞而产生的可用于文本序列生成的模型。
其实早就有人将RL应用于对话生成的训练当中,因为对话生成任务本身非常符合RL的运行机理(让人类满意,拿奖励)。假设根据输入句子,返回的回答 从人类得到的奖励记为 ,而Encoder-Decoder对话模型服从的参数被统一记为,则基于RL的目标函数说白了就是最大化生成对话的期望奖励,其中 表示在参数 下,一组对话出现的概率。
既然是一个最优化的问题,很直接地便想到使用基于梯度的优化方法解决。当然,在强化学习中,我们要得到的是最优策略 ,继而我们可以用策略梯度算法解决。
具体做法和2.3.1节推导策略梯度计算的公式类似,再贴一下
引用参考文献44的推导过程,如下
所以,当我们把等式 argmaxθ(⋅) 中的右边项单独记为 ,它表示对话模型找到最优参数时所得到的奖励期望。实际中,某句话的应答有N种可能性,则每组对话出现的概率可视为服从均匀分布,故还可以进行如下变形:
在优化过程中,对话模型的权重 更新如下,为所获奖励的变化梯度
借助复合函数的求导法则,继续推导奖励的变化梯度,
这样一来,梯度优化的重心就转化到了生成对话的概率上来,也就是说,通过对参数 进行更新,奖励会使模型趋于将优质对话的出现概率提高,而惩罚则会让模型趋于将劣质对话的出现概率降低。
SeqGAN的提出为GAN用于对话生成(Chatbot)完成了重要的铺垫,同样起到铺垫作用的还有另外一个GAN在图像生成领域的神奇应用——Conditional GAN[18~19],有条件的GAN,顾名思义就是根据一定的条件生成一定的东西,该工作根据输入的文字描述作为条件,生成对应的图像,比如:
对话生成可以理解为同样的模式,上一句对话作为条件,下一句应答则为要生成的数据,唯一的不同是需要生成离散的文本数据,而这个问题,SeqGAN已经帮忙解决了。权且称之为:Conditional SeqGAN。Conditional SeqGAN中的优化梯度可写成:
不难看出,此式子与上面的变化梯度仅一字之差,只是把“打分器”给出的奖励得分换成了鉴别器认为生成对话来自真人的概率得分 :
总之,RL+ GAN 利用强化学习中的Reward机制以及 Policy Gradient 等技术,巧妙地避开了GAN面对离散数据时梯度无法BP的难题,在使用强化学习的方法训练生成器G的间隙,又采用对抗学习的原版方法训练判别器D。 在Conditional SeqGAN对话模型的一些精选结果中,RL+ GAN 训练得到的生成器时常能返回一些类似真人的逼真回答。
此外,值得一提的是,我们所熟知的Actor-Critic是不是也是一种更广义上的GAN呢?
至此,我们总结下
这里我们可以梳理下RLHF和GPT的本质关系。实际上,这里使用RLHF就是为了解决我们无法对一个离散的训练进行求导的问题。而使用强化学习来解决这个问题也不是ChatGPT的独创:早在2016年SeqGAN的作者就已经使用了这样的方法了。因此我们可以从问题本质的角度去这么理解ChatGPT:它就是把Transformer和“SeqGAN”结合在一起。
从问题本质上看,ChatGPT与之前的工作的最大不同,就体现在它使用了类似SeqGAN的方式进行微调:先通过基于人类偏好定义奖励函数,再基于奖励函数通过PPO持续优化。
huggingface的两篇RL教程:An Introduction to Deep Reinforcement Learning、GitHub:The Hugging Face Deep Reinforcement Learning Course
事实上,可能很多朋友也已经意识到,本文的前大部分内容里,GPT-N理解起来相对轻松,而instructGPT/ChatGPT的整体架构思想也不算复杂,但其中涉及到的强化学习部分则让想深挖细节的初学者变得立马吃力起来(除非你已“入一定门”,或者你有课程/老师可以不断问),看似就两个概念,一个RLHF,一个PPO算法,但要真正把这两个概念讲清楚、讲透彻则没那么容易了,特别是PPO算法。
所以1.6日决定只是想写个ChatGPT通俗导论,但为了讲清楚其中的PPO算法,更考虑到ChatGPT笔记之后,再下一篇是强化学习极简入门,故中途花了大半时间去从头彻底搞懂RL,最终把网上关于RL的大部分中英文资料都翻遍之外(详见参考文献与推荐阅读),还专门买了这几本强化学习中文书以系统学习
总之,RL里面的概念和公式很多(相比ML/DL,RL因为想要机器/程序具备更高、更好的自主决策能力),而绝大部分的资料:没有站在初学者的角度去通俗易懂化、没有把概念形象具体化、没有把公式拆解举例化(如果逐一做到了这三点,何愁写不出通俗易懂的文章/书籍/课程)。
以下是本文自1.15发布初稿之后的修改记录: