微调与RLHF在实际业务中的最佳实践思路【2023H2】
TLDR
本文实际上讨论包括LLM微调和RLHF在内的一大类泛微调方式,本文称之为【广义微调】。标题写“微调和RLHF”只是为了方便理解。
核心观点:获取广义微调的高质量数据成本是如此之高,以至于应该为此定制广义微调的训练过程、优化目标、甚至一些模型结构都不足为奇。
本文也是在向基座LLM API团队喊话,抛一个我认为的下一代的广义微调API设计思路和目标场景。
对微调和RLHF比较熟悉的同学可以考虑直接跳转到第4节,前面内容更多是照顾没做过广义微调的读者和逻辑铺垫。
其他
本文属于《Rethinking LLM》系列,为了缩短标题才没有加入。这意味着本文的阅读难度会相对较大。但我仍尽量让业内非技术岗位的读者也能明白,本文的一些思路需要非技术岗位的配合才能实现。
本文不讨论多模态跨模态关联的广义微调。
微调、RLHF、领域大模型、基座公司的宣传的微调服务等等内容已经充斥网络,本文无意也无法讨论所有内容,虽然本文已经接接近1万字。从前期试读反馈来看,已经发现有一些读者的诉求本文无法照顾,这里也只能请读者理解。
0、前言
本专栏主题类似的上一篇文章是 《【2023H1】Rethinking LLM(2):如何理解LLM中的微调和RLHF阶段》(发表于知乎),但这篇文章内容只能算是入门向,后面就一直也没有很完整的来谈这方面的进阶认知。一方面是因为这方面认知还在不断发展,另外也是因为我无意讨论一些会很快(1年左右)过时的技术细节知识。直到最近我终于有精力来整理截至目前的认知。
主要讨论在实际场景中应用广义微调的策略架构设计思路,而非具体的细节,所以标题特别标注是【思路】。【道】在不同的场景会得到不同的【术】,本文希望给出一种普适很多场景的“方案”,所以只能是道。
本文重点是讨论2年之后仍然有效的内容,所以不会太多的深入库的细节之类的,因为在我看来这些细节很可能会在1年之后过时。以及本文会提到的一些思路目前并没有开源库支持。本文就没打算写成一个cookbook来让人直接抄训练目标设计或者代码等等。
标题称“最佳实践”,可能有些自吹,但也确实是我目前认为的最好的思路。读者有批评和反对意见欢迎找我交流、或者直接撰文批判。
1、广义微调
广义微调是我在本文构造的一个新概念,它包括传统认知中的微调和RLHF(包括Reward model环节),但并不仅限于传统常用的这两种的具体操作方式。所以本文才特意创造一个新词来提醒读者:本文的分析框架针对的并不是大家习惯的微调和RLHF。
1.1、广义微调
具象来说,广义微调类的方案具有如下特点:
广义微调对于基座模型的参数只做了“少量”改变,类似于微调的感觉。这个少量不是从改变参数量来说的,而是从权重差的某种数学范数来说的。
相对于预训练过程,广义微调需要的计算量相对较小。这里排除Reward model这样的辅助模型的训练成本。
并不能明显地改变基座模型中知识的存储结构和方式,只能对其中已有的知识表达方式进行某种差异化的选择性强化和抑制。这也是前两点的直接结果。也就是现在常说的“微调是激发LLM模型中的某些已有能力”这样的感觉。
广义微调依赖于外部提供某种明确的监督信号,而不同于预训练阶段的基于大量语料的自监督学习。
基于QA对的传统微调 和 基于结果pair rank信息的RLHF都符合上述特点,但除了它们以外还有其他的方式。虽然我无法给出广义微调的简洁定义,但在文章后面会展示一些其他非标准微调或RLHF的广义微调案例或思路。
1.2、广义微调的本质作用
为什么LLM会需要划分预训练阶段和广义微调阶段呢?因为广义微调能够提供一些预训练阶段无法有效达成的好处。LLM的广义微调是迁移学习的典型案例,甚至可能是最成功的案例。人们在大量语料的预训练结果(基座LLM)中意外的发现了一些可以被人简单改造后利用的价值点,而广义微调就是这个“简单改造”过程。广义微调类似于一个类似“去粗取精”的过程,或者说:排除我们不想要的部分,加强我们想要的部分。
广义微调之所以能成功,本质上是因为基座LLM参数化的具体方式,以及人们广义微调的过程能够在不显著破坏其原有能力的情况下碰巧能够将其往我们的目标“掰一掰”。
概括一下就是:使用有限的监督数据(以及有限的算力),来改善模型在期望任务上的效果表现。
1.3、广义微调在实践中的作用
上一节只是说理论上能够成功,但理论上可行实际上不可行的方案太多了。到现在为止的实践经验告诉我们:广义微调是可行的,至少成功率是可接受的。除此之外,还有一些定性经验:
靠广义微调不能有效的改变模型的知识结构,或者记住新的知识体系。
广义微调对于监督信号的数据质量要求很高。Token级别的广义微调(例如传统SFT微调)对于数据多样性要求也很高,否则可能会过拟合输入序列模式。
如果不是直接在业务流程上进行记录,那么高质量的数据准备是一个成本很高的事情。雇佣人工撰写回答基本不可行。使用模拟生成数据也需要GPT4级别的模型才更靠谱。
广义微调可以在实践中的具体问题场景上,能够有效地提升模型效果。它并非银弹,但这个方案的性价比很不错。
当场景的prompt模版较长时候,也可以用微调来降低需要的prompt模版长度。
因为它能够使用高质量的数据提升模型效果,所以它可以被用于:
大参数量模型运行一段时间后,用其日志数据去微调小模型,达到让广义微调后的小模型实现接近的效果,从而替换掉大模型来降低推理成本。
系统运行一段时间后,使用积累的数据去广义微调各个环节的模型,相对于冷启动阶段获得效果提升。但该方式会有边际效果递减的问题,主要在前几次有效。
系统运行一段时间后,使用整个流程上的积累数据去广义微调一个融合原来多环节功能的模型,实现降低推理成本、提升反应速度、甚至优化效果。
如果冷启动效果较差,可以定制一个高质量的模拟数据去广义微调来提升效果。
本节的内容可以有很多,仅仅节选了一些与本文主题有关的部分。
2、高质量数据获取的成本
数据获取成本是本文的一个逻辑基础,虽然有些偏题,但还是得专门讨论下。
没实际做过微调的人可能会有如下想象:
微调就是拉一些数据调包,按QA/IQA格式准备一下,甚至OpenAI的微调API最少只需要100条数据就可以。这能有多难?
但随便就这样去做一下的话,大概率不能得到一个期望的效果,虽然可能性并不是0。本文则期望讨论一些更“靠谱”的方式,平衡实现成本和最终能实现的效果及达到它的概率。
本节有一个前提,就是并没有业务现场已有的历史数据并且数量足够。举个历史数据储备不错的例子:历史所有的知识产权申请材料,及其审核结果。在有这样数据积累的场景中开发要更容易一些,而且很可能在之前就已经实现了业务流程的智能化。本节更多是讨论没有这样的已有数据的场景。
这时候获得数据有两种方式:在业务流程之外单独进行人工标注,或者是通过某些方式来构造数据。
2.1、高质量的模拟数据生成
构造模拟数据有以下思路/场景:
【1】使用AIGC生成数据,并可以自动检验结果
例如:通过LLM生成各种不同的代码,虽然可能正确率不高。后续使用编译器等工具检查代码是否可以编译通过。通过这样的检验过滤之后,可以提高数据集的平均质量。
【2】复杂流程中的长程数据
在复杂的策略流程中,可以将流程中不只一个环节的结果关联起来,来构造数据行。
多环节的策略流程中,经常就可以使用这样的方式。
比较复杂的案例就是在Multi Agent的策略架构中,直接构造【最初问题】与【讨论后结果】的映射对作为数据。当然随着内部流程环节的变多,这样的数据难度会变大。也可以插入一些中间步骤的结果来降低数据的学习难度。Multi Agent的策略架构可以见我之前的文章:
《【2023Q2】Rethinking LLM:自动化的RLHF数据生成 与 Multi-Agent Alignment》(发表于知乎)
2.2、大批量的人工标注
人工的大量标注是一种保底方案:没有业务的自然数据,也没有好的办法来自动生成,那么就只能找团队来做人工标注了。
而团队标注面对的问题是:如何有效的传达标注目标,如何如何评价每个标注员的工作质量,还要尽量的降低人工成本。如何做一个定制需求的数据标注团队其实并不是一个简单的事情,如何设计内部工作流,以及如何让需求提出方尽量快的明确和稳定自己的需求是比较难的。
从数据需求和供给方两边综合来说,有几个关键因素:
标注的目标是明确的,并且能够尽快的准确传递给数据标注团队,并尽量保持需求变化不要太快。
有效的设计标注对象/标注问题,让标注员在单位时间要能提供提供尽可能多的增量信息。
标注的结果的质量评价方式要能够尽量的客观与自动化。
尽量避免由于标注问题本身存在模糊性,而导致不同人可能给出不同结果导致难以简单的进行标注结果相互校验。
后几点目标有一个共同的解决思路,就是要尽量选择一个“高信噪比”的标注问题。这个高信噪比是指:同一个标注case,大部分标注员会对其做出明确且一致的结果。让标注员感觉模棱两可、几种标注方式都可以的问题不是一个足够好的标注问题。
【人工撰写回答】
直接让人工撰写回答是一个相当差的标注问题,不光因为让人写长回答是一个很耗费时间和精力的事情。也因为很难对撰写的回答进行量化的质量评估,导致数据中容易混有大量质量较低的数据。
而且,人在沟通和打字时候都有尽量倾向于简短沟通,如果对方觉得没有理解,对方会提问来让自己补充。导致人一般撰写回答的时候,结果往往都会偏短,但实际上又很难把它评价为一个差的回答。
我见到了一些领域专家对于撰写数据充满热情,但尝试不久后就敬而远之的情况。除非自己真的做过,否则绝大部分人都会低估人工撰写回答的成本。大概经常写文章的人才能够理解为什么这是件成本很高的事情吧。
3、回顾 传统 微调 和 RLHF
3.1、传统 微调
传统微调最适合的场景是:我们希望“模型的回答逐个token都模仿提供的数据”,也就是逐字模仿,措辞方式、语气词、标点符号的使用风格、排版风格等等都要去模仿。因为对于传统微调的优化目标来说,我们无法让模型的学习过程知道“光学习它的语气就行了,排版格式不用学”。
这个学习过程导致了一些问题,第一是它对于预料的token级质量要求比较高。模型不知道数据中混杂的少量情况是脏数据,还是它就应该学习的内容。而微调的数据量又不大(跟预训练可比),更加重了这个问题。这导致如果没有有效的监督方式,让大量人工来给模型撰写微调用的数据是一个很难组织化完成的工作。
第二是,我们需要足够多样性的数据,来确保模型学到的是我们期望它学到的相关性。
举一个例子,我们希望让LLM做选择题,并准备了一个微调数据集,其中选C的占比50%。那么LLM比较容易地学到选C的概率更高,而不是去分析问题。因为选C的概率高这个信息很容易被模型发现,更容易学习。在中国参加过高中教育的众所周知,人也是这样的。
其他的相关性还有:最长的回答一般是正确回答。
如果我们希望避免模型去学习我们给的微调数据集中的不重要的相关性,在这里就需要针对性的去做一个各个选项都平衡的数据集。但可惜的是,在LLM来看数据集中这样的不重要相关性几乎无穷无尽,可能超过人简单的想象,我们很难通过枚举来逐一排除。尽量构造多样性的数据是有效的,但肯定做不到100分,LLM总能发现人类无法认知到的相关性。
3.2、传统 RLHF(Reinforcement Learning from Human Feedback)
在我看来,OpenAI使用RLHF最早就是为了解决以下问题:
高质量的微调数据集制作成本高到无法接受,即使都让专家来人工撰写也做不到足够好。
人并不擅长生成长文本,相对来说比较两个回答的成本更低,对标注人员的能力的要求也更低。
当模型的平均能力超过标注人员的平均能力时,如何进行有效地标注。
标注问题从“产生一个完整的回答”变成了“比较一些回答的好坏”。(当然RLHF也可以用来学习回答是否具有某个特性这样的监督信号,以下为了行文简略不再反复提醒。)
而传统的RLHF也仍然不是银弹,它有如下问题:
人并“不擅长”阅读大量文字,并比较两端较为大量的文字。虽然成本比让人写这样的文字成本要低,但其成本仍然是很高的。
并不是所有场景下都能很容易地比较两个回答的好坏。对于“质量”接近的回答,不同的标注者可能给出完全相反的标记。虽然说冲突的标记数据RLHF学习过程也能处理,但这导致了一定程度上标注人工的浪费,或者说非最优。
RLHF依赖于构建一个reward model模型,但reward本身的选择在RL中也是众所周知的玄学,并容易被学习过程钻漏洞。
RL本身的样本利用效率相对于监督学习更低,这意味着需要更多的标注数据。
4、广义微调的场景选择
4.1、场景 及 场景的划分
【场景】可以认为是一次LLM API调用解决的具体子问题,是与整体策略流程的划分是有关的。例如原本只需要调用一次LLM,但后面发现准确率做不高,所以拆成了几次LLM调用(甚至包括非LLM的调用),那么对应的场景其实也从1次变成了几次。
场景的划分(策略流程阶段的划分)需要平衡考虑以下因素:
全流程的策略效果
全流程的总推理成本,全流程的总响应时间
每个环节的的高质量监督信号数据的获取成本(监督信号数据可以来源于人工反馈,也可以来源于后续LLM环节的验证等)
尽可能多的提取领域专家的知识,以改善整体策略效果
如果数据是需要人工标注的,那么要考虑单次标注的信噪比
场景对应的微调方式的成本
完整讨论其实需要系统性地讲下如何做“LLM原生应用的复杂策略流程的整体设计”,但由于篇幅问题本文从略。
4.2、重新思考 场景的选择
回顾传统微调中的问题,其最核心点就是如何低成本地获取高质量的监督信号数据,很多场景下这个问题直接决定了传统微调和RLHF是否可行。
让我们放下原有的习惯认知,重新思考这个问题,会有如下结论:
一般场景下,业务流程外的额外人工标注成本很高。但人工标注很多时候无法避免,有些业务信息仅有组织内的专家才知道,Multi Agent做通用数据生产的能力还较弱。能在已有的业务流程中直接采集人工的结果是最好的方式。
人类不擅长生产“高比特量”的数据。“做选择”比“直接撰写”成本低,“写少量文字”比“写大量文字”成本低,“描述一幅图片”比“画出一幅图片”成本低。
人“验证一个答案/评价一个作品”比“解决一个问题/产出一个作品”的成本低。
人的标注具有一定随机性,对于某些问题标注的随机性可能大于另一类问题,不同“情况”下人工标注结果信噪比可能会有很大差异。这个信噪比跟问题难度、标注员的平均素质、标注员对标准的理解与拉齐程度、标注员的精神状态等都有关系。
由于标注信噪比的关系,不适合让人对于一个过于细碎的对象进行标注,至少要保持语义的完整性。例如比较一个序列的两个不同的后继token,一般会导致标注信噪比很低。
人不擅长比较两个很复杂的结果。体现为标注时间增加、标注员单位时间的精力损耗提升、标注结果的一致率下降导致信噪比下降。
由以上可进一步推论:
需要广义微调的场景的标记数据 最好是业务流程中人类可见的一部分,或者能被其他方式自动评价,这样可以自然的采集未来使用的广义微调数据。
标注的对象不能太小,以避免标注信噪比太低。但又不适合太大,因为会提高人的标注成本,且会增加广义微调的训练难度。应该选择在合适的标注信噪比下的最小可标注信息单元。
让用户做选择好过让用户直接评价好坏。不同选项的标注信息单元最好都有低成本的自动生成方案。
这个信噪比最合适的标准,可以参考“人类标注员能够很容易地就至少80%的case形成一致意见”这样的标准。
4.3、广义微调的方案选择和流程顺序
虽然一般认知中,传统微调应该先于RLHF,但本文的建议是:
【1】用SFT还是RLHF应该由标注问题决定
而不是说拿到什么标注数据上来都先SFT一下。是不是要用SFT,还是要用RLHF或者重新设计微调训练方式是要看标注问题来分析的。
【2】流程的顺序也没有那么死板
这个建议其实和传统认知和一些实践结果有冲突。例如有人发现RLHF之后再做SFT效果会较差,我认为这其实是我们没有找到最正确的多轮广义微调的方式。由于篇幅问题,本文不在这里展开。
只有对于同一个子场景的微调时才要分析是否应该以某种特定顺序进行。
我认为(针对不同场景的)广义微调的流程顺序是可以任意交换的,且权重diff的结果也是可以任意叠加的,真正意义上符合“微扰”的特性。当然,这需要我们找到“正确”的广义微调方式。
5、广义微调的场景案例
以下举一些实际或者虚拟的案例来方便理解:
5.1、Midjourney & DALL-E
Midjourney 有个设计,就是一次总是产出4副图片。最近出的DALL-E 3也包含这个设计,不过会在生成后过滤掉一些有问题的图。
对于用户来说,本来没有要求多张。当然提供了多张提升了一些用户体验,但平衡计算量和用户体验的话似乎有点得不偿失。
实际上这是一种改变产品的交互流程来搜集用户反馈的方式。可以通过用户对于结果中的哪张进行放大等操作来识别用户最喜欢这其中的哪张图。仅凭产品交互上的少量改变和可接受的计算量,就获得了质量还比较高的用户反馈数据。
由此可以推测它们在内部有某种直接对于这个数据的RLHF类方案,来从用户选择数据中进行学习。
5.2、标注 文本的类别,而非其内容
在不少多轮对话场景下,对话或应答是有较大的随意性的。很多时候面对两个回答或对话历史,产品设计者也很难确定哪个更好。
有些场景下,我们确实对于模型的回应方向/思路有一些倾向性。例如某些时候应该回答,另一些时候应该向用户提问来补充信息。可能我们对于两个回答很难区分哪个更好,也很难区分两种提问方式哪个更好,但可能我们比较明确的知道在某些场景下,应该进一步向用户提问,在另一些场景下应该假设用户未指定的方面都按照默认来执行。
这时候,其实可以针对回答的方向/思路进行人工标注。本质上这可以看成是:根据业务场景设定了一些类别标签,并给每个回答进行标签的分类,并希望通过人工标注来干预模型在回答方向/思路上的表现。如果在某个场景下,我们明确的知道应该生成某个标签的回答,这就是类似传统微调的问题,可以直接让模型预测一个该场景的【标签token】。如果这时候并没有标准答案,但我们可以比较不同标签之间的好坏,那么就是一个类似针对于短回答的RLHF的过程,通过RLHF来让模型学会人对不同标签之间的相对偏好关系。
标签的粒度可以粗,也可以细,这完全看具体业务场景的需求。标签也可以有多个,都没有问题。
现在大家知道如何让LLM在适当的时候学习向用户主动提问了。
5.3、以整体方式标注 多轮对话,而非一轮回答
上一节演示一种应对低信噪比的思路,本节则给另一种思路:
在一些场景下,LLM单次的回答相对于整体目标来说过于细碎,可能需要看更多轮的回答才能确定是否完成了既定目标,例如引导学生进行有效的思考等等。这时候也可以考虑把K轮对话整体作为标注单元,如前面所说K不适合太大。K也可以不是一个固定值,而是看是否触发某些标准或用户更换了话题来切分。
这时候有个问题是:实际用户一般只会在某个历史上。其他的分支历史上的用户回答如何产生呢?有几种思路:
多轮回答并不需要完整给出每个回答,可以同时使用【2】的思路,考虑一个多轮问答的标签序列,而不是内容序列。这时候用户回答的标签就可以同一些方式低成本的进行模拟生成。
使用一些LLM或模拟能力更强的Agent来模拟扮演不同类型的用户进行回答。
如果对话的场景比较受限,可以从其他用户讨论同样内容的对话历史中进行匹配。
5.4、微调续写
很多人觉得传统微调只能以QA的方式来进行,但实际上作为单纯的续写问题也是可以的。在某些场景这会更适合。
本文在此仅作提示,不做举例展开。
6、广义微调的技术需求
本节从前面的思路展望一下未来的广义微调框架的特性。
6.1、关于 非标准场景下 如何训练
做研发的同学到这里会有个问题是:如何去做这些非标准模式下的广义微调呢?如果目前还没有符合对应场景的开源库,那自己是否就可以拒绝这样的需求呢?
我的看法是,一般场景下,高质量的标注场景选择的收益是高于为此定制广义微调训练方式的。虽然我们也在平衡各种因素的情况下考虑广义微调训练本身的研发和定制成本,但我觉得很多时候就是要在这方面进行让步的,因为高质量的数据持续产出是更高价值的事情。长期的能够把用户的习惯扭转的成本其实超过当时为此定制开发训练过程的成本。
但确实现在大部分在应用层做传统微调和RLHF的人并没有自己定制整个过程去适配不同标注问题的能力,我的建议是:
微调框架、微调API提供者应该考虑到不同场景的微调需求,一些较为通用的非标准训练目标应该尽量提供。在大家都能提供之前,这会是一个差异化的feature,吸引很多开发者用户过来,毕竟他们自己可能根本就做不好。
做算法的同学应该尽量去思考广义微调的细节过程,能够敢于去修改已有的方案,更好的适配数据生产的标注问题。这才是算法同学该做的事情,单纯抄论文/cookbook或者调包何来的壁垒?
不同场景下的最优标注目标是各种各样的,甚至即使是同样的问题也会跟能触达的用户/标注员的平均认知/习惯有关,可能很难做一个方案普适大部分场景的情况。
本文无意做一个cookbook,对于每个具体标注问题的训练方式讨论就不在这里进行了。我建了一个该主题的群,有兴趣的读者可以加群讨论,二维码在文末尾。
6.2、灵活的标注平台
需要标注的对象和标注粒度是跟场景、用户平均水平等等都有关的。3-5年的尺度上一般会发生变化,甚至不少场景下在用户熟悉了之后,标注问题就会发生一次变化。不同的情况下,就需要不同的标注对象和标注流程。
而我们目前的标注平台、业务数据流的可视化方式是否能够比较低成本地适应这种变化的标注对象?这应该是未被认真考虑过的领域。
我认为在大型业务流程上,需要一个能够灵活配置来适应不同标注问题的平台。
6.3、不同类型监督信息的融合
既然标注数据是最重要的,那么如果有不同来源的几种监督信号,是否应该联合使用呢?答案肯定是:能用的情况下就应该都用。
会有不同类型的监督信号可能因为:
不同的标注员群体的平均素质不同
对于同一个回答,不同专业的标注员只标注他们擅长的的维度
标注流程变更之前的标注数据是否能以某种形式迁移过来提供价值
所以这对于广义微调的训练过程提出了新的需求。
这方面我没有适合的案例,所以也不展开了。有兴趣可以加群讨论。
6.4、自动广义微调平台 和 上层策略的自动切换
从客户的角度来说,大家都希望系统是能够自动学习的。这就需要能够在数据流确定的情况下,全自动的跑广义微调过程。
最基本的自动微调这块OpenAI和百度千帆已经在做了,LLM API供应商都逐步做起来只是时间问题。我相信这方面会越来越自动化,最终到:配置 标注问题、模型、数据流就可以实现全自动,一个大型策略上配几十个全自动微调场景会很常见。
为了配合自动广义微调的能力,还需要业务策略系统支持自动或半自动的灰度对比两个模型版本,并且能够自动替换,当然并不是什么难以实现的功能。
不过,就算是古董的GBDT模型,能够做到自动训练、人工触发自动灰度实验对比、结果自动分析、人工触发新版本全量的算法系统都还是比例没那么高的,即使在信息化和智能化度很高的互联网大厂当中也是如此。策略更新的自动化在后面肯定是有不少需求的,但我并没有看到有多少人在做这方面。
交流与合作
如果希望和我交流讨论,或参与相关的讨论群,或者建立合作,请私信联系,见 联系方式。
希望留言可以到知乎对应文章下留言。
本文于2023.10.29首发于微信公众号与知乎。
知乎链接 https://zhuanlan.zhihu.com/p/663637777