Open main menu
首页
专栏
课程
分类
归档
Chat
Sci-Hub
谷歌学术
Libgen
GitHub镜像
登录/注册
搜索
关闭
Previous
Previous
Next
Next
ChatGPT技术原理解析:从RL之PPO算法、RLHF到GPT4、instructGPT
sockstack
/
331
/
2023-11-09 00:02:11
<p><span style="color: red; font-size: 18px">ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。</span><br><a href="https://ckai.xyz/?sockstack§ion=detail" target="__blank">https://ckai.xyz</a><br><br></p> <article class="baidu_pl"><div id="article_content" class="article_content clearfix"> <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css"> <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-25cebea3f9.css"> <div id="content_views" class="htmledit_views"> <p><strong>写在最前面</strong>,为了彻底写清楚ChatGPT背后的所有关键细节,从1月初写到4月底仍未完工,除了本文之外,过程中涉及到多篇文章(RL 论文 项目 CV多模态),再加上之前写的Transformer、RL数学基础等多篇笔记,成了一个大系列:</p> <ul> <li>Transformer通俗笔记:从Word2Vec、Seq2Seq逐步理解到GPT、BERT</li> <li>RL所需的微积分/概率统计基础、最优化基础</li> <li>强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO</li> <li>ChatGPT与多模态必读论文100篇(2.27日起,每周更新)</li> <li>类ChatGPT的部署与微调:从LLaMA、Alpaca/Vicuna/BELLE、中文版、从GLM、ChatGLM到MOSS、ChatDoctor、可商用</li> <li>类ChatGPT代码逐行解读:从零实现Transformer、ChatGLM-6B、从零实现TRL、ChatLLaMA、ColossalChat、DeepSpeed Chat</li> <li>AI绘画与CV多模态原理解析:VAE、扩散模型DDPM、DETR、ViT/Swin transformer、CLIP/BLIP到stable diffusion、GPT4(后者待6月中旬发布)</li> </ul> <p>另,我<span style="color:#ed7976;">本人主讲的</span>《ChatGPT技术原理解析》、及《类ChatGPT项目实战 [定制中文垂直商用版,且提供GPU]》会比本系列讲的更加深入、细致、透彻</p> <hr> <h1>前言</h1> <p>自从我那篇Transformer通俗笔记一经发布,然后就不断改、不断找人寻求反馈、不断改,其中一位朋友倪老师(之前我司NLP高级班学员现课程助教老师之一)在谬赞Transformer笔记无懈可击的同时,给我建议到,“后面估计可以尝试尝试在BERT的基础上,讲一讲prompt学习了”</p> <p>再然后,当我还在各种改Transformer笔记的时候,12月初突然出来了一个ChatGPT刷爆朋友圈,即便很多之前不接触AI的朋友也在问ChatGPT这种类似聊天机器人却远胜一般聊天机器人各种问题(上一次出现这种盛况的还是16年的AlphaGo)。</p> <p>据我观察,大家问ChatGPT的问题千奇百怪</p> <ul> <li>有的让他算经典的鸡兔同笼问题,且也能在和人类自然而流畅的互动中举一反三</li> <li>有的让其根据要求排查代码bug,要知道此前debug想寻求帮助<br> 要么问人(问熟人用社交软件,问陌生人则类似那种问答网站,持续问一般得付费,毕竟没人乐意持续免费答疑大量技术难题)<br> 要么Google搜有没人遇到类似的问题(但别人遇到的问题很难与你的百分百一致)<br> 要么用Codex这类代码软件,但在和人类的互动交互上,还不是那么善解人意</li> </ul> <p>所以ChatGPT就相当于你写代码或各类问题的私人顾问,而这个私人顾问能瞬间、精准理解你的意图,不会让你像用以前那种聊天机器人经常觉得智障甚至对牛弹琴,加之其背后依托的是人类级百科全书式的资料库,所以有人惊呼:ChatGPT会不会替代Google这类搜索引擎。</p> <p>虽然一开始大部分技术者对待ChatGPT还是比较冷静的,毕竟它给的答案不像权威技术专家那样具备足够的公信力,也不像Google给出来源从而不能比较好的验证其正确程度,但后来很快发生的几件大事彻底改变了大家此前的看法</p> <ol> <li>23年1月初,微软欲用 ChatGPT 扶必应“上位”,对抗 Google,且很快,ChatGPT直接让其所在的公司OpenAI估值翻倍</li> <li>23年3月中旬,OpenAI正式对外发布GPT-4,增加了多模态(支持图片的输入形式),且ChatGPT底层的语言模型直接从GPT3.5升级到了GPT4,回答问题的准确率大幅提升</li> <li>23年3月17日,微软推出Microsoft 365 Copilot,集成GPT4的能力,实现自动化办公,通过在Word PPT Excel等办公软件上输入一行指令,瞬间解决一个任务<br> 3.23日更推出GitHub Copilot X,让自动化编程不再遥远</li> <li>23年3月24日,OpenAI宣布推出插件功能,赋予ChatGPT使用工具(数学问题精准计算)、联网(获取实时最新消息,底层知识不再只截止到21年9月份)的能力</li> </ol> <p>然目前关于ChatGPT中文的资料里,真正<strong>能让人一看就懂</strong>的非常非常少,当少数文章具备比较好的可读性之后,你又会发现一旦涉及算法细节就千篇一律的泛泛而谈,如果不是泛泛而谈的,则更多堆砌概念和公式,有的甚至漏洞百出<br> 总之中文资料里,可能因为instructGPT/ChatGPT刚出来不久的缘故,<strong>兼顾可读性、细节性、准确性</strong>的文章少的可怜</p> <p>考虑到ChatGPT非一蹴而就,而是经过了各个前置技术的发展、迭代、结合而成,故逐一阐述</p> <ul> <li>2017年之前早已有之的一些数学/AI/<strong>RL</strong>等基础技术,比如微积分、概率统计、最优化、策略梯度、<strong>TRPO</strong>算法(2015年提出)</li> <li>2017年6月OpenAI联合DeepMind首次正式提出的:Deep Reinforcement Learning from Human Preferences,即<em>基于人类偏好的深度强化学习</em>,简称<strong>RLHF</strong> </li> <li>2017年7月的OpenAI团队提出的对TRPO算法的改进:<strong>PPO</strong>算法<br> 关于RL、策略梯度、TRPO、PPO则写在了此文《强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO<span style="color:#4d4d4d;">》<br> 且在这篇RL极简入门笔记之前,99%的文章都不会把PPO算法从头推到尾,该文把PPO从零推到尾,按照“RL-策略梯度-重要性采样(重要性权重)-增加基线(避免奖励总为正)-TRPO(加进KL散度约束)-PPO(解决TRPO计算量大的问题)”的顺序逐步介绍每一步推导</span> </li> </ul> <ul> <li>2017年6月的<strong>Transformer</strong>/Self-Attention<br> 关于transformer/self-attention,除了本文,更可以看下上篇《Transformer通俗笔记:从Word2Vec、Seq2Seq逐步理解到GPT、BERT》<br> </li> <li>2018年6月的<strong>GPT</strong>(Generative Pre-trained Transformer),其关键构成是基于Transformer-Decoder的Masked Self-Attention</li> <li>2019年2月的融合prompt learning的<strong>GPT2</strong>,prompt learning的意义在于不用微调也能做任务</li> <li>2020年5月的<strong>GPT3</strong>,参数规模到了1750亿,终于真正做到预训练之后不用再微调模式,通过In-context learning(简称<strong>ICL</strong>)开启prompt新范式,且你可能没想到的是,<strong>这一年的9月份OpenAI已经开始研究GPT3与RLHF的结合了</strong>,且此时用的策略优化方法为PPO<br> </li> <li>2021年7月的<strong>Codex</strong>,通过对GPT3进行大量的代码训练迭代而出Codex,从而具备代码/推理能力</li> <li>2021年9月Google提出的FLAN大模型:基于指令微调技术Instruction Fine-Tuning (<strong>IFT</strong>)<br><em>此前,Google曾在21年5月对外宣布内部正在研发对话模型LaMDA,而FLAN is the instruction-tuned version of LaMDA-PT<br> 2019年10月,Google发布T5模型(transfer text to text transformer),虽也基于transformer,但区别于BERT的编码器架构与GPT的解码器架构,T5是transformer的encoder-decoder架构<br> 2022年1月,Google发布LaMDA论文『 </em>LaMDA: Language Models for Dialog Applications』<br><em>2022年4月,Google提出PaLM: Scaling Language Modeling with Pathways,5400亿参数<br> 2022年10月,Google提出Flan-T5<br> 23年3月6日,Google提出多模态LLM模型PaLM-E</em> </li> <li>2022年1月的Google研究者提出的思维链技术(Chain of Thought,简称<strong>CoT</strong>)<br> </li> <li>2022年3月的OpenAI正式发布<strong>instructGPT</strong>:GPT3 + instruction tuning + RLHF + PPO,其中,instruction tuning和prompt learning的核心区别在于instruction tuning会提供更多的指令引导模型输出更符合预期的结果,例如<br> 提示学习:给女朋友买了这个项链,她很喜欢,这个项链太____了<br> 指令微调:判断这句话的情感:给女朋友买了这个项链,她很喜欢。选项:A=好;B=一般;C=差<br> 你也可以暂简单理解instruction tuning为带人类指令的prompting</li> <li>2021年第4季度逐步发展而来的<strong>GPT3.5</strong>,并于22年不断融合Codex、InstructGPT的技术能力</li> <li>2022年11月的<strong>ChatGPT</strong>:语言模型层面的核心架构是<strong>GPT3.5</strong>(基于Transformer-Decoder的Masked Self-Attention且融合了Codex的代码/推理能力、instruction tuning等技术)<strong> + RLHF + PPO3</strong><br> </li> <li>2023年3月中旬,OpenAI正式对外发布<strong>GPT-4</strong>,增加了多模态(支持图片的输入形式),且ChatGPT底层的语言模型直接从GPT3.5升级到了GPT4</li> </ul> <p>如你所见,自从1.6日开始写ChatGPT笔记,1.15日发布本文,但为把ChatGPT背后所涉及的关键技术阐述细致、透彻,故本文越写越长,长到最后成了一个系列,有的内容抽离出去独立成文,有的还在不断完善</p> <h1>第一部分 从RL、策略梯度到TRPO、PPO算法、RLHF</h1> <p>再次强调说明下,本第一部分在23年2.10日有个重要修改</p> <ul> <li>2.10日之前,考虑到本文的主旨核心ChatGPT用到了RLHF和PPO,所以本文的第一部分从强化学习讲到PPO算法,毕竟虽然只是想重点介绍下PPO,但写到最后还是把PPO所有相关的前置知识都细致介绍了个遍,不然,总感觉有细节没交待而不够透彻</li> <li>2.10日之后,又考虑到有些朋友可能对RL细节有所了解,或者更多希望整体了解ChatGPT整体架构而暂不细究其所用的策略迭代算法PPO的前置技术、RL细节</li> </ul> <p>综上,为兼顾两者,且加之为避免本文篇幅过长而影响完读率,故把下面原先第一部分的大部分内容抽取出来放到了新一篇RL笔记里进一步细致阐述:强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO</p> <blockquote> <p>第一部分 RL基础:什么是RL与MRP、MDP<br> 1.1 入门强化学习所需掌握的基本概念</p> <ul> <li>1.1.1 什么是强化学习:依据策略执行动作-感知状态-得到奖励</li> <li>1.1.2 RL与监督学习的区别和RL方法的分类</li> </ul> <p>1.2 什么是马尔科夫决策过程</p> <ul> <li>1.2.1 MDP的前置知识:随机过程、马尔可夫过程、马尔可夫奖励</li> <li>1.2.2 马尔可夫决策过程(MDP):马尔可夫奖励(MRP) + 智能体动作因素</li> </ul> <hr> <p>第二部分 RL进阶之三大表格求解法:DP、MC、TD<br> 2.1 动态规划法</p> <ul> <li>2.1.1 什么是动态规划</li> <li>2.1.2 通过动态规划法求解最优策略</li> </ul> <p>2.2 蒙特卡洛法<br> 2.3 时序差分法及与DP、MC的区别<br> 2.4 RL的分类:基于模型(Value-base/Policy-based)与不基于模型</p> <hr> <p>第三部分 价值学习:从n步Sarsa算法到Q-learning、DQN<br> 3.1 TD(0)控制/Sarsa(0)算法与TD(n)控制/n步Sarsa算法<br> 3.2 Q-learning</p> <ul> <li>3.2.1 重要性采样:让同策略完成到异策略的转变</li> <li>3.2.2 Sarsa算法与Q-learning更新规则的对比</li> </ul> <p>3.3 DQN</p> <hr> <p>第四部分 策略学习:从策略梯度、Actor-Criti到TRPO、PPO算法<br> 4.1 策略梯度与其突出问题:采样效率低下</p> <ul> <li>4.1.1 什么是策略梯度和梯度计算/更新的流程</li> <li>4.1.2 避免采样的数据仅能用一次:重要性采样(为采样q解决p从而增加重要性权重)</li> </ul> <p>4.2 优势演员-评论家算法(Advantage Actor-Criti):为避免奖励总为正增加基线<br> 4.3 基于信任区域的TRPO:加进KL散度解决两个分布相差大或步长难以确定的问题</p> </blockquote> <h2>1.4 近端策略优化PPO:解决TRPO的计算量大的问题</h2> <p>如上所述,PPO算法是针对TRPO计算量的大的问题提出来的,正因为PPO基于TRPO的基础上改进,故PPO也解决了策略梯度不好确定学习率Learning rate (或步长Step size) 的问题</p> <p>毕竟通过上文,我们已经得知</p> <ol> <li>如果 step size 过大, 学出来的 Policy 会一直乱动,不会收敛;但如果 Step Size 太小,想完成训练,我们会等到地老天荒</li> <li>而PPO 利用 New Policy 和 Old Policy 的比例,限制了 New Policy 的更新幅度,让策略梯度对稍微大点的 Step size 不那么敏感</li> </ol> <p>具体做法是,PPO算法有两个主要的变种:近端策略优化惩罚(PPO-penalty)和近端策略优化裁剪(PPO-clip),其中PPO-penalty和TRPO一样也用上了KL散度约束。</p> <p>近端策略优化惩罚PPO-penalty的流程如下</p> <ol> <li> <p>首先,明确目标函数,咱们需要优化<img referrerpolicy="no-referrer" alt="gif.latex?J%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?J%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29">,让其最大化</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="J^{\theta^{\prime}}(\theta)=\mathbb{E}_{\left(s_{t}, a_{t}\right) \sim \pi_{\theta^{\prime}}}\left[\frac{p_{\theta}\left(a_{t} \mid s_{t}\right)}{p_{\theta^{\prime}}\left(a_{t} \mid s_{t}\right)} A^{\theta^{\prime}}\left(s_{t}, a_{t}\right)\right]" class="mathcode" src="https://latex.codecogs.com/gif.latex?J%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3D%5Cmathbb%7BE%7D_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%20%5Csim%20%5Cpi_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%7D%5Cleft%5B%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%5D"></p> <p>『注:如果你想仔细抠接下来各种公式但一上来就被上面这个弄迷糊了,说明还是需要先看下上文说过的这篇RL极简入门,而一旦踏入RL,便得做好两万五千里的准备,当然,<strong>如果只是想了解ChatGPT背后大概的技术原理,可以不用细抠PPO的公式怎么来的,不影响你对ChatGPT整体架构的理解</strong>,且下文会讲其在ChatGPT中是如何运用的』</p> </li> <li> <p>接下来,先初始化一个策略的参数<img referrerpolicy="no-referrer" alt="\theta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta">,在每一个迭代里面,我们用前一个训练的迭代得到的actor的参数<img referrerpolicy="no-referrer" alt="\theta '" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%20%27">与环境交互,采样到大量状态-动作对, 根据<img referrerpolicy="no-referrer" alt="\theta '" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%20%27">交互的结果,估测<img referrerpolicy="no-referrer" alt="A^{\theta '}(s_t,a_t)" class="mathcode" src="https://latex.codecogs.com/gif.latex?A%5E%7B%5Ctheta%20%27%7D%28s_t%2Ca_t%29"></p> </li> <li>由于目标函数牵涉到重要性采样,而在做重要性采样的时候,<img referrerpolicy="no-referrer" alt="gif.latex?p_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?p_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29">不能与<img referrerpolicy="no-referrer" alt="gif.latex?p_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?p_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29">相差太多,所以需要在训练的时候加个约束,这个约束就好像正则化的项一样,是 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta">与 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27">输出动作的 KL散度,用于衡量 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta"> 与 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27"> 的相似程度,我们希望在训练的过程中,学习出的 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta"> 与 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27"> 越相似越好<br> 所以需要最后使用 PPO 的优化公式:<img referrerpolicy="no-referrer" alt="\\J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)" src="https://latex.codecogs.com/gif.latex?%5C%5CJ_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3DJ%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29"><p><br> 当然,也可以把上述那两个公式合二为一『如此可以更直观的看出,PPO-penalty把KL散度约束作为惩罚项放在了目标函数中(可用梯度上升的方法去最大化它),此举相对TRPO减少了计算量』</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="gif.latex?%5Cbegin%7Baligned%7D%20%26J_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3D%5Cmathbb%7BE%7D_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%20%5Csim%20%5Cpi_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%7D%5Cleft%5B%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%5D%20%5Cend%7Baligned%7D%20-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20%26J_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3D%5Cmathbb%7BE%7D_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%20%5Csim%20%5Cpi_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%7D%5Cleft%5B%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%5D%20%5Cend%7Baligned%7D%20-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29"></p> </li> </ol> <p>上述流程有一个细节并没有讲到,即<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta">是怎么取值的呢,事实上,<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta">是可以动态调整的,故称之为自适应KL惩罚(adaptive KL penalty),具体而言</p> <ul> <li>先设一个可以接受的 KL 散度的最大值<img referrerpolicy="no-referrer" alt="KL_{max}" class="mathcode" src="https://latex.codecogs.com/gif.latex?KL_%7Bmax%7D"><br> 假设优化完<img referrerpolicy="no-referrer" alt="\\J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)" src="https://latex.codecogs.com/gif.latex?%5C%5CJ_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3DJ%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29">以后,KL 散度值太大导致<img referrerpolicy="no-referrer" alt="\mathrm{KL}(\theta,\theta')>\mathrm{KL}_{\max}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cmathrm%7BKL%7D%28%5Ctheta%2C%5Ctheta%27%29%3E%5Cmathrm%7BKL%7D_%7B%5Cmax%7D">,意味着 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta">与<img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27">差距过大(即学习率/步长过大),也就代表后面惩罚的项<img referrerpolicy="no-referrer" alt="\beta \mathrm{KL}(\theta ,\theta ')" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta%20%5Cmathrm%7BKL%7D%28%5Ctheta%20%2C%5Ctheta%20%27%29">惩罚效果太弱而没有发挥作用,故增大惩罚把<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta">增大</li> <li>再设一个 KL 散度的最小值<img referrerpolicy="no-referrer" alt="KL_{min}" class="mathcode" src="https://latex.codecogs.com/gif.latex?KL_%7Bmin%7D"><br> 如果优化完<img referrerpolicy="no-referrer" alt="\\J_{\mathrm{PPO}}^{\theta^{\prime}}(\theta)=J^{\theta^{\prime}}(\theta)-\beta \mathrm{KL}\left(\theta, \theta^{\prime}\right)" src="https://latex.codecogs.com/gif.latex?%5C%5CJ_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3DJ%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29">以后,KL散度值比最小值还要小导致<img referrerpolicy="no-referrer" alt="\mathrm{KL}(\theta,\theta')< {KL}_{\min}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cmathrm%7BKL%7D%28%5Ctheta%2C%5Ctheta%27%29%3C%20%7BKL%7D_%7B%5Cmin%7D">,意味着 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta">与 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27"> 差距过小,也就代表后面这一项<img referrerpolicy="no-referrer" alt="\beta \mathrm{KL}(\theta ,\theta ')" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta%20%5Cmathrm%7BKL%7D%28%5Ctheta%20%2C%5Ctheta%20%27%29">的惩罚效果太强了,我们怕它只优化后一项,使<img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta">与 <img referrerpolicy="no-referrer" alt="gif.latex?%5Ctheta%27" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%27"> 一样,这不是我们想要的,所以减小惩罚即减小<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta"> </li> </ul> <p>总之,近端策略优化惩罚可表示为</p> <p style="text-align:center;"><img referrerpolicy="no-referrer" alt="\begin{aligned} &J_{\text{PPO}}^{\theta'}(\theta)=J^{\theta'}(\theta)-\beta \text{KL}\left(\theta, \theta'\right) \\ &J^{\theta'}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \frac{p_{\theta}\left(a_{t} \mid s_{t}\right)}{p_{\theta'}\left(a_{t} \mid s_{t}\right)} A^{\theta'}\left(s_{t}, a_{t}\right)\end{aligned}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20%26J_%7B%5Ctext%7BPPO%7D%7D%5E%7B%5Ctheta%27%7D%28%5Ctheta%29%3DJ%5E%7B%5Ctheta%27%7D%28%5Ctheta%29-%5Cbeta%20%5Ctext%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%27%5Cright%29%20%5C%5C%20%26J%5E%7B%5Ctheta%27%7D%28%5Ctheta%29%20%5Capprox%20%5Csum_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%7D%20%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%27%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cend%7Baligned%7D"></p> <p>当然,如果觉得计算 KL散度很复杂,则还有一个PPO2算法,即近端策略优化裁剪PPO-clip,包括PPO算法的一个简单实现,均详见RL极简入门一文</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} J_{\mathrm{PPO2}}^{\theta'}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \min &\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta'}\left(a_{t} | s_{t}\right)} A^{\theta'}\left(s_{t}, a_{t}\right),{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta'}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta'}\left(s_{t}, a_{t}\right)\right) \end{aligned}" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20J_%7B%5Cmathrm%7BPPO2%7D%7D%5E%7B%5Ctheta%27%7D%28%5Ctheta%29%20%5Capprox%20%5Csum_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%7D%20%5Cmin%20%26%5Cleft%28%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%27%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%2C%7Bclip%7D%5Cleft%28%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%2C%201-%5Cvarepsilon%2C%201&plus;%5Cvarepsilon%5Cright%29%20A%5E%7B%5Ctheta%27%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%29%20%5Cend%7Baligned%7D"></p> <blockquote> <p>PPO算法是一种具体的Actor-Critic算法实现,比如在对话机器人中,输入的prompt是state,输出的response是action,想要得到的策略就是怎么从prompt生成action能够得到最大的reward,也就是拟合人类的偏好。具体实现时,可以按如下两大步骤实现</p> <ul><li>首先 Make Experience 部分,利用 SFT 、Actor、RM、Critic模型计算生成 Experience 存入 buffer 中<br> 具体做法是先定义4个模型:Actor(action_logits)、SFT(sft_logits)、Critic(value)、RM「r(x, y)」,和kl_div、reward、优势函数adv<br> 然后从prompt库中采样出来的prompt在经过SFT(<span style="color:#7b7f82;">很快,你会通过本文下文可知,微调过GPT3/GPT3.5的模型称之为SFT</span>)做generate得到一个response,这个『prompt + response』定义为sequence(这个采样的过程是批量采样进行generate,得到一个sequence buffer),接着这个sequence buffer的内容做batched之后输入给4个模型做inference</li></ul> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="488" src="https://img-blog.csdnimg.cn/1ecb75833281415497f94e0cbe0279bd.png" width="600"></p> <p>之后是参数更新部分,利用 Experience 计算价值损失(value loss)和策略损失(policy loss)</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="390" src="https://img-blog.csdnimg.cn/bd6e7b452a10424eab899855dd4eec9a.png" width="600"></p> <p>更多请参见强化学习极简入门的最后一小节4.4.3节... </p> </blockquote> <h2>1.5 模仿学习(逆强化学习)思路下的RLHF:从人类反馈中学习</h2> <h3>1.5.1 什么是模仿学习(逆强化学习)</h3> <p>虽然RL理论上虽不需要大量标注数据,但实际上它所需求的reward会存在缺陷:</p> <ol> <li> <p>比如游戏AI中,reward的制定非常困难,可能要制定成百上千条游戏规则,这并不比标注大量数据来得容易,又比如自动驾驶的多步决策(sequential decision)场景中,学习器很难频繁地获得reward,容易累计误差导致一些严重的事故</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="d031d2873feecc4c67cf7d45ece4386e.png" height="385" src="https://img-blog.csdnimg.cn/img_convert/d031d2873feecc4c67cf7d45ece4386e.png" width="700"></p> </li> <li> <p>再比如聊天机器人方面,不好定义什么是好的对话、什么是不好的对话,当然,对此可以收集很多人类的对话当做范例,如此,模仿学习思路下的<em>基于人来偏好的深度强化学习</em>(对应论文为:Deep Reinforcement Learning from Human Preferences 2017,简称RLHF)应运而生<br> RLHF试图解决的问题是,在奖励函数不够明确的情况下,通过基于人类对事物比较的偏好而非绝对奖励值训练奖励函数</p> </li> </ol> <p>模仿学习的思路是不让模型在人类制定的规则下自己学习,而是让模型模仿人类的行为。而逆强化学习就是模仿学习的其中一种,何谓逆强化学习呢?</p> <ul> <li>原来的强化学习里,有Environment和Reward Model(由奖励函数推出什么样的策略/动作是最好的),但逆强化学习没有奖励函数,只有一些人类/专家的示范,怎么办呢</li> <li>可以<u>通过人类标注数据训练得到Reward Model</u>(相当于有了人类标注数据,则相信它是不错的,然后反推人类因为什么样的奖励函数才会采取这些行为)</li> <li>有了奖励函数之后,就可以使用一般的强化学习的方法去找出最优策略/动作</li> </ul> <h3>1.5.2 RLHF:基于人类偏好的深度强化学习</h3> <p>实际上,RLHF(Reinforcement Learning with Human Feedback)这一概念最早被定义为<em>基于人类反馈的强化学习</em>,它最早是在2008年《TAMER:Training an Agent Manually via Evaluative Reinforcement》一文中被提及的</p> <p>在2017年前后,深度强化学习(Deep Reinforcement Learning)逐渐发展并流行起来,如你所见,2017年6月由OpenAI联合Google DeepMind一块推出:<em>基于人类偏好的深度强化学习</em>《Deep Reinforcement Learning from Human Preferences》,也简称RLHF</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="348" src="https://img-blog.csdnimg.cn/5742da727fbb4fb5a4274b75f9af6c0c.png" width="700"></p> <p>当让一个强化学习智能体探索环境并与之交互(比如Atari游戏),RLHF的核心步骤如下图所示:</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="312" src="https://img-blog.csdnimg.cn/e94393305b0b40659583bc3f75f44d25.png" width="700"></p> <ol> <li>首先,智能体的一对1-2秒的行为片段定期地回馈给人类操作员,人类基于偏好对智能体的行为作出某种偏好性的选择评判</li> <li>接着,人类这种基于偏好的选择评判被预测器(reward predictor)来预测奖励函数</li> <li>智能体通过预测器预测出的奖励函数作出更优的行为(毕竟智能体要最大化奖励嘛)</li> </ol> <p>再之后,OpenAI团队通过下述两篇论文进一步阐述了RLHF</p> <ul> <li>Fine-Tuning Language Models from Human Preferences (Zieglar et al. 2019)<br> 在Reward model的训练中,我们需要人的参与,human labelers给policy模型生成的文本打分,这个分数作为reward model学习的标签 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="225" src="https://img-blog.csdnimg.cn/6ce3da16ad6b41c998ee25b8aca3fa75.png" width="700"></p> Reward mode训练好后,那么在训练policy model时,Reward model便可以完全取代human labeler打分,分数作为信号传给policy model,再利用OpenAI默认的策略优化算法PPO来训练 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="160" src="https://img-blog.csdnimg.cn/b070502a47924402bf65968b53a3f726.png" width="700"></p> </li> <li>Learning to summarize with human feedback (Stiennon et al., 2020)<br> 如你所见,OpenAI团队在2020年9月的这篇论文里就已经提出了类似instructGPT/ChatGPT的训练模式: <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="552" src="https://img-blog.csdnimg.cn/97b7e66fd24947e59fbf90b1b9a57706.png" width="1000"></p> 1 根据人工标注数据微调监督模型<br> 所谓微调,即指当我们预训练出一个语言模型后,为了更好的让它完成咱们手头上的任务,会通过一定的样例/样本对该模型的参数做一定的调整或适配<br> 2 训练一个奖励函数(下文会详述reward的这个损失函数,这里暂且做个粗略理解,即相当于reward不再是人直接给了,而是用高质量标注训练一个好的reward模型) <p class="img-center"><img referrerpolicy="no-referrer" alt="loss(r_\theta) = -E_{(x,y_0,y_1,i)\sim D}[log( \sigma (r_\theta(x, y_i) - r_\theta(x, y_{1-i}))]" class="mathcode" src="https://latex.codecogs.com/gif.latex?loss%28r_%5Ctheta%29%20%3D%20-E_%7B%28x%2Cy_0%2Cy_1%2Ci%29%5Csim%20D%7D%5Blog%28%20%5Csigma%20%28r_%5Ctheta%28x%2C%20y_i%29%20-%20r_%5Ctheta%28x%2C%20y_%7B1-i%7D%29%29%5D"></p> 3 有了reward,接下来便可以通过PPO优化模型的策略(下文也会详细阐述这个公式) <p class="img-center"><img referrerpolicy="no-referrer" alt="R(x, y) = r_\theta (x, y) - \beta log\left [ \pi _{\phi}^{RL}(y|x)/\pi _{}^{SFT}(y|x) \right ]" class="mathcode" src="https://latex.codecogs.com/gif.latex?R%28x%2C%20y%29%20%3D%20r_%5Ctheta%20%28x%2C%20y%29%20-%20%5Cbeta%20log%5Cleft%20%5B%20%5Cpi%20_%7B%5Cphi%7D%5E%7BRL%7D%28y%7Cx%29/%5Cpi%20_%7B%7D%5E%7BSFT%7D%28y%7Cx%29%20%5Cright%20%5D"></p> </li> </ul> <h1>第二部分 从GPT/GPT2/GPT3到GPT3.5/GPT4:微调到prompt学习的过渡</h1> <h2>2.1 GPT:基于Transformer Decoder预训练 + 微调/Finetune</h2> <p>NLP自发展以来,先后经历了4种任务处理范式</p> <ol> <li>第一种范式,<u>非神经网络时代的完全监督学习</u>(Fully Supervised Learning, Non-Neural Network)<br> 具体而言,即手工设计一系列特征模板,来输入模型。模型对任务的处理结果高度依赖于特征模板的设计,同时也高度依赖领域专家的知识。举个例子,比如对于条件随机场CRF模型,业界甚至有一个专门的库CRF++帮助自动生成大量的随机模板然后输入模型进行训练,从而避免对领域专家的过度依赖</li> <li>第二范式,<u>基于神经网络的完全监督学习</u>(Fully Supervised Learning, Neural Network)<br> 神经网络学派开始流行以后,处理范式基本基本是预训练后的词嵌入表征 + 模型架构的调整,在这个时期,一方面的工作在词嵌入上,比如NNLM/CBOW/SKIP/GRAM/GLOVE/ELMO等,另一方面的工作则在模型架构上,比如BI-LSTM/SEQ2SEQ架构在神经机器翻译领域NMT的应用等</li> <li>第三范式,<u>预训练-微调范式</u> (Pre-train、Fine-tune)<br> 相比于第二范式而言,第三范式的优点在于更进一步减少了人工的参与,不再需要对于每个任务采取不同的模型架构,而是在超大的文本数据集上预训练一个具备泛化能力的通用的模型,然后再根据下游任务本身的特点对模型进行针对性的微调即可,使得一个模型解决多种任务成为可能,比如GPT1模型</li> <li>第四范式,<u>预训练、提示、预测范式</u>(Pre-train、Prompt、Predict)<br> 在这个过程我们往往不对预训练语言模型改动太多,我们希望是通过对合适prompt的利用将下游任务建模的方式重新定义,这则是GPT2、GPT3的特点</li> </ol> <h3>2.1.1 GPT = Multi-Head Attention层 + Feed forward层 + 求和与归一化的前置LN层 + 残差</h3> <p>GPT由openAI在2018年通过此论文“Improving Language Understanding by Generative Pre-Training”提出,使用了一个大型的未标记文本语料库来进行生成式预训练(该语料库包含40GB的文本数据,比如互联网上抓取的网页、维基百科、书籍和其他来源的文本)</p> <p>在GPT 被提出之前</p> <ol> <li>大多数深度学习方法都需要大量人工标注的高质量数据,但是标注数据的代价是巨大的<br> 故如何利用容易获取的大规模无标注数据来为模型的训练提供指导成为亟待解决的第一个问题</li> <li>另外NLP领域中有许多任务依赖于自然语言在隐含空间中的表征,不同任务对应的表征很可能是不同的,这使得根据一种任务数据学习到的模型很难泛化到其他任务上<br> 因此如何将从大规模无标注数据上学习到的表征应用到不同的下游任务成为亟待解决的第二个问题</li> </ol> <p>在上一篇Transformer笔记中,我们已经了解到:GPT是“Generative Pre-Training Transformer”的简称,从名字看其含义是指的生成式的预训练,它和BERT都是<strong>(无监督)预训练-(监督)微调模式</strong>的典型代表</p> <ul> <li>第一阶段,在未标记数据上使用语言建模目标来学习神经网络模型的初始参数</li> <li>第二阶段,针对目标任务使用相应的标记数据对这些参数进行微调<br> 之所以叫微调是因为在这个阶段用的数据量远远小于第一阶段,并且基本没有更改模型架构和引入过多新的参数</li> </ul> <p>由于Decoder具备文本生成能力,故作为侧重生成式任务的GPT选择了Transformer Decoder部分作为核心架构</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="61a6cc2a71dd2e3b126ff058cd5d045e.png" height="398" src="https://img-blog.csdnimg.cn/img_convert/61a6cc2a71dd2e3b126ff058cd5d045e.png" width="700"></p> <p>不过,与原始的Transformer Decoder相比,GPT所用的结构删除了Encoder-Decoder Attention,只保留了多头注意力层Multi-Head Attention层和前馈神经网络Feed forward层,最后再加上求和与归一化的前置LN层 + 残差<br> 通过这样的结构,GPT便可以利用无标注的自然语言数据进行训练:根据给定的前<img referrerpolicy="no-referrer" alt="i-1" class="mathcode" src="https://latex.codecogs.com/gif.latex?i-1">个token,预测第 <img referrerpolicy="no-referrer" alt="i" class="mathcode" src="https://latex.codecogs.com/gif.latex?i"> 个token,训练过程中使用的是基于最大似然估计的损失函数,即让模型预测的概率分布尽可能接近实际下一个单词的分布</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="318" src="https://img-blog.csdnimg.cn/img_convert/1831052632dbed6050771e49dd341516.png" width="700"></p> <p>其中的关键便是这个Self-Attention,模型通过自注意力机制可以学习序列中不同位置之间的依赖关系,即在处理每个位置的信息时,模型会考虑序列中<u>和该位置的信息有关联的其他所有位置上的信息</u>,这种机制使得模型能够有效地处理长距离依赖关系</p> <h3>2.1.2 什么是Self-Attention与Masked Self-Attention</h3> <p>所谓自注意力,即指当我们需要用到自注意力编码单词<img referrerpolicy="no-referrer" alt="X_1,X_2,X_3,X_4" class="mathcode" src="https://latex.codecogs.com/gif.latex?X_1%2CX_2%2CX_3%2CX_4">的时候,会按下面几个步骤依次处理(配图来自此文)</p> <ol> <li>为每个单词路径创建Query、Key、Value,具体做法就是每个单词的表示向量和对应的权重矩阵(<img referrerpolicy="no-referrer" alt="W^Q,W^K,W^V" class="mathcode" src="https://latex.codecogs.com/gif.latex?W%5EQ%2CW%5EK%2CW%5EV">)做矩阵乘法 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="383" src="https://img-blog.csdnimg.cn/452ba38d4bf44c7aafc14e44933e2239.png" width="700"></p> </li> <li>对于每个输入token,使用其Query向量对其他所有的token的Key向量进行评分,获得注意力分数,比如通过<img referrerpolicy="no-referrer" alt="X_1" class="mathcode" src="https://latex.codecogs.com/gif.latex?X_1">的<img referrerpolicy="no-referrer" alt="q_1" class="mathcode" src="https://latex.codecogs.com/gif.latex?q_1">向量,分别与<img referrerpolicy="no-referrer" alt="X_1,X_2,X_3,X_4" class="mathcode" src="https://latex.codecogs.com/gif.latex?X_1%2CX_2%2CX_3%2CX_4">的<img referrerpolicy="no-referrer" alt="k_1,k_2,k_3,k_4" class="mathcode" src="https://latex.codecogs.com/gif.latex?k_1%2Ck_2%2Ck_3%2Ck_4">向量分别做点乘,最终得到<img referrerpolicy="no-referrer" alt="X_1" class="mathcode" src="https://latex.codecogs.com/gif.latex?X_1">在各个单词<img referrerpolicy="no-referrer" alt="X_1,X_2,X_3,X_4" class="mathcode" src="https://latex.codecogs.com/gif.latex?X_1%2CX_2%2CX_3%2CX_4">上的注意力分数:20% 10% 50% 20% <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="388" src="https://img-blog.csdnimg.cn/a7ff56efd16a42999498d25db1751f1a.png" width="700"></p> </li> <li>将Value向量乘以上一步得到的注意力分数(相当于对当下单词而言,不同单词重要性的权重),之后加起来,从而获得所有token的加权和 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="381" src="https://img-blog.csdnimg.cn/3842d5cfc696477cac1cf9eb5136b4c1.png" width="700"></p> </li> </ol> <p>之后对每个token都进行上述同样的三步操作,最终会得到每个token新的表示向量,新向量中包含该token的上下文信息,之后再将这些数据传给Transformer组件的下一个子层:前馈神经网络</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="399" src="https://img-blog.csdnimg.cn/05b64b744bc74d828e0394a95ce4e487.png" width="700"></p> <p>至于所谓Masked Self-Attention就是在处理当前词的时候看不到后面的词。举个例子,处理“it”的时候,注意力机制看不到“it”后面的词(通过将“it”后面的词的权重设置为一个非常大的负数,进一步softmax之后变为0,从而屏蔽掉),但会关注到“it”前面词中的“a robot”,继而注意力会计算三个词“it”、“a”、“robot”的向量及其attention分数的加权和</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="388" src="https://img-blog.csdnimg.cn/img_convert/4f09155231abbc5ede08a1354f25c5a9.png" width="700"></p> <p>更多细节可以看下上篇BERT笔记(特别是此前还不了解Transformer的),或此文:图解注意力机制</p> <h2>2.2 GPT2承1启3:基于prompt尝试舍弃微调 直接Zero-shot Learning</h2> <p>虽然GPT1的预训练加微调的范式仅需要少量的微调和些许的架构改动,但能不能有一种模型完全不需要对下游任务进行适配就可以表现优异?GPT2便是在往这个方向努力:不微调但给模型一定的参考样例以帮助模型推断如何根据任务输入生成相应的任务输出</p> <p>最终,针对小样本/零样本的N-shot Learning应运而生,分为如下三种</p> <ul> <li>Zero-shot Learning (零样本学习),是指在没有任何样本/示例情况下,让预训练语言模型完成特定任务<br> 相当于不再使用二阶段训练模式(预训练+微调),而是彻底放弃了微调阶段,仅通过大规模多领域的数据预训练,让模型在Zero-shot Learming的设置下自己学会解决多任务的问题,而且效果还不错(虽然GPT2通过Zero-shot Learming在有些任务的表现上尚且还不如SOTA模型,但基本超越了一些简单模型,说明潜力巨大),你说神不神奇?<br><br> 这就好比以前我们刚开始学解题时,听老师讲了一系列知识和方法之后,老师为了让我们更好的解题,在正式答题考试之前,会先通过几个样题让我们找找感觉,方便在样题中微调或修正自己对所学知识/方法的理解<br> Zero-shot Learming则相当于没有练手/预热、<u>没有参考样例</u>/演示/范本,学完知识/方法之后直接答题!</li> <li>One shot Learning (单样本学习),顾名思义,是指在只有一个样本/示例的情况下,预训练语言模型完成特定任务</li> <li>Few-shot Learning (少样本或小样本学习),类似的,是指在只有少量样本/示例的情况下,预训练语言模型完成特定任务</li> </ul> <p>此外,只需将自然语言的任务示例和提示信息作为上下文输入给GPT-2,它就可以在小样本的情况下执行任何NLP任务,包括所谓的完形填空任务,比如</p> <blockquote> <p>假如我要判断“我喜欢这个电影" 这句话的情感(“正面" 或者 "负面"),原有的任务形式是把他看成一个分类问题</p> <p>输入:我喜欢这个电影</p> <p>输出:“正面" 或者 "负面"</p> <p></p> <p>而如果用GPT2去解决的话,任务可以变成“完形填空",</p> <p>输入:我喜欢这个电影,整体上来看,这是一个 __ 的电影</p> <p>输出:“有趣的" 或者 "无聊的"</p> </blockquote> <p>加的这句提示“<strong>整体上来看,这是一个 __ 的电影</strong>”对于让模型输出人类期望的输出有很大的帮助。</p> <p>这个所谓的提示用NLP的术语表达就是prompt,即给预训练语言模型的一个线索/提示,帮助它可以更好的理解人类的问题<br> 例如有人忘记了某篇古诗,我们给予特定的提示,他就可以想起来,例如当有人说:</p> <blockquote>白日依山尽 </blockquote> <p>大家自然而然地会想起来下一句诗:黄河入海流</p> <p>亦或者,搜索引擎,可以根据我们的输入,进行输出的提示:</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="393" src="https://img-blog.csdnimg.cn/7b9d2eca7b3548508e9cfa98acc8e371.png" width="700"></p> <h2>2.3 GPT3:In-context learning正式开启prompt新范式(小样本学习)</h2> <h3>2.3.1 GPT3在0样本、单样本、小样本下的突出能力</h3> <p>GPT3简单来说,就是规模大、有钱多金、效果出奇好,具体而言,它的参数规模达到了1750亿,并且使用45TB数据进行训练(当然,GPT3论文中说道:<span style="color:#7b7f82;"><em>constituting 45TB of compressed plaintext before filtering and 570GB after filtering, roughly equivalent to 400 billion byte-pair-encoded tokens</em></span>),其预训练任务就是“句子接龙”,给定前文持续预测下一个字,而且更为关键的是,在小样本的情况下,其性能表现一度超越SOTA模型</p> <p>为形象描述,举一个GPT3在0样本、单样本、少量样本下的机器翻译使用范例,如下图</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="b74c354d63fc4bb1bd8fa73b87739185.png" height="595" src="https://img-blog.csdnimg.cn/b74c354d63fc4bb1bd8fa73b87739185.png" width="700"></p> <ul> <li>图中右侧是普通模型微调的过程,模型通过大量训练预料进行训练,然后基于特定的任务数据进行梯度迭代更新(gradient update),训练至收敛后的模型才具备良好的翻译能力</li> <li>图中左侧是GPT3分别在0样本(只给出任务描述)、单样本(只给出任务描述+一个翻译样本)、小样本(给出任务描述+少量样本)的情况下所展示出的能力<br> 一方面,单样本也好 小样本也好,更多只是<strong>作为例子去提示模型,模型不利用样本做训练,即不做模型参数的任何更新</strong><br> 二方面,人们一度惊讶于其在0样本下如此强大的学习能力,使得很多人去研究背后的In Context Learning<br><br> 毕竟,我们知道普通模型微调的原理:拿一些例子当作微调阶段的训练数据,利用反向传播去修正LLM的模型参数,而修正模型参数这个动作,确实体现了LLM从这些例子学习的过程<br> 但是,In Context Learning只是拿出例子让LLM看了一眼,并没有根据例子,用反向传播去修正LLM模型参数的动作,就要求它去预测新例子<br><br> 此举意味着什么呢?<br> 1 既然没有修正模型参数,这意味着LLM并未经历一个修正过程,相当于所有的举一反三和推理/推断的能力在上一阶段预训练中便已具备(或许此举也导致参数规模越来越大),才使得模型在面对下游任务时 不用微调、不做梯度更新或参数更新,且换个角度讲,如此巨大规模的模型想微调参数其门槛也太高了<br> 2 预训练中 好的预训练数据非常重要,就好比让模型在0样本下翻译英语到法语,那预训练数据中 必然有大量英语、法语的文本数据<br> 3 抓什么样的数据 多大规模 怎么喂给模型等等一系列工程细节,这块是导致很多模型效果有差距的重要原因之一</li> </ul> <h3>2.3.2 In Context Learning(ICL)背后的玄机:隐式微调?</h3> <p>零样本下 模型没法通过样本去学习/修正,但即便是少样本下,也有工作试图证明In Context Learning并没有从样本中学习,比如“Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?”,它发现了:</p> <ol> <li>在提供给LLM的样本示例<img referrerpolicy="no-referrer" alt="<x_i,y_i>" class="mathcode" src="https://latex.codecogs.com/gif.latex?%3Cx_i%2Cy_i%3E">中,<img referrerpolicy="no-referrer" alt="y_i" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_i">是否是<img referrerpolicy="no-referrer" alt="x_i" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_i">对应的正确答案其实并不重要,如果我们把正确答案<img referrerpolicy="no-referrer" alt="y_i" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_i">替换成随机的另外一个答案 <img referrerpolicy="no-referrer" alt="y_j" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_j">,这并不影响In Context Learning的效果<br><br> 比如下图中,无论是分类任务(图中上部分),还是多项选择任务(图中下部分),随机标注设置下(红)模型表现均和正确标注(黄)表现相当,且明显超过没有in-context样本的zero-shot设置(蓝) <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="521" src="https://img-blog.csdnimg.cn/f9a531cf142446c9bb594d14bd9d9df0.png" width="700"></p> 这起码说明了一点:In Context Learning并没有提供给LLM那个从<img referrerpolicy="no-referrer" alt="x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">映射到 <img referrerpolicy="no-referrer" alt="y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y"> 的映射函数信息:<img referrerpolicy="no-referrer" alt="y=f(x)" class="mathcode" src="https://latex.codecogs.com/gif.latex?y%3Df%28x%29">,否则的话你乱换正确标签,肯定会扰乱这个 <img referrerpolicy="no-referrer" alt="y=f(x)" class="mathcode" src="https://latex.codecogs.com/gif.latex?y%3Df%28x%29">映射函数,也就是说,In Context Learning并未学习这个输入空间到输出空间的映射过程</li> <li>真正对In Context Learning影响比较大的是:<img referrerpolicy="no-referrer" alt="x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">和<img referrerpolicy="no-referrer" alt="y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y">的分布,也就是输入文本 <img referrerpolicy="no-referrer" alt="x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x"> 的分布和候选答案 <img referrerpolicy="no-referrer" alt="y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y"> 有哪些,如果你改变这两个分布,比如把 <img referrerpolicy="no-referrer" alt="y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y"> 替换成候选答案之外的内容,则In Context Learning效果急剧下降<br> 总之,<strong>这个工作证明了In Context Learning并未学习映射函数,但是输入和输出的分布很重要</strong>,这两个不能乱改(此部分 待后续23年5月份进一步补充完善)</li> </ol> <p>有些工作认为LLM还是从给出的示例学习了这个映射函数<img referrerpolicy="no-referrer" alt="y=f(x)" class="mathcode" src="https://latex.codecogs.com/gif.latex?y%3Df%28x%29">,不过是种隐式地学习</p> <ul> <li>比如“What learning algorithm is in-context learning? Investigations with linear models”认为Transformer能够隐式地从示例中学习 <img referrerpolicy="no-referrer" alt="x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x"> 到 <img referrerpolicy="no-referrer" alt="y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y"> 的映射过程,它的激活函数中包含了一些简单映射函数,而LLM通过示例能够激发对应的那一个</li> <li>而“Why Can GPT Learn In-Context? Language Models Secretly Perform Gradient Descent as Meta-Optimizers”这篇文章则将ICL看作是一种隐式的Fine-tuning</li> </ul> <h2>2.4 Prompt技术的升级与创新:指令微调技术(IFT)与思维链技术(CoT)</h2> <h3>2.4.1 Google提出FLAN大模型:基于指令微调技术Instruction Fine-Tuning (IFT)</h3> <p>OpenAI的GPT3虽然不再微调模型(pre-training + prompt),但Google依然坚持预训练 + 微调的模式</p> <p>2021年9月,谷歌的研究者们在此篇论文中《Finetuned Language Models Are Zero-Shot Learners》提出了基于<strong>Instruction Fine-Tuning</strong>(指令微调,简称IFT)的FLAN大模型(参数规模为137B),极大地提升了大语言模型的理解能力与多任务能力,且<strong>其在评估的25个数据集中有20个数据集的零样本学习能力超过175B版本的GPT3</strong>(毕竟指令微调的目标之一即是致力于improving zero-shot generalization to tasks that were not seen in training),最终达到的效果就是:遵循人类指令,举一反三地完成任务</p> <p>有两点值得注意的是</p> <ol> <li>根据论文中的这句话:“FLAN is the instruction-tuned version of LaMDA-PT”,可知指令微调的是LaMDA,而LaMDA是Google在21年5月对外宣布内部正在研发的对话模型(不过,LaMDA的论文直到22年1月才发布)</li> <li>论文中也解释了取名为FLAN的缘由 <p>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.</p> <p>We refer to this resulting model as FLAN, for <strong><u>F</u></strong>inetuned <strong><u>La</u></strong>nguage <u><strong>N</strong></u>et</p> </li> </ol> <p>至于IFT的数据通常是由人工手写指令和语言模型引导的指令实例的集合,这些指令数据由三个主要组成部分组成:指令、输入和输出,对于给定的指令,可以有多个输入和输出实例</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="141" src="https://img-blog.csdnimg.cn/05d74bcd64944f7c87902bd59f12ea1d.png" width="700"></p> <p>相比于GPT-3,且区别在于Finetune,FLAN的核心思想是,当面对给定的任务A时,首先将模型在大量的其他不同类型的任务比如B、C、D...上进行微调,微调的方式是将任务的指令与数据进行拼接(可以理解为一种Prompt),随后给出任务A的指令,直接进行推断,如下图所示</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="232" src="https://img-blog.csdnimg.cn/8df866b5d7d4486eb8e5ab9f5ad56191.png" width="700"></p> <p>例如,我们的最终目标是推理任务</p> <ol> <li>FLAN首先讲语言模型在其他任务上进行微调,包括给定任务指令的翻译、常识推理、情感分类等<br> 在面对翻译任务时可以给出指令“请把这句话翻译成西班牙语”<br> 在面对常识推理任务时可以给出指令“请预测下面可能发生的情况”</li> <li>而当模型根据这些“指令”完成了微调阶段的各种任务后(将指令拼接在微调数据的前面),在面对从未见过的自然语言推理任务的指令比如:“这段话能从假设中推导出来吗?” 时,就能更好地调动出已有的知识回答问题 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="292" src="https://img-blog.csdnimg.cn/f16b9ac94a7c474891c1b73246afd85f.png" width="700"></p> </li> </ol> <p>相当于通过指令微调之后,模型可以更好的做之前预训练时没见过的新任务且降低了对prompt的敏感度(某些场景下不一定非得设计特定prompt才能激发模型更好的回答)</p> <p>这或许也启发了OpenAI重新注意到了微调这一模式(毕竟如上文所述,<span style="color:#ed7976;">原本GPT3在预训练之后已彻底放弃再微调模型</span>),从而在InstructGPT中针对GPT3做Supervised fine-tuning(简称SFT)</p> <h3>2.4.2 关于PL的进一步总结:到底如何理解prompt learning</h3> <p>自此,总结一下,关于「prompt learning」最简单粗暴的理解,其实就是让模型逐步学会人类的各种自然指令或人话,而不用根据下游任务去微调模型或更改模型的参数,直接根据人类的指令直接干活,这个指令就是prompt,而设计好的prompt很关键 也需要很多技巧,是一个不算特别小的工程,所以叫prompt engineering,再进一步,对于技术侧 这里面还有一些细微的细节</p> <blockquote> <ol> <li> <p>GPT3 出来之前(2020年之前),模型基本都是预训练 + 微调,比如GPT1和BERT</p> </li> <li> <p>GPT3刚出来的时候,可以只预训练 不微调,让模型直接学习人类指令直接干活 即prompt learning,之所以可以做到如此 是因为GPT3 当时具备了零样本或少样本学习能力<br> 当然,说是说只预训练 不微调,我个人觉得还是微调了的,只是如上文所说的某种隐式微调而已</p> </li> <li> <p>2021年,Google发现微调下GPT3后 比OpenAI不微调GPT3在零样本上的学习能力更加强大<br> 从而现在又重新回归:预训练之后 再根据下游任务微调的模式,最后封装给用户,客户去prompt模型</p> <p><br> 所以现在的prompt learning更多针对的是 去提示/prompt:<strong>已具备零样本学习能力的且还做了进一步微调的GPT3.5/GPT4</strong><br> (<span style="color:#7b7f82;">怎么微调呢,比如很快下文你会看到的SFT和RLHF,当然 也可以不做微调,比如后来Meta发布的类ChatGPT模型LLaMA本身便没咋做微调,虽它刚发布时比不上GPT3.5/4之类的,但其核心意义在于13B通过更多数据训练之后 在很多任务上可以强过175B的GPT3</span>)</p> <p>再之后,就出来了很多个基于LLaMA微调的各种开源模型(这块可以查看本文开头所列的:类ChatGPT的部署与微调系列文章)</p> </li> </ol> </blockquote> <h3>2.4.3 基于思维链(Chain-of-thought)技术下的prompt</h3> <p>为让大语言模型进一步具备解决数学推理问题的能力,22年1月,谷歌大脑团队的Jason Wei、Xuezhi Wang等人提出了最新的Prompting机制——Chain of Thought(简称CoT),简言之就是给模型推理步骤的prompt,让其学习人类如何一步步思考/推理,从而让模型具备基本的推理能力,最终可以求解一些简单甚至相对复杂的数学推理能力</p> <p>以下是一个示例(下图左侧为standard prompting,下图右侧为基于Cot的prompt,高亮部分为chain-of-thought),模型在引入基于Cot技术的prompt的引导下,一步一步算出了正确答案,有没有一种眼前一亮的感觉?相当于模型具备了逻辑推理能力</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="352" src="https://img-blog.csdnimg.cn/c93a2597c53240dabdafb2b99f12051d.png" width="700"></p> <p>那效果如何呢,作者对比了标准prompting、基于Cot技术的prompting分别在这三个大语言模型LaMDA、GPT、PaLM(除了GPT由openAI发布,另外两个均由Google发布)上的测试结果,测试发现:具有540B参数的PaLM模型可以在一个代表小学水平的数学推理问题集GSM8K(GSM8K最初由OpenAI于2021年10月提出)上的准确率达到了60.1%左右</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="446" src="https://img-blog.csdnimg.cn/a9e3250b63ed40a38ee96d14eaf7635f.png" width="700"></p> <p>很快,这项技术引起了很多人的关注,比如不论是few-shot还是zero-shot,在加入Cot技术之后,都能回答此前不能回答的某些数学推理问题,甚至出现了风靡一时的“let's think step by step”的梗(通过该条语句可以激发模型的推理能力)</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="366" src="https://img-blog.csdnimg.cn/029ac3d1134a474abd060e48d838a049.png" width="700"></p> <h2>2.5 GPT3到GPT3.5:从InstructGPT到ChatGPT初版的迭代过程</h2> <p>据OpenAI官网对GPT3.5的介绍,<strong>GPT3.5从2021年第四季度开始</strong>就混合使用文本和代码进行训练,我们来看下GPT3.5的各个系列模型及其各自的发展演变脉络图</p> <p><strong>基于GPT3的发展路线:一条是侧重代码/推理的Codex,一条侧重理解人类的instructGPT</strong></p> <ul> <li> <u>第一条线:为了具备代码/推理能力:GPT3 + 代码训练 = Codex</u><br> 2020 年5-6月,OpenAI先后发布了<br> GPT3的论文《Language Models are Few-Shot Learners》<br> GPT-3的最大规模的版本——175B(1750亿参数)大小的API Davinci(有着2048个词的上下文窗口),此时的GPT3还只能写一些简单的代码和做一些简单的数学题<br><br> 2021 年7月,OpenAI发布Codex的论文《Evaluating Large Language Models Trained on Code》,其中初始的Codex是根据120亿参数的GPT-3变体进行微调的,且通过对159GB的Python代码进行代码训练<br> 后来这个120 亿参数的模型演变成OpenAI API中的code-cushman-001,具备较强的代码/推理能力<br><br> 代码能力好理解,通过大量的代码训练,但其推理能力是如何获取到的呢,其中关键在于很多代码是为了解决数学推理问题,训练中可以用『类似后续22年年初Google一些研究者定义的CoT技术』获取推理能力,当然,此时文本上的能力尚且偏弱</li> <li> <u>第二条线:为了更好理解人类:GPT3 + 指令学习 + RLHF = instructGPT</u><br> 上文第一部分已经提到过,根据OpenAI的这篇论文《Learning to summarize with human feedback (Stiennon et al., 2020)》可知,2020年openAI便再研究GPT3与RLHF的结合了,但此时还是会经常一本正经的胡说八道,且很容易输出负面甚至带有危害的内容(毕竟人类言论中存在不少不友好的言论)<br><br> 在OpenAI于2021年彻底加强Codex之后,终于有时间解决模型与人类对话的问题了,于是在2022年3月,OpenAI发布遵循人类指令学习的论文(指令学习可以认为就是指令微调instruct tuning):Training language models to follow instructions with human feedback,这就是instructGPT,且把RLHF用得更好了<br> 其核心API就是instruct-davinci-beta和text-davinci-001(当然,文本上的能力不错但代码/推理上的能力偏弱) <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="420" src="https://img-blog.csdnimg.cn/1133d2956f234040a30fa4278e2734d0.png" width="700"></p> </li> </ul> <p><strong>基于GPT3.5的发展路线:增强代码/推理能力且更懂人类终于迭代出ChatGPT</strong></p> <ul> <li> <u>首先,融合代码/推理与理解人类的能力,且基于code-cushman-002迭代出text-davinci-002</u><br> 2022年4月至7月,OpenAI开始对code-davinci-002(有着8192个token的上下文窗口)模型进行Beta测试,也称其为Codex(当配备完善的思维链时,其在GSM8K等数学测试数据上的表现十分优异)<br> 2022 年5-6月发布的text-davinci-002是一个基于code-davinci-002的有监督指令微调(即在code-davinci-002基础上加入supervised instruction tuning) 模型<br> 在text-davinci-002上面进行指令微调很可能降低了模型的上下文学习能力,但是增强了模型的零样本能力(更懂人类)</li> <li> <u>其次,为了进一步理解人类:text-davinci-002 + RLHF = text-davinci-003/ChatGPT</u><br> text-davinci-003、ChatGPT都是基于text-davinci-002基础上改进的基于人类反馈的强化学习的指令微调模型 (instruction tuning with reinforcement learning from human feedback)<br><br> text-davinci-003恢复了一些在text-davinci-002中丢失的部分上下文学习能力(比如在微调的时候混入了语言建模) 并进一步改进了零样本能力(得益于RLHF,生成更加符合人类期待的反馈或者说模型与人类对齐)<br><br> 至于ChatGPT则更不用说了,其对应的API为<strong>gpt-3.5-turbo</strong>(由23年3.2日OpenAI最新发布)<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 代码/推理能力强大,考虑到Codex学习了大量的开源代码,由此是不也能理解为何ChatGPT具备那么强大的编码及debug能力了,且训练代码中包含不少解决数学问题的代码,加上对代码注释的学习(基于一些代码和代码描述的样式/范例使用类似CoT这样的技术学习),是不是也就能学会代码背后的推理能力呢<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 而且理解人类的能力前所未有</li> </ul> <h2>2.6 ChatGPT初版与InstructGPT的差别:基于GPT3还是GPT3.5微调</h2> <p>通过OpenAI公布的ChatGPT训练图可知,ChatGPT的训练流程与InstructGPT是一致的,差异只在于</p> <ul> <li>InstructGPT(有1.3B 6B 175B参数的版本,这个细节你马上会再看到的),是在GPT-3(原始的GPT3有1.3B 2.7B 6.7B 13B 175B等8个参数大小的版本)上做Fine-Tune</li> <li>22年11月份的初版ChatGPT是在GPT-3.5上做Fine-Tune <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="450" src="https://img-blog.csdnimg.cn/725f34d9c6654c8983dcda50148b1f02.png" width="800"></p> </li> </ul> <h2>2.7 基于GPT4的ChatGPT改进版:新增多模态技术能力</h2> <p>23年3月14日(国内3.15凌晨),OpenAI正式对外发布自从22年8月份便开始训练的GPT4,之前订阅ChatGPT plus版的可以直接体验GPT4</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="393" src="https://img-blog.csdnimg.cn/6f3b99c974224ad48bc9f5ebbe6929e0.png" width="700"></p> <p>根据OpenAI官网发布的《GPT-4 Technical Report》可知 </p> <ol> <li>gpt-4 has a context length of 8,192 tokens. We are also providing limited access to our 32,768–context (about 50 pages of text,约25000个字) version</li> <li>GPT-4经过预训练之后,再通过RLHF的方法微调(具体怎么微调,下文第三部分详述)<br> “GPT-4 is a Transformer-style model pre-trained to predict the next token in a document, using both publicly available data (such as internet data) and data licensed from third-party providers. The model was then fine-tuned using Reinforcement Learning from Human Feedback (RLHF)”<br><br> RLHF的作用在于<br> 对于某些特定任务,The GPT-4 base model is only slightly better at this task than GPT-3.5; however, after RLHF post-training we observe large improvements over GPT-3.5 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="367" src="https://img-blog.csdnimg.cn/74ab07c2395c4bc08c5bab772095ee99.png" width="700"></p> </li> <li>RLHF之外,为了进一步让模型输出安全的回答,过程中还提出了<span style="color:#000000;">基于规则的奖励模型</span>RBRMs(<span style="color:#000000;">rule-based reward models),奖励规则由人编写</span><br> RBRMs<span style="color:#000000;">相当于是零样本下GPT-4的决策依据或者分类器<br> 这些分类器在RLHF微调期间为GPT-4策略模型提供了额外的奖励信号,以生成正确回答为目标,从而拒绝生成有害内容,说白了,额外增加RBRMs就是为了让模型的输出更安全(且合理拒答的同时避免误杀,比如下面第二个图所示的例子:寻找cigarettes)</span> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="255" src="https://img-blog.csdnimg.cn/974beb9bee394f0794c56d52de02d25e.png" width="700"></p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="370" src="https://img-blog.csdnimg.cn/dc30db988ae045d993f1584713592e75.png" width="700"></p> </li> <li>经过测试,GPT4在遵循人类指令上表现的更好(同样指令下,输出更符合人类预期的回答),且在常识性推理、解题等多项任务上的表现均超过GPT3和对应的SOTA</li> <li>具备了多模态的能力,可以接受图片形式的输入(图片输入接口暂未开放),并按指令读图 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="778" src="https://img-blog.csdnimg.cn/e16c9c6245ec496bb23e2f2d3862019f.png" width="700"></p> </li> </ol> <p>此外,通过GPT4的技术报告第60页可知,其训练方式和基于GPT3的instructGPT或基于GPT3.5的ChatGPT初版的训练方式如出一辙</p> <blockquote> <p>先收集数据</p> <ul> <li>一部分是人工标注问题-答案对:We collect <strong><em>demonstration data</em></strong> (given an input, demonstrating how the model should respond)</li> <li>一部分是基于人类偏好对模型输出的多个答案进行排序的数据:<em><strong>ranking data</strong></em> on outputs from our models (given an input and several outputs, rank the outputs from best to worst) from human trainers</li> </ul> <p>接下来三个步骤(具体下文第三部分详述)</p> <ol> <li>通过人工标注的数据(问题-答案对)监督微调GPT4<br> We use the demonstration data to finetune GPT-4 using supervised learning (SFT) to imitate the behavior in the demonstrations.</li> <li>通过对模型多个回答进行人工排序的数据训练一个奖励模型,这个奖励模型相当于是模型输出好坏的裁判<br> We use the ranking data to train a reward model (RM), which predicts the average labeler’s preference for a given output</li> <li>通过最大化奖励函数的目标下,通过PPO算法继续微调GPT4模型<br> and use this signal as a reward to fine-tune the GPT-4 SFT model using reinforcement learning (specifically, the PPO algorithm)</li> </ol> </blockquote> <p>至于GPT4背后多模态的能力起源与发展历史,请参见:AI绘画能力的起源:通俗理解VAE、扩散模型DDPM、DETR、ViT/Swin transformer,而下篇《AIGC下的CV多模态原理解析:从CLIP/BLIP到stable diffusion/Midjourney、GPT4》待6月中旬发布</p> <h1>第三部分 InstructGPT/ChatGPT训练三阶段及多轮对话能力</h1> <h2>3.1 基于GPT3的InstructGPT训练三阶段</h2> <h3>3.1.0 ChatGPT初版的前身之InstructGPT:<strong>基于</strong>RLHF手段微调的GPT</h3> <p>根据InstructGPT的原始论文可知,InstructGPT的训练分为三个阶段(<span style="color:#7b7f82;">有监督微调“经过无监督预训练好的GPT3”、然后基于人类偏好排序的数据训练一个奖励模型、最终在最大化奖励的目标下通过PPO算法来优化策略</span>):</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="475" src="https://img-blog.csdnimg.cn/72a8c7c487864a4e9444036411dc93c3.png" width="800"></p> <ol> <li> <p><strong>阶段1:利用人类的问答数据去对GPT3进行有监督训练出SFT模型(作为baseline)</strong><br> 首先,OpenAI是先设计了一个prompt dataset,里面有大量的提示样本,给出了各种各样的任务描述,其次,找了一个团队对这个prompt dataset进行标注(本质就是人工回答问题)</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="188" src="https://img-blog.csdnimg.cn/8212f02b257a47c98709297e1e812040.png" width="600"></p> <p>最后,用这个来自OpenAI API和labeler-written的<span style="color:#4da8ee;">13k</span>大小的标注好的数据集(<strong>问题-答案对</strong>)比如<img referrerpolicy="no-referrer" alt="<x_1,y_1>,<x_2,y_2>,<x_3,y_3>\cdots <x_n,y_n>" class="mathcode" src="https://latex.codecogs.com/gif.latex?%3Cx_1%2Cy_1%3E%2C%3Cx_2%2Cy_2%3E%2C%3Cx_3%2Cy_3%3E%5Ccdots%20%3Cx_n%2Cy_n%3E">微调GPT3(trained for 16 epochs, 使用余弦学习率衰减, and residual dropout of 0.2),这个微调好的GPT3我们称之为SFT模型(SFT的全称Supervised fine-tuning,监督微调之意),它作为baseline具备了最基本的预测能力(该基线模型的大小为<span style="color:#ed7976;">175B</span>)</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="153" src="https://img-blog.csdnimg.cn/f9a13aaa56734561abc7b630bec89028.png" width="700"></p> <p><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 说白了,让人类就一些问题写出人工答案,再把这些问题和答案丢给模型学习,这便是有监督训练,但人类不可能针对所有问题都写出答案给到模型(如果人类能把所有问题都标注/回答了,那还要模型干嘛,^_^)<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 所以我们需要让模型学到人类的喜爱偏好(训练出一个RM模型代替人类当裁判,避免让实验人员守在电脑前对模型吐出来的结果不停地打分)<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 继而在遵循这种喜爱偏好下生成人类期待的答案,想达到这个效果就是得让模型明确什么是更好的输出,怎么明确?通过奖惩! </p> </li> <li> <p><strong>阶段2:通过RLHF的思路训练一个奖励模型RM</strong><br> 首先通过『移除了最后一层unembedding layer的上一阶段的SFT模型』初始化出我们的RM模型,考虑到175B计算量大且不稳定不适合作为奖励函数,故最后大小缩减到<span style="color:#ed7976;">6B</span><br> 然后回答来自OpenAI API和labeler-written且规模大小为<span style="color:#4da8ee;">33k</span>的数据集的一些问题比如<img referrerpolicy="no-referrer" alt="x_{n+1}" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bn&plus;1%7D">,接着针对每个问题收集4个不同的输出从而获取4个回答<img referrerpolicy="no-referrer" alt="<y_{n+1}^{1},y_{n+1}^{2},y_{n+1}^{3},y_{n+1}^{4}>" class="mathcode" src="https://latex.codecogs.com/gif.latex?%3Cy_%7Bn&plus;1%7D%5E%7B1%7D%2Cy_%7Bn&plus;1%7D%5E%7B2%7D%2Cy_%7Bn&plus;1%7D%5E%7B3%7D%2Cy_%7Bn&plus;1%7D%5E%7B4%7D%3E"><br> 可能有的读者会疑问为何有多个输出,原因在于模型每次预测一个词都有对应的概率,根据不同的概率大小可以采样出很多答案,比如通过beam search保留k个当前最优的答案(beam search相当于贪心算法的加强版,除了最好的答案外,还会保留多个比较好的答案供选择)<br><br> 接着人工对这4个回答的好坏进行标注且排序,排序的结果用来训练一个奖励模型RM,具体做法就是学习排序结果从而理解人类的偏好『<span style="color:#7b7f82;">顺带提一嘴,如论文第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,最终选择一个最优的</span>』<br> 但通过人来标注/排序的结果训练出奖励模型之后怎么用呢,这就是训练阶段3要做的事情</p> </li> <li> <p><strong>阶段3:通过训练好的RM模型预测结果且通过PPO算法优化模型策略</strong><br><strong>首先</strong>,让第一阶段微调好的SFT模型初始化出一个PPO模型<br> 通过instructGPT论文第56页得知,experimented with a few variants of the SFT models as the PPO’s init model,即PPO模型有多个大小的版本,比如<span style="color:#ed7976;">1.3B 6B 175B</span>(可理解为带着RL且初始版本为SFT的模型)<br><strong>然后</strong>,去回答仅来自OpenAI API不带人类任何标注的且规模大小为<span style="color:#4da8ee;">31k</span>的一些问题比如<img referrerpolicy="no-referrer" alt="x_{n+2}" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bn&plus;2%7D"><br> 此时不再让人工评估好坏,而是让阶段2训练好的奖励模型RM去给PPO模型的预测结果比如<img referrerpolicy="no-referrer" alt="<y_{n+2}^{1},y_{n+2}^{2},y_{n+2}^{3},y_{n+2}^{4}>" class="mathcode" src="https://latex.codecogs.com/gif.latex?%3Cy_%7Bn&plus;2%7D%5E%7B1%7D%2Cy_%7Bn&plus;2%7D%5E%7B2%7D%2Cy_%7Bn&plus;2%7D%5E%7B3%7D%2Cy_%7Bn&plus;2%7D%5E%7B4%7D%3E">进行打分进而排序(看是否优质,比如是否迎合人类偏好)<br><strong>之后</strong>,通过不断更大化奖励而优化PPO模型的生成策略(因为生成策略更好,模型的回答便会更好),策略优化的过程中使用PPO算法限制策略更新范围<br><strong>最后</strong>,根据优化后的策略再次生成 <img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> RM再评估 <img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow">模型再优化后再生成,如此循环进行,直到策略最优为止<br><br> 最终效果还不错,哪怕是1.3B的PPO模型的效果也要比175B的SFT、175B的GPT3的效果都要更好</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="386" src="https://img-blog.csdnimg.cn/c9e1b0266bc14700a3f9c252126a7df0.png" width="700"></p> <p>当然 这三步下来,比如第一轮迭代出一个相对最优的策略后,后面某个时间段 比如第二轮是可以再次通过新一批人类排序的数据训练一个新的RM,然后再迭代出一个当下最优的策略</p> <hr> <p>此外,如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 <span style="color:#7b7f82;">175B SFT model requires 4.9 petaflops/s-days</span> and training our <span style="color:#7b7f82;">175B PPO-ptx model requires 60 petaflops/s-days</span>,compared to <span style="color:#7b7f82;">3,640 petaflops/s-days for GPT-3</span> (Brown et al., 2020),且如论文第40页所说,所有模型都是用的Adam优化器训练,β1= 0.9和β2= 0.95</p> </li> </ol> <p>另 值得一提的是,上文反复提到策略,那怎么理解这个经常在RL中出现的“策略”呢,举几个例子</p> <ul> <li>类似于一个人做事如果有好的策略或方法论,他便能有更好的行为或效率,从而把事情做更好</li> <li>再比如一家公司如果有好的经营策略,这家公司便能有更好的经营结果,从而取得更好的业绩</li> <li>对于模型也是一样的,如果它有更好的生成策略,它便能给人类提供更好的回答</li> </ul> <p>此外,可能有读者疑问,InstructGPT使用RLHF的思路,只是为了训练出一个奖励函数么?事实上,还有额外多方面的用途</p> <ol> <li>一方面是为了让GPT的输出与对用户的友好度上尽可能地对齐(Alignment),即微调出一个用户友好型GPT<br> 以往的GPT训练,都是基于大量无标注的语料,这些语料通常收集自充斥大量“行话”、“黑话”的互联网中,这样训练出来的语言模型,它可能会有虚假的、恶意的或者有负面情绪等问题的输出</li> <li>二方面,为了更好的理解人类的意图</li> </ol> <p>因此,通过人工干预微调GPT,使其输出对用户友好(避免乱说话),且更好的和人类对话,所以,对InstructGPT的简单理解,可以是<em>基于人类偏好的深度强化学习</em>(RLHF)手段微调的GPT。</p> <p>接下来,我们分别具体阐述上面的阶段1、阶段2、阶段3。</p> <h3>3.1.1 InstructGPT训练阶段1:针对预训练后的GPT3进行监督微调</h3> <p>阶段1的本质就是使用监督学习方法对GPT-3模型进行微调(回归到预训练-微调模式),具体使用labeler demonstrations作为训练数据,具体微调过程中</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="230" src="https://img-blog.csdnimg.cn/93f758832a8345788e79da7935a344ba.png" width="851"></p> <ol> <li>进行了16个周期(epochs)的训练<br> 一个周期指的是在整个训练数据集上进行一次完整的前向和反向传播</li> <li>采用了余弦学习率衰减策略<br> 这是一种调整学习率的方法(学习率是一个调整模型权重更新速度的超参数),使其在训练过程中逐渐减小,有助于模型在后期训练中更好地收敛</li> <li>残差丢弃率(residual dropout)为0.2<br> 这是一种正则化技术,有助于防止模型过拟合,在训练过程中,丢弃率决定了神经元被随机关闭的概率</li> </ol> <h3>3.1.2 InstructGPT训练阶段2:如何对多个输出排序及如何训练RM模型</h3> <p>训练RM的核心是由人类对SFT生成的多个输出(基于同一个输入)进行排序,再用来训练RM。按照模仿学习的定义,直观上的理解可以是,RM在模仿人类对回答语句的排序思路。</p> <p>为了更具体的说明,我们代入一个场景,假设你向一个六岁小孩解释什么是登陆月球或什么是RL,如下图</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="862" src="https://img-blog.csdnimg.cn/79bc702fdf3542a8a9e5b8b89d7a9986.png" width="470"></p> <ol> <li>SFT生成了 <em>A、B、C、D </em>四个回答语句,然后人类对照着Prompt输入(即提问)来对4个回答的好坏做出合适的排序,如<img referrerpolicy="no-referrer" alt="D>C>A=B" class="mathcode" src="https://latex.codecogs.com/gif.latex?D%3EC%3EA%3DB"> </li> <li>为了让RM学到人类偏好(即排序),可以4个语句两两组合分别计算loss再相加取均值,即分别计算<img referrerpolicy="no-referrer" alt="gif.latex?C_%7B4%7D%5E%7B2%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?C_%7B4%7D%5E%7B2%7D">个即6个loss,具体的loss形式如下图: <p class="img-center"><img referrerpolicy="no-referrer" alt="gif.latex?%5Ctext%7Bloss%7D%28%5Ctheta%29%3D-%5Cfrac%7B1%7D%7B%20%28_%7B2%7D%5E%7BK%7D%5Ctextrm%7B%7D%29%20%7DE_%7B%28x%2Cy_w%2Cy_l%29%5Csim%20D%7D%5B%5Clog%28%5Csigma%28r_%5Ctheta%28x%2Cy_w%29-r_%5Ctheta%28x%2Cy_l%29%29%29%5D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctext%7Bloss%7D%28%5Ctheta%29%3D-%5Cfrac%7B1%7D%7B%20%28_%7B2%7D%5E%7BK%7D%5Ctextrm%7B%7D%29%20%7DE_%7B%28x%2Cy_w%2Cy_l%29%5Csim%20D%7D%5B%5Clog%28%5Csigma%28r_%5Ctheta%28x%2Cy_w%29-r_%5Ctheta%28x%2Cy_l%29%29%29%5D"></p> </li> </ol> <p>针对这个损失函数需要逐一说明的是</p> <ol> <li>这是一个常见的排序模型, <img referrerpolicy="no-referrer" alt="r_\theta (x,y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%5Ctheta%20%28x%2Cy%29">是RM模型,其中<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> <img referrerpolicy="no-referrer" alt="gif.latex?x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">是提示Prompt输入,实际训练中,使用的批量大小(batch size)为 64,表示每个批次中独立提示(prompts)的数量<br><img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> <img referrerpolicy="no-referrer" alt="gif.latex?y" class="mathcode" src="https://latex.codecogs.com/gif.latex?y">是SFT的预测输出(比如<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bw%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bw%7D">/<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bl%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bl%7D">),相当于针对每个prompt 随机生成<img referrerpolicy="no-referrer" alt="K" class="mathcode" src="https://latex.codecogs.com/gif.latex?K">个输出(<img referrerpolicy="no-referrer" alt="4\leq K \leq 9" class="mathcode" src="https://latex.codecogs.com/gif.latex?4%5Cleq%20K%20%5Cleq%209">),然后针对<img referrerpolicy="no-referrer" alt="K" class="mathcode" src="https://latex.codecogs.com/gif.latex?K">个输出做<img referrerpolicy="no-referrer" alt="gif.latex?%28_%7B2%7D%5E%7BK%7D%5Ctextrm%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?%28_%7B2%7D%5E%7BK%7D%5Ctextrm%29">次比较,比如4个输出有6次比较,9个输出有36次比较<br><img referrerpolicy="no-referrer" alt="gif.latex?D" class="mathcode" src="https://latex.codecogs.com/gif.latex?D">是人类比较的数据集<br><br> 有一点要提下的是,RLHF中的rank就好比监督学习中的弱标注——它并不提供直接的监督信号。但通过学习简单的排序,RM可以学到人类的偏好<br> 为何是排序,而非直接打分呢,道理很简单,排序相比打分更容易接近客观事实,即不同的标注员,打分的偏好会有很大的差异(比如同样一段精彩的文本,有人认为可以打1.0,但有人认为只能打0.8),而这种差异就会导致出现大量的噪声样本,若改成排序,则不同标注员的排序一致性相比打分一致性就大大提升了</li> <li>首先把你的问题<img referrerpolicy="no-referrer" alt="gif.latex?x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">和答案<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bw%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bw%7D">放进奖励函数<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D">中,再把问题<img referrerpolicy="no-referrer" alt="gif.latex?x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">和<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bl%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bl%7D">也放进奖励函数<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D">中,然后分别输出,假定<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bw%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bw%7D">是语句组合对中相对<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bl%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bl%7D">排序更高的,所以两者一减『这里面使用的是排序损失函数(即Pairwise ranking loss),<u>奖励的差异表示一种应答比另一种应答更受人类标注者青睐的对数概率</u>』,我们希望相减的结果越大越好</li> <li>最后通过Logitech函数变成一个loss函数,而因为loss函数最前面加了一个负号,相当于最大化上面第2点最后相减的结果<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D">(<img referrerpolicy="no-referrer" alt="gif.latex?x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">,<img referrerpolicy="no-referrer" alt="gif.latex?y_%7Bw%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_%7Bw%7D">) − <img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D"> (<img referrerpolicy="no-referrer" alt="gif.latex?x" class="mathcode" src="https://latex.codecogs.com/gif.latex?x">,<img referrerpolicy="no-referrer" alt="y_l" class="mathcode" src="https://latex.codecogs.com/gif.latex?y_l">)等于是最小化这个loss函数</li> </ol> <p>值得一提的是,通过在训练集上进行了一个周期(epoch)的训练,选择了学习率(lr)为 9e-6,且采用余弦学习率调度策略,在训练结束时,学习率降低至初始值的10%。</p> <p>最终,通过这种形式的梯度回传,RM逐渐学会了给D这类语句以高排名甚至打出一个高分,给A、B以低排名甚至打出一个低分,从而模仿到了人类偏好。到了这一步,不妨可以这么简单理解RLHF:所谓的<em>基于人类偏好的深度强化学习</em>,某种意义上来说,就是由人类的偏好来充当reward</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="1b37ed859770ba388d86273e3c7c6517.png" height="453" src="https://img-blog.csdnimg.cn/img_convert/1b37ed859770ba388d86273e3c7c6517.png" width="600"></p> <h3>3.1.3 InstructGPT训练阶段3:如何通过PPO算法进一步优化模型的策略</h3> <p>简而言之,阶段3可以用下图形象化表示</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="78055db0e39e623f2e2b7b4efa4b3593.png" height="512" src="https://img-blog.csdnimg.cn/img_convert/78055db0e39e623f2e2b7b4efa4b3593.png" width="600"></p> <p>具体而言,instructGPT原始论文中的目标函数如下所示</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="126" src="https://img-blog.csdnimg.cn/3bec8b5062e6439f993962b621da0d3e.png" width="800"></p> <p>InstructGPT这篇论文吧,对大家实在是太友好了,友好到全篇论文就只给了两个公式(奖励函数的损失函数以及上面这个目标函数),关键这两个公式都还只是简写,针对<img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">这个目标函数在和交大张老师及七月在线赵、倪等老师核对之后,发现实际中真正要算的时候,需要先如下展开下(马上还有二次展开)</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} objective(\phi ) &= E_{(x,y)\sim D_{\pi _{\phi }^{RL}}} [r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \\&= E_{(x,y)\sim D_{\pi _{ }^{RL'}}} [\frac{\pi _{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)}r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \end{aligned}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20objective%28%5Cphi%20%29%20%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%7D%7D%20%5Br_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5C%5C%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%20%7D%5E%7BRL%27%7D%7D%7D%20%5B%5Cfrac%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7Dr_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5Cend%7Baligned%7D"></p> <p><img referrerpolicy="no-referrer" alt="\pi ^{SFT}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D">是基线策略,<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D">是『新策略<img referrerpolicy="no-referrer" alt="\pi _{\phi }^{RL}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D">』更新之前的旧策略,为何呢?考虑到大部分文章在分析上面的目标函数时基本都是人云亦云、一带而过,故再逐一拆接下这个目标函数,分为三个部分</p> <ol> <li> <span style="color:#fe2c24;">第一部分</span>是<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29">,相当于阶段2中根据人类偏好学习出来的RM模型「<span style="color:#7b7f82;">所以你便会看到这里的</span><img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29"><span style="color:#7b7f82;">中只有一个<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29">,而不是再通过比较排序再训练<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29">,毕竟这里的<img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29">是已经通过上阶段比较排序而训练好的</span><img referrerpolicy="no-referrer" alt="gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%7B%5Ctheta%20%7D%28x%2Cy%29">」,从而基于“最大化奖励”这个目标下不断优化PPO模型的策略<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">(如上文所述,PPO模型一开始是被SFT模型初始化而来的)</li> <li> <span style="color:#fe2c24;">第二部分</span>则是用KL散度对比RL最终学到的策略<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">和原始策略<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi%20%5E%7BSFT%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D">的差距,一开始时,<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">的初始化值就是<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi%20%5E%7BSFT%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D">,咱们希望<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">最终迭代结束后,它俩之间的差距不至于太大<br><br> 怎么避免它两相差太多呢?可以类似PPO算法那样,通过KL散度衡量两个策略的概率分布之间的差距,从而使得咱们<u>在优化策略</u><u>时限制参数更新的范围</u>) <p class="img-center"><img referrerpolicy="no-referrer" alt="gif.latex?%5Cbegin%7Baligned%7D%20%26J_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3D%5Cmathbb%7BE%7D_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%20%5Csim%20%5Cpi_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%7D%5Cleft%5B%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%5D%20%5Cend%7Baligned%7D%20-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20%26J_%7B%5Cmathrm%7BPPO%7D%7D%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%28%5Ctheta%29%3D%5Cmathbb%7BE%7D_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%20%5Csim%20%5Cpi_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%7D%5Cleft%5B%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28a_%7Bt%7D%20%5Cmid%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%5E%7B%5Cprime%7D%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%5D%20%5Cend%7Baligned%7D%20-%5Cbeta%20%5Cmathrm%7BKL%7D%5Cleft%28%5Ctheta%2C%20%5Ctheta%5E%7B%5Cprime%7D%5Cright%29"></p> 其中, KL奖励系数<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta">控制 KL 惩罚,但具体怎么设置呢?网上很少有文章会阐述这点,但如果你仔细看了相关内容的话,你会发现有好几个地方都提到了<br> 一个是本文第一部分1.4节提到的自适应KL惩罚(adaptive KL penalty),来自2017年发表的PPO论文 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="175" src="https://img-blog.csdnimg.cn/2c3b63b5cb414b438df7a89e14dae8a4.png" width="600"></p> 一个是上文1.5.2节提到的这篇2019年发表的论文《<span style="color:#7b7f82;">Fine-Tuning Language Models from Human Preferences</span>》『<span style="color:#7b7f82;">也是本博客内另一篇文章“ChatGPT相关技术论文100篇”中提到的第56篇,另这是论文对应的代码:微调GPT2</span>』,其中提到了一种根据 KL_target 自适应调节<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta">的算法,这个方法已经被 TRLX/TRL实现 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="277" src="https://img-blog.csdnimg.cn/c3f775519533445db1120f7dc79d4ba1.png" width="600"></p> 更多训练细节可以看下instructGPT论文原文 <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="244" src="https://img-blog.csdnimg.cn/dcf2240f8a56451089a314ffe0c6fc08.png" width="800"></p> 好,接下来,重点来了,对于这前两部分,若简言之,<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">/<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D">与PPO算法表达式中的<img referrerpolicy="no-referrer" alt="\theta /\theta '" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%20/%5Ctheta%20%27">一一对应,比如与环境交互的<img referrerpolicy="no-referrer" alt="\theta '" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%20%27">等同于旧策略<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D">,但具体而言,则有以下4点<br><span style="color:#ed7976;"><strong>①</strong> </span>已经掌握人类偏好的RM模型一旦判定现有回答的不够好,便得更新<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">,但如果<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">一旦变化,会导致后续<img referrerpolicy="no-referrer" alt="\bar{R}_{\theta}=\mathbb{E}_{\tau \sim p_{\theta}(\tau)}\left[R(\tau) \nabla \log p_{\theta}(\tau)\right]" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbar%7BR%7D_%7B%5Ctheta%7D%3D%5Cmathbb%7BE%7D_%7B%5Ctau%20%5Csim%20p_%7B%5Ctheta%7D%28%5Ctau%29%7D%5Cleft%5BR%28%5Ctau%29%20%5Cnabla%20%5Clog%20p_%7B%5Ctheta%7D%28%5Ctau%29%5Cright%5D">计算一系列问答评分时中的<img referrerpolicy="no-referrer" alt="p_\theta (\tau )" class="mathcode" src="https://latex.codecogs.com/gif.latex?p_%5Ctheta%20%28%5Ctau%20%29">发生变化(策略一变轨迹必变),进而已采样的问答数据 <p class="img-center"><img referrerpolicy="no-referrer" alt="<x_{n+2},\left \{ y_{n+2}^{1},y_{n+2}^{2},y_{n+2}^{3},y_{n+2}^{4} \right \}><x_{n+3},\cdots ><x_{n+4},\cdots ><x_{n+5},\cdots >" class="mathcode" src="https://latex.codecogs.com/gif.latex?%3Cx_%7Bn&plus;2%7D%2C%5Cleft%20%5C%7B%20y_%7Bn&plus;2%7D%5E%7B1%7D%2Cy_%7Bn&plus;2%7D%5E%7B2%7D%2Cy_%7Bn&plus;2%7D%5E%7B3%7D%2Cy_%7Bn&plus;2%7D%5E%7B4%7D%20%5Cright%20%5C%7D%3E%3Cx_%7Bn&plus;3%7D%2C%5Ccdots%20%3E%3Cx_%7Bn&plus;4%7D%2C%5Ccdots%20%3E%3Cx_%7Bn&plus;5%7D%2C%5Ccdots%20%3E"></p> 便没法继续使用,而只能不断采样一批批新的问答数据(更新一次<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">后,得采样新一批数据;再更新一次<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">后,再采样新一批数据..)<br><br><span style="color:#ed7976;"><strong>②</strong> </span>为避免<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">只要一更新便只能一次次去采样一批批新问答数据<br> 说白了,为了提高数据利用率,我们改让<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D">去和环境交互『<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D"><span style="color:#7b7f82;">也被</span><img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi%20%5E%7BSFT%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D"><span style="color:#7b7f82;">初始化,会先固定一段时间,且基于重要性采样的原则 增加重要性权重</span>』<br> 然后通过最大化奖励而不断迭代<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">(<span style="color:#7b7f82;">相当于在策略</span><img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D"><span style="color:#7b7f82;">下模型回答的好不好始终由RM模型评判</span>),迭代过程中可一定程度的重复使用旧策略<img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D">生成的已有数据反复验证(注意这里的用词:一定程度的重复使用,就像蓄水池一样,提高水资源的利用率,但会适时更新) <hr> <span style="color:#7b7f82;"> 考虑到有些读者对这一块 还是有些疑惑,故再补充说明下<br> a) 首先,使用旧策略<span style="color:#4d4d4d;"><img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D"></span>生成一批数据,包括状态、动作和奖励等信息,这些数据可以类似<strong>Deep Q Network</strong>那样,存储在一个经验回放缓冲区(Experience Replay Buffer)中<br> b) 其次,在训练新策略<span style="color:#7b7f82;"><img referrerpolicy="no-referrer" alt="\pi _{\phi }^{RL}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D"></span>时,从经验回放缓冲区中随机抽取一批数据<br> c) 对于旧策略<span style="color:#4d4d4d;"><img referrerpolicy="no-referrer" alt="\pi ^{RL'}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BRL%27%7D"></span>采样到的每个数据样本<img referrerpolicy="no-referrer" alt="(x, y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?%28x%2C%20y%29">,计算重要性采样权重<img referrerpolicy="no-referrer" alt="w(x, y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?w%28x%2C%20y%29"></span> <p class="img-center"><img referrerpolicy="no-referrer" alt="w(x,y) = \frac{\pi _{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)}" class="mathcode" src="https://latex.codecogs.com/gif.latex?w%28x%2Cy%29%20%3D%20%5Cfrac%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7D"></p> <span style="color:#7b7f82;"> d) 使用这些加权样本来更新新策略,具体来说,将原始目标函数中的期望部分替换为加权样本的期望:</span> <p class="img-center"><img referrerpolicy="no-referrer" alt="objective(\phi) = E_{(x, y) \sim D_{\pi^{RL'}}}[w(x, y) * r_{\theta }(x, y)]" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29%20%3D%20E_%7B%28x%2C%20y%29%20%5Csim%20D_%7B%5Cpi%5E%7BRL%27%7D%7D%7D%5Bw%28x%2C%20y%29%20*%20r_%7B%5Ctheta%20%7D%28x%2C%20y%29%5D"></p> <span style="color:#7b7f82;"> e) 按照更新后的目标函数进行梯度计算和参数更新<br> f) 在训练过程中,可以多次重复使用经验回放缓冲区中的数据进行训练(这里的多次可以理解为有限次数)。但是,需要注意的是,随着策略更新,新旧策略之间的差异可能会变大,这时重要性采样权重可能变得不稳定,从而影响训练的稳定性<br> 为了解决这个问题(</span><span style="color:#fe2c24;">注意</span><span style="color:#7b7f82;">,下面这几段对于很多人想了很久,也不一定能立马意识到的)</span><br><span style="color:#7b7f82;"> <u>可以适时更新一批新数据</u>,比如<br> <img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 前几轮通过旧策略π(RL')采样的数据放在经验缓冲区里,把新策略π(RL)多次迭代更新出π(RL2)、π(RL3),这个过程中重要性采样的比值为π(RL2)或π(RL3)比上π(RL')<br> <img referrerpolicy="no-referrer" alt="\rightarrow" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Crightarrow"> 再之后通过π(RL3)采样一批新数据再次放在经验缓冲区里,从而继续迭代π(RL3)更新出π(RL4)、π(RL5),这个过程中重要性采样的比值为π(RL4)或π(RL5)比上π(RL3),以此类推..<br> <u>还可以使用一些方法限制策略更新的幅度</u>,例如PPO中的截断重要性采样比率(具体参见本文第一部分提到的RL极简入门一文)</span> <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} J_{\mathrm{PPO2}}^{\theta'}(\theta) \approx \sum_{\left(s_{t}, a_{t}\right)} \min &\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta'}\left(a_{t} | s_{t}\right)} A^{\theta'}\left(s_{t}, a_{t}\right),{clip}\left(\frac{p_{\theta}\left(a_{t} | s_{t}\right)}{p_{\theta'}\left(a_{t} | s_{t}\right)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta'}\left(s_{t}, a_{t}\right)\right) \end{aligned}" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20J_%7B%5Cmathrm%7BPPO2%7D%7D%5E%7B%5Ctheta%27%7D%28%5Ctheta%29%20%5Capprox%20%5Csum_%7B%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%7D%20%5Cmin%20%26%5Cleft%28%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%20A%5E%7B%5Ctheta%27%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%2C%7Bclip%7D%5Cleft%28%5Cfrac%7Bp_%7B%5Ctheta%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%7Bp_%7B%5Ctheta%27%7D%5Cleft%28a_%7Bt%7D%20%7C%20s_%7Bt%7D%5Cright%29%7D%2C%201-%5Cvarepsilon%2C%201&plus;%5Cvarepsilon%5Cright%29%20A%5E%7B%5Ctheta%27%7D%5Cleft%28s_%7Bt%7D%2C%20a_%7Bt%7D%5Cright%29%5Cright%29%20%5Cend%7Baligned%7D"></p> <span style="color:#7b7f82;"> 相当于为了对重要性比值做约束,故<strong>在<img referrerpolicy="no-referrer" alt="r_\theta (x,y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%5Ctheta%20%28x%2Cy%29">的部分里得加个截断处理</strong>(<em>说白了,重要性比值 根据截断去约束,当然你也可以改成 根据一个KL散度去约束,毕竟截断和KL散度约束都是实现PPO算法本身的方式,遗憾的是原论文中的目标函数<img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">对于这点也未展开体现出来,算是简洁的不能再简洁了,所以你得再仔细体会下上面这几段</em>),如下所示</span> <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} objective(\phi ) &= E_{(x,y)\sim D_{\pi _{\phi }^{RL}}} [r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \\&= E_{(x,y)\sim D_{\pi _{ }^{RL'}}} [\frac{\pi _{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)}r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \\&= E_{(x,y)\sim D_{\pi _{ }^{RL'}}} [\min \left(\frac{\pi_{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)} A^{\theta^{RL'}}\left(x,y\right),{clip}\left(\frac{\pi_{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)}, 1-\varepsilon, 1+\varepsilon\right) A^{\theta^{RL'}}\left(x,y\right)\right) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \end{aligned}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20objective%28%5Cphi%20%29%20%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%7D%7D%20%5Br_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5C%5C%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%20%7D%5E%7BRL%27%7D%7D%7D%20%5B%5Cfrac%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7Dr_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5C%5C%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%20%7D%5E%7BRL%27%7D%7D%7D%20%5B%5Cmin%20%5Cleft%28%5Cfrac%7B%5Cpi_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7D%20A%5E%7B%5Ctheta%5E%7BRL%27%7D%7D%5Cleft%28x%2Cy%5Cright%29%2C%7Bclip%7D%5Cleft%28%5Cfrac%7B%5Cpi_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7D%2C%201-%5Cvarepsilon%2C%201&plus;%5Cvarepsilon%5Cright%29%20A%5E%7B%5Ctheta%5E%7BRL%27%7D%7D%5Cleft%28x%2Cy%5Cright%29%5Cright%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5Cend%7Baligned%7D"></p> <hr> <span style="color:#ed7976;"><strong>③ </strong></span>迭代中我们追求整个目标函数<img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">最大化,自然要求最终优化好的策略『假定为π(RL100)』与基线策略π(SFT)的差距,即KL散度约束的<img referrerpolicy="no-referrer" alt="\beta log(\pi _{\phi }^{RL}(y|x)/\pi ^{SFT}(y|x))" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29/%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%29">最小『<span style="color:#7b7f82;"><em>这也是 <img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">中唯一的KL散度约束,而KL散度越小代表两个策略之间的差距越小</em></span>』 <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} objective(\phi ) &= E_{(x,y)\sim D_{\pi _{\phi }^{RL}}} [r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \\&= E_{(x,y)\sim D_{\pi _{ }^{RL'}}} [\frac{\pi _{\phi }^{RL}(y|x)}{\pi ^{RL'}(y|x)}r_\theta (x,y) - \beta log(\pi _{\phi }^{RL}(y|x) / \pi ^{SFT}(y|x) )] + \gamma E_{x\sim D_{pretrain}} [log(\pi _{\phi }^{RL})] \end{aligned}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20objective%28%5Cphi%20%29%20%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%7D%7D%20%5Br_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5C%5C%26%3D%20E_%7B%28x%2Cy%29%5Csim%20D_%7B%5Cpi%20_%7B%20%7D%5E%7BRL%27%7D%7D%7D%20%5B%5Cfrac%7B%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%7D%7B%5Cpi%20%5E%7BRL%27%7D%28y%7Cx%29%7Dr_%5Ctheta%20%28x%2Cy%29%20-%20%5Cbeta%20log%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%28y%7Cx%29%20/%20%5Cpi%20%5E%7BSFT%7D%28y%7Cx%29%20%29%5D%20&plus;%20%5Cgamma%20E_%7Bx%5Csim%20D_%7Bpretrain%7D%7D%20%5Blog%28%5Cpi%20_%7B%5Cphi%20%7D%5E%7BRL%7D%29%5D%20%5Cend%7Baligned%7D"></p> 至于如果忘了KL散度公式的具体表达或者忘了怎么推导而来的,可以看下RL极简入门关于TRPO的部分 <p class="img-center"><img referrerpolicy="no-referrer" alt="\begin{aligned} D_{KL}(p||q) &= H(p,q) - H(p) \\&= -\sum p(x)logq(x) + \sum p(x)logp(x) \\&= -\sum p(x)log\frac{q(x)}{p(x)} \\&= \sum p(x)log\frac{p(x)}{q(x)} \end{aligned}" src="https://latex.codecogs.com/gif.latex?%5Cbegin%7Baligned%7D%20D_%7BKL%7D%28p%7C%7Cq%29%20%26%3D%20H%28p%2Cq%29%20-%20H%28p%29%20%5C%5C%26%3D%20-%5Csum%20p%28x%29logq%28x%29%20&plus;%20%5Csum%20p%28x%29logp%28x%29%20%5C%5C%26%3D%20-%5Csum%20p%28x%29log%5Cfrac%7Bq%28x%29%7D%7Bp%28x%29%7D%20%5C%5C%26%3D%20%5Csum%20p%28x%29log%5Cfrac%7Bp%28x%29%7D%7Bq%28x%29%7D%20%5Cend%7Baligned%7D"></p> <span style="color:#ed7976;"><strong>④</strong> </span>直到<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">迭代出最优策略(是否最优裁判RM模型说了算)</li> <li> <span style="color:#fe2c24;">第三部分</span>是加在最后边的偏置项,其中, <img referrerpolicy="no-referrer" alt="gif.latex?D_%7Bpretrai%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?D_%7Bpretrai%7D">是GPT3的预训练数据分布,预训练损失系数<img referrerpolicy="no-referrer" alt="gif.latex?%5Cgamma" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cgamma">控制预训练梯度的强度,且<img referrerpolicy="no-referrer" alt="gif.latex?%5Cgamma" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cgamma">设置为0则称为PPO模型,否则称为PPO-ptx模型<br><br> 之所以加最后的这个偏置项,是防止ChatGPT在训练过程中过度优化,从而避免过于放飞自我,通过某种刁钻的方式取悦人类,而不是老老实实地根据人类的问题给出正确答案<br> 通俗点说,以保持GPT3原有的核心性能,防止各种训练之后,忘了最早是从哪里出发的(不忘来时路:GPT3 =》SFT =》RM =》RLHF)<br><br> 更多可以看下一些类ChatGPT项目的代码实现(比如本ChatGPT系列的此文:类ChatGPT逐行代码解读(2/2):从零实现ChatLLaMA、ColossalChat、DeepSpeed Chat),比如ColossalChat<img referrerpolicy="no-referrer" alt="" src="https://img-blog.csdnimg.cn/img_convert/c16ccb65bb19b11425eeb4b29e5ccd66.png"> </li> </ol> <h2>3.2 InstructGPT如何更好的构建多轮对话能力</h2> <p>这里我们先从自然语言任务中最基本的语言模型简单说起。一个语言模型大概是说,当你给定前面的若干个词后,它会给你下一个词;而当你有了下一个词后,它会再给你接一个词,以此递推</p> <ol> <li>实际上,我们向ChatGPT提出的问题,可以看成是下图的输入<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">,然后我们可以将ChatGPT给出的回答抽象成下图的输出<img referrerpolicy="no-referrer" alt="gif.latex?Y" class="mathcode" src="https://latex.codecogs.com/gif.latex?Y"> </li> <li>而ChatGPT这类语言模型,提供了若干个类似手机输入法的“候选句”,每个候选句对应的概率不一</li> <li>所谓的语言模型的训练,其实就是让模型调整候选句对应的概率,使得输出的候选句的概率尽可能大</li> </ol> <p class="img-center"><img referrerpolicy="no-referrer" alt="4ea27677bac93469d6143a5161d5b037.png" height="337" src="https://img-blog.csdnimg.cn/img_convert/4ea27677bac93469d6143a5161d5b037.png" width="600"></p> <p>对应到强化学习的框架中,环境从某种意义上说被直接被奖励模型RM取代了,如下图</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="725d62dd8d0f2997cc2329d5a50977bc.png" height="337" src="https://img-blog.csdnimg.cn/img_convert/725d62dd8d0f2997cc2329d5a50977bc.png" width="600"></p> <ol> <li>图中的状态State即是输入语句<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">,Agent则是模型,当模型拿到一个<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">,它根据生成/回答策略执行的动作action即是预测下一个单词<img referrerpolicy="no-referrer" alt="gif.latex?x_%7Bk%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bk%7D">(是个概率分布,可以选取概率最大的候选词)</li> <li>注意,ChatGPT需要输出一整句话<img referrerpolicy="no-referrer" alt="Y" class="mathcode" src="https://latex.codecogs.com/gif.latex?Y">,所以要完成最终的输出,需要做若干次action,即多次预测<br> 怎么做多次预测呢,当RM接收到模型给出的下一个单词的预测<img referrerpolicy="no-referrer" alt="gif.latex?x_%7Bk%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bk%7D">后,会把这个单词<img referrerpolicy="no-referrer" alt="gif.latex?x_%7Bk%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bk%7D">放到已有单词序列<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">的末尾,即<img referrerpolicy="no-referrer" alt="\left \{ x_0\cdots x_{k-1} x_k \right \}" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cleft%20%5C%7B%20x_0%5Ccdots%20x_%7Bk-1%7D%20x_k%20%5Cright%20%5C%7D">,从而继续让模型预测下一个词<img referrerpolicy="no-referrer" alt="x_{k+1}" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bk&plus;1%7D"> </li> <li>打个比方,这里的智能体就是手机输入法,而环境就是使用输入法的用户。用户所做的事情,就是当输入法给出一系列候选词后,<strong>基于某种偏好选择某个词</strong>,然后让手机输入法再去猜下一个词,直到输入法把整个句子猜出来为止</li> </ol> <p>这里我们明白了在语言模型场景下强化学习的状态和动作对应什么,那么奖励Reward呢?由于上文已经分析过instructGPT的目标函数了,这里就不再赘述,直接上图:</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="300d2c30d66a2fc2c9a96a2535790a19.png" height="337" src="https://img-blog.csdnimg.cn/img_convert/300d2c30d66a2fc2c9a96a2535790a19.png" width="600"></p> <p>至此,还有一个细节问题,即奖励函数是对整个输入语句<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">和整个输出语句<img referrerpolicy="no-referrer" alt="gif.latex?Y" class="mathcode" src="https://latex.codecogs.com/gif.latex?Y">而言的,而我们又在之前讨论过,智能体是根据一个一个词来去拼凑出整个回答的。图中的奖赏函数只能给出完整回答的奖赏,那么在智能体生成回答的过程中,每个动作action给出的词<img referrerpolicy="no-referrer" alt="gif.latex?x_%7Bk%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?x_%7Bk%7D">对应的奖赏是什么呢?</p> <p>这个细节在InstructGPT的论文中并没有给出。幸运的是,上文提到过的这篇论文《Learning from summarize from Human feedback》中的一个引脚标注给出了这个疑问的答案</p> <blockquote> <p>论文里说,奖赏模型只在最终生成回答之后才给出奖赏,在中间的过程中是不给出奖赏的。在这里论文里没有使用回答一词,而是使用总结一词,因为它的任务是将一篇长文章进行归纳总结</p> <p class="img-center"><img referrerpolicy="no-referrer" alt="" height="188" src="https://img-blog.csdnimg.cn/23e1b2939c3a41a29f99971d5427e1ce.png" width="600"></p> <p>换言之,只有在ChatGPT输出了EOS token的时候,整个轨迹才结束(EOS token是NLP中用来表示一段话结束的标志)</p> </blockquote> <p>总结上文,可得</p> <ol> <li>由于多轮对话要求语言模型有记忆性,因此无法直接使用RL,问题出在奖赏函数中:ChatGPT的奖励函数是针对GPT的一整个输入语句<img referrerpolicy="no-referrer" alt="gif.latex?X" class="mathcode" src="https://latex.codecogs.com/gif.latex?X">和一整个输出语句<img referrerpolicy="no-referrer" alt="gif.latex?Y" class="mathcode" src="https://latex.codecogs.com/gif.latex?Y">而言的,而ChatGPT的语言模型在强化学习的训练策略中,每个action其实输出的是一个个词语</li> <li>因此,OpenAI的团队采取不对序列的中间生成给予reward的方式解决这个矛盾</li> </ol> <p>考虑到多轮对话场景里,存在某一轮对话中的代词指向上一轮对话中的某个人或物的可能,为此,ChatGPT多轮对话的核心关键是</p> <ol> <li>“基于Transformer的生成式模型”GPT3/GPT3.5足够强大<br> 在回答用户问题的过程中,每段对话都是一个个序列<br> 把之前的部分对话内容(<span style="color:#7b7f82;">对历史对话数据的规模做个限制,比如限制在8K大小,另 GPT4可以处理的上下文大小最高可达32k</span>)都保存下来,和当前的输入一起作为输入给模型,这些信息被编码成一个向量作为模型的输入<br><br> 且得益于Transformer的自注意力机制,使得模型能够理解不同对话历史之间的依赖关系,并在生成回答时考虑到之前的对话历史<br> 此外,模型还使用位置编码来区分每个对话历史的位置,确保模型可以正确地捕捉到对话历史的顺序信息</li> <li>其次,为加强多轮对话能力,instructGPT/ChatGPT在训练的时候就引入了大量多轮对话的数据</li> </ol> <hr> <h1>第四部分 类ChatGPT开源项目的训练框架/代码实现/部署微调</h1> <p>虽说GPT3在2020年就出来了,但OpenAI并未开源,所以直到一年半后以后才有国内外各个团队比如DeepMind等陆续复现出来,这些大厂的复现代码我们自然无法窥知一二,毕竟人家也未开源出来</p> <p>再到后来基于GPT3的InstructGPT、基于GPT3.5的ChatGPT初版(GPT3.5的参数规模也尚无准确定论)、GPT4均未开源,OpenAI不再open,好在Meta等公司或研究者开源出了一系列类ChatGPT项目,本部分针对其中部分做下简要推荐..</p> <p>...</p> <p>为避免本文篇幅再次过长,本第4部分余下的内容已抽取出去独立成文,请点击:</p> <ul> <li>类ChatGPT的部署与微调:(上)从LLaMA、Alpaca/Vicuna/BELLE、中文版、(下)从ChatGLM、MOSS到ChatDoctor、可商用</li> <li>类ChatGPT代码逐行解读:(1/2)从零起步实现Transformer、llama/ChatGLM、(2/2)从零实现TRL、ChatLLaMA、ColossalChat、DeepSpeed Chat</li> </ul> <hr> <h1>后记(含修改/优化/完善记录)</h1> <p>事实上,可能很多朋友也已经意识到,本文的前大部分内容里,GPT-N理解起来相对轻松(包括Transformer通过理解上篇BERT笔记不算特别复杂),而instructGPT/ChatGPT的整体架构思想也不算复杂,但其中涉及到的RL部分则让想深挖细节的初学者变得立马吃力起来(除非你已“入一定门”,或者你有课程/老师可以不断问),比如一个PPO算法,要真正把这个概念讲清楚、讲透彻且从零推到尾则没那么容易了。</p> <p>以下是本文的部分修改/优化/完善记录</p> <ol> <li> <strong>开始第一大阶段的修改</strong><br> 1.22日,优化关于“instructGPT:如何基于RLHF运用到多轮对话场景”中的部分描述<br> 且为避免篇幅过长而影响完读率,权衡之下把扩展阅读下的SeqGAN相关内容删除</li> <li>1.27日,修改此部分内容:“instructGPT/ChatGPT:如何更好的构建多轮对话能力”,之前的阐述没在点子上</li> <li>2.9日,受正在编写的微积分和概率统计笔记的启发:把公式、定理、概念、技术放在历史这个大背景下阐述会让读者理解更为深刻,故,在本文开头前沿里,新增ChatGPT各个前置技术的发展、迭代、结合,并依据这些前置技术的先后提出顺序重新编排全文结构</li> <li>2.10日,把第一部分中的大部分RL细节抽取出来放到新一篇笔记《RL极简入门》里</li> <li>2.15日,针对本文开头所梳理的ChatGPT各项前置技术的推出时间从年份细化到月份,新增“RLHF”,及“低成本实现ChatGPT低配版训练过程的开源项目”</li> <li>2.16日,为更一目了然,进一步完善本文对自注意力机制的阐述</li> <li>2.17日,进一步完善本文对RLHF的阐述,比如新增对两篇RLHF相关论文的介绍</li> <li>2.21日,根据instructGPT原始论文,修正大量同类解读中针对“ChatGPT训练三步骤”也存在的不够精准的个别描述</li> <li>2.22日,新增关于“Prompt技术的升级与创新:指令微调技术(IFT)与思维链技术(CoT)”的部分</li> <li> <strong>进入第二大阶段的修改</strong><br> 2.25日,新增关于"GPT3到GPT3.5:从instructGPT到ChatGPT的迭代过程"的部分<br><br> 相比前几天有了质的提升<br> 之前哪怕修改十几次也都是1.x版本,今天的这个版本可以称之为2.0版本了,还会不断完善</li> <li>2.26日,修正instructGPT/ChatGPT训练三步骤中“<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D">/<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi%20%5E%7BSFT%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D">与PPO算法表达式中<img referrerpolicy="no-referrer" alt="\theta /\theta '" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Ctheta%20/%5Ctheta%20%27">的对应关系”<br> 且修正为:SFT就是基线模型 最后不用去更新它的策略<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi%20%5E%7BSFT%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi%20%5E%7BSFT%7D">,更新的是论文中命名为PPO模型的策略<img referrerpolicy="no-referrer" alt="gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cpi_%7B%5Cphi%7D%5E%7BRL%7D"> </li> <li>2.28日,修正对one-shot和few-shot的描述,相当于one-shot相当于就一个样本/示例,few-shot就是少量样本/示例<br> 且在本文最后附上了“ChatGPT相关技术的100篇论文必读榜”</li> <li>3.1日,修正训练RM模型的描述中个别不够准确的措辞,比如通过人类的排序而非打分去训练奖励函数/模型<br> 且删除关于“近端策略优化裁剪PPO-clip”的介绍,毕竟详细的可以查看另一篇RL极简入门</li> <li>3.2日,考虑到本文一读者留言说,“第三部分的<img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">,其中RL是需要更新的模型,而SFT是代替RL采样的不变的模型。那么为什么数学期望的下标的是RL,这不是意味着对正在更新的模型采样吗?如果是这样那PPO还有什么意义呢?”<br> 故为方便大家一目了然,已把该目标函数展开了下</li> <li>3.3日,在本文第二部分开头补充“NLP自发展以来先后经历的4种任务处理范式”</li> <li>3.7日,修正RLHF这一概念的最早提出时间,且补充关于beam search的介绍、完善关于“GPT的(无监督)预训练-(监督)微调模式”的描述</li> <li> <strong>进入第三大阶段的修改(根据论文精修)</strong><br> 3.8日,通过再次回顾GPT3的论文,补充关于为何GPT3不需要微调的原因,且修正个别不太精准的描述</li> <li>3.11日,根据Google的FLAN论文,修订关于指令微调的部分细节,以让行文更准确</li> <li>3.15日,新增一节“2.7 ChatGPT改进版:底层语言模型从GPT3.5升级到GPT4”的内容<br> 新增一小节“3.3.2 斯坦福Alpaca:人人都可微调Meta家70亿参数的LLaMA大模型”的内容</li> <li>3.16日,新增“Masked Self-Attention对屏蔽尾部词的实现方法”的描述</li> <li>3.17日,新增关于“GPT4的训练方式和基于GPT3的instructGPT或基于GPT3.5的ChatGPT初版的训练方式如出一辙”的描述<br> 修订对RLHF的精准定义:<em>基于人类偏好的深度强化学习</em> </li> <li>3.19日,把之前文末推荐的一些开源项目独立出来并完善为本文的“第四部分 关于类ChatGPT的部分开源项目”,并重点阐述Meta开源的LLaMA</li> <li>3.20,通过再次回顾instructGPT论文里的训练三阶段,给本文补充一些细节</li> <li>3.21,根据论文《SELF-INSTRUCT: Aligning Language Model with Self Generated Instructions》,修正“4.3 斯坦福Alpaca:人人都可微调Meta家70亿参数的LLaMA大模型”节中不准确的描述</li> <li>3.22,随着对一系列开源项目的研究深入,为避免本文篇幅再度过长,故把本文的第4部分 抽取出去独立成文:《类ChatGPT开源项目的部署与微调:从LLaMA到ChatGLM-6B》</li> <li>3.25,根据ChatGPT/GPT的最新技术发展,更新前言里的部分内容</li> <li>3.28,修正个别细节,比如根据instructGPT论文第56页可知,PPO模型初始化时曾experimented with a few variants of the SFT models as the PPO’s init model,即PPO模型有多个大小的版本,比如1.3B 6B 175B</li> <li> <strong>进入第四大阶段的修改(根据论文再修)</strong><br> 4.7,补充关于SFT与RM模型训练中的一些超参数的设置</li> <li>4.18,补充关于GPT1、GPT3的数据集的相关细节</li> <li>4.21,修正一个描述的笔误,即奖励模型的训练中,用的损失函数是rank loss,而非MSE loss</li> <li>4.27,依据RLHF部分中提到的论文“Fine-Tuning Language Models from Human Preferences”,增加关于instructGPT目标函数中 KL奖励系数<img referrerpolicy="no-referrer" alt="gif.latex?%5Cbeta" class="mathcode" src="https://latex.codecogs.com/gif.latex?%5Cbeta"> 的具体设置方法,毕竟网上很少有文章介绍这点</li> <li>4.29,考虑到不少同学在我所讲的ChatGPT原理解析课里询问有关prompt learning的细节,故新增一节“2.4.2 关于prompt learning的进一步总结:到底如何理解prompt learning”</li> <li>5.5,针对本文下面部分读者的留言,新增一些小细节的描述,比如为何<img referrerpolicy="no-referrer" alt="objective(\phi)" class="mathcode" src="https://latex.codecogs.com/gif.latex?objective%28%5Cphi%29">中不对<img referrerpolicy="no-referrer" alt="r_\theta (x,y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%5Ctheta%20%28x%2Cy%29">再进行比较排序训练了,原因是之前的阶段2 已经通过比较排序训练好了<img referrerpolicy="no-referrer" alt="r_\theta (x,y)" class="mathcode" src="https://latex.codecogs.com/gif.latex?r_%5Ctheta%20%28x%2Cy%29"><br> 再比如新增对于“旧策略生成的数据 是具体怎么重复使用的”这一问题的解释说明,毕竟网上同类文章里 还没见过有哪篇如此细致的解释说明过</li> <li> <hr> <strong>进入第五大阶段的修改(结合上课反馈 + 论文精修)</strong><br> 5.7,因为讲ChatGPT原理课,故在再次完整回顾instructGPT论文之后,补充一些数据、训练代价等细节</li> <li>5.9,因ChatGPT原理课一学员“吹牛班的春天”的意见/建议,特修正「instructGPT训练阶段三」中个别不够准确的描述,至此本文开始从完善阶段超完美阶段进发(换言之,本次修改后使得本文正式突破85分,超100分迈进)</li> <li>5.13,根据上面5.9的补充意见,算是史无前例的二次展开了instructGPT论文中目标函数的表达式,以和相关描述完全对应起来<br> 当你持续复现instructGPT的话,你会发现细节很多,而只有当你想复现你才会去思考这些细节,从而造就本文或本系列才有的细致</li> <li>//待更.. </li> </ol> <p>为了写本笔记,过去两个月翻了大量中英文资料/paper(中间一度花了大量时间去深入RL),大部分时间读的更多是中文资料,2月最后几天读的更多是英文paper,正是2月底这最后几天对ChatGPT背后技术原理的研究才真正进入状态(后还组建了一个“<strong>ChatGPT之100篇论文阅读组</strong>”,我和10来位博士、业界大佬从23年2.27日起上半年之内读完ChatGPT相关技术的100篇论文,榜单见此文),当然 还在不断深入,由此而感慨:</p> <ul> <li>读的论文越多,你会发现大部分人对ChatGPT的技术解读都是不够准确或全面的,毕竟很多人没有那个工作需要或研究需要,去深入了解各种细节</li> <li>因为100天100篇这个任务,让自己有史以来一篇一篇一行一行读100篇,之前看的比较散 不系统 抠的也不细<br> 比如回顾“Attention is all you need”这篇后,对优化上一篇Transformer笔记便有了很多心得</li> </ul> <p>总之,读的论文越多,博客内相关笔记的质量将飞速提升 自己的技术研究能力也能有巨大飞跃</p> <p></p> <h1>参考文献与推荐阅读</h1> <ol> <li>Transformer通俗笔记:从Word2Vec、Seq2Seq逐步理解到GPT、BERT,July</li> <li>《预训练语言模型》,电子工业出版</li> <li>GPT3原始论文:Language Models are Few-Shot Learners,这是翻译之一</li> <li>GPT,GPT-2,GPT-3 论文精读,2018年6月份OpenAI提出GPT(当年10月份Google提出BERT),随后2019年2月14日推出GPT2,20年年中推出GPT3,此文介绍了GPT发家史</li> <li> <p> 此外,写过图解Word2vec、图解transformer的<strong>Jay Alammar</strong>也写过:图解GPT2(其翻译版)、图解GPT3(其翻译版)</p> </li> <li> <p>GPT系列论文阅读笔记,另 300行代码实现GPT:GitHub - karpathy/minGPT: A minimal PyTorch re-implementation of the OpenAI GPT (Generative Pretrained Transformer) training</p> </li> <li>OpenAI关于对GPT3.5的介绍:https://beta.openai.com/docs/model-index-for-researchers</li> <li>prompt提示学习(一)简要介绍</li> <li>CMU刘鹏飞:近代自然语言处理技术发展的“第四范式”</li> <li>大模型prompt Turing技术上,这是针对这次分享的解读</li> <li>NLP小样本学习:如何用20条数据完成文本分类,此外,小样本学习也是七月NLP高级班上重点讲的技术之一,最新一期NLP11则加入了ChatGPT背后原理的解析</li> <li>【论文解读】in-context learning到底在学啥?</li> <li>万字拆解!追溯ChatGPT各项能力的起源</li> <li>A Survey for In-context Learning,这是对该论文的解读,该论文作者之一维护的一个Paper List for In-context Learning</li> <li>首次提出instruction turning的FLAN原始论文:FINETUNED LANGUAGE MODELS ARE ZERO-SHOT LEARNERS,这是解读之一<br> 此外,FLAN-T5原始论文:Scaling Instruction-Finetuned Language Models,这是对T5的解读之一</li> <li>GPT-3.5 + ChatGPT: An illustrated overview - Life Architect</li> <li>Chain-of-Thought Prompting Elicits Reasoning in Large Language Models,思维链技术的开山之作,这是针对该篇论文的来自亚马逊一研究者的解读(YouTube),这是针对该篇论文的解读笔记,这是关于Cot的一些关键paper,这是T5作者之一关于Cot的分享之一</li> <li>Large Language Models are Zero-Shot Reasoners,来自东京大学和Google的研究者</li> <li>Multimodal Chain-of-Thought Reasoning in Language Models,来自亚马逊的研究者</li> <li>Large Language Models Are Reasoning Teachers,提出了 Fine-tune-CoT 方法,旨在利用非常大的语言模型 (LMs) 的CoT推理能力来教导小模型如何解决复杂任务</li> <li>PLM 是做题家吗?一文速览预训练语言模型数学推理能力新进展</li> <li>有了Chain of Thought Prompting,大模型能做逻辑推理吗?</li> <li>热点解读:大模型的突现能力和ChatGPT引爆的范式转变</li> <li>通向AGI之路:大型语言模型(LLM)技术精要,张俊林</li> <li>Codex介绍页面:OpenAI Codex,Codex原始论文:Evaluating Large Language Models Trained on Code,另这是针对Codex原始论文的解读</li> <li> <strong>PPO原始论文</strong>:Proximal Policy Optimization Algorithms</li> <li>PPO算法解读(英文2篇):解读1 RL — Proximal Policy Optimization (PPO) Explained、解读2 Proximal Policy Optimization (PPO)</li> <li>PPO算法解读(中文3篇):Easy RL上关于PPO的详解、详解近端策略优化、详解深度强化学习 PPO算法</li> <li>PPO算法实现:https://github.com/lvwerra/trl</li> <li>如何选择深度强化学习算法?MuZero/SAC/PPO/TD3/DDPG/DQN/等</li> <li>Google搜索:instructGPT如何基于PPO算法进行训练,出来的一系列文章</li> <li> <strong>InstructGPT原始论文</strong>(确实有68页,^_^):Training language models to follow instructions with human feedback,我是23年2.28日首次基本完整看完</li> <li>InstructGPT 论文精读,来自动手学深度学习一书作者李沐的解读</li> <li>ChatGPT原理猜想(1)--从InstructGPT讲起,ChatGPT原理猜想(2)--InstructGPT深入学习</li> <li>ChatGPT: Optimizing Language Models for Dialogue,OpenAI关于ChatGPT的官方发布页面</li> <li>ChatGPT会取代搜索引擎吗,张俊林</li> <li>Illustrating Reinforcement Learning from Human Feedback (RLHF),另这是中文翻译版之一</li> <li>OpenAI联合DeepMind发布全新研究:根据人类反馈进行强化学习,表明2017年便开始研究RLHF了</li> <li>基于人类偏好的深度强化学习(Deep reinforcement learning from human preferences),这是翻译版之一,这是解读之一</li> <li>《Learning from summarize from Human feedback》,这篇博客是对这篇论文的解读之一</li> <li>HuggingFace的视频分享:RL from Human Feedback- From Zero to chatGPT,这是文字解读:ChatGPT 背后的“功臣”——RLHF 技术详解</li> <li>OpenAI's InstructGPT: Aligning Language Models with Human Intent</li> <li>不忽悠的ChatGPT,作者Ben</li> <li>别光顾着玩,让我来告诉你ChatGPT的原理,来自B站UP主弗兰克甜</li> <li>浅析ChatGPT的原理及应用,此外,这里还有一篇外文解读:How ChatGPT actually works</li> <li>Role of RL in Text Generation by GAN(强化学习在生成对抗网络文本生成中扮演的角色)</li> <li>抱抱脸:ChatGPT背后的算法——RLHF</li> <li>关于指令微调等关键技术:What Makes a Dialog Agent Useful?,这是此文的翻译版</li> <li>谷歌FLAN-T5作者亲讲:5400亿参数,1800个任务,如何实现大语言模型“自我改进”</li> <li>为什么chatgpt的上下文连续对话能力得到了大幅度提升?</li> <li>LaMDA: Language Models for Dialog Applications,Google对话机器人LaMDA原始英文论文</li> <li>https://github.com/hpcaitech/ColossalAI/tree/main/applications/ChatGPT</li> <li>https://www.hpc-ai.tech/blog/colossal-ai-chatgpt</li> <li>ChatGPT原理介绍</li> <li>ChatGPT 标注指南来了!数据是关键</li> <li>https://openai.com/research/gpt-4,GPT4的介绍页面</li> <li>LLaMA模型惨遭泄漏,Meta版ChatGPT被迫「开源」!GitHub斩获8k星,评测大量出炉</li> <li>还在为玩不了ChatGPT苦恼?这十几个开源平替也能体验智能对话</li> <li>大模型训练避坑指南</li> <li>复现instructGPT的两个尝试:Instruct GPT复现的一些细节与想法、复现 Instruct GPT / RLHF</li> <li>ChatGPT相关技术必读论文100篇(2.27日起,几乎每天更新)</li> </ol> </div> </div> <div id="treeSkill"></div> </article>
ChatGPT技术原理解析:从RL之PPO算法、RLHF到GPT4、instructGPT
作者
sockstack
许可协议
CC BY 4.0
发布于
2023-11-09
修改于
2024-12-22
上一篇:软件:常用 Linux 软件汇总,值得收藏
下一篇:最新ChatGPT镜像网站入口 国内无需注册 打开网页就能体验!
尚未登录
登录 / 注册
文章分类
博客重构之路
5
Spring Boot简单入门
4
k8s 入门教程
0
MySQL 知识
1
NSQ 消息队列
0
ThinkPHP5 源码分析
5
使用 Docker 从零开始搭建私人代码仓库
3
日常开发汇总
4
标签列表
springboot
hyperf
swoole
webman
php
多线程
数据结构
docker
k8s
thinkphp
mysql
tailwindcss
flowbite
css
前端